+++ /dev/null
-vendor/
\ No newline at end of file
+++ /dev/null
-<?php
-
-// autoload.php generated by Composer
-
-require_once __DIR__ . '/composer' . '/autoload_real.php';
-
-return ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029::getLoader();
+++ /dev/null
-../umpirsky/twig-gettext-extractor/twig-gettext-extractor
\ No newline at end of file
+++ /dev/null
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- * Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Autoload;
-
-/**
- * ClassLoader implements a PSR-0 class loader
- *
- * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
- *
- * $loader = new \Composer\Autoload\ClassLoader();
- *
- * // register classes with namespaces
- * $loader->add('Symfony\Component', __DIR__.'/component');
- * $loader->add('Symfony', __DIR__.'/framework');
- *
- * // activate the autoloader
- * $loader->register();
- *
- * // to enable searching the include path (eg. for PEAR packages)
- * $loader->setUseIncludePath(true);
- *
- * In this example, if you try to use a class in the Symfony\Component
- * namespace or one of its children (Symfony\Component\Console for instance),
- * the autoloader will first look for the class under the component/
- * directory, and it will then fallback to the framework/ directory if not
- * found before giving up.
- *
- * This class is loosely based on the Symfony UniversalClassLoader.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Jordi Boggiano <j.boggiano@seld.be>
- */
-class ClassLoader
-{
- private $prefixes = array();
- private $fallbackDirs = array();
- private $useIncludePath = false;
- private $classMap = array();
-
- public function getPrefixes()
- {
- return call_user_func_array('array_merge', $this->prefixes);
- }
-
- public function getFallbackDirs()
- {
- return $this->fallbackDirs;
- }
-
- public function getClassMap()
- {
- return $this->classMap;
- }
-
- /**
- * @param array $classMap Class to filename map
- */
- public function addClassMap(array $classMap)
- {
- if ($this->classMap) {
- $this->classMap = array_merge($this->classMap, $classMap);
- } else {
- $this->classMap = $classMap;
- }
- }
-
- /**
- * Registers a set of classes, merging with any others previously set.
- *
- * @param string $prefix The classes prefix
- * @param array|string $paths The location(s) of the classes
- * @param bool $prepend Prepend the location(s)
- */
- public function add($prefix, $paths, $prepend = false)
- {
- if (!$prefix) {
- if ($prepend) {
- $this->fallbackDirs = array_merge(
- (array) $paths,
- $this->fallbackDirs
- );
- } else {
- $this->fallbackDirs = array_merge(
- $this->fallbackDirs,
- (array) $paths
- );
- }
-
- return;
- }
-
- $first = $prefix[0];
- if (!isset($this->prefixes[$first][$prefix])) {
- $this->prefixes[$first][$prefix] = (array) $paths;
-
- return;
- }
- if ($prepend) {
- $this->prefixes[$first][$prefix] = array_merge(
- (array) $paths,
- $this->prefixes[$first][$prefix]
- );
- } else {
- $this->prefixes[$first][$prefix] = array_merge(
- $this->prefixes[$first][$prefix],
- (array) $paths
- );
- }
- }
-
- /**
- * Registers a set of classes, replacing any others previously set.
- *
- * @param string $prefix The classes prefix
- * @param array|string $paths The location(s) of the classes
- */
- public function set($prefix, $paths)
- {
- if (!$prefix) {
- $this->fallbackDirs = (array) $paths;
-
- return;
- }
- $this->prefixes[substr($prefix, 0, 1)][$prefix] = (array) $paths;
- }
-
- /**
- * Turns on searching the include path for class files.
- *
- * @param bool $useIncludePath
- */
- public function setUseIncludePath($useIncludePath)
- {
- $this->useIncludePath = $useIncludePath;
- }
-
- /**
- * Can be used to check if the autoloader uses the include path to check
- * for classes.
- *
- * @return bool
- */
- public function getUseIncludePath()
- {
- return $this->useIncludePath;
- }
-
- /**
- * Registers this instance as an autoloader.
- *
- * @param bool $prepend Whether to prepend the autoloader or not
- */
- public function register($prepend = false)
- {
- spl_autoload_register(array($this, 'loadClass'), true, $prepend);
- }
-
- /**
- * Unregisters this instance as an autoloader.
- */
- public function unregister()
- {
- spl_autoload_unregister(array($this, 'loadClass'));
- }
-
- /**
- * Loads the given class or interface.
- *
- * @param string $class The name of the class
- * @return bool|null True if loaded, null otherwise
- */
- public function loadClass($class)
- {
- if ($file = $this->findFile($class)) {
- include $file;
-
- return true;
- }
- }
-
- /**
- * Finds the path to the file where the class is defined.
- *
- * @param string $class The name of the class
- *
- * @return string|false The path if found, false otherwise
- */
- public function findFile($class)
- {
- // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
- if ('\\' == $class[0]) {
- $class = substr($class, 1);
- }
-
- if (isset($this->classMap[$class])) {
- return $this->classMap[$class];
- }
-
- if (false !== $pos = strrpos($class, '\\')) {
- // namespaced class name
- $classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
- $className = substr($class, $pos + 1);
- } else {
- // PEAR-like class name
- $classPath = null;
- $className = $class;
- }
-
- $classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php';
-
- $first = $class[0];
- if (isset($this->prefixes[$first])) {
- foreach ($this->prefixes[$first] as $prefix => $dirs) {
- if (0 === strpos($class, $prefix)) {
- foreach ($dirs as $dir) {
- if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
- return $dir . DIRECTORY_SEPARATOR . $classPath;
- }
- }
- }
- }
- }
-
- foreach ($this->fallbackDirs as $dir) {
- if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
- return $dir . DIRECTORY_SEPARATOR . $classPath;
- }
- }
-
- if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
- return $file;
- }
-
- return $this->classMap[$class] = false;
- }
-}
+++ /dev/null
-<?php
-
-// autoload_classmap.php generated by Composer
-
-$vendorDir = dirname(dirname(__FILE__));
-$baseDir = dirname($vendorDir);
-
-return array(
- 'Collator' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/Collator.php',
- 'IntlDateFormatter' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/IntlDateFormatter.php',
- 'Locale' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/Locale.php',
- 'NumberFormatter' => $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/NumberFormatter.php',
-);
+++ /dev/null
-<?php
-
-// autoload_files.php generated by Composer
-
-$vendorDir = dirname(dirname(__FILE__));
-$baseDir = dirname($vendorDir);
-
-return array(
- $vendorDir . '/symfony/intl/Symfony/Component/Intl/Resources/stubs/functions.php',
-);
\ No newline at end of file
+++ /dev/null
-<?php
-
-// autoload_namespaces.php generated by Composer
-
-$vendorDir = dirname(dirname(__FILE__));
-$baseDir = dirname($vendorDir);
-
-return array(
- 'Twig_Extensions_' => array($vendorDir . '/twig/extensions/lib'),
- 'Twig_' => array($vendorDir . '/twig/twig/lib'),
- 'Twig\\Gettext' => array($vendorDir . '/umpirsky/twig-gettext-extractor'),
- 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
- 'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'),
- 'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'),
- 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
- 'Symfony\\Component\\Intl\\' => array($vendorDir . '/symfony/intl'),
- 'Symfony\\Component\\Icu\\' => array($vendorDir . '/symfony/icu'),
- 'Symfony\\Component\\Form\\' => array($vendorDir . '/symfony/form'),
- 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
- 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
- 'Symfony\\Bridge\\Twig\\' => array($vendorDir . '/symfony/twig-bridge'),
-);
+++ /dev/null
-<?php
-
-// autoload_real.php generated by Composer
-
-class ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029
-{
- private static $loader;
-
- public static function loadClassLoader($class)
- {
- if ('Composer\Autoload\ClassLoader' === $class) {
- require __DIR__ . '/ClassLoader.php';
- }
- }
-
- public static function getLoader()
- {
- if (null !== self::$loader) {
- return self::$loader;
- }
-
- spl_autoload_register(array('ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029', 'loadClassLoader'), true, true);
- self::$loader = $loader = new \Composer\Autoload\ClassLoader();
- spl_autoload_unregister(array('ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029', 'loadClassLoader'));
-
- $vendorDir = dirname(__DIR__);
- $baseDir = dirname($vendorDir);
-
- $map = require __DIR__ . '/autoload_namespaces.php';
- foreach ($map as $namespace => $path) {
- $loader->set($namespace, $path);
- }
-
- $classMap = require __DIR__ . '/autoload_classmap.php';
- if ($classMap) {
- $loader->addClassMap($classMap);
- }
-
- $loader->register(true);
-
- foreach (require __DIR__ . '/autoload_files.php' as $file) {
- require $file;
- }
-
- return $loader;
- }
-}
+++ /dev/null
-[
- {
- "name": "twig/twig",
- "version": "v1.13.2",
- "version_normalized": "1.13.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/fabpot/Twig.git",
- "reference": "v1.13.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.13.2",
- "reference": "v1.13.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.2.4"
- },
- "time": "2013-08-03 15:35:31",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.13-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Twig_": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Armin Ronacher",
- "email": "armin.ronacher@active-4.com"
- }
- ],
- "description": "Twig, the flexible, fast, and secure template language for PHP",
- "homepage": "http://twig.sensiolabs.org",
- "keywords": [
- "templating"
- ]
- },
- {
- "name": "twig/extensions",
- "version": "dev-master",
- "version_normalized": "9999999-dev",
- "source": {
- "type": "git",
- "url": "https://github.com/fabpot/Twig-extensions.git",
- "reference": "f5b0c84f3699e494c84ee627d7d583e115d2c4a2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/fabpot/Twig-extensions/zipball/f5b0c84f3699e494c84ee627d7d583e115d2c4a2",
- "reference": "f5b0c84f3699e494c84ee627d7d583e115d2c4a2",
- "shasum": ""
- },
- "require": {
- "twig/twig": "~1.0"
- },
- "time": "2013-07-02 11:21:55",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "installation-source": "source",
- "autoload": {
- "psr-0": {
- "Twig_Extensions_": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- }
- ],
- "description": "Common additional features for Twig that do not directly belong in core",
- "homepage": "https://github.com/fabpot/Twig-extensions",
- "keywords": [
- "debug",
- "i18n",
- "text"
- ]
- },
- {
- "name": "symfony/icu",
- "version": "v1.0.0",
- "version_normalized": "1.0.0.0",
- "target-dir": "Symfony/Component/Icu",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Icu.git",
- "reference": "v1.0.0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Icu/zipball/v1.0.0",
- "reference": "v1.0.0",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3",
- "symfony/intl": ">=2.3,<3.0"
- },
- "time": "2013-06-03 18:32:07",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Icu\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- }
- ],
- "description": "Contains an excerpt of the ICU data and classes to load it.",
- "homepage": "http://symfony.com",
- "keywords": [
- "icu",
- "intl"
- ]
- },
- {
- "name": "symfony/intl",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/Intl",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Intl.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Intl/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3",
- "symfony/icu": "~1.0-RC"
- },
- "require-dev": {
- "symfony/filesystem": ">=2.1"
- },
- "suggest": {
- "ext-intl": "to use the component with locales other than \"en\""
- },
- "time": "2013-07-08 13:00:35",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Intl\\": ""
- },
- "classmap": [
- "Symfony/Component/Intl/Resources/stubs"
- ],
- "files": [
- "Symfony/Component/Intl/Resources/stubs/functions.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- },
- {
- "name": "Igor Wiedler",
- "email": "igor@wiedler.ch",
- "homepage": "http://wiedler.ch/igor/"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- },
- {
- "name": "Eriksen Costa",
- "email": "eriksen.costa@infranology.com.br"
- }
- ],
- "description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
- "homepage": "http://symfony.com",
- "keywords": [
- "i18n",
- "icu",
- "internationalization",
- "intl",
- "l10n",
- "localization"
- ]
- },
- {
- "name": "symfony/property-access",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/PropertyAccess",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/PropertyAccess.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "time": "2013-07-01 12:24:43",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\PropertyAccess\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony PropertyAccess Component",
- "homepage": "http://symfony.com",
- "keywords": [
- "access",
- "array",
- "extraction",
- "index",
- "injection",
- "object",
- "property",
- "property path",
- "reflection"
- ]
- },
- {
- "name": "symfony/options-resolver",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/OptionsResolver",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/OptionsResolver.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/OptionsResolver/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "time": "2013-04-11 06:50:46",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\OptionsResolver\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony OptionsResolver Component",
- "homepage": "http://symfony.com",
- "keywords": [
- "config",
- "configuration",
- "options"
- ]
- },
- {
- "name": "symfony/event-dispatcher",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/EventDispatcher",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/EventDispatcher.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "symfony/dependency-injection": "~2.0"
- },
- "suggest": {
- "symfony/dependency-injection": "",
- "symfony/http-kernel": ""
- },
- "time": "2013-05-13 14:36:40",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\EventDispatcher\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony EventDispatcher Component",
- "homepage": "http://symfony.com"
- },
- {
- "name": "symfony/form",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/Form",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Form.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Form/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3",
- "symfony/event-dispatcher": "~2.1",
- "symfony/intl": "~2.3",
- "symfony/options-resolver": "~2.1",
- "symfony/property-access": "~2.2"
- },
- "require-dev": {
- "symfony/http-foundation": "~2.2",
- "symfony/validator": "~2.2"
- },
- "suggest": {
- "symfony/http-foundation": "",
- "symfony/validator": ""
- },
- "time": "2013-07-01 12:24:43",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Form\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony Form Component",
- "homepage": "http://symfony.com"
- },
- {
- "name": "symfony/translation",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/Translation",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Translation.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "symfony/config": "~2.0",
- "symfony/yaml": "~2.2"
- },
- "suggest": {
- "symfony/config": "",
- "symfony/yaml": ""
- },
- "time": "2013-05-13 14:36:40",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Translation\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony Translation Component",
- "homepage": "http://symfony.com"
- },
- {
- "name": "symfony/filesystem",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/Filesystem",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Filesystem.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "time": "2013-06-04 15:02:05",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Filesystem\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony Filesystem Component",
- "homepage": "http://symfony.com"
- },
- {
- "name": "symfony/routing",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Component/Routing",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/Routing.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "doctrine/common": "~2.2",
- "psr/log": "~1.0",
- "symfony/config": "~2.2",
- "symfony/yaml": "~2.0"
- },
- "suggest": {
- "doctrine/common": "",
- "symfony/config": "",
- "symfony/yaml": ""
- },
- "time": "2013-06-23 08:16:02",
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Routing\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony Routing Component",
- "homepage": "http://symfony.com"
- },
- {
- "name": "symfony/twig-bridge",
- "version": "v2.3.2",
- "version_normalized": "2.3.2.0",
- "target-dir": "Symfony/Bridge/Twig",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/TwigBridge.git",
- "reference": "v2.3.2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/TwigBridge/zipball/v2.3.2",
- "reference": "v2.3.2",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3",
- "twig/twig": "~1.11"
- },
- "require-dev": {
- "symfony/form": "2.2.*",
- "symfony/http-kernel": "~2.2",
- "symfony/routing": "~2.2",
- "symfony/security": "~2.0",
- "symfony/templating": "~2.1",
- "symfony/translation": "~2.2",
- "symfony/yaml": "~2.0"
- },
- "suggest": {
- "symfony/form": "",
- "symfony/http-kernel": "",
- "symfony/routing": "",
- "symfony/security": "",
- "symfony/templating": "",
- "symfony/translation": "",
- "symfony/yaml": ""
- },
- "time": "2013-05-16 10:19:58",
- "type": "symfony-bridge",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Symfony\\Bridge\\Twig\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "description": "Symfony Twig Bridge",
- "homepage": "http://symfony.com"
- },
- {
- "name": "umpirsky/twig-gettext-extractor",
- "version": "1.1.3",
- "version_normalized": "1.1.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/umpirsky/Twig-Gettext-Extractor.git",
- "reference": "1.1.3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/umpirsky/Twig-Gettext-Extractor/zipball/1.1.3",
- "reference": "1.1.3",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3",
- "symfony/filesystem": ">=2.0,<3.0",
- "symfony/form": ">=2.0,<3.0",
- "symfony/routing": ">=2.0,<3.0",
- "symfony/translation": ">=2.0,<3.0",
- "symfony/twig-bridge": ">=2.0,<3.0",
- "twig/extensions": "1.0.*",
- "twig/twig": ">=1.2.0,<2.0-dev"
- },
- "require-dev": {
- "symfony/config": "2.1.*"
- },
- "time": "2013-02-14 16:41:48",
- "bin": [
- "twig-gettext-extractor"
- ],
- "type": "application",
- "installation-source": "dist",
- "autoload": {
- "psr-0": {
- "Twig\\Gettext": "."
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Саша Стаменковић",
- "email": "umpirsky@gmail.com",
- "homepage": "http://umpirsky.com"
- }
- ],
- "description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates."
- }
-]
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-CHANGELOG
-=========
-
-2.1.0
------
-
- * added TraceableEventDispatcherInterface
- * added ContainerAwareEventDispatcher
- * added a reference to the EventDispatcher on the Event
- * added a reference to the Event name on the event
- * added fluid interface to the dispatch() method which now returns the Event
- object
- * added GenericEvent event class
- * added the possibility for subscribers to subscribe several times for the
- same event
- * added ImmutableEventDispatcher
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Lazily loads listeners and subscribers from the dependency injection
- * container
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Jordan Alliot <jordan.alliot@gmail.com>
- */
-class ContainerAwareEventDispatcher extends EventDispatcher
-{
- /**
- * The container from where services are loaded
- * @var ContainerInterface
- */
- private $container;
-
- /**
- * The service IDs of the event listeners and subscribers
- * @var array
- */
- private $listenerIds = array();
-
- /**
- * The services registered as listeners
- * @var array
- */
- private $listeners = array();
-
- /**
- * Constructor.
- *
- * @param ContainerInterface $container A ContainerInterface instance
- */
- public function __construct(ContainerInterface $container)
- {
- $this->container = $container;
- }
-
- /**
- * Adds a service as event listener
- *
- * @param string $eventName Event for which the listener is added
- * @param array $callback The service ID of the listener service & the method
- * name that has to be called
- * @param integer $priority The higher this value, the earlier an event listener
- * will be triggered in the chain.
- * Defaults to 0.
- *
- * @throws \InvalidArgumentException
- */
- public function addListenerService($eventName, $callback, $priority = 0)
- {
- if (!is_array($callback) || 2 !== count($callback)) {
- throw new \InvalidArgumentException('Expected an array("service", "method") argument');
- }
-
- $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority);
- }
-
- public function removeListener($eventName, $listener)
- {
- $this->lazyLoad($eventName);
-
- if (isset($this->listeners[$eventName])) {
- foreach ($this->listeners[$eventName] as $key => $l) {
- foreach ($this->listenerIds[$eventName] as $i => $args) {
- list($serviceId, $method, $priority) = $args;
- if ($key === $serviceId.'.'.$method) {
- if ($listener === array($l, $method)) {
- unset($this->listeners[$eventName][$key]);
- if (empty($this->listeners[$eventName])) {
- unset($this->listeners[$eventName]);
- }
- unset($this->listenerIds[$eventName][$i]);
- if (empty($this->listenerIds[$eventName])) {
- unset($this->listenerIds[$eventName]);
- }
- }
- }
- }
- }
- }
-
- parent::removeListener($eventName, $listener);
- }
-
- /**
- * @see EventDispatcherInterface::hasListeners
- */
- public function hasListeners($eventName = null)
- {
- if (null === $eventName) {
- return (Boolean) count($this->listenerIds) || (Boolean) count($this->listeners);
- }
-
- if (isset($this->listenerIds[$eventName])) {
- return true;
- }
-
- return parent::hasListeners($eventName);
- }
-
- /**
- * @see EventDispatcherInterface::getListeners
- */
- public function getListeners($eventName = null)
- {
- if (null === $eventName) {
- foreach (array_keys($this->listenerIds) as $serviceEventName) {
- $this->lazyLoad($serviceEventName);
- }
- } else {
- $this->lazyLoad($eventName);
- }
-
- return parent::getListeners($eventName);
- }
-
- /**
- * Adds a service as event subscriber
- *
- * @param string $serviceId The service ID of the subscriber service
- * @param string $class The service's class name (which must implement EventSubscriberInterface)
- */
- public function addSubscriberService($serviceId, $class)
- {
- foreach ($class::getSubscribedEvents() as $eventName => $params) {
- if (is_string($params)) {
- $this->listenerIds[$eventName][] = array($serviceId, $params, 0);
- } elseif (is_string($params[0])) {
- $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0);
- } else {
- foreach ($params as $listener) {
- $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0);
- }
- }
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * Lazily loads listeners for this event from the dependency injection
- * container.
- *
- * @throws \InvalidArgumentException if the service is not defined
- */
- public function dispatch($eventName, Event $event = null)
- {
- $this->lazyLoad($eventName);
-
- return parent::dispatch($eventName, $event);
- }
-
- public function getContainer()
- {
- return $this->container;
- }
-
- /**
- * Lazily loads listeners for this event from the dependency injection
- * container.
- *
- * @param string $eventName The name of the event to dispatch. The name of
- * the event is the name of the method that is
- * invoked on listeners.
- */
- protected function lazyLoad($eventName)
- {
- if (isset($this->listenerIds[$eventName])) {
- foreach ($this->listenerIds[$eventName] as $args) {
- list($serviceId, $method, $priority) = $args;
- $listener = $this->container->get($serviceId);
-
- $key = $serviceId.'.'.$method;
- if (!isset($this->listeners[$eventName][$key])) {
- $this->addListener($eventName, array($listener, $method), $priority);
- } elseif ($listener !== $this->listeners[$eventName][$key]) {
- parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method));
- $this->addListener($eventName, array($listener, $method), $priority);
- }
-
- $this->listeners[$eventName][$key] = $listener;
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher\Debug;
-
-/**
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface TraceableEventDispatcherInterface
-{
- /**
- * Gets the called listeners.
- *
- * @return array An array of called listeners
- */
- public function getCalledListeners();
-
- /**
- * Gets the not called listeners.
- *
- * @return array An array of not called listeners
- */
- public function getNotCalledListeners();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-/**
- * Event is the base class for classes containing event data.
- *
- * This class contains no event data. It is used by events that do not pass
- * state information to an event handler when an event is raised.
- *
- * You can call the method stopPropagation() to abort the execution of
- * further listeners in your event listener.
- *
- * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
- * @author Jonathan Wage <jonwage@gmail.com>
- * @author Roman Borschel <roman@code-factory.org>
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @api
- */
-class Event
-{
- /**
- * @var Boolean Whether no further event listeners should be triggered
- */
- private $propagationStopped = false;
-
- /**
- * @var EventDispatcher Dispatcher that dispatched this event
- */
- private $dispatcher;
-
- /**
- * @var string This event's name
- */
- private $name;
-
- /**
- * Returns whether further event listeners should be triggered.
- *
- * @see Event::stopPropagation
- * @return Boolean Whether propagation was already stopped for this event.
- *
- * @api
- */
- public function isPropagationStopped()
- {
- return $this->propagationStopped;
- }
-
- /**
- * Stops the propagation of the event to further event listeners.
- *
- * If multiple event listeners are connected to the same event, no
- * further event listener will be triggered once any trigger calls
- * stopPropagation().
- *
- * @api
- */
- public function stopPropagation()
- {
- $this->propagationStopped = true;
- }
-
- /**
- * Stores the EventDispatcher that dispatches this Event
- *
- * @param EventDispatcherInterface $dispatcher
- *
- * @api
- */
- public function setDispatcher(EventDispatcherInterface $dispatcher)
- {
- $this->dispatcher = $dispatcher;
- }
-
- /**
- * Returns the EventDispatcher that dispatches this Event
- *
- * @return EventDispatcherInterface
- *
- * @api
- */
- public function getDispatcher()
- {
- return $this->dispatcher;
- }
-
- /**
- * Gets the event's name.
- *
- * @return string
- *
- * @api
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * Sets the event's name property.
- *
- * @param string $name The event name.
- *
- * @api
- */
- public function setName($name)
- {
- $this->name = $name;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-/**
- * The EventDispatcherInterface is the central point of Symfony's event listener system.
- *
- * Listeners are registered on the manager and events are dispatched through the
- * manager.
- *
- * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
- * @author Jonathan Wage <jonwage@gmail.com>
- * @author Roman Borschel <roman@code-factory.org>
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Jordi Boggiano <j.boggiano@seld.be>
- * @author Jordan Alliot <jordan.alliot@gmail.com>
- *
- * @api
- */
-class EventDispatcher implements EventDispatcherInterface
-{
- private $listeners = array();
- private $sorted = array();
-
- /**
- * @see EventDispatcherInterface::dispatch
- *
- * @api
- */
- public function dispatch($eventName, Event $event = null)
- {
- if (null === $event) {
- $event = new Event();
- }
-
- $event->setDispatcher($this);
- $event->setName($eventName);
-
- if (!isset($this->listeners[$eventName])) {
- return $event;
- }
-
- $this->doDispatch($this->getListeners($eventName), $eventName, $event);
-
- return $event;
- }
-
- /**
- * @see EventDispatcherInterface::getListeners
- */
- public function getListeners($eventName = null)
- {
- if (null !== $eventName) {
- if (!isset($this->sorted[$eventName])) {
- $this->sortListeners($eventName);
- }
-
- return $this->sorted[$eventName];
- }
-
- foreach (array_keys($this->listeners) as $eventName) {
- if (!isset($this->sorted[$eventName])) {
- $this->sortListeners($eventName);
- }
- }
-
- return $this->sorted;
- }
-
- /**
- * @see EventDispatcherInterface::hasListeners
- */
- public function hasListeners($eventName = null)
- {
- return (Boolean) count($this->getListeners($eventName));
- }
-
- /**
- * @see EventDispatcherInterface::addListener
- *
- * @api
- */
- public function addListener($eventName, $listener, $priority = 0)
- {
- $this->listeners[$eventName][$priority][] = $listener;
- unset($this->sorted[$eventName]);
- }
-
- /**
- * @see EventDispatcherInterface::removeListener
- */
- public function removeListener($eventName, $listener)
- {
- if (!isset($this->listeners[$eventName])) {
- return;
- }
-
- foreach ($this->listeners[$eventName] as $priority => $listeners) {
- if (false !== ($key = array_search($listener, $listeners, true))) {
- unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]);
- }
- }
- }
-
- /**
- * @see EventDispatcherInterface::addSubscriber
- *
- * @api
- */
- public function addSubscriber(EventSubscriberInterface $subscriber)
- {
- foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
- if (is_string($params)) {
- $this->addListener($eventName, array($subscriber, $params));
- } elseif (is_string($params[0])) {
- $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
- } else {
- foreach ($params as $listener) {
- $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
- }
- }
- }
- }
-
- /**
- * @see EventDispatcherInterface::removeSubscriber
- */
- public function removeSubscriber(EventSubscriberInterface $subscriber)
- {
- foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
- if (is_array($params) && is_array($params[0])) {
- foreach ($params as $listener) {
- $this->removeListener($eventName, array($subscriber, $listener[0]));
- }
- } else {
- $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
- }
- }
- }
-
- /**
- * Triggers the listeners of an event.
- *
- * This method can be overridden to add functionality that is executed
- * for each listener.
- *
- * @param array[callback] $listeners The event listeners.
- * @param string $eventName The name of the event to dispatch.
- * @param Event $event The event object to pass to the event handlers/listeners.
- */
- protected function doDispatch($listeners, $eventName, Event $event)
- {
- foreach ($listeners as $listener) {
- call_user_func($listener, $event);
- if ($event->isPropagationStopped()) {
- break;
- }
- }
- }
-
- /**
- * Sorts the internal list of listeners for the given event by priority.
- *
- * @param string $eventName The name of the event.
- */
- private function sortListeners($eventName)
- {
- $this->sorted[$eventName] = array();
-
- if (isset($this->listeners[$eventName])) {
- krsort($this->listeners[$eventName]);
- $this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-/**
- * The EventDispatcherInterface is the central point of Symfony's event listener system.
- * Listeners are registered on the manager and events are dispatched through the
- * manager.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @api
- */
-interface EventDispatcherInterface
-{
- /**
- * Dispatches an event to all registered listeners.
- *
- * @param string $eventName The name of the event to dispatch. The name of
- * the event is the name of the method that is
- * invoked on listeners.
- * @param Event $event The event to pass to the event handlers/listeners.
- * If not supplied, an empty Event instance is created.
- *
- * @return Event
- *
- * @api
- */
- public function dispatch($eventName, Event $event = null);
-
- /**
- * Adds an event listener that listens on the specified events.
- *
- * @param string $eventName The event to listen on
- * @param callable $listener The listener
- * @param integer $priority The higher this value, the earlier an event
- * listener will be triggered in the chain (defaults to 0)
- *
- * @api
- */
- public function addListener($eventName, $listener, $priority = 0);
-
- /**
- * Adds an event subscriber.
- *
- * The subscriber is asked for all the events he is
- * interested in and added as a listener for these events.
- *
- * @param EventSubscriberInterface $subscriber The subscriber.
- *
- * @api
- */
- public function addSubscriber(EventSubscriberInterface $subscriber);
-
- /**
- * Removes an event listener from the specified events.
- *
- * @param string|array $eventName The event(s) to remove a listener from
- * @param callable $listener The listener to remove
- */
- public function removeListener($eventName, $listener);
-
- /**
- * Removes an event subscriber.
- *
- * @param EventSubscriberInterface $subscriber The subscriber
- */
- public function removeSubscriber(EventSubscriberInterface $subscriber);
-
- /**
- * Gets the listeners of a specific event or all listeners.
- *
- * @param string $eventName The name of the event
- *
- * @return array The event listeners for the specified event, or all event listeners by event name
- */
- public function getListeners($eventName = null);
-
- /**
- * Checks whether an event has any registered listeners.
- *
- * @param string $eventName The name of the event
- *
- * @return Boolean true if the specified event has any listeners, false otherwise
- */
- public function hasListeners($eventName = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-/**
- * An EventSubscriber knows himself what events he is interested in.
- * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes
- * {@link getSubscribedEvents} and registers the subscriber as a listener for all
- * returned events.
- *
- * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
- * @author Jonathan Wage <jonwage@gmail.com>
- * @author Roman Borschel <roman@code-factory.org>
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @api
- */
-interface EventSubscriberInterface
-{
- /**
- * Returns an array of event names this subscriber wants to listen to.
- *
- * The array keys are event names and the value can be:
- *
- * * The method name to call (priority defaults to 0)
- * * An array composed of the method name to call and the priority
- * * An array of arrays composed of the method names to call and respective
- * priorities, or 0 if unset
- *
- * For instance:
- *
- * * array('eventName' => 'methodName')
- * * array('eventName' => array('methodName', $priority))
- * * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
- *
- * @return array The event names to listen to
- *
- * @api
- */
- public static function getSubscribedEvents();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-/**
- * Event encapsulation class.
- *
- * Encapsulates events thus decoupling the observer from the subject they encapsulate.
- *
- * @author Drak <drak@zikula.org>
- */
-class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
-{
- /**
- * Observer pattern subject.
- *
- * @var mixed usually object or callable
- */
- protected $subject;
-
- /**
- * Array of arguments.
- *
- * @var array
- */
- protected $arguments;
-
- /**
- * Encapsulate an event with $subject and $args.
- *
- * @param mixed $subject The subject of the event, usually an object.
- * @param array $arguments Arguments to store in the event.
- */
- public function __construct($subject = null, array $arguments = array())
- {
- $this->subject = $subject;
- $this->arguments = $arguments;
- }
-
- /**
- * Getter for subject property.
- *
- * @return mixed $subject The observer subject.
- */
- public function getSubject()
- {
- return $this->subject;
- }
-
- /**
- * Get argument by key.
- *
- * @param string $key Key.
- *
- * @throws \InvalidArgumentException If key is not found.
- *
- * @return mixed Contents of array key.
- */
- public function getArgument($key)
- {
- if ($this->hasArgument($key)) {
- return $this->arguments[$key];
- }
-
- throw new \InvalidArgumentException(sprintf('%s not found in %s', $key, $this->getName()));
- }
-
- /**
- * Add argument to event.
- *
- * @param string $key Argument name.
- * @param mixed $value Value.
- *
- * @return GenericEvent
- */
- public function setArgument($key, $value)
- {
- $this->arguments[$key] = $value;
-
- return $this;
- }
-
- /**
- * Getter for all arguments.
- *
- * @return array
- */
- public function getArguments()
- {
- return $this->arguments;
- }
-
- /**
- * Set args property.
- *
- * @param array $args Arguments.
- *
- * @return GenericEvent
- */
- public function setArguments(array $args = array())
- {
- $this->arguments = $args;
-
- return $this;
- }
-
- /**
- * Has argument.
- *
- * @param string $key Key of arguments array.
- *
- * @return boolean
- */
- public function hasArgument($key)
- {
- return array_key_exists($key, $this->arguments);
- }
-
- /**
- * ArrayAccess for argument getter.
- *
- * @param string $key Array key.
- *
- * @throws \InvalidArgumentException If key does not exist in $this->args.
- *
- * @return mixed
- */
- public function offsetGet($key)
- {
- return $this->getArgument($key);
- }
-
- /**
- * ArrayAccess for argument setter.
- *
- * @param string $key Array key to set.
- * @param mixed $value Value.
- */
- public function offsetSet($key, $value)
- {
- $this->setArgument($key, $value);
- }
-
- /**
- * ArrayAccess for unset argument.
- *
- * @param string $key Array key.
- */
- public function offsetUnset($key)
- {
- if ($this->hasArgument($key)) {
- unset($this->arguments[$key]);
- }
- }
-
- /**
- * ArrayAccess has argument.
- *
- * @param string $key Array key.
- *
- * @return boolean
- */
- public function offsetExists($key)
- {
- return $this->hasArgument($key);
- }
-
- /**
- * IteratorAggregate for iterating over the object like an array
- *
- * @return \ArrayIterator
- */
- public function getIterator()
- {
- return new \ArrayIterator($this->arguments);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-/**
- * A read-only proxy for an event dispatcher.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ImmutableEventDispatcher implements EventDispatcherInterface
-{
- /**
- * The proxied dispatcher.
- * @var EventDispatcherInterface
- */
- private $dispatcher;
-
- /**
- * Creates an unmodifiable proxy for an event dispatcher.
- *
- * @param EventDispatcherInterface $dispatcher The proxied event dispatcher.
- */
- public function __construct(EventDispatcherInterface $dispatcher)
- {
- $this->dispatcher = $dispatcher;
- }
-
- /**
- * {@inheritdoc}
- */
- public function dispatch($eventName, Event $event = null)
- {
- return $this->dispatcher->dispatch($eventName, $event);
- }
-
- /**
- * {@inheritdoc}
- */
- public function addListener($eventName, $listener, $priority = 0)
- {
- throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
- }
-
- /**
- * {@inheritdoc}
- */
- public function addSubscriber(EventSubscriberInterface $subscriber)
- {
- throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
- }
-
- /**
- * {@inheritdoc}
- */
- public function removeListener($eventName, $listener)
- {
- throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
- }
-
- /**
- * {@inheritdoc}
- */
- public function removeSubscriber(EventSubscriberInterface $subscriber)
- {
- throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
- }
-
- /**
- * {@inheritdoc}
- */
- public function getListeners($eventName = null)
- {
- return $this->dispatcher->getListeners($eventName);
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasListeners($eventName = null)
- {
- return $this->dispatcher->hasListeners($eventName);
- }
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-EventDispatcher Component
-=========================
-
-EventDispatcher implements a lightweight version of the Observer design
-pattern.
-
- use Symfony\Component\EventDispatcher\EventDispatcher;
- use Symfony\Component\EventDispatcher\Event;
-
- $dispatcher = new EventDispatcher();
-
- $dispatcher->addListener('event_name', function (Event $event) {
- // ...
- });
-
- $dispatcher->dispatch('event_name');
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/EventDispatcher/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher\Tests;
-
-use Symfony\Component\DependencyInjection\Container;
-use Symfony\Component\DependencyInjection\Scope;
-use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
-use Symfony\Component\EventDispatcher\Event;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-class ContainerAwareEventDispatcherTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\DependencyInjection\Container')) {
- $this->markTestSkipped('The "DependencyInjection" component is not available');
- }
- }
-
- public function testAddAListenerService()
- {
- $event = new Event();
-
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $service
- ->expects($this->once())
- ->method('onEvent')
- ->with($event)
- ;
-
- $container = new Container();
- $container->set('service.listener', $service);
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
-
- $dispatcher->dispatch('onEvent', $event);
- }
-
- public function testAddASubscriberService()
- {
- $event = new Event();
-
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\SubscriberService');
-
- $service
- ->expects($this->once())
- ->method('onEvent')
- ->with($event)
- ;
-
- $container = new Container();
- $container->set('service.subscriber', $service);
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService');
-
- $dispatcher->dispatch('onEvent', $event);
- }
-
- public function testPreventDuplicateListenerService()
- {
- $event = new Event();
-
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $service
- ->expects($this->once())
- ->method('onEvent')
- ->with($event)
- ;
-
- $container = new Container();
- $container->set('service.listener', $service);
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 5);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 10);
-
- $dispatcher->dispatch('onEvent', $event);
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testTriggerAListenerServiceOutOfScope()
- {
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $scope = new Scope('scope');
- $container = new Container();
- $container->addScope($scope);
- $container->enterScope('scope');
-
- $container->set('service.listener', $service, 'scope');
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
-
- $container->leaveScope('scope');
- $dispatcher->dispatch('onEvent');
- }
-
- public function testReEnteringAScope()
- {
- $event = new Event();
-
- $service1 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $service1
- ->expects($this->exactly(2))
- ->method('onEvent')
- ->with($event)
- ;
-
- $scope = new Scope('scope');
- $container = new Container();
- $container->addScope($scope);
- $container->enterScope('scope');
-
- $container->set('service.listener', $service1, 'scope');
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
- $dispatcher->dispatch('onEvent', $event);
-
- $service2 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $service2
- ->expects($this->once())
- ->method('onEvent')
- ->with($event)
- ;
-
- $container->enterScope('scope');
- $container->set('service.listener', $service2, 'scope');
-
- $dispatcher->dispatch('onEvent', $event);
-
- $container->leaveScope('scope');
-
- $dispatcher->dispatch('onEvent');
- }
-
- public function testHasListenersOnLazyLoad()
- {
- $event = new Event();
-
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $container = new Container();
- $container->set('service.listener', $service);
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
-
- $event->setDispatcher($dispatcher);
- $event->setName('onEvent');
-
- $service
- ->expects($this->once())
- ->method('onEvent')
- ->with($event)
- ;
-
- $this->assertTrue($dispatcher->hasListeners());
-
- if ($dispatcher->hasListeners('onEvent')) {
- $dispatcher->dispatch('onEvent');
- }
- }
-
- public function testGetListenersOnLazyLoad()
- {
- $event = new Event();
-
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $container = new Container();
- $container->set('service.listener', $service);
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
-
- $listeners = $dispatcher->getListeners();
-
- $this->assertTrue(isset($listeners['onEvent']));
-
- $this->assertCount(1, $dispatcher->getListeners('onEvent'));
- }
-
- public function testRemoveAfterDispatch()
- {
- $event = new Event();
-
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $container = new Container();
- $container->set('service.listener', $service);
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
-
- $dispatcher->dispatch('onEvent', new Event());
- $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent'));
- $this->assertFalse($dispatcher->hasListeners('onEvent'));
- }
-
- public function testRemoveBeforeDispatch()
- {
- $event = new Event();
-
- $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service');
-
- $container = new Container();
- $container->set('service.listener', $service);
-
- $dispatcher = new ContainerAwareEventDispatcher($container);
- $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
-
- $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent'));
- $this->assertFalse($dispatcher->hasListeners('onEvent'));
- }
-}
-
-class Service
-{
- public function onEvent(Event $e)
- {
- }
-}
-
-class SubscriberService implements EventSubscriberInterface
-{
- public static function getSubscribedEvents()
- {
- return array(
- 'onEvent' => 'onEvent',
- 'onEvent' => array('onEvent', 10),
- 'onEvent' => array('onEvent'),
- );
- }
-
- public function onEvent(Event $e)
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher\Tests;
-
-use Symfony\Component\EventDispatcher\Event;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-class EventDispatcherTest extends \PHPUnit_Framework_TestCase
-{
- /* Some pseudo events */
- const preFoo = 'pre.foo';
- const postFoo = 'post.foo';
- const preBar = 'pre.bar';
- const postBar = 'post.bar';
-
- private $dispatcher;
-
- private $listener;
-
- protected function setUp()
- {
- $this->dispatcher = new EventDispatcher();
- $this->listener = new TestEventListener();
- }
-
- protected function tearDown()
- {
- $this->dispatcher = null;
- $this->listener = null;
- }
-
- public function testInitialState()
- {
- $this->assertEquals(array(), $this->dispatcher->getListeners());
- $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
- $this->assertFalse($this->dispatcher->hasListeners(self::postFoo));
- }
-
- public function testAddListener()
- {
- $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo'));
- $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'));
- $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
- $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
- $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo));
- $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo));
- $this->assertCount(2, $this->dispatcher->getListeners());
- }
-
- public function testGetListenersSortsByPriority()
- {
- $listener1 = new TestEventListener();
- $listener2 = new TestEventListener();
- $listener3 = new TestEventListener();
- $listener1->name = '1';
- $listener2->name = '2';
- $listener3->name = '3';
-
- $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10);
- $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10);
- $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo'));
-
- $expected = array(
- array($listener2, 'preFoo'),
- array($listener3, 'preFoo'),
- array($listener1, 'preFoo'),
- );
-
- $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo'));
- }
-
- public function testGetAllListenersSortsByPriority()
- {
- $listener1 = new TestEventListener();
- $listener2 = new TestEventListener();
- $listener3 = new TestEventListener();
- $listener4 = new TestEventListener();
- $listener5 = new TestEventListener();
- $listener6 = new TestEventListener();
-
- $this->dispatcher->addListener('pre.foo', $listener1, -10);
- $this->dispatcher->addListener('pre.foo', $listener2);
- $this->dispatcher->addListener('pre.foo', $listener3, 10);
- $this->dispatcher->addListener('post.foo', $listener4, -10);
- $this->dispatcher->addListener('post.foo', $listener5);
- $this->dispatcher->addListener('post.foo', $listener6, 10);
-
- $expected = array(
- 'pre.foo' => array($listener3, $listener2, $listener1),
- 'post.foo' => array($listener6, $listener5, $listener4),
- );
-
- $this->assertSame($expected, $this->dispatcher->getListeners());
- }
-
- public function testDispatch()
- {
- $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo'));
- $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'));
- $this->dispatcher->dispatch(self::preFoo);
- $this->assertTrue($this->listener->preFooInvoked);
- $this->assertFalse($this->listener->postFooInvoked);
- $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent'));
- $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo));
- $event = new Event();
- $return = $this->dispatcher->dispatch(self::preFoo, $event);
- $this->assertEquals('pre.foo', $event->getName());
- $this->assertSame($event, $return);
- }
-
- public function testDispatchForClosure()
- {
- $invoked = 0;
- $listener = function () use (&$invoked) {
- $invoked++;
- };
- $this->dispatcher->addListener('pre.foo', $listener);
- $this->dispatcher->addListener('post.foo', $listener);
- $this->dispatcher->dispatch(self::preFoo);
- $this->assertEquals(1, $invoked);
- }
-
- public function testStopEventPropagation()
- {
- $otherListener = new TestEventListener();
-
- // postFoo() stops the propagation, so only one listener should
- // be executed
- // Manually set priority to enforce $this->listener to be called first
- $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10);
- $this->dispatcher->addListener('post.foo', array($otherListener, 'preFoo'));
- $this->dispatcher->dispatch(self::postFoo);
- $this->assertTrue($this->listener->postFooInvoked);
- $this->assertFalse($otherListener->postFooInvoked);
- }
-
- public function testDispatchByPriority()
- {
- $invoked = array();
- $listener1 = function () use (&$invoked) {
- $invoked[] = '1';
- };
- $listener2 = function () use (&$invoked) {
- $invoked[] = '2';
- };
- $listener3 = function () use (&$invoked) {
- $invoked[] = '3';
- };
- $this->dispatcher->addListener('pre.foo', $listener1, -10);
- $this->dispatcher->addListener('pre.foo', $listener2);
- $this->dispatcher->addListener('pre.foo', $listener3, 10);
- $this->dispatcher->dispatch(self::preFoo);
- $this->assertEquals(array('3', '2', '1'), $invoked);
- }
-
- public function testRemoveListener()
- {
- $this->dispatcher->addListener('pre.bar', $this->listener);
- $this->assertTrue($this->dispatcher->hasListeners(self::preBar));
- $this->dispatcher->removeListener('pre.bar', $this->listener);
- $this->assertFalse($this->dispatcher->hasListeners(self::preBar));
- $this->dispatcher->removeListener('notExists', $this->listener);
- }
-
- public function testAddSubscriber()
- {
- $eventSubscriber = new TestEventSubscriber();
- $this->dispatcher->addSubscriber($eventSubscriber);
- $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
- $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
- }
-
- public function testAddSubscriberWithPriorities()
- {
- $eventSubscriber = new TestEventSubscriber();
- $this->dispatcher->addSubscriber($eventSubscriber);
-
- $eventSubscriber = new TestEventSubscriberWithPriorities();
- $this->dispatcher->addSubscriber($eventSubscriber);
-
- $listeners = $this->dispatcher->getListeners('pre.foo');
- $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
- $this->assertCount(2, $listeners);
- $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]);
- }
-
- public function testAddSubscriberWithMultipleListeners()
- {
- $eventSubscriber = new TestEventSubscriberWithMultipleListeners();
- $this->dispatcher->addSubscriber($eventSubscriber);
-
- $listeners = $this->dispatcher->getListeners('pre.foo');
- $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
- $this->assertCount(2, $listeners);
- $this->assertEquals('preFoo2', $listeners[0][1]);
- }
-
- public function testRemoveSubscriber()
- {
- $eventSubscriber = new TestEventSubscriber();
- $this->dispatcher->addSubscriber($eventSubscriber);
- $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
- $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
- $this->dispatcher->removeSubscriber($eventSubscriber);
- $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
- $this->assertFalse($this->dispatcher->hasListeners(self::postFoo));
- }
-
- public function testRemoveSubscriberWithPriorities()
- {
- $eventSubscriber = new TestEventSubscriberWithPriorities();
- $this->dispatcher->addSubscriber($eventSubscriber);
- $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
- $this->dispatcher->removeSubscriber($eventSubscriber);
- $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
- }
-
- public function testRemoveSubscriberWithMultipleListeners()
- {
- $eventSubscriber = new TestEventSubscriberWithMultipleListeners();
- $this->dispatcher->addSubscriber($eventSubscriber);
- $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
- $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo));
- $this->dispatcher->removeSubscriber($eventSubscriber);
- $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
- }
-
- public function testEventReceivesTheDispatcherInstance()
- {
- $test = $this;
- $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) {
- $dispatcher = $event->getDispatcher();
- });
- $this->dispatcher->dispatch('test');
- $this->assertSame($this->dispatcher, $dispatcher);
- }
-
- /**
- * @see https://bugs.php.net/bug.php?id=62976
- *
- * This bug affects:
- * - The PHP 5.3 branch for versions < 5.3.18
- * - The PHP 5.4 branch for versions < 5.4.8
- * - The PHP 5.5 branch is not affected
- */
- public function testWorkaroundForPhpBug62976()
- {
- $dispatcher = new EventDispatcher();
- $dispatcher->addListener('bug.62976', new CallableClass());
- $dispatcher->removeListener('bug.62976', function() {});
- $this->assertTrue($dispatcher->hasListeners('bug.62976'));
- }
-}
-
-class CallableClass
-{
- public function __invoke()
- {
- }
-}
-
-class TestEventListener
-{
- public $preFooInvoked = false;
- public $postFooInvoked = false;
-
- /* Listener methods */
-
- public function preFoo(Event $e)
- {
- $this->preFooInvoked = true;
- }
-
- public function postFoo(Event $e)
- {
- $this->postFooInvoked = true;
-
- $e->stopPropagation();
- }
-}
-
-class TestEventSubscriber implements EventSubscriberInterface
-{
- public static function getSubscribedEvents()
- {
- return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo');
- }
-}
-
-class TestEventSubscriberWithPriorities implements EventSubscriberInterface
-{
- public static function getSubscribedEvents()
- {
- return array(
- 'pre.foo' => array('preFoo', 10),
- 'post.foo' => array('postFoo'),
- );
- }
-}
-
-class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface
-{
- public static function getSubscribedEvents()
- {
- return array('pre.foo' => array(
- array('preFoo1'),
- array('preFoo2', 10)
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher\Tests;
-
-use Symfony\Component\EventDispatcher\Event;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-
-/**
- * Test class for Event.
- */
-class EventTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \Symfony\Component\EventDispatcher\Event
- */
- protected $event;
-
- /**
- * @var \Symfony\Component\EventDispatcher\EventDispatcher
- */
- protected $dispatcher;
-
- /**
- * Sets up the fixture, for example, opens a network connection.
- * This method is called before a test is executed.
- */
- protected function setUp()
- {
- $this->event = new Event;
- $this->dispatcher = new EventDispatcher();
- }
-
- /**
- * Tears down the fixture, for example, closes a network connection.
- * This method is called after a test is executed.
- */
- protected function tearDown()
- {
- $this->event = null;
- $this->eventDispatcher = null;
- }
-
- public function testIsPropagationStopped()
- {
- $this->assertFalse($this->event->isPropagationStopped());
- }
-
- public function testStopPropagationAndIsPropagationStopped()
- {
- $this->event->stopPropagation();
- $this->assertTrue($this->event->isPropagationStopped());
- }
-
- public function testSetDispatcher()
- {
- $this->event->setDispatcher($this->dispatcher);
- $this->assertSame($this->dispatcher, $this->event->getDispatcher());
- }
-
- public function testGetDispatcher()
- {
- $this->assertNull($this->event->getDispatcher());
- }
-
- public function testGetName()
- {
- $this->assertNull($this->event->getName());
- }
-
- public function testSetName()
- {
- $this->event->setName('foo');
- $this->assertEquals('foo', $this->event->getName());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher\Tests;
-
-use Symfony\Component\EventDispatcher\GenericEvent;
-
-/**
- * Test class for Event.
- */
-class GenericEventTest extends \PHPUnit_Framework_TestCase
-{
-
- /**
- * @var GenericEvent
- */
- private $event;
-
- private $subject;
-
- /**
- * Prepares the environment before running a test.
- */
- protected function setUp()
- {
- parent::setUp();
-
- $this->subject = new \StdClass();
- $this->event = new GenericEvent($this->subject, array('name' => 'Event'), 'foo');
- }
-
- /**
- * Cleans up the environment after running a test.
- */
- protected function tearDown()
- {
- $this->subject = null;
- $this->event = null;
-
- parent::tearDown();
- }
-
- public function testConstruct()
- {
- $this->assertEquals($this->event, new GenericEvent($this->subject, array('name' => 'Event')));
- }
-
- /**
- * Tests Event->getArgs()
- */
- public function testGetArguments()
- {
- // test getting all
- $this->assertSame(array('name' => 'Event'), $this->event->getArguments());
- }
-
- public function testSetArguments()
- {
- $result = $this->event->setArguments(array('foo' => 'bar'));
- $this->assertAttributeSame(array('foo' => 'bar'), 'arguments', $this->event);
- $this->assertSame($this->event, $result);
- }
-
- public function testSetArgument()
- {
- $result = $this->event->setArgument('foo2', 'bar2');
- $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event);
- $this->assertEquals($this->event, $result);
- }
-
- public function testGetArgument()
- {
- // test getting key
- $this->assertEquals('Event', $this->event->getArgument('name'));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testGetArgException()
- {
- $this->event->getArgument('nameNotExist');
- }
-
- public function testOffsetGet()
- {
- // test getting key
- $this->assertEquals('Event', $this->event['name']);
-
- // test getting invalid arg
- $this->setExpectedException('InvalidArgumentException');
- $this->assertFalse($this->event['nameNotExist']);
- }
-
- public function testOffsetSet()
- {
- $this->event['foo2'] = 'bar2';
- $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event);
- }
-
- public function testOffsetUnset()
- {
- unset($this->event['name']);
- $this->assertAttributeSame(array(), 'arguments', $this->event);
- }
-
- public function testOffsetIsset()
- {
- $this->assertTrue(isset($this->event['name']));
- $this->assertFalse(isset($this->event['nameNotExist']));
- }
-
- public function testHasArgument()
- {
- $this->assertTrue($this->event->hasArgument('name'));
- $this->assertFalse($this->event->hasArgument('nameNotExist'));
- }
-
- public function testGetSubject()
- {
- $this->assertSame($this->subject, $this->event->getSubject());
- }
-
- public function testHasIterator()
- {
- $data = array();
- foreach ($this->event as $key => $value) {
- $data[$key] = $value;
- }
- $this->assertEquals(array('name' => 'Event'), $data);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher\Tests;
-
-use Symfony\Component\EventDispatcher\Event;
-use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ImmutableEventDispatcherTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $innerDispatcher;
-
- /**
- * @var ImmutableEventDispatcher
- */
- private $dispatcher;
-
- protected function setUp()
- {
- $this->innerDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->dispatcher = new ImmutableEventDispatcher($this->innerDispatcher);
- }
-
- public function testDispatchDelegates()
- {
- $event = new Event();
-
- $this->innerDispatcher->expects($this->once())
- ->method('dispatch')
- ->with('event', $event)
- ->will($this->returnValue('result'));
-
- $this->assertSame('result', $this->dispatcher->dispatch('event', $event));
- }
-
- public function testGetListenersDelegates()
- {
- $this->innerDispatcher->expects($this->once())
- ->method('getListeners')
- ->with('event')
- ->will($this->returnValue('result'));
-
- $this->assertSame('result', $this->dispatcher->getListeners('event'));
- }
-
- public function testHasListenersDelegates()
- {
- $this->innerDispatcher->expects($this->once())
- ->method('hasListeners')
- ->with('event')
- ->will($this->returnValue('result'));
-
- $this->assertSame('result', $this->dispatcher->hasListeners('event'));
- }
-
- /**
- * @expectedException \BadMethodCallException
- */
- public function testAddListenerDisallowed()
- {
- $this->dispatcher->addListener('event', function () { return 'foo'; });
- }
-
- /**
- * @expectedException \BadMethodCallException
- */
- public function testAddSubscriberDisallowed()
- {
- $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface');
-
- $this->dispatcher->addSubscriber($subscriber);
- }
-
- /**
- * @expectedException \BadMethodCallException
- */
- public function testRemoveListenerDisallowed()
- {
- $this->dispatcher->removeListener('event', function () { return 'foo'; });
- }
-
- /**
- * @expectedException \BadMethodCallException
- */
- public function testRemoveSubscriberDisallowed()
- {
- $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface');
-
- $this->dispatcher->removeSubscriber($subscriber);
- }
-}
+++ /dev/null
-{
- "name": "symfony/event-dispatcher",
- "type": "library",
- "description": "Symfony EventDispatcher Component",
- "keywords": [],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "symfony/dependency-injection": "~2.0"
- },
- "suggest": {
- "symfony/dependency-injection": "",
- "symfony/http-kernel": ""
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\EventDispatcher\\": "" }
- },
- "target-dir": "Symfony/Component/EventDispatcher",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony EventDispatcher Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./Resources</directory>
- <directory>./Tests</directory>
- <directory>./vendor</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-CHANGELOG
-=========
-
-2.3.0
------
-
- * added the dumpFile() method to atomically write files
-
-2.2.0
------
-
- * added a delete option for the mirror() method
-
-2.1.0
------
-
- * 24eb396 : BC Break : mkdir() function now throws exception in case of failure instead of returning Boolean value
- * created the component
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Filesystem\Exception;
-
-/**
- * Exception interface for all exceptions thrown by the component.
- *
- * @author Romain Neutron <imprec@gmail.com>
- *
- * @api
- */
-interface ExceptionInterface
-{
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Filesystem\Exception;
-
-/**
- * Exception class thrown when a filesystem operation failure happens
- *
- * @author Romain Neutron <imprec@gmail.com>
- *
- * @api
- */
-class IOException extends \RuntimeException implements ExceptionInterface
-{
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Filesystem;
-
-use Symfony\Component\Filesystem\Exception\IOException;
-
-/**
- * Provides basic utility to manipulate the file system.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Filesystem
-{
- /**
- * Copies a file.
- *
- * This method only copies the file if the origin file is newer than the target file.
- *
- * By default, if the target already exists, it is not overridden.
- *
- * @param string $originFile The original filename
- * @param string $targetFile The target filename
- * @param boolean $override Whether to override an existing file or not
- *
- * @throws IOException When copy fails
- */
- public function copy($originFile, $targetFile, $override = false)
- {
- if (stream_is_local($originFile) && !is_file($originFile)) {
- throw new IOException(sprintf('Failed to copy %s because file not exists', $originFile));
- }
-
- $this->mkdir(dirname($targetFile));
-
- if (!$override && is_file($targetFile)) {
- $doCopy = filemtime($originFile) > filemtime($targetFile);
- } else {
- $doCopy = true;
- }
-
- if ($doCopy) {
- // https://bugs.php.net/bug.php?id=64634
- $source = fopen($originFile, 'r');
- $target = fopen($targetFile, 'w+');
- stream_copy_to_stream($source, $target);
- fclose($source);
- fclose($target);
- unset($source, $target);
-
- if (!is_file($targetFile)) {
- throw new IOException(sprintf('Failed to copy %s to %s', $originFile, $targetFile));
- }
- }
- }
-
- /**
- * Creates a directory recursively.
- *
- * @param string|array|\Traversable $dirs The directory path
- * @param integer $mode The directory mode
- *
- * @throws IOException On any directory creation failure
- */
- public function mkdir($dirs, $mode = 0777)
- {
- foreach ($this->toIterator($dirs) as $dir) {
- if (is_dir($dir)) {
- continue;
- }
-
- if (true !== @mkdir($dir, $mode, true)) {
- throw new IOException(sprintf('Failed to create %s', $dir));
- }
- }
- }
-
- /**
- * Checks the existence of files or directories.
- *
- * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to check
- *
- * @return Boolean true if the file exists, false otherwise
- */
- public function exists($files)
- {
- foreach ($this->toIterator($files) as $file) {
- if (!file_exists($file)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Sets access and modification time of file.
- *
- * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create
- * @param integer $time The touch time as a unix timestamp
- * @param integer $atime The access time as a unix timestamp
- *
- * @throws IOException When touch fails
- */
- public function touch($files, $time = null, $atime = null)
- {
- foreach ($this->toIterator($files) as $file) {
- $touch = $time ? @touch($file, $time, $atime) : @touch($file);
- if (true !== $touch) {
- throw new IOException(sprintf('Failed to touch %s', $file));
- }
- }
- }
-
- /**
- * Removes files or directories.
- *
- * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove
- *
- * @throws IOException When removal fails
- */
- public function remove($files)
- {
- $files = iterator_to_array($this->toIterator($files));
- $files = array_reverse($files);
- foreach ($files as $file) {
- if (!file_exists($file) && !is_link($file)) {
- continue;
- }
-
- if (is_dir($file) && !is_link($file)) {
- $this->remove(new \FilesystemIterator($file));
-
- if (true !== @rmdir($file)) {
- throw new IOException(sprintf('Failed to remove directory %s', $file));
- }
- } else {
- // https://bugs.php.net/bug.php?id=52176
- if (defined('PHP_WINDOWS_VERSION_MAJOR') && is_dir($file)) {
- if (true !== @rmdir($file)) {
- throw new IOException(sprintf('Failed to remove file %s', $file));
- }
- } else {
- if (true !== @unlink($file)) {
- throw new IOException(sprintf('Failed to remove file %s', $file));
- }
- }
- }
- }
- }
-
- /**
- * Change mode for an array of files or directories.
- *
- * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode
- * @param integer $mode The new mode (octal)
- * @param integer $umask The mode mask (octal)
- * @param Boolean $recursive Whether change the mod recursively or not
- *
- * @throws IOException When the change fail
- */
- public function chmod($files, $mode, $umask = 0000, $recursive = false)
- {
- foreach ($this->toIterator($files) as $file) {
- if ($recursive && is_dir($file) && !is_link($file)) {
- $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
- }
- if (true !== @chmod($file, $mode & ~$umask)) {
- throw new IOException(sprintf('Failed to chmod file %s', $file));
- }
- }
- }
-
- /**
- * Change the owner of an array of files or directories
- *
- * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change owner
- * @param string $user The new owner user name
- * @param Boolean $recursive Whether change the owner recursively or not
- *
- * @throws IOException When the change fail
- */
- public function chown($files, $user, $recursive = false)
- {
- foreach ($this->toIterator($files) as $file) {
- if ($recursive && is_dir($file) && !is_link($file)) {
- $this->chown(new \FilesystemIterator($file), $user, true);
- }
- if (is_link($file) && function_exists('lchown')) {
- if (true !== @lchown($file, $user)) {
- throw new IOException(sprintf('Failed to chown file %s', $file));
- }
- } else {
- if (true !== @chown($file, $user)) {
- throw new IOException(sprintf('Failed to chown file %s', $file));
- }
- }
- }
- }
-
- /**
- * Change the group of an array of files or directories
- *
- * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change group
- * @param string $group The group name
- * @param Boolean $recursive Whether change the group recursively or not
- *
- * @throws IOException When the change fail
- */
- public function chgrp($files, $group, $recursive = false)
- {
- foreach ($this->toIterator($files) as $file) {
- if ($recursive && is_dir($file) && !is_link($file)) {
- $this->chgrp(new \FilesystemIterator($file), $group, true);
- }
- if (is_link($file) && function_exists('lchgrp')) {
- if (true !== @lchgrp($file, $group)) {
- throw new IOException(sprintf('Failed to chgrp file %s', $file));
- }
- } else {
- if (true !== @chgrp($file, $group)) {
- throw new IOException(sprintf('Failed to chgrp file %s', $file));
- }
- }
- }
- }
-
- /**
- * Renames a file or a directory.
- *
- * @param string $origin The origin filename or directory
- * @param string $target The new filename or directory
- * @param Boolean $overwrite Whether to overwrite the target if it already exists
- *
- * @throws IOException When target file or directory already exists
- * @throws IOException When origin cannot be renamed
- */
- public function rename($origin, $target, $overwrite = false)
- {
- // we check that target does not exist
- if (!$overwrite && is_readable($target)) {
- throw new IOException(sprintf('Cannot rename because the target "%s" already exist.', $target));
- }
-
- if (true !== @rename($origin, $target)) {
- throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target));
- }
- }
-
- /**
- * Creates a symbolic link or copy a directory.
- *
- * @param string $originDir The origin directory path
- * @param string $targetDir The symbolic link name
- * @param Boolean $copyOnWindows Whether to copy files if on Windows
- *
- * @throws IOException When symlink fails
- */
- public function symlink($originDir, $targetDir, $copyOnWindows = false)
- {
- if (!function_exists('symlink') && $copyOnWindows) {
- $this->mirror($originDir, $targetDir);
-
- return;
- }
-
- $this->mkdir(dirname($targetDir));
-
- $ok = false;
- if (is_link($targetDir)) {
- if (readlink($targetDir) != $originDir) {
- $this->remove($targetDir);
- } else {
- $ok = true;
- }
- }
-
- if (!$ok) {
- if (true !== @symlink($originDir, $targetDir)) {
- $report = error_get_last();
- if (is_array($report)) {
- if (defined('PHP_WINDOWS_VERSION_MAJOR') && false !== strpos($report['message'], 'error code(1314)')) {
- throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?');
- }
- }
- throw new IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir));
- }
- }
- }
-
- /**
- * Given an existing path, convert it to a path relative to a given starting path
- *
- * @param string $endPath Absolute path of target
- * @param string $startPath Absolute path where traversal begins
- *
- * @return string Path of target relative to starting path
- */
- public function makePathRelative($endPath, $startPath)
- {
- // Normalize separators on windows
- if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
- $endPath = strtr($endPath, '\\', '/');
- $startPath = strtr($startPath, '\\', '/');
- }
-
- // Split the paths into arrays
- $startPathArr = explode('/', trim($startPath, '/'));
- $endPathArr = explode('/', trim($endPath, '/'));
-
- // Find for which directory the common path stops
- $index = 0;
- while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
- $index++;
- }
-
- // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
- $depth = count($startPathArr) - $index;
-
- // Repeated "../" for each level need to reach the common path
- $traverser = str_repeat('../', $depth);
-
- $endPathRemainder = implode('/', array_slice($endPathArr, $index));
-
- // Construct $endPath from traversing to the common path, then to the remaining $endPath
- $relativePath = $traverser.(strlen($endPathRemainder) > 0 ? $endPathRemainder.'/' : '');
-
- return (strlen($relativePath) === 0) ? './' : $relativePath;
- }
-
- /**
- * Mirrors a directory to another.
- *
- * @param string $originDir The origin directory
- * @param string $targetDir The target directory
- * @param \Traversable $iterator A Traversable instance
- * @param array $options An array of boolean options
- * Valid options are:
- * - $options['override'] Whether to override an existing file on copy or not (see copy())
- * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink())
- * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
- *
- * @throws IOException When file type is unknown
- */
- public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
- {
- $targetDir = rtrim($targetDir, '/\\');
- $originDir = rtrim($originDir, '/\\');
-
- // Iterate in destination folder to remove obsolete entries
- if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
- $deleteIterator = $iterator;
- if (null === $deleteIterator) {
- $flags = \FilesystemIterator::SKIP_DOTS;
- $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
- }
- foreach ($deleteIterator as $file) {
- $origin = str_replace($targetDir, $originDir, $file->getPathname());
- if (!$this->exists($origin)) {
- $this->remove($file);
- }
- }
- }
-
- $copyOnWindows = false;
- if (isset($options['copy_on_windows']) && !function_exists('symlink')) {
- $copyOnWindows = $options['copy_on_windows'];
- }
-
- if (null === $iterator) {
- $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
- $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
- }
-
- foreach ($iterator as $file) {
- $target = str_replace($originDir, $targetDir, $file->getPathname());
-
- if ($copyOnWindows) {
- if (is_link($file) || is_file($file)) {
- $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
- } elseif (is_dir($file)) {
- $this->mkdir($target);
- } else {
- throw new IOException(sprintf('Unable to guess "%s" file type.', $file));
- }
- } else {
- if (is_link($file)) {
- $this->symlink($file, $target);
- } elseif (is_dir($file)) {
- $this->mkdir($target);
- } elseif (is_file($file)) {
- $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
- } else {
- throw new IOException(sprintf('Unable to guess "%s" file type.', $file));
- }
- }
- }
- }
-
- /**
- * Returns whether the file path is an absolute path.
- *
- * @param string $file A file path
- *
- * @return Boolean
- */
- public function isAbsolutePath($file)
- {
- if (strspn($file, '/\\', 0, 1)
- || (strlen($file) > 3 && ctype_alpha($file[0])
- && substr($file, 1, 1) === ':'
- && (strspn($file, '/\\', 2, 1))
- )
- || null !== parse_url($file, PHP_URL_SCHEME)
- ) {
- return true;
- }
-
- return false;
- }
-
- /**
- * @param mixed $files
- *
- * @return \Traversable
- */
- private function toIterator($files)
- {
- if (!$files instanceof \Traversable) {
- $files = new \ArrayObject(is_array($files) ? $files : array($files));
- }
-
- return $files;
- }
-
- /**
- * Atomically dumps content into a file.
- *
- * @param string $filename The file to be written to.
- * @param string $content The data to write into the file.
- * @param integer $mode The file mode (octal).
- * @throws IOException If the file cannot be written to.
- */
- public function dumpFile($filename, $content, $mode = 0666)
- {
- $dir = dirname($filename);
-
- if (!is_dir($dir)) {
- $this->mkdir($dir);
- } elseif (!is_writable($dir)) {
- throw new IOException(sprintf('Unable to write in the %s directory\n', $dir));
- }
-
- $tmpFile = tempnam($dir, basename($filename));
-
- if (false === @file_put_contents($tmpFile, $content)) {
- throw new IOException(sprintf('Failed to write file "%s".', $filename));
- }
-
- $this->rename($tmpFile, $filename, true);
- $this->chmod($filename, $mode);
- }
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-Filesystem Component
-====================
-
-Filesystem provides basic utility to manipulate the file system:
-
-```php
-<?php
-
-use Symfony\Component\Filesystem\Filesystem;
-
-$filesystem = new Filesystem();
-
-$filesystem->copy($originFile, $targetFile, $override = false);
-
-$filesystem->mkdir($dirs, $mode = 0777);
-
-$filesystem->touch($files, $time = null, $atime = null);
-
-$filesystem->remove($files);
-
-$filesystem->chmod($files, $mode, $umask = 0000, $recursive = false);
-
-$filesystem->chown($files, $user, $recursive = false);
-
-$filesystem->chgrp($files, $group, $recursive = false);
-
-$filesystem->rename($origin, $target);
-
-$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);
-
-$filesystem->makePathRelative($endPath, $startPath);
-
-$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());
-
-$filesystem->isAbsolutePath($file);
-```
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/Filesystem/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Filesystem\Tests;
-
-use Symfony\Component\Filesystem\Filesystem;
-
-/**
- * Test class for Filesystem.
- */
-class FilesystemTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var string $workspace
- */
- private $workspace = null;
-
- /**
- * @var \Symfony\Component\Filesystem\Filesystem $filesystem
- */
- private $filesystem = null;
-
- private static $symlinkOnWindows = null;
-
- public static function setUpBeforeClass()
- {
- if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
- self::$symlinkOnWindows = true;
- $originDir = tempnam(sys_get_temp_dir(), 'sl');
- $targetDir = tempnam(sys_get_temp_dir(), 'sl');
- if (true !== @symlink($originDir, $targetDir)) {
- $report = error_get_last();
- if (is_array($report) && false !== strpos($report['message'], 'error code(1314)')) {
- self::$symlinkOnWindows = false;
- }
- }
- }
- }
-
- public function setUp()
- {
- $this->filesystem = new Filesystem();
- $this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().rand(0, 1000);
- mkdir($this->workspace, 0777, true);
- $this->workspace = realpath($this->workspace);
- }
-
- public function tearDown()
- {
- $this->clean($this->workspace);
- }
-
- /**
- * @param string $file
- */
- private function clean($file)
- {
- if (is_dir($file) && !is_link($file)) {
- $dir = new \FilesystemIterator($file);
- foreach ($dir as $childFile) {
- $this->clean($childFile);
- }
-
- rmdir($file);
- } else {
- unlink($file);
- }
- }
-
- public function testCopyCreatesNewFile()
- {
- $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
- $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
-
- file_put_contents($sourceFilePath, 'SOURCE FILE');
-
- $this->filesystem->copy($sourceFilePath, $targetFilePath);
-
- $this->assertFileExists($targetFilePath);
- $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testCopyFails()
- {
- $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
- $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
-
- $this->filesystem->copy($sourceFilePath, $targetFilePath);
- }
-
- public function testCopyOverridesExistingFileIfModified()
- {
- $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
- $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
-
- file_put_contents($sourceFilePath, 'SOURCE FILE');
- file_put_contents($targetFilePath, 'TARGET FILE');
- touch($targetFilePath, time() - 1000);
-
- $this->filesystem->copy($sourceFilePath, $targetFilePath);
-
- $this->assertFileExists($targetFilePath);
- $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
- }
-
- public function testCopyDoesNotOverrideExistingFileByDefault()
- {
- $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
- $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
-
- file_put_contents($sourceFilePath, 'SOURCE FILE');
- file_put_contents($targetFilePath, 'TARGET FILE');
-
- // make sure both files have the same modification time
- $modificationTime = time() - 1000;
- touch($sourceFilePath, $modificationTime);
- touch($targetFilePath, $modificationTime);
-
- $this->filesystem->copy($sourceFilePath, $targetFilePath);
-
- $this->assertFileExists($targetFilePath);
- $this->assertEquals('TARGET FILE', file_get_contents($targetFilePath));
- }
-
- public function testCopyOverridesExistingFileIfForced()
- {
- $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
- $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
-
- file_put_contents($sourceFilePath, 'SOURCE FILE');
- file_put_contents($targetFilePath, 'TARGET FILE');
-
- // make sure both files have the same modification time
- $modificationTime = time() - 1000;
- touch($sourceFilePath, $modificationTime);
- touch($targetFilePath, $modificationTime);
-
- $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
-
- $this->assertFileExists($targetFilePath);
- $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
- }
-
- public function testCopyCreatesTargetDirectoryIfItDoesNotExist()
- {
- $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
- $targetFileDirectory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
- $targetFilePath = $targetFileDirectory.DIRECTORY_SEPARATOR.'copy_target_file';
-
- file_put_contents($sourceFilePath, 'SOURCE FILE');
-
- $this->filesystem->copy($sourceFilePath, $targetFilePath);
-
- $this->assertTrue(is_dir($targetFileDirectory));
- $this->assertFileExists($targetFilePath);
- $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
- }
-
- public function testMkdirCreatesDirectoriesRecursively()
- {
- $directory = $this->workspace
- .DIRECTORY_SEPARATOR.'directory'
- .DIRECTORY_SEPARATOR.'sub_directory';
-
- $this->filesystem->mkdir($directory);
-
- $this->assertTrue(is_dir($directory));
- }
-
- public function testMkdirCreatesDirectoriesFromArray()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
- $directories = array(
- $basePath.'1', $basePath.'2', $basePath.'3'
- );
-
- $this->filesystem->mkdir($directories);
-
- $this->assertTrue(is_dir($basePath.'1'));
- $this->assertTrue(is_dir($basePath.'2'));
- $this->assertTrue(is_dir($basePath.'3'));
- }
-
- public function testMkdirCreatesDirectoriesFromTraversableObject()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
- $directories = new \ArrayObject(array(
- $basePath.'1', $basePath.'2', $basePath.'3'
- ));
-
- $this->filesystem->mkdir($directories);
-
- $this->assertTrue(is_dir($basePath.'1'));
- $this->assertTrue(is_dir($basePath.'2'));
- $this->assertTrue(is_dir($basePath.'3'));
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testMkdirCreatesDirectoriesFails()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
- $dir = $basePath.'2';
-
- file_put_contents($dir, '');
-
- $this->filesystem->mkdir($dir);
- }
-
- public function testTouchCreatesEmptyFile()
- {
- $file = $this->workspace.DIRECTORY_SEPARATOR.'1';
-
- $this->filesystem->touch($file);
-
- $this->assertFileExists($file);
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testTouchFails()
- {
- $file = $this->workspace.DIRECTORY_SEPARATOR.'1'.DIRECTORY_SEPARATOR.'2';
-
- $this->filesystem->touch($file);
- }
-
- public function testTouchCreatesEmptyFilesFromArray()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
- $files = array(
- $basePath.'1', $basePath.'2', $basePath.'3'
- );
-
- $this->filesystem->touch($files);
-
- $this->assertFileExists($basePath.'1');
- $this->assertFileExists($basePath.'2');
- $this->assertFileExists($basePath.'3');
- }
-
- public function testTouchCreatesEmptyFilesFromTraversableObject()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
- $files = new \ArrayObject(array(
- $basePath.'1', $basePath.'2', $basePath.'3'
- ));
-
- $this->filesystem->touch($files);
-
- $this->assertFileExists($basePath.'1');
- $this->assertFileExists($basePath.'2');
- $this->assertFileExists($basePath.'3');
- }
-
- public function testRemoveCleansFilesAndDirectoriesIteratively()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
-
- mkdir($basePath);
- mkdir($basePath.'dir');
- touch($basePath.'file');
-
- $this->filesystem->remove($basePath);
-
- $this->assertTrue(!is_dir($basePath));
- }
-
- public function testRemoveCleansArrayOfFilesAndDirectories()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
-
- mkdir($basePath.'dir');
- touch($basePath.'file');
-
- $files = array(
- $basePath.'dir', $basePath.'file'
- );
-
- $this->filesystem->remove($files);
-
- $this->assertTrue(!is_dir($basePath.'dir'));
- $this->assertTrue(!is_file($basePath.'file'));
- }
-
- public function testRemoveCleansTraversableObjectOfFilesAndDirectories()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
-
- mkdir($basePath.'dir');
- touch($basePath.'file');
-
- $files = new \ArrayObject(array(
- $basePath.'dir', $basePath.'file'
- ));
-
- $this->filesystem->remove($files);
-
- $this->assertTrue(!is_dir($basePath.'dir'));
- $this->assertTrue(!is_file($basePath.'file'));
- }
-
- public function testRemoveIgnoresNonExistingFiles()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
-
- mkdir($basePath.'dir');
-
- $files = array(
- $basePath.'dir', $basePath.'file'
- );
-
- $this->filesystem->remove($files);
-
- $this->assertTrue(!is_dir($basePath.'dir'));
- }
-
- public function testRemoveCleansInvalidLinks()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
-
- mkdir($basePath);
- mkdir($basePath.'dir');
- // create symlink to unexisting file
- @symlink($basePath.'file', $basePath.'link');
-
- $this->filesystem->remove($basePath);
-
- $this->assertTrue(!is_dir($basePath));
- }
-
- public function testFilesExists()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
-
- mkdir($basePath);
- touch($basePath.'file1');
- mkdir($basePath.'folder');
-
- $this->assertTrue($this->filesystem->exists($basePath.'file1'));
- $this->assertTrue($this->filesystem->exists($basePath.'folder'));
- }
-
- public function testFilesExistsTraversableObjectOfFilesAndDirectories()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
-
- mkdir($basePath.'dir');
- touch($basePath.'file');
-
- $files = new \ArrayObject(array(
- $basePath.'dir', $basePath.'file'
- ));
-
- $this->assertTrue($this->filesystem->exists($files));
- }
-
- public function testFilesNotExistsTraversableObjectOfFilesAndDirectories()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR;
-
- mkdir($basePath.'dir');
- touch($basePath.'file');
- touch($basePath.'file2');
-
- $files = new \ArrayObject(array(
- $basePath.'dir', $basePath.'file', $basePath.'file2'
- ));
-
- unlink($basePath.'file');
-
- $this->assertFalse($this->filesystem->exists($files));
- }
-
- public function testInvalidFileNotExists()
- {
- $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
-
- $this->assertFalse($this->filesystem->exists($basePath.time()));
- }
-
- public function testChmodChangesFileMode()
- {
- $this->markAsSkippedIfChmodIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
- $file = $dir.DIRECTORY_SEPARATOR.'file';
- touch($file);
-
- $this->filesystem->chmod($file, 0400);
- $this->filesystem->chmod($dir, 0753);
-
- $this->assertEquals(753, $this->getFilePermissions($dir));
- $this->assertEquals(400, $this->getFilePermissions($file));
- }
-
- public function testChmodWrongMod()
- {
- $this->markAsSkippedIfChmodIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'file';
- touch($dir);
-
- $this->filesystem->chmod($dir, 'Wrongmode');
- }
-
- public function testChmodRecursive()
- {
- $this->markAsSkippedIfChmodIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
- $file = $dir.DIRECTORY_SEPARATOR.'file';
- touch($file);
-
- $this->filesystem->chmod($file, 0400, 0000, true);
- $this->filesystem->chmod($dir, 0753, 0000, true);
-
- $this->assertEquals(753, $this->getFilePermissions($dir));
- $this->assertEquals(753, $this->getFilePermissions($file));
- }
-
- public function testChmodAppliesUmask()
- {
- $this->markAsSkippedIfChmodIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- touch($file);
-
- $this->filesystem->chmod($file, 0770, 0022);
- $this->assertEquals(750, $this->getFilePermissions($file));
- }
-
- public function testChmodChangesModeOfArrayOfFiles()
- {
- $this->markAsSkippedIfChmodIsMissing();
-
- $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $files = array($directory, $file);
-
- mkdir($directory);
- touch($file);
-
- $this->filesystem->chmod($files, 0753);
-
- $this->assertEquals(753, $this->getFilePermissions($file));
- $this->assertEquals(753, $this->getFilePermissions($directory));
- }
-
- public function testChmodChangesModeOfTraversableFileObject()
- {
- $this->markAsSkippedIfChmodIsMissing();
-
- $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $files = new \ArrayObject(array($directory, $file));
-
- mkdir($directory);
- touch($file);
-
- $this->filesystem->chmod($files, 0753);
-
- $this->assertEquals(753, $this->getFilePermissions($file));
- $this->assertEquals(753, $this->getFilePermissions($directory));
- }
-
- public function testChown()
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
-
- $this->filesystem->chown($dir, $this->getFileOwner($dir));
- }
-
- public function testChownRecursive()
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
- $file = $dir.DIRECTORY_SEPARATOR.'file';
- touch($file);
-
- $this->filesystem->chown($dir, $this->getFileOwner($dir), true);
- }
-
- public function testChownSymlink()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
-
- $this->filesystem->symlink($file, $link);
-
- $this->filesystem->chown($link, $this->getFileOwner($link));
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testChownSymlinkFails()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
-
- $this->filesystem->symlink($file, $link);
-
- $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999));
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testChownFail()
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
-
- $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999));
- }
-
- public function testChgrp()
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
-
- $this->filesystem->chgrp($dir, $this->getFileGroup($dir));
- }
-
- public function testChgrpRecursive()
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
- $file = $dir.DIRECTORY_SEPARATOR.'file';
- touch($file);
-
- $this->filesystem->chgrp($dir, $this->getFileGroup($dir), true);
- }
-
- public function testChgrpSymlink()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
-
- $this->filesystem->symlink($file, $link);
-
- $this->filesystem->chgrp($link, $this->getFileGroup($link));
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testChgrpSymlinkFails()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
-
- $this->filesystem->symlink($file, $link);
-
- $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999));
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testChgrpFail()
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
- mkdir($dir);
-
- $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999));
- }
-
- public function testRename()
- {
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
- touch($file);
-
- $this->filesystem->rename($file, $newPath);
-
- $this->assertFileNotExists($file);
- $this->assertFileExists($newPath);
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testRenameThrowsExceptionIfTargetAlreadyExists()
- {
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
-
- touch($file);
- touch($newPath);
-
- $this->filesystem->rename($file, $newPath);
- }
-
- public function testRenameOverwritesTheTargetIfItAlreadyExists()
- {
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
-
- touch($file);
- touch($newPath);
-
- $this->filesystem->rename($file, $newPath, true);
-
- $this->assertFileNotExists($file);
- $this->assertFileExists($newPath);
- }
-
- /**
- * @expectedException \Symfony\Component\Filesystem\Exception\IOException
- */
- public function testRenameThrowsExceptionOnError()
- {
- $file = $this->workspace.DIRECTORY_SEPARATOR.uniqid();
- $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
-
- $this->filesystem->rename($file, $newPath);
- }
-
- public function testSymlink()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
-
- $this->filesystem->symlink($file, $link);
-
- $this->assertTrue(is_link($link));
- $this->assertEquals($file, readlink($link));
- }
-
- /**
- * @depends testSymlink
- */
- public function testRemoveSymlink()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- $this->filesystem->remove($link);
-
- $this->assertTrue(!is_link($link));
- }
-
- public function testSymlinkIsOverwrittenIfPointsToDifferentTarget()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
- symlink($this->workspace, $link);
-
- $this->filesystem->symlink($file, $link);
-
- $this->assertTrue(is_link($link));
- $this->assertEquals($file, readlink($link));
- }
-
- public function testSymlinkIsNotOverwrittenIfAlreadyCreated()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
- symlink($file, $link);
-
- $this->filesystem->symlink($file, $link);
-
- $this->assertTrue(is_link($link));
- $this->assertEquals($file, readlink($link));
- }
-
- public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
- $link1 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'link';
- $link2 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'subdir'.DIRECTORY_SEPARATOR.'link';
-
- touch($file);
-
- $this->filesystem->symlink($file, $link1);
- $this->filesystem->symlink($file, $link2);
-
- $this->assertTrue(is_link($link1));
- $this->assertEquals($file, readlink($link1));
- $this->assertTrue(is_link($link2));
- $this->assertEquals($file, readlink($link2));
- }
-
- /**
- * @dataProvider providePathsForMakePathRelative
- */
- public function testMakePathRelative($endPath, $startPath, $expectedPath)
- {
- $path = $this->filesystem->makePathRelative($endPath, $startPath);
-
- $this->assertEquals($expectedPath, $path);
- }
-
- /**
- * @return array
- */
- public function providePathsForMakePathRelative()
- {
- $paths = array(
- array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component', '../'),
- array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'),
- array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component', '../'),
- array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'),
- array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),
- array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'),
- array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'),
- array('/aa/bb', '/aa/bb', './'),
- array('/aa/bb', '/aa/bb/', './'),
- array('/aa/bb/', '/aa/bb', './'),
- array('/aa/bb/', '/aa/bb/', './'),
- array('/aa/bb/cc', '/aa/bb/cc/dd', '../'),
- array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'),
- array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'),
- array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'),
- array('/aa/bb/cc', '/aa', 'bb/cc/'),
- array('/aa/bb/cc', '/aa/', 'bb/cc/'),
- array('/aa/bb/cc/', '/aa', 'bb/cc/'),
- array('/aa/bb/cc/', '/aa/', 'bb/cc/'),
- array('/a/aab/bb', '/a/aa', '../aab/bb/'),
- array('/a/aab/bb', '/a/aa/', '../aab/bb/'),
- array('/a/aab/bb/', '/a/aa', '../aab/bb/'),
- array('/a/aab/bb/', '/a/aa/', '../aab/bb/'),
- );
-
- if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
- $paths[] = array('c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/');
- }
-
- return $paths;
- }
-
- public function testMirrorCopiesFilesAndDirectoriesRecursively()
- {
- $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
- $directory = $sourcePath.'directory'.DIRECTORY_SEPARATOR;
- $file1 = $directory.'file1';
- $file2 = $sourcePath.'file2';
-
- mkdir($sourcePath);
- mkdir($directory);
- file_put_contents($file1, 'FILE1');
- file_put_contents($file2, 'FILE2');
-
- $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
-
- $this->filesystem->mirror($sourcePath, $targetPath);
-
- $this->assertTrue(is_dir($targetPath));
- $this->assertTrue(is_dir($targetPath.'directory'));
- $this->assertFileEquals($file1, $targetPath.'directory'.DIRECTORY_SEPARATOR.'file1');
- $this->assertFileEquals($file2, $targetPath.'file2');
-
- $this->filesystem->remove($file1);
-
- $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => false));
- $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
-
- $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
- $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
-
- file_put_contents($file1, 'FILE1');
-
- $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
- $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
-
- $this->filesystem->remove($directory);
- $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
- $this->assertFalse($this->filesystem->exists($targetPath.'directory'));
- $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
- }
-
- public function testMirrorCopiesLinks()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
-
- mkdir($sourcePath);
- file_put_contents($sourcePath.'file1', 'FILE1');
- symlink($sourcePath.'file1', $sourcePath.'link1');
-
- $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
-
- $this->filesystem->mirror($sourcePath, $targetPath);
-
- $this->assertTrue(is_dir($targetPath));
- $this->assertFileEquals($sourcePath.'file1', $targetPath.DIRECTORY_SEPARATOR.'link1');
- $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
- }
-
- public function testMirrorCopiesLinkedDirectoryContents()
- {
- $this->markAsSkippedIfSymlinkIsMissing();
-
- $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
-
- mkdir($sourcePath.'nested/', 0777, true);
- file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
- // Note: We symlink directory, not file
- symlink($sourcePath.'nested', $sourcePath.'link1');
-
- $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
-
- $this->filesystem->mirror($sourcePath, $targetPath);
-
- $this->assertTrue(is_dir($targetPath));
- $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
- $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
- }
-
- /**
- * @dataProvider providePathsForIsAbsolutePath
- */
- public function testIsAbsolutePath($path, $expectedResult)
- {
- $result = $this->filesystem->isAbsolutePath($path);
-
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * @return array
- */
- public function providePathsForIsAbsolutePath()
- {
- return array(
- array('/var/lib', true),
- array('c:\\\\var\\lib', true),
- array('\\var\\lib', true),
- array('var/lib', false),
- array('../var/lib', false),
- array('', false),
- array(null, false)
- );
- }
-
- public function testDumpFile()
- {
- $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
-
- $this->filesystem->dumpFile($filename, 'bar', 0753);
-
- $this->assertFileExists($filename);
- $this->assertSame('bar', file_get_contents($filename));
-
- // skip mode check on windows
- if (!defined('PHP_WINDOWS_VERSION_MAJOR')) {
- $this->assertEquals(753, $this->getFilePermissions($filename));
- }
- }
-
- public function testDumpFileOverwritesAnExistingFile()
- {
- $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
- file_put_contents($filename, 'FOO BAR');
-
- $this->filesystem->dumpFile($filename, 'bar');
-
- $this->assertFileExists($filename);
- $this->assertSame('bar', file_get_contents($filename));
- }
-
- /**
- * Returns file permissions as three digits (i.e. 755)
- *
- * @param string $filePath
- *
- * @return integer
- */
- private function getFilePermissions($filePath)
- {
- return (int) substr(sprintf('%o', fileperms($filePath)), -3);
- }
-
- private function getFileOwner($filepath)
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $infos = stat($filepath);
- if ($datas = posix_getpwuid($infos['uid'])) {
- return $datas['name'];
- }
- }
-
- private function getFileGroup($filepath)
- {
- $this->markAsSkippedIfPosixIsMissing();
-
- $infos = stat($filepath);
- if ($datas = posix_getgrgid($infos['gid'])) {
- return $datas['name'];
- }
- }
-
- private function markAsSkippedIfSymlinkIsMissing()
- {
- if (!function_exists('symlink')) {
- $this->markTestSkipped('symlink is not supported');
- }
-
- if (defined('PHP_WINDOWS_VERSION_MAJOR') && false === self::$symlinkOnWindows) {
- $this->markTestSkipped('symlink requires "Create symbolic links" privilege on windows');
- }
- }
-
- private function markAsSkippedIfChmodIsMissing()
- {
- if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
- $this->markTestSkipped('chmod is not supported on windows');
- }
- }
-
- private function markAsSkippedIfPosixIsMissing()
- {
- if (defined('PHP_WINDOWS_VERSION_MAJOR') || !function_exists('posix_isatty')) {
- $this->markTestSkipped('Posix is not supported');
- }
- }
-}
+++ /dev/null
-{
- "name": "symfony/filesystem",
- "type": "library",
- "description": "Symfony Filesystem Component",
- "keywords": [],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3"
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\Filesystem\\": "" }
- },
- "target-dir": "Symfony/Component/Filesystem",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony Filesystem Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./Tests</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractExtension implements FormExtensionInterface
-{
- /**
- * The types provided by this extension
- * @var FormTypeInterface[] An array of FormTypeInterface
- */
- private $types;
-
- /**
- * The type extensions provided by this extension
- * @var FormTypeExtensionInterface[] An array of FormTypeExtensionInterface
- */
- private $typeExtensions;
-
- /**
- * The type guesser provided by this extension
- * @var FormTypeGuesserInterface
- */
- private $typeGuesser;
-
- /**
- * Whether the type guesser has been loaded
- * @var Boolean
- */
- private $typeGuesserLoaded = false;
-
- /**
- * {@inheritdoc}
- */
- public function getType($name)
- {
- if (null === $this->types) {
- $this->initTypes();
- }
-
- if (!isset($this->types[$name])) {
- throw new InvalidArgumentException(sprintf('The type "%s" can not be loaded by this extension', $name));
- }
-
- return $this->types[$name];
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasType($name)
- {
- if (null === $this->types) {
- $this->initTypes();
- }
-
- return isset($this->types[$name]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeExtensions($name)
- {
- if (null === $this->typeExtensions) {
- $this->initTypeExtensions();
- }
-
- return isset($this->typeExtensions[$name])
- ? $this->typeExtensions[$name]
- : array();
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasTypeExtensions($name)
- {
- if (null === $this->typeExtensions) {
- $this->initTypeExtensions();
- }
-
- return isset($this->typeExtensions[$name]) && count($this->typeExtensions[$name]) > 0;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeGuesser()
- {
- if (!$this->typeGuesserLoaded) {
- $this->initTypeGuesser();
- }
-
- return $this->typeGuesser;
- }
-
- /**
- * Registers the types.
- *
- * @return FormTypeInterface[] An array of FormTypeInterface instances
- */
- protected function loadTypes()
- {
- return array();
- }
-
- /**
- * Registers the type extensions.
- *
- * @return FormTypeExtensionInterface[] An array of FormTypeExtensionInterface instances
- */
- protected function loadTypeExtensions()
- {
- return array();
- }
-
- /**
- * Registers the type guesser.
- *
- * @return FormTypeGuesserInterface|null A type guesser
- */
- protected function loadTypeGuesser()
- {
- return null;
- }
-
- /**
- * Initializes the types.
- *
- * @throws UnexpectedTypeException if any registered type is not an instance of FormTypeInterface
- */
- private function initTypes()
- {
- $this->types = array();
-
- foreach ($this->loadTypes() as $type) {
- if (!$type instanceof FormTypeInterface) {
- throw new UnexpectedTypeException($type, 'Symfony\Component\Form\FormTypeInterface');
- }
-
- $this->types[$type->getName()] = $type;
- }
- }
-
- /**
- * Initializes the type extensions.
- *
- * @throws UnexpectedTypeException if any registered type extension is not
- * an instance of FormTypeExtensionInterface
- */
- private function initTypeExtensions()
- {
- $this->typeExtensions = array();
-
- foreach ($this->loadTypeExtensions() as $extension) {
- if (!$extension instanceof FormTypeExtensionInterface) {
- throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
- }
-
- $type = $extension->getExtendedType();
-
- $this->typeExtensions[$type][] = $extension;
- }
- }
-
- /**
- * Initializes the type guesser.
- *
- * @throws UnexpectedTypeException if the type guesser is not an instance of FormTypeGuesserInterface
- */
- private function initTypeGuesser()
- {
- $this->typeGuesserLoaded = true;
-
- $this->typeGuesser = $this->loadTypeGuesser();
- if (null !== $this->typeGuesser && !$this->typeGuesser instanceof FormTypeGuesserInterface) {
- throw new UnexpectedTypeException($this->typeGuesser, 'Symfony\Component\Form\FormTypeGuesserInterface');
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Default implementation of {@link FormRendererEngineInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractRendererEngine implements FormRendererEngineInterface
-{
- /**
- * The variable in {@link FormView} used as cache key.
- */
- const CACHE_KEY_VAR = 'cache_key';
-
- /**
- * @var array
- */
- protected $defaultThemes;
-
- /**
- * @var array
- */
- protected $themes = array();
-
- /**
- * @var array
- */
- protected $resources = array();
-
- /**
- * @var array
- */
- private $resourceHierarchyLevels = array();
-
- /**
- * Creates a new renderer engine.
- *
- * @param array $defaultThemes The default themes. The type of these
- * themes is open to the implementation.
- */
- public function __construct(array $defaultThemes = array())
- {
- $this->defaultThemes = $defaultThemes;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setTheme(FormView $view, $themes)
- {
- $cacheKey = $view->vars[self::CACHE_KEY_VAR];
-
- // Do not cast, as casting turns objects into arrays of properties
- $this->themes[$cacheKey] = is_array($themes) ? $themes : array($themes);
-
- // Unset instead of resetting to an empty array, in order to allow
- // implementations (like TwigRendererEngine) to check whether $cacheKey
- // is set at all.
- unset($this->resources[$cacheKey]);
- unset($this->resourceHierarchyLevels[$cacheKey]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getResourceForBlockName(FormView $view, $blockName)
- {
- $cacheKey = $view->vars[self::CACHE_KEY_VAR];
-
- if (!isset($this->resources[$cacheKey][$blockName])) {
- $this->loadResourceForBlockName($cacheKey, $view, $blockName);
- }
-
- return $this->resources[$cacheKey][$blockName];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, $hierarchyLevel)
- {
- $cacheKey = $view->vars[self::CACHE_KEY_VAR];
- $blockName = $blockNameHierarchy[$hierarchyLevel];
-
- if (!isset($this->resources[$cacheKey][$blockName])) {
- $this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel);
- }
-
- return $this->resources[$cacheKey][$blockName];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, $hierarchyLevel)
- {
- $cacheKey = $view->vars[self::CACHE_KEY_VAR];
- $blockName = $blockNameHierarchy[$hierarchyLevel];
-
- if (!isset($this->resources[$cacheKey][$blockName])) {
- $this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel);
- }
-
- // If $block was previously rendered loaded with loadTemplateForBlock(), the template
- // is cached but the hierarchy level is not. In this case, we know that the block
- // exists at this very hierarchy level, so we can just set it.
- if (!isset($this->resourceHierarchyLevels[$cacheKey][$blockName])) {
- $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
- }
-
- return $this->resourceHierarchyLevels[$cacheKey][$blockName];
- }
-
- /**
- * Loads the cache with the resource for a given block name.
- *
- * @see getResourceForBlock()
- *
- * @param string $cacheKey The cache key of the form view.
- * @param FormView $view The form view for finding the applying themes.
- * @param string $blockName The name of the block to load.
- *
- * @return Boolean True if the resource could be loaded, false otherwise.
- */
- abstract protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName);
-
- /**
- * Loads the cache with the resource for a specific level of a block hierarchy.
- *
- * @see getResourceForBlockHierarchy()
- *
- * @param string $cacheKey The cache key used for storing the
- * resource.
- * @param FormView $view The form view for finding the applying
- * themes.
- * @param array $blockNameHierarchy The block hierarchy, with the most
- * specific block name at the end.
- * @param integer $hierarchyLevel The level in the block hierarchy that
- * should be loaded.
- *
- * @return Boolean True if the resource could be loaded, false otherwise.
- */
- private function loadResourceForBlockNameHierarchy($cacheKey, FormView $view, array $blockNameHierarchy, $hierarchyLevel)
- {
- $blockName = $blockNameHierarchy[$hierarchyLevel];
-
- // Try to find a template for that block
- if ($this->loadResourceForBlockName($cacheKey, $view, $blockName)) {
- // If loadTemplateForBlock() returns true, it was able to populate the
- // cache. The only missing thing is to set the hierarchy level at which
- // the template was found.
- $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
-
- return true;
- }
-
- if ($hierarchyLevel > 0) {
- $parentLevel = $hierarchyLevel - 1;
- $parentBlockName = $blockNameHierarchy[$parentLevel];
-
- // The next two if statements contain slightly duplicated code. This is by intention
- // and tries to avoid execution of unnecessary checks in order to increase performance.
-
- if (isset($this->resources[$cacheKey][$parentBlockName])) {
- // It may happen that the parent block is already loaded, but its level is not.
- // In this case, the parent block must have been loaded by loadResourceForBlock(),
- // which does not check the hierarchy of the block. Subsequently the block must have
- // been found directly on the parent level.
- if (!isset($this->resourceHierarchyLevels[$cacheKey][$parentBlockName])) {
- $this->resourceHierarchyLevels[$cacheKey][$parentBlockName] = $parentLevel;
- }
-
- // Cache the shortcuts for further accesses
- $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
- $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
-
- return true;
- }
-
- if ($this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $parentLevel)) {
- // Cache the shortcuts for further accesses
- $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
- $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
-
- return true;
- }
- }
-
- // Cache the result for further accesses
- $this->resources[$cacheKey][$blockName] = false;
- $this->resourceHierarchyLevels[$cacheKey][$blockName] = false;
-
- return false;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractType implements FormTypeInterface
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'form';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractTypeExtension implements FormTypeExtensionInterface
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\AlreadySubmittedException;
-use Symfony\Component\Form\Exception\BadMethodCallException;
-
-/**
- * A form button.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Button implements \IteratorAggregate, FormInterface
-{
- /**
- * @var FormInterface
- */
- private $parent;
-
- /**
- * @var FormConfigInterface
- */
- private $config;
-
- /**
- * @var Boolean
- */
- private $submitted = false;
-
- /**
- * Creates a new button from a form configuration.
- *
- * @param FormConfigInterface $config The button's configuration.
- */
- public function __construct(FormConfigInterface $config)
- {
- $this->config = $config;
- }
-
- /**
- * Unsupported method.
- *
- * @param mixed $offset
- *
- * @return Boolean Always returns false.
- */
- public function offsetExists($offset)
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param mixed $offset
- *
- * @throws BadMethodCallException
- */
- public function offsetGet($offset)
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param mixed $offset
- * @param mixed $value
- *
- * @throws BadMethodCallException
- */
- public function offsetSet($offset, $value)
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param mixed $offset
- *
- * @throws BadMethodCallException
- */
- public function offsetUnset($offset)
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * {@inheritdoc}
- */
- public function setParent(FormInterface $parent = null)
- {
- $this->parent = $parent;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return $this->parent;
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param int|string|FormInterface $child
- * @param null $type
- * @param array $options
- *
- * @throws BadMethodCallException
- */
- public function add($child, $type = null, array $options = array())
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string $name
- *
- * @throws BadMethodCallException
- */
- public function get($name)
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * @param string $name
- *
- * @return Boolean Always returns false.
- */
- public function has($name)
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string $name
- *
- * @throws BadMethodCallException
- */
- public function remove($name)
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * {@inheritdoc}
- */
- public function all()
- {
- return array();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getErrors()
- {
- return array();
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string $modelData
- *
- * @throws BadMethodCallException
- */
- public function setData($modelData)
- {
- throw new BadMethodCallException('Buttons cannot have data.');
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getData()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getNormData()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getViewData()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return array Always returns an empty array.
- */
- public function getExtraData()
- {
- return array();
- }
-
- /**
- * Returns the button's configuration.
- *
- * @return FormConfigInterface The configuration.
- */
- public function getConfig()
- {
- return $this->config;
- }
-
- /**
- * Returns whether the button is submitted.
- *
- * @return Boolean true if the button was submitted.
- */
- public function isSubmitted()
- {
- return $this->submitted;
- }
-
- /**
- * Returns the name by which the button is identified in forms.
- *
- * @return string The name of the button.
- */
- public function getName()
- {
- return $this->config->getName();
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getPropertyPath()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @param FormError $error
- *
- * @throws BadMethodCallException
- */
- public function addError(FormError $error)
- {
- throw new BadMethodCallException('Buttons cannot have errors.');
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns true.
- */
- public function isValid()
- {
- return true;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function isRequired()
- {
- return false;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isDisabled()
- {
- return $this->config->getDisabled();
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns true.
- */
- public function isEmpty()
- {
- return true;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns true.
- */
- public function isSynchronized()
- {
- return true;
- }
-
- /**
- * Unsupported method.
- *
- * @throws BadMethodCallException
- */
- public function initialize()
- {
- throw new BadMethodCallException('Buttons cannot be initialized. Call initialize() on the root form instead.');
- }
-
- /**
- * Unsupported method.
- *
- * @param mixed $request
- *
- * @throws BadMethodCallException
- */
- public function handleRequest($request = null)
- {
- throw new BadMethodCallException('Buttons cannot handle requests. Call handleRequest() on the root form instead.');
- }
-
- /**
- * Submits data to the button.
- *
- * @param null|string $submittedData The data.
- * @param Boolean $clearMissing Not used.
- *
- * @return Button The button instance
- *
- * @throws Exception\AlreadySubmittedException If the button has already been submitted.
- */
- public function submit($submittedData, $clearMissing = true)
- {
- if ($this->submitted) {
- throw new AlreadySubmittedException('A form can only be submitted once');
- }
-
- $this->submitted = true;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRoot()
- {
- return $this->parent ? $this->parent->getRoot() : $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isRoot()
- {
- return null === $this->parent;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createView(FormView $parent = null)
- {
- if (null === $parent && $this->parent) {
- $parent = $this->parent->createView();
- }
-
- return $this->config->getType()->createView($this, $parent);
- }
-
- /**
- * Unsupported method.
- *
- * @return integer Always returns 0.
- */
- public function count()
- {
- return 0;
- }
-
- /**
- * Unsupported method.
- *
- * @return \EmptyIterator Always returns an empty iterator.
- */
- public function getIterator()
- {
- return new \EmptyIterator();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\Form\Exception\BadMethodCallException;
-
-/**
- * A builder for {@link Button} instances.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
-{
- /**
- * @var Boolean
- */
- protected $locked = false;
-
- /**
- * @var Boolean
- */
- private $disabled;
-
- /**
- * @var ResolvedFormTypeInterface
- */
- private $type;
-
- /**
- * @var string
- */
- private $name;
-
- /**
- * @var array
- */
- private $attributes = array();
-
- /**
- * @var array
- */
- private $options;
-
- /**
- * Creates a new button builder.
- *
- * @param string $name The name of the button.
- * @param array $options The button's options.
- *
- * @throws InvalidArgumentException If the name is empty.
- */
- public function __construct($name, array $options)
- {
- if (empty($name) && 0 != $name) {
- throw new InvalidArgumentException('Buttons cannot have empty names.');
- }
-
- $this->name = (string) $name;
- $this->options = $options;
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string|integer|FormBuilderInterface $child
- * @param string|FormTypeInterface $type
- * @param array $options
- *
- * @throws BadMethodCallException
- */
- public function add($child, $type = null, array $options = array())
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string $name
- * @param string|FormTypeInterface $type
- * @param array $options
- *
- * @throws BadMethodCallException
- */
- public function create($name, $type = null, array $options = array())
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string $name
- *
- * @throws BadMethodCallException
- */
- public function get($name)
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string $name
- *
- * @throws BadMethodCallException
- */
- public function remove($name)
- {
- throw new BadMethodCallException('Buttons cannot have children.');
- }
-
- /**
- * Unsupported method.
- *
- * @param string $name
- *
- * @return Boolean Always returns false.
- */
- public function has($name)
- {
- return false;
- }
-
- /**
- * Returns the children.
- *
- * @return array Always returns an empty array.
- */
- public function all()
- {
- return array();
- }
-
- /**
- * Creates the button.
- *
- * @return Button The button
- */
- public function getForm()
- {
- return new Button($this->getFormConfig());
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param string $eventName
- * @param callable $listener
- * @param integer $priority
- *
- * @throws BadMethodCallException
- */
- public function addEventListener($eventName, $listener, $priority = 0)
- {
- throw new BadMethodCallException('Buttons do not support event listeners.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param EventSubscriberInterface $subscriber
- *
- * @throws BadMethodCallException
- */
- public function addEventSubscriber(EventSubscriberInterface $subscriber)
- {
- throw new BadMethodCallException('Buttons do not support event subscribers.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param DataTransformerInterface $viewTransformer
- * @param Boolean $forcePrepend
- *
- * @throws BadMethodCallException
- */
- public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false)
- {
- throw new BadMethodCallException('Buttons do not support data transformers.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @throws BadMethodCallException
- */
- public function resetViewTransformers()
- {
- throw new BadMethodCallException('Buttons do not support data transformers.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param DataTransformerInterface $modelTransformer
- * @param Boolean $forceAppend
- *
- * @throws BadMethodCallException
- */
- public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false)
- {
- throw new BadMethodCallException('Buttons do not support data transformers.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @throws BadMethodCallException
- */
- public function resetModelTransformers()
- {
- throw new BadMethodCallException('Buttons do not support data transformers.');
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAttribute($name, $value)
- {
- $this->attributes[$name] = $value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAttributes(array $attributes)
- {
- $this->attributes = $attributes;
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param DataMapperInterface $dataMapper
- *
- * @throws BadMethodCallException
- */
- public function setDataMapper(DataMapperInterface $dataMapper = null)
- {
- throw new BadMethodCallException('Buttons do not support data mappers.');
- }
-
- /**
- * Set whether the button is disabled.
- *
- * @param Boolean $disabled Whether the button is disabled
- *
- * @return ButtonBuilder The button builder.
- */
- public function setDisabled($disabled)
- {
- $this->disabled = $disabled;
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param mixed $emptyData
- *
- * @throws BadMethodCallException
- */
- public function setEmptyData($emptyData)
- {
- throw new BadMethodCallException('Buttons do not support empty data.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param Boolean $errorBubbling
- *
- * @throws BadMethodCallException
- */
- public function setErrorBubbling($errorBubbling)
- {
- throw new BadMethodCallException('Buttons do not support error bubbling.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param Boolean $required
- *
- * @throws BadMethodCallException
- */
- public function setRequired($required)
- {
- throw new BadMethodCallException('Buttons cannot be required.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param null $propertyPath
- *
- * @throws BadMethodCallException
- */
- public function setPropertyPath($propertyPath)
- {
- throw new BadMethodCallException('Buttons do not support property paths.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param Boolean $mapped
- *
- * @throws BadMethodCallException
- */
- public function setMapped($mapped)
- {
- throw new BadMethodCallException('Buttons do not support data mapping.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param Boolean $byReference
- *
- * @throws BadMethodCallException
- */
- public function setByReference($byReference)
- {
- throw new BadMethodCallException('Buttons do not support data mapping.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param Boolean $virtual
- *
- * @throws BadMethodCallException
- */
- public function setVirtual($virtual)
- {
- throw new BadMethodCallException('Buttons cannot be virtual.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param Boolean $compound
- *
- * @throws BadMethodCallException
- */
- public function setCompound($compound)
- {
- throw new BadMethodCallException('Buttons cannot be compound.');
- }
-
- /**
- * Sets the type of the button.
- *
- * @param ResolvedFormTypeInterface $type The type of the button.
- *
- * @return ButtonBuilder The button builder.
- */
- public function setType(ResolvedFormTypeInterface $type)
- {
- $this->type = $type;
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param array $data
- *
- * @throws BadMethodCallException
- */
- public function setData($data)
- {
- throw new BadMethodCallException('Buttons do not support data.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param Boolean $locked
- *
- * @throws BadMethodCallException
- */
- public function setDataLocked($locked)
- {
- throw new BadMethodCallException('Buttons do not support data locking.');
- }
-
- /**
- * Unsupported method.
- *
- * This method should not be invoked.
- *
- * @param FormFactoryInterface $formFactory
- *
- * @return void
- *
- * @throws BadMethodCallException
- */
- public function setFormFactory(FormFactoryInterface $formFactory)
- {
- throw new BadMethodCallException('Buttons do not support form factories.');
- }
-
- /**
- * Unsupported method.
- *
- * @param string $action
- *
- * @throws BadMethodCallException
- */
- public function setAction($action)
- {
- throw new BadMethodCallException('Buttons do not support actions.');
- }
-
- /**
- * Unsupported method.
- *
- * @param string $method
- *
- * @throws BadMethodCallException
- */
- public function setMethod($method)
- {
- throw new BadMethodCallException('Buttons do not support methods.');
- }
-
- /**
- * Unsupported method.
- *
- * @param RequestHandlerInterface $requestHandler
- *
- * @throws BadMethodCallException
- */
- public function setRequestHandler(RequestHandlerInterface $requestHandler)
- {
- throw new BadMethodCallException('Buttons do not support form processors.');
- }
-
- /**
- * Unsupported method.
- *
- * @param Boolean $initialize
- *
- * @throws BadMethodCallException
- */
- public function setAutoInitialize($initialize)
- {
- if (true === $initialize) {
- throw new BadMethodCallException('Buttons do not support automatic initialization.');
- }
-
- return $this;
- }
-
- /**
- * Unsupported method.
- *
- * @param Boolean $inheritData
- *
- * @throws BadMethodCallException
- */
- public function setInheritData($inheritData)
- {
- throw new BadMethodCallException('Buttons do not support data inheritance.');
- }
-
- /**
- * Builds and returns the button configuration.
- *
- * @return FormConfigInterface
- */
- public function getFormConfig()
- {
- // This method should be idempotent, so clone the builder
- $config = clone $this;
- $config->locked = true;
-
- return $config;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getEventDispatcher()
- {
- return null;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getPropertyPath()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getMapped()
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getByReference()
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getVirtual()
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getCompound()
- {
- return false;
- }
-
- /**
- * Returns the form type used to construct the button.
- *
- * @return ResolvedFormTypeInterface The button's type.
- */
- public function getType()
- {
- return $this->type;
- }
-
- /**
- * Unsupported method.
- *
- * @return array Always returns an empty array.
- */
- public function getViewTransformers()
- {
- return array();
- }
-
- /**
- * Unsupported method.
- *
- * @return array Always returns an empty array.
- */
- public function getModelTransformers()
- {
- return array();
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getDataMapper()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getRequired()
- {
- return false;
- }
-
- /**
- * Returns whether the button is disabled.
- *
- * @return Boolean Whether the button is disabled.
- */
- public function getDisabled()
- {
- return $this->disabled;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getErrorBubbling()
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getEmptyData()
- {
- return null;
- }
-
- /**
- * Returns additional attributes of the button.
- *
- * @return array An array of key-value combinations.
- */
- public function getAttributes()
- {
- return $this->attributes;
- }
-
- /**
- * Returns whether the attribute with the given name exists.
- *
- * @param string $name The attribute name.
- *
- * @return Boolean Whether the attribute exists.
- */
- public function hasAttribute($name)
- {
- return array_key_exists($name, $this->attributes);
- }
-
- /**
- * Returns the value of the given attribute.
- *
- * @param string $name The attribute name.
- * @param mixed $default The value returned if the attribute does not exist.
- *
- * @return mixed The attribute value.
- */
- public function getAttribute($name, $default = null)
- {
- return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getData()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getDataClass()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getDataLocked()
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getFormFactory()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getAction()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getMethod()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return null Always returns null.
- */
- public function getRequestHandler()
- {
- return null;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getAutoInitialize()
- {
- return false;
- }
-
- /**
- * Unsupported method.
- *
- * @return Boolean Always returns false.
- */
- public function getInheritData()
- {
- return false;
- }
-
- /**
- * Returns all options passed during the construction of the button.
- *
- * @return array The passed options.
- */
- public function getOptions()
- {
- return $this->options;
- }
-
- /**
- * Returns whether a specific option exists.
- *
- * @param string $name The option name,
- *
- * @return Boolean Whether the option exists.
- */
- public function hasOption($name)
- {
- return array_key_exists($name, $this->options);
- }
-
- /**
- * Returns the value of a specific option.
- *
- * @param string $name The option name.
- * @param mixed $default The value returned if the option does not exist.
- *
- * @return mixed The option value.
- */
- public function getOption($name, $default = null)
- {
- return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
- }
-
- /**
- * Unsupported method.
- *
- * @return integer Always returns 0.
- */
- public function count()
- {
- return 0;
- }
-
- /**
- * Unsupported method.
- *
- * @return \EmptyIterator Always returns an empty iterator.
- */
- public function getIterator()
- {
- return new \EmptyIterator();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A type that should be converted into a {@link Button} instance.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ButtonTypeInterface extends FormTypeInterface
-{
-}
+++ /dev/null
-CHANGELOG
-=========
-
-
-2.3.0
-------
-
- * deprecated FormPerformanceTestCase and FormIntegrationTestCase in the Symfony\Component\Form\Tests namespace and moved them to the Symfony\Component\Form\Test namespace
- * deprecated TypeTestCase in the Symfony\Component\Form\Tests\Extension\Core\Type namespace and moved it to the Symfony\Component\Form\Test namespace
- * changed FormRenderer::humanize() to humanize also camel cased field name
- * added RequestHandlerInterface and FormInterface::handleRequest()
- * deprecated passing a Request instance to FormInterface::bind()
- * added options "method" and "action" to FormType
- * deprecated option "virtual" in favor "inherit_data"
- * deprecated VirtualFormAwareIterator in favor of InheritDataAwareIterator
- * [BC BREAK] removed the "array" type hint from DataMapperInterface
- * improved forms inheriting their parent data to actually return that data from getData(), getNormData() and getViewData()
- * added component-level exceptions for various SPL exceptions
- changed all uses of the deprecated Exception class to use more specialized exceptions instead
- removed NotInitializedException, NotValidException, TypeDefinitionException, TypeLoaderException, CreationException
- * added events PRE_SUBMIT, SUBMIT and POST_SUBMIT
- * deprecated events PRE_BIND, BIND and POST_BIND
- * [BC BREAK] renamed bind() and isBound() in FormInterface to submit() and isSubmitted()
- * added methods submit() and isSubmitted() to Form
- * deprecated bind() and isBound() in Form
- * deprecated AlreadyBoundException in favor of AlreadySubmittedException
- * added support for PATCH requests
- * [BC BREAK] added initialize() to FormInterface
- * [BC BREAK] added getAutoInitialize() to FormConfigInterface
- * [BC BREAK] added setAutoInitialize() to FormConfigBuilderInterface
- * [BC BREAK] initialization for Form instances added to a form tree must be manually disabled
- * PRE_SET_DATA is now guaranteed to be called after children were added by the form builder,
- unless FormInterface::setData() is called manually
- * fixed CSRF error message to be translated
- * custom CSRF error messages can now be set through the "csrf_message" option
- * fixed: expanded single-choice fields now show a radio button for the empty value
-
-2.2.0
------
-
- * TrimListener now removes unicode whitespaces
- * deprecated getParent(), setParent() and hasParent() in FormBuilderInterface
- * FormInterface::add() now accepts a FormInterface instance OR a field's name, type and options
- * removed special characters between the choice or text fields of DateType unless
- the option "format" is set to a custom value
- * deprecated FormException and introduced ExceptionInterface instead
- * [BC BREAK] FormException is now an interface
- * protected FormBuilder methods from being called when it is turned into a FormConfigInterface with getFormConfig()
- * [BC BREAK] inserted argument `$message` in the constructor of `FormError`
- * the PropertyPath class and related classes were moved to a dedicated
- PropertyAccess component. During the move, InvalidPropertyException was
- renamed to NoSuchPropertyException. FormUtil was split: FormUtil::singularify()
- can now be found in Symfony\Component\PropertyAccess\StringUtil. The methods
- getValue() and setValue() from PropertyPath were extracted into a new class
- PropertyAccessor.
- * added an optional PropertyAccessorInterface parameter to FormType,
- ObjectChoiceList and PropertyPathMapper
- * [BC BREAK] PropertyPathMapper and FormType now have a constructor
- * [BC BREAK] setting the option "validation_groups" to ``false`` now disables validation
- instead of assuming group "Default"
-
-2.1.0
------
-
- * [BC BREAK] ``read_only`` field attribute now renders as ``readonly="readonly"``, use ``disabled`` instead
- * [BC BREAK] child forms now aren't validated anymore by default
- * made validation of form children configurable (new option: cascade_validation)
- * added support for validation groups as callbacks
- * made the translation catalogue configurable via the "translation_domain" option
- * added Form::getErrorsAsString() to help debugging forms
- * allowed setting different options for RepeatedType fields (like the label)
- * added support for empty form name at root level, this enables rendering forms
- without form name prefix in field names
- * [BC BREAK] form and field names must start with a letter, digit or underscore
- and only contain letters, digits, underscores, hyphens and colons
- * [BC BREAK] changed default name of the prototype in the "collection" type
- from "$$name$$" to "\__name\__". No dollars are appended/prepended to custom
- names anymore.
- * [BC BREAK] improved ChoiceListInterface
- * [BC BREAK] added SimpleChoiceList and LazyChoiceList as replacement of
- ArrayChoiceList
- * added ChoiceList and ObjectChoiceList to use objects as choices
- * [BC BREAK] removed EntitiesToArrayTransformer and EntityToIdTransformer.
- The former has been replaced by CollectionToArrayTransformer in combination
- with EntityChoiceList, the latter is not required in the core anymore.
- * [BC BREAK] renamed
- * ArrayToBooleanChoicesTransformer to ChoicesToBooleanArrayTransformer
- * ScalarToBooleanChoicesTransformer to ChoiceToBooleanArrayTransformer
- * ArrayToChoicesTransformer to ChoicesToValuesTransformer
- * ScalarToChoiceTransformer to ChoiceToValueTransformer
- to be consistent with the naming in ChoiceListInterface.
- They were merged into ChoiceList and have no public equivalent anymore.
- * choice fields now throw a FormException if neither the "choices" nor the
- "choice_list" option is set
- * the radio type is now a child of the checkbox type
- * the collection, choice (with multiple selection) and entity (with multiple
- selection) types now make use of addXxx() and removeXxx() methods in your
- model if you set "by_reference" to false. For a custom, non-recognized
- singular form, set the "property_path" option like this: "plural|singular"
- * forms now don't create an empty object anymore if they are completely
- empty and not required. The empty value for such forms is null.
- * added constant Guess::VERY_HIGH_CONFIDENCE
- * [BC BREAK] The methods `add`, `remove`, `setParent`, `bind` and `setData`
- in class Form now throw an exception if the form is already bound
- * fields of constrained classes without a NotBlank or NotNull constraint are
- set to not required now, as stated in the docs
- * fixed TimeType and DateTimeType to not display seconds when "widget" is
- "single_text" unless "with_seconds" is set to true
- * checkboxes of in an expanded multiple-choice field don't include the choice
- in their name anymore. Their names terminate with "[]" now.
- * deprecated FormValidatorInterface and substituted its implementations
- by event subscribers
- * simplified CSRF protection and removed the csrf type
- * deprecated FieldType and merged it into FormType
- * added new option "compound" that lets you switch between field and form behavior
- * [BC BREAK] renamed theme blocks
- * "field_*" to "form_*"
- * "field_widget" to "form_widget_simple"
- * "widget_choice_options" to "choice_widget_options"
- * "generic_label" to "form_label"
- * added theme blocks "form_widget_compound", "choice_widget_expanded" and
- "choice_widget_collapsed" to make theming more modular
- * ValidatorTypeGuesser now guesses "collection" for array type constraint
- * added method `guessPattern` to FormTypeGuesserInterface to guess which pattern to use in the HTML5 attribute "pattern"
- * deprecated method `guessMinLength` in favor of `guessPattern`
- * labels don't display field attributes anymore. Label attributes can be
- passed in the "label_attr" option/variable
- * added option "mapped" which should be used instead of setting "property_path" to false
- * [BC BREAK] "data_class" now *must* be set if a form maps to an object and should be left empty otherwise
- * improved error mapping on forms
- * dot (".") rules are now allowed to map errors assigned to a form to
- one of its children
- * errors are not mapped to unsynchronized forms anymore
- * [BC BREAK] changed Form constructor to accept a single `FormConfigInterface` object
- * [BC BREAK] changed argument order in the FormBuilder constructor
- * added Form method `getViewData`
- * deprecated Form methods
- * `getTypes`
- * `getErrorBubbling`
- * `getNormTransformers`
- * `getClientTransformers`
- * `getAttribute`
- * `hasAttribute`
- * `getClientData`
- * added FormBuilder methods
- * `getTypes`
- * `addViewTransformer`
- * `getViewTransformers`
- * `resetViewTransformers`
- * `addModelTransformer`
- * `getModelTransformers`
- * `resetModelTransformers`
- * deprecated FormBuilder methods
- * `prependClientTransformer`
- * `appendClientTransformer`
- * `getClientTransformers`
- * `resetClientTransformers`
- * `prependNormTransformer`
- * `appendNormTransformer`
- * `getNormTransformers`
- * `resetNormTransformers`
- * deprecated the option "validation_constraint" in favor of the new
- option "constraints"
- * removed superfluous methods from DataMapperInterface
- * `mapFormToData`
- * `mapDataToForm`
- * added `setDefaultOptions` to FormTypeInterface and FormTypeExtensionInterface
- which accepts an OptionsResolverInterface instance
- * deprecated the methods `getDefaultOptions` and `getAllowedOptionValues`
- in FormTypeInterface and FormTypeExtensionInterface
- * options passed during construction can now be accessed from FormConfigInterface
- * added FormBuilderInterface and FormConfigEditorInterface
- * [BC BREAK] the method `buildForm` in FormTypeInterface and FormTypeExtensionInterface
- now receives a FormBuilderInterface instead of a FormBuilder instance
- * [BC BREAK] the method `buildViewBottomUp` was renamed to `finishView` in
- FormTypeInterface and FormTypeExtensionInterface
- * [BC BREAK] the options array is now passed as last argument of the
- methods
- * `buildView`
- * `finishView`
- in FormTypeInterface and FormTypeExtensionInterface
- * [BC BREAK] no options are passed to `getParent` of FormTypeInterface anymore
- * deprecated DataEvent and FilterDataEvent in favor of the new FormEvent which is
- now passed to all events thrown by the component
- * FormEvents::BIND now replaces FormEvents::BIND_NORM_DATA
- * FormEvents::PRE_SET_DATA now replaces FormEvents::SET_DATA
- * FormEvents::PRE_BIND now replaces FormEvents::BIND_CLIENT_DATA
- * deprecated FormEvents::SET_DATA, FormEvents::BIND_CLIENT_DATA and
- FormEvents::BIND_NORM_DATA
- * [BC BREAK] reversed the order of the first two arguments to `createNamed`
- and `createNamedBuilder` in `FormFactoryInterface`
- * deprecated `getChildren` in Form and FormBuilder in favor of `all`
- * deprecated `hasChildren` in Form and FormBuilder in favor of `count`
- * FormBuilder now implements \IteratorAggregate
- * [BC BREAK] compound forms now always need a data mapper
- * FormBuilder now maintains the order when explicitly adding form builders as children
- * ChoiceType now doesn't add the empty value anymore if the choices already contain an empty element
- * DateType, TimeType and DateTimeType now show empty values again if not required
- * [BC BREAK] fixed rendering of errors for DateType, BirthdayType and similar ones
- * [BC BREAK] fixed: form constraints are only validated if they belong to the validated group
- * deprecated `bindRequest` in `Form` and replaced it by a listener to FormEvents::PRE_BIND
- * fixed: the "data" option supersedes default values from the model
- * changed DateType to refer to the "format" option for calculating the year and day choices instead
- of padding them automatically
- * [BC BREAK] DateType defaults to the format "yyyy-MM-dd" now if the widget is
- "single_text", in order to support the HTML 5 date field out of the box
- * added the option "format" to DateTimeType
- * [BC BREAK] DateTimeType now outputs RFC 3339 dates by default, as generated and
- consumed by HTML5 browsers, if the widget is "single_text"
- * deprecated the options "data_timezone" and "user_timezone" in DateType, DateTimeType and TimeType
- and renamed them to "model_timezone" and "view_timezone"
- * fixed: TransformationFailedExceptions thrown in the model transformer are now caught by the form
- * added FormRegistryInterface, ResolvedFormTypeInterface and ResolvedFormTypeFactoryInterface
- * deprecated FormFactory methods
- * `addType`
- * `hasType`
- * `getType`
- * [BC BREAK] FormFactory now expects a FormRegistryInterface and a ResolvedFormTypeFactoryInterface as constructor argument
- * [BC BREAK] The method `createBuilder` in FormTypeInterface is not supported anymore for performance reasons
- * [BC BREAK] Removed `setTypes` from FormBuilder
- * deprecated AbstractType methods
- * `getExtensions`
- * `setExtensions`
- * ChoiceType now caches its created choice lists to improve performance
- * [BC BREAK] Rows of a collection field cannot be themed individually anymore. All rows in the collection
- field now have the same block names, which contains "entry" where it previously contained the row index.
- * [BC BREAK] When registering a type through the DI extension, the tag alias has to match the actual type name.
- * added FormRendererInterface, FormRendererEngineInterface and implementations of these interfaces
- * [BC BREAK] removed the following methods from FormUtil:
- * `toArrayKey`
- * `toArrayKeys`
- * `isChoiceGroup`
- * `isChoiceSelected`
- * [BC BREAK] renamed method `renderBlock` in FormHelper to `block` and changed its signature
- * made FormView properties public and deprecated their accessor methods
- * made the normalized data of a form accessible in the template through the variable "form.vars.data"
- * made the original data of a choice accessible in the template through the property "choice.data"
- * added convenience class Forms and FormFactoryBuilderInterface
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-class CallbackTransformer implements DataTransformerInterface
-{
- /**
- * The callback used for forward transform
- * @var \Closure
- */
- private $transform;
-
- /**
- * The callback used for reverse transform
- * @var \Closure
- */
- private $reverseTransform;
-
- /**
- * Constructor.
- *
- * @param \Closure $transform The forward transform callback
- * @param \Closure $reverseTransform The reverse transform callback
- */
- public function __construct(\Closure $transform, \Closure $reverseTransform)
- {
- $this->transform = $transform;
- $this->reverseTransform = $reverseTransform;
- }
-
- /**
- * Transforms a value from the original representation to a transformed representation.
- *
- * @param mixed $data The value in the original representation
- *
- * @return mixed The value in the transformed representation
- *
- * @throws UnexpectedTypeException when the argument is not a string
- * @throws TransformationFailedException when the transformation fails
- */
- public function transform($data)
- {
- return call_user_func($this->transform, $data);
- }
-
- /**
- * Transforms a value from the transformed representation to its original
- * representation.
- *
- * @param mixed $data The value in the transformed representation
- *
- * @return mixed The value in the original representation
- *
- * @throws UnexpectedTypeException when the argument is not of the expected type
- * @throws TransformationFailedException when the transformation fails
- */
- public function reverseTransform($data)
- {
- return call_user_func($this->reverseTransform, $data);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A clickable form element.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ClickableInterface
-{
- /**
- * Returns whether this element was clicked.
- *
- * @return Boolean Whether this element was clicked.
- */
- public function isClicked();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface DataMapperInterface
-{
- /**
- * Maps properties of some data to a list of forms.
- *
- * @param mixed $data Structured data.
- * @param FormInterface[] $forms A list of {@link FormInterface} instances.
- *
- * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported.
- */
- public function mapDataToForms($data, $forms);
-
- /**
- * Maps the data of a list of forms into the properties of some data.
- *
- * @param FormInterface[] $forms A list of {@link FormInterface} instances.
- * @param mixed $data Structured data.
- *
- * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported.
- */
- public function mapFormsToData($forms, &$data);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * Transforms a value between different representations.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface DataTransformerInterface
-{
- /**
- * Transforms a value from the original representation to a transformed representation.
- *
- * This method is called on two occasions inside a form field:
- *
- * 1. When the form field is initialized with the data attached from the datasource (object or array).
- * 2. When data from a request is submitted using {@link Form::submit()} to transform the new input data
- * back into the renderable format. For example if you have a date field and submit '2009-10-10'
- * you might accept this value because its easily parsed, but the transformer still writes back
- * "2009/10/10" onto the form field (for further displaying or other purposes).
- *
- * This method must be able to deal with empty values. Usually this will
- * be NULL, but depending on your implementation other empty values are
- * possible as well (such as empty strings). The reasoning behind this is
- * that value transformers must be chainable. If the transform() method
- * of the first value transformer outputs NULL, the second value transformer
- * must be able to process that value.
- *
- * By convention, transform() should return an empty string if NULL is
- * passed.
- *
- * @param mixed $value The value in the original representation
- *
- * @return mixed The value in the transformed representation
- *
- * @throws TransformationFailedException When the transformation fails.
- */
- public function transform($value);
-
- /**
- * Transforms a value from the transformed representation to its original
- * representation.
- *
- * This method is called when {@link Form::submit()} is called to transform the requests tainted data
- * into an acceptable format for your data processing/model layer.
- *
- * This method must be able to deal with empty values. Usually this will
- * be an empty string, but depending on your implementation other empty
- * values are possible as well (such as empty strings). The reasoning behind
- * this is that value transformers must be chainable. If the
- * reverseTransform() method of the first value transformer outputs an
- * empty string, the second value transformer must be able to process that
- * value.
- *
- * By convention, reverseTransform() should return NULL if an empty string
- * is passed.
- *
- * @param mixed $value The value in the transformed representation
- *
- * @return mixed The value in the original representation
- *
- * @throws TransformationFailedException When the transformation fails.
- */
- public function reverseTransform($value);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Alias of {@link AlreadySubmittedException}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link AlreadySubmittedException} instead.
- */
-class AlreadyBoundException extends LogicException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Thrown when an operation is called that is not acceptable after submitting
- * a form.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class AlreadySubmittedException extends AlreadyBoundException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Base BadMethodCallException for the Form component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-class ErrorMappingException extends RuntimeException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Base ExceptionInterface for the Form component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Base InvalidArgumentException for the Form component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-class InvalidConfigurationException extends InvalidArgumentException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Base LogicException for Form component.
- *
- * @author Alexander Kotynia <aleksander.kot@gmail.com>
- */
-class LogicException extends \LogicException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Base OutOfBoundsException for Form component.
- *
- * @author Alexander Kotynia <aleksander.kot@gmail.com>
- */
-class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Base RuntimeException for the Form component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RuntimeException extends \RuntimeException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-class StringCastException extends RuntimeException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-/**
- * Indicates a value transformation error.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class TransformationFailedException extends RuntimeException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-class UnexpectedTypeException extends InvalidArgumentException
-{
- public function __construct($value, $expectedType)
- {
- parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\ChoiceList;
-
-use Symfony\Component\Form\FormConfigBuilder;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\Form\Exception\InvalidConfigurationException;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-/**
- * A choice list for choices of arbitrary data types.
- *
- * Choices and labels are passed in two arrays. The indices of the choices
- * and the labels should match. Choices may also be given as hierarchy of
- * unlimited depth by creating nested arrays. The title of the sub-hierarchy
- * can be stored in the array key pointing to the nested array. The topmost
- * level of the hierarchy may also be a \Traversable.
- *
- * <code>
- * $choices = array(true, false);
- * $labels = array('Agree', 'Disagree');
- * $choiceList = new ChoiceList($choices, $labels);
- * </code>
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ChoiceList implements ChoiceListInterface
-{
- /**
- * The choices with their indices as keys.
- *
- * @var array
- */
- private $choices = array();
-
- /**
- * The choice values with the indices of the matching choices as keys.
- *
- * @var array
- */
- private $values = array();
-
- /**
- * The preferred view objects as hierarchy containing also the choice groups
- * with the indices of the matching choices as bottom-level keys.
- *
- * @var array
- */
- private $preferredViews = array();
-
- /**
- * The non-preferred view objects as hierarchy containing also the choice
- * groups with the indices of the matching choices as bottom-level keys.
- *
- * @var array
- */
- private $remainingViews = array();
-
- /**
- * Creates a new choice list.
- *
- * @param array|\Traversable $choices The array of choices. Choices may also be given
- * as hierarchy of unlimited depth. Hierarchies are
- * created by creating nested arrays. The title of
- * the sub-hierarchy can be stored in the array
- * key pointing to the nested array. The topmost
- * level of the hierarchy may also be a \Traversable.
- * @param array $labels The array of labels. The structure of this array
- * should match the structure of $choices.
- * @param array $preferredChoices A flat array of choices that should be
- * presented to the user with priority.
- *
- * @throws UnexpectedTypeException If the choices are not an array or \Traversable.
- */
- public function __construct($choices, array $labels, array $preferredChoices = array())
- {
- if (!is_array($choices) && !$choices instanceof \Traversable) {
- throw new UnexpectedTypeException($choices, 'array or \Traversable');
- }
-
- $this->initialize($choices, $labels, $preferredChoices);
- }
-
- /**
- * Initializes the list with choices.
- *
- * Safe to be called multiple times. The list is cleared on every call.
- *
- * @param array|\Traversable $choices The choices to write into the list.
- * @param array $labels The labels belonging to the choices.
- * @param array $preferredChoices The choices to display with priority.
- */
- protected function initialize($choices, array $labels, array $preferredChoices)
- {
- $this->choices = array();
- $this->values = array();
- $this->preferredViews = array();
- $this->remainingViews = array();
-
- $this->addChoices(
- $this->preferredViews,
- $this->remainingViews,
- $choices,
- $labels,
- $preferredChoices
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getChoices()
- {
- return $this->choices;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getValues()
- {
- return $this->values;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPreferredViews()
- {
- return $this->preferredViews;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRemainingViews()
- {
- return $this->remainingViews;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getChoicesForValues(array $values)
- {
- $values = $this->fixValues($values);
- $choices = array();
-
- foreach ($values as $j => $givenValue) {
- foreach ($this->values as $i => $value) {
- if ($value === $givenValue) {
- $choices[] = $this->choices[$i];
- unset($values[$j]);
-
- if (0 === count($values)) {
- break 2;
- }
- }
- }
- }
-
- return $choices;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getValuesForChoices(array $choices)
- {
- $choices = $this->fixChoices($choices);
- $values = array();
-
- foreach ($this->choices as $i => $choice) {
- foreach ($choices as $j => $givenChoice) {
- if ($choice === $givenChoice) {
- $values[] = $this->values[$i];
- unset($choices[$j]);
-
- if (0 === count($choices)) {
- break 2;
- }
- }
- }
- }
-
- return $values;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIndicesForChoices(array $choices)
- {
- $choices = $this->fixChoices($choices);
- $indices = array();
-
- foreach ($this->choices as $i => $choice) {
- foreach ($choices as $j => $givenChoice) {
- if ($choice === $givenChoice) {
- $indices[] = $i;
- unset($choices[$j]);
-
- if (0 === count($choices)) {
- break 2;
- }
- }
- }
- }
-
- return $indices;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIndicesForValues(array $values)
- {
- $values = $this->fixValues($values);
- $indices = array();
-
- foreach ($this->values as $i => $value) {
- foreach ($values as $j => $givenValue) {
- if ($value === $givenValue) {
- $indices[] = $i;
- unset($values[$j]);
-
- if (0 === count($values)) {
- break 2;
- }
- }
- }
- }
-
- return $indices;
- }
-
- /**
- * Recursively adds the given choices to the list.
- *
- * @param array $bucketForPreferred The bucket where to store the preferred
- * view objects.
- * @param array $bucketForRemaining The bucket where to store the
- * non-preferred view objects.
- * @param array|\Traversable $choices The list of choices.
- * @param array $labels The labels corresponding to the choices.
- * @param array $preferredChoices The preferred choices.
- *
- * @throws InvalidArgumentException If the structures of the choices and labels array do not match.
- * @throws InvalidConfigurationException If no valid value or index could be created for a choice.
- */
- protected function addChoices(array &$bucketForPreferred, array &$bucketForRemaining, $choices, array $labels, array $preferredChoices)
- {
- // Add choices to the nested buckets
- foreach ($choices as $group => $choice) {
- if (!array_key_exists($group, $labels)) {
- throw new InvalidArgumentException('The structures of the choices and labels array do not match.');
- }
-
- if (is_array($choice)) {
- // Don't do the work if the array is empty
- if (count($choice) > 0) {
- $this->addChoiceGroup(
- $group,
- $bucketForPreferred,
- $bucketForRemaining,
- $choice,
- $labels[$group],
- $preferredChoices
- );
- }
- } else {
- $this->addChoice(
- $bucketForPreferred,
- $bucketForRemaining,
- $choice,
- $labels[$group],
- $preferredChoices
- );
- }
- }
- }
-
- /**
- * Recursively adds a choice group.
- *
- * @param string $group The name of the group.
- * @param array $bucketForPreferred The bucket where to store the preferred
- * view objects.
- * @param array $bucketForRemaining The bucket where to store the
- * non-preferred view objects.
- * @param array $choices The list of choices in the group.
- * @param array $labels The labels corresponding to the choices in the group.
- * @param array $preferredChoices The preferred choices.
- *
- * @throws InvalidConfigurationException If no valid value or index could be created for a choice.
- */
- protected function addChoiceGroup($group, array &$bucketForPreferred, array &$bucketForRemaining, array $choices, array $labels, array $preferredChoices)
- {
- // If this is a choice group, create a new level in the choice
- // key hierarchy
- $bucketForPreferred[$group] = array();
- $bucketForRemaining[$group] = array();
-
- $this->addChoices(
- $bucketForPreferred[$group],
- $bucketForRemaining[$group],
- $choices,
- $labels,
- $preferredChoices
- );
-
- // Remove child levels if empty
- if (empty($bucketForPreferred[$group])) {
- unset($bucketForPreferred[$group]);
- }
- if (empty($bucketForRemaining[$group])) {
- unset($bucketForRemaining[$group]);
- }
- }
-
- /**
- * Adds a new choice.
- *
- * @param array $bucketForPreferred The bucket where to store the preferred
- * view objects.
- * @param array $bucketForRemaining The bucket where to store the
- * non-preferred view objects.
- * @param mixed $choice The choice to add.
- * @param string $label The label for the choice.
- * @param array $preferredChoices The preferred choices.
- *
- * @throws InvalidConfigurationException If no valid value or index could be created.
- */
- protected function addChoice(array &$bucketForPreferred, array &$bucketForRemaining, $choice, $label, array $preferredChoices)
- {
- $index = $this->createIndex($choice);
-
- if ('' === $index || null === $index || !FormConfigBuilder::isValidName((string) $index)) {
- throw new InvalidConfigurationException(sprintf('The index "%s" created by the choice list is invalid. It should be a valid, non-empty Form name.', $index));
- }
-
- $value = $this->createValue($choice);
-
- if (!is_string($value)) {
- throw new InvalidConfigurationException(sprintf('The value created by the choice list is of type "%s", but should be a string.', gettype($value)));
- }
-
- $view = new ChoiceView($choice, $value, $label);
-
- $this->choices[$index] = $this->fixChoice($choice);
- $this->values[$index] = $value;
-
- if ($this->isPreferred($choice, $preferredChoices)) {
- $bucketForPreferred[$index] = $view;
- } else {
- $bucketForRemaining[$index] = $view;
- }
- }
-
- /**
- * Returns whether the given choice should be preferred judging by the
- * given array of preferred choices.
- *
- * Extension point to optimize performance by changing the structure of the
- * $preferredChoices array.
- *
- * @param mixed $choice The choice to test.
- * @param array $preferredChoices An array of preferred choices.
- *
- * @return Boolean Whether the choice is preferred.
- */
- protected function isPreferred($choice, array $preferredChoices)
- {
- return false !== array_search($choice, $preferredChoices, true);
- }
-
- /**
- * Creates a new unique index for this choice.
- *
- * Extension point to change the indexing strategy.
- *
- * @param mixed $choice The choice to create an index for
- *
- * @return integer|string A unique index containing only ASCII letters,
- * digits and underscores.
- */
- protected function createIndex($choice)
- {
- return count($this->choices);
- }
-
- /**
- * Creates a new unique value for this choice.
- *
- * By default, an integer is generated since it cannot be guaranteed that
- * all values in the list are convertible to (unique) strings. Subclasses
- * can override this behaviour if they can guarantee this property.
- *
- * @param mixed $choice The choice to create a value for
- *
- * @return string A unique string.
- */
- protected function createValue($choice)
- {
- return (string) count($this->values);
- }
-
- /**
- * Fixes the data type of the given choice value to avoid comparison
- * problems.
- *
- * @param mixed $value The choice value.
- *
- * @return string The value as string.
- */
- protected function fixValue($value)
- {
- return (string) $value;
- }
-
- /**
- * Fixes the data types of the given choice values to avoid comparison
- * problems.
- *
- * @param array $values The choice values.
- *
- * @return array The values as strings.
- */
- protected function fixValues(array $values)
- {
- foreach ($values as $i => $value) {
- $values[$i] = $this->fixValue($value);
- }
-
- return $values;
- }
-
- /**
- * Fixes the data type of the given choice index to avoid comparison
- * problems.
- *
- * @param mixed $index The choice index.
- *
- * @return integer|string The index as PHP array key.
- */
- protected function fixIndex($index)
- {
- if (is_bool($index) || (string) (int) $index === (string) $index) {
- return (int) $index;
- }
-
- return (string) $index;
- }
-
- /**
- * Fixes the data types of the given choice indices to avoid comparison
- * problems.
- *
- * @param array $indices The choice indices.
- *
- * @return array The indices as strings.
- */
- protected function fixIndices(array $indices)
- {
- foreach ($indices as $i => $index) {
- $indices[$i] = $this->fixIndex($index);
- }
-
- return $indices;
- }
-
- /**
- * Fixes the data type of the given choice to avoid comparison problems.
- *
- * Extension point. In this implementation, choices are guaranteed to
- * always maintain their type and thus can be typesafely compared.
- *
- * @param mixed $choice The choice.
- *
- * @return mixed The fixed choice.
- */
- protected function fixChoice($choice)
- {
- return $choice;
- }
-
- /**
- * Fixes the data type of the given choices to avoid comparison problems.
- *
- * @param array $choices The choices.
- *
- * @return array The fixed choices.
- *
- * @see fixChoice
- */
- protected function fixChoices(array $choices)
- {
- return $choices;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\ChoiceList;
-
-/**
- * Contains choices that can be selected in a form field.
- *
- * Each choice has three different properties:
- *
- * - Choice: The choice that should be returned to the application by the
- * choice field. Can be any scalar value or an object, but no
- * array.
- * - Label: A text representing the choice that is displayed to the user.
- * - Value: A uniquely identifying value that can contain arbitrary
- * characters, but no arrays or objects. This value is displayed
- * in the HTML "value" attribute.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ChoiceListInterface
-{
- /**
- * Returns the list of choices
- *
- * @return array The choices with their indices as keys
- */
- public function getChoices();
-
- /**
- * Returns the values for the choices
- *
- * @return array The values with the corresponding choice indices as keys
- */
- public function getValues();
-
- /**
- * Returns the choice views of the preferred choices as nested array with
- * the choice groups as top-level keys.
- *
- * Example:
- *
- * <source>
- * array(
- * 'Group 1' => array(
- * 10 => ChoiceView object,
- * 20 => ChoiceView object,
- * ),
- * 'Group 2' => array(
- * 30 => ChoiceView object,
- * ),
- * )
- * </source>
- *
- * @return array A nested array containing the views with the corresponding
- * choice indices as keys on the lowest levels and the choice
- * group names in the keys of the higher levels
- */
- public function getPreferredViews();
-
- /**
- * Returns the choice views of the choices that are not preferred as nested
- * array with the choice groups as top-level keys.
- *
- * Example:
- *
- * <source>
- * array(
- * 'Group 1' => array(
- * 10 => ChoiceView object,
- * 20 => ChoiceView object,
- * ),
- * 'Group 2' => array(
- * 30 => ChoiceView object,
- * ),
- * )
- * </source>
- *
- * @return array A nested array containing the views with the corresponding
- * choice indices as keys on the lowest levels and the choice
- * group names in the keys of the higher levels
- *
- * @see getPreferredValues
- */
- public function getRemainingViews();
-
- /**
- * Returns the choices corresponding to the given values.
- *
- * The choices can have any data type.
- *
- * @param array $values An array of choice values. Not existing values in
- * this array are ignored
- *
- * @return array An array of choices with ascending, 0-based numeric keys
- */
- public function getChoicesForValues(array $values);
-
- /**
- * Returns the values corresponding to the given choices.
- *
- * The values must be strings.
- *
- * @param array $choices An array of choices. Not existing choices in this
- * array are ignored
- *
- * @return array An array of choice values with ascending, 0-based numeric
- * keys
- */
- public function getValuesForChoices(array $choices);
-
- /**
- * Returns the indices corresponding to the given choices.
- *
- * The indices must be positive integers or strings accepted by
- * {@link FormConfigBuilder::validateName()}.
- *
- * The index "placeholder" is internally reserved.
- *
- * @param array $choices An array of choices. Not existing choices in this
- * array are ignored
- *
- * @return array An array of indices with ascending, 0-based numeric keys
- */
- public function getIndicesForChoices(array $choices);
-
- /**
- * Returns the indices corresponding to the given values.
- *
- * The indices must be positive integers or strings accepted by
- * {@link FormConfigBuilder::validateName()}.
- *
- * The index "placeholder" is internally reserved.
- *
- * @param array $values An array of choice values. Not existing values in
- * this array are ignored
- *
- * @return array An array of indices with ascending, 0-based numeric keys
- */
- public function getIndicesForValues(array $values);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\ChoiceList;
-
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-
-/**
- * A choice list that is loaded lazily
- *
- * This list loads itself as soon as any of the getters is accessed for the
- * first time. You should implement loadChoiceList() in your child classes,
- * which should return a ChoiceListInterface instance.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class LazyChoiceList implements ChoiceListInterface
-{
- /**
- * The loaded choice list
- *
- * @var ChoiceListInterface
- */
- private $choiceList;
-
- /**
- * {@inheritdoc}
- */
- public function getChoices()
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getChoices();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getValues()
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getValues();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPreferredViews()
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getPreferredViews();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRemainingViews()
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getRemainingViews();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getChoicesForValues(array $values)
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getChoicesForValues($values);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getValuesForChoices(array $choices)
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getValuesForChoices($choices);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIndicesForChoices(array $choices)
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getIndicesForChoices($choices);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIndicesForValues(array $values)
- {
- if (!$this->choiceList) {
- $this->load();
- }
-
- return $this->choiceList->getIndicesForValues($values);
- }
-
- /**
- * Loads the choice list
- *
- * Should be implemented by child classes.
- *
- * @return ChoiceListInterface The loaded choice list
- */
- abstract protected function loadChoiceList();
-
- private function load()
- {
- $choiceList = $this->loadChoiceList();
-
- if (!$choiceList instanceof ChoiceListInterface) {
- throw new InvalidArgumentException(sprintf('loadChoiceList() should return a ChoiceListInterface instance. Got %s', gettype($choiceList)));
- }
-
- $this->choiceList = $choiceList;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
-*
-* (c) Fabien Potencier <fabien@symfony.com>
-*
-* For the full copyright and license information, please view the LICENSE
-* file that was distributed with this source code.
-*/
-
-namespace Symfony\Component\Form\Extension\Core\ChoiceList;
-
-use Symfony\Component\Form\Exception\StringCastException;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\PropertyAccess\PropertyPath;
-use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
-use Symfony\Component\PropertyAccess\PropertyAccess;
-use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
-
-/**
- * A choice list for object choices.
- *
- * Supports generation of choice labels, choice groups and choice values
- * by calling getters of the object (or associated objects).
- *
- * <code>
- * $choices = array($user1, $user2);
- *
- * // call getName() to determine the choice labels
- * $choiceList = new ObjectChoiceList($choices, 'name');
- * </code>
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ObjectChoiceList extends ChoiceList
-{
- /**
- * @var PropertyAccessorInterface
- */
- private $propertyAccessor;
-
- /**
- * The property path used to obtain the choice label.
- *
- * @var PropertyPath
- */
- private $labelPath;
-
- /**
- * The property path used for object grouping.
- *
- * @var PropertyPath
- */
- private $groupPath;
-
- /**
- * The property path used to obtain the choice value.
- *
- * @var PropertyPath
- */
- private $valuePath;
-
- /**
- * Creates a new object choice list.
- *
- * @param array|\Traversable $choices The array of choices. Choices may also be given
- * as hierarchy of unlimited depth by creating nested
- * arrays. The title of the sub-hierarchy can be
- * stored in the array key pointing to the nested
- * array. The topmost level of the hierarchy may also
- * be a \Traversable.
- * @param string $labelPath A property path pointing to the property used
- * for the choice labels. The value is obtained
- * by calling the getter on the object. If the
- * path is NULL, the object's __toString() method
- * is used instead.
- * @param array $preferredChoices A flat array of choices that should be
- * presented to the user with priority.
- * @param string $groupPath A property path pointing to the property used
- * to group the choices. Only allowed if
- * the choices are given as flat array.
- * @param string $valuePath A property path pointing to the property used
- * for the choice values. If not given, integers
- * are generated instead.
- * @param PropertyAccessorInterface $propertyAccessor The reflection graph for reading property paths.
- */
- public function __construct($choices, $labelPath = null, array $preferredChoices = array(), $groupPath = null, $valuePath = null, PropertyAccessorInterface $propertyAccessor = null)
- {
- $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
- $this->labelPath = null !== $labelPath ? new PropertyPath($labelPath) : null;
- $this->groupPath = null !== $groupPath ? new PropertyPath($groupPath) : null;
- $this->valuePath = null !== $valuePath ? new PropertyPath($valuePath) : null;
-
- parent::__construct($choices, array(), $preferredChoices);
- }
-
- /**
- * Initializes the list with choices.
- *
- * Safe to be called multiple times. The list is cleared on every call.
- *
- * @param array|\Traversable $choices The choices to write into the list.
- * @param array $labels Ignored.
- * @param array $preferredChoices The choices to display with priority.
- *
- * @throws InvalidArgumentException When passing a hierarchy of choices and using
- * the "groupPath" option at the same time.
- */
- protected function initialize($choices, array $labels, array $preferredChoices)
- {
- if (null !== $this->groupPath) {
- $groupedChoices = array();
-
- foreach ($choices as $i => $choice) {
- if (is_array($choice)) {
- throw new InvalidArgumentException('You should pass a plain object array (without groups) when using the "groupPath" option.');
- }
-
- try {
- $group = $this->propertyAccessor->getValue($choice, $this->groupPath);
- } catch (NoSuchPropertyException $e) {
- // Don't group items whose group property does not exist
- // see https://github.com/symfony/symfony/commit/d9b7abb7c7a0f28e0ce970afc5e305dce5dccddf
- $group = null;
- }
-
- if (null === $group) {
- $groupedChoices[$i] = $choice;
- } else {
- if (!isset($groupedChoices[$group])) {
- $groupedChoices[$group] = array();
- }
-
- $groupedChoices[$group][$i] = $choice;
- }
- }
-
- $choices = $groupedChoices;
- }
-
- $labels = array();
-
- $this->extractLabels($choices, $labels);
-
- parent::initialize($choices, $labels, $preferredChoices);
- }
-
- /**
- * Creates a new unique value for this choice.
- *
- * If a property path for the value was given at object creation,
- * the getter behind that path is now called to obtain a new value.
- * Otherwise a new integer is generated.
- *
- * @param mixed $choice The choice to create a value for
- *
- * @return integer|string A unique value without character limitations.
- */
- protected function createValue($choice)
- {
- if ($this->valuePath) {
- return (string) $this->propertyAccessor->getValue($choice, $this->valuePath);
- }
-
- return parent::createValue($choice);
- }
-
- private function extractLabels($choices, array &$labels)
- {
- foreach ($choices as $i => $choice) {
- if (is_array($choice)) {
- $labels[$i] = array();
- $this->extractLabels($choice, $labels[$i]);
- } elseif ($this->labelPath) {
- $labels[$i] = $this->propertyAccessor->getValue($choice, $this->labelPath);
- } elseif (method_exists($choice, '__toString')) {
- $labels[$i] = (string) $choice;
- } else {
- throw new StringCastException(sprintf('A "__toString()" method was not found on the objects of type "%s" passed to the choice field. To read a custom getter instead, set the argument $labelPath to the desired property path.', get_class($choice)));
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\ChoiceList;
-
-/**
- * A choice list for choices of type string or integer.
- *
- * Choices and their associated labels can be passed in a single array. Since
- * choices are passed as array keys, only strings or integer choices are
- * allowed. Choices may also be given as hierarchy of unlimited depth by
- * creating nested arrays. The title of the sub-hierarchy can be stored in the
- * array key pointing to the nested array.
- *
- * <code>
- * $choiceList = new SimpleChoiceList(array(
- * 'creditcard' => 'Credit card payment',
- * 'cash' => 'Cash payment',
- * ));
- * </code>
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SimpleChoiceList extends ChoiceList
-{
- /**
- * Creates a new simple choice list.
- *
- * @param array $choices The array of choices with the choices as keys and
- * the labels as values. Choices may also be given
- * as hierarchy of unlimited depth by creating nested
- * arrays. The title of the sub-hierarchy is stored
- * in the array key pointing to the nested array.
- * @param array $preferredChoices A flat array of choices that should be
- * presented to the user with priority.
- */
- public function __construct(array $choices, array $preferredChoices = array())
- {
- // Flip preferred choices to speed up lookup
- parent::__construct($choices, $choices, array_flip($preferredChoices));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getChoicesForValues(array $values)
- {
- $values = $this->fixValues($values);
-
- // The values are identical to the choices, so we can just return them
- // to improve performance a little bit
- return $this->fixChoices(array_intersect($values, $this->getValues()));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getValuesForChoices(array $choices)
- {
- $choices = $this->fixChoices($choices);
-
- // The choices are identical to the values, so we can just return them
- // to improve performance a little bit
- return $this->fixValues(array_intersect($choices, $this->getValues()));
- }
-
- /**
- * Recursively adds the given choices to the list.
- *
- * Takes care of splitting the single $choices array passed in the
- * constructor into choices and labels.
- *
- * @param array $bucketForPreferred The bucket where to store the preferred
- * view objects.
- * @param array $bucketForRemaining The bucket where to store the
- * non-preferred view objects.
- * @param array|\Traversable $choices The list of choices.
- * @param array $labels Ignored.
- * @param array $preferredChoices The preferred choices.
- */
- protected function addChoices(array &$bucketForPreferred, array &$bucketForRemaining, $choices, array $labels, array $preferredChoices)
- {
- // Add choices to the nested buckets
- foreach ($choices as $choice => $label) {
- if (is_array($label)) {
- // Don't do the work if the array is empty
- if (count($label) > 0) {
- $this->addChoiceGroup(
- $choice,
- $bucketForPreferred,
- $bucketForRemaining,
- $label,
- $label,
- $preferredChoices
- );
- }
- } else {
- $this->addChoice(
- $bucketForPreferred,
- $bucketForRemaining,
- $choice,
- $label,
- $preferredChoices
- );
- }
- }
- }
-
- /**
- * Returns whether the given choice should be preferred judging by the
- * given array of preferred choices.
- *
- * Optimized for performance by treating the preferred choices as array
- * where choices are stored in the keys.
- *
- * @param mixed $choice The choice to test.
- * @param array $preferredChoices An array of preferred choices.
- *
- * @return Boolean Whether the choice is preferred.
- */
- protected function isPreferred($choice, array $preferredChoices)
- {
- // Optimize performance over the default implementation
- return isset($preferredChoices[$choice]);
- }
-
- /**
- * Converts the choice to a valid PHP array key.
- *
- * @param mixed $choice The choice.
- *
- * @return string|integer A valid PHP array key.
- */
- protected function fixChoice($choice)
- {
- return $this->fixIndex($choice);
- }
-
- /**
- * {@inheritdoc}
- */
- protected function fixChoices(array $choices)
- {
- return $this->fixIndices($choices);
- }
-
- /**
- * {@inheritdoc}
- */
- protected function createValue($choice)
- {
- // Choices are guaranteed to be unique and scalar, so we can simply
- // convert them to strings
- return (string) $choice;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core;
-
-use Symfony\Component\Form\AbstractExtension;
-use Symfony\Component\PropertyAccess\PropertyAccess;
-
-/**
- * Represents the main form extension, which loads the core functionality.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CoreExtension extends AbstractExtension
-{
- protected function loadTypes()
- {
- return array(
- new Type\FormType(PropertyAccess::getPropertyAccessor()),
- new Type\BirthdayType(),
- new Type\CheckboxType(),
- new Type\ChoiceType(),
- new Type\CollectionType(),
- new Type\CountryType(),
- new Type\DateType(),
- new Type\DateTimeType(),
- new Type\EmailType(),
- new Type\HiddenType(),
- new Type\IntegerType(),
- new Type\LanguageType(),
- new Type\LocaleType(),
- new Type\MoneyType(),
- new Type\NumberType(),
- new Type\PasswordType(),
- new Type\PercentType(),
- new Type\RadioType(),
- new Type\RepeatedType(),
- new Type\SearchType(),
- new Type\TextareaType(),
- new Type\TextType(),
- new Type\TimeType(),
- new Type\TimezoneType(),
- new Type\UrlType(),
- new Type\FileType(),
- new Type\ButtonType(),
- new Type\SubmitType(),
- new Type\ResetType(),
- new Type\CurrencyType(),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataMapper;
-
-use Symfony\Component\Form\DataMapperInterface;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\PropertyAccess\PropertyAccess;
-use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
-
-/**
- * A data mapper using property paths to read/write data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PropertyPathMapper implements DataMapperInterface
-{
- /**
- * @var PropertyAccessorInterface
- */
- private $propertyAccessor;
-
- /**
- * Creates a new property path mapper.
- *
- * @param PropertyAccessorInterface $propertyAccessor
- */
- public function __construct(PropertyAccessorInterface $propertyAccessor = null)
- {
- $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
- }
-
- /**
- * {@inheritdoc}
- */
- public function mapDataToForms($data, $forms)
- {
- if (null === $data || array() === $data) {
- return;
- }
-
- if (!is_array($data) && !is_object($data)) {
- throw new UnexpectedTypeException($data, 'object, array or empty');
- }
-
- foreach ($forms as $form) {
- $propertyPath = $form->getPropertyPath();
- $config = $form->getConfig();
-
- if (null !== $propertyPath && $config->getMapped()) {
- $form->setData($this->propertyAccessor->getValue($data, $propertyPath));
- }
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function mapFormsToData($forms, &$data)
- {
- if (null === $data) {
- return;
- }
-
- if (!is_array($data) && !is_object($data)) {
- throw new UnexpectedTypeException($data, 'object, array or empty');
- }
-
- foreach ($forms as $form) {
- $propertyPath = $form->getPropertyPath();
- $config = $form->getConfig();
-
- // Write-back is disabled if the form is not synchronized (transformation failed)
- // and if the form is disabled (modification not allowed)
- if (null !== $propertyPath && $config->getMapped() && $form->isSynchronized() && !$form->isDisabled()) {
- // If the data is identical to the value in $data, we are
- // dealing with a reference
- if (!is_object($data) || !$config->getByReference() || $form->getData() !== $this->propertyAccessor->getValue($data, $propertyPath)) {
- $this->propertyAccessor->setValue($data, $propertyPath, $form->getData());
- }
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ArrayToPartsTransformer implements DataTransformerInterface
-{
- private $partMapping;
-
- public function __construct(array $partMapping)
- {
- $this->partMapping = $partMapping;
- }
-
- public function transform($array)
- {
- if (null === $array) {
- $array = array();
- }
-
- if (!is_array($array) ) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- $result = array();
-
- foreach ($this->partMapping as $partKey => $originalKeys) {
- if (empty($array)) {
- $result[$partKey] = null;
- } else {
- $result[$partKey] = array_intersect_key($array, array_flip($originalKeys));
- }
- }
-
- return $result;
- }
-
- public function reverseTransform($array)
- {
- if (!is_array($array) ) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- $result = array();
- $emptyKeys = array();
-
- foreach ($this->partMapping as $partKey => $originalKeys) {
- if (!empty($array[$partKey])) {
- foreach ($originalKeys as $originalKey) {
- if (isset($array[$partKey][$originalKey])) {
- $result[$originalKey] = $array[$partKey][$originalKey];
- }
- }
- } else {
- $emptyKeys[] = $partKey;
- }
- }
-
- if (count($emptyKeys) > 0) {
- if (count($emptyKeys) === count($this->partMapping)) {
- // All parts empty
- return null;
- }
-
- throw new TransformationFailedException(
- sprintf('The keys "%s" should not be empty', implode('", "', $emptyKeys)
- ));
- }
-
- return $result;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-abstract class BaseDateTimeTransformer implements DataTransformerInterface
-{
- protected static $formats = array(
- \IntlDateFormatter::NONE,
- \IntlDateFormatter::FULL,
- \IntlDateFormatter::LONG,
- \IntlDateFormatter::MEDIUM,
- \IntlDateFormatter::SHORT,
- );
-
- protected $inputTimezone;
-
- protected $outputTimezone;
-
- /**
- * Constructor.
- *
- * @param string $inputTimezone The name of the input timezone
- * @param string $outputTimezone The name of the output timezone
- *
- * @throws UnexpectedTypeException if a timezone is not a string
- */
- public function __construct($inputTimezone = null, $outputTimezone = null)
- {
- if (!is_string($inputTimezone) && null !== $inputTimezone) {
- throw new UnexpectedTypeException($inputTimezone, 'string');
- }
-
- if (!is_string($outputTimezone) && null !== $outputTimezone) {
- throw new UnexpectedTypeException($outputTimezone, 'string');
- }
-
- $this->inputTimezone = $inputTimezone ?: date_default_timezone_get();
- $this->outputTimezone = $outputTimezone ?: date_default_timezone_get();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * Transforms between a Boolean and a string.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class BooleanToStringTransformer implements DataTransformerInterface
-{
- /**
- * The value emitted upon transform if the input is true
- * @var string
- */
- private $trueValue;
-
- /**
- * Sets the value emitted upon transform if the input is true.
- *
- * @param string $trueValue
- */
- public function __construct($trueValue)
- {
- $this->trueValue = $trueValue;
- }
-
- /**
- * Transforms a Boolean into a string.
- *
- * @param Boolean $value Boolean value.
- *
- * @return string String value.
- *
- * @throws TransformationFailedException If the given value is not a Boolean.
- */
- public function transform($value)
- {
- if (null === $value) {
- return null;
- }
-
- if (!is_bool($value)) {
- throw new TransformationFailedException('Expected a Boolean.');
- }
-
- return true === $value ? $this->trueValue : null;
- }
-
- /**
- * Transforms a string into a Boolean.
- *
- * @param string $value String value.
- *
- * @return Boolean Boolean value.
- *
- * @throws TransformationFailedException If the given value is not a string.
- */
- public function reverseTransform($value)
- {
- if (null === $value) {
- return false;
- }
-
- if (!is_string($value)) {
- throw new TransformationFailedException('Expected a string.');
- }
-
- return true;
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ChoiceToBooleanArrayTransformer implements DataTransformerInterface
-{
- private $choiceList;
-
- private $placeholderPresent;
-
- /**
- * Constructor.
- *
- * @param ChoiceListInterface $choiceList
- * @param Boolean $placeholderPresent
- */
- public function __construct(ChoiceListInterface $choiceList, $placeholderPresent)
- {
- $this->choiceList = $choiceList;
- $this->placeholderPresent = $placeholderPresent;
- }
-
- /**
- * Transforms a single choice to a format appropriate for the nested
- * checkboxes/radio buttons.
- *
- * The result is an array with the options as keys and true/false as values,
- * depending on whether a given option is selected. If this field is rendered
- * as select tag, the value is not modified.
- *
- * @param mixed $choice An array if "multiple" is set to true, a scalar
- * value otherwise.
- *
- * @return mixed An array
- *
- * @throws TransformationFailedException If the given value is not scalar or
- * if the choices can not be retrieved.
- */
- public function transform($choice)
- {
- try {
- $values = $this->choiceList->getValues();
- } catch (\Exception $e) {
- throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
- }
-
- $index = current($this->choiceList->getIndicesForChoices(array($choice)));
-
- foreach ($values as $i => $value) {
- $values[$i] = $i === $index;
- }
-
- if ($this->placeholderPresent) {
- $values['placeholder'] = false === $index;
- }
-
- return $values;
- }
-
- /**
- * Transforms a checkbox/radio button array to a single choice.
- *
- * The input value is an array with the choices as keys and true/false as
- * values, depending on whether a given choice is selected. The output
- * is the selected choice.
- *
- * @param array $values An array of values
- *
- * @return mixed A scalar value
- *
- * @throws TransformationFailedException If the given value is not an array,
- * if the recuperation of the choices
- * fails or if some choice can't be
- * found.
- */
- public function reverseTransform($values)
- {
- if (!is_array($values)) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- try {
- $choices = $this->choiceList->getChoices();
- } catch (\Exception $e) {
- throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
- }
-
- foreach ($values as $i => $selected) {
- if ($selected) {
- if (isset($choices[$i])) {
- return $choices[$i] === '' ? null : $choices[$i];
- } elseif ($this->placeholderPresent && 'placeholder' === $i) {
- return null;
- } else {
- throw new TransformationFailedException(sprintf('The choice "%s" does not exist', $i));
- }
- }
- }
-
- return null;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ChoiceToValueTransformer implements DataTransformerInterface
-{
- private $choiceList;
-
- /**
- * Constructor.
- *
- * @param ChoiceListInterface $choiceList
- */
- public function __construct(ChoiceListInterface $choiceList)
- {
- $this->choiceList = $choiceList;
- }
-
- public function transform($choice)
- {
- return (string) current($this->choiceList->getValuesForChoices(array($choice)));
- }
-
- public function reverseTransform($value)
- {
- if (null !== $value && !is_scalar($value)) {
- throw new TransformationFailedException('Expected a scalar.');
- }
-
- // These are now valid ChoiceList values, so we can return null
- // right away
- if ('' === $value || null === $value) {
- return null;
- }
-
- $choices = $this->choiceList->getChoicesForValues(array($value));
-
- if (1 !== count($choices)) {
- throw new TransformationFailedException(sprintf('The choice "%s" does not exist or is not unique', $value));
- }
-
- $choice = current($choices);
-
- return '' === $choice ? null : $choice;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ChoicesToBooleanArrayTransformer implements DataTransformerInterface
-{
- private $choiceList;
-
- public function __construct(ChoiceListInterface $choiceList)
- {
- $this->choiceList = $choiceList;
- }
-
- /**
- * Transforms an array of choices to a format appropriate for the nested
- * checkboxes/radio buttons.
- *
- * The result is an array with the options as keys and true/false as values,
- * depending on whether a given option is selected. If this field is rendered
- * as select tag, the value is not modified.
- *
- * @param mixed $array An array
- *
- * @return mixed An array
- *
- * @throws TransformationFailedException If the given value is not an array
- * or if the choices can not be retrieved.
- */
- public function transform($array)
- {
- if (null === $array) {
- return array();
- }
-
- if (!is_array($array)) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- try {
- $values = $this->choiceList->getValues();
- } catch (\Exception $e) {
- throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
- }
-
- $indexMap = array_flip($this->choiceList->getIndicesForChoices($array));
-
- foreach ($values as $i => $value) {
- $values[$i] = isset($indexMap[$i]);
- }
-
- return $values;
- }
-
- /**
- * Transforms a checkbox/radio button array to an array of choices.
- *
- * The input value is an array with the choices as keys and true/false as
- * values, depending on whether a given choice is selected. The output
- * is an array with the selected choices.
- *
- * @param mixed $values An array
- *
- * @return mixed An array
- *
- * @throws TransformationFailedException If the given value is not an array,
- * if the recuperation of the choices
- * fails or if some choice can't be
- * found.
- */
- public function reverseTransform($values)
- {
- if (!is_array($values)) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- try {
- $choices = $this->choiceList->getChoices();
- } catch (\Exception $e) {
- throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
- }
-
- $result = array();
- $unknown = array();
-
- foreach ($values as $i => $selected) {
- if ($selected) {
- if (isset($choices[$i])) {
- $result[] = $choices[$i];
- } else {
- $unknown[] = $i;
- }
- }
- }
-
- if (count($unknown) > 0) {
- throw new TransformationFailedException(sprintf('The choices "%s" were not found', implode('", "', $unknown)));
- }
-
- return $result;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ChoicesToValuesTransformer implements DataTransformerInterface
-{
- private $choiceList;
-
- /**
- * Constructor.
- *
- * @param ChoiceListInterface $choiceList
- */
- public function __construct(ChoiceListInterface $choiceList)
- {
- $this->choiceList = $choiceList;
- }
-
- /**
- * @param array $array
- *
- * @return array
- *
- * @throws TransformationFailedException If the given value is not an array.
- */
- public function transform($array)
- {
- if (null === $array) {
- return array();
- }
-
- if (!is_array($array)) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- return $this->choiceList->getValuesForChoices($array);
- }
-
- /**
- * @param array $array
- *
- * @return array
- *
- * @throws TransformationFailedException If the given value is not an array
- * or if no matching choice could be
- * found for some given value.
- */
- public function reverseTransform($array)
- {
- if (null === $array) {
- return array();
- }
-
- if (!is_array($array)) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- $choices = $this->choiceList->getChoicesForValues($array);
-
- if (count($choices) !== count($array)) {
- throw new TransformationFailedException('Could not find all matching choices for the given values');
- }
-
- return $choices;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * Passes a value through multiple value transformers
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class DataTransformerChain implements DataTransformerInterface
-{
- /**
- * The value transformers
- * @var DataTransformerInterface[]
- */
- protected $transformers;
-
- /**
- * Uses the given value transformers to transform values
- *
- * @param array $transformers
- */
- public function __construct(array $transformers)
- {
- $this->transformers = $transformers;
- }
-
- /**
- * Passes the value through the transform() method of all nested transformers
- *
- * The transformers receive the value in the same order as they were passed
- * to the constructor. Each transformer receives the result of the previous
- * transformer as input. The output of the last transformer is returned
- * by this method.
- *
- * @param mixed $value The original value
- *
- * @return mixed The transformed value
- *
- * @throws TransformationFailedException
- */
- public function transform($value)
- {
- foreach ($this->transformers as $transformer) {
- $value = $transformer->transform($value);
- }
-
- return $value;
- }
-
- /**
- * Passes the value through the reverseTransform() method of all nested
- * transformers
- *
- * The transformers receive the value in the reverse order as they were passed
- * to the constructor. Each transformer receives the result of the previous
- * transformer as input. The output of the last transformer is returned
- * by this method.
- *
- * @param mixed $value The transformed value
- *
- * @return mixed The reverse-transformed value
- *
- * @throws TransformationFailedException
- */
- public function reverseTransform($value)
- {
- for ($i = count($this->transformers) - 1; $i >= 0; --$i) {
- $value = $this->transformers[$i]->reverseTransform($value);
- }
-
- return $value;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-/**
- * Transforms between a normalized time and a localized time string/array.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class DateTimeToArrayTransformer extends BaseDateTimeTransformer
-{
- private $pad;
-
- private $fields;
-
- /**
- * Constructor.
- *
- * @param string $inputTimezone The input timezone
- * @param string $outputTimezone The output timezone
- * @param array $fields The date fields
- * @param Boolean $pad Whether to use padding
- *
- * @throws UnexpectedTypeException if a timezone is not a string
- */
- public function __construct($inputTimezone = null, $outputTimezone = null, array $fields = null, $pad = false)
- {
- parent::__construct($inputTimezone, $outputTimezone);
-
- if (null === $fields) {
- $fields = array('year', 'month', 'day', 'hour', 'minute', 'second');
- }
-
- $this->fields = $fields;
- $this->pad = (Boolean) $pad;
- }
-
- /**
- * Transforms a normalized date into a localized date.
- *
- * @param \DateTime $dateTime Normalized date.
- *
- * @return array Localized date.
- *
- * @throws TransformationFailedException If the given value is not an
- * instance of \DateTime or if the
- * output timezone is not supported.
- */
- public function transform($dateTime)
- {
- if (null === $dateTime) {
- return array_intersect_key(array(
- 'year' => '',
- 'month' => '',
- 'day' => '',
- 'hour' => '',
- 'minute' => '',
- 'second' => '',
- ), array_flip($this->fields));
- }
-
- if (!$dateTime instanceof \DateTime) {
- throw new TransformationFailedException('Expected a \DateTime.');
- }
-
- $dateTime = clone $dateTime;
- if ($this->inputTimezone !== $this->outputTimezone) {
- try {
- $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
- }
-
- $result = array_intersect_key(array(
- 'year' => $dateTime->format('Y'),
- 'month' => $dateTime->format('m'),
- 'day' => $dateTime->format('d'),
- 'hour' => $dateTime->format('H'),
- 'minute' => $dateTime->format('i'),
- 'second' => $dateTime->format('s'),
- ), array_flip($this->fields));
-
- if (!$this->pad) {
- foreach ($result as &$entry) {
- // remove leading zeros
- $entry = (string) (int) $entry;
- }
- }
-
- return $result;
- }
-
- /**
- * Transforms a localized date into a normalized date.
- *
- * @param array $value Localized date
- *
- * @return \DateTime Normalized date
- *
- * @throws TransformationFailedException If the given value is not an array,
- * if the value could not be transformed
- * or if the input timezone is not
- * supported.
- */
- public function reverseTransform($value)
- {
- if (null === $value) {
- return null;
- }
-
- if (!is_array($value)) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- if ('' === implode('', $value)) {
- return null;
- }
-
- $emptyFields = array();
-
- foreach ($this->fields as $field) {
- if (!isset($value[$field])) {
- $emptyFields[] = $field;
- }
- }
-
- if (count($emptyFields) > 0) {
- throw new TransformationFailedException(
- sprintf('The fields "%s" should not be empty', implode('", "', $emptyFields)
- ));
- }
-
- if (isset($value['month']) && !ctype_digit($value['month']) && !is_int($value['month'])) {
- throw new TransformationFailedException('This month is invalid');
- }
-
- if (isset($value['day']) && !ctype_digit($value['day']) && !is_int($value['day'])) {
- throw new TransformationFailedException('This day is invalid');
- }
-
- if (isset($value['year']) && !ctype_digit($value['year']) && !is_int($value['year'])) {
- throw new TransformationFailedException('This year is invalid');
- }
-
- if (!empty($value['month']) && !empty($value['day']) && !empty($value['year']) && false === checkdate($value['month'], $value['day'], $value['year'])) {
- throw new TransformationFailedException('This is an invalid date');
- }
-
- try {
- $dateTime = new \DateTime(sprintf(
- '%s-%s-%s %s:%s:%s %s',
- empty($value['year']) ? '1970' : $value['year'],
- empty($value['month']) ? '1' : $value['month'],
- empty($value['day']) ? '1' : $value['day'],
- empty($value['hour']) ? '0' : $value['hour'],
- empty($value['minute']) ? '0' : $value['minute'],
- empty($value['second']) ? '0' : $value['second'],
- $this->outputTimezone
- ));
-
- if ($this->inputTimezone !== $this->outputTimezone) {
- $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
- }
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
-
- return $dateTime;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-/**
- * Transforms between a normalized time and a localized time string
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
-{
- private $dateFormat;
- private $timeFormat;
- private $pattern;
- private $calendar;
-
- /**
- * Constructor.
- *
- * @see BaseDateTimeTransformer::formats for available format options
- *
- * @param string $inputTimezone The name of the input timezone
- * @param string $outputTimezone The name of the output timezone
- * @param integer $dateFormat The date format
- * @param integer $timeFormat The time format
- * @param integer $calendar One of the \IntlDateFormatter calendar constants
- * @param string $pattern A pattern to pass to \IntlDateFormatter
- *
- * @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string
- */
- public function __construct($inputTimezone = null, $outputTimezone = null, $dateFormat = null, $timeFormat = null, $calendar = \IntlDateFormatter::GREGORIAN, $pattern = null)
- {
- parent::__construct($inputTimezone, $outputTimezone);
-
- if (null === $dateFormat) {
- $dateFormat = \IntlDateFormatter::MEDIUM;
- }
-
- if (null === $timeFormat) {
- $timeFormat = \IntlDateFormatter::SHORT;
- }
-
- if (!in_array($dateFormat, self::$formats, true)) {
- throw new UnexpectedTypeException($dateFormat, implode('", "', self::$formats));
- }
-
- if (!in_array($timeFormat, self::$formats, true)) {
- throw new UnexpectedTypeException($timeFormat, implode('", "', self::$formats));
- }
-
- $this->dateFormat = $dateFormat;
- $this->timeFormat = $timeFormat;
- $this->calendar = $calendar;
- $this->pattern = $pattern;
- }
-
- /**
- * Transforms a normalized date into a localized date string/array.
- *
- * @param \DateTime $dateTime Normalized date.
- *
- * @return string|array Localized date string/array.
- *
- * @throws TransformationFailedException If the given value is not an instance
- * of \DateTime or if the date could not
- * be transformed.
- */
- public function transform($dateTime)
- {
- if (null === $dateTime) {
- return '';
- }
-
- if (!$dateTime instanceof \DateTime) {
- throw new TransformationFailedException('Expected a \DateTime.');
- }
-
- // convert time to UTC before passing it to the formatter
- $dateTime = clone $dateTime;
- if ('UTC' !== $this->inputTimezone) {
- $dateTime->setTimezone(new \DateTimeZone('UTC'));
- }
-
- $value = $this->getIntlDateFormatter()->format((int) $dateTime->format('U'));
-
- if (intl_get_error_code() != 0) {
- throw new TransformationFailedException(intl_get_error_message());
- }
-
- return $value;
- }
-
- /**
- * Transforms a localized date string/array into a normalized date.
- *
- * @param string|array $value Localized date string/array
- *
- * @return \DateTime Normalized date
- *
- * @throws TransformationFailedException if the given value is not a string,
- * if the date could not be parsed or
- * if the input timezone is not supported
- */
- public function reverseTransform($value)
- {
- if (!is_string($value)) {
- throw new TransformationFailedException('Expected a string.');
- }
-
- if ('' === $value) {
- return null;
- }
-
- $timestamp = $this->getIntlDateFormatter()->parse($value);
-
- if (intl_get_error_code() != 0) {
- throw new TransformationFailedException(intl_get_error_message());
- }
-
- try {
- // read timestamp into DateTime object - the formatter delivers in UTC
- $dateTime = new \DateTime(sprintf('@%s UTC', $timestamp));
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
-
- if ('UTC' !== $this->inputTimezone) {
- try {
- $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
- }
-
- return $dateTime;
- }
-
- /**
- * Returns a preconfigured IntlDateFormatter instance
- *
- * @return \IntlDateFormatter
- */
- protected function getIntlDateFormatter()
- {
- $dateFormat = $this->dateFormat;
- $timeFormat = $this->timeFormat;
- $timezone = $this->outputTimezone;
- $calendar = $this->calendar;
- $pattern = $this->pattern;
-
- $intlDateFormatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormat, $timeFormat, $timezone, $calendar, $pattern);
- $intlDateFormatter->setLenient(false);
-
- return $intlDateFormatter;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class DateTimeToRfc3339Transformer extends BaseDateTimeTransformer
-{
- /**
- * {@inheritDoc}
- */
- public function transform($dateTime)
- {
- if (null === $dateTime) {
- return '';
- }
-
- if (!$dateTime instanceof \DateTime) {
- throw new TransformationFailedException('Expected a \DateTime.');
- }
-
- if ($this->inputTimezone !== $this->outputTimezone) {
- $dateTime = clone $dateTime;
- $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
- }
-
- return preg_replace('/\+00:00$/', 'Z', $dateTime->format('c'));
- }
-
- /**
- * {@inheritDoc}
- */
- public function reverseTransform($rfc3339)
- {
- if (!is_string($rfc3339)) {
- throw new TransformationFailedException('Expected a string.');
- }
-
- if ('' === $rfc3339) {
- return null;
- }
-
- try {
- $dateTime = new \DateTime($rfc3339);
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
-
- if ($this->outputTimezone !== $this->inputTimezone) {
- try {
- $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
- }
-
- if (preg_match('/(\d{4})-(\d{2})-(\d{2})/', $rfc3339, $matches)) {
- if (!checkdate($matches[2], $matches[3], $matches[1])) {
- throw new TransformationFailedException(sprintf(
- 'The date "%s-%s-%s" is not a valid date.',
- $matches[1],
- $matches[2],
- $matches[3]
- ));
- }
- }
-
- return $dateTime;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-/**
- * Transforms between a date string and a DateTime object
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class DateTimeToStringTransformer extends BaseDateTimeTransformer
-{
- /**
- * Format used for generating strings
- * @var string
- */
- private $generateFormat;
-
- /**
- * Format used for parsing strings
- *
- * Different than the {@link $generateFormat} because formats for parsing
- * support additional characters in PHP that are not supported for
- * generating strings.
- *
- * @var string
- */
- private $parseFormat;
-
- /**
- * Whether to parse by appending a pipe "|" to the parse format.
- *
- * This only works as of PHP 5.3.7.
- *
- * @var Boolean
- */
- private $parseUsingPipe;
-
- /**
- * Transforms a \DateTime instance to a string
- *
- * @see \DateTime::format() for supported formats
- *
- * @param string $inputTimezone The name of the input timezone
- * @param string $outputTimezone The name of the output timezone
- * @param string $format The date format
- * @param Boolean $parseUsingPipe Whether to parse by appending a pipe "|" to the parse format
- *
- * @throws UnexpectedTypeException if a timezone is not a string
- */
- public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = null)
- {
- parent::__construct($inputTimezone, $outputTimezone);
-
- $this->generateFormat = $this->parseFormat = $format;
-
- // The pipe in the parser pattern only works as of PHP 5.3.7
- // See http://bugs.php.net/54316
- $this->parseUsingPipe = null === $parseUsingPipe
- ? version_compare(phpversion(), '5.3.7', '>=')
- : $parseUsingPipe;
-
- // See http://php.net/manual/en/datetime.createfromformat.php
- // The character "|" in the format makes sure that the parts of a date
- // that are *not* specified in the format are reset to the corresponding
- // values from 1970-01-01 00:00:00 instead of the current time.
- // Without "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 12:32:47",
- // where the time corresponds to the current server time.
- // With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00",
- // which is at least deterministic and thus used here.
- if ($this->parseUsingPipe && false === strpos($this->parseFormat, '|')) {
- $this->parseFormat .= '|';
- }
- }
-
- /**
- * Transforms a DateTime object into a date string with the configured format
- * and timezone
- *
- * @param \DateTime $value A DateTime object
- *
- * @return string A value as produced by PHP's date() function
- *
- * @throws TransformationFailedException If the given value is not a \DateTime
- * instance or if the output timezone
- * is not supported.
- */
- public function transform($value)
- {
- if (null === $value) {
- return '';
- }
-
- if (!$value instanceof \DateTime) {
- throw new TransformationFailedException('Expected a \DateTime.');
- }
-
- $value = clone $value;
- try {
- $value->setTimezone(new \DateTimeZone($this->outputTimezone));
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
-
- return $value->format($this->generateFormat);
- }
-
- /**
- * Transforms a date string in the configured timezone into a DateTime object.
- *
- * @param string $value A value as produced by PHP's date() function
- *
- * @return \DateTime An instance of \DateTime
- *
- * @throws TransformationFailedException If the given value is not a string,
- * if the date could not be parsed or
- * if the input timezone is not supported.
- */
- public function reverseTransform($value)
- {
- if (empty($value)) {
- return null;
- }
-
- if (!is_string($value)) {
- throw new TransformationFailedException('Expected a string.');
- }
-
- try {
- $outputTz = new \DateTimeZone($this->outputTimezone);
- $dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
-
- $lastErrors = \DateTime::getLastErrors();
-
- if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
- throw new TransformationFailedException(
- implode(', ', array_merge(
- array_values($lastErrors['warnings']),
- array_values($lastErrors['errors'])
- ))
- );
- }
-
- // On PHP versions < 5.3.7 we need to emulate the pipe operator
- // and reset parts not given in the format to their equivalent
- // of the UNIX base timestamp.
- if (!$this->parseUsingPipe) {
- list($year, $month, $day, $hour, $minute, $second) = explode('-', $dateTime->format('Y-m-d-H-i-s'));
-
- // Check which of the date parts are present in the pattern
- preg_match(
- '/(' .
- '(?P<day>[djDl])|' .
- '(?P<month>[FMmn])|' .
- '(?P<year>[Yy])|' .
- '(?P<hour>[ghGH])|' .
- '(?P<minute>i)|' .
- '(?P<second>s)|' .
- '(?P<dayofyear>z)|' .
- '(?P<timestamp>U)|' .
- '[^djDlFMmnYyghGHiszU]' .
- ')*/',
- $this->parseFormat,
- $matches
- );
-
- // preg_match() does not guarantee to set all indices, so
- // set them unless given
- $matches = array_merge(array(
- 'day' => false,
- 'month' => false,
- 'year' => false,
- 'hour' => false,
- 'minute' => false,
- 'second' => false,
- 'dayofyear' => false,
- 'timestamp' => false,
- ), $matches);
-
- // Reset all parts that don't exist in the format to the
- // corresponding part of the UNIX base timestamp
- if (!$matches['timestamp']) {
- if (!$matches['dayofyear']) {
- if (!$matches['day']) {
- $day = 1;
- }
- if (!$matches['month']) {
- $month = 1;
- }
- }
- if (!$matches['year']) {
- $year = 1970;
- }
- if (!$matches['hour']) {
- $hour = 0;
- }
- if (!$matches['minute']) {
- $minute = 0;
- }
- if (!$matches['second']) {
- $second = 0;
- }
- $dateTime->setDate($year, $month, $day);
- $dateTime->setTime($hour, $minute, $second);
- }
- }
-
- if ($this->inputTimezone !== $this->outputTimezone) {
- $dateTime->setTimeZone(new \DateTimeZone($this->inputTimezone));
- }
- } catch (TransformationFailedException $e) {
- throw $e;
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
-
- return $dateTime;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * Transforms between a timestamp and a DateTime object
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
-{
- /**
- * Transforms a DateTime object into a timestamp in the configured timezone.
- *
- * @param \DateTime $value A \DateTime object
- *
- * @return integer A timestamp
- *
- * @throws TransformationFailedException If the given value is not an instance
- * of \DateTime or if the output
- * timezone is not supported.
- */
- public function transform($value)
- {
- if (null === $value) {
- return null;
- }
-
- if (!$value instanceof \DateTime) {
- throw new TransformationFailedException('Expected a \DateTime.');
- }
-
- $value = clone $value;
- try {
- $value->setTimezone(new \DateTimeZone($this->outputTimezone));
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
-
- return (int) $value->format('U');
- }
-
- /**
- * Transforms a timestamp in the configured timezone into a DateTime object
- *
- * @param string $value A timestamp
- *
- * @return \DateTime A \DateTime object
- *
- * @throws TransformationFailedException If the given value is not a timestamp
- * or if the given timestamp is invalid.
- */
- public function reverseTransform($value)
- {
- if (null === $value) {
- return null;
- }
-
- if (!is_numeric($value)) {
- throw new TransformationFailedException('Expected a numeric.');
- }
-
- try {
- $dateTime = new \DateTime();
- $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
- $dateTime->setTimestamp($value);
-
- if ($this->inputTimezone !== $this->outputTimezone) {
- $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
- }
- } catch (\Exception $e) {
- throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
- }
-
- return $dateTime;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * Transforms between an integer and a localized number with grouping
- * (each thousand) and comma separators.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IntegerToLocalizedStringTransformer extends NumberToLocalizedStringTransformer
-{
- /**
- * {@inheritDoc}
- */
- public function reverseTransform($value)
- {
- if (!is_string($value)) {
- throw new TransformationFailedException('Expected a string.');
- }
-
- if ('' === $value) {
- return null;
- }
-
- if ('NaN' === $value) {
- throw new TransformationFailedException('"NaN" is not a valid integer');
- }
-
- $formatter = $this->getNumberFormatter();
- $value = $formatter->parse(
- $value,
- PHP_INT_SIZE == 8 ? $formatter::TYPE_INT64 : $formatter::TYPE_INT32
- );
-
- if (intl_is_failure($formatter->getErrorCode())) {
- throw new TransformationFailedException($formatter->getErrorMessage());
- }
-
- return $value;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * Transforms between a normalized format and a localized money string.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class MoneyToLocalizedStringTransformer extends NumberToLocalizedStringTransformer
-{
-
- private $divisor;
-
- public function __construct($precision = null, $grouping = null, $roundingMode = null, $divisor = null)
- {
- if (null === $grouping) {
- $grouping = true;
- }
-
- if (null === $precision) {
- $precision = 2;
- }
-
- parent::__construct($precision, $grouping, $roundingMode);
-
- if (null === $divisor) {
- $divisor = 1;
- }
-
- $this->divisor = $divisor;
- }
-
- /**
- * Transforms a normalized format into a localized money string.
- *
- * @param number $value Normalized number
- *
- * @return string Localized money string.
- *
- * @throws TransformationFailedException If the given value is not numeric or
- * if the value can not be transformed.
- */
- public function transform($value)
- {
- if (null !== $value) {
- if (!is_numeric($value)) {
- throw new TransformationFailedException('Expected a numeric.');
- }
-
- $value /= $this->divisor;
- }
-
- return parent::transform($value);
- }
-
- /**
- * Transforms a localized money string into a normalized format.
- *
- * @param string $value Localized money string
- *
- * @return number Normalized number
- *
- * @throws TransformationFailedException If the given value is not a string
- * or if the value can not be transformed.
- */
- public function reverseTransform($value)
- {
- $value = parent::reverseTransform($value);
-
- if (null !== $value) {
- $value *= $this->divisor;
- }
-
- return $value;
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * Transforms between a number type and a localized number with grouping
- * (each thousand) and comma separators.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class NumberToLocalizedStringTransformer implements DataTransformerInterface
-{
- const ROUND_FLOOR = \NumberFormatter::ROUND_FLOOR;
- const ROUND_DOWN = \NumberFormatter::ROUND_DOWN;
- const ROUND_HALFDOWN = \NumberFormatter::ROUND_HALFDOWN;
- const ROUND_HALFEVEN = \NumberFormatter::ROUND_HALFEVEN;
- const ROUND_HALFUP = \NumberFormatter::ROUND_HALFUP;
- const ROUND_UP = \NumberFormatter::ROUND_UP;
- const ROUND_CEILING = \NumberFormatter::ROUND_CEILING;
-
- protected $precision;
-
- protected $grouping;
-
- protected $roundingMode;
-
- public function __construct($precision = null, $grouping = null, $roundingMode = null)
- {
- if (null === $grouping) {
- $grouping = false;
- }
-
- if (null === $roundingMode) {
- $roundingMode = self::ROUND_HALFUP;
- }
-
- $this->precision = $precision;
- $this->grouping = $grouping;
- $this->roundingMode = $roundingMode;
- }
-
- /**
- * Transforms a number type into localized number.
- *
- * @param integer|float $value Number value.
- *
- * @return string Localized value.
- *
- * @throws TransformationFailedException If the given value is not numeric
- * or if the value can not be transformed.
- */
- public function transform($value)
- {
- if (null === $value) {
- return '';
- }
-
- if (!is_numeric($value)) {
- throw new TransformationFailedException('Expected a numeric.');
- }
-
- $formatter = $this->getNumberFormatter();
- $value = $formatter->format($value);
-
- if (intl_is_failure($formatter->getErrorCode())) {
- throw new TransformationFailedException($formatter->getErrorMessage());
- }
-
- // Convert fixed spaces to normal ones
- $value = str_replace("\xc2\xa0", ' ', $value);
-
- return $value;
- }
-
- /**
- * Transforms a localized number into an integer or float
- *
- * @param string $value The localized value
- *
- * @return integer|float The numeric value
- *
- * @throws TransformationFailedException If the given value is not a string
- * or if the value can not be transformed.
- */
- public function reverseTransform($value)
- {
- if (!is_string($value)) {
- throw new TransformationFailedException('Expected a string.');
- }
-
- if ('' === $value) {
- return null;
- }
-
- if ('NaN' === $value) {
- throw new TransformationFailedException('"NaN" is not a valid number');
- }
-
- $position = 0;
- $formatter = $this->getNumberFormatter();
- $groupSep = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
- $decSep = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
-
- if ('.' !== $decSep && (!$this->grouping || '.' !== $groupSep)) {
- $value = str_replace('.', $decSep, $value);
- }
-
- if (',' !== $decSep && (!$this->grouping || ',' !== $groupSep)) {
- $value = str_replace(',', $decSep, $value);
- }
-
- $result = $formatter->parse($value, \NumberFormatter::TYPE_DOUBLE, $position);
-
- if (intl_is_failure($formatter->getErrorCode())) {
- throw new TransformationFailedException($formatter->getErrorMessage());
- }
-
- if ($result >= PHP_INT_MAX || $result <= -PHP_INT_MAX) {
- throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like');
- }
-
- if (function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value)) {
- $strlen = function ($string) use ($encoding) {
- return mb_strlen($string, $encoding);
- };
- $substr = function ($string, $offset, $length) use ($encoding) {
- return mb_substr($string, $offset, $length, $encoding);
- };
- } else {
- $strlen = 'strlen';
- $substr = 'substr';
- }
-
- $length = $strlen($value);
-
- // After parsing, position holds the index of the character where the
- // parsing stopped
- if ($position < $length) {
- // Check if there are unrecognized characters at the end of the
- // number (excluding whitespace characters)
- $remainder = trim($substr($value, $position, $length), " \t\n\r\0\x0b\xc2\xa0");
-
- if ('' !== $remainder) {
- throw new TransformationFailedException(
- sprintf('The number contains unrecognized characters: "%s"', $remainder)
- );
- }
- }
-
- return $result;
- }
-
- /**
- * Returns a preconfigured \NumberFormatter instance
- *
- * @return \NumberFormatter
- */
- protected function getNumberFormatter()
- {
- $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
-
- if (null !== $this->precision) {
- $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->precision);
- $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode);
- }
-
- $formatter->setAttribute(\NumberFormatter::GROUPING_USED, $this->grouping);
-
- return $formatter;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-/**
- * Transforms between a normalized format (integer or float) and a percentage value.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Florian Eckerstorfer <florian@eckerstorfer.org>
- */
-class PercentToLocalizedStringTransformer implements DataTransformerInterface
-{
- const FRACTIONAL = 'fractional';
- const INTEGER = 'integer';
-
- protected static $types = array(
- self::FRACTIONAL,
- self::INTEGER,
- );
-
- private $type;
-
- private $precision;
-
- /**
- * Constructor.
- *
- * @see self::$types for a list of supported types
- *
- * @param integer $precision The precision
- * @param string $type One of the supported types
- *
- * @throws UnexpectedTypeException if the given value of type is unknown
- */
- public function __construct($precision = null, $type = null)
- {
- if (null === $precision) {
- $precision = 0;
- }
-
- if (null === $type) {
- $type = self::FRACTIONAL;
- }
-
- if (!in_array($type, self::$types, true)) {
- throw new UnexpectedTypeException($type, implode('", "', self::$types));
- }
-
- $this->type = $type;
- $this->precision = $precision;
- }
-
- /**
- * Transforms between a normalized format (integer or float) into a percentage value.
- *
- * @param number $value Normalized value
- *
- * @return number Percentage value
- *
- * @throws TransformationFailedException If the given value is not numeric or
- * if the value could not be transformed.
- */
- public function transform($value)
- {
- if (null === $value) {
- return '';
- }
-
- if (!is_numeric($value)) {
- throw new TransformationFailedException('Expected a numeric.');
- }
-
- if (self::FRACTIONAL == $this->type) {
- $value *= 100;
- }
-
- $formatter = $this->getNumberFormatter();
- $value = $formatter->format($value);
-
- if (intl_is_failure($formatter->getErrorCode())) {
- throw new TransformationFailedException($formatter->getErrorMessage());
- }
-
- // replace the UTF-8 non break spaces
- return $value;
- }
-
- /**
- * Transforms between a percentage value into a normalized format (integer or float).
- *
- * @param number $value Percentage value.
- *
- * @return number Normalized value.
- *
- * @throws TransformationFailedException If the given value is not a string or
- * if the value could not be transformed.
- */
- public function reverseTransform($value)
- {
- if (!is_string($value)) {
- throw new TransformationFailedException('Expected a string.');
- }
-
- if ('' === $value) {
- return null;
- }
-
- $formatter = $this->getNumberFormatter();
- // replace normal spaces so that the formatter can read them
- $value = $formatter->parse(str_replace(' ', ' ', $value));
-
- if (intl_is_failure($formatter->getErrorCode())) {
- throw new TransformationFailedException($formatter->getErrorMessage());
- }
-
- if (self::FRACTIONAL == $this->type) {
- $value /= 100;
- }
-
- return $value;
- }
-
- /**
- * Returns a preconfigured \NumberFormatter instance
- *
- * @return \NumberFormatter
- */
- protected function getNumberFormatter()
- {
- $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
-
- $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->precision);
-
- return $formatter;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ValueToDuplicatesTransformer implements DataTransformerInterface
-{
- private $keys;
-
- public function __construct(array $keys)
- {
- $this->keys = $keys;
- }
-
- /**
- * Duplicates the given value through the array.
- *
- * @param mixed $value The value
- *
- * @return array The array
- */
- public function transform($value)
- {
- $result = array();
-
- foreach ($this->keys as $key) {
- $result[$key] = $value;
- }
-
- return $result;
- }
-
- /**
- * Extracts the duplicated value from an array.
- *
- * @param array $array
- *
- * @return mixed The value
- *
- * @throws TransformationFailedException If the given value is not an array or
- * if the given array can not be transformed.
- */
- public function reverseTransform($array)
- {
- if (!is_array($array)) {
- throw new TransformationFailedException('Expected an array.');
- }
-
- $result = current($array);
- $emptyKeys = array();
-
- foreach ($this->keys as $key) {
- if (!empty($array[$key])) {
- if ($array[$key] !== $result) {
- throw new TransformationFailedException(
- 'All values in the array should be the same'
- );
- }
- } else {
- $emptyKeys[] = $key;
- }
- }
-
- if (count($emptyKeys) > 0) {
- if (count($emptyKeys) == count($this->keys)) {
- // All keys empty
- return null;
- }
-
- throw new TransformationFailedException(
- sprintf('The keys "%s" should not be empty', implode('", "', $emptyKeys)
- ));
- }
-
- return $result;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
-
-/**
- * Takes care of converting the input from a list of checkboxes to a correctly
- * indexed array.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FixCheckboxInputListener implements EventSubscriberInterface
-{
- private $choiceList;
-
- /**
- * Constructor.
- *
- * @param ChoiceListInterface $choiceList
- */
- public function __construct(ChoiceListInterface $choiceList)
- {
- $this->choiceList = $choiceList;
- }
-
- public function preSubmit(FormEvent $event)
- {
- $values = (array) $event->getData();
- $indices = $this->choiceList->getIndicesForValues($values);
-
- $event->setData(count($indices) > 0 ? array_combine($indices, $values) : array());
- }
-
- /**
- * Alias of {@link preSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link preSubmit()} instead.
- */
- public function preBind(FormEvent $event)
- {
- $this->preSubmit($event);
- }
-
- public static function getSubscribedEvents()
- {
- return array(FormEvents::PRE_SUBMIT => 'preSubmit');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
-
-/**
- * Takes care of converting the input from a single radio button
- * to an array.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FixRadioInputListener implements EventSubscriberInterface
-{
- private $choiceList;
-
- private $placeholderPresent;
-
- /**
- * Constructor.
- *
- * @param ChoiceListInterface $choiceList
- * @param Boolean $placeholderPresent
- */
- public function __construct(ChoiceListInterface $choiceList, $placeholderPresent)
- {
- $this->choiceList = $choiceList;
- $this->placeholderPresent = $placeholderPresent;
- }
-
- public function preSubmit(FormEvent $event)
- {
- $value = $event->getData();
- $index = current($this->choiceList->getIndicesForValues(array($value)));
-
- $event->setData(false !== $index ? array($index => $value) : ($this->placeholderPresent ? array('placeholder' => '') : array())) ;
- }
-
- /**
- * Alias of {@link preSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link preSubmit()} instead.
- */
- public function preBind(FormEvent $event)
- {
- $this->preSubmit($event);
- }
-
- public static function getSubscribedEvents()
- {
- return array(FormEvents::PRE_SUBMIT => 'preSubmit');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Adds a protocol to a URL if it doesn't already have one.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FixUrlProtocolListener implements EventSubscriberInterface
-{
- private $defaultProtocol;
-
- public function __construct($defaultProtocol = 'http')
- {
- $this->defaultProtocol = $defaultProtocol;
- }
-
- public function onSubmit(FormEvent $event)
- {
- $data = $event->getData();
-
- if ($this->defaultProtocol && $data && !preg_match('~^\w+://~', $data)) {
- $event->setData($this->defaultProtocol.'://'.$data);
- }
- }
-
- /**
- * Alias of {@link onSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link onSubmit()} instead.
- */
- public function onBind(FormEvent $event)
- {
- $this->onSubmit($event);
- }
-
- public static function getSubscribedEvents()
- {
- return array(FormEvents::SUBMIT => 'onSubmit');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\EventListener;
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class MergeCollectionListener implements EventSubscriberInterface
-{
- /**
- * Whether elements may be added to the collection
- * @var Boolean
- */
- private $allowAdd;
-
- /**
- * Whether elements may be removed from the collection
- * @var Boolean
- */
- private $allowDelete;
-
- /**
- * Creates a new listener.
- *
- * @param Boolean $allowAdd Whether values might be added to the
- * collection.
- * @param Boolean $allowDelete Whether values might be removed from the
- * collection.
- */
- public function __construct($allowAdd = false, $allowDelete = false)
- {
- $this->allowAdd = $allowAdd;
- $this->allowDelete = $allowDelete;
- }
-
- public static function getSubscribedEvents()
- {
- return array(
- FormEvents::SUBMIT => 'onSubmit',
- );
- }
-
- public function onSubmit(FormEvent $event)
- {
- $dataToMergeInto = $event->getForm()->getNormData();
- $data = $event->getData();
-
- if (null === $data) {
- $data = array();
- }
-
- if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
- throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
- }
-
- if (null !== $dataToMergeInto && !is_array($dataToMergeInto) && !($dataToMergeInto instanceof \Traversable && $dataToMergeInto instanceof \ArrayAccess)) {
- throw new UnexpectedTypeException($dataToMergeInto, 'array or (\Traversable and \ArrayAccess)');
- }
-
- // If we are not allowed to change anything, return immediately
- if ((!$this->allowAdd && !$this->allowDelete) || $data === $dataToMergeInto) {
- $event->setData($dataToMergeInto);
-
- return;
- }
-
- if (!$dataToMergeInto) {
- // No original data was set. Set it if allowed
- if ($this->allowAdd) {
- $dataToMergeInto = $data;
- }
- } else {
- // Calculate delta
- $itemsToAdd = is_object($data) ? clone $data : $data;
- $itemsToDelete = array();
-
- foreach ($dataToMergeInto as $beforeKey => $beforeItem) {
- foreach ($data as $afterKey => $afterItem) {
- if ($afterItem === $beforeItem) {
- // Item found, next original item
- unset($itemsToAdd[$afterKey]);
- continue 2;
- }
- }
-
- // Item not found, remember for deletion
- $itemsToDelete[] = $beforeKey;
- }
-
- // Remove deleted items before adding to free keys that are to be
- // replaced
- if ($this->allowDelete) {
- foreach ($itemsToDelete as $key) {
- unset($dataToMergeInto[$key]);
- }
- }
-
- // Add remaining items
- if ($this->allowAdd) {
- foreach ($itemsToAdd as $key => $item) {
- if (!isset($dataToMergeInto[$key])) {
- $dataToMergeInto[$key] = $item;
- } else {
- $dataToMergeInto[] = $item;
- }
- }
- }
- }
-
- $event->setData($dataToMergeInto);
- }
-
- /**
- * Alias of {@link onSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link onSubmit()} instead.
- */
- public function onBind(FormEvent $event)
- {
- $this->onSubmit($event);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Resize a collection form element based on the data sent from the client.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ResizeFormListener implements EventSubscriberInterface
-{
- /**
- * @var string
- */
- protected $type;
-
- /**
- * @var array
- */
- protected $options;
-
- /**
- * Whether children could be added to the group
- * @var Boolean
- */
- protected $allowAdd;
-
- /**
- * Whether children could be removed from the group
- * @var Boolean
- */
- protected $allowDelete;
-
- public function __construct($type, array $options = array(), $allowAdd = false, $allowDelete = false)
- {
- $this->type = $type;
- $this->allowAdd = $allowAdd;
- $this->allowDelete = $allowDelete;
- $this->options = $options;
- }
-
- public static function getSubscribedEvents()
- {
- return array(
- FormEvents::PRE_SET_DATA => 'preSetData',
- FormEvents::PRE_SUBMIT => 'preSubmit',
- // (MergeCollectionListener, MergeDoctrineCollectionListener)
- FormEvents::SUBMIT => array('onSubmit', 50),
- );
- }
-
- public function preSetData(FormEvent $event)
- {
- $form = $event->getForm();
- $data = $event->getData();
-
- if (null === $data) {
- $data = array();
- }
-
- if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
- throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
- }
-
- // First remove all rows
- foreach ($form as $name => $child) {
- $form->remove($name);
- }
-
- // Then add all rows again in the correct order
- foreach ($data as $name => $value) {
- $form->add($name, $this->type, array_replace(array(
- 'property_path' => '['.$name.']',
- ), $this->options));
- }
- }
-
- public function preSubmit(FormEvent $event)
- {
- $form = $event->getForm();
- $data = $event->getData();
-
- if (null === $data || '' === $data) {
- $data = array();
- }
-
- if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
- throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
- }
-
- // Remove all empty rows
- if ($this->allowDelete) {
- foreach ($form as $name => $child) {
- if (!isset($data[$name])) {
- $form->remove($name);
- }
- }
- }
-
- // Add all additional rows
- if ($this->allowAdd) {
- foreach ($data as $name => $value) {
- if (!$form->has($name)) {
- $form->add($name, $this->type, array_replace(array(
- 'property_path' => '['.$name.']',
- ), $this->options));
- }
- }
- }
- }
-
- public function onSubmit(FormEvent $event)
- {
- $form = $event->getForm();
- $data = $event->getData();
-
- if (null === $data) {
- $data = array();
- }
-
- if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
- throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
- }
-
- // The data mapper only adds, but does not remove items, so do this
- // here
- if ($this->allowDelete) {
- foreach ($data as $name => $child) {
- if (!$form->has($name)) {
- unset($data[$name]);
- }
- }
- }
-
- $event->setData($data);
- }
-
- /**
- * Alias of {@link preSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link preSubmit()} instead.
- */
- public function preBind(FormEvent $event)
- {
- $this->preSubmit($event);
- }
-
- /**
- * Alias of {@link onSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link onSubmit()} instead.
- */
- public function onBind(FormEvent $event)
- {
- $this->onSubmit($event);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Trims string data
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class TrimListener implements EventSubscriberInterface
-{
- public function preSubmit(FormEvent $event)
- {
- $data = $event->getData();
-
- if (!is_string($data)) {
- return;
- }
-
- if (null !== $result = @preg_replace('/^[\pZ\p{Cc}]+|[\pZ\p{Cc}]+$/u', '', $data)) {
- $event->setData($result);
- } else {
- $event->setData(trim($data));
- }
- }
-
- /**
- * Alias of {@link preSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link preSubmit()} instead.
- */
- public function preBind(FormEvent $event)
- {
- $this->preSubmit($event);
- }
-
- public static function getSubscribedEvents()
- {
- return array(FormEvents::PRE_SUBMIT => 'preSubmit');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * Encapsulates common logic of {@link FormType} and {@link ButtonType}.
- *
- * This type does not appear in the form's type inheritance chain and as such
- * cannot be extended (via {@link FormTypeExtension}s) nor themed.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class BaseType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->setDisabled($options['disabled']);
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $name = $form->getName();
- $blockName = $options['block_name'] ?: $form->getName();
- $translationDomain = $options['translation_domain'];
-
- if ($view->parent) {
- if ('' !== ($parentFullName = $view->parent->vars['full_name'])) {
- $id = sprintf('%s_%s', $view->parent->vars['id'], $name);
- $fullName = sprintf('%s[%s]', $parentFullName, $name);
- $uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName);
- } else {
- $id = $name;
- $fullName = $name;
- $uniqueBlockPrefix = '_'.$blockName;
- }
-
- if (!$translationDomain) {
- $translationDomain = $view->parent->vars['translation_domain'];
- }
- } else {
- $id = $name;
- $fullName = $name;
- $uniqueBlockPrefix = '_'.$blockName;
-
- // Strip leading underscores and digits. These are allowed in
- // form names, but not in HTML4 ID attributes.
- // http://www.w3.org/TR/html401/struct/global.html#adef-id
- $id = ltrim($id, '_0123456789');
- }
-
- $blockPrefixes = array();
- for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) {
- array_unshift($blockPrefixes, $type->getName());
- }
- $blockPrefixes[] = $uniqueBlockPrefix;
-
- if (!$translationDomain) {
- $translationDomain = 'messages';
- }
-
- $view->vars = array_replace($view->vars, array(
- 'form' => $view,
- 'id' => $id,
- 'name' => $name,
- 'full_name' => $fullName,
- 'disabled' => $form->isDisabled(),
- 'label' => $options['label'],
- 'multipart' => false,
- 'attr' => $options['attr'],
- 'block_prefixes' => $blockPrefixes,
- 'unique_block_prefix' => $uniqueBlockPrefix,
- 'translation_domain' => $translationDomain,
- // Using the block name here speeds up performance in collection
- // forms, where each entry has the same full block name.
- // Including the type is important too, because if rows of a
- // collection form have different types (dynamically), they should
- // be rendered differently.
- // https://github.com/symfony/symfony/issues/5038
- 'cache_key' => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getName(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'block_name' => null,
- 'disabled' => false,
- 'label' => null,
- 'attr' => array(),
- 'translation_domain' => null,
- ));
-
- $resolver->setAllowedTypes(array(
- 'attr' => 'array',
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class BirthdayType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'years' => range(date('Y') - 120, date('Y')),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'date';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'birthday';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\ButtonTypeInterface;
-
-/**
- * A form button.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ButtonType extends BaseType implements ButtonTypeInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return null;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'button';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class CheckboxType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder
- ->addViewTransformer(new BooleanToStringTransformer($options['value']))
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars = array_replace($view->vars, array(
- 'value' => $options['value'],
- 'checked' => null !== $form->getViewData(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $emptyData = function (FormInterface $form, $clientData) {
- return $clientData;
- };
-
- $resolver->setDefaults(array(
- 'value' => '1',
- 'empty_data' => $emptyData,
- 'compound' => false,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'checkbox';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Exception\LogicException;
-use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
-use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
-use Symfony\Component\Form\Extension\Core\EventListener\FixCheckboxInputListener;
-use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
-use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToBooleanArrayTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToBooleanArrayTransformer;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class ChoiceType extends AbstractType
-{
- /**
- * Caches created choice lists.
- * @var array
- */
- private $choiceListCache = array();
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- if (!$options['choice_list'] && !is_array($options['choices']) && !$options['choices'] instanceof \Traversable) {
- throw new LogicException('Either the option "choices" or "choice_list" must be set.');
- }
-
- if ($options['expanded']) {
- // Initialize all choices before doing the index check below.
- // This helps in cases where index checks are optimized for non
- // initialized choice lists. For example, when using an SQL driver,
- // the index check would read in one SQL query and the initialization
- // requires another SQL query. When the initialization is done first,
- // one SQL query is sufficient.
- $preferredViews = $options['choice_list']->getPreferredViews();
- $remainingViews = $options['choice_list']->getRemainingViews();
-
- // Check if the choices already contain the empty value
- // Only add the empty value option if this is not the case
- if (null !== $options['empty_value'] && 0 === count($options['choice_list']->getIndicesForValues(array('')))) {
- $placeholderView = new ChoiceView(null, '', $options['empty_value']);
-
- // "placeholder" is a reserved index
- // see also ChoiceListInterface::getIndicesForChoices()
- $this->addSubForms($builder, array('placeholder' => $placeholderView), $options);
- }
-
- $this->addSubForms($builder, $preferredViews, $options);
- $this->addSubForms($builder, $remainingViews, $options);
-
- if ($options['multiple']) {
- $builder->addViewTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']));
- $builder->addEventSubscriber(new FixCheckboxInputListener($options['choice_list']), 10);
- } else {
- $builder->addViewTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list'], $builder->has('placeholder')));
- $builder->addEventSubscriber(new FixRadioInputListener($options['choice_list'], $builder->has('placeholder')), 10);
- }
- } else {
- if ($options['multiple']) {
- $builder->addViewTransformer(new ChoicesToValuesTransformer($options['choice_list']));
- } else {
- $builder->addViewTransformer(new ChoiceToValueTransformer($options['choice_list']));
- }
- }
-
- if ($options['multiple'] && $options['by_reference']) {
- // Make sure the collection created during the client->norm
- // transformation is merged back into the original collection
- $builder->addEventSubscriber(new MergeCollectionListener(true, true));
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars = array_replace($view->vars, array(
- 'multiple' => $options['multiple'],
- 'expanded' => $options['expanded'],
- 'preferred_choices' => $options['choice_list']->getPreferredViews(),
- 'choices' => $options['choice_list']->getRemainingViews(),
- 'separator' => '-------------------',
- 'empty_value' => null,
- ));
-
- // The decision, whether a choice is selected, is potentially done
- // thousand of times during the rendering of a template. Provide a
- // closure here that is optimized for the value of the form, to
- // avoid making the type check inside the closure.
- if ($options['multiple']) {
- $view->vars['is_selected'] = function ($choice, array $values) {
- return false !== array_search($choice, $values, true);
- };
- } else {
- $view->vars['is_selected'] = function ($choice, $value) {
- return $choice === $value;
- };
- }
-
- // Check if the choices already contain the empty value
- // Only add the empty value option if this is not the case
- if (null !== $options['empty_value'] && 0 === count($options['choice_list']->getIndicesForValues(array('')))) {
- $view->vars['empty_value'] = $options['empty_value'];
- }
-
- if ($options['multiple'] && !$options['expanded']) {
- // Add "[]" to the name in case a select tag with multiple options is
- // displayed. Otherwise only one of the selected options is sent in the
- // POST request.
- $view->vars['full_name'] = $view->vars['full_name'].'[]';
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- if ($options['expanded']) {
- // Radio buttons should have the same name as the parent
- $childName = $view->vars['full_name'];
-
- // Checkboxes should append "[]" to allow multiple selection
- if ($options['multiple']) {
- $childName .= '[]';
- }
-
- foreach ($view as $childView) {
- $childView->vars['full_name'] = $childName;
- }
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $choiceListCache =& $this->choiceListCache;
-
- $choiceList = function (Options $options) use (&$choiceListCache) {
- // Harden against NULL values (like in EntityType and ModelType)
- $choices = null !== $options['choices'] ? $options['choices'] : array();
-
- // Reuse existing choice lists in order to increase performance
- $hash = md5(json_encode(array($choices, $options['preferred_choices'])));
-
- if (!isset($choiceListCache[$hash])) {
- $choiceListCache[$hash] = new SimpleChoiceList($choices, $options['preferred_choices']);
- }
-
- return $choiceListCache[$hash];
- };
-
- $emptyData = function (Options $options) {
- if ($options['multiple'] || $options['expanded']) {
- return array();
- }
-
- return '';
- };
-
- $emptyValue = function (Options $options) {
- return $options['required'] ? null : '';
- };
-
- $emptyValueNormalizer = function (Options $options, $emptyValue) {
- if ($options['multiple']) {
- // never use an empty value for this case
- return null;
- } elseif (false === $emptyValue) {
- // an empty value should be added but the user decided otherwise
- return null;
- } elseif ($options['expanded'] && '' === $emptyValue) {
- // never use an empty label for radio buttons
- return 'None';
- }
-
- // empty value has been set explicitly
- return $emptyValue;
- };
-
- $compound = function (Options $options) {
- return $options['expanded'];
- };
-
- $resolver->setDefaults(array(
- 'multiple' => false,
- 'expanded' => false,
- 'choice_list' => $choiceList,
- 'choices' => array(),
- 'preferred_choices' => array(),
- 'empty_data' => $emptyData,
- 'empty_value' => $emptyValue,
- 'error_bubbling' => false,
- 'compound' => $compound,
- // The view data is always a string, even if the "data" option
- // is manually set to an object.
- // See https://github.com/symfony/symfony/pull/5582
- 'data_class' => null,
- ));
-
- $resolver->setNormalizers(array(
- 'empty_value' => $emptyValueNormalizer,
- ));
-
- $resolver->setAllowedTypes(array(
- 'choice_list' => array('null', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'choice';
- }
-
- /**
- * Adds the sub fields for an expanded choice field.
- *
- * @param FormBuilderInterface $builder The form builder.
- * @param array $choiceViews The choice view objects.
- * @param array $options The build options.
- */
- private function addSubForms(FormBuilderInterface $builder, array $choiceViews, array $options)
- {
- foreach ($choiceViews as $i => $choiceView) {
- if (is_array($choiceView)) {
- // Flatten groups
- $this->addSubForms($builder, $choiceView, $options);
- } else {
- $choiceOpts = array(
- 'value' => $choiceView->value,
- 'label' => $choiceView->label,
- 'translation_domain' => $options['translation_domain'],
- );
-
- if ($options['multiple']) {
- $choiceType = 'checkbox';
- // The user can check 0 or more checkboxes. If required
- // is true, he is required to check all of them.
- $choiceOpts['required'] = false;
- } else {
- $choiceType = 'radio';
- }
-
- $builder->add($i, $choiceType, $choiceOpts);
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class CollectionType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- if ($options['allow_add'] && $options['prototype']) {
- $prototype = $builder->create($options['prototype_name'], $options['type'], array_replace(array(
- 'label' => $options['prototype_name'].'label__',
- ), $options['options']));
- $builder->setAttribute('prototype', $prototype->getForm());
- }
-
- $resizeListener = new ResizeFormListener(
- $options['type'],
- $options['options'],
- $options['allow_add'],
- $options['allow_delete']
- );
-
- $builder->addEventSubscriber($resizeListener);
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars = array_replace($view->vars, array(
- 'allow_add' => $options['allow_add'],
- 'allow_delete' => $options['allow_delete'],
- ));
-
- if ($form->getConfig()->hasAttribute('prototype')) {
- $view->vars['prototype'] = $form->getConfig()->getAttribute('prototype')->createView($view);
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- if ($form->getConfig()->hasAttribute('prototype') && $view->vars['prototype']->vars['multipart']) {
- $view->vars['multipart'] = true;
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $optionsNormalizer = function (Options $options, $value) {
- $value['block_name'] = 'entry';
-
- return $value;
- };
-
- $resolver->setDefaults(array(
- 'allow_add' => false,
- 'allow_delete' => false,
- 'prototype' => true,
- 'prototype_name' => '__name__',
- 'type' => 'text',
- 'options' => array(),
- ));
-
- $resolver->setNormalizers(array(
- 'options' => $optionsNormalizer,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'collection';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class CountryType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'choices' => Intl::getRegionBundle()->getCountryNames(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'choice';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'country';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class CurrencyType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'choices' => Intl::getCurrencyBundle()->getCurrencyNames(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'choice';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'currency';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\ReversedTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class DateTimeType extends AbstractType
-{
- const DEFAULT_DATE_FORMAT = \IntlDateFormatter::MEDIUM;
-
- const DEFAULT_TIME_FORMAT = \IntlDateFormatter::MEDIUM;
-
- /**
- * This is not quite the HTML5 format yet, because ICU lacks the
- * capability of parsing and generating RFC 3339 dates, which
- * are like the below pattern but with a timezone suffix. The
- * timezone suffix is
- *
- * * "Z" for UTC
- * * "(-|+)HH:mm" for other timezones (note the colon!)
- *
- * For more information see:
- *
- * http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
- * http://www.w3.org/TR/html-markup/input.datetime.html
- * http://tools.ietf.org/html/rfc3339
- *
- * An ICU ticket was created:
- * http://icu-project.org/trac/ticket/9421
- *
- * It was supposedly fixed, but is not available in all PHP installations
- * yet. To temporarily circumvent this issue, DateTimeToRfc3339Transformer
- * is used when the format matches this constant.
- */
- const HTML5_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZZZZ";
-
- private static $acceptedFormats = array(
- \IntlDateFormatter::FULL,
- \IntlDateFormatter::LONG,
- \IntlDateFormatter::MEDIUM,
- \IntlDateFormatter::SHORT,
- );
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $parts = array('year', 'month', 'day', 'hour');
- $dateParts = array('year', 'month', 'day');
- $timeParts = array('hour');
-
- if ($options['with_minutes']) {
- $parts[] = 'minute';
- $timeParts[] = 'minute';
- }
-
- if ($options['with_seconds']) {
- $parts[] = 'second';
- $timeParts[] = 'second';
- }
-
- $dateFormat = is_int($options['date_format']) ? $options['date_format'] : self::DEFAULT_DATE_FORMAT;
- $timeFormat = self::DEFAULT_TIME_FORMAT;
- $calendar = \IntlDateFormatter::GREGORIAN;
- $pattern = is_string($options['format']) ? $options['format'] : null;
-
- if (!in_array($dateFormat, self::$acceptedFormats, true)) {
- throw new InvalidOptionsException('The "date_format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
- }
-
- if ('single_text' === $options['widget']) {
- if (self::HTML5_FORMAT === $pattern) {
- $builder->addViewTransformer(new DateTimeToRfc3339Transformer(
- $options['model_timezone'],
- $options['view_timezone']
- ));
- } else {
- $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
- $options['model_timezone'],
- $options['view_timezone'],
- $dateFormat,
- $timeFormat,
- $calendar,
- $pattern
- ));
- }
- } else {
- // Only pass a subset of the options to children
- $dateOptions = array_intersect_key($options, array_flip(array(
- 'years',
- 'months',
- 'days',
- 'empty_value',
- 'required',
- 'translation_domain',
- )));
-
- $timeOptions = array_intersect_key($options, array_flip(array(
- 'hours',
- 'minutes',
- 'seconds',
- 'with_minutes',
- 'with_seconds',
- 'empty_value',
- 'required',
- 'translation_domain',
- )));
-
- if (null !== $options['date_widget']) {
- $dateOptions['widget'] = $options['date_widget'];
- }
-
- if (null !== $options['time_widget']) {
- $timeOptions['widget'] = $options['time_widget'];
- }
-
- if (null !== $options['date_format']) {
- $dateOptions['format'] = $options['date_format'];
- }
-
- $dateOptions['input'] = $timeOptions['input'] = 'array';
- $dateOptions['error_bubbling'] = $timeOptions['error_bubbling'] = true;
-
- $builder
- ->addViewTransformer(new DataTransformerChain(array(
- new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts),
- new ArrayToPartsTransformer(array(
- 'date' => $dateParts,
- 'time' => $timeParts,
- )),
- )))
- ->add('date', 'date', $dateOptions)
- ->add('time', 'time', $timeOptions)
- ;
- }
-
- if ('string' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'])
- ));
- } elseif ('timestamp' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
- ));
- } elseif ('array' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
- ));
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars['widget'] = $options['widget'];
-
- // Change the input to a HTML5 date input if
- // * the widget is set to "single_text"
- // * the format matches the one expected by HTML5
- if ('single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
- $view->vars['type'] = 'datetime';
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $compound = function (Options $options) {
- return $options['widget'] !== 'single_text';
- };
-
- // Defaults to the value of "widget"
- $dateWidget = function (Options $options) {
- return $options['widget'];
- };
-
- // Defaults to the value of "widget"
- $timeWidget = function (Options $options) {
- return $options['widget'];
- };
-
- $resolver->setDefaults(array(
- 'input' => 'datetime',
- 'model_timezone' => null,
- 'view_timezone' => null,
- 'format' => self::HTML5_FORMAT,
- 'date_format' => null,
- 'widget' => null,
- 'date_widget' => $dateWidget,
- 'time_widget' => $timeWidget,
- 'with_minutes' => true,
- 'with_seconds' => false,
- // Don't modify \DateTime classes by reference, we treat
- // them like immutable value objects
- 'by_reference' => false,
- 'error_bubbling' => false,
- // If initialized with a \DateTime object, FormType initializes
- // this option to "\DateTime". Since the internal, normalized
- // representation is not \DateTime, but an array, we need to unset
- // this option.
- 'data_class' => null,
- 'compound' => $compound,
- ));
-
- // Don't add some defaults in order to preserve the defaults
- // set in DateType and TimeType
- $resolver->setOptional(array(
- 'empty_value',
- 'years',
- 'months',
- 'days',
- 'hours',
- 'minutes',
- 'seconds',
- ));
-
- $resolver->setAllowedValues(array(
- 'input' => array(
- 'datetime',
- 'string',
- 'timestamp',
- 'array',
- ),
- 'date_widget' => array(
- null, // inherit default from DateType
- 'single_text',
- 'text',
- 'choice',
- ),
- 'time_widget' => array(
- null, // inherit default from TimeType
- 'single_text',
- 'text',
- 'choice',
- ),
- // This option will overwrite "date_widget" and "time_widget" options
- 'widget' => array(
- null, // default, don't overwrite options
- 'single_text',
- 'text',
- 'choice',
- ),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'datetime';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
-use Symfony\Component\Form\ReversedTransformer;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
-
-class DateType extends AbstractType
-{
- const DEFAULT_FORMAT = \IntlDateFormatter::MEDIUM;
-
- const HTML5_FORMAT = 'yyyy-MM-dd';
-
- private static $acceptedFormats = array(
- \IntlDateFormatter::FULL,
- \IntlDateFormatter::LONG,
- \IntlDateFormatter::MEDIUM,
- \IntlDateFormatter::SHORT,
- );
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $dateFormat = is_int($options['format']) ? $options['format'] : self::DEFAULT_FORMAT;
- $timeFormat = \IntlDateFormatter::NONE;
- $calendar = \IntlDateFormatter::GREGORIAN;
- $pattern = is_string($options['format']) ? $options['format'] : null;
-
- if (!in_array($dateFormat, self::$acceptedFormats, true)) {
- throw new InvalidOptionsException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
- }
-
- if (null !== $pattern && (false === strpos($pattern, 'y') || false === strpos($pattern, 'M') || false === strpos($pattern, 'd'))) {
- throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern));
- }
-
- if ('single_text' === $options['widget']) {
- $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
- $options['model_timezone'],
- $options['view_timezone'],
- $dateFormat,
- $timeFormat,
- $calendar,
- $pattern
- ));
- } else {
- $yearOptions = $monthOptions = $dayOptions = array(
- 'error_bubbling' => true,
- );
-
- $formatter = new \IntlDateFormatter(
- \Locale::getDefault(),
- $dateFormat,
- $timeFormat,
- 'UTC',
- $calendar,
- $pattern
- );
- $formatter->setLenient(false);
-
- if ('choice' === $options['widget']) {
- // Only pass a subset of the options to children
- $yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years']));
- $yearOptions['empty_value'] = $options['empty_value']['year'];
- $monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months']));
- $monthOptions['empty_value'] = $options['empty_value']['month'];
- $dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days']));
- $dayOptions['empty_value'] = $options['empty_value']['day'];
- }
-
- // Append generic carry-along options
- foreach (array('required', 'translation_domain') as $passOpt) {
- $yearOptions[$passOpt] = $monthOptions[$passOpt] = $dayOptions[$passOpt] = $options[$passOpt];
- }
-
- $builder
- ->add('year', $options['widget'], $yearOptions)
- ->add('month', $options['widget'], $monthOptions)
- ->add('day', $options['widget'], $dayOptions)
- ->addViewTransformer(new DateTimeToArrayTransformer(
- $options['model_timezone'], $options['view_timezone'], array('year', 'month', 'day')
- ))
- ->setAttribute('formatter', $formatter)
- ;
- }
-
- if ('string' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'Y-m-d')
- ));
- } elseif ('timestamp' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
- ));
- } elseif ('array' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], array('year', 'month', 'day'))
- ));
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars['widget'] = $options['widget'];
-
- // Change the input to a HTML5 date input if
- // * the widget is set to "single_text"
- // * the format matches the one expected by HTML5
- if ('single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) {
- $view->vars['type'] = 'date';
- }
-
- if ($form->getConfig()->hasAttribute('formatter')) {
- $pattern = $form->getConfig()->getAttribute('formatter')->getPattern();
-
- // remove special characters unless the format was explicitly specified
- if (!is_string($options['format'])) {
- $pattern = preg_replace('/[^yMd]+/', '', $pattern);
- }
-
- // set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy)
- // lookup various formats at http://userguide.icu-project.org/formatparse/datetime
- if (preg_match('/^([yMd]+)[^yMd]*([yMd]+)[^yMd]*([yMd]+)$/', $pattern)) {
- $pattern = preg_replace(array('/y+/', '/M+/', '/d+/'), array('{{ year }}', '{{ month }}', '{{ day }}'), $pattern);
- } else {
- // default fallback
- $pattern = '{{ year }}{{ month }}{{ day }}';
- }
-
- $view->vars['date_pattern'] = $pattern;
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $compound = function (Options $options) {
- return $options['widget'] !== 'single_text';
- };
-
- $emptyValue = $emptyValueDefault = function (Options $options) {
- return $options['required'] ? null : '';
- };
-
- $emptyValueNormalizer = function (Options $options, $emptyValue) use ($emptyValueDefault) {
- if (is_array($emptyValue)) {
- $default = $emptyValueDefault($options);
-
- return array_merge(
- array('year' => $default, 'month' => $default, 'day' => $default),
- $emptyValue
- );
- }
-
- return array(
- 'year' => $emptyValue,
- 'month' => $emptyValue,
- 'day' => $emptyValue
- );
- };
-
- $format = function (Options $options) {
- return $options['widget'] === 'single_text' ? DateType::HTML5_FORMAT : DateType::DEFAULT_FORMAT;
- };
-
- $resolver->setDefaults(array(
- 'years' => range(date('Y') - 5, date('Y') + 5),
- 'months' => range(1, 12),
- 'days' => range(1, 31),
- 'widget' => 'choice',
- 'input' => 'datetime',
- 'format' => $format,
- 'model_timezone' => null,
- 'view_timezone' => null,
- 'empty_value' => $emptyValue,
- // Don't modify \DateTime classes by reference, we treat
- // them like immutable value objects
- 'by_reference' => false,
- 'error_bubbling' => false,
- // If initialized with a \DateTime object, FormType initializes
- // this option to "\DateTime". Since the internal, normalized
- // representation is not \DateTime, but an array, we need to unset
- // this option.
- 'data_class' => null,
- 'compound' => $compound,
- ));
-
- $resolver->setNormalizers(array(
- 'empty_value' => $emptyValueNormalizer,
- ));
-
- $resolver->setAllowedValues(array(
- 'input' => array(
- 'datetime',
- 'string',
- 'timestamp',
- 'array',
- ),
- 'widget' => array(
- 'single_text',
- 'text',
- 'choice',
- ),
- ));
-
- $resolver->setAllowedTypes(array(
- 'format' => array('int', 'string'),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'date';
- }
-
- private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $timestamps)
- {
- $pattern = $formatter->getPattern();
- $timezone = $formatter->getTimezoneId();
-
- if (version_compare(\PHP_VERSION, '5.5.0-dev', '>=')) {
- $formatter->setTimeZone(\DateTimeZone::UTC);
- } else {
- $formatter->setTimeZoneId(\DateTimeZone::UTC);
- }
-
- if (preg_match($regex, $pattern, $matches)) {
- $formatter->setPattern($matches[0]);
-
- foreach ($timestamps as $key => $timestamp) {
- $timestamps[$key] = $formatter->format($timestamp);
- }
-
- // I'd like to clone the formatter above, but then we get a
- // segmentation fault, so let's restore the old state instead
- $formatter->setPattern($pattern);
- }
-
- if (version_compare(\PHP_VERSION, '5.5.0-dev', '>=')) {
- $formatter->setTimeZone($timezone);
- } else {
- $formatter->setTimeZoneId($timezone);
- }
-
- return $timestamps;
- }
-
- private function listYears(array $years)
- {
- $result = array();
-
- foreach ($years as $year) {
- $result[$year] = gmmktime(0, 0, 0, 6, 15, $year);
- }
-
- return $result;
- }
-
- private function listMonths(array $months)
- {
- $result = array();
-
- foreach ($months as $month) {
- $result[$month] = gmmktime(0, 0, 0, $month, 15);
- }
-
- return $result;
- }
-
- private function listDays(array $days)
- {
- $result = array();
-
- foreach ($days as $day) {
- $result[$day] = gmmktime(0, 0, 0, 5, $day);
- }
-
- return $result;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-
-class EmailType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'text';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'email';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class FileType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars = array_replace($view->vars, array(
- 'type' => 'file',
- 'value' => '',
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- $view
- ->vars['multipart'] = true
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'compound' => false,
- 'data_class' => 'Symfony\Component\HttpFoundation\File\File',
- 'empty_data' => null,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'file';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
-use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
-use Symfony\Component\Form\Exception\LogicException;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-use Symfony\Component\PropertyAccess\PropertyAccess;
-use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
-
-class FormType extends BaseType
-{
- /**
- * @var PropertyAccessorInterface
- */
- private $propertyAccessor;
-
- public function __construct(PropertyAccessorInterface $propertyAccessor = null)
- {
- $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor();
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- parent::buildForm($builder, $options);
-
- $builder
- ->setRequired($options['required'])
- ->setErrorBubbling($options['error_bubbling'])
- ->setEmptyData($options['empty_data'])
- ->setPropertyPath($options['property_path'])
- ->setMapped($options['mapped'])
- ->setByReference($options['by_reference'])
- ->setInheritData($options['inherit_data'])
- ->setCompound($options['compound'])
- ->setData(isset($options['data']) ? $options['data'] : null)
- ->setDataLocked(isset($options['data']))
- ->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
- ->setMethod($options['method'])
- ->setAction($options['action'])
- ->setAutoInitialize($options['auto_initialize'])
- ;
-
- if ($options['trim']) {
- $builder->addEventSubscriber(new TrimListener());
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- parent::buildView($view, $form, $options);
-
- $name = $form->getName();
- $readOnly = $options['read_only'];
-
- if ($view->parent) {
- if ('' === $name) {
- throw new LogicException('Form node with empty name can be used only as root form node.');
- }
-
- // Complex fields are read-only if they themselves or their parents are.
- if (!$readOnly) {
- $readOnly = $view->parent->vars['read_only'];
- }
- }
-
- $view->vars = array_replace($view->vars, array(
- 'read_only' => $readOnly,
- 'errors' => $form->getErrors(),
- 'valid' => $form->isSubmitted() ? $form->isValid() : true,
- 'value' => $form->getViewData(),
- 'data' => $form->getNormData(),
- 'required' => $form->isRequired(),
- 'max_length' => $options['max_length'],
- 'pattern' => $options['pattern'],
- 'size' => null,
- 'label_attr' => $options['label_attr'],
- 'compound' => $form->getConfig()->getCompound(),
- 'method' => $form->getConfig()->getMethod(),
- 'action' => $form->getConfig()->getAction(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- $multipart = false;
-
- foreach ($view->children as $child) {
- if ($child->vars['multipart']) {
- $multipart = true;
- break;
- }
- }
-
- $view->vars['multipart'] = $multipart;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- parent::setDefaultOptions($resolver);
-
- // Derive "data_class" option from passed "data" object
- $dataClass = function (Options $options) {
- return isset($options['data']) && is_object($options['data']) ? get_class($options['data']) : null;
- };
-
- // Derive "empty_data" closure from "data_class" option
- $emptyData = function (Options $options) {
- $class = $options['data_class'];
-
- if (null !== $class) {
- return function (FormInterface $form) use ($class) {
- return $form->isEmpty() && !$form->isRequired() ? null : new $class();
- };
- }
-
- return function (FormInterface $form) {
- return $form->getConfig()->getCompound() ? array() : '';
- };
- };
-
- // For any form that is not represented by a single HTML control,
- // errors should bubble up by default
- $errorBubbling = function (Options $options) {
- return $options['compound'];
- };
-
- // BC with old "virtual" option
- $inheritData = function (Options $options) {
- if (null !== $options['virtual']) {
- // Uncomment this as soon as the deprecation note should be shown
- // trigger_error('The form option "virtual" is deprecated since version 2.3 and will be removed in 3.0. Use "inherit_data" instead.', E_USER_DEPRECATED);
- return $options['virtual'];
- }
-
- return false;
- };
-
- // If data is given, the form is locked to that data
- // (independent of its value)
- $resolver->setOptional(array(
- 'data',
- ));
-
- $resolver->setDefaults(array(
- 'data_class' => $dataClass,
- 'empty_data' => $emptyData,
- 'trim' => true,
- 'required' => true,
- 'read_only' => false,
- 'max_length' => null,
- 'pattern' => null,
- 'property_path' => null,
- 'mapped' => true,
- 'by_reference' => true,
- 'error_bubbling' => $errorBubbling,
- 'label_attr' => array(),
- 'virtual' => null,
- 'inherit_data' => $inheritData,
- 'compound' => true,
- 'method' => 'POST',
- // According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
- // section 4.2., empty URIs are considered same-document references
- 'action' => '',
- 'auto_initialize' => true,
- ));
-
- $resolver->setAllowedTypes(array(
- 'label_attr' => 'array',
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return null;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'form';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class HiddenType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- // hidden fields cannot have a required attribute
- 'required' => false,
- // Pass errors to the parent
- 'error_bubbling' => true,
- 'compound' => false,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'hidden';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class IntegerType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->addViewTransformer(
- new IntegerToLocalizedStringTransformer(
- $options['precision'],
- $options['grouping'],
- $options['rounding_mode']
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- // default precision is locale specific (usually around 3)
- 'precision' => null,
- 'grouping' => false,
- // Integer cast rounds towards 0, so do the same when displaying fractions
- 'rounding_mode' => \NumberFormatter::ROUND_DOWN,
- 'compound' => false,
- ));
-
- $resolver->setAllowedValues(array(
- 'rounding_mode' => array(
- \NumberFormatter::ROUND_FLOOR,
- \NumberFormatter::ROUND_DOWN,
- \NumberFormatter::ROUND_HALFDOWN,
- \NumberFormatter::ROUND_HALFEVEN,
- \NumberFormatter::ROUND_HALFUP,
- \NumberFormatter::ROUND_UP,
- \NumberFormatter::ROUND_CEILING,
- ),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'integer';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class LanguageType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'choices' => Intl::getLanguageBundle()->getLanguageNames(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'choice';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'language';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Locale\Locale;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class LocaleType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'choices' => Intl::getLocaleBundle()->getLocaleNames(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'choice';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'locale';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class MoneyType extends AbstractType
-{
- protected static $patterns = array();
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder
- ->addViewTransformer(new MoneyToLocalizedStringTransformer(
- $options['precision'],
- $options['grouping'],
- null,
- $options['divisor']
- ))
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars['money_pattern'] = self::getPattern($options['currency']);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'precision' => 2,
- 'grouping' => false,
- 'divisor' => 1,
- 'currency' => 'EUR',
- 'compound' => false,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'money';
- }
-
- /**
- * Returns the pattern for this locale
- *
- * The pattern contains the placeholder "{{ widget }}" where the HTML tag should
- * be inserted
- */
- protected static function getPattern($currency)
- {
- if (!$currency) {
- return '{{ widget }}';
- }
-
- $locale = \Locale::getDefault();
-
- if (!isset(self::$patterns[$locale])) {
- self::$patterns[$locale] = array();
- }
-
- if (!isset(self::$patterns[$locale][$currency])) {
- $format = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
- $pattern = $format->formatCurrency('123', $currency);
-
- // the spacings between currency symbol and number are ignored, because
- // a single space leads to better readability in combination with input
- // fields
-
- // the regex also considers non-break spaces (0xC2 or 0xA0 in UTF-8)
-
- preg_match('/^([^\s\xc2\xa0]*)[\s\xc2\xa0]*123(?:[,.]0+)?[\s\xc2\xa0]*([^\s\xc2\xa0]*)$/u', $pattern, $matches);
-
- if (!empty($matches[1])) {
- self::$patterns[$locale][$currency] = $matches[1].' {{ widget }}';
- } elseif (!empty($matches[2])) {
- self::$patterns[$locale][$currency] = '{{ widget }} '.$matches[2];
- } else {
- self::$patterns[$locale][$currency] = '{{ widget }}';
- }
- }
-
- return self::$patterns[$locale][$currency];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class NumberType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->addViewTransformer(new NumberToLocalizedStringTransformer(
- $options['precision'],
- $options['grouping'],
- $options['rounding_mode']
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- // default precision is locale specific (usually around 3)
- 'precision' => null,
- 'grouping' => false,
- 'rounding_mode' => \NumberFormatter::ROUND_HALFUP,
- 'compound' => false,
- ));
-
- $resolver->setAllowedValues(array(
- 'rounding_mode' => array(
- \NumberFormatter::ROUND_FLOOR,
- \NumberFormatter::ROUND_DOWN,
- \NumberFormatter::ROUND_HALFDOWN,
- \NumberFormatter::ROUND_HALFEVEN,
- \NumberFormatter::ROUND_HALFUP,
- \NumberFormatter::ROUND_UP,
- \NumberFormatter::ROUND_CEILING,
- ),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'number';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class PasswordType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- if ($options['always_empty'] || !$form->isSubmitted()) {
- $view->vars['value'] = '';
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'always_empty' => true,
- 'trim' => false,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'text';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'password';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class PercentType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['precision'], $options['type']));
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'precision' => 0,
- 'type' => 'fractional',
- 'compound' => false,
- ));
-
- $resolver->setAllowedValues(array(
- 'type' => array(
- 'fractional',
- 'integer',
- ),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'percent';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-
-class RadioType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'checkbox';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'radio';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class RepeatedType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- // Overwrite required option for child fields
- $options['first_options']['required'] = $options['required'];
- $options['second_options']['required'] = $options['required'];
-
- if (!isset($options['options']['error_bubbling'])) {
- $options['options']['error_bubbling'] = $options['error_bubbling'];
- }
-
- $builder
- ->addViewTransformer(new ValueToDuplicatesTransformer(array(
- $options['first_name'],
- $options['second_name'],
- )))
- ->add($options['first_name'], $options['type'], array_merge($options['options'], $options['first_options']))
- ->add($options['second_name'], $options['type'], array_merge($options['options'], $options['second_options']))
- ;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'type' => 'text',
- 'options' => array(),
- 'first_options' => array(),
- 'second_options' => array(),
- 'first_name' => 'first',
- 'second_name' => 'second',
- 'error_bubbling' => false,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'repeated';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\ButtonTypeInterface;
-
-/**
- * A reset button.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ResetType extends AbstractType implements ButtonTypeInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'button';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'reset';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-
-class SearchType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'text';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'search';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\SubmitButtonTypeInterface;
-
-/**
- * A submit button.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SubmitType extends AbstractType implements SubmitButtonTypeInterface
-{
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars['clicked'] = $form->isClicked();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'button';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'submit';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class TextType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'compound' => false,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'text';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\FormInterface;
-
-class TextareaType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars['pattern'] = null;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'text';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'textarea';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\ReversedTransformer;
-use Symfony\Component\Form\Exception\InvalidConfigurationException;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class TimeType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $parts = array('hour');
- $format = 'H';
-
- if ($options['with_seconds'] && !$options['with_minutes']) {
- throw new InvalidConfigurationException('You can not disable minutes if you have enabled seconds.');
- }
-
- if ($options['with_minutes']) {
- $format .= ':i';
- $parts[] = 'minute';
- }
-
- if ($options['with_seconds']) {
- $format .= ':s';
- $parts[] = 'second';
- }
-
- if ('single_text' === $options['widget']) {
- $builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format));
- } else {
- $hourOptions = $minuteOptions = $secondOptions = array(
- 'error_bubbling' => true,
- );
-
- if ('choice' === $options['widget']) {
- $hours = $minutes = array();
-
- foreach ($options['hours'] as $hour) {
- $hours[$hour] = str_pad($hour, 2, '0', STR_PAD_LEFT);
- }
-
- // Only pass a subset of the options to children
- $hourOptions['choices'] = $hours;
- $hourOptions['empty_value'] = $options['empty_value']['hour'];
-
- if ($options['with_minutes']) {
- foreach ($options['minutes'] as $minute) {
- $minutes[$minute] = str_pad($minute, 2, '0', STR_PAD_LEFT);
- }
-
- $minuteOptions['choices'] = $minutes;
- $minuteOptions['empty_value'] = $options['empty_value']['minute'];
- }
-
- if ($options['with_seconds']) {
- $seconds = array();
-
- foreach ($options['seconds'] as $second) {
- $seconds[$second] = str_pad($second, 2, '0', STR_PAD_LEFT);
- }
-
- $secondOptions['choices'] = $seconds;
- $secondOptions['empty_value'] = $options['empty_value']['second'];
- }
-
- // Append generic carry-along options
- foreach (array('required', 'translation_domain') as $passOpt) {
- $hourOptions[$passOpt] = $options[$passOpt];
-
- if ($options['with_minutes']) {
- $minuteOptions[$passOpt] = $options[$passOpt];
- }
-
- if ($options['with_seconds']) {
- $secondOptions[$passOpt] = $options[$passOpt];
- }
- }
- }
-
- $builder->add('hour', $options['widget'], $hourOptions);
-
- if ($options['with_minutes']) {
- $builder->add('minute', $options['widget'], $minuteOptions);
- }
-
- if ($options['with_seconds']) {
- $builder->add('second', $options['widget'], $secondOptions);
- }
-
- $builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget']));
- }
-
- if ('string' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'H:i:s')
- ));
- } elseif ('timestamp' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone'])
- ));
- } elseif ('array' === $options['input']) {
- $builder->addModelTransformer(new ReversedTransformer(
- new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
- ));
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- $view->vars = array_replace($view->vars, array(
- 'widget' => $options['widget'],
- 'with_minutes' => $options['with_minutes'],
- 'with_seconds' => $options['with_seconds'],
- ));
-
- if ('single_text' === $options['widget']) {
- $view->vars['type'] = 'time';
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $compound = function (Options $options) {
- return $options['widget'] !== 'single_text';
- };
-
- $emptyValue = $emptyValueDefault = function (Options $options) {
- return $options['required'] ? null : '';
- };
-
- $emptyValueNormalizer = function (Options $options, $emptyValue) use ($emptyValueDefault) {
- if (is_array($emptyValue)) {
- $default = $emptyValueDefault($options);
-
- return array_merge(
- array('hour' => $default, 'minute' => $default, 'second' => $default),
- $emptyValue
- );
- }
-
- return array(
- 'hour' => $emptyValue,
- 'minute' => $emptyValue,
- 'second' => $emptyValue
- );
- };
-
- $resolver->setDefaults(array(
- 'hours' => range(0, 23),
- 'minutes' => range(0, 59),
- 'seconds' => range(0, 59),
- 'widget' => 'choice',
- 'input' => 'datetime',
- 'with_minutes' => true,
- 'with_seconds' => false,
- 'model_timezone' => null,
- 'view_timezone' => null,
- 'empty_value' => $emptyValue,
- // Don't modify \DateTime classes by reference, we treat
- // them like immutable value objects
- 'by_reference' => false,
- 'error_bubbling' => false,
- // If initialized with a \DateTime object, FormType initializes
- // this option to "\DateTime". Since the internal, normalized
- // representation is not \DateTime, but an array, we need to unset
- // this option.
- 'data_class' => null,
- 'compound' => $compound,
- ));
-
- $resolver->setNormalizers(array(
- 'empty_value' => $emptyValueNormalizer,
- ));
-
- $resolver->setAllowedValues(array(
- 'input' => array(
- 'datetime',
- 'string',
- 'timestamp',
- 'array',
- ),
- 'widget' => array(
- 'single_text',
- 'text',
- 'choice',
- ),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'time';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class TimezoneType extends AbstractType
-{
- /**
- * Stores the available timezone choices
- * @var array
- */
- private static $timezones;
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'choices' => self::getTimezones(),
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'choice';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'timezone';
- }
-
- /**
- * Returns the timezone choices.
- *
- * The choices are generated from the ICU function
- * \DateTimeZone::listIdentifiers(). They are cached during a single request,
- * so multiple timezone fields on the same page don't lead to unnecessary
- * overhead.
- *
- * @return array The timezone choices
- */
- public static function getTimezones()
- {
- if (null === static::$timezones) {
- static::$timezones = array();
-
- foreach (\DateTimeZone::listIdentifiers() as $timezone) {
- $parts = explode('/', $timezone);
-
- if (count($parts) > 2) {
- $region = $parts[0];
- $name = $parts[1].' - '.$parts[2];
- } elseif (count($parts) > 1) {
- $region = $parts[0];
- $name = $parts[1];
- } else {
- $region = 'Other';
- $name = $parts[0];
- }
-
- static::$timezones[$region][$timezone] = str_replace('_', ' ', $name);
- }
- }
-
- return static::$timezones;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class UrlType extends AbstractType
-{
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->addEventSubscriber(new FixUrlProtocolListener($options['default_protocol']));
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'default_protocol' => 'http',
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return 'text';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'url';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Core\View;
-
-/**
- * Represents a choice in templates.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ChoiceView
-{
- /**
- * The original choice value.
- *
- * @var mixed
- */
- public $data;
-
- /**
- * The view representation of the choice.
- *
- * @var string
- */
- public $value;
-
- /**
- * The label displayed to humans.
- *
- * @var string
- */
- public $label;
-
- /**
- * Creates a new ChoiceView.
- *
- * @param mixed $data The original choice.
- * @param string $value The view representation of the choice.
- * @param string $label The label displayed to humans.
- */
- public function __construct($data, $value, $label)
- {
- $this->data = $data;
- $this->value = $value;
- $this->label = $label;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf;
-
-use Symfony\Component\Form\Extension\Csrf\Type;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-use Symfony\Component\Form\AbstractExtension;
-use Symfony\Component\Translation\TranslatorInterface;
-
-/**
- * This extension protects forms by using a CSRF token.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CsrfExtension extends AbstractExtension
-{
- /**
- * @var CsrfProviderInterface
- */
- private $csrfProvider;
-
- /**
- * @var TranslatorInterface
- */
- private $translator;
-
- /**
- * @var null|string
- */
- private $translationDomain;
-
- /**
- * Constructor.
- *
- * @param CsrfProviderInterface $csrfProvider The CSRF provider
- * @param TranslatorInterface $translator The translator for translating error messages.
- * @param null|string $translationDomain The translation domain for translating.
- */
- public function __construct(CsrfProviderInterface $csrfProvider, TranslatorInterface $translator = null, $translationDomain = null)
- {
- $this->csrfProvider = $csrfProvider;
- $this->translator = $translator;
- $this->translationDomain = $translationDomain;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function loadTypeExtensions()
- {
- return array(
- new Type\FormTypeCsrfExtension($this->csrfProvider, true, '_token', $this->translator, $this->translationDomain),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
-
-/**
- * Marks classes able to provide CSRF protection
- *
- * You can generate a CSRF token by using the method generateCsrfToken(). To
- * this method you should pass a value that is unique to the page that should
- * be secured against CSRF attacks. This value doesn't necessarily have to be
- * secret. Implementations of this interface are responsible for adding more
- * secret information.
- *
- * If you want to secure a form submission against CSRF attacks, you could
- * supply an "intention" string. This way you make sure that the form can only
- * be submitted to pages that are designed to handle the form, that is, that use
- * the same intention string to validate the CSRF token with isCsrfTokenValid().
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface CsrfProviderInterface
-{
- /**
- * Generates a CSRF token for a page of your application.
- *
- * @param string $intention Some value that identifies the action intention
- * (i.e. "authenticate"). Doesn't have to be a secret value.
- */
- public function generateCsrfToken($intention);
-
- /**
- * Validates a CSRF token.
- *
- * @param string $intention The intention used when generating the CSRF token
- * @param string $token The token supplied by the browser
- *
- * @return Boolean Whether the token supplied by the browser is correct
- */
- public function isCsrfTokenValid($intention, $token);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
-
-/**
- * Default implementation of CsrfProviderInterface.
- *
- * This provider uses the session ID returned by session_id() as well as a
- * user-defined secret value to secure the CSRF token.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class DefaultCsrfProvider implements CsrfProviderInterface
-{
- /**
- * A secret value used for generating the CSRF token
- * @var string
- */
- protected $secret;
-
- /**
- * Initializes the provider with a secret value
- *
- * A recommended value for the secret is a generated value with at least
- * 32 characters and mixed letters, digits and special characters.
- *
- * @param string $secret A secret value included in the CSRF token
- */
- public function __construct($secret)
- {
- $this->secret = $secret;
- }
-
- /**
- * {@inheritDoc}
- */
- public function generateCsrfToken($intention)
- {
- return sha1($this->secret.$intention.$this->getSessionId());
- }
-
- /**
- * {@inheritDoc}
- */
- public function isCsrfTokenValid($intention, $token)
- {
- return $token === $this->generateCsrfToken($intention);
- }
-
- /**
- * Returns the ID of the user session.
- *
- * Automatically starts the session if necessary.
- *
- * @return string The session ID
- */
- protected function getSessionId()
- {
- if (version_compare(PHP_VERSION, '5.4', '>=')) {
- if (PHP_SESSION_NONE === session_status()) {
- session_start();
- }
- } elseif (!session_id()) {
- session_start();
- }
-
- return session_id();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
-
-use Symfony\Component\HttpFoundation\Session\Session;
-
-/**
- * This provider uses a Symfony2 Session object to retrieve the user's
- * session ID.
- *
- * @see DefaultCsrfProvider
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SessionCsrfProvider extends DefaultCsrfProvider
-{
- /**
- * The user session from which the session ID is returned
- * @var Session
- */
- protected $session;
-
- /**
- * Initializes the provider with a Session object and a secret value.
- *
- * A recommended value for the secret is a generated value with at least
- * 32 characters and mixed letters, digits and special characters.
- *
- * @param Session $session The user session
- * @param string $secret A secret value included in the CSRF token
- */
- public function __construct(Session $session, $secret)
- {
- parent::__construct($secret);
-
- $this->session = $session;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function getSessionId()
- {
- $this->session->start();
-
- return $this->session->getId();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\EventListener;
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-use Symfony\Component\Translation\TranslatorInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CsrfValidationListener implements EventSubscriberInterface
-{
- /**
- * The name of the CSRF field
- * @var string
- */
- private $fieldName;
-
- /**
- * The provider for generating and validating CSRF tokens
- * @var CsrfProviderInterface
- */
- private $csrfProvider;
-
- /**
- * A text mentioning the intention of the CSRF token
- *
- * Validation of the token will only succeed if it was generated in the
- * same session and with the same intention.
- *
- * @var string
- */
- private $intention;
-
- /**
- * The message displayed in case of an error.
- * @var string
- */
- private $errorMessage;
-
- /**
- * @var TranslatorInterface
- */
- private $translator;
-
- /**
- * @var null|string
- */
- private $translationDomain;
-
- public static function getSubscribedEvents()
- {
- return array(
- FormEvents::PRE_SUBMIT => 'preSubmit',
- );
- }
-
- public function __construct($fieldName, CsrfProviderInterface $csrfProvider, $intention, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null)
- {
- $this->fieldName = $fieldName;
- $this->csrfProvider = $csrfProvider;
- $this->intention = $intention;
- $this->errorMessage = $errorMessage;
- $this->translator = $translator;
- $this->translationDomain = $translationDomain;
- }
-
- public function preSubmit(FormEvent $event)
- {
- $form = $event->getForm();
- $data = $event->getData();
-
- if ($form->isRoot() && $form->getConfig()->getOption('compound')) {
- if (!isset($data[$this->fieldName]) || !$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) {
- $errorMessage = $this->errorMessage;
-
- if (null !== $this->translator) {
- $errorMessage = $this->translator->trans($errorMessage, array(), $this->translationDomain);
- }
-
- $form->addError(new FormError($errorMessage));
- }
-
- if (is_array($data)) {
- unset($data[$this->fieldName]);
- }
- }
-
- $event->setData($data);
- }
-
- /**
- * Alias of {@link preSubmit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link preSubmit()} instead.
- */
- public function preBind(FormEvent $event)
- {
- $this->preSubmit($event);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Csrf\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-use Symfony\Component\Translation\TranslatorInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormTypeCsrfExtension extends AbstractTypeExtension
-{
- /**
- * @var CsrfProviderInterface
- */
- private $defaultCsrfProvider;
-
- /**
- * @var Boolean
- */
- private $defaultEnabled;
-
- /**
- * @var string
- */
- private $defaultFieldName;
-
- /**
- * @var TranslatorInterface
- */
- private $translator;
-
- /**
- * @var null|string
- */
- private $translationDomain;
-
- public function __construct(CsrfProviderInterface $defaultCsrfProvider, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null)
- {
- $this->defaultCsrfProvider = $defaultCsrfProvider;
- $this->defaultEnabled = $defaultEnabled;
- $this->defaultFieldName = $defaultFieldName;
- $this->translator = $translator;
- $this->translationDomain = $translationDomain;
- }
-
- /**
- * Adds a CSRF field to the form when the CSRF protection is enabled.
- *
- * @param FormBuilderInterface $builder The form builder
- * @param array $options The options
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- if (!$options['csrf_protection']) {
- return;
- }
-
- $builder
- ->setAttribute('csrf_factory', $builder->getFormFactory())
- ->addEventSubscriber(new CsrfValidationListener(
- $options['csrf_field_name'],
- $options['csrf_provider'],
- $options['intention'],
- $options['csrf_message'],
- $this->translator,
- $this->translationDomain
- ))
- ;
- }
-
- /**
- * Adds a CSRF field to the root form view.
- *
- * @param FormView $view The form view
- * @param FormInterface $form The form
- * @param array $options The options
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- if ($options['csrf_protection'] && !$view->parent && $options['compound']) {
- $factory = $form->getConfig()->getAttribute('csrf_factory');
- $data = $options['csrf_provider']->generateCsrfToken($options['intention']);
-
- $csrfForm = $factory->createNamed($options['csrf_field_name'], 'hidden', $data, array(
- 'mapped' => false,
- ));
-
- $view->children[$options['csrf_field_name']] = $csrfForm->createView($view);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'csrf_protection' => $this->defaultEnabled,
- 'csrf_field_name' => $this->defaultFieldName,
- 'csrf_provider' => $this->defaultCsrfProvider,
- 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.',
- 'intention' => 'unknown',
- ));
- }
-
- /**
- * {@inheritDoc}
- */
- public function getExtendedType()
- {
- return 'form';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\DependencyInjection;
-
-use Symfony\Component\Form\FormExtensionInterface;
-use Symfony\Component\Form\FormTypeGuesserChain;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-class DependencyInjectionExtension implements FormExtensionInterface
-{
- private $container;
-
- private $typeServiceIds;
-
- private $guesserServiceIds;
-
- private $guesser;
-
- private $guesserLoaded = false;
-
- public function __construct(ContainerInterface $container,
- array $typeServiceIds, array $typeExtensionServiceIds,
- array $guesserServiceIds)
- {
- $this->container = $container;
- $this->typeServiceIds = $typeServiceIds;
- $this->typeExtensionServiceIds = $typeExtensionServiceIds;
- $this->guesserServiceIds = $guesserServiceIds;
- }
-
- public function getType($name)
- {
- if (!isset($this->typeServiceIds[$name])) {
- throw new InvalidArgumentException(sprintf('The field type "%s" is not registered with the service container.', $name));
- }
-
- $type = $this->container->get($this->typeServiceIds[$name]);
-
- if ($type->getName() !== $name) {
- throw new InvalidArgumentException(
- sprintf('The type name specified for the service "%s" does not match the actual name. Expected "%s", given "%s"',
- $this->typeServiceIds[$name],
- $name,
- $type->getName()
- ));
- }
-
- return $type;
- }
-
- public function hasType($name)
- {
- return isset($this->typeServiceIds[$name]);
- }
-
- public function getTypeExtensions($name)
- {
- $extensions = array();
-
- if (isset($this->typeExtensionServiceIds[$name])) {
- foreach ($this->typeExtensionServiceIds[$name] as $serviceId) {
- $extensions[] = $this->container->get($serviceId);
- }
- }
-
- return $extensions;
- }
-
- public function hasTypeExtensions($name)
- {
- return isset($this->typeExtensionServiceIds[$name]);
- }
-
- public function getTypeGuesser()
- {
- if (!$this->guesserLoaded) {
- $this->guesserLoaded = true;
- $guessers = array();
-
- foreach ($this->guesserServiceIds as $serviceId) {
- $guessers[] = $this->container->get($serviceId);
- }
-
- if (count($guessers) > 0) {
- $this->guesser = new FormTypeGuesserChain($guessers);
- }
- }
-
- return $this->guesser;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\HttpFoundation\EventListener;
-
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Exception\LogicException;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Pass the
- * Request instance to {@link Form::process()} instead.
- */
-class BindRequestListener implements EventSubscriberInterface
-{
- public static function getSubscribedEvents()
- {
- // High priority in order to supersede other listeners
- return array(FormEvents::PRE_BIND => array('preBind', 128));
- }
-
- public function preBind(FormEvent $event)
- {
- $form = $event->getForm();
-
- /* @var Request $request */
- $request = $event->getData();
-
- // Only proceed if we actually deal with a Request
- if (!$request instanceof Request) {
- return;
- }
-
- // Uncomment this as soon as the deprecation note should be shown
- // trigger_error('Passing a Request instance to Form::submit() is deprecated since version 2.3 and will be disabled in 3.0. Call Form::process($request) instead.', E_USER_DEPRECATED);
-
- $name = $form->getConfig()->getName();
- $default = $form->getConfig()->getCompound() ? array() : null;
-
- // Store the bound data in case of a post request
- switch ($request->getMethod()) {
- case 'POST':
- case 'PUT':
- case 'DELETE':
- case 'PATCH':
- if ('' === $name) {
- // Form bound without name
- $params = $request->request->all();
- $files = $request->files->all();
- } else {
- $params = $request->request->get($name, $default);
- $files = $request->files->get($name, $default);
- }
-
- if (is_array($params) && is_array($files)) {
- $data = array_replace_recursive($params, $files);
- } else {
- $data = $params ?: $files;
- }
-
- break;
-
- case 'GET':
- $data = '' === $name
- ? $request->query->all()
- : $request->query->get($name, $default);
-
- break;
-
- default:
- throw new LogicException(sprintf(
- 'The request method "%s" is not supported',
- $request->getMethod()
- ));
- }
-
- $event->setData($data);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\HttpFoundation;
-
-use Symfony\Component\Form\AbstractExtension;
-
-/**
- * Integrates the HttpFoundation component with the Form library.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class HttpFoundationExtension extends AbstractExtension
-{
- protected function loadTypeExtensions()
- {
- return array(
- new Type\FormTypeHttpFoundationExtension(),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\HttpFoundation;
-
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\RequestHandlerInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * A request processor using the {@link Request} class of the HttpFoundation
- * component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class HttpFoundationRequestHandler implements RequestHandlerInterface
-{
- /**
- * {@inheritdoc}
- */
- public function handleRequest(FormInterface $form, $request = null)
- {
- if (!$request instanceof Request) {
- throw new UnexpectedTypeException($request, 'Symfony\Component\HttpFoundation\Request');
- }
-
- $name = $form->getName();
- $method = $form->getConfig()->getMethod();
-
- if ($method !== $request->getMethod()) {
- return;
- }
-
- if ('GET' === $method) {
- if ('' === $name) {
- $data = $request->query->all();
- } else {
- // Don't submit GET requests if the form's name does not exist
- // in the request
- if (!$request->query->has($name)) {
- return;
- }
-
- $data = $request->query->get($name);
- }
- } else {
- if ('' === $name) {
- $params = $request->request->all();
- $files = $request->files->all();
- } else {
- $default = $form->getConfig()->getCompound() ? array() : null;
- $params = $request->request->get($name, $default);
- $files = $request->files->get($name, $default);
- }
-
- if (is_array($params) && is_array($files)) {
- $data = array_replace_recursive($params, $files);
- } else {
- $data = $params ?: $files;
- }
- }
-
- // Don't auto-submit the form unless at least one field is present.
- if ('' === $name && count(array_intersect_key($data, $form->all())) <= 0) {
- return;
- }
-
- $form->submit($data, 'PATCH' !== $method);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\HttpFoundation\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
-use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
-use Symfony\Component\Form\FormBuilderInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormTypeHttpFoundationExtension extends AbstractTypeExtension
-{
- /**
- * @var BindRequestListener
- */
- private $listener;
-
- /**
- * @var HttpFoundationRequestHandler
- */
- private $requestHandler;
-
- public function __construct()
- {
- $this->listener = new BindRequestListener();
- $this->requestHandler = new HttpFoundationRequestHandler();
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->addEventSubscriber($this->listener);
- $builder->setRequestHandler($this->requestHandler);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getExtendedType()
- {
- return 'form';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Templating;
-
-use Symfony\Component\Form\AbstractExtension;
-use Symfony\Component\Form\FormRenderer;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-use Symfony\Component\Templating\PhpEngine;
-use Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper;
-
-/**
- * Integrates the Templating component with the Form library.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class TemplatingExtension extends AbstractExtension
-{
- public function __construct(PhpEngine $engine, CsrfProviderInterface $csrfProvider = null, array $defaultThemes = array())
- {
- $engine->addHelpers(array(
- new FormHelper(new FormRenderer(new TemplatingRendererEngine($engine, $defaultThemes), $csrfProvider))
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Templating;
-
-use Symfony\Component\Form\AbstractRendererEngine;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Templating\EngineInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class TemplatingRendererEngine extends AbstractRendererEngine
-{
- /**
- * @var EngineInterface
- */
- private $engine;
-
- public function __construct(EngineInterface $engine, array $defaultThemes = array())
- {
- parent::__construct($defaultThemes);
-
- $this->engine = $engine;
- }
-
- /**
- * {@inheritdoc}
- */
- public function renderBlock(FormView $view, $resource, $blockName, array $variables = array())
- {
- return trim($this->engine->render($resource, $variables));
- }
-
- /**
- * Loads the cache with the resource for a given block name.
- *
- * This implementation tries to load as few blocks as possible, since each block
- * is represented by a template on the file system.
- *
- * @see getResourceForBlock()
- *
- * @param string $cacheKey The cache key of the form view.
- * @param FormView $view The form view for finding the applying themes.
- * @param string $blockName The name of the block to load.
- *
- * @return Boolean True if the resource could be loaded, false otherwise.
- */
- protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName)
- {
- // Recursively try to find the block in the themes assigned to $view,
- // then of its parent form, then of the parent form of the parent and so on.
- // When the root form is reached in this recursion, also the default
- // themes are taken into account.
-
- // Check each theme whether it contains the searched block
- if (isset($this->themes[$cacheKey])) {
- for ($i = count($this->themes[$cacheKey]) - 1; $i >= 0; --$i) {
- if ($this->loadResourceFromTheme($cacheKey, $blockName, $this->themes[$cacheKey][$i])) {
- return true;
- }
- }
- }
-
- // Check the default themes once we reach the root form without success
- if (!$view->parent) {
- for ($i = count($this->defaultThemes) - 1; $i >= 0; --$i) {
- if ($this->loadResourceFromTheme($cacheKey, $blockName, $this->defaultThemes[$i])) {
- return true;
- }
- }
- }
-
- // If we did not find anything in the themes of the current view, proceed
- // with the themes of the parent view
- if ($view->parent) {
- $parentCacheKey = $view->parent->vars[self::CACHE_KEY_VAR];
-
- if (!isset($this->resources[$parentCacheKey][$blockName])) {
- $this->loadResourceForBlockName($parentCacheKey, $view->parent, $blockName);
- }
-
- // If a template exists in the parent themes, cache that template
- // for the current theme as well to speed up further accesses
- if ($this->resources[$parentCacheKey][$blockName]) {
- $this->resources[$cacheKey][$blockName] = $this->resources[$parentCacheKey][$blockName];
-
- return true;
- }
- }
-
- // Cache that we didn't find anything to speed up further accesses
- $this->resources[$cacheKey][$blockName] = false;
-
- return false;
- }
-
- /**
- * Tries to load the resource for a block from a theme.
- *
- * @param string $cacheKey The cache key for storing the resource.
- * @param string $blockName The name of the block to load a resource for.
- * @param mixed $theme The theme to load the block from.
- *
- * @return Boolean True if the resource could be loaded, false otherwise.
- */
- protected function loadResourceFromTheme($cacheKey, $blockName, $theme)
- {
- if ($this->engine->exists($templateName = $theme.':'.$blockName.'.html.php')) {
- $this->resources[$cacheKey][$blockName] = $templateName;
-
- return true;
- }
-
- return false;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\Constraints;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Form extends Constraint
-{
- /**
- * Violation code marking an invalid form.
- */
- const ERR_INVALID = 1;
-
- /**
- * {@inheritdoc}
- */
- public function getTargets()
- {
- return self::CLASS_CONSTRAINT;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\Constraints;
-
-use Symfony\Component\Form\ClickableInterface;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Extension\Validator\Util\ServerParams;
-use Symfony\Component\Validator\Constraint;
-use Symfony\Component\Validator\ConstraintValidator;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormValidator extends ConstraintValidator
-{
- /**
- * @var ServerParams
- */
- private $serverParams;
-
- /**
- * Creates a validator with the given server parameters.
- *
- * @param ServerParams $params The server parameters. Default
- * parameters are created if null.
- */
- public function __construct(ServerParams $params = null)
- {
- $this->serverParams = $params ?: new ServerParams();
- }
-
- /**
- * {@inheritdoc}
- */
- public function validate($form, Constraint $constraint)
- {
- if (!$form instanceof FormInterface) {
- return;
- }
-
- /* @var FormInterface $form */
- $config = $form->getConfig();
-
- if ($form->isSynchronized()) {
- // Validate the form data only if transformation succeeded
- $groups = self::getValidationGroups($form);
-
- // Validate the data against its own constraints
- if (self::allowDataWalking($form)) {
- foreach ($groups as $group) {
- $this->context->validate($form->getData(), 'data', $group, true);
- }
- }
-
- // Validate the data against the constraints defined
- // in the form
- $constraints = $config->getOption('constraints');
- foreach ($constraints as $constraint) {
- foreach ($groups as $group) {
- if (in_array($group, $constraint->groups)) {
- $this->context->validateValue($form->getData(), $constraint, 'data', $group);
-
- // Prevent duplicate validation
- continue 2;
- }
- }
- }
- } else {
- $childrenSynchronized = true;
-
- foreach ($form as $child) {
- if (!$child->isSynchronized()) {
- $childrenSynchronized = false;
- break;
- }
- }
-
- // Mark the form with an error if it is not synchronized BUT all
- // of its children are synchronized. If any child is not
- // synchronized, an error is displayed there already and showing
- // a second error in its parent form is pointless, or worse, may
- // lead to duplicate errors if error bubbling is enabled on the
- // child.
- // See also https://github.com/symfony/symfony/issues/4359
- if ($childrenSynchronized) {
- $clientDataAsString = is_scalar($form->getViewData())
- ? (string) $form->getViewData()
- : gettype($form->getViewData());
-
- $this->context->addViolation(
- $config->getOption('invalid_message'),
- array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')),
- $form->getViewData(),
- null,
- Form::ERR_INVALID
- );
- }
- }
-
- // Mark the form with an error if it contains extra fields
- if (count($form->getExtraData()) > 0) {
- $this->context->addViolation(
- $config->getOption('extra_fields_message'),
- array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
- $form->getExtraData()
- );
- }
-
- // Mark the form with an error if the uploaded size was too large
- $length = $this->serverParams->getContentLength();
-
- if ($form->isRoot() && null !== $length) {
- $max = $this->serverParams->getPostMaxSize();
-
- if (!empty($max) && $length > $max) {
- $this->context->addViolation(
- $config->getOption('post_max_size_message'),
- array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()),
- $length
- );
- }
- }
- }
-
- /**
- * Returns whether the data of a form may be walked.
- *
- * @param FormInterface $form The form to test.
- *
- * @return Boolean Whether the graph walker may walk the data.
- */
- private static function allowDataWalking(FormInterface $form)
- {
- $data = $form->getData();
-
- // Scalar values cannot have mapped constraints
- if (!is_object($data) && !is_array($data)) {
- return false;
- }
-
- // Root forms are always validated
- if ($form->isRoot()) {
- return true;
- }
-
- // Non-root forms are validated if validation cascading
- // is enabled in all ancestor forms
- while (null !== ($form = $form->getParent())) {
- if (!$form->getConfig()->getOption('cascade_validation')) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns the validation groups of the given form.
- *
- * @param FormInterface $form The form.
- *
- * @return array The validation groups.
- */
- private static function getValidationGroups(FormInterface $form)
- {
- $button = self::findClickedButton($form->getRoot());
-
- if (null !== $button) {
- $groups = $button->getConfig()->getOption('validation_groups');
-
- if (null !== $groups) {
- return self::resolveValidationGroups($groups, $form);
- }
- }
-
- do {
- $groups = $form->getConfig()->getOption('validation_groups');
-
- if (null !== $groups) {
- return self::resolveValidationGroups($groups, $form);
- }
-
- $form = $form->getParent();
- } while (null !== $form);
-
- return array(Constraint::DEFAULT_GROUP);
- }
-
- /**
- * Extracts a clicked button from a form tree, if one exists.
- *
- * @param FormInterface $form The root form.
- *
- * @return ClickableInterface|null The clicked button or null.
- */
- private static function findClickedButton(FormInterface $form)
- {
- if ($form instanceof ClickableInterface && $form->isClicked()) {
- return $form;
- }
-
- foreach ($form as $child) {
- if (null !== ($button = self::findClickedButton($child))) {
- return $button;
- }
- }
-
- return null;
- }
-
- /**
- * Post-processes the validation groups option for a given form.
- *
- * @param array|callable $groups The validation groups.
- * @param FormInterface $form The validated form.
- *
- * @return array The validation groups.
- */
- private static function resolveValidationGroups($groups, FormInterface $form)
- {
- if (!is_string($groups) && is_callable($groups)) {
- $groups = call_user_func($groups, $form);
- }
-
- return (array) $groups;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\EventListener;
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface;
-use Symfony\Component\Validator\ValidatorInterface;
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Validator\Constraints\Form;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ValidationListener implements EventSubscriberInterface
-{
- private $validator;
-
- private $violationMapper;
-
- /**
- * {@inheritdoc}
- */
- public static function getSubscribedEvents()
- {
- return array(FormEvents::POST_SUBMIT => 'validateForm');
- }
-
- public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper)
- {
- $this->validator = $validator;
- $this->violationMapper = $violationMapper;
- }
-
- /**
- * Validates the form and its domain object.
- *
- * @param FormEvent $event The event object
- */
- public function validateForm(FormEvent $event)
- {
- $form = $event->getForm();
-
- if ($form->isRoot()) {
- // Validate the form in group "Default"
- $violations = $this->validator->validate($form);
-
- if (count($violations) > 0) {
- foreach ($violations as $violation) {
- // Allow the "invalid" constraint to be put onto
- // non-synchronized forms
- $allowNonSynchronized = Form::ERR_INVALID === $violation->getCode();
-
- $this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized);
- }
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * Encapsulates common logic of {@link FormTypeValidatorExtension} and
- * {@link SubmitTypeValidatorExtension}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class BaseValidatorExtension extends AbstractTypeExtension
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- // Make sure that validation groups end up as null, closure or array
- $validationGroupsNormalizer = function (Options $options, $groups) {
- if (false === $groups) {
- return array();
- }
-
- if (empty($groups)) {
- return null;
- }
-
- if (is_callable($groups)) {
- return $groups;
- }
-
- return (array) $groups;
- };
-
- $resolver->setDefaults(array(
- 'validation_groups' => null,
- ));
-
- $resolver->setNormalizers(array(
- 'validation_groups' => $validationGroupsNormalizer,
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\Type;
-
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
-use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
-use Symfony\Component\Validator\ValidatorInterface;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormTypeValidatorExtension extends BaseValidatorExtension
-{
- /**
- * @var ValidatorInterface
- */
- private $validator;
-
- /**
- * @var ViolationMapper
- */
- private $violationMapper;
-
- public function __construct(ValidatorInterface $validator)
- {
- $this->validator = $validator;
- $this->violationMapper = new ViolationMapper();
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper));
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- parent::setDefaultOptions($resolver);
-
- // Constraint should always be converted to an array
- $constraintsNormalizer = function (Options $options, $constraints) {
- return is_object($constraints) ? array($constraints) : (array) $constraints;
- };
-
- $resolver->setDefaults(array(
- 'error_mapping' => array(),
- 'constraints' => array(),
- 'cascade_validation' => false,
- 'invalid_message' => 'This value is not valid.',
- 'invalid_message_parameters' => array(),
- 'extra_fields_message' => 'This form should not contain extra fields.',
- 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
- ));
-
- $resolver->setNormalizers(array(
- 'constraints' => $constraintsNormalizer,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getExtendedType()
- {
- return 'form';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\OptionsResolver\Options;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RepeatedTypeValidatorExtension extends AbstractTypeExtension
-{
- /**
- * {@inheritdoc}
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- // Map errors to the first field
- $errorMapping = function (Options $options) {
- return array('.' => $options['first_name']);
- };
-
- $resolver->setDefaults(array(
- 'error_mapping' => $errorMapping,
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getExtendedType()
- {
- return 'repeated';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\Type;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SubmitTypeValidatorExtension extends AbstractTypeExtension
-{
- /**
- * {@inheritdoc}
- */
- public function getExtendedType()
- {
- return 'submit';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\Util;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ServerParams
-{
- /**
- * Returns maximum post size in bytes.
- *
- * @return null|integer The maximum post size in bytes
- */
- public function getPostMaxSize()
- {
- $iniMax = $this->getNormalizedIniPostMaxSize();
-
- if ('' === $iniMax) {
- return null;
- }
-
- if (preg_match('#^\+?(0X?)?(.*?)([KMG]?)$#', $iniMax, $match)) {
- $shifts = array('' => 0, 'K' => 10, 'M' => 20, 'G' => 30);
- $bases = array('' => 10, '0' => 8, '0X' => 16);
-
- return intval($match[2], $bases[$match[1]]) << $shifts[$match[3]];
- }
-
- return 0;
- }
-
- /**
- * Returns the normalized "post_max_size" ini setting.
- *
- * @return string
- */
- public function getNormalizedIniPostMaxSize()
- {
- return strtoupper(trim(ini_get('post_max_size')));
- }
-
- /**
- * Returns the content length of the request.
- *
- * @return mixed The request content length.
- */
- public function getContentLength()
- {
- return isset($_SERVER['CONTENT_LENGTH'])
- ? (int) $_SERVER['CONTENT_LENGTH']
- : null;
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator;
-
-use Symfony\Component\Form\Extension\Validator\Type;
-use Symfony\Component\Form\Extension\Validator\Constraints\Form;
-use Symfony\Component\Form\AbstractExtension;
-use Symfony\Component\Validator\ValidatorInterface;
-use Symfony\Component\Validator\Constraints\Valid;
-
-/**
- * Extension supporting the Symfony2 Validator component in forms.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ValidatorExtension extends AbstractExtension
-{
- private $validator;
-
- public function __construct(ValidatorInterface $validator)
- {
- $this->validator = $validator;
-
- // Register the form constraints in the validator programmatically.
- // This functionality is required when using the Form component without
- // the DIC, where the XML file is loaded automatically. Thus the following
- // code must be kept synchronized with validation.xml
-
- /** @var \Symfony\Component\Validator\Mapping\ClassMetadata $metadata */
- $metadata = $this->validator->getMetadataFactory()->getMetadataFor('Symfony\Component\Form\Form');
- $metadata->addConstraint(new Form());
- $metadata->addPropertyConstraint('children', new Valid());
- }
-
- public function loadTypeGuesser()
- {
- return new ValidatorTypeGuesser($this->validator->getMetadataFactory());
- }
-
- protected function loadTypeExtensions()
- {
- return array(
- new Type\FormTypeValidatorExtension($this->validator),
- new Type\RepeatedTypeValidatorExtension(),
- new Type\SubmitTypeValidatorExtension(),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator;
-
-use Symfony\Component\Form\FormTypeGuesserInterface;
-use Symfony\Component\Form\Guess\Guess;
-use Symfony\Component\Form\Guess\TypeGuess;
-use Symfony\Component\Form\Guess\ValueGuess;
-use Symfony\Component\Validator\MetadataFactoryInterface;
-use Symfony\Component\Validator\Constraint;
-
-class ValidatorTypeGuesser implements FormTypeGuesserInterface
-{
- private $metadataFactory;
-
- public function __construct(MetadataFactoryInterface $metadataFactory)
- {
- $this->metadataFactory = $metadataFactory;
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessType($class, $property)
- {
- $guesser = $this;
-
- return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
- return $guesser->guessTypeForConstraint($constraint);
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessRequired($class, $property)
- {
- $guesser = $this;
-
- return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
- return $guesser->guessRequiredForConstraint($constraint);
- // If we don't find any constraint telling otherwise, we can assume
- // that a field is not required (with LOW_CONFIDENCE)
- }, false);
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessMaxLength($class, $property)
- {
- $guesser = $this;
-
- return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
- return $guesser->guessMaxLengthForConstraint($constraint);
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessPattern($class, $property)
- {
- $guesser = $this;
-
- return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
- return $guesser->guessPatternForConstraint($constraint);
- });
- }
-
- /**
- * Guesses a field class name for a given constraint
- *
- * @param Constraint $constraint The constraint to guess for
- *
- * @return TypeGuess The guessed field class and options
- */
- public function guessTypeForConstraint(Constraint $constraint)
- {
- switch (get_class($constraint)) {
- case 'Symfony\Component\Validator\Constraints\Type':
- switch ($constraint->type) {
- case 'array':
- return new TypeGuess('collection', array(), Guess::MEDIUM_CONFIDENCE);
- case 'boolean':
- case 'bool':
- return new TypeGuess('checkbox', array(), Guess::MEDIUM_CONFIDENCE);
-
- case 'double':
- case 'float':
- case 'numeric':
- case 'real':
- return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE);
-
- case 'integer':
- case 'int':
- case 'long':
- return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE);
-
- case '\DateTime':
- return new TypeGuess('date', array(), Guess::MEDIUM_CONFIDENCE);
-
- case 'string':
- return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
- }
- break;
-
- case 'Symfony\Component\Validator\Constraints\Country':
- return new TypeGuess('country', array(), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Date':
- return new TypeGuess('date', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\DateTime':
- return new TypeGuess('datetime', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Email':
- return new TypeGuess('email', array(), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\File':
- case 'Symfony\Component\Validator\Constraints\Image':
- return new TypeGuess('file', array(), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Language':
- return new TypeGuess('language', array(), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Locale':
- return new TypeGuess('locale', array(), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Time':
- return new TypeGuess('time', array('input' => 'string'), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Url':
- return new TypeGuess('url', array(), Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Ip':
- return new TypeGuess('text', array(), Guess::MEDIUM_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\MaxLength':
- case 'Symfony\Component\Validator\Constraints\MinLength':
- case 'Symfony\Component\Validator\Constraints\Regex':
- return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Min':
- case 'Symfony\Component\Validator\Constraints\Max':
- return new TypeGuess('number', array(), Guess::LOW_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\MinCount':
- case 'Symfony\Component\Validator\Constraints\MaxCount':
- return new TypeGuess('collection', array(), Guess::LOW_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\True':
- case 'Symfony\Component\Validator\Constraints\False':
- return new TypeGuess('checkbox', array(), Guess::MEDIUM_CONFIDENCE);
- }
-
- return null;
- }
-
- /**
- * Guesses whether a field is required based on the given constraint
- *
- * @param Constraint $constraint The constraint to guess for
- *
- * @return Guess The guess whether the field is required
- */
- public function guessRequiredForConstraint(Constraint $constraint)
- {
- switch (get_class($constraint)) {
- case 'Symfony\Component\Validator\Constraints\NotNull':
- case 'Symfony\Component\Validator\Constraints\NotBlank':
- case 'Symfony\Component\Validator\Constraints\True':
- return new ValueGuess(true, Guess::HIGH_CONFIDENCE);
- }
-
- return null;
- }
-
- /**
- * Guesses a field's maximum length based on the given constraint
- *
- * @param Constraint $constraint The constraint to guess for
- *
- * @return Guess The guess for the maximum length
- */
- public function guessMaxLengthForConstraint(Constraint $constraint)
- {
- switch (get_class($constraint)) {
- case 'Symfony\Component\Validator\Constraints\MaxLength':
- return new ValueGuess($constraint->limit, Guess::HIGH_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Type':
- if (in_array($constraint->type, array('double', 'float', 'numeric', 'real'))) {
- return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
- }
- break;
-
- case 'Symfony\Component\Validator\Constraints\Max':
- return new ValueGuess(strlen((string) $constraint->limit), Guess::LOW_CONFIDENCE);
- }
-
- return null;
- }
-
- /**
- * Guesses a field's pattern based on the given constraint
- *
- * @param Constraint $constraint The constraint to guess for
- *
- * @return Guess The guess for the pattern
- */
- public function guessPatternForConstraint(Constraint $constraint)
- {
- switch (get_class($constraint)) {
- case 'Symfony\Component\Validator\Constraints\MinLength':
- return new ValueGuess(sprintf('.{%s,}', (string) $constraint->limit), Guess::LOW_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Regex':
- $htmlPattern = $constraint->getHtmlPattern();
-
- if (null !== $htmlPattern) {
- return new ValueGuess($htmlPattern, Guess::HIGH_CONFIDENCE);
- }
- break;
-
- case 'Symfony\Component\Validator\Constraints\Min':
- return new ValueGuess(sprintf('.{%s,}', strlen((string) $constraint->limit)), Guess::LOW_CONFIDENCE);
-
- case 'Symfony\Component\Validator\Constraints\Type':
- if (in_array($constraint->type, array('double', 'float', 'numeric', 'real'))) {
- return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
- }
- break;
- }
-
- return null;
- }
-
- /**
- * Iterates over the constraints of a property, executes a constraints on
- * them and returns the best guess
- *
- * @param string $class The class to read the constraints from
- * @param string $property The property for which to find constraints
- * @param \Closure $closure The closure that returns a guess
- * for a given constraint
- * @param mixed $defaultValue The default value assumed if no other value
- * can be guessed.
- *
- * @return Guess The guessed value with the highest confidence
- */
- protected function guess($class, $property, \Closure $closure, $defaultValue = null)
- {
- $guesses = array();
- $classMetadata = $this->metadataFactory->getMetadataFor($class);
-
- if ($classMetadata->hasMemberMetadatas($property)) {
- $memberMetadatas = $classMetadata->getMemberMetadatas($property);
-
- foreach ($memberMetadatas as $memberMetadata) {
- $constraints = $memberMetadata->getConstraints();
-
- foreach ($constraints as $constraint) {
- if ($guess = $closure($constraint)) {
- $guesses[] = $guess;
- }
- }
- }
-
- if (null !== $defaultValue) {
- $guesses[] = new ValueGuess($defaultValue, Guess::LOW_CONFIDENCE);
- }
- }
-
- return Guess::getBestGuess($guesses);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Exception\ErrorMappingException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class MappingRule
-{
- /**
- * @var FormInterface
- */
- private $origin;
-
- /**
- * @var string
- */
- private $propertyPath;
-
- /**
- * @var string
- */
- private $targetPath;
-
- public function __construct(FormInterface $origin, $propertyPath, $targetPath)
- {
- $this->origin = $origin;
- $this->propertyPath = $propertyPath;
- $this->targetPath = $targetPath;
- }
-
- /**
- * @return FormInterface
- */
- public function getOrigin()
- {
- return $this->origin;
- }
-
- /**
- * Matches a property path against the rule path.
- *
- * If the rule matches, the form mapped by the rule is returned.
- * Otherwise this method returns false.
- *
- * @param string $propertyPath The property path to match against the rule.
- *
- * @return null|FormInterface The mapped form or null.
- */
- public function match($propertyPath)
- {
- if ($propertyPath === (string) $this->propertyPath) {
- return $this->getTarget();
- }
-
- return null;
- }
-
- /**
- * Matches a property path against a prefix of the rule path.
- *
- * @param string $propertyPath The property path to match against the rule.
- *
- * @return Boolean Whether the property path is a prefix of the rule or not.
- */
- public function isPrefix($propertyPath)
- {
- $length = strlen($propertyPath);
- $prefix = substr($this->propertyPath, 0, $length);
- $next = isset($this->propertyPath[$length]) ? $this->propertyPath[$length] : null;
-
- return $prefix === $propertyPath && ('[' === $next || '.' === $next);
- }
-
- /**
- * @return FormInterface
- *
- * @throws ErrorMappingException
- */
- public function getTarget()
- {
- $childNames = explode('.', $this->targetPath);
- $target = $this->origin;
-
- foreach ($childNames as $childName) {
- if (!$target->has($childName)) {
- throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName()));
- }
- $target = $target->get($childName);
- }
-
- return $target;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\PropertyAccess\PropertyPath;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RelativePath extends PropertyPath
-{
- /**
- * @var FormInterface
- */
- private $root;
-
- /**
- * @param FormInterface $root
- * @param string $propertyPath
- */
- public function __construct(FormInterface $root, $propertyPath)
- {
- parent::__construct($propertyPath);
-
- $this->root = $root;
- }
-
- /**
- * @return FormInterface
- */
- public function getRoot()
- {
- return $this->root;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Util\InheritDataAwareIterator;
-use Symfony\Component\PropertyAccess\PropertyPathIterator;
-use Symfony\Component\PropertyAccess\PropertyPathBuilder;
-use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface;
-use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationPathIterator;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Validator\ConstraintViolation;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ViolationMapper implements ViolationMapperInterface
-{
- /**
- * @var Boolean
- */
- private $allowNonSynchronized;
-
- /**
- * {@inheritdoc}
- */
- public function mapViolation(ConstraintViolation $violation, FormInterface $form, $allowNonSynchronized = false)
- {
- $this->allowNonSynchronized = $allowNonSynchronized;
-
- // The scope is the currently found most specific form that
- // an error should be mapped to. After setting the scope, the
- // mapper will try to continue to find more specific matches in
- // the children of scope. If it cannot, the error will be
- // mapped to this scope.
- $scope = null;
-
- $violationPath = null;
- $relativePath = null;
- $match = false;
-
- // Don't create a ViolationPath instance for empty property paths
- if (strlen($violation->getPropertyPath()) > 0) {
- $violationPath = new ViolationPath($violation->getPropertyPath());
- $relativePath = $this->reconstructPath($violationPath, $form);
- }
-
- // This case happens if the violation path is empty and thus
- // the violation should be mapped to the root form
- if (null === $violationPath) {
- $scope = $form;
- }
-
- // In general, mapping happens from the root form to the leaf forms
- // First, the rules of the root form are applied to determine
- // the subsequent descendant. The rules of this descendant are then
- // applied to find the next and so on, until we have found the
- // most specific form that matches the violation.
-
- // If any of the forms found in this process is not synchronized,
- // mapping is aborted. Non-synchronized forms could not reverse
- // transform the value entered by the user, thus any further violations
- // caused by the (invalid) reverse transformed value should be
- // ignored.
-
- if (null !== $relativePath) {
- // Set the scope to the root of the relative path
- // This root will usually be $form. If the path contains
- // an unmapped form though, the last unmapped form found
- // will be the root of the path.
- $scope = $relativePath->getRoot();
- $it = new PropertyPathIterator($relativePath);
-
- while ($this->acceptsErrors($scope) && null !== ($child = $this->matchChild($scope, $it))) {
- $scope = $child;
- $it->next();
- $match = true;
- }
- }
-
- // This case happens if an error happened in the data under a
- // form inheriting its parent data that does not match any of the
- // children of that form.
- if (null !== $violationPath && !$match) {
- // If we could not map the error to anything more specific
- // than the root element, map it to the innermost directly
- // mapped form of the violation path
- // e.g. "children[foo].children[bar].data.baz"
- // Here the innermost directly mapped child is "bar"
-
- $scope = $form;
- $it = new ViolationPathIterator($violationPath);
-
- // Note: acceptsErrors() will always return true for forms inheriting
- // their parent data, because these forms can never be non-synchronized
- // (they don't do any data transformation on their own)
- while ($this->acceptsErrors($scope) && $it->valid() && $it->mapsForm()) {
- if (!$scope->has($it->current())) {
- // Break if we find a reference to a non-existing child
- break;
- }
-
- $scope = $scope->get($it->current());
- $it->next();
- }
- }
-
- // Follow dot rules until we have the final target
- $mapping = $scope->getConfig()->getOption('error_mapping');
-
- while ($this->acceptsErrors($scope) && isset($mapping['.'])) {
- $dotRule = new MappingRule($scope, '.', $mapping['.']);
- $scope = $dotRule->getTarget();
- $mapping = $scope->getConfig()->getOption('error_mapping');
- }
-
- // Only add the error if the form is synchronized
- if ($this->acceptsErrors($scope)) {
- $scope->addError(new FormError(
- $violation->getMessage(),
- $violation->getMessageTemplate(),
- $violation->getMessageParameters(),
- $violation->getMessagePluralization()
- ));
- }
- }
-
- /**
- * Tries to match the beginning of the property path at the
- * current position against the children of the scope.
- *
- * If a matching child is found, it is returned. Otherwise
- * null is returned.
- *
- * @param FormInterface $form The form to search.
- * @param PropertyPathIteratorInterface $it The iterator at its current position.
- *
- * @return null|FormInterface The found match or null.
- */
- private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it)
- {
- // Remember at what property path underneath "data"
- // we are looking. Check if there is a child with that
- // path, otherwise increase path by one more piece
- $chunk = '';
- $foundChild = null;
- $foundAtIndex = 0;
-
- // Construct mapping rules for the given form
- $rules = array();
-
- foreach ($form->getConfig()->getOption('error_mapping') as $propertyPath => $targetPath) {
- // Dot rules are considered at the very end
- if ('.' !== $propertyPath) {
- $rules[] = new MappingRule($form, $propertyPath, $targetPath);
- }
- }
-
- // Skip forms inheriting their parent data when iterating the children
- $childIterator = new \RecursiveIteratorIterator(
- new InheritDataAwareIterator($form->all())
- );
-
- // Make the path longer until we find a matching child
- while (true) {
- if (!$it->valid()) {
- return null;
- }
-
- if ($it->isIndex()) {
- $chunk .= '['.$it->current().']';
- } else {
- $chunk .= ('' === $chunk ? '' : '.').$it->current();
- }
-
- // Test mapping rules as long as we have any
- foreach ($rules as $key => $rule) {
- /* @var MappingRule $rule */
-
- // Mapping rule matches completely, terminate.
- if (null !== ($form = $rule->match($chunk))) {
- return $form;
- }
-
- // Keep only rules that have $chunk as prefix
- if (!$rule->isPrefix($chunk)) {
- unset($rules[$key]);
- }
- }
-
- // Test children unless we already found one
- if (null === $foundChild) {
- foreach ($childIterator as $child) {
- /* @var FormInterface $child */
- $childPath = (string) $child->getPropertyPath();
-
- // Child found, mark as return value
- if ($chunk === $childPath) {
- $foundChild = $child;
- $foundAtIndex = $it->key();
- }
- }
- }
-
- // Add element to the chunk
- $it->next();
-
- // If we reached the end of the path or if there are no
- // more matching mapping rules, return the found child
- if (null !== $foundChild && (!$it->valid() || count($rules) === 0)) {
- // Reset index in case we tried to find mapping
- // rules further down the path
- $it->seek($foundAtIndex);
-
- return $foundChild;
- }
- }
-
- return null;
- }
-
- /**
- * Reconstructs a property path from a violation path and a form tree.
- *
- * @param ViolationPath $violationPath The violation path.
- * @param FormInterface $origin The root form of the tree.
- *
- * @return RelativePath The reconstructed path.
- */
- private function reconstructPath(ViolationPath $violationPath, FormInterface $origin)
- {
- $propertyPathBuilder = new PropertyPathBuilder($violationPath);
- $it = $violationPath->getIterator();
- $scope = $origin;
-
- // Remember the current index in the builder
- $i = 0;
-
- // Expand elements that map to a form (like "children[address]")
- for ($it->rewind(); $it->valid() && $it->mapsForm(); $it->next()) {
- if (!$scope->has($it->current())) {
- // Scope relates to a form that does not exist
- // Bail out
- break;
- }
-
- // Process child form
- $scope = $scope->get($it->current());
-
- if ($scope->getConfig()->getInheritData()) {
- // Form inherits its parent data
- // Cut the piece out of the property path and proceed
- $propertyPathBuilder->remove($i);
- } elseif (!$scope->getConfig()->getMapped()) {
- // Form is not mapped
- // Set the form as new origin and strip everything
- // we have so far in the path
- $origin = $scope;
- $propertyPathBuilder->remove(0, $i + 1);
- $i = 0;
- } else {
- /* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */
- $propertyPath = $scope->getPropertyPath();
-
- if (null === $propertyPath) {
- // Property path of a mapped form is null
- // Should not happen, bail out
- break;
- }
-
- $propertyPathBuilder->replace($i, 1, $propertyPath);
- $i += $propertyPath->getLength();
- }
- }
-
- $finalPath = $propertyPathBuilder->getPropertyPath();
-
- return null !== $finalPath ? new RelativePath($origin, $finalPath) : null;
- }
-
- /**
- * @param FormInterface $form
- *
- * @return Boolean
- */
- private function acceptsErrors(FormInterface $form)
- {
- return $this->allowNonSynchronized || $form->isSynchronized();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Validator\ConstraintViolation;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ViolationMapperInterface
-{
- /**
- * Maps a constraint violation to a form in the form tree under
- * the given form.
- *
- * @param ConstraintViolation $violation The violation to map.
- * @param FormInterface $form The root form of the tree
- * to map it to.
- * @param Boolean $allowNonSynchronized Whether to allow
- * mapping to non-synchronized forms.
- */
- public function mapViolation(ConstraintViolation $violation, FormInterface $form, $allowNonSynchronized = false);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\Form\Exception\OutOfBoundsException;
-use Symfony\Component\PropertyAccess\PropertyPath;
-use Symfony\Component\PropertyAccess\PropertyPathInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ViolationPath implements \IteratorAggregate, PropertyPathInterface
-{
- /**
- * @var array
- */
- private $elements = array();
-
- /**
- * @var array
- */
- private $isIndex = array();
-
- /**
- * @var array
- */
- private $mapsForm = array();
-
- /**
- * @var string
- */
- private $pathAsString = '';
-
- /**
- * @var integer
- */
- private $length = 0;
-
- /**
- * Creates a new violation path from a string.
- *
- * @param string $violationPath The property path of a {@link ConstraintViolation}
- * object.
- */
- public function __construct($violationPath)
- {
- $path = new PropertyPath($violationPath);
- $elements = $path->getElements();
- $data = false;
-
- for ($i = 0, $l = count($elements); $i < $l; ++$i) {
- if (!$data) {
- // The element "data" has not yet been passed
- if ('children' === $elements[$i] && $path->isProperty($i)) {
- // Skip element "children"
- ++$i;
-
- // Next element must exist and must be an index
- // Otherwise consider this the end of the path
- if ($i >= $l || !$path->isIndex($i)) {
- break;
- }
-
- $this->elements[] = $elements[$i];
- $this->isIndex[] = true;
- $this->mapsForm[] = true;
- } elseif ('data' === $elements[$i] && $path->isProperty($i)) {
- // Skip element "data"
- ++$i;
-
- // End of path
- if ($i >= $l) {
- break;
- }
-
- $this->elements[] = $elements[$i];
- $this->isIndex[] = $path->isIndex($i);
- $this->mapsForm[] = false;
- $data = true;
- } else {
- // Neither "children" nor "data" property found
- // Consider this the end of the path
- break;
- }
- } else {
- // Already after the "data" element
- // Pick everything as is
- $this->elements[] = $elements[$i];
- $this->isIndex[] = $path->isIndex($i);
- $this->mapsForm[] = false;
- }
- }
-
- $this->length = count($this->elements);
-
- $this->buildString();
- }
-
- /**
- * {@inheritdoc}
- */
- public function __toString()
- {
- return $this->pathAsString;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLength()
- {
- return $this->length;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- if ($this->length <= 1) {
- return null;
- }
-
- $parent = clone $this;
-
- --$parent->length;
- array_pop($parent->elements);
- array_pop($parent->isIndex);
- array_pop($parent->mapsForm);
-
- $parent->buildString();
-
- return $parent;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getElements()
- {
- return $this->elements;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getElement($index)
- {
- if (!isset($this->elements[$index])) {
- throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
- }
-
- return $this->elements[$index];
- }
-
- /**
- * {@inheritdoc}
- */
- public function isProperty($index)
- {
- if (!isset($this->isIndex[$index])) {
- throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
- }
-
- return !$this->isIndex[$index];
- }
-
- /**
- * {@inheritdoc}
- */
- public function isIndex($index)
- {
- if (!isset($this->isIndex[$index])) {
- throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
- }
-
- return $this->isIndex[$index];
- }
-
- /**
- * Returns whether an element maps directly to a form.
- *
- * Consider the following violation path:
- *
- * <code>
- * children[address].children[office].data.street
- * </code>
- *
- * In this example, "address" and "office" map to forms, while
- * "street does not.
- *
- * @param integer $index The element index.
- *
- * @return Boolean Whether the element maps to a form.
- *
- * @throws OutOfBoundsException If the offset is invalid.
- */
- public function mapsForm($index)
- {
- if (!isset($this->mapsForm[$index])) {
- throw new OutOfBoundsException(sprintf('The index %s is not within the violation path', $index));
- }
-
- return $this->mapsForm[$index];
- }
-
- /**
- * Returns a new iterator for this path
- *
- * @return ViolationPathIterator
- */
- public function getIterator()
- {
- return new ViolationPathIterator($this);
- }
-
- /**
- * Builds the string representation from the elements.
- */
- private function buildString()
- {
- $this->pathAsString = '';
- $data = false;
-
- foreach ($this->elements as $index => $element) {
- if ($this->mapsForm[$index]) {
- $this->pathAsString .= ".children[$element]";
- } elseif (!$data) {
- $this->pathAsString .= '.data'.($this->isIndex[$index] ? "[$element]" : ".$element");
- $data = true;
- } else {
- $this->pathAsString .= $this->isIndex[$index] ? "[$element]" : ".$element";
- }
- }
-
- if ('' !== $this->pathAsString) {
- // remove leading dot
- $this->pathAsString = substr($this->pathAsString, 1);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\PropertyAccess\PropertyPathIterator;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ViolationPathIterator extends PropertyPathIterator
-{
- public function __construct(ViolationPath $violationPath)
- {
- parent::__construct($violationPath);
- }
-
- public function mapsForm()
- {
- return $this->path->mapsForm($this->key());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\RuntimeException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\Form\Exception\AlreadySubmittedException;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\Exception\LogicException;
-use Symfony\Component\Form\Exception\OutOfBoundsException;
-use Symfony\Component\Form\Util\FormUtil;
-use Symfony\Component\Form\Util\InheritDataAwareIterator;
-use Symfony\Component\PropertyAccess\PropertyPath;
-
-/**
- * Form represents a form.
- *
- * To implement your own form fields, you need to have a thorough understanding
- * of the data flow within a form. A form stores its data in three different
- * representations:
- *
- * (1) the "model" format required by the form's object
- * (2) the "normalized" format for internal processing
- * (3) the "view" format used for display
- *
- * A date field, for example, may store a date as "Y-m-d" string (1) in the
- * object. To facilitate processing in the field, this value is normalized
- * to a DateTime object (2). In the HTML representation of your form, a
- * localized string (3) is presented to and modified by the user.
- *
- * In most cases, format (1) and format (2) will be the same. For example,
- * a checkbox field uses a Boolean value for both internal processing and
- * storage in the object. In these cases you simply need to set a value
- * transformer to convert between formats (2) and (3). You can do this by
- * calling addViewTransformer().
- *
- * In some cases though it makes sense to make format (1) configurable. To
- * demonstrate this, let's extend our above date field to store the value
- * either as "Y-m-d" string or as timestamp. Internally we still want to
- * use a DateTime object for processing. To convert the data from string/integer
- * to DateTime you can set a normalization transformer by calling
- * addNormTransformer(). The normalized data is then converted to the displayed
- * data as described before.
- *
- * The conversions (1) -> (2) -> (3) use the transform methods of the transformers.
- * The conversions (3) -> (2) -> (1) use the reverseTransform methods of the transformers.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Form implements \IteratorAggregate, FormInterface
-{
- /**
- * The form's configuration
- * @var FormConfigInterface
- */
- private $config;
-
- /**
- * The parent of this form
- * @var FormInterface
- */
- private $parent;
-
- /**
- * The children of this form
- * @var FormInterface[] An array of FormInterface instances
- */
- private $children = array();
-
- /**
- * The errors of this form
- * @var FormError[] An array of FormError instances
- */
- private $errors = array();
-
- /**
- * Whether this form was submitted
- * @var Boolean
- */
- private $submitted = false;
-
- /**
- * The form data in model format
- * @var mixed
- */
- private $modelData;
-
- /**
- * The form data in normalized format
- * @var mixed
- */
- private $normData;
-
- /**
- * The form data in view format
- * @var mixed
- */
- private $viewData;
-
- /**
- * The submitted values that don't belong to any children
- * @var array
- */
- private $extraData = array();
-
- /**
- * Whether the data in model, normalized and view format is
- * synchronized. Data may not be synchronized if transformation errors
- * occur.
- * @var Boolean
- */
- private $synchronized = true;
-
- /**
- * Whether the form's data has been initialized.
- *
- * When the data is initialized with its default value, that default value
- * is passed through the transformer chain in order to synchronize the
- * model, normalized and view format for the first time. This is done
- * lazily in order to save performance when {@link setData()} is called
- * manually, making the initialization with the configured default value
- * superfluous.
- *
- * @var Boolean
- */
- private $defaultDataSet = false;
-
- /**
- * Whether setData() is currently being called.
- * @var Boolean
- */
- private $lockSetData = false;
-
- /**
- * Creates a new form based on the given configuration.
- *
- * @param FormConfigInterface $config The form configuration.
- *
- * @throws LogicException if a data mapper is not provided for a compound form
- */
- public function __construct(FormConfigInterface $config)
- {
- // Compound forms always need a data mapper, otherwise calls to
- // `setData` and `add` will not lead to the correct population of
- // the child forms.
- if ($config->getCompound() && !$config->getDataMapper()) {
- throw new LogicException('Compound forms need a data mapper');
- }
-
- // If the form inherits the data from its parent, it is not necessary
- // to call setData() with the default data.
- if ($config->getInheritData()) {
- $this->defaultDataSet = true;
- }
-
- $this->config = $config;
- }
-
- public function __clone()
- {
- foreach ($this->children as $key => $child) {
- $this->children[$key] = clone $child;
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function getConfig()
- {
- return $this->config;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return $this->config->getName();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPropertyPath()
- {
- if (null !== $this->config->getPropertyPath()) {
- return $this->config->getPropertyPath();
- }
-
- if (null === $this->getName() || '' === $this->getName()) {
- return null;
- }
-
- $parent = $this->parent;
-
- while ($parent && $parent->getConfig()->getInheritData()) {
- $parent = $parent->getParent();
- }
-
- if ($parent && null === $parent->getConfig()->getDataClass()) {
- return new PropertyPath('['.$this->getName().']');
- }
-
- return new PropertyPath($this->getName());
- }
-
- /**
- * {@inheritdoc}
- */
- public function isRequired()
- {
- if (null === $this->parent || $this->parent->isRequired()) {
- return $this->config->getRequired();
- }
-
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public function isDisabled()
- {
- if (null === $this->parent || !$this->parent->isDisabled()) {
- return $this->config->getDisabled();
- }
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setParent(FormInterface $parent = null)
- {
- if ($this->submitted) {
- throw new AlreadySubmittedException('You cannot set the parent of a submitted form');
- }
-
- if (null !== $parent && '' === $this->config->getName()) {
- throw new LogicException('A form with an empty name cannot have a parent form.');
- }
-
- $this->parent = $parent;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return $this->parent;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRoot()
- {
- return $this->parent ? $this->parent->getRoot() : $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isRoot()
- {
- return null === $this->parent;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setData($modelData)
- {
- // If the form is submitted while disabled, it is set to submitted, but the data is not
- // changed. In such cases (i.e. when the form is not initialized yet) don't
- // abort this method.
- if ($this->submitted && $this->defaultDataSet) {
- throw new AlreadySubmittedException('You cannot change the data of a submitted form.');
- }
-
- // If the form inherits its parent's data, disallow data setting to
- // prevent merge conflicts
- if ($this->config->getInheritData()) {
- throw new RuntimeException('You cannot change the data of a form inheriting its parent data.');
- }
-
- // Don't allow modifications of the configured data if the data is locked
- if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) {
- return $this;
- }
-
- if (is_object($modelData) && !$this->config->getByReference()) {
- $modelData = clone $modelData;
- }
-
- if ($this->lockSetData) {
- throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead.');
- }
-
- $this->lockSetData = true;
- $dispatcher = $this->config->getEventDispatcher();
-
- // Hook to change content of the data
- if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA)) {
- $event = new FormEvent($this, $modelData);
- $dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event);
- $modelData = $event->getData();
- }
-
- // Treat data as strings unless a value transformer exists
- if (!$this->config->getViewTransformers() && !$this->config->getModelTransformers() && is_scalar($modelData)) {
- $modelData = (string) $modelData;
- }
-
- // Synchronize representations - must not change the content!
- $normData = $this->modelToNorm($modelData);
- $viewData = $this->normToView($normData);
-
- // Validate if view data matches data class (unless empty)
- if (!FormUtil::isEmpty($viewData)) {
- $dataClass = $this->config->getDataClass();
-
- $actualType = is_object($viewData) ? 'an instance of class '.get_class($viewData) : ' a(n) '.gettype($viewData);
-
- if (null === $dataClass && is_object($viewData) && !$viewData instanceof \ArrayAccess) {
- $expectedType = 'scalar, array or an instance of \ArrayAccess';
-
- throw new LogicException(
- 'The form\'s view data is expected to be of type '.$expectedType.', ' .
- 'but is '.$actualType.'. You ' .
- 'can avoid this error by setting the "data_class" option to ' .
- '"'.get_class($viewData).'" or by adding a view transformer ' .
- 'that transforms '.$actualType.' to '.$expectedType.'.'
- );
- }
-
- if (null !== $dataClass && !$viewData instanceof $dataClass) {
- throw new LogicException(
- 'The form\'s view data is expected to be an instance of class ' .
- $dataClass.', but is '. $actualType.'. You can avoid this error ' .
- 'by setting the "data_class" option to null or by adding a view ' .
- 'transformer that transforms '.$actualType.' to an instance of ' .
- $dataClass.'.'
- );
- }
- }
-
- $this->modelData = $modelData;
- $this->normData = $normData;
- $this->viewData = $viewData;
- $this->defaultDataSet = true;
- $this->lockSetData = false;
-
- // It is not necessary to invoke this method if the form doesn't have children,
- // even if the form is compound.
- if (count($this->children) > 0) {
- // Update child forms from the data
- $childrenIterator = new InheritDataAwareIterator($this->children);
- $childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
- $this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);
- }
-
- if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) {
- $event = new FormEvent($this, $modelData);
- $dispatcher->dispatch(FormEvents::POST_SET_DATA, $event);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getData()
- {
- if ($this->config->getInheritData()) {
- if (!$this->parent) {
- throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
- }
-
- return $this->parent->getData();
- }
-
- if (!$this->defaultDataSet) {
- $this->setData($this->config->getData());
- }
-
- return $this->modelData;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getNormData()
- {
- if ($this->config->getInheritData()) {
- if (!$this->parent) {
- throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
- }
-
- return $this->parent->getNormData();
- }
-
- if (!$this->defaultDataSet) {
- $this->setData($this->config->getData());
- }
-
- return $this->normData;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getViewData()
- {
- if ($this->config->getInheritData()) {
- if (!$this->parent) {
- throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
- }
-
- return $this->parent->getViewData();
- }
-
- if (!$this->defaultDataSet) {
- $this->setData($this->config->getData());
- }
-
- return $this->viewData;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getExtraData()
- {
- return $this->extraData;
- }
-
- /**
- * {@inheritdoc}
- */
- public function initialize()
- {
- if (null !== $this->parent) {
- throw new RuntimeException('Only root forms should be initialized.');
- }
-
- // Guarantee that the *_SET_DATA events have been triggered once the
- // form is initialized. This makes sure that dynamically added or
- // removed fields are already visible after initialization.
- if (!$this->defaultDataSet) {
- $this->setData($this->config->getData());
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function handleRequest($request = null)
- {
- $this->config->getRequestHandler()->handleRequest($this, $request);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function submit($submittedData, $clearMissing = true)
- {
- if ($this->submitted) {
- throw new AlreadySubmittedException('A form can only be submitted once');
- }
-
- // Initialize errors in the very beginning so that we don't lose any
- // errors added during listeners
- $this->errors = array();
-
- // Obviously, a disabled form should not change its data upon submission.
- if ($this->isDisabled()) {
- $this->submitted = true;
-
- return $this;
- }
-
- // The data must be initialized if it was not initialized yet.
- // This is necessary to guarantee that the *_SET_DATA listeners
- // are always invoked before submit() takes place.
- if (!$this->defaultDataSet) {
- $this->setData($this->config->getData());
- }
-
- // Treat false as NULL to support binding false to checkboxes.
- // Don't convert NULL to a string here in order to determine later
- // whether an empty value has been submitted or whether no value has
- // been submitted at all. This is important for processing checkboxes
- // and radio buttons with empty values.
- if (false === $submittedData) {
- $submittedData = null;
- } elseif (is_scalar($submittedData)) {
- $submittedData = (string) $submittedData;
- }
-
- $dispatcher = $this->config->getEventDispatcher();
-
- // Hook to change content of the data submitted by the browser
- if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
- $event = new FormEvent($this, $submittedData);
- $dispatcher->dispatch(FormEvents::PRE_SUBMIT, $event);
- $submittedData = $event->getData();
- }
-
- // Check whether the form is compound.
- // This check is preferable over checking the number of children,
- // since forms without children may also be compound.
- // (think of empty collection forms)
- if ($this->config->getCompound()) {
- if (!is_array($submittedData)) {
- $submittedData = array();
- }
-
- foreach ($this->children as $name => $child) {
- if (isset($submittedData[$name]) || $clearMissing) {
- $child->submit(isset($submittedData[$name]) ? $submittedData[$name] : null, $clearMissing);
- unset($submittedData[$name]);
- }
- }
-
- $this->extraData = $submittedData;
- }
-
- // Forms that inherit their parents' data also are not processed,
- // because then it would be too difficult to merge the changes in
- // the child and the parent form. Instead, the parent form also takes
- // changes in the grandchildren (i.e. children of the form that inherits
- // its parent's data) into account.
- // (see InheritDataAwareIterator below)
- if ($this->config->getInheritData()) {
- $this->submitted = true;
-
- // When POST_SUBMIT is reached, the data is not yet updated, so pass
- // NULL to prevent hard-to-debug bugs.
- $dataForPostSubmit = null;
- } else {
- // If the form is compound, the default data in view format
- // is reused. The data of the children is merged into this
- // default data using the data mapper.
- // If the form is not compound, the submitted data is also the data in view format.
- $viewData = $this->config->getCompound() ? $this->viewData : $submittedData;
-
- if (FormUtil::isEmpty($viewData)) {
- $emptyData = $this->config->getEmptyData();
-
- if ($emptyData instanceof \Closure) {
- /* @var \Closure $emptyData */
- $emptyData = $emptyData($this, $viewData);
- }
-
- $viewData = $emptyData;
- }
-
- // Merge form data from children into existing view data
- // It is not necessary to invoke this method if the form has no children,
- // even if it is compound.
- if (count($this->children) > 0) {
- // Use InheritDataAwareIterator to process children of
- // descendants that inherit this form's data.
- // These descendants will not be submitted normally (see the check
- // for $this->config->getInheritData() above)
- $childrenIterator = new InheritDataAwareIterator($this->children);
- $childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
- $this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData);
- }
-
- $modelData = null;
- $normData = null;
-
- try {
- // Normalize data to unified representation
- $normData = $this->viewToNorm($viewData);
-
- // Hook to change content of the data into the normalized
- // representation
- if ($dispatcher->hasListeners(FormEvents::SUBMIT)) {
- $event = new FormEvent($this, $normData);
- $dispatcher->dispatch(FormEvents::SUBMIT, $event);
- $normData = $event->getData();
- }
-
- // Synchronize representations - must not change the content!
- $modelData = $this->normToModel($normData);
- $viewData = $this->normToView($normData);
- } catch (TransformationFailedException $e) {
- $this->synchronized = false;
- }
-
- $this->submitted = true;
- $this->modelData = $modelData;
- $this->normData = $normData;
- $this->viewData = $viewData;
-
- $dataForPostSubmit = $viewData;
- }
-
- if ($dispatcher->hasListeners(FormEvents::POST_SUBMIT)) {
- $event = new FormEvent($this, $dataForPostSubmit);
- $dispatcher->dispatch(FormEvents::POST_SUBMIT, $event);
- }
-
- return $this;
- }
-
- /**
- * Alias of {@link submit()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link submit()} instead.
- */
- public function bind($submittedData)
- {
- return $this->submit($submittedData);
- }
-
- /**
- * {@inheritdoc}
- */
- public function addError(FormError $error)
- {
- if ($this->parent && $this->config->getErrorBubbling()) {
- $this->parent->addError($error);
- } else {
- $this->errors[] = $error;
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isSubmitted()
- {
- return $this->submitted;
- }
-
- /**
- * Alias of {@link isSubmitted()}.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link isSubmitted()} instead.
- */
- public function isBound()
- {
- return $this->submitted;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isSynchronized()
- {
- return $this->synchronized;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isEmpty()
- {
- foreach ($this->children as $child) {
- if (!$child->isEmpty()) {
- return false;
- }
- }
-
- return FormUtil::isEmpty($this->modelData) ||
- // arrays, countables
- 0 === count($this->modelData) ||
- // traversables that are not countable
- ($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData));
- }
-
- /**
- * {@inheritdoc}
- */
- public function isValid()
- {
- if (!$this->submitted) {
- return false;
- }
-
- if (count($this->errors) > 0) {
- return false;
- }
-
- if (!$this->isDisabled()) {
- foreach ($this->children as $child) {
- if (!$child->isValid()) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getErrors()
- {
- return $this->errors;
- }
-
- /**
- * Returns a string representation of all form errors (including children errors).
- *
- * This method should only be used to help debug a form.
- *
- * @param integer $level The indentation level (used internally)
- *
- * @return string A string representation of all errors
- */
- public function getErrorsAsString($level = 0)
- {
- $errors = '';
- foreach ($this->errors as $error) {
- $errors .= str_repeat(' ', $level).'ERROR: '.$error->getMessage()."\n";
- }
-
- foreach ($this->children as $key => $child) {
- $errors .= str_repeat(' ', $level).$key.":\n";
- if ($err = $child->getErrorsAsString($level + 4)) {
- $errors .= $err;
- } else {
- $errors .= str_repeat(' ', $level + 4)."No errors\n";
- }
- }
-
- return $errors;
- }
-
- /**
- * {@inheritdoc}
- */
- public function all()
- {
- return $this->children;
- }
-
- /**
- * {@inheritdoc}
- */
- public function add($child, $type = null, array $options = array())
- {
- if ($this->submitted) {
- throw new AlreadySubmittedException('You cannot add children to a submitted form');
- }
-
- if (!$this->config->getCompound()) {
- throw new LogicException('You cannot add children to a simple form. Maybe you should set the option "compound" to true?');
- }
-
- // Obtain the view data
- $viewData = null;
-
- // If setData() is currently being called, there is no need to call
- // mapDataToForms() here, as mapDataToForms() is called at the end
- // of setData() anyway. Not doing this check leads to an endless
- // recursion when initializing the form lazily and an event listener
- // (such as ResizeFormListener) adds fields depending on the data:
- //
- // * setData() is called, the form is not initialized yet
- // * add() is called by the listener (setData() is not complete, so
- // the form is still not initialized)
- // * getViewData() is called
- // * setData() is called since the form is not initialized yet
- // * ... endless recursion ...
- //
- // Also skip data mapping if setData() has not been called yet.
- // setData() will be called upon form initialization and data mapping
- // will take place by then.
- if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
- $viewData = $this->getViewData();
- }
-
- if (!$child instanceof FormInterface) {
- if (!is_string($child) && !is_int($child)) {
- throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormInterface');
- }
-
- if (null !== $type && !is_string($type) && !$type instanceof FormTypeInterface) {
- throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
- }
-
- // Never initialize child forms automatically
- $options['auto_initialize'] = false;
-
- if (null === $type) {
- $child = $this->config->getFormFactory()->createForProperty($this->config->getDataClass(), $child, null, $options);
- } else {
- $child = $this->config->getFormFactory()->createNamed($child, $type, null, $options);
- }
- } elseif ($child->getConfig()->getAutoInitialize()) {
- throw new RuntimeException(sprintf(
- 'Automatic initialization is only supported on root forms. You '.
- 'should set the "auto_initialize" option to false on the field "%s".',
- $child->getName()
- ));
- }
-
- $this->children[$child->getName()] = $child;
-
- $child->setParent($this);
-
- if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
- $childrenIterator = new InheritDataAwareIterator(array($child));
- $childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
- $this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function remove($name)
- {
- if ($this->submitted) {
- throw new AlreadySubmittedException('You cannot remove children from a submitted form');
- }
-
- if (isset($this->children[$name])) {
- $this->children[$name]->setParent(null);
-
- unset($this->children[$name]);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function has($name)
- {
- return isset($this->children[$name]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function get($name)
- {
- if (isset($this->children[$name])) {
- return $this->children[$name];
- }
-
- throw new OutOfBoundsException(sprintf('Child "%s" does not exist.', $name));
- }
-
- /**
- * Returns whether a child with the given name exists (implements the \ArrayAccess interface).
- *
- * @param string $name The name of the child
- *
- * @return Boolean
- */
- public function offsetExists($name)
- {
- return $this->has($name);
- }
-
- /**
- * Returns the child with the given name (implements the \ArrayAccess interface).
- *
- * @param string $name The name of the child
- *
- * @return FormInterface The child form
- *
- * @throws \OutOfBoundsException If the named child does not exist.
- */
- public function offsetGet($name)
- {
- return $this->get($name);
- }
-
- /**
- * Adds a child to the form (implements the \ArrayAccess interface).
- *
- * @param string $name Ignored. The name of the child is used.
- * @param FormInterface $child The child to be added.
- *
- * @throws AlreadySubmittedException If the form has already been submitted.
- * @throws LogicException When trying to add a child to a non-compound form.
- *
- * @see self::add()
- */
- public function offsetSet($name, $child)
- {
- $this->add($child);
- }
-
- /**
- * Removes the child with the given name from the form (implements the \ArrayAccess interface).
- *
- * @param string $name The name of the child to remove
- *
- * @throws AlreadySubmittedException If the form has already been submitted.
- */
- public function offsetUnset($name)
- {
- $this->remove($name);
- }
-
- /**
- * Returns the iterator for this group.
- *
- * @return \ArrayIterator
- */
- public function getIterator()
- {
- return new \ArrayIterator($this->children);
- }
-
- /**
- * Returns the number of form children (implements the \Countable interface).
- *
- * @return integer The number of embedded form children
- */
- public function count()
- {
- return count($this->children);
- }
-
- /**
- * {@inheritdoc}
- */
- public function createView(FormView $parent = null)
- {
- if (null === $parent && $this->parent) {
- $parent = $this->parent->createView();
- }
-
- return $this->config->getType()->createView($this, $parent);
- }
-
- /**
- * Normalizes the value if a normalization transformer is set.
- *
- * @param mixed $value The value to transform
- *
- * @return mixed
- */
- private function modelToNorm($value)
- {
- foreach ($this->config->getModelTransformers() as $transformer) {
- $value = $transformer->transform($value);
- }
-
- return $value;
- }
-
- /**
- * Reverse transforms a value if a normalization transformer is set.
- *
- * @param string $value The value to reverse transform
- *
- * @return mixed
- */
- private function normToModel($value)
- {
- $transformers = $this->config->getModelTransformers();
-
- for ($i = count($transformers) - 1; $i >= 0; --$i) {
- $value = $transformers[$i]->reverseTransform($value);
- }
-
- return $value;
- }
-
- /**
- * Transforms the value if a value transformer is set.
- *
- * @param mixed $value The value to transform
- *
- * @return mixed
- */
- private function normToView($value)
- {
- // Scalar values should be converted to strings to
- // facilitate differentiation between empty ("") and zero (0).
- // Only do this for simple forms, as the resulting value in
- // compound forms is passed to the data mapper and thus should
- // not be converted to a string before.
- if (!$this->config->getViewTransformers() && !$this->config->getCompound()) {
- return null === $value || is_scalar($value) ? (string) $value : $value;
- }
-
- foreach ($this->config->getViewTransformers() as $transformer) {
- $value = $transformer->transform($value);
- }
-
- return $value;
- }
-
- /**
- * Reverse transforms a value if a value transformer is set.
- *
- * @param string $value The value to reverse transform
- *
- * @return mixed
- */
- private function viewToNorm($value)
- {
- $transformers = $this->config->getViewTransformers();
-
- if (!$transformers) {
- return '' === $value ? null : $value;
- }
-
- for ($i = count($transformers) - 1; $i >= 0; --$i) {
- $value = $transformers[$i]->reverseTransform($value);
- }
-
- return $value;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\BadMethodCallException;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-
-/**
- * A builder for creating {@link Form} instances.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormBuilderInterface
-{
- /**
- * The children of the form builder.
- *
- * @var FormBuilderInterface[]
- */
- private $children = array();
-
- /**
- * The data of children who haven't been converted to form builders yet.
- *
- * @var array
- */
- private $unresolvedChildren = array();
-
- /**
- * Creates a new form builder.
- *
- * @param string $name
- * @param string $dataClass
- * @param EventDispatcherInterface $dispatcher
- * @param FormFactoryInterface $factory
- * @param array $options
- */
- public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = array())
- {
- parent::__construct($name, $dataClass, $dispatcher, $options);
-
- $this->setFormFactory($factory);
- }
-
- /**
- * {@inheritdoc}
- */
- public function add($child, $type = null, array $options = array())
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- if ($child instanceof self) {
- $this->children[$child->getName()] = $child;
-
- // In case an unresolved child with the same name exists
- unset($this->unresolvedChildren[$child->getName()]);
-
- return $this;
- }
-
- if (!is_string($child) && !is_int($child)) {
- throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormBuilder');
- }
-
- if (null !== $type && !is_string($type) && !$type instanceof FormTypeInterface) {
- throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
- }
-
- // Add to "children" to maintain order
- $this->children[$child] = null;
- $this->unresolvedChildren[$child] = array(
- 'type' => $type,
- 'options' => $options,
- );
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function create($name, $type = null, array $options = array())
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- if (null === $type && null === $this->getDataClass()) {
- $type = 'text';
- }
-
- if (null !== $type) {
- return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options);
- }
-
- return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function get($name)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- if (isset($this->unresolvedChildren[$name])) {
- return $this->resolveChild($name);
- }
-
- if (isset($this->children[$name])) {
- return $this->children[$name];
- }
-
- throw new InvalidArgumentException(sprintf('The child with the name "%s" does not exist.', $name));
- }
-
- /**
- * {@inheritdoc}
- */
- public function remove($name)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- unset($this->unresolvedChildren[$name]);
-
- if (array_key_exists($name, $this->children)) {
- unset($this->children[$name]);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function has($name)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- if (isset($this->unresolvedChildren[$name])) {
- return true;
- }
-
- if (isset($this->children[$name])) {
- return true;
- }
-
- return false;
- }
-
- /**
- * {@inheritdoc}
- */
- public function all()
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->resolveChildren();
-
- return $this->children;
- }
-
- /**
- * {@inheritdoc}
- */
- public function count()
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- return count($this->children);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormConfig()
- {
- $config = parent::getFormConfig();
-
- $config->children = array();
- $config->unresolvedChildren = array();
-
- return $config;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getForm()
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->resolveChildren();
-
- $form = new Form($this->getFormConfig());
-
- foreach ($this->children as $child) {
- // Automatic initialization is only supported on root forms
- $form->add($child->setAutoInitialize(false)->getForm());
- }
-
- if ($this->getAutoInitialize()) {
- // Automatically initialize the form if it is configured so
- $form->initialize();
- }
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIterator()
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- return new \ArrayIterator($this->children);
- }
-
- /**
- * Converts an unresolved child into a {@link FormBuilder} instance.
- *
- * @param string $name The name of the unresolved child.
- *
- * @return FormBuilder The created instance.
- */
- private function resolveChild($name)
- {
- $info = $this->unresolvedChildren[$name];
- $child = $this->create($name, $info['type'], $info['options']);
- $this->children[$name] = $child;
- unset($this->unresolvedChildren[$name]);
-
- return $child;
- }
-
- /**
- * Converts all unresolved children into {@link FormBuilder} instances.
- */
- private function resolveChildren()
- {
- foreach ($this->unresolvedChildren as $name => $info) {
- $this->children[$name] = $this->create($name, $info['type'], $info['options']);
- }
-
- $this->unresolvedChildren = array();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormBuilderInterface extends \Traversable, \Countable, FormConfigBuilderInterface
-{
- /**
- * Adds a new field to this group. A field must have a unique name within
- * the group. Otherwise the existing field is overwritten.
- *
- * If you add a nested group, this group should also be represented in the
- * object hierarchy.
- *
- * @param string|integer|FormBuilderInterface $child
- * @param string|FormTypeInterface $type
- * @param array $options
- *
- * @return FormBuilderInterface The builder object.
- */
- public function add($child, $type = null, array $options = array());
-
- /**
- * Creates a form builder.
- *
- * @param string $name The name of the form or the name of the property
- * @param string|FormTypeInterface $type The type of the form or null if name is a property
- * @param array $options The options
- *
- * @return FormBuilderInterface The created builder.
- */
- public function create($name, $type = null, array $options = array());
-
- /**
- * Returns a child by name.
- *
- * @param string $name The name of the child
- *
- * @return FormBuilderInterface The builder for the child
- *
- * @throws Exception\InvalidArgumentException if the given child does not exist
- */
- public function get($name);
-
- /**
- * Removes the field with the given name.
- *
- * @param string $name
- *
- * @return FormBuilderInterface The builder object.
- */
- public function remove($name);
-
- /**
- * Returns whether a field with the given name exists.
- *
- * @param string $name
- *
- * @return Boolean
- */
- public function has($name);
-
- /**
- * Returns the children.
- *
- * @return array
- */
- public function all();
-
- /**
- * Creates the form.
- *
- * @return Form The form
- */
- public function getForm();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\BadMethodCallException;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\PropertyAccess\PropertyPath;
-use Symfony\Component\PropertyAccess\PropertyPathInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
-
-/**
- * A basic form configuration.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormConfigBuilder implements FormConfigBuilderInterface
-{
- /**
- * Caches a globally unique {@link NativeRequestHandler} instance.
- *
- * @var NativeRequestHandler
- */
- private static $nativeRequestProcessor;
-
- /**
- * The accepted request methods.
- *
- * @var array
- */
- private static $allowedMethods = array(
- 'GET',
- 'PUT',
- 'POST',
- 'DELETE',
- 'PATCH'
- );
-
- /**
- * @var Boolean
- */
- protected $locked = false;
-
- /**
- * @var EventDispatcherInterface
- */
- private $dispatcher;
-
- /**
- * @var string
- */
- private $name;
-
- /**
- * @var PropertyPathInterface
- */
- private $propertyPath;
-
- /**
- * @var Boolean
- */
- private $mapped = true;
-
- /**
- * @var Boolean
- */
- private $byReference = true;
-
- /**
- * @var Boolean
- */
- private $inheritData = false;
-
- /**
- * @var Boolean
- */
- private $compound = false;
-
- /**
- * @var ResolvedFormTypeInterface
- */
- private $type;
-
- /**
- * @var array
- */
- private $viewTransformers = array();
-
- /**
- * @var array
- */
- private $modelTransformers = array();
-
- /**
- * @var DataMapperInterface
- */
- private $dataMapper;
-
- /**
- * @var Boolean
- */
- private $required = true;
-
- /**
- * @var Boolean
- */
- private $disabled = false;
-
- /**
- * @var Boolean
- */
- private $errorBubbling = false;
-
- /**
- * @var mixed
- */
- private $emptyData;
-
- /**
- * @var array
- */
- private $attributes = array();
-
- /**
- * @var mixed
- */
- private $data;
-
- /**
- * @var string
- */
- private $dataClass;
-
- /**
- * @var Boolean
- */
- private $dataLocked;
-
- /**
- * @var FormFactoryInterface
- */
- private $formFactory;
-
- /**
- * @var string
- */
- private $action;
-
- /**
- * @var string
- */
- private $method = 'POST';
-
- /**
- * @var RequestHandlerInterface
- */
- private $requestHandler;
-
- /**
- * @var Boolean
- */
- private $autoInitialize = false;
-
- /**
- * @var array
- */
- private $options;
-
- /**
- * Creates an empty form configuration.
- *
- * @param string|integer $name The form name
- * @param string $dataClass The class of the form's data
- * @param EventDispatcherInterface $dispatcher The event dispatcher
- * @param array $options The form options
- *
- * @throws InvalidArgumentException If the data class is not a valid class or if
- * the name contains invalid characters.
- */
- public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, array $options = array())
- {
- self::validateName($name);
-
- if (null !== $dataClass && !class_exists($dataClass)) {
- throw new InvalidArgumentException(sprintf('The data class "%s" is not a valid class.', $dataClass));
- }
-
- $this->name = (string) $name;
- $this->dataClass = $dataClass;
- $this->dispatcher = $dispatcher;
- $this->options = $options;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addEventListener($eventName, $listener, $priority = 0)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->dispatcher->addListener($eventName, $listener, $priority);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addEventSubscriber(EventSubscriberInterface $subscriber)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->dispatcher->addSubscriber($subscriber);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- if ($forcePrepend) {
- array_unshift($this->viewTransformers, $viewTransformer);
- } else {
- $this->viewTransformers[] = $viewTransformer;
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function resetViewTransformers()
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->viewTransformers = array();
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- if ($forceAppend) {
- $this->modelTransformers[] = $modelTransformer;
- } else {
- array_unshift($this->modelTransformers, $modelTransformer);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function resetModelTransformers()
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->modelTransformers = array();
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getEventDispatcher()
- {
- if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) {
- $this->dispatcher = new ImmutableEventDispatcher($this->dispatcher);
- }
-
- return $this->dispatcher;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPropertyPath()
- {
- return $this->propertyPath;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getMapped()
- {
- return $this->mapped;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getByReference()
- {
- return $this->byReference;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getInheritData()
- {
- return $this->inheritData;
- }
-
- /**
- * Alias of {@link getInheritData()}.
- *
- * @return FormConfigBuilder The configuration object.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link getInheritData()} instead.
- */
- public function getVirtual()
- {
- // Uncomment this as soon as the deprecation note should be shown
- // trigger_error('getVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use getInheritData() instead.', E_USER_DEPRECATED);
- return $this->getInheritData();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCompound()
- {
- return $this->compound;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getType()
- {
- return $this->type;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getViewTransformers()
- {
- return $this->viewTransformers;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getModelTransformers()
- {
- return $this->modelTransformers;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDataMapper()
- {
- return $this->dataMapper;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRequired()
- {
- return $this->required;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDisabled()
- {
- return $this->disabled;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getErrorBubbling()
- {
- return $this->errorBubbling;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getEmptyData()
- {
- return $this->emptyData;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getAttributes()
- {
- return $this->attributes;
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasAttribute($name)
- {
- return array_key_exists($name, $this->attributes);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getAttribute($name, $default = null)
- {
- return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getData()
- {
- return $this->data;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDataClass()
- {
- return $this->dataClass;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDataLocked()
- {
- return $this->dataLocked;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormFactory()
- {
- return $this->formFactory;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getAction()
- {
- return $this->action;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getMethod()
- {
- return $this->method;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRequestHandler()
- {
- if (null === $this->requestHandler) {
- if (null === self::$nativeRequestProcessor) {
- self::$nativeRequestProcessor = new NativeRequestHandler();
- }
- $this->requestHandler = self::$nativeRequestProcessor;
- }
-
- return $this->requestHandler;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getAutoInitialize()
- {
- return $this->autoInitialize;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getOptions()
- {
- return $this->options;
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasOption($name)
- {
- return array_key_exists($name, $this->options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getOption($name, $default = null)
- {
- return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAttribute($name, $value)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->attributes[$name] = $value;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAttributes(array $attributes)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->attributes = $attributes;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDataMapper(DataMapperInterface $dataMapper = null)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->dataMapper = $dataMapper;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDisabled($disabled)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->disabled = (Boolean) $disabled;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setEmptyData($emptyData)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->emptyData = $emptyData;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setErrorBubbling($errorBubbling)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRequired($required)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->required = (Boolean) $required;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setPropertyPath($propertyPath)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- if (null !== $propertyPath && !$propertyPath instanceof PropertyPathInterface) {
- $propertyPath = new PropertyPath($propertyPath);
- }
-
- $this->propertyPath = $propertyPath;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setMapped($mapped)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->mapped = $mapped;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setByReference($byReference)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->byReference = $byReference;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setInheritData($inheritData)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->inheritData = $inheritData;
-
- return $this;
- }
-
- /**
- * Alias of {@link setInheritData()}.
- *
- * @param Boolean $inheritData Whether the form should inherit its parent's data.
- *
- * @return FormConfigBuilder The configuration object.
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link setInheritData()} instead.
- */
- public function setVirtual($inheritData)
- {
- // Uncomment this as soon as the deprecation note should be shown
- // trigger_error('setVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use setInheritData() instead.', E_USER_DEPRECATED);
-
- $this->setInheritData($inheritData);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setCompound($compound)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->compound = $compound;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setType(ResolvedFormTypeInterface $type)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->type = $type;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setData($data)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->data = $data;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDataLocked($locked)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->dataLocked = $locked;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setFormFactory(FormFactoryInterface $formFactory)
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- $this->formFactory = $formFactory;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAction($action)
- {
- if ($this->locked) {
- throw new BadMethodCallException('The config builder cannot be modified anymore.');
- }
-
- $this->action = $action;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setMethod($method)
- {
- if ($this->locked) {
- throw new BadMethodCallException('The config builder cannot be modified anymore.');
- }
-
- $upperCaseMethod = strtoupper($method);
-
- if (!in_array($upperCaseMethod, self::$allowedMethods)) {
- throw new InvalidArgumentException(sprintf(
- 'The form method is "%s", but should be one of "%s".',
- $method,
- implode('", "', self::$allowedMethods)
- ));
- }
-
- $this->method = $upperCaseMethod;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRequestHandler(RequestHandlerInterface $requestHandler)
- {
- if ($this->locked) {
- throw new BadMethodCallException('The config builder cannot be modified anymore.');
- }
-
- $this->requestHandler = $requestHandler;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAutoInitialize($initialize)
- {
- $this->autoInitialize = (Boolean) $initialize;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormConfig()
- {
- if ($this->locked) {
- throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
- }
-
- // This method should be idempotent, so clone the builder
- $config = clone $this;
- $config->locked = true;
-
- return $config;
- }
-
- /**
- * Validates whether the given variable is a valid form name.
- *
- * @param string|integer $name The tested form name.
- *
- * @throws UnexpectedTypeException If the name is not a string or an integer.
- * @throws InvalidArgumentException If the name contains invalid characters.
- */
- public static function validateName($name)
- {
- if (null !== $name && !is_string($name) && !is_int($name)) {
- throw new UnexpectedTypeException($name, 'string, integer or null');
- }
-
- if (!self::isValidName($name)) {
- throw new InvalidArgumentException(sprintf(
- 'The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").',
- $name
- ));
- }
- }
-
- /**
- * Returns whether the given variable contains a valid form name.
- *
- * A name is accepted if it
- *
- * * is empty
- * * starts with a letter, digit or underscore
- * * contains only letters, digits, numbers, underscores ("_"),
- * hyphens ("-") and colons (":")
- *
- * @param string $name The tested form name.
- *
- * @return Boolean Whether the name is valid.
- */
- public static function isValidName($name)
- {
- return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormConfigBuilderInterface extends FormConfigInterface
-{
- /**
- * Adds an event listener to an event on this form.
- *
- * @param string $eventName The name of the event to listen to.
- * @param callable $listener The listener to execute.
- * @param integer $priority The priority of the listener. Listeners
- * with a higher priority are called before
- * listeners with a lower priority.
- *
- * @return self The configuration object.
- */
- public function addEventListener($eventName, $listener, $priority = 0);
-
- /**
- * Adds an event subscriber for events on this form.
- *
- * @param EventSubscriberInterface $subscriber The subscriber to attach.
- *
- * @return self The configuration object.
- */
- public function addEventSubscriber(EventSubscriberInterface $subscriber);
-
- /**
- * Appends / prepends a transformer to the view transformer chain.
- *
- * The transform method of the transformer is used to convert data from the
- * normalized to the view format.
- * The reverseTransform method of the transformer is used to convert from the
- * view to the normalized format.
- *
- * @param DataTransformerInterface $viewTransformer
- * @param Boolean $forcePrepend if set to true, prepend instead of appending
- *
- * @return self The configuration object.
- */
- public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false);
-
- /**
- * Clears the view transformers.
- *
- * @return self The configuration object.
- */
- public function resetViewTransformers();
-
- /**
- * Prepends / appends a transformer to the normalization transformer chain.
- *
- * The transform method of the transformer is used to convert data from the
- * model to the normalized format.
- * The reverseTransform method of the transformer is used to convert from the
- * normalized to the model format.
- *
- * @param DataTransformerInterface $modelTransformer
- * @param Boolean $forceAppend if set to true, append instead of prepending
- *
- * @return self The configuration object.
- */
- public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false);
-
- /**
- * Clears the normalization transformers.
- *
- * @return self The configuration object.
- */
- public function resetModelTransformers();
-
- /**
- * Sets the value for an attribute.
- *
- * @param string $name The name of the attribute
- * @param string $value The value of the attribute
- *
- * @return self The configuration object.
- */
- public function setAttribute($name, $value);
-
- /**
- * Sets the attributes.
- *
- * @param array $attributes The attributes.
- *
- * @return self The configuration object.
- */
- public function setAttributes(array $attributes);
-
- /**
- * Sets the data mapper used by the form.
- *
- * @param DataMapperInterface $dataMapper
- *
- * @return self The configuration object.
- */
- public function setDataMapper(DataMapperInterface $dataMapper = null);
-
- /**
- * Set whether the form is disabled.
- *
- * @param Boolean $disabled Whether the form is disabled
- *
- * @return self The configuration object.
- */
- public function setDisabled($disabled);
-
- /**
- * Sets the data used for the client data when no value is submitted.
- *
- * @param mixed $emptyData The empty data.
- *
- * @return self The configuration object.
- */
- public function setEmptyData($emptyData);
-
- /**
- * Sets whether errors bubble up to the parent.
- *
- * @param Boolean $errorBubbling
- *
- * @return self The configuration object.
- */
- public function setErrorBubbling($errorBubbling);
-
- /**
- * Sets whether this field is required to be filled out when submitted.
- *
- * @param Boolean $required
- *
- * @return self The configuration object.
- */
- public function setRequired($required);
-
- /**
- * Sets the property path that the form should be mapped to.
- *
- * @param null|string|\Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath
- * The property path or null if the path should be set
- * automatically based on the form's name.
- *
- * @return self The configuration object.
- */
- public function setPropertyPath($propertyPath);
-
- /**
- * Sets whether the form should be mapped to an element of its
- * parent's data.
- *
- * @param Boolean $mapped Whether the form should be mapped.
- *
- * @return self The configuration object.
- */
- public function setMapped($mapped);
-
- /**
- * Sets whether the form's data should be modified by reference.
- *
- * @param Boolean $byReference Whether the data should be
- * modified by reference.
- *
- * @return self The configuration object.
- */
- public function setByReference($byReference);
-
- /**
- * Sets whether the form should read and write the data of its parent.
- *
- * @param Boolean $inheritData Whether the form should inherit its parent's data.
- *
- * @return self The configuration object.
- */
- public function setInheritData($inheritData);
-
- /**
- * Sets whether the form should be compound.
- *
- * @param Boolean $compound Whether the form should be compound.
- *
- * @return self The configuration object.
- *
- * @see FormConfigInterface::getCompound()
- */
- public function setCompound($compound);
-
- /**
- * Set the types.
- *
- * @param ResolvedFormTypeInterface $type The type of the form.
- *
- * @return self The configuration object.
- */
- public function setType(ResolvedFormTypeInterface $type);
-
- /**
- * Sets the initial data of the form.
- *
- * @param array $data The data of the form in application format.
- *
- * @return self The configuration object.
- */
- public function setData($data);
-
- /**
- * Locks the form's data to the data passed in the configuration.
- *
- * A form with locked data is restricted to the data passed in
- * this configuration. The data can only be modified then by
- * submitting the form.
- *
- * @param Boolean $locked Whether to lock the default data.
- *
- * @return self The configuration object.
- */
- public function setDataLocked($locked);
-
- /**
- * Sets the form factory used for creating new forms.
- *
- * @param FormFactoryInterface $formFactory The form factory.
- */
- public function setFormFactory(FormFactoryInterface $formFactory);
-
- /**
- * Sets the target URL of the form.
- *
- * @param string $action The target URL of the form.
- *
- * @return self The configuration object.
- */
- public function setAction($action);
-
- /**
- * Sets the HTTP method used by the form.
- *
- * @param string $method The HTTP method of the form.
- *
- * @return self The configuration object.
- */
- public function setMethod($method);
-
- /**
- * Sets the request handler used by the form.
- *
- * @param RequestHandlerInterface $requestHandler
- *
- * @return self The configuration object.
- */
- public function setRequestHandler(RequestHandlerInterface $requestHandler);
-
- /**
- * Sets whether the form should be initialized automatically.
- *
- * Should be set to true only for root forms.
- *
- * @param Boolean $initialize True to initialize the form automatically,
- * false to suppress automatic initialization.
- * In the second case, you need to call
- * {@link FormInterface::initialize()} manually.
- *
- * @return self The configuration object.
- */
- public function setAutoInitialize($initialize);
-
- /**
- * Builds and returns the form configuration.
- *
- * @return FormConfigInterface
- */
- public function getFormConfig();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * The configuration of a {@link Form} object.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormConfigInterface
-{
- /**
- * Returns the event dispatcher used to dispatch form events.
- *
- * @return \Symfony\Component\EventDispatcher\EventDispatcherInterface The dispatcher.
- */
- public function getEventDispatcher();
-
- /**
- * Returns the name of the form used as HTTP parameter.
- *
- * @return string The form name.
- */
- public function getName();
-
- /**
- * Returns the property path that the form should be mapped to.
- *
- * @return null|\Symfony\Component\PropertyAccess\PropertyPathInterface The property path.
- */
- public function getPropertyPath();
-
- /**
- * Returns whether the form should be mapped to an element of its
- * parent's data.
- *
- * @return Boolean Whether the form is mapped.
- */
- public function getMapped();
-
- /**
- * Returns whether the form's data should be modified by reference.
- *
- * @return Boolean Whether to modify the form's data by reference.
- */
- public function getByReference();
-
- /**
- * Returns whether the form should read and write the data of its parent.
- *
- * @return Boolean Whether the form should inherit its parent's data.
- */
- public function getInheritData();
-
- /**
- * Returns whether the form is compound.
- *
- * This property is independent of whether the form actually has
- * children. A form can be compound and have no children at all, like
- * for example an empty collection form.
- *
- * @return Boolean Whether the form is compound.
- */
- public function getCompound();
-
- /**
- * Returns the form types used to construct the form.
- *
- * @return ResolvedFormTypeInterface The form's type.
- */
- public function getType();
-
- /**
- * Returns the view transformers of the form.
- *
- * @return DataTransformerInterface[] An array of {@link DataTransformerInterface} instances.
- */
- public function getViewTransformers();
-
- /**
- * Returns the model transformers of the form.
- *
- * @return DataTransformerInterface[] An array of {@link DataTransformerInterface} instances.
- */
- public function getModelTransformers();
-
- /**
- * Returns the data mapper of the form.
- *
- * @return DataMapperInterface The data mapper.
- */
- public function getDataMapper();
-
- /**
- * Returns whether the form is required.
- *
- * @return Boolean Whether the form is required.
- */
- public function getRequired();
-
- /**
- * Returns whether the form is disabled.
- *
- * @return Boolean Whether the form is disabled.
- */
- public function getDisabled();
-
- /**
- * Returns whether errors attached to the form will bubble to its parent.
- *
- * @return Boolean Whether errors will bubble up.
- */
- public function getErrorBubbling();
-
- /**
- * Returns the data that should be returned when the form is empty.
- *
- * @return mixed The data returned if the form is empty.
- */
- public function getEmptyData();
-
- /**
- * Returns additional attributes of the form.
- *
- * @return array An array of key-value combinations.
- */
- public function getAttributes();
-
- /**
- * Returns whether the attribute with the given name exists.
- *
- * @param string $name The attribute name.
- *
- * @return Boolean Whether the attribute exists.
- */
- public function hasAttribute($name);
-
- /**
- * Returns the value of the given attribute.
- *
- * @param string $name The attribute name.
- * @param mixed $default The value returned if the attribute does not exist.
- *
- * @return mixed The attribute value.
- */
- public function getAttribute($name, $default = null);
-
- /**
- * Returns the initial data of the form.
- *
- * @return mixed The initial form data.
- */
- public function getData();
-
- /**
- * Returns the class of the form data or null if the data is scalar or an array.
- *
- * @return string The data class or null.
- */
- public function getDataClass();
-
- /**
- * Returns whether the form's data is locked.
- *
- * A form with locked data is restricted to the data passed in
- * this configuration. The data can only be modified then by
- * submitting the form.
- *
- * @return Boolean Whether the data is locked.
- */
- public function getDataLocked();
-
- /**
- * Returns the form factory used for creating new forms.
- *
- * @return FormFactoryInterface The form factory.
- */
- public function getFormFactory();
-
- /**
- * Returns the target URL of the form.
- *
- * @return string The target URL of the form.
- */
- public function getAction();
-
- /**
- * Returns the HTTP method used by the form.
- *
- * @return string The HTTP method of the form.
- */
- public function getMethod();
-
- /**
- * Returns the request handler used by the form.
- *
- * @return RequestHandlerInterface The request handler.
- */
- public function getRequestHandler();
-
- /**
- * Returns whether the form should be initialized upon creation.
- *
- * @return Boolean Returns true if the form should be initialized
- * when created, false otherwise.
- */
- public function getAutoInitialize();
-
- /**
- * Returns all options passed during the construction of the form.
- *
- * @return array The passed options.
- */
- public function getOptions();
-
- /**
- * Returns whether a specific option exists.
- *
- * @param string $name The option name,
- *
- * @return Boolean Whether the option exists.
- */
- public function hasOption($name);
-
- /**
- * Returns the value of a specific option.
- *
- * @param string $name The option name.
- * @param mixed $default The value returned if the option does not exist.
- *
- * @return mixed The option value.
- */
- public function getOption($name, $default = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Wraps errors in forms
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormError
-{
- /**
- * @var string
- */
- private $message;
-
- /**
- * The template for the error message
- * @var string
- */
- protected $messageTemplate;
-
- /**
- * The parameters that should be substituted in the message template
- * @var array
- */
- protected $messageParameters;
-
- /**
- * The value for error message pluralization
- * @var integer|null
- */
- protected $messagePluralization;
-
- /**
- * Constructor
- *
- * Any array key in $messageParameters will be used as a placeholder in
- * $messageTemplate.
- *
- * @param string $message The translated error message
- * @param string|null $messageTemplate The template for the error message
- * @param array $messageParameters The parameters that should be
- * substituted in the message template.
- * @param integer|null $messagePluralization The value for error message pluralization
- *
- * @see \Symfony\Component\Translation\Translator
- */
- public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null)
- {
- $this->message = $message;
- $this->messageTemplate = $messageTemplate ?: $message;
- $this->messageParameters = $messageParameters;
- $this->messagePluralization = $messagePluralization;
- }
-
- /**
- * Returns the error message
- *
- * @return string
- */
- public function getMessage()
- {
- return $this->message;
- }
-
- /**
- * Returns the error message template
- *
- * @return string
- */
- public function getMessageTemplate()
- {
- return $this->messageTemplate;
- }
-
- /**
- * Returns the parameters to be inserted in the message template
- *
- * @return array
- */
- public function getMessageParameters()
- {
- return $this->messageParameters;
- }
-
- /**
- * Returns the value for error message pluralization.
- *
- * @return integer|null
- */
- public function getMessagePluralization()
- {
- return $this->messagePluralization;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\EventDispatcher\Event;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormEvent extends Event
-{
- private $form;
- protected $data;
-
- /**
- * Constructs an event.
- *
- * @param FormInterface $form The associated form
- * @param mixed $data The data
- */
- public function __construct(FormInterface $form, $data)
- {
- $this->form = $form;
- $this->data = $data;
- }
-
- /**
- * Returns the form at the source of the event.
- *
- * @return FormInterface
- */
- public function getForm()
- {
- return $this->form;
- }
-
- /**
- * Returns the data associated with this event.
- *
- * @return mixed
- */
- public function getData()
- {
- return $this->data;
- }
-
- /**
- * Allows updating with some filtered data.
- *
- * @param mixed $data
- */
- public function setData($data)
- {
- $this->data = $data;
- }
-}
+++ /dev/null
-<?php
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-final class FormEvents
-{
- const PRE_SUBMIT = 'form.pre_bind';
-
- const SUBMIT = 'form.bind';
-
- const POST_SUBMIT = 'form.post_bind';
-
- const PRE_SET_DATA = 'form.pre_set_data';
-
- const POST_SET_DATA = 'form.post_set_data';
-
- /**
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link PRE_SUBMIT} instead.
- */
- const PRE_BIND = 'form.pre_bind';
-
- /**
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link SUBMIT} instead.
- */
- const BIND = 'form.bind';
-
- /**
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link POST_SUBMIT} instead.
- */
- const POST_BIND = 'form.post_bind';
-
- private function __construct()
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Interface for extensions which provide types, type extensions and a guesser.
- */
-interface FormExtensionInterface
-{
- /**
- * Returns a type by name.
- *
- * @param string $name The name of the type
- *
- * @return FormTypeInterface The type
- *
- * @throws Exception\InvalidArgumentException if the given type is not supported by this extension
- */
- public function getType($name);
-
- /**
- * Returns whether the given type is supported.
- *
- * @param string $name The name of the type
- *
- * @return Boolean Whether the type is supported by this extension
- */
- public function hasType($name);
-
- /**
- * Returns the extensions for the given type.
- *
- * @param string $name The name of the type
- *
- * @return FormTypeExtensionInterface[] An array of extensions as FormTypeExtensionInterface instances
- */
- public function getTypeExtensions($name);
-
- /**
- * Returns whether this extension provides type extensions for the given type.
- *
- * @param string $name The name of the type
- *
- * @return Boolean Whether the given type has extensions
- */
- public function hasTypeExtensions($name);
-
- /**
- * Returns the type guesser provided by this extension.
- *
- * @return FormTypeGuesserInterface|null The type guesser
- */
- public function getTypeGuesser();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-class FormFactory implements FormFactoryInterface
-{
- /**
- * @var FormRegistryInterface
- */
- private $registry;
-
- /**
- * @var ResolvedFormTypeFactoryInterface
- */
- private $resolvedTypeFactory;
-
- public function __construct(FormRegistryInterface $registry, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
- {
- $this->registry = $registry;
- $this->resolvedTypeFactory = $resolvedTypeFactory;
- }
-
- /**
- * {@inheritdoc}
- */
- public function create($type = 'form', $data = null, array $options = array())
- {
- return $this->createBuilder($type, $data, $options)->getForm();
- }
-
- /**
- * {@inheritdoc}
- */
- public function createNamed($name, $type = 'form', $data = null, array $options = array())
- {
- return $this->createNamedBuilder($name, $type, $data, $options)->getForm();
- }
-
- /**
- * {@inheritdoc}
- */
- public function createForProperty($class, $property, $data = null, array $options = array())
- {
- return $this->createBuilderForProperty($class, $property, $data, $options)->getForm();
- }
-
- /**
- * {@inheritdoc}
- */
- public function createBuilder($type = 'form', $data = null, array $options = array())
- {
- $name = $type instanceof FormTypeInterface || $type instanceof ResolvedFormTypeInterface
- ? $type->getName()
- : $type;
-
- return $this->createNamedBuilder($name, $type, $data, $options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array())
- {
- if (null !== $data && !array_key_exists('data', $options)) {
- $options['data'] = $data;
- }
-
- if ($type instanceof FormTypeInterface) {
- $type = $this->resolveType($type);
- } elseif (is_string($type)) {
- $type = $this->registry->getType($type);
- } elseif (!$type instanceof ResolvedFormTypeInterface) {
- throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface');
- }
-
- return $type->createBuilder($this, $name, $options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function createBuilderForProperty($class, $property, $data = null, array $options = array())
- {
- if (null === $guesser = $this->registry->getTypeGuesser()) {
- return $this->createNamedBuilder($property, 'text', $data, $options);
- }
-
- $typeGuess = $guesser->guessType($class, $property);
- $maxLengthGuess = $guesser->guessMaxLength($class, $property);
- $requiredGuess = $guesser->guessRequired($class, $property);
- $patternGuess = $guesser->guessPattern($class, $property);
-
- $type = $typeGuess ? $typeGuess->getType() : 'text';
-
- $maxLength = $maxLengthGuess ? $maxLengthGuess->getValue() : null;
- $pattern = $patternGuess ? $patternGuess->getValue() : null;
-
- if (null !== $pattern) {
- $options = array_merge(array('pattern' => $pattern), $options);
- }
-
- if (null !== $maxLength) {
- $options = array_merge(array('max_length' => $maxLength), $options);
- }
-
- if ($requiredGuess) {
- $options = array_merge(array('required' => $requiredGuess->getValue()), $options);
- }
-
- // user options may override guessed options
- if ($typeGuess) {
- $options = array_merge($typeGuess->getOptions(), $options);
- }
-
- return $this->createNamedBuilder($property, $type, $data, $options);
- }
-
- /**
- * Wraps a type into a ResolvedFormTypeInterface implementation and connects
- * it with its parent type.
- *
- * @param FormTypeInterface $type The type to resolve.
- *
- * @return ResolvedFormTypeInterface The resolved type.
- */
- private function resolveType(FormTypeInterface $type)
- {
- $parentType = $type->getParent();
-
- if ($parentType instanceof FormTypeInterface) {
- $parentType = $this->resolveType($parentType);
- } elseif (null !== $parentType) {
- $parentType = $this->registry->getType($parentType);
- }
-
- return $this->resolvedTypeFactory->createResolvedType(
- $type,
- // Type extensions are not supported for unregistered type instances,
- // i.e. type instances that are passed to the FormFactory directly,
- // nor for their parents, if getParent() also returns a type instance.
- array(),
- $parentType
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * The default implementation of FormFactoryBuilderInterface.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormFactoryBuilder implements FormFactoryBuilderInterface
-{
- /**
- * @var ResolvedFormTypeFactoryInterface
- */
- private $resolvedTypeFactory;
-
- /**
- * @var array
- */
- private $extensions = array();
-
- /**
- * @var array
- */
- private $types = array();
-
- /**
- * @var array
- */
- private $typeExtensions = array();
-
- /**
- * @var array
- */
- private $typeGuessers = array();
-
- /**
- * {@inheritdoc}
- */
- public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
- {
- $this->resolvedTypeFactory = $resolvedTypeFactory;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addExtension(FormExtensionInterface $extension)
- {
- $this->extensions[] = $extension;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addExtensions(array $extensions)
- {
- $this->extensions = array_merge($this->extensions, $extensions);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addType(FormTypeInterface $type)
- {
- $this->types[$type->getName()] = $type;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addTypes(array $types)
- {
- foreach ($types as $type) {
- $this->types[$type->getName()] = $type;
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addTypeExtension(FormTypeExtensionInterface $typeExtension)
- {
- $this->typeExtensions[$typeExtension->getExtendedType()][] = $typeExtension;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addTypeExtensions(array $typeExtensions)
- {
- foreach ($typeExtensions as $typeExtension) {
- $this->typeExtensions[$typeExtension->getExtendedType()][] = $typeExtension;
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addTypeGuesser(FormTypeGuesserInterface $typeGuesser)
- {
- $this->typeGuessers[] = $typeGuesser;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addTypeGuessers(array $typeGuessers)
- {
- $this->typeGuessers = array_merge($this->typeGuessers, $typeGuessers);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormFactory()
- {
- $extensions = $this->extensions;
-
- if (count($this->types) > 0 || count($this->typeExtensions) > 0 || count($this->typeGuessers) > 0) {
- if (count($this->typeGuessers) > 1) {
- $typeGuesser = new FormTypeGuesserChain($this->typeGuessers);
- } else {
- $typeGuesser = isset($this->typeGuessers[0]) ? $this->typeGuessers[0] : null;
- }
-
- $extensions[] = new PreloadedExtension($this->types, $this->typeExtensions, $typeGuesser);
- }
-
- $resolvedTypeFactory = $this->resolvedTypeFactory ?: new ResolvedFormTypeFactory();
- $registry = new FormRegistry($extensions, $resolvedTypeFactory);
-
- return new FormFactory($registry, $resolvedTypeFactory);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A builder for FormFactoryInterface objects.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormFactoryBuilderInterface
-{
- /**
- * Sets the factory for creating ResolvedFormTypeInterface instances.
- *
- * @param ResolvedFormTypeFactoryInterface $resolvedTypeFactory
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory);
-
- /**
- * Adds an extension to be loaded by the factory.
- *
- * @param FormExtensionInterface $extension The extension.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addExtension(FormExtensionInterface $extension);
-
- /**
- * Adds a list of extensions to be loaded by the factory.
- *
- * @param array $extensions The extensions.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addExtensions(array $extensions);
-
- /**
- * Adds a form type to the factory.
- *
- * @param FormTypeInterface $type The form type.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addType(FormTypeInterface $type);
-
- /**
- * Adds a list of form types to the factory.
- *
- * @param array $types The form types.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addTypes(array $types);
-
- /**
- * Adds a form type extension to the factory.
- *
- * @param FormTypeExtensionInterface $typeExtension The form type extension.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addTypeExtension(FormTypeExtensionInterface $typeExtension);
-
- /**
- * Adds a list of form type extensions to the factory.
- *
- * @param array $typeExtensions The form type extensions.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addTypeExtensions(array $typeExtensions);
-
- /**
- * Adds a type guesser to the factory.
- *
- * @param FormTypeGuesserInterface $typeGuesser The type guesser.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addTypeGuesser(FormTypeGuesserInterface $typeGuesser);
-
- /**
- * Adds a list of type guessers to the factory.
- *
- * @param array $typeGuessers The type guessers.
- *
- * @return FormFactoryBuilderInterface The builder.
- */
- public function addTypeGuessers(array $typeGuessers);
-
- /**
- * Builds and returns the factory.
- *
- * @return FormFactoryInterface The form factory.
- */
- public function getFormFactory();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormFactoryInterface
-{
- /**
- * Returns a form.
- *
- * @see createBuilder()
- *
- * @param string|FormTypeInterface $type The type of the form
- * @param mixed $data The initial data
- * @param array $options The options
- *
- * @return FormInterface The form named after the type
- *
- * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
- */
- public function create($type = 'form', $data = null, array $options = array());
-
- /**
- * Returns a form.
- *
- * @see createNamedBuilder()
- *
- * @param string|integer $name The name of the form
- * @param string|FormTypeInterface $type The type of the form
- * @param mixed $data The initial data
- * @param array $options The options
- *
- * @return FormInterface The form
- *
- * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
- */
- public function createNamed($name, $type = 'form', $data = null, array $options = array());
-
- /**
- * Returns a form for a property of a class.
- *
- * @see createBuilderForProperty()
- *
- * @param string $class The fully qualified class name
- * @param string $property The name of the property to guess for
- * @param mixed $data The initial data
- * @param array $options The options for the builder
- *
- * @return FormInterface The form named after the property
- *
- * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the form type
- */
- public function createForProperty($class, $property, $data = null, array $options = array());
-
- /**
- * Returns a form builder.
- *
- * @param string|FormTypeInterface $type The type of the form
- * @param mixed $data The initial data
- * @param array $options The options
- *
- * @return FormBuilderInterface The form builder
- *
- * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
- */
- public function createBuilder($type = 'form', $data = null, array $options = array());
-
- /**
- * Returns a form builder.
- *
- * @param string|integer $name The name of the form
- * @param string|FormTypeInterface $type The type of the form
- * @param mixed $data The initial data
- * @param array $options The options
- *
- * @return FormBuilderInterface The form builder
- *
- * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the given type
- */
- public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array());
-
- /**
- * Returns a form builder for a property of a class.
- *
- * If any of the 'max_length', 'required' and type options can be guessed,
- * and are not provided in the options argument, the guessed value is used.
- *
- * @param string $class The fully qualified class name
- * @param string $property The name of the property to guess for
- * @param mixed $data The initial data
- * @param array $options The options for the builder
- *
- * @return FormBuilderInterface The form builder named after the property
- *
- * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException if any given option is not applicable to the form type
- */
- public function createBuilderForProperty($class, $property, $data = null, array $options = array());
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A form group bundling multiple forms in a hierarchical structure.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormInterface extends \ArrayAccess, \Traversable, \Countable
-{
- /**
- * Sets the parent form.
- *
- * @param FormInterface|null $parent The parent form or null if it's the root.
- *
- * @return FormInterface The form instance
- *
- * @throws Exception\AlreadySubmittedException If the form has already been submitted.
- * @throws Exception\LogicException When trying to set a parent for a form with
- * an empty name.
- */
- public function setParent(FormInterface $parent = null);
-
- /**
- * Returns the parent form.
- *
- * @return FormInterface|null The parent form or null if there is none.
- */
- public function getParent();
-
- /**
- * Adds a child to the form.
- *
- * @param FormInterface|string|integer $child The FormInterface instance or the name of the child.
- * @param string|null $type The child's type, if a name was passed.
- * @param array $options The child's options, if a name was passed.
- *
- * @return FormInterface The form instance
- *
- * @throws Exception\AlreadySubmittedException If the form has already been submitted.
- * @throws Exception\LogicException When trying to add a child to a non-compound form.
- * @throws Exception\UnexpectedTypeException If $child or $type has an unexpected type.
- */
- public function add($child, $type = null, array $options = array());
-
- /**
- * Returns the child with the given name.
- *
- * @param string $name The name of the child
- *
- * @return FormInterface The child form
- *
- * @throws \OutOfBoundsException If the named child does not exist.
- */
- public function get($name);
-
- /**
- * Returns whether a child with the given name exists.
- *
- * @param string $name The name of the child
- *
- * @return Boolean
- */
- public function has($name);
-
- /**
- * Removes a child from the form.
- *
- * @param string $name The name of the child to remove
- *
- * @return FormInterface The form instance
- *
- * @throws Exception\AlreadySubmittedException If the form has already been submitted.
- */
- public function remove($name);
-
- /**
- * Returns all children in this group.
- *
- * @return FormInterface[] An array of FormInterface instances
- */
- public function all();
-
- /**
- * Returns all errors.
- *
- * @return FormError[] An array of FormError instances that occurred during validation
- */
- public function getErrors();
-
- /**
- * Updates the form with default data.
- *
- * @param mixed $modelData The data formatted as expected for the underlying object
- *
- * @return FormInterface The form instance
- *
- * @throws Exception\AlreadySubmittedException If the form has already been submitted.
- * @throws Exception\LogicException If listeners try to call setData in a cycle. Or if
- * the view data does not match the expected type
- * according to {@link FormConfigInterface::getDataClass}.
- */
- public function setData($modelData);
-
- /**
- * Returns the data in the format needed for the underlying object.
- *
- * @return mixed
- */
- public function getData();
-
- /**
- * Returns the normalized data of the field.
- *
- * @return mixed When the field is not submitted, the default data is returned.
- * When the field is submitted, the normalized submitted data is
- * returned if the field is valid, null otherwise.
- */
- public function getNormData();
-
- /**
- * Returns the data transformed by the value transformer.
- *
- * @return mixed
- */
- public function getViewData();
-
- /**
- * Returns the extra data.
- *
- * @return array The submitted data which do not belong to a child
- */
- public function getExtraData();
-
- /**
- * Returns the form's configuration.
- *
- * @return FormConfigInterface The configuration.
- */
- public function getConfig();
-
- /**
- * Returns whether the form is submitted.
- *
- * @return Boolean true if the form is submitted, false otherwise
- */
- public function isSubmitted();
-
- /**
- * Returns the name by which the form is identified in forms.
- *
- * @return string The name of the form.
- */
- public function getName();
-
- /**
- * Returns the property path that the form is mapped to.
- *
- * @return \Symfony\Component\PropertyAccess\PropertyPathInterface The property path.
- */
- public function getPropertyPath();
-
- /**
- * Adds an error to this form.
- *
- * @param FormError $error
- *
- * @return FormInterface The form instance
- */
- public function addError(FormError $error);
-
- /**
- * Returns whether the form and all children are valid.
- *
- * If the form is not submitted, this method always returns false.
- *
- * @return Boolean
- */
- public function isValid();
-
- /**
- * Returns whether the form is required to be filled out.
- *
- * If the form has a parent and the parent is not required, this method
- * will always return false. Otherwise the value set with setRequired()
- * is returned.
- *
- * @return Boolean
- */
- public function isRequired();
-
- /**
- * Returns whether this form is disabled.
- *
- * The content of a disabled form is displayed, but not allowed to be
- * modified. The validation of modified disabled forms should fail.
- *
- * Forms whose parents are disabled are considered disabled regardless of
- * their own state.
- *
- * @return Boolean
- */
- public function isDisabled();
-
- /**
- * Returns whether the form is empty.
- *
- * @return Boolean
- */
- public function isEmpty();
-
- /**
- * Returns whether the data in the different formats is synchronized.
- *
- * @return Boolean
- */
- public function isSynchronized();
-
- /**
- * Initializes the form tree.
- *
- * Should be called on the root form after constructing the tree.
- *
- * @return FormInterface The form instance.
- */
- public function initialize();
-
- /**
- * Inspects the given request and calls {@link submit()} if the form was
- * submitted.
- *
- * Internally, the request is forwarded to the configured
- * {@link RequestHandlerInterface} instance, which determines whether to
- * submit the form or not.
- *
- * @param mixed $request The request to handle.
- *
- * @return FormInterface The form instance.
- */
- public function handleRequest($request = null);
-
- /**
- * Submits data to the form, transforms and validates it.
- *
- * @param null|string|array $submittedData The submitted data.
- * @param Boolean $clearMissing Whether to set fields to NULL
- * when they are missing in the
- * submitted data.
- *
- * @return FormInterface The form instance
- *
- * @throws Exception\AlreadySubmittedException If the form has already been submitted.
- */
- public function submit($submittedData, $clearMissing = true);
-
- /**
- * Returns the root of the form tree.
- *
- * @return FormInterface The root of the tree
- */
- public function getRoot();
-
- /**
- * Returns whether the field is the root of the form tree.
- *
- * @return Boolean
- */
- public function isRoot();
-
- /**
- * Creates a view.
- *
- * @param FormView $parent The parent view
- *
- * @return FormView The view
- */
- public function createView(FormView $parent = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\ExceptionInterface;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-
-/**
- * The central registry of the Form component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormRegistry implements FormRegistryInterface
-{
- /**
- * Extensions
- *
- * @var FormExtensionInterface[] An array of FormExtensionInterface
- */
- private $extensions = array();
-
- /**
- * @var array
- */
- private $types = array();
-
- /**
- * @var FormTypeGuesserInterface|false|null
- */
- private $guesser = false;
-
- /**
- * @var ResolvedFormTypeFactoryInterface
- */
- private $resolvedTypeFactory;
-
- /**
- * Constructor.
- *
- * @param FormExtensionInterface[] $extensions An array of FormExtensionInterface
- * @param ResolvedFormTypeFactoryInterface $resolvedTypeFactory The factory for resolved form types.
- *
- * @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
- */
- public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
- {
- foreach ($extensions as $extension) {
- if (!$extension instanceof FormExtensionInterface) {
- throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormExtensionInterface');
- }
- }
-
- $this->extensions = $extensions;
- $this->resolvedTypeFactory = $resolvedTypeFactory;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getType($name)
- {
- if (!is_string($name)) {
- throw new UnexpectedTypeException($name, 'string');
- }
-
- if (!isset($this->types[$name])) {
- /** @var FormTypeInterface $type */
- $type = null;
-
- foreach ($this->extensions as $extension) {
- /* @var FormExtensionInterface $extension */
- if ($extension->hasType($name)) {
- $type = $extension->getType($name);
- break;
- }
- }
-
- if (!$type) {
- throw new InvalidArgumentException(sprintf('Could not load type "%s"', $name));
- }
-
- $this->resolveAndAddType($type);
- }
-
- return $this->types[$name];
- }
-
- /**
- * Wraps a type into a ResolvedFormTypeInterface implementation and connects
- * it with its parent type.
- *
- * @param FormTypeInterface $type The type to resolve.
- *
- * @return ResolvedFormTypeInterface The resolved type.
- */
- private function resolveAndAddType(FormTypeInterface $type)
- {
- $parentType = $type->getParent();
-
- if ($parentType instanceof FormTypeInterface) {
- $this->resolveAndAddType($parentType);
- $parentType = $parentType->getName();
- }
-
- $typeExtensions = array();
-
- foreach ($this->extensions as $extension) {
- /* @var FormExtensionInterface $extension */
- $typeExtensions = array_merge(
- $typeExtensions,
- $extension->getTypeExtensions($type->getName())
- );
- }
-
- $this->types[$type->getName()] = $this->resolvedTypeFactory->createResolvedType(
- $type,
- $typeExtensions,
- $parentType ? $this->getType($parentType) : null
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasType($name)
- {
- if (isset($this->types[$name])) {
- return true;
- }
-
- try {
- $this->getType($name);
- } catch (ExceptionInterface $e) {
- return false;
- }
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeGuesser()
- {
- if (false === $this->guesser) {
- $guessers = array();
-
- foreach ($this->extensions as $extension) {
- /* @var FormExtensionInterface $extension */
- $guesser = $extension->getTypeGuesser();
-
- if ($guesser) {
- $guessers[] = $guesser;
- }
- }
-
- $this->guesser = !empty($guessers) ? new FormTypeGuesserChain($guessers) : null;
- }
-
- return $this->guesser;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getExtensions()
- {
- return $this->extensions;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * The central registry of the Form component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormRegistryInterface
-{
- /**
- * Returns a form type by name.
- *
- * This methods registers the type extensions from the form extensions.
- *
- * @param string $name The name of the type
- *
- * @return ResolvedFormTypeInterface The type
- *
- * @throws Exception\UnexpectedTypeException if the passed name is not a string
- * @throws Exception\InvalidArgumentException if the type can not be retrieved from any extension
- */
- public function getType($name);
-
- /**
- * Returns whether the given form type is supported.
- *
- * @param string $name The name of the type
- *
- * @return Boolean Whether the type is supported
- */
- public function hasType($name);
-
- /**
- * Returns the guesser responsible for guessing types.
- *
- * @return FormTypeGuesserInterface|null
- */
- public function getTypeGuesser();
-
- /**
- * Returns the extensions loaded by the framework.
- *
- * @return array
- */
- public function getExtensions();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\LogicException;
-use Symfony\Component\Form\Exception\BadMethodCallException;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-
-/**
- * Renders a form into HTML using a rendering engine.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormRenderer implements FormRendererInterface
-{
- const CACHE_KEY_VAR = 'unique_block_prefix';
-
- /**
- * @var FormRendererEngineInterface
- */
- private $engine;
-
- /**
- * @var CsrfProviderInterface
- */
- private $csrfProvider;
-
- /**
- * @var array
- */
- private $blockNameHierarchyMap = array();
-
- /**
- * @var array
- */
- private $hierarchyLevelMap = array();
-
- /**
- * @var array
- */
- private $variableStack = array();
-
- public function __construct(FormRendererEngineInterface $engine, CsrfProviderInterface $csrfProvider = null)
- {
- $this->engine = $engine;
- $this->csrfProvider = $csrfProvider;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getEngine()
- {
- return $this->engine;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setTheme(FormView $view, $themes)
- {
- $this->engine->setTheme($view, $themes);
- }
-
- /**
- * {@inheritdoc}
- */
- public function renderCsrfToken($intention)
- {
- if (null === $this->csrfProvider) {
- throw new BadMethodCallException('CSRF token can only be generated if a CsrfProviderInterface is injected in the constructor.');
- }
-
- return $this->csrfProvider->generateCsrfToken($intention);
- }
-
- /**
- * {@inheritdoc}
- */
- public function renderBlock(FormView $view, $blockName, array $variables = array())
- {
- $resource = $this->engine->getResourceForBlockName($view, $blockName);
-
- if (!$resource) {
- throw new LogicException(sprintf('No block "%s" found while rendering the form.', $blockName));
- }
-
- $viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
-
- // The variables are cached globally for a view (instead of for the
- // current suffix)
- if (!isset($this->variableStack[$viewCacheKey])) {
- $this->variableStack[$viewCacheKey] = array();
-
- // The default variable scope contains all view variables, merged with
- // the variables passed explicitly to the helper
- $scopeVariables = $view->vars;
-
- $varInit = true;
- } else {
- // Reuse the current scope and merge it with the explicitly passed variables
- $scopeVariables = end($this->variableStack[$viewCacheKey]);
-
- $varInit = false;
- }
-
- // Merge the passed with the existing attributes
- if (isset($variables['attr']) && isset($scopeVariables['attr'])) {
- $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']);
- }
-
- // Merge the passed with the exist *label* attributes
- if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) {
- $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']);
- }
-
- // Do not use array_replace_recursive(), otherwise array variables
- // cannot be overwritten
- $variables = array_replace($scopeVariables, $variables);
-
- $this->variableStack[$viewCacheKey][] = $variables;
-
- // Do the rendering
- $html = $this->engine->renderBlock($view, $resource, $blockName, $variables);
-
- // Clear the stack
- array_pop($this->variableStack[$viewCacheKey]);
-
- if ($varInit) {
- unset($this->variableStack[$viewCacheKey]);
- }
-
- return $html;
- }
-
- /**
- * {@inheritdoc}
- */
- public function searchAndRenderBlock(FormView $view, $blockNameSuffix, array $variables = array())
- {
- $renderOnlyOnce = 'row' === $blockNameSuffix || 'widget' === $blockNameSuffix;
-
- if ($renderOnlyOnce && $view->isRendered()) {
- return '';
- }
-
- // The cache key for storing the variables and types
- $viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
- $viewAndSuffixCacheKey = $viewCacheKey.$blockNameSuffix;
-
- // In templates, we have to deal with two kinds of block hierarchies:
- //
- // +---------+ +---------+
- // | Theme B | -------> | Theme A |
- // +---------+ +---------+
- //
- // form_widget -------> form_widget
- // ^
- // |
- // choice_widget -----> choice_widget
- //
- // The first kind of hierarchy is the theme hierarchy. This allows to
- // override the block "choice_widget" from Theme A in the extending
- // Theme B. This kind of inheritance needs to be supported by the
- // template engine and, for example, offers "parent()" or similar
- // functions to fall back from the custom to the parent implementation.
- //
- // The second kind of hierarchy is the form type hierarchy. This allows
- // to implement a custom "choice_widget" block (no matter in which theme),
- // or to fallback to the block of the parent type, which would be
- // "form_widget" in this example (again, no matter in which theme).
- // If the designer wants to explicitly fallback to "form_widget" in his
- // custom "choice_widget", for example because he only wants to wrap
- // a <div> around the original implementation, he can simply call the
- // widget() function again to render the block for the parent type.
- //
- // The second kind is implemented in the following blocks.
- if (!isset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey])) {
- // INITIAL CALL
- // Calculate the hierarchy of template blocks and start on
- // the bottom level of the hierarchy (= "_<id>_<section>" block)
- $blockNameHierarchy = array();
- foreach ($view->vars['block_prefixes'] as $blockNamePrefix) {
- $blockNameHierarchy[] = $blockNamePrefix.'_'.$blockNameSuffix;
- }
- $hierarchyLevel = count($blockNameHierarchy) - 1;
-
- $hierarchyInit = true;
- } else {
- // RECURSIVE CALL
- // If a block recursively calls searchAndRenderBlock() again, resume rendering
- // using the parent type in the hierarchy.
- $blockNameHierarchy = $this->blockNameHierarchyMap[$viewAndSuffixCacheKey];
- $hierarchyLevel = $this->hierarchyLevelMap[$viewAndSuffixCacheKey] - 1;
-
- $hierarchyInit = false;
- }
-
- // The variables are cached globally for a view (instead of for the
- // current suffix)
- if (!isset($this->variableStack[$viewCacheKey])) {
- $this->variableStack[$viewCacheKey] = array();
-
- // The default variable scope contains all view variables, merged with
- // the variables passed explicitly to the helper
- $scopeVariables = $view->vars;
-
- $varInit = true;
- } else {
- // Reuse the current scope and merge it with the explicitly passed variables
- $scopeVariables = end($this->variableStack[$viewCacheKey]);
-
- $varInit = false;
- }
-
- // Load the resource where this block can be found
- $resource = $this->engine->getResourceForBlockNameHierarchy($view, $blockNameHierarchy, $hierarchyLevel);
-
- // Update the current hierarchy level to the one at which the resource was
- // found. For example, if looking for "choice_widget", but only a resource
- // is found for its parent "form_widget", then the level is updated here
- // to the parent level.
- $hierarchyLevel = $this->engine->getResourceHierarchyLevel($view, $blockNameHierarchy, $hierarchyLevel);
-
- // The actually existing block name in $resource
- $blockName = $blockNameHierarchy[$hierarchyLevel];
-
- // Escape if no resource exists for this block
- if (!$resource) {
- throw new LogicException(sprintf(
- 'Unable to render the form as none of the following blocks exist: "%s".',
- implode('", "', array_reverse($blockNameHierarchy))
- ));
- }
-
- // Merge the passed with the existing attributes
- if (isset($variables['attr']) && isset($scopeVariables['attr'])) {
- $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']);
- }
-
- // Merge the passed with the exist *label* attributes
- if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) {
- $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']);
- }
-
- // Do not use array_replace_recursive(), otherwise array variables
- // cannot be overwritten
- $variables = array_replace($scopeVariables, $variables);
-
- // In order to make recursive calls possible, we need to store the block hierarchy,
- // the current level of the hierarchy and the variables so that this method can
- // resume rendering one level higher of the hierarchy when it is called recursively.
- //
- // We need to store these values in maps (associative arrays) because within a
- // call to widget() another call to widget() can be made, but for a different view
- // object. These nested calls should not override each other.
- $this->blockNameHierarchyMap[$viewAndSuffixCacheKey] = $blockNameHierarchy;
- $this->hierarchyLevelMap[$viewAndSuffixCacheKey] = $hierarchyLevel;
-
- // We also need to store the variables for the view so that we can render other
- // blocks for the same view using the same variables as in the outer block.
- $this->variableStack[$viewCacheKey][] = $variables;
-
- // Do the rendering
- $html = $this->engine->renderBlock($view, $resource, $blockName, $variables);
-
- // Clear the stack
- array_pop($this->variableStack[$viewCacheKey]);
-
- // Clear the caches if they were filled for the first time within
- // this function call
- if ($hierarchyInit) {
- unset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey]);
- unset($this->hierarchyLevelMap[$viewAndSuffixCacheKey]);
- }
-
- if ($varInit) {
- unset($this->variableStack[$viewCacheKey]);
- }
-
- if ($renderOnlyOnce) {
- $view->setRendered();
- }
-
- return $html;
- }
-
- /**
- * {@inheritdoc}
- */
- public function humanize($text)
- {
- return ucfirst(trim(strtolower(preg_replace(array('/([A-Z])/', '/[_\s]+/'), array('_$1', ' '), $text))));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Adapter for rendering form templates with a specific templating engine.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormRendererEngineInterface
-{
- /**
- * Sets the theme(s) to be used for rendering a view and its children.
- *
- * @param FormView $view The view to assign the theme(s) to.
- * @param mixed $themes The theme(s). The type of these themes
- * is open to the implementation.
- */
- public function setTheme(FormView $view, $themes);
-
- /**
- * Returns the resource for a block name.
- *
- * The resource is first searched in the themes attached to $view, then
- * in the themes of its parent view and so on, until a resource was found.
- *
- * The type of the resource is decided by the implementation. The resource
- * is later passed to {@link renderBlock()} by the rendering algorithm.
- *
- * @param FormView $view The view for determining the used themes.
- * First the themes attached directly to the
- * view with {@link setTheme()} are considered,
- * then the ones of its parent etc.
- * @param string $blockName The name of the block to render.
- *
- * @return mixed The renderer resource or false, if none was found.
- */
- public function getResourceForBlockName(FormView $view, $blockName);
-
- /**
- * Returns the resource for a block hierarchy.
- *
- * A block hierarchy is an array which starts with the root of the hierarchy
- * and continues with the child of that root, the child of that child etc.
- * The following is an example for a block hierarchy:
- *
- * <code>
- * form_widget
- * text_widget
- * url_widget
- * </code>
- *
- * In this example, "url_widget" is the most specific block, while the other
- * blocks are its ancestors in the hierarchy.
- *
- * The second parameter $hierarchyLevel determines the level of the hierarchy
- * that should be rendered. For example, if $hierarchyLevel is 2 for the
- * above hierarchy, the engine will first look for the block "url_widget",
- * then, if that does not exist, for the block "text_widget" etc.
- *
- * The type of the resource is decided by the implementation. The resource
- * is later passed to {@link renderBlock()} by the rendering algorithm.
- *
- * @param FormView $view The view for determining the
- * used themes. First the themes
- * attached directly to the view
- * with {@link setTheme()} are
- * considered, then the ones of
- * its parent etc.
- * @param array $blockNameHierarchy The block name hierarchy, with
- * the root block at the beginning.
- * @param integer $hierarchyLevel The level in the hierarchy at
- * which to start looking. Level 0
- * indicates the root block, i.e.
- * the first element of
- * $blockNameHierarchy.
- *
- * @return mixed The renderer resource or false, if none was found.
- */
- public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, $hierarchyLevel);
-
- /**
- * Returns the hierarchy level at which a resource can be found.
- *
- * A block hierarchy is an array which starts with the root of the hierarchy
- * and continues with the child of that root, the child of that child etc.
- * The following is an example for a block hierarchy:
- *
- * <code>
- * form_widget
- * text_widget
- * url_widget
- * </code>
- *
- * The second parameter $hierarchyLevel determines the level of the hierarchy
- * that should be rendered.
- *
- * If we call this method with the hierarchy level 2, the engine will first
- * look for a resource for block "url_widget". If such a resource exists,
- * the method returns 2. Otherwise it tries to find a resource for block
- * "text_widget" (at level 1) and, again, returns 1 if a resource was found.
- * The method continues to look for resources until the root level was
- * reached and nothing was found. In this case false is returned.
- *
- * The type of the resource is decided by the implementation. The resource
- * is later passed to {@link renderBlock()} by the rendering algorithm.
- *
- * @param FormView $view The view for determining the
- * used themes. First the themes
- * attached directly to the view
- * with {@link setTheme()} are
- * considered, then the ones of
- * its parent etc.
- * @param array $blockNameHierarchy The block name hierarchy, with
- * the root block at the beginning.
- * @param integer $hierarchyLevel The level in the hierarchy at
- * which to start looking. Level 0
- * indicates the root block, i.e.
- * the first element of
- * $blockNameHierarchy.
- *
- * @return integer|Boolean The hierarchy level or false, if no resource was found.
- */
- public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, $hierarchyLevel);
-
- /**
- * Renders a block in the given renderer resource.
- *
- * The resource can be obtained by calling {@link getResourceForBlock()}
- * or {@link getResourceForBlockHierarchy()}. The type of the resource is
- * decided by the implementation.
- *
- * @param FormView $view The view to render.
- * @param mixed $resource The renderer resource.
- * @param string $blockName The name of the block to render.
- * @param array $variables The variables to pass to the template.
- *
- * @return string The HTML markup.
- */
- public function renderBlock(FormView $view, $resource, $blockName, array $variables = array());
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Renders a form into HTML.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormRendererInterface
-{
- /**
- * Returns the engine used by this renderer.
- *
- * @return FormRendererEngineInterface The renderer engine.
- */
- public function getEngine();
-
- /**
- * Sets the theme(s) to be used for rendering a view and its children.
- *
- * @param FormView $view The view to assign the theme(s) to.
- * @param mixed $themes The theme(s). The type of these themes
- * is open to the implementation.
- */
- public function setTheme(FormView $view, $themes);
-
- /**
- * Renders a named block of the form theme.
- *
- * @param FormView $view The view for which to render the block.
- * @param string $blockName The name of the block.
- * @param array $variables The variables to pass to the template.
- *
- * @return string The HTML markup
- */
- public function renderBlock(FormView $view, $blockName, array $variables = array());
-
- /**
- * Searches and renders a block for a given name suffix.
- *
- * The block is searched by combining the block names stored in the
- * form view with the given suffix. If a block name is found, that
- * block is rendered.
- *
- * If this method is called recursively, the block search is continued
- * where a block was found before.
- *
- * @param FormView $view The view for which to render the block.
- * @param string $blockNameSuffix The suffix of the block name.
- * @param array $variables The variables to pass to the template.
- *
- * @return string The HTML markup
- */
- public function searchAndRenderBlock(FormView $view, $blockNameSuffix, array $variables = array());
-
- /**
- * Renders a CSRF token.
- *
- * Use this helper for CSRF protection without the overhead of creating a
- * form.
- *
- * <code>
- * <input type="hidden" name="token" value="<?php $renderer->renderCsrfToken('rm_user_'.$user->getId()) ?>">
- * </code>
- *
- * Check the token in your action using the same intention.
- *
- * <code>
- * $csrfProvider = $this->get('form.csrf_provider');
- * if (!$csrfProvider->isCsrfTokenValid('rm_user_'.$user->getId(), $token)) {
- * throw new \RuntimeException('CSRF attack detected.');
- * }
- * </code>
- *
- * @param string $intention The intention of the protected action
- *
- * @return string A CSRF token
- */
- public function renderCsrfToken($intention);
-
- /**
- * Makes a technical name human readable.
- *
- * Sequences of underscores are replaced by single spaces. The first letter
- * of the resulting string is capitalized, while all other letters are
- * turned to lowercase.
- *
- * @param string $text The text to humanize.
- *
- * @return string The humanized text.
- */
- public function humanize($text);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormTypeExtensionInterface
-{
- /**
- * Builds the form.
- *
- * This method is called after the extended type has built the form to
- * further modify it.
- *
- * @see FormTypeInterface::buildForm()
- *
- * @param FormBuilderInterface $builder The form builder
- * @param array $options The options
- */
- public function buildForm(FormBuilderInterface $builder, array $options);
-
- /**
- * Builds the view.
- *
- * This method is called after the extended type has built the view to
- * further modify it.
- *
- * @see FormTypeInterface::buildView()
- *
- * @param FormView $view The view
- * @param FormInterface $form The form
- * @param array $options The options
- */
- public function buildView(FormView $view, FormInterface $form, array $options);
-
- /**
- * Finishes the view.
- *
- * This method is called after the extended type has finished the view to
- * further modify it.
- *
- * @see FormTypeInterface::finishView()
- *
- * @param FormView $view The view
- * @param FormInterface $form The form
- * @param array $options The options
- */
- public function finishView(FormView $view, FormInterface $form, array $options);
-
- /**
- * Overrides the default options from the extended type.
- *
- * @param OptionsResolverInterface $resolver The resolver for the options.
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver);
-
- /**
- * Returns the name of the type being extended.
- *
- * @return string The name of the type being extended
- */
- public function getExtendedType();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Guess\Guess;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-
-class FormTypeGuesserChain implements FormTypeGuesserInterface
-{
- private $guessers = array();
-
- /**
- * Constructor.
- *
- * @param array $guessers Guessers as instances of FormTypeGuesserInterface
- *
- * @throws UnexpectedTypeException if any guesser does not implement FormTypeGuesserInterface
- */
- public function __construct(array $guessers)
- {
- foreach ($guessers as $guesser) {
- if (!$guesser instanceof FormTypeGuesserInterface) {
- throw new UnexpectedTypeException($guesser, 'Symfony\Component\Form\FormTypeGuesserInterface');
- }
-
- if ($guesser instanceof self) {
- $this->guessers = array_merge($this->guessers, $guesser->guessers);
- } else {
- $this->guessers[] = $guesser;
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessType($class, $property)
- {
- return $this->guess(function ($guesser) use ($class, $property) {
- return $guesser->guessType($class, $property);
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessRequired($class, $property)
- {
- return $this->guess(function ($guesser) use ($class, $property) {
- return $guesser->guessRequired($class, $property);
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessMaxLength($class, $property)
- {
- return $this->guess(function ($guesser) use ($class, $property) {
- return $guesser->guessMaxLength($class, $property);
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public function guessPattern($class, $property)
- {
- return $this->guess(function ($guesser) use ($class, $property) {
- return $guesser->guessPattern($class, $property);
- });
- }
-
- /**
- * Executes a closure for each guesser and returns the best guess from the
- * return values
- *
- * @param \Closure $closure The closure to execute. Accepts a guesser
- * as argument and should return a Guess instance
- *
- * @return Guess The guess with the highest confidence
- */
- private function guess(\Closure $closure)
- {
- $guesses = array();
-
- foreach ($this->guessers as $guesser) {
- if ($guess = $closure($guesser)) {
- $guesses[] = $guess;
- }
- }
-
- return Guess::getBestGuess($guesses);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormTypeGuesserInterface
-{
- /**
- * Returns a field guess for a property name of a class
- *
- * @param string $class The fully qualified class name
- * @param string $property The name of the property to guess for
- *
- * @return Guess\TypeGuess A guess for the field's type and options
- */
- public function guessType($class, $property);
-
- /**
- * Returns a guess whether a property of a class is required
- *
- * @param string $class The fully qualified class name
- * @param string $property The name of the property to guess for
- *
- * @return Guess\Guess A guess for the field's required setting
- */
- public function guessRequired($class, $property);
-
- /**
- * Returns a guess about the field's maximum length
- *
- * @param string $class The fully qualified class name
- * @param string $property The name of the property to guess for
- *
- * @return Guess\Guess A guess for the field's maximum length
- */
- public function guessMaxLength($class, $property);
-
- /**
- * Returns a guess about the field's pattern
- *
- * - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below
- * - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess.
- * Example:
- * You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5)
- * @link https://github.com/symfony/symfony/pull/3927
- *
- * @param string $class The fully qualified class name
- * @param string $property The name of the property to guess for
- *
- * @return Guess\Guess A guess for the field's required pattern
- */
- public function guessPattern($class, $property);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface FormTypeInterface
-{
- /**
- * Builds the form.
- *
- * This method is called for each type in the hierarchy starting form the
- * top most type. Type extensions can further modify the form.
- *
- * @see FormTypeExtensionInterface::buildForm()
- *
- * @param FormBuilderInterface $builder The form builder
- * @param array $options The options
- */
- public function buildForm(FormBuilderInterface $builder, array $options);
-
- /**
- * Builds the form view.
- *
- * This method is called for each type in the hierarchy starting form the
- * top most type. Type extensions can further modify the view.
- *
- * A view of a form is built before the views of the child forms are built.
- * This means that you cannot access child views in this method. If you need
- * to do so, move your logic to {@link finishView()} instead.
- *
- * @see FormTypeExtensionInterface::buildView()
- *
- * @param FormView $view The view
- * @param FormInterface $form The form
- * @param array $options The options
- */
- public function buildView(FormView $view, FormInterface $form, array $options);
-
- /**
- * Finishes the form view.
- *
- * This method gets called for each type in the hierarchy starting form the
- * top most type. Type extensions can further modify the view.
- *
- * When this method is called, views of the form's children have already
- * been built and finished and can be accessed. You should only implement
- * such logic in this method that actually accesses child views. For everything
- * else you are recommended to implement {@link buildView()} instead.
- *
- * @see FormTypeExtensionInterface::finishView()
- *
- * @param FormView $view The view
- * @param FormInterface $form The form
- * @param array $options The options
- */
- public function finishView(FormView $view, FormInterface $form, array $options);
-
- /**
- * Sets the default options for this type.
- *
- * @param OptionsResolverInterface $resolver The resolver for the options.
- */
- public function setDefaultOptions(OptionsResolverInterface $resolver);
-
- /**
- * Returns the name of the parent type.
- *
- * You can also return a type instance from this method, although doing so
- * is discouraged because it leads to a performance penalty. The support
- * for returning type instances may be dropped from future releases.
- *
- * @return string|null|FormTypeInterface The name of the parent type if any, null otherwise.
- */
- public function getParent();
-
- /**
- * Returns the name of this type.
- *
- * @return string The name of this type
- */
- public function getName();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\BadMethodCallException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
-{
- /**
- * The variables assigned to this view.
- * @var array
- */
- public $vars = array(
- 'value' => null,
- 'attr' => array(),
- );
-
- /**
- * The parent view.
- * @var FormView
- */
- public $parent;
-
- /**
- * The child views.
- * @var array
- */
- public $children = array();
-
- /**
- * Is the form attached to this renderer rendered?
- *
- * Rendering happens when either the widget or the row method was called.
- * Row implicitly includes widget, however certain rendering mechanisms
- * have to skip widget rendering when a row is rendered.
- *
- * @var Boolean
- */
- private $rendered = false;
-
- public function __construct(FormView $parent = null)
- {
- $this->parent = $parent;
- }
-
- /**
- * Returns whether the view was already rendered.
- *
- * @return Boolean Whether this view's widget is rendered.
- */
- public function isRendered()
- {
- $hasChildren = 0 < count($this->children);
-
- if (true === $this->rendered || !$hasChildren) {
- return $this->rendered;
- }
-
- if ($hasChildren) {
- foreach ($this->children as $child) {
- if (!$child->isRendered()) {
- return false;
- }
- }
-
- return $this->rendered = true;
- }
-
- return false;
- }
-
- /**
- * Marks the view as rendered.
- *
- * @return FormView The view object.
- */
- public function setRendered()
- {
- $this->rendered = true;
-
- return $this;
- }
-
- /**
- * Returns a child by name (implements \ArrayAccess).
- *
- * @param string $name The child name
- *
- * @return FormView The child view
- */
- public function offsetGet($name)
- {
- return $this->children[$name];
- }
-
- /**
- * Returns whether the given child exists (implements \ArrayAccess).
- *
- * @param string $name The child name
- *
- * @return Boolean Whether the child view exists
- */
- public function offsetExists($name)
- {
- return isset($this->children[$name]);
- }
-
- /**
- * Implements \ArrayAccess.
- *
- * @throws BadMethodCallException always as setting a child by name is not allowed
- */
- public function offsetSet($name, $value)
- {
- throw new BadMethodCallException('Not supported');
- }
-
- /**
- * Removes a child (implements \ArrayAccess).
- *
- * @param string $name The child name
- */
- public function offsetUnset($name)
- {
- unset($this->children[$name]);
- }
-
- /**
- * Returns an iterator to iterate over children (implements \IteratorAggregate)
- *
- * @return \ArrayIterator The iterator
- */
- public function getIterator()
- {
- return new \ArrayIterator($this->children);
- }
-
- /**
- * Implements \Countable.
- *
- * @return integer The number of children views
- */
- public function count()
- {
- return count($this->children);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Extension\Core\CoreExtension;
-
-/**
- * Entry point of the Form component.
- *
- * Use this class to conveniently create new form factories:
- *
- * <code>
- * use Symfony\Component\Form\Forms;
- *
- * $formFactory = Forms::createFormFactory();
- *
- * $form = $formFactory->createBuilder()
- * ->add('firstName', 'text')
- * ->add('lastName', 'text')
- * ->add('age', 'integer')
- * ->add('gender', 'choice', array(
- * 'choices' => array('m' => 'Male', 'f' => 'Female'),
- * ))
- * ->getForm();
- * </code>
- *
- * You can also add custom extensions to the form factory:
- *
- * <code>
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addExtension(new AcmeExtension())
- * ->getFormFactory();
- * </code>
- *
- * If you create custom form types or type extensions, it is
- * generally recommended to create your own extensions that lazily
- * load these types and type extensions. In projects where performance
- * does not matter that much, you can also pass them directly to the
- * form factory:
- *
- * <code>
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addType(new PersonType())
- * ->addType(new PhoneNumberType())
- * ->addTypeExtension(new FormTypeHelpTextExtension())
- * ->getFormFactory();
- * </code>
- *
- * Support for CSRF protection is provided by the CsrfExtension.
- * This extension needs a CSRF provider with a strong secret
- * (e.g. a 20 character long random string). The default
- * implementation for this is DefaultCsrfProvider:
- *
- * <code>
- * use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
- * use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider;
- *
- * $secret = 'V8a5Z97e...';
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addExtension(new CsrfExtension(new DefaultCsrfProvider($secret)))
- * ->getFormFactory();
- * </code>
- *
- * Support for the HttpFoundation is provided by the
- * HttpFoundationExtension. You are also advised to load the CSRF
- * extension with the driver for HttpFoundation's Session class:
- *
- * <code>
- * use Symfony\Component\HttpFoundation\Session\Session;
- * use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension;
- * use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
- * use Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider;
- *
- * $session = new Session();
- * $secret = 'V8a5Z97e...';
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addExtension(new HttpFoundationExtension())
- * ->addExtension(new CsrfExtension(new SessionCsrfProvider($session, $secret)))
- * ->getFormFactory();
- * </code>
- *
- * Support for the Validator component is provided by ValidatorExtension.
- * This extension needs a validator object to function properly:
- *
- * <code>
- * use Symfony\Component\Validator\Validation;
- * use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
- *
- * $validator = Validation::createValidator();
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addExtension(new ValidatorExtension($validator))
- * ->getFormFactory();
- * </code>
- *
- * Support for the Templating component is provided by TemplatingExtension.
- * This extension needs a PhpEngine object for rendering forms. As second
- * argument you should pass the names of the default themes. Here is an
- * example for using the default layout with "<div>" tags:
- *
- * <code>
- * use Symfony\Component\Form\Extension\Templating\TemplatingExtension;
- *
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addExtension(new TemplatingExtension($engine, null, array(
- * 'FrameworkBundle:Form',
- * )))
- * ->getFormFactory();
- * </code>
- *
- * The next example shows how to include the "<table>" layout:
- *
- * <code>
- * use Symfony\Component\Form\Extension\Templating\TemplatingExtension;
- *
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addExtension(new TemplatingExtension($engine, null, array(
- * 'FrameworkBundle:Form',
- * 'FrameworkBundle:FormTable',
- * )))
- * ->getFormFactory();
- * </code>
- *
- * If you also loaded the CsrfExtension, you should pass the CSRF provider
- * to the extension so that you can render CSRF tokens in your templates
- * more easily:
- *
- * <code>
- * use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
- * use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider;
- * use Symfony\Component\Form\Extension\Templating\TemplatingExtension;
- *
- *
- * $secret = 'V8a5Z97e...';
- * $csrfProvider = new DefaultCsrfProvider($secret);
- * $formFactory = Forms::createFormFactoryBuilder()
- * ->addExtension(new CsrfExtension($csrfProvider))
- * ->addExtension(new TemplatingExtension($engine, $csrfProvider, array(
- * 'FrameworkBundle:Form',
- * )))
- * ->getFormFactory();
- * </code>
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-final class Forms
-{
- /**
- * Creates a form factory with the default configuration.
- *
- * @return FormFactoryInterface The form factory.
- */
- public static function createFormFactory()
- {
- return self::createFormFactoryBuilder()->getFormFactory();
- }
-
- /**
- * Creates a form factory builder with the default configuration.
- *
- * @return FormFactoryBuilderInterface The form factory builder.
- */
- public static function createFormFactoryBuilder()
- {
- $builder = new FormFactoryBuilder();
- $builder->addExtension(new CoreExtension());
-
- return $builder;
- }
-
- /**
- * This class cannot be instantiated.
- */
- private function __construct()
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Guess;
-
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-
-/**
- * Base class for guesses made by TypeGuesserInterface implementation
- *
- * Each instance contains a confidence value about the correctness of the guess.
- * Thus an instance with confidence HIGH_CONFIDENCE is more likely to be
- * correct than an instance with confidence LOW_CONFIDENCE.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class Guess
-{
- /**
- * Marks an instance with a value that is extremely likely to be correct
- * @var integer
- */
- const VERY_HIGH_CONFIDENCE = 3;
-
- /**
- * Marks an instance with a value that is very likely to be correct
- * @var integer
- */
- const HIGH_CONFIDENCE = 2;
-
- /**
- * Marks an instance with a value that is likely to be correct
- * @var integer
- */
- const MEDIUM_CONFIDENCE = 1;
-
- /**
- * Marks an instance with a value that may be correct
- * @var integer
- */
- const LOW_CONFIDENCE = 0;
-
- /**
- * The confidence about the correctness of the value
- *
- * One of VERY_HIGH_CONFIDENCE, HIGH_CONFIDENCE, MEDIUM_CONFIDENCE
- * and LOW_CONFIDENCE.
- *
- * @var integer
- */
- private $confidence;
-
- /**
- * Returns the guess most likely to be correct from a list of guesses
- *
- * If there are multiple guesses with the same, highest confidence, the
- * returned guess is any of them.
- *
- * @param array $guesses A list of guesses
- *
- * @return Guess The guess with the highest confidence
- */
- public static function getBestGuess(array $guesses)
- {
- $result = null;
- $maxConfidence = -1;
-
- foreach ($guesses as $guess) {
- if ($maxConfidence < $confidence = $guess->getConfidence()) {
- $maxConfidence = $confidence;
- $result = $guess;
- }
- }
-
- return $result;
- }
-
- /**
- * Constructor
- *
- * @param integer $confidence The confidence
- *
- * @throws InvalidArgumentException if the given value of confidence is unknown
- */
- public function __construct($confidence)
- {
- if (self::VERY_HIGH_CONFIDENCE !== $confidence && self::HIGH_CONFIDENCE !== $confidence &&
- self::MEDIUM_CONFIDENCE !== $confidence && self::LOW_CONFIDENCE !== $confidence) {
- throw new InvalidArgumentException('The confidence should be one of the constants defined in Guess.');
- }
-
- $this->confidence = $confidence;
- }
-
- /**
- * Returns the confidence that the guessed value is correct
- *
- * @return integer One of the constants VERY_HIGH_CONFIDENCE,
- * HIGH_CONFIDENCE, MEDIUM_CONFIDENCE and LOW_CONFIDENCE
- */
- public function getConfidence()
- {
- return $this->confidence;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Guess;
-
-/**
- * Contains a guessed class name and a list of options for creating an instance
- * of that class
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class TypeGuess extends Guess
-{
- /**
- * The guessed field type
- * @var string
- */
- private $type;
-
- /**
- * The guessed options for creating an instance of the guessed class
- * @var array
- */
- private $options;
-
- /**
- * Constructor
- *
- * @param string $type The guessed field type
- * @param array $options The options for creating instances of the
- * guessed class
- * @param integer $confidence The confidence that the guessed class name
- * is correct
- */
- public function __construct($type, array $options, $confidence)
- {
- parent::__construct($confidence);
-
- $this->type = $type;
- $this->options = $options;
- }
-
- /**
- * Returns the guessed field type
- *
- * @return string
- */
- public function getType()
- {
- return $this->type;
- }
-
- /**
- * Returns the guessed options for creating instances of the guessed type
- *
- * @return array
- */
- public function getOptions()
- {
- return $this->options;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Guess;
-
-/**
- * Contains a guessed value
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ValueGuess extends Guess
-{
- /**
- * The guessed value
- * @var array
- */
- private $value;
-
- /**
- * Constructor
- *
- * @param string $value The guessed value
- * @param integer $confidence The confidence that the guessed class name
- * is correct
- */
- public function __construct($value, $confidence)
- {
- parent::__construct($confidence);
-
- $this->value = $value;
- }
-
- /**
- * Returns the guessed value
- *
- * @return mixed
- */
- public function getValue()
- {
- return $this->value;
- }
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\RequestHandlerInterface;
-
-/**
- * A request handler using PHP's super globals $_GET, $_POST and $_SERVER.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class NativeRequestHandler implements RequestHandlerInterface
-{
- /**
- * The allowed keys of the $_FILES array.
- *
- * @var array
- */
- private static $fileKeys = array(
- 'error',
- 'name',
- 'size',
- 'tmp_name',
- 'type',
- );
-
- /**
- * {@inheritdoc}
- */
- public function handleRequest(FormInterface $form, $request = null)
- {
- if (null !== $request) {
- throw new UnexpectedTypeException($request, 'null');
- }
-
- $name = $form->getName();
- $method = $form->getConfig()->getMethod();
-
- if ($method !== self::getRequestMethod()) {
- return;
- }
-
- if ('GET' === $method) {
- if ('' === $name) {
- $data = $_GET;
- } else {
- // Don't submit GET requests if the form's name does not exist
- // in the request
- if (!isset($_GET[$name])) {
- return;
- }
-
- $data = $_GET[$name];
- }
- } else {
- $fixedFiles = array();
- foreach ($_FILES as $name => $file) {
- $fixedFiles[$name] = self::stripEmptyFiles(self::fixPhpFilesArray($file));
- }
-
- if ('' === $name) {
- $params = $_POST;
- $files = $fixedFiles;
- } else {
- $default = $form->getConfig()->getCompound() ? array() : null;
- $params = isset($_POST[$name]) ? $_POST[$name] : $default;
- $files = isset($fixedFiles[$name]) ? $fixedFiles[$name] : $default;
- }
-
- if (is_array($params) && is_array($files)) {
- $data = array_replace_recursive($params, $files);
- } else {
- $data = $params ?: $files;
- }
- }
-
- // Don't auto-submit the form unless at least one field is present.
- if ('' === $name && count(array_intersect_key($data, $form->all())) <= 0) {
- return;
- }
-
- $form->submit($data, 'PATCH' !== $method);
- }
-
- /**
- * Returns the method used to submit the request to the server.
- *
- * @return string The request method.
- */
- private static function getRequestMethod()
- {
- $method = isset($_SERVER['REQUEST_METHOD'])
- ? strtoupper($_SERVER['REQUEST_METHOD'])
- : 'GET';
-
- if ('POST' === $method && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
- $method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
- }
-
- return $method;
- }
-
- /**
- * Fixes a malformed PHP $_FILES array.
- *
- * PHP has a bug that the format of the $_FILES array differs, depending on
- * whether the uploaded file fields had normal field names or array-like
- * field names ("normal" vs. "parent[child]").
- *
- * This method fixes the array to look like the "normal" $_FILES array.
- *
- * It's safe to pass an already converted array, in which case this method
- * just returns the original array unmodified.
- *
- * This method is identical to {@link Symfony\Component\HttpFoundation\FileBag::fixPhpFilesArray}
- * and should be kept as such in order to port fixes quickly and easily.
- *
- * @param array $data
- *
- * @return array
- */
- private static function fixPhpFilesArray($data)
- {
- if (!is_array($data)) {
- return $data;
- }
-
- $keys = array_keys($data);
- sort($keys);
-
- if (self::$fileKeys !== $keys || !isset($data['name']) || !is_array($data['name'])) {
- return $data;
- }
-
- $files = $data;
- foreach (self::$fileKeys as $k) {
- unset($files[$k]);
- }
-
- foreach (array_keys($data['name']) as $key) {
- $files[$key] = self::fixPhpFilesArray(array(
- 'error' => $data['error'][$key],
- 'name' => $data['name'][$key],
- 'type' => $data['type'][$key],
- 'tmp_name' => $data['tmp_name'][$key],
- 'size' => $data['size'][$key]
- ));
- }
-
- return $files;
- }
-
- /**
- * Sets empty uploaded files to NULL in the given uploaded files array.
- *
- * @param mixed $data The file upload data.
- *
- * @return array|null Returns the stripped upload data.
- */
- private static function stripEmptyFiles($data)
- {
- if (!is_array($data)) {
- return $data;
- }
-
- $keys = array_keys($data);
- sort($keys);
-
- if (self::$fileKeys === $keys) {
- if (UPLOAD_ERR_NO_FILE === $data['error']) {
- return null;
- }
-
- return $data;
- }
-
- foreach ($data as $key => $value) {
- $data[$key] = self::stripEmptyFiles($value);
- }
-
- return $data;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-
-/**
- * A form extension with preloaded types, type exceptions and type guessers.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PreloadedExtension implements FormExtensionInterface
-{
- /**
- * @var array
- */
- private $types = array();
-
- /**
- * @var array
- */
- private $typeExtensions = array();
-
- /**
- * @var FormTypeGuesserInterface
- */
- private $typeGuesser;
-
- /**
- * Creates a new preloaded extension.
- *
- * @param array $types The types that the extension should support.
- * @param array $typeExtensions The type extensions that the extension should support.
- * @param FormTypeGuesserInterface|null $typeGuesser The guesser that the extension should support.
- */
- public function __construct(array $types, array $typeExtensions, FormTypeGuesserInterface $typeGuesser = null)
- {
- $this->types = $types;
- $this->typeExtensions = $typeExtensions;
- $this->typeGuesser = $typeGuesser;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getType($name)
- {
- if (!isset($this->types[$name])) {
- throw new InvalidArgumentException(sprintf('The type "%s" can not be loaded by this extension', $name));
- }
-
- return $this->types[$name];
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasType($name)
- {
- return isset($this->types[$name]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeExtensions($name)
- {
- return isset($this->typeExtensions[$name])
- ? $this->typeExtensions[$name]
- : array();
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasTypeExtensions($name)
- {
- return !empty($this->typeExtensions[$name]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeGuesser()
- {
- return $this->typeGuesser;
- }
-}
+++ /dev/null
-Form Component
-==============
-
-Form provides tools for defining forms, rendering and mapping request data to
-related models. Furthermore it provides integration with the Validation
-component.
-
-Resources
----------
-
-Silex integration:
-
-https://github.com/fabpot/Silex/blob/master/src/Silex/Provider/FormServiceProvider.php
-
-Documentation:
-
-http://symfony.com/doc/2.3/book/forms.html
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/Form/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Submits forms if they were submitted.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface RequestHandlerInterface
-{
- /**
- * Submits a form if it was submitted.
- *
- * @param FormInterface $form The form to submit.
- * @param mixed $request The current request.
- */
- public function handleRequest(FormInterface $form, $request = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\OptionsResolver\OptionsResolver;
-
-/**
- * A wrapper for a form type and its extensions.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ResolvedFormType implements ResolvedFormTypeInterface
-{
- /**
- * @var FormTypeInterface
- */
- private $innerType;
-
- /**
- * @var array
- */
- private $typeExtensions;
-
- /**
- * @var ResolvedFormTypeInterface
- */
- private $parent;
-
- /**
- * @var OptionsResolver
- */
- private $optionsResolver;
-
- public function __construct(FormTypeInterface $innerType, array $typeExtensions = array(), ResolvedFormTypeInterface $parent = null)
- {
- if (!preg_match('/^[a-z0-9_]*$/i', $innerType->getName())) {
- throw new InvalidArgumentException(sprintf(
- 'The "%s" form type name ("%s") is not valid. Names must only contain letters, numbers, and "_".',
- get_class($innerType),
- $innerType->getName()
- ));
- }
-
- foreach ($typeExtensions as $extension) {
- if (!$extension instanceof FormTypeExtensionInterface) {
- throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
- }
- }
-
- $this->innerType = $innerType;
- $this->typeExtensions = $typeExtensions;
- $this->parent = $parent;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return $this->innerType->getName();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- return $this->parent;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getInnerType()
- {
- return $this->innerType;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeExtensions()
- {
- // BC
- if ($this->innerType instanceof AbstractType) {
- return $this->innerType->getExtensions();
- }
-
- return $this->typeExtensions;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createBuilder(FormFactoryInterface $factory, $name, array $options = array())
- {
- $options = $this->getOptionsResolver()->resolve($options);
-
- // Should be decoupled from the specific option at some point
- $dataClass = isset($options['data_class']) ? $options['data_class'] : null;
-
- $builder = $this->newBuilder($name, $dataClass, $factory, $options);
- $builder->setType($this);
-
- $this->buildForm($builder, $options);
-
- return $builder;
- }
-
- /**
- * {@inheritdoc}
- */
- public function createView(FormInterface $form, FormView $parent = null)
- {
- $options = $form->getConfig()->getOptions();
-
- $view = $this->newView($parent);
-
- $this->buildView($view, $form, $options);
-
- foreach ($form as $name => $child) {
- /* @var FormInterface $child */
- $view->children[$name] = $child->createView($view);
- }
-
- $this->finishView($view, $form, $options);
-
- return $view;
- }
-
- /**
- * Configures a form builder for the type hierarchy.
- *
- * This method is protected in order to allow implementing classes
- * to change or call it in re-implementations of {@link createBuilder()}.
- *
- * @param FormBuilderInterface $builder The builder to configure.
- * @param array $options The options used for the configuration.
- */
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- if (null !== $this->parent) {
- $this->parent->buildForm($builder, $options);
- }
-
- $this->innerType->buildForm($builder, $options);
-
- foreach ($this->typeExtensions as $extension) {
- /* @var FormTypeExtensionInterface $extension */
- $extension->buildForm($builder, $options);
- }
- }
-
- /**
- * Configures a form view for the type hierarchy.
- *
- * This method is protected in order to allow implementing classes
- * to change or call it in re-implementations of {@link createView()}.
- *
- * It is called before the children of the view are built.
- *
- * @param FormView $view The form view to configure.
- * @param FormInterface $form The form corresponding to the view.
- * @param array $options The options used for the configuration.
- */
- public function buildView(FormView $view, FormInterface $form, array $options)
- {
- if (null !== $this->parent) {
- $this->parent->buildView($view, $form, $options);
- }
-
- $this->innerType->buildView($view, $form, $options);
-
- foreach ($this->typeExtensions as $extension) {
- /* @var FormTypeExtensionInterface $extension */
- $extension->buildView($view, $form, $options);
- }
- }
-
- /**
- * Finishes a form view for the type hierarchy.
- *
- * This method is protected in order to allow implementing classes
- * to change or call it in re-implementations of {@link createView()}.
- *
- * It is called after the children of the view have been built.
- *
- * @param FormView $view The form view to configure.
- * @param FormInterface $form The form corresponding to the view.
- * @param array $options The options used for the configuration.
- */
- public function finishView(FormView $view, FormInterface $form, array $options)
- {
- if (null !== $this->parent) {
- $this->parent->finishView($view, $form, $options);
- }
-
- $this->innerType->finishView($view, $form, $options);
-
- foreach ($this->typeExtensions as $extension) {
- /* @var FormTypeExtensionInterface $extension */
- $extension->finishView($view, $form, $options);
- }
- }
-
- /**
- * Returns the configured options resolver used for this type.
- *
- * This method is protected in order to allow implementing classes
- * to change or call it in re-implementations of {@link createBuilder()}.
- *
- * @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
- */
- public function getOptionsResolver()
- {
- if (null === $this->optionsResolver) {
- if (null !== $this->parent) {
- $this->optionsResolver = clone $this->parent->getOptionsResolver();
- } else {
- $this->optionsResolver = new OptionsResolver();
- }
-
- $this->innerType->setDefaultOptions($this->optionsResolver);
-
- foreach ($this->typeExtensions as $extension) {
- /* @var FormTypeExtensionInterface $extension */
- $extension->setDefaultOptions($this->optionsResolver);
- }
- }
-
- return $this->optionsResolver;
- }
-
- /**
- * Creates a new builder instance.
- *
- * Override this method if you want to customize the builder class.
- *
- * @param string $name The name of the builder.
- * @param string $dataClass The data class.
- * @param FormFactoryInterface $factory The current form factory.
- * @param array $options The builder options.
- *
- * @return FormBuilderInterface The new builder instance.
- */
- protected function newBuilder($name, $dataClass, FormFactoryInterface $factory, array $options)
- {
- if ($this->innerType instanceof ButtonTypeInterface) {
- return new ButtonBuilder($name, $options);
- }
-
- if ($this->innerType instanceof SubmitButtonTypeInterface) {
- return new SubmitButtonBuilder($name, $options);
- }
-
- return new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options);
- }
-
- /**
- * Creates a new view instance.
- *
- * Override this method if you want to customize the view class.
- *
- * @param FormView|null $parent The parent view, if available.
- *
- * @return FormView A new view instance.
- */
- protected function newView(FormView $parent = null)
- {
- return new FormView($parent);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ResolvedFormTypeFactory implements ResolvedFormTypeFactoryInterface
-{
- /**
- * {@inheritdoc}
- */
- public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null)
- {
- return new ResolvedFormType($type, $typeExtensions, $parent);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Creates ResolvedFormTypeInterface instances.
- *
- * This interface allows you to use your custom ResolvedFormTypeInterface
- * implementation, within which you can customize the concrete FormBuilderInterface
- * implementations or FormView subclasses that are used by the framework.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ResolvedFormTypeFactoryInterface
-{
- /**
- * Resolves a form type.
- *
- * @param FormTypeInterface $type
- * @param array $typeExtensions
- * @param ResolvedFormTypeInterface $parent
- *
- * @return ResolvedFormTypeInterface
- *
- * @throws Exception\UnexpectedTypeException if the types parent {@link FormTypeInterface::getParent()} is not a string
- * @throws Exception\InvalidArgumentException if the types parent can not be retrieved from any extension
- */
- public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A wrapper for a form type and its extensions.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ResolvedFormTypeInterface
-{
- /**
- * Returns the name of the type.
- *
- * @return string The type name.
- */
- public function getName();
-
- /**
- * Returns the parent type.
- *
- * @return ResolvedFormTypeInterface The parent type or null.
- */
- public function getParent();
-
- /**
- * Returns the wrapped form type.
- *
- * @return FormTypeInterface The wrapped form type.
- */
- public function getInnerType();
-
- /**
- * Returns the extensions of the wrapped form type.
- *
- * @return FormTypeExtensionInterface[] An array of {@link FormTypeExtensionInterface} instances.
- */
- public function getTypeExtensions();
-
- /**
- * Creates a new form builder for this type.
- *
- * @param FormFactoryInterface $factory The form factory.
- * @param string $name The name for the builder.
- * @param array $options The builder options.
- *
- * @return FormBuilderInterface The created form builder.
- */
- public function createBuilder(FormFactoryInterface $factory, $name, array $options = array());
-
- /**
- * Creates a new form view for a form of this type.
- *
- * @param FormInterface $form The form to create a view for.
- * @param FormView $parent The parent view or null.
- *
- * @return FormView The created form view.
- */
- public function createView(FormInterface $form, FormView $parent = null);
-
- /**
- * Configures a form builder for the type hierarchy.
- *
- * @param FormBuilderInterface $builder The builder to configure.
- * @param array $options The options used for the configuration.
- */
- public function buildForm(FormBuilderInterface $builder, array $options);
-
- /**
- * Configures a form view for the type hierarchy.
- *
- * It is called before the children of the view are built.
- *
- * @param FormView $view The form view to configure.
- * @param FormInterface $form The form corresponding to the view.
- * @param array $options The options used for the configuration.
- */
- public function buildView(FormView $view, FormInterface $form, array $options);
-
- /**
- * Finishes a form view for the type hierarchy.
- *
- * It is called after the children of the view have been built.
- *
- * @param FormView $view The form view to configure.
- * @param FormInterface $form The form corresponding to the view.
- * @param array $options The options used for the configuration.
- */
- public function finishView(FormView $view, FormInterface $form, array $options);
-
- /**
- * Returns the configured options resolver used for this type.
- *
- * @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
- */
- public function getOptionsResolver();
-}
+++ /dev/null
-<?xml version="1.0" ?>
-
-<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
-
- <class name="Symfony\Component\Form\Form">
- <constraint name="Symfony\Component\Form\Extension\Validator\Constraints\Form" />
- <property name="children">
- <constraint name="Valid" />
- </property>
- </class>
-</constraint-mapping>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>هذا النموذج يجب الا يحتوى على اى حقول اضافية.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>مساحة الملف المرسل كبيرة. من فضلك حاول ارسال ملف اصغر.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>قيمة رمز الموقع غير صحيحة. من فضلك اعد ارسال النموذج.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>\r
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">\r
- <file source-language="en" datatype="plaintext" original="file.ext">\r
- <body>\r
- <trans-unit id="28">\r
- <source>This form should not contain extra fields.</source>\r
- <target>Тази форма не трябва да съдържа допълнителни полета.</target>\r
- </trans-unit>\r
- <trans-unit id="29">\r
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>\r
- <target>Каченият файл е твърде голям. Моля, опитайте да качите по-малък файл.</target>\r
- </trans-unit>\r
- <trans-unit id="30">\r
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>\r
- <target>Невалиден CSRF токен. Моля, опитайте да изпратите формата отново.</target>\r
- </trans-unit>\r
- </body>\r
- </file>\r
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Aquest formulari no hauria de contenir camps addicionals.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>L'arxiu pujat és massa gran. Per favor, pugi un arxiu més petit.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>El token CSRF no és vàlid. Per favor, provi d'enviar novament el formulari.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Tato skupina polí nesmí obsahovat další pole.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Nahraný soubor je příliš velký. Nahrajte prosím menší soubor.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF token je neplatný. Zkuste prosím znovu odeslat formulář.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Feltgruppen må ikke indeholde ekstra felter.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Den oploadede fil var for stor. Opload venligst en mindre fil.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF nøglen er ugyldig.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Dieses Formular sollte keine zusätzlichen Felder enthalten.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Die hochgeladene Datei ist zu groß. Versuchen Sie bitte eine kleinere Datei hochzuladen.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Das CSRF-Token ist ungültig. Versuchen Sie bitte das Formular erneut zu senden.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Αυτή η φόρμα δεν πρέπει να περιέχει επιπλέον πεδία.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Το αρχείο είναι πολύ μεγάλο. Παρακαλούμε προσπαθήστε να ανεβάσετε ένα μικρότερο αρχείο.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Το CSRF token δεν είναι έγκυρο. Παρακαλούμε δοκιμάστε να υποβάλετε τη φόρμα ξανά.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>This form should not contain extra fields.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>The uploaded file was too large. Please try to upload a smaller file.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>The CSRF token is invalid. Please try to resubmit the form.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Este formulario no debería contener campos adicionales.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>El archivo subido es demasiado grande. Por favor, suba un archivo más pequeño.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>El token CSRF no es válido. Por favor, pruebe de enviar nuevamente el formulario</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version='1.0'?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Väljade grupp ei tohiks sisalda lisaväljasid.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Üleslaaditud fail oli liiga suur. Palun proovi uuesti väiksema failiga.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF-märgis on vigane. Palun proovi vormi uuesti esitada.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Formulario honek ez luke aparteko eremurik eduki behar.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Igotako fitxategia handiegia da. Mesedez saiatu fitxategi txikiago bat igotzen.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid.</source>
- <target>CSFR tokena ez da egokia.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>این فرم نباید فیلد اضافی داشته باشد.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>فایل بارگذاری شده بسیار بزرگ است. لطفا فایل کوچکتری را بارگزاری کنید.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>مقدار CSRF نامعتبر است. لطفا فرم را مجددا ارسال فرمایید..</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This field group should not contain extra fields.</source>
- <target>Tämä kenttäryhmä ei voi sisältää ylimääräisiä kenttiä.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Ladattu tiedosto on liian iso. Ole hyvä ja lataa pienempi tiedosto.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF tarkiste on virheellinen. Olen hyvä ja yritä lähettää lomake uudestaan.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Ce formulaire ne doit pas contenir des champs supplémentaires.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Le fichier téléchargé est trop volumineux. Merci d'essayer d'envoyer un fichier plus petit.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Le jeton CSRF est invalide. Veuillez renvoyer le formulaire.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Este formulario non debería conter campos adicionais.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>O arquivo subido é demasiado grande. Por favor, suba un arquivo máis pequeno.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>O token CSRF non é válido. Por favor, probe a enviar novamente o formulario</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>הטופס לא צריך להכיל שדות נוספים.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>הקובץ שהועלה גדול מדי. נסה להעלות קובץ קטן יותר.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid.</source>
- <target>אסימון CSRF אינו חוקי.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Ovaj obrazac ne smije sadržavati dodatna polja.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Prenesena datoteka je prevelika. Molim pokušajte prenijeti manju datoteku.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF vrijednost nije ispravna. Pokušajte ponovo poslati obrazac.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Ez a mezőcsoport nem tartalmazhat extra mezőket.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>A feltöltött fájl túl nagy. Kérem próbáljon egy kisebb fájlt feltölteni.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Érvénytelen CSRF token. Kérem próbálja újra elküldeni az űrlapot.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Այս ձևը չպետք է պարունակի լրացուցիչ տողեր.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Վերբեռնված ֆայլը չափազանց մեծ է: Խնդրվում է վերբեռնել ավելի փոքր չափսի ֆայլ.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF արժեքը անթույլատրելի է: Փորձեք նորից ուղարկել ձևը.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Gabungan kolom tidak boleh mengandung kolom tambahan.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Berkas yang di unggah terlalu besar. Silahkan coba unggah berkas yang lebih kecil.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF-Token tidak sah. Silahkan coba kirim ulang formulir.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Questo form non dovrebbe contenere nessun campo extra.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Il file caricato è troppo grande. Per favore caricare un file più piccolo.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Il token CSRF non è valido. Provare a reinviare il form.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>フィールドグループに追加のフィールドを含んではなりません.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>アップロードされたファイルが大きすぎます。小さなファイルで再度アップロードしてください.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid.</source>
- <target>CSRFトークンが無効です.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Dës Feldergrupp sollt keng zousätzlech Felder enthalen.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>De geschécktene Fichier ass ze grouss. Versicht wann ech gelift ee méi klenge Fichier eropzelueden.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Den CSRF-Token ass ongëlteg. Versicht wann ech gelift de Formulaire nach eng Kéier ze schécken.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Forma negali turėti papildomų laukų.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Įkelta byla yra per didelė. bandykite įkelti mažesnę.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF kodas nepriimtinas. Bandykite siųsti formos užklausą dar kartą.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Šajā veidlapā nevajadzētu būt papildus ievades laukiem.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Augšupielādētā faila izmērs bija par lielu. Lūdzu mēģiniet augšupielādēt mazāka izmēra failu.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Dotais CSRF talons nav derīgs. Lūdzu mēģiniet vēlreiz iesniegt veidlapu.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Форм нэмэлт талбар багтаах боломжгүй.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Upload хийсэн файл хэтэрхий том байна. Бага хэмжээтэй файл оруулна уу.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF token буруу байна. Формоо дахин илгээнэ үү.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Feltgruppen må ikke inneholde ekstra felter.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Den opplastede file var for stor. Vennligst last opp en mindre fil.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid.</source>
- <target>CSRF nøkkelen er ugyldig.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Dit formulier mag geen extra velden bevatten.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Het geüploade bestand is te groot. Probeer een kleiner bestand te uploaden.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>De CSRF-token is ongeldig. Probeer het formulier opnieuw te versturen.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Ten formularz nie powinien zawierać dodatkowych pól.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Wgrany plik był za duży. Proszę spróbować wgrać mniejszy plik.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Token CSRF jest nieprawidłowy. Proszę spróbować wysłać formularz ponownie.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Este formulário não deveria conter campos extra.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>O arquivo enviado é muito grande. Por favor, tente enviar um ficheiro mais pequeno.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>O token CSRF é inválido. Por favor submeta o formulário novamente.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Este formulário não deve conter campos adicionais.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>O arquivo enviado é muito grande. Por favor, tente enviar um arquivo menor.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>O token CSRF é inválido. Por favor, tente reenviar o formulário.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Aceast formular nu ar trebui să conțină câmpuri suplimentare.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Fișierul încărcat a fost prea mare. Vă rugăm sa încărcați un fișier mai mic.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>Token-ul CSRF este invalid. Vă rugăm să trimiteți formularul incă o dată.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Эта форма не должна содержать дополнительных полей.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Загруженный файл слишком большой. Пожалуйста, попробуйте загрузить файл меньшего размера.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF значение недопустимо. Пожалуйста, попробуйте повторить отправку формы.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Polia by nemali obsahovať ďalšie prvky.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Odoslaný súbor je príliš veľký. Prosím odošlite súbor s menšou veľkosťou.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF token je neplatný. Prosím skúste znovu odoslať formulár.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>To področje ne sme vsebovati dodatnih polj.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Naložena datoteka je prevelika. Prosim, poizkusite naložiti manjšo.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF vrednost je napačna. Prosimo, ponovno pošljite obrazec.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Овај формулар не треба да садржи додатна поља.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Отпремљена датотека је била превелика. Молим покушајте отпремање мање датотеке.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF вредност је невалидна. Покушајте поново.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Ovaj formular ne treba da sadrži dodatna polja.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Otpremljena datoteka je bila prevelika. Molim pokušajte otpremanje manje datoteke.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF vrednost je nevalidna. Pokušajte ponovo.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Formuläret kan inte innehålla extra fält.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Den uppladdade filen var för stor. Försök ladda upp en mindre fil.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid.</source>
- <target>CSRF-symbolen är inte giltig.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>Ця форма не повинна містити додаткових полів.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>Завантажений файл занадто великий. Будь-ласка, спробуйте завантажити файл меншого розміру.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF значення недопустиме. Будь-ласка, спробуйте відправити форму знову.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="28">
- <source>This form should not contain extra fields.</source>
- <target>该表单中不可有额外字段.</target>
- </trans-unit>
- <trans-unit id="29">
- <source>The uploaded file was too large. Please try to upload a smaller file.</source>
- <target>上传文件太大, 请重新尝试上传一个较小的文件.</target>
- </trans-unit>
- <trans-unit id="30">
- <source>The CSRF token is invalid. Please try to resubmit the form.</source>
- <target>CSRF 验证符无效, 请重新提交.</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * Reverses a transformer
- *
- * When the transform() method is called, the reversed transformer's
- * reverseTransform() method is called and vice versa.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ReversedTransformer implements DataTransformerInterface
-{
- /**
- * The reversed transformer
- * @var DataTransformerInterface
- */
- protected $reversedTransformer;
-
- /**
- * Reverses this transformer
- *
- * @param DataTransformerInterface $reversedTransformer
- */
- public function __construct(DataTransformerInterface $reversedTransformer)
- {
- $this->reversedTransformer = $reversedTransformer;
- }
-
- /**
- * {@inheritDoc}
- */
- public function transform($value)
- {
- return $this->reversedTransformer->reverseTransform($value);
- }
-
- /**
- * {@inheritDoc}
- */
- public function reverseTransform($value)
- {
- return $this->reversedTransformer->transform($value);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A button that submits the form.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SubmitButton extends Button implements ClickableInterface
-{
- /**
- * @var Boolean
- */
- private $clicked = false;
-
- /**
- * {@inheritdoc}
- */
- public function isClicked()
- {
- return $this->clicked;
- }
-
- /**
- * Submits data to the button.
- *
- * @param null|string $submittedData The data.
- * @param Boolean $clearMissing Not used.
- *
- * @return SubmitButton The button instance
- *
- * @throws Exception\AlreadySubmittedException If the form has already been submitted.
- */
- public function submit($submittedData, $clearMissing = true)
- {
- parent::submit($submittedData, $clearMissing);
-
- $this->clicked = null !== $submittedData;
-
- return $this;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A builder for {@link SubmitButton} instances.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SubmitButtonBuilder extends ButtonBuilder
-{
- /**
- * Creates the button.
- *
- * @return Button The button
- */
- public function getForm()
- {
- return new SubmitButton($this->getFormConfig());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-/**
- * A type that should be converted into a {@link SubmitButton} instance.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface SubmitButtonTypeInterface extends FormTypeInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Test;
-
-use Symfony\Component\Form\FormEvent;
-
-class DeprecationErrorHandler
-{
- public static function handle($errorNumber, $message, $file, $line, $context)
- {
- if ($errorNumber & E_USER_DEPRECATED) {
- return true;
- }
-
- return \PHPUnit_Util_ErrorHandler::handleError($errorNumber, $message, $file, $line);
- }
-
- public static function handleBC($errorNumber, $message, $file, $line, $context)
- {
- if ($errorNumber & E_USER_DEPRECATED) {
- return true;
- }
-
- return false;
- }
-
- public static function preBind($listener, FormEvent $event)
- {
- set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handle'));
- $listener->preBind($event);
- restore_error_handler();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Test;
-
-interface FormBuilderInterface extends \Iterator, \Symfony\Component\Form\FormBuilderInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Test;
-
-use Symfony\Component\Form\Forms;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class FormIntegrationTestCase extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \Symfony\Component\Form\FormFactoryInterface
- */
- protected $factory;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->factory = Forms::createFormFactoryBuilder()
- ->addExtensions($this->getExtensions())
- ->getFormFactory();
- }
-
- protected function getExtensions()
- {
- return array();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Test;
-
-interface FormInterface extends \Iterator, \Symfony\Component\Form\FormInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Test;
-
-/**
- * Base class for performance tests.
- *
- * Copied from Doctrine 2's OrmPerformanceTestCase.
- *
- * @author robo
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class FormPerformanceTestCase extends FormIntegrationTestCase
-{
- /**
- * @var integer
- */
- protected $maxRunningTime = 0;
-
- /**
- */
- protected function runTest()
- {
- $s = microtime(true);
- parent::runTest();
- $time = microtime(true) - $s;
-
- if ($this->maxRunningTime != 0 && $time > $this->maxRunningTime) {
- $this->fail(
- sprintf(
- 'expected running time: <= %s but was: %s',
-
- $this->maxRunningTime,
- $time
- )
- );
- }
- }
-
- /**
- * @param integer $maxRunningTime
- * @throws \InvalidArgumentException
- */
- public function setMaxRunningTime($maxRunningTime)
- {
- if (is_integer($maxRunningTime) && $maxRunningTime >= 0) {
- $this->maxRunningTime = $maxRunningTime;
- } else {
- throw new \InvalidArgumentException;
- }
- }
-
- /**
- * @return integer
- * @since Method available since Release 2.3.0
- */
- public function getMaxRunningTime()
- {
- return $this->maxRunningTime;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Test;
-
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-
-abstract class TypeTestCase extends FormIntegrationTestCase
-{
- /**
- * @var FormBuilder
- */
- protected $builder;
-
- /**
- * @var EventDispatcher
- */
- protected $dispatcher;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
- }
-
- public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual)
- {
- self::assertEquals($expected->format('c'), $actual->format('c'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Form\Tests\Fixtures\AlternatingRowType;
-
-abstract class AbstractDivLayoutTest extends AbstractLayoutTest
-{
- public function testRow()
- {
- $form = $this->factory->createNamed('name', 'text');
- $form->addError(new FormError('[trans]Error![/trans]'));
- $view = $form->createView();
- $html = $this->renderRow($view);
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name"]
- /following-sibling::ul
- [./li[.="[trans]Error![/trans]"]]
- [count(./li)=1]
- /following-sibling::input[@id="name"]
- ]
-'
- );
- }
-
- public function testRowOverrideVariables()
- {
- $view = $this->factory->createNamed('name', 'text')->createView();
- $html = $this->renderRow($view, array(
- 'attr' => array('class' => 'my&class'),
- 'label' => 'foo&bar',
- 'label_attr' => array('class' => 'my&label&class'),
- ));
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name"][@class="my&label&class required"][.="[trans]foo&bar[/trans]"]
- /following-sibling::input[@id="name"][@class="my&class"]
- ]
-'
- );
- }
-
- public function testRepeatedRow()
- {
- $form = $this->factory->createNamed('name', 'repeated');
- $form->addError(new FormError('[trans]Error![/trans]'));
- $view = $form->createView();
- $html = $this->renderRow($view);
-
- // The errors of the form are not rendered by intention!
- // In practice, repeated fields cannot have errors as all errors
- // on them are mapped to the first child.
- // (see RepeatedTypeValidatorExtension)
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name_first"]
- /following-sibling::input[@id="name_first"]
- ]
-/following-sibling::div
- [
- ./label[@for="name_second"]
- /following-sibling::input[@id="name_second"]
- ]
-'
- );
- }
-
- public function testButtonRow()
- {
- $form = $this->factory->createNamed('name', 'button');
- $view = $form->createView();
- $html = $this->renderRow($view);
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./button[@type="button"][@name="name"]
- ]
- [count(//label)=0]
-'
- );
- }
-
- public function testRest()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('field1', 'text')
- ->add('field2', 'repeated')
- ->add('field3', 'text')
- ->add('field4', 'text')
- ->getForm()
- ->createView();
-
- // Render field2 row -> does not implicitly call renderWidget because
- // it is a repeated field!
- $this->renderRow($view['field2']);
-
- // Render field3 widget
- $this->renderWidget($view['field3']);
-
- // Rest should only contain field1 and field4
- $html = $this->renderRest($view);
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name_field1"]
- /following-sibling::input[@type="text"][@id="name_field1"]
- ]
-/following-sibling::div
- [
- ./label[@for="name_field4"]
- /following-sibling::input[@type="text"][@id="name_field4"]
- ]
- [count(../div)=2]
- [count(..//label)=2]
- [count(..//input)=3]
-/following-sibling::input
- [@type="hidden"]
- [@id="name__token"]
-'
- );
- }
-
- public function testRestWithChildrenForms()
- {
- $child1 = $this->factory->createNamedBuilder('child1', 'form')
- ->add('field1', 'text')
- ->add('field2', 'text');
-
- $child2 = $this->factory->createNamedBuilder('child2', 'form')
- ->add('field1', 'text')
- ->add('field2', 'text');
-
- $view = $this->factory->createNamedBuilder('parent', 'form')
- ->add($child1)
- ->add($child2)
- ->getForm()
- ->createView();
-
- // Render child1.field1 row
- $this->renderRow($view['child1']['field1']);
-
- // Render child2.field2 widget (remember that widget don't render label)
- $this->renderWidget($view['child2']['field2']);
-
- // Rest should only contain child1.field2 and child2.field1
- $html = $this->renderRest($view);
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[not(@for)]
- /following-sibling::div[@id="parent_child1"]
- [
- ./div
- [
- ./label[@for="parent_child1_field2"]
- /following-sibling::input[@id="parent_child1_field2"]
- ]
- ]
- ]
-
-/following-sibling::div
- [
- ./label[not(@for)]
- /following-sibling::div[@id="parent_child2"]
- [
- ./div
- [
- ./label[@for="parent_child2_field1"]
- /following-sibling::input[@id="parent_child2_field1"]
- ]
- ]
- ]
- [count(//label)=4]
- [count(//input[@type="text"])=2]
-/following-sibling::input[@type="hidden"][@id="parent__token"]
-'
- );
- }
-
- public function testRestAndRepeatedWithRow()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('first', 'text')
- ->add('password', 'repeated')
- ->getForm()
- ->createView();
-
- $this->renderRow($view['password']);
-
- $html = $this->renderRest($view);
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name_first"]
- /following-sibling::input[@type="text"][@id="name_first"]
- ]
- [count(.//input)=1]
-/following-sibling::input
- [@type="hidden"]
- [@id="name__token"]
-'
- );
- }
-
- public function testRestAndRepeatedWithRowPerChild()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('first', 'text')
- ->add('password', 'repeated')
- ->getForm()
- ->createView();
-
- $this->renderRow($view['password']['first']);
- $this->renderRow($view['password']['second']);
-
- $html = $this->renderRest($view);
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name_first"]
- /following-sibling::input[@type="text"][@id="name_first"]
- ]
- [count(.//input)=1]
- [count(.//label)=1]
-/following-sibling::input
- [@type="hidden"]
- [@id="name__token"]
-'
- );
- }
-
- public function testRestAndRepeatedWithWidgetPerChild()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('first', 'text')
- ->add('password', 'repeated')
- ->getForm()
- ->createView();
-
- // The password form is considered as rendered as all its children
- // are rendered
- $this->renderWidget($view['password']['first']);
- $this->renderWidget($view['password']['second']);
-
- $html = $this->renderRest($view);
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name_first"]
- /following-sibling::input[@type="text"][@id="name_first"]
- ]
- [count(//input)=2]
- [count(//label)=1]
-/following-sibling::input
- [@type="hidden"]
- [@id="name__token"]
-'
- );
- }
-
- public function testCollection()
- {
- $form = $this->factory->createNamed('name', 'collection', array('a', 'b'), array(
- 'type' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div[./input[@type="text"][@value="a"]]
- /following-sibling::div[./input[@type="text"][@value="b"]]
- ]
- [count(./div[./input])=2]
-'
- );
- }
-
- // https://github.com/symfony/symfony/issues/5038
- public function testCollectionWithAlternatingRowTypes()
- {
- $data = array(
- array('title' => 'a'),
- array('title' => 'b'),
- );
- $form = $this->factory->createNamed('name', 'collection', $data, array(
- 'type' => new AlternatingRowType(),
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div[./div/div/input[@type="text"][@value="a"]]
- /following-sibling::div[./div/div/textarea[.="b"]]
- ]
- [count(./div[./div/div/input])=1]
- [count(./div[./div/div/textarea])=1]
-'
- );
- }
-
- public function testEmptyCollection()
- {
- $form = $this->factory->createNamed('name', 'collection', array(), array(
- 'type' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [./input[@type="hidden"][@id="name__token"]]
- [count(./div)=0]
-'
- );
- }
-
- public function testCollectionRow()
- {
- $collection = $this->factory->createNamedBuilder(
- 'collection',
- 'collection',
- array('a', 'b'),
- array('type' => 'text')
- );
-
- $form = $this->factory->createNamedBuilder('form', 'form')
- ->add($collection)
- ->getForm();
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [
- ./label[not(@for)]
- /following-sibling::div
- [
- ./div
- [
- ./label[@for="form_collection_0"]
- /following-sibling::input[@type="text"][@value="a"]
- ]
- /following-sibling::div
- [
- ./label[@for="form_collection_1"]
- /following-sibling::input[@type="text"][@value="b"]
- ]
- ]
- ]
- /following-sibling::input[@type="hidden"][@id="form__token"]
- ]
- [count(.//input)=3]
-'
- );
- }
-
- public function testForm()
- {
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->setMethod('PUT')
- ->setAction('http://example.com')
- ->add('firstName', 'text')
- ->add('lastName', 'text')
- ->getForm();
-
- // include ampersands everywhere to validate escaping
- $html = $this->renderForm($form->createView(), array(
- 'id' => 'my&id',
- 'attr' => array('class' => 'my&class'),
- ));
-
- $this->assertMatchesXpath($html,
-'/form
- [
- ./input[@type="hidden"][@name="_method"][@value="PUT"]
- /following-sibling::div
- [
- ./div
- [
- ./label[@for="name_firstName"]
- /following-sibling::input[@type="text"][@id="name_firstName"]
- ]
- /following-sibling::div
- [
- ./label[@for="name_lastName"]
- /following-sibling::input[@type="text"][@id="name_lastName"]
- ]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(.//input)=3]
- [@id="my&id"]
- [@class="my&class"]
- ]
- [@method="post"]
- [@action="http://example.com"]
- [@class="my&class"]
-'
- );
- }
-
- public function testFormWidget()
- {
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->add('firstName', 'text')
- ->add('lastName', 'text')
- ->getForm();
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [
- ./label[@for="name_firstName"]
- /following-sibling::input[@type="text"][@id="name_firstName"]
- ]
- /following-sibling::div
- [
- ./label[@for="name_lastName"]
- /following-sibling::input[@type="text"][@id="name_lastName"]
- ]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(.//input)=3]
-'
- );
- }
-
- // https://github.com/symfony/symfony/issues/2308
- public function testNestedFormError()
- {
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->add($this->factory
- ->createNamedBuilder('child', 'form', null, array('error_bubbling' => false))
- ->add('grandChild', 'form')
- )
- ->getForm();
-
- $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div/label
- /following-sibling::ul[./li[.="[trans]Error![/trans]"]]
- ]
- [count(.//li[.="[trans]Error![/trans]"])=1]
-'
- );
- }
-
- public function testCsrf()
- {
- $this->csrfProvider->expects($this->any())
- ->method('generateCsrfToken')
- ->will($this->returnValue('foo&bar'));
-
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->add($this->factory
- // No CSRF protection on nested forms
- ->createNamedBuilder('child', 'form')
- ->add($this->factory->createNamedBuilder('grandchild', 'text'))
- )
- ->getForm();
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- /following-sibling::input[@type="hidden"][@id="name__token"][@value="foo&bar"]
- ]
- [count(.//input[@type="hidden"])=1]
-'
- );
- }
-
- public function testRepeated()
- {
- $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
- 'type' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [
- ./label[@for="name_first"]
- /following-sibling::input[@type="text"][@id="name_first"]
- ]
- /following-sibling::div
- [
- ./label[@for="name_second"]
- /following-sibling::input[@type="text"][@id="name_second"]
- ]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(.//input)=3]
-'
- );
- }
-
- public function testRepeatedWithCustomOptions()
- {
- $form = $this->factory->createNamed('name', 'repeated', null, array(
- // the global required value cannot be overridden
- 'first_options' => array('label' => 'Test', 'required' => false),
- 'second_options' => array('label' => 'Test2')
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [
- ./label[@for="name_first"][.="[trans]Test[/trans]"]
- /following-sibling::input[@type="text"][@id="name_first"][@required="required"]
- ]
- /following-sibling::div
- [
- ./label[@for="name_second"][.="[trans]Test2[/trans]"]
- /following-sibling::input[@type="text"][@id="name_second"][@required="required"]
- ]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(.//input)=3]
-'
- );
- }
-
- public function testSearchInputName()
- {
- $form = $this->factory->createNamedBuilder('full', 'form')
- ->add('name', 'search')
- ->getForm();
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [
- ./label[@for="full_name"]
- /following-sibling::input[@type="search"][@id="full_name"][@name="full[name]"]
- ]
- /following-sibling::input[@type="hidden"][@id="full__token"]
- ]
- [count(//input)=2]
-'
- );
- }
-
- public function testLabelHasNoId()
- {
- $form = $this->factory->createNamed('name', 'text');
- $html = $this->renderRow($form->createView());
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./label[@for="name"][not(@id)]
- /following-sibling::input[@id="name"]
- ]
-'
- );
- }
-
- public function testLabelIsNotRenderedWhenSetToFalse()
- {
- $form = $this->factory->createNamed('name', 'text', null, array(
- 'label' => false
- ));
- $html = $this->renderRow($form->createView());
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./input[@id="name"]
- ]
- [count(//label)=0]
-'
- );
- }
-
- /**
- * @dataProvider themeBlockInheritanceProvider
- */
- public function testThemeBlockInheritance($theme)
- {
- $view = $this->factory
- ->createNamed('name', 'email')
- ->createView()
- ;
-
- $this->setTheme($view, $theme);
-
- $this->assertMatchesXpath(
- $this->renderWidget($view),
- '/input[@type="email"][@rel="theme"]'
- );
- }
-
- /**
- * @dataProvider themeInheritanceProvider
- */
- public function testThemeInheritance($parentTheme, $childTheme)
- {
- $child = $this->factory->createNamedBuilder('child', 'form')
- ->add('field', 'text');
-
- $view = $this->factory->createNamedBuilder('parent', 'form')
- ->add('field', 'text')
- ->add($child)
- ->getForm()
- ->createView()
- ;
-
- $this->setTheme($view, $parentTheme);
- $this->setTheme($view['child'], $childTheme);
-
- $this->assertWidgetMatchesXpath($view, array(),
-'/div
- [
- ./div
- [
- ./label[.="parent"]
- /following-sibling::input[@type="text"]
- ]
- /following-sibling::div
- [
- ./label[.="child"]
- /following-sibling::div
- [
- ./div
- [
- ./label[.="child"]
- /following-sibling::input[@type="text"]
- ]
- ]
- ]
- /following-sibling::input[@type="hidden"]
- ]
-'
- );
- }
-
- /**
- * The block "_name_child_label" should be overridden in the theme of the
- * implemented driver.
- */
- public function testCollectionRowWithCustomBlock()
- {
- $collection = array('one', 'two', 'three');
- $form = $this->factory->createNamedBuilder('name', 'collection', $collection)
- ->getForm();
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div[./label[.="Custom label: [trans]0[/trans]"]]
- /following-sibling::div[./label[.="Custom label: [trans]1[/trans]"]]
- /following-sibling::div[./label[.="Custom label: [trans]2[/trans]"]]
- ]
-'
- );
- }
-
- public function testFormEndWithRest()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('field1', 'text')
- ->add('field2', 'text')
- ->getForm()
- ->createView();
-
- $this->renderWidget($view['field1']);
-
- // Rest should only contain field2
- $html = $this->renderEnd($view);
-
- // Insert the start tag, the end tag should be rendered by the helper
- $this->assertMatchesXpath('<form>' . $html,
-'/form
- [
- ./div
- [
- ./label[@for="name_field2"]
- /following-sibling::input[@type="text"][@id="name_field2"]
- ]
- /following-sibling::input
- [@type="hidden"]
- [@id="name__token"]
- ]
-'
- );
- }
-
- public function testFormEndWithoutRest()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('field1', 'text')
- ->add('field2', 'text')
- ->getForm()
- ->createView();
-
- $this->renderWidget($view['field1']);
-
- // Rest should only contain field2, but isn't rendered
- $html = $this->renderEnd($view, array('render_rest' => false));
-
- $this->assertEquals('</form>', $html);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\AbstractExtension;
-use Symfony\Component\Form\Tests\Fixtures\FooType;
-
-class AbstractExtensionTest extends \PHPUnit_Framework_TestCase
-{
- public function testHasType()
- {
- $loader = new ConcreteExtension();
- $this->assertTrue($loader->hasType('foo'));
- $this->assertFalse($loader->hasType('bar'));
- }
-
- public function testGetType()
- {
- $loader = new ConcreteExtension();
- $this->assertInstanceOf('Symfony\Component\Form\Tests\Fixtures\FooType', $loader->getType('foo'));
- }
-}
-
-class ConcreteExtension extends AbstractExtension
-{
- protected function loadTypes()
- {
- return array(new FooType());
- }
-
- protected function loadTypeGuesser()
- {
- }
-}
+++ /dev/null
-<?php
-
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-
-abstract class AbstractFormTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var EventDispatcherInterface
- */
- protected $dispatcher;
-
- /**
- * @var \Symfony\Component\Form\FormFactoryInterface
- */
- protected $factory;
-
- /**
- * @var \Symfony\Component\Form\FormInterface
- */
- protected $form;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- // We need an actual dispatcher to use the deprecated
- // bindRequest() method
- $this->dispatcher = new EventDispatcher();
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->form = $this->createForm();
- }
-
- protected function tearDown()
- {
- $this->dispatcher = null;
- $this->factory = null;
- $this->form = null;
- }
-
- /**
- * @return \Symfony\Component\Form\FormInterface
- */
- abstract protected function createForm();
-
- /**
- * @param string $name
- * @param EventDispatcherInterface $dispatcher
- * @param string $dataClass
- *
- * @return FormBuilder
- */
- protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null)
- {
- return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory);
- }
-
- /**
- * @param string $name
- *
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- protected function getMockForm($name = 'name')
- {
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
-
- $form->expects($this->any())
- ->method('getName')
- ->will($this->returnValue($name));
- $form->expects($this->any())
- ->method('getConfig')
- ->will($this->returnValue($config));
-
- return $form;
- }
-
- /**
- * @param string $name
- *
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- protected function getValidForm($name)
- {
- $form = $this->getMockForm($name);
-
- $form->expects($this->any())
- ->method('isValid')
- ->will($this->returnValue(true));
-
- return $form;
- }
-
- /**
- * @param string $name
- *
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- protected function getInvalidForm($name)
- {
- $form = $this->getMockForm($name);
-
- $form->expects($this->any())
- ->method('isValid')
- ->will($this->returnValue(false));
-
- return $form;
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- protected function getDataMapper()
- {
- return $this->getMock('Symfony\Component\Form\DataMapperInterface');
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- protected function getDataTransformer()
- {
- return $this->getMock('Symfony\Component\Form\DataTransformerInterface');
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- protected function getFormValidator()
- {
- return $this->getMock('Symfony\Component\Form\FormValidatorInterface');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
-
-abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormIntegrationTestCase
-{
- protected $csrfProvider;
-
- protected function setUp()
- {
- if (!extension_loaded('intl')) {
- $this->markTestSkipped('The "intl" extension is not available');
- }
-
- \Locale::setDefault('en');
-
- $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
-
- parent::setUp();
- }
-
- protected function getExtensions()
- {
- return array(
- new CsrfExtension($this->csrfProvider),
- );
- }
-
- protected function tearDown()
- {
- $this->csrfProvider = null;
-
- parent::tearDown();
- }
-
- protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue)
- {
- $xpath = new \DOMXPath($element->ownerDocument);
- $nodeList = $xpath->evaluate($expression);
- $this->assertEquals(1, $nodeList->length);
- $this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
- }
-
- protected function assertMatchesXpath($html, $expression, $count = 1)
- {
- $dom = new \DomDocument('UTF-8');
- try {
- // Wrap in <root> node so we can load HTML with multiple tags at
- // the top level
- $dom->loadXml('<root>'.$html.'</root>');
- } catch (\Exception $e) {
- $this->fail(sprintf(
- "Failed loading HTML:\n\n%s\n\nError: %s",
- $html,
- $e->getMessage()
- ));
- }
- $xpath = new \DOMXPath($dom);
- $nodeList = $xpath->evaluate('/root'.$expression);
-
- if ($nodeList->length != $count) {
- $dom->formatOutput = true;
- $this->fail(sprintf(
- "Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
- $expression,
- $count == 1 ? 'once' : $count.' times',
- $nodeList->length == 1 ? 'once' : $nodeList->length.' times',
- // strip away <root> and </root>
- substr($dom->saveHTML(), 6, -8)
- ));
- }
- }
-
- protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
- {
- // include ampersands everywhere to validate escaping
- $html = $this->renderWidget($view, array_merge(array(
- 'id' => 'my&id',
- 'attr' => array('class' => 'my&class'),
- ), $vars));
-
- $xpath = trim($xpath).'
- [@id="my&id"]
- [@class="my&class"]';
-
- $this->assertMatchesXpath($html, $xpath);
- }
-
- abstract protected function renderForm(FormView $view, array $vars = array());
-
- abstract protected function renderEnctype(FormView $view);
-
- abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
-
- abstract protected function renderErrors(FormView $view);
-
- abstract protected function renderWidget(FormView $view, array $vars = array());
-
- abstract protected function renderRow(FormView $view, array $vars = array());
-
- abstract protected function renderRest(FormView $view, array $vars = array());
-
- abstract protected function renderStart(FormView $view, array $vars = array());
-
- abstract protected function renderEnd(FormView $view, array $vars = array());
-
- abstract protected function setTheme(FormView $view, array $themes);
-
- public function testEnctype()
- {
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->add('file', 'file')
- ->getForm();
-
- $this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
- }
-
- public function testNoEnctype()
- {
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->add('text', 'text')
- ->getForm();
-
- $this->assertEquals('', $this->renderEnctype($form->createView()));
- }
-
- public function testLabel()
- {
- $form = $this->factory->createNamed('name', 'text');
- $view = $form->createView();
- $this->renderWidget($view, array('label' => 'foo'));
- $html = $this->renderLabel($view);
-
- $this->assertMatchesXpath($html,
-'/label
- [@for="name"]
- [.="[trans]Name[/trans]"]
-'
- );
- }
-
- public function testLabelOnForm()
- {
- $form = $this->factory->createNamed('name', 'date');
- $view = $form->createView();
- $this->renderWidget($view, array('label' => 'foo'));
- $html = $this->renderLabel($view);
-
- $this->assertMatchesXpath($html,
-'/label
- [@class="required"]
- [.="[trans]Name[/trans]"]
-'
- );
- }
-
- public function testLabelWithCustomTextPassedAsOption()
- {
- $form = $this->factory->createNamed('name', 'text', null, array(
- 'label' => 'Custom label',
- ));
- $html = $this->renderLabel($form->createView());
-
- $this->assertMatchesXpath($html,
-'/label
- [@for="name"]
- [.="[trans]Custom label[/trans]"]
-'
- );
- }
-
- public function testLabelWithCustomTextPassedDirectly()
- {
- $form = $this->factory->createNamed('name', 'text');
- $html = $this->renderLabel($form->createView(), 'Custom label');
-
- $this->assertMatchesXpath($html,
-'/label
- [@for="name"]
- [.="[trans]Custom label[/trans]"]
-'
- );
- }
-
- public function testLabelWithCustomTextPassedAsOptionAndDirectly()
- {
- $form = $this->factory->createNamed('name', 'text', null, array(
- 'label' => 'Custom label',
- ));
- $html = $this->renderLabel($form->createView(), 'Overridden label');
-
- $this->assertMatchesXpath($html,
-'/label
- [@for="name"]
- [.="[trans]Overridden label[/trans]"]
-'
- );
- }
-
- public function testLabelDoesNotRenderFieldAttributes()
- {
- $form = $this->factory->createNamed('name', 'text');
- $html = $this->renderLabel($form->createView(), null, array(
- 'attr' => array(
- 'class' => 'my&class'
- ),
- ));
-
- $this->assertMatchesXpath($html,
-'/label
- [@for="name"]
- [@class="required"]
-'
- );
- }
-
- public function testLabelWithCustomAttributesPassedDirectly()
- {
- $form = $this->factory->createNamed('name', 'text');
- $html = $this->renderLabel($form->createView(), null, array(
- 'label_attr' => array(
- 'class' => 'my&class'
- ),
- ));
-
- $this->assertMatchesXpath($html,
-'/label
- [@for="name"]
- [@class="my&class required"]
-'
- );
- }
-
- public function testLabelWithCustomTextAndCustomAttributesPassedDirectly()
- {
- $form = $this->factory->createNamed('name', 'text');
- $html = $this->renderLabel($form->createView(), 'Custom label', array(
- 'label_attr' => array(
- 'class' => 'my&class'
- ),
- ));
-
- $this->assertMatchesXpath($html,
-'/label
- [@for="name"]
- [@class="my&class required"]
- [.="[trans]Custom label[/trans]"]
-'
- );
- }
-
- // https://github.com/symfony/symfony/issues/5029
- public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly()
- {
- $form = $this->factory->createNamed('name', 'text', null, array(
- 'label' => 'Custom label',
- ));
- $html = $this->renderLabel($form->createView(), null, array(
- 'label_attr' => array(
- 'class' => 'my&class'
- ),
- ));
-
- $this->assertMatchesXpath($html,
- '/label
- [@for="name"]
- [@class="my&class required"]
- [.="[trans]Custom label[/trans]"]
-'
- );
- }
-
- public function testErrors()
- {
- $form = $this->factory->createNamed('name', 'text');
- $form->addError(new FormError('[trans]Error 1[/trans]'));
- $form->addError(new FormError('[trans]Error 2[/trans]'));
- $view = $form->createView();
- $html = $this->renderErrors($view);
-
- $this->assertMatchesXpath($html,
-'/ul
- [
- ./li[.="[trans]Error 1[/trans]"]
- /following-sibling::li[.="[trans]Error 2[/trans]"]
- ]
- [count(./li)=2]
-'
- );
- }
-
- public function testWidgetById()
- {
- $form = $this->factory->createNamed('text_id', 'text');
- $html = $this->renderWidget($form->createView());
-
- $this->assertMatchesXpath($html,
-'/div
- [
- ./input
- [@type="text"]
- [@id="text_id"]
- ]
- [@id="container"]
-'
- );
- }
-
- public function testCheckedCheckbox()
- {
- $form = $this->factory->createNamed('name', 'checkbox', true);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="checkbox"]
- [@name="name"]
- [@checked="checked"]
- [@value="1"]
-'
- );
- }
-
- public function testUncheckedCheckbox()
- {
- $form = $this->factory->createNamed('name', 'checkbox', false);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="checkbox"]
- [@name="name"]
- [not(@checked)]
-'
- );
- }
-
- public function testCheckboxWithValue()
- {
- $form = $this->factory->createNamed('name', 'checkbox', false, array(
- 'value' => 'foo&bar',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="checkbox"]
- [@name="name"]
- [@value="foo&bar"]
-'
- );
- }
-
- public function testSingleChoice()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [@required="required"]
- [
- ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=2]
-'
- );
- }
-
- public function testSingleChoiceWithPreferred()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'preferred_choices' => array('&b'),
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
-'/select
- [@name="name"]
- [@required="required"]
- [
- ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
- /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- ]
- [count(./option)=3]
-'
- );
- }
-
- public function testSingleChoiceWithPreferredAndNoSeparator()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'preferred_choices' => array('&b'),
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array('separator' => null),
-'/select
- [@name="name"]
- [@required="required"]
- [
- ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- ]
- [count(./option)=2]
-'
- );
- }
-
- public function testSingleChoiceWithPreferredAndBlankSeparator()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'preferred_choices' => array('&b'),
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array('separator' => ''),
-'/select
- [@name="name"]
- [@required="required"]
- [
- ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- /following-sibling::option[@disabled="disabled"][not(@selected)][.=""]
- /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- ]
- [count(./option)=3]
-'
- );
- }
-
- public function testChoiceWithOnlyPreferred()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'preferred_choices' => array('&a', '&b'),
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [count(./option)=2]
-'
- );
- }
-
- public function testSingleChoiceNonRequired()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'required' => false,
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [not(@required)]
- [
- ./option[@value=""][.="[trans][/trans]"]
- /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=3]
-'
- );
- }
-
- public function testSingleChoiceNonRequiredNoneSelected()
- {
- $form = $this->factory->createNamed('name', 'choice', null, array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'required' => false,
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [not(@required)]
- [
- ./option[@value=""][.="[trans][/trans]"]
- /following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=3]
-'
- );
- }
-
- public function testSingleChoiceWithNonRequiredEmptyValue()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'multiple' => false,
- 'expanded' => false,
- 'required' => false,
- 'empty_value' => 'Select&Anything&Not&Me',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [not(@required)]
- [
- ./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Anything&Not&Me[/trans]"]
- /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=3]
-'
- );
- }
-
- public function testSingleChoiceRequiredWithEmptyValue()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'required' => true,
- 'multiple' => false,
- 'expanded' => false,
- 'empty_value' => 'Test&Me'
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [@required="required"]
- [
- ./option[not(@value)][not(@selected)][@disabled][.="[trans]Test&Me[/trans]"]
- /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=3]
-'
- );
- }
-
- public function testSingleChoiceRequiredWithEmptyValueViaView()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'required' => true,
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array('empty_value' => ''),
-'/select
- [@name="name"]
- [@required="required"]
- [
- ./option[not(@value)][not(@selected)][@disabled][.="[trans][/trans]"]
- /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=3]
-'
- );
- }
-
- public function testSingleChoiceGrouped()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array(
- 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'Group&2' => array('&c' => 'Choice&C'),
- ),
- 'multiple' => false,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [./optgroup[@label="[trans]Group&1[/trans]"]
- [
- ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=2]
- ]
- [./optgroup[@label="[trans]Group&2[/trans]"]
- [./option[@value="&c"][not(@selected)][.="[trans]Choice&C[/trans]"]]
- [count(./option)=1]
- ]
- [count(./optgroup)=2]
-'
- );
- }
-
- public function testMultipleChoice()
- {
- $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'multiple' => true,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name[]"]
- [@multiple="multiple"]
- [
- ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=2]
-'
- );
- }
-
- public function testMultipleChoiceSkipsEmptyValue()
- {
- $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'multiple' => true,
- 'expanded' => false,
- 'empty_value' => 'Test&Me'
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name[]"]
- [@multiple="multiple"]
- [
- ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=2]
-'
- );
- }
-
- public function testMultipleChoiceNonRequired()
- {
- $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'required' => false,
- 'multiple' => true,
- 'expanded' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name[]"]
- [@multiple="multiple"]
- [
- ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
- /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
- ]
- [count(./option)=2]
-'
- );
- }
-
- public function testSingleChoiceExpanded()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'multiple' => false,
- 'expanded' => true,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
- /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
- /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
- /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(./input)=3]
-'
- );
- }
-
- public function testSingleChoiceExpandedWithEmptyValue()
- {
- $form = $this->factory->createNamed('name', 'choice', '&a', array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
- 'multiple' => false,
- 'expanded' => true,
- 'empty_value' => 'Test&Me'
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./input[@type="radio"][@name="name"][@id="name_placeholder"][not(@checked)]
- /following-sibling::label[@for="name_placeholder"][.="[trans]Test&Me[/trans]"]
- /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@checked]
- /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
- /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
- /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(./input)=4]
-'
- );
- }
-
- public function testSingleChoiceExpandedWithBooleanValue()
- {
- $form = $this->factory->createNamed('name', 'choice', true, array(
- 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
- 'multiple' => false,
- 'expanded' => true,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./input[@type="radio"][@name="name"][@id="name_0"][@checked]
- /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
- /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
- /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(./input)=3]
-'
- );
- }
-
- public function testMultipleChoiceExpanded()
- {
- $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
- 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
- 'multiple' => true,
- 'expanded' => true,
- 'required' => true,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
- /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
- /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
- /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
- /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
- /following-sibling::label[@for="name_2"][.="[trans]Choice&C[/trans]"]
- /following-sibling::input[@type="hidden"][@id="name__token"]
- ]
- [count(./input)=4]
-'
- );
- }
-
- public function testCountry()
- {
- $form = $this->factory->createNamed('name', 'country', 'AT');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
- [count(./option)>200]
-'
- );
- }
-
- public function testCountryWithEmptyValue()
- {
- $form = $this->factory->createNamed('name', 'country', 'AT', array(
- 'empty_value' => 'Select&Country',
- 'required' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Country[/trans]"]]
- [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
- [count(./option)>201]
-'
- );
- }
-
- public function testDateTime()
- {
- $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
- 'input' => 'string',
- 'with_seconds' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [@id="name_date"]
- [
- ./select
- [@id="name_date_month"]
- [./option[@value="2"][@selected="selected"]]
- /following-sibling::select
- [@id="name_date_day"]
- [./option[@value="3"][@selected="selected"]]
- /following-sibling::select
- [@id="name_date_year"]
- [./option[@value="2011"][@selected="selected"]]
- ]
- /following-sibling::div
- [@id="name_time"]
- [
- ./select
- [@id="name_time_hour"]
- [./option[@value="4"][@selected="selected"]]
- /following-sibling::select
- [@id="name_time_minute"]
- [./option[@value="5"][@selected="selected"]]
- ]
- ]
- [count(.//select)=5]
-'
- );
- }
-
- public function testDateTimeWithEmptyValueGlobal()
- {
- $form = $this->factory->createNamed('name', 'datetime', null, array(
- 'input' => 'string',
- 'empty_value' => 'Change&Me',
- 'required' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [@id="name_date"]
- [
- ./select
- [@id="name_date_month"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- /following-sibling::select
- [@id="name_date_day"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- /following-sibling::select
- [@id="name_date_year"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- ]
- /following-sibling::div
- [@id="name_time"]
- [
- ./select
- [@id="name_time_hour"]
- [./option[@value=""][.="[trans]Change&Me[/trans]"]]
- /following-sibling::select
- [@id="name_time_minute"]
- [./option[@value=""][.="[trans]Change&Me[/trans]"]]
- ]
- ]
- [count(.//select)=5]
-'
- );
- }
-
- public function testDateTimeWithEmptyValueOnTime()
- {
- $data = array('year' => '2011', 'month' => '2', 'day' => '3', 'hour' => '', 'minute' => '');
-
- $form = $this->factory->createNamed('name', 'datetime', $data, array(
- 'input' => 'array',
- 'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
- 'required' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [@id="name_date"]
- [
- ./select
- [@id="name_date_month"]
- [./option[@value="2"][@selected="selected"]]
- /following-sibling::select
- [@id="name_date_day"]
- [./option[@value="3"][@selected="selected"]]
- /following-sibling::select
- [@id="name_date_year"]
- [./option[@value="2011"][@selected="selected"]]
- ]
- /following-sibling::div
- [@id="name_time"]
- [
- ./select
- [@id="name_time_hour"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- /following-sibling::select
- [@id="name_time_minute"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- ]
- ]
- [count(.//select)=5]
-'
- );
- }
-
- public function testDateTimeWithSeconds()
- {
- $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
- 'input' => 'string',
- 'with_seconds' => true,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./div
- [@id="name_date"]
- [
- ./select
- [@id="name_date_month"]
- [./option[@value="2"][@selected="selected"]]
- /following-sibling::select
- [@id="name_date_day"]
- [./option[@value="3"][@selected="selected"]]
- /following-sibling::select
- [@id="name_date_year"]
- [./option[@value="2011"][@selected="selected"]]
- ]
- /following-sibling::div
- [@id="name_time"]
- [
- ./select
- [@id="name_time_hour"]
- [./option[@value="4"][@selected="selected"]]
- /following-sibling::select
- [@id="name_time_minute"]
- [./option[@value="5"][@selected="selected"]]
- /following-sibling::select
- [@id="name_time_second"]
- [./option[@value="6"][@selected="selected"]]
- ]
- ]
- [count(.//select)=6]
-'
- );
- }
-
- public function testDateTimeSingleText()
- {
- $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
- 'input' => 'string',
- 'date_widget' => 'single_text',
- 'time_widget' => 'single_text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./input
- [@type="date"]
- [@id="name_date"]
- [@name="name[date]"]
- [@value="2011-02-03"]
- /following-sibling::input
- [@type="time"]
- [@id="name_time"]
- [@name="name[time]"]
- [@value="04:05"]
- ]
-'
- );
- }
-
- public function testDateTimeWithWidgetSingleText()
- {
- $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
- 'input' => 'string',
- 'widget' => 'single_text',
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="datetime"]
- [@name="name"]
- [@value="2011-02-03T04:05:06Z"]
-'
- );
- }
-
- public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
- {
- $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
- 'input' => 'string',
- 'date_widget' => 'choice',
- 'time_widget' => 'choice',
- 'widget' => 'single_text',
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="datetime"]
- [@name="name"]
- [@value="2011-02-03T04:05:06Z"]
-'
- );
- }
-
- public function testDateChoice()
- {
- $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
- 'input' => 'string',
- 'widget' => 'choice',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_month"]
- [./option[@value="2"][@selected="selected"]]
- /following-sibling::select
- [@id="name_day"]
- [./option[@value="3"][@selected="selected"]]
- /following-sibling::select
- [@id="name_year"]
- [./option[@value="2011"][@selected="selected"]]
- ]
- [count(./select)=3]
-'
- );
- }
-
- public function testDateChoiceWithEmptyValueGlobal()
- {
- $form = $this->factory->createNamed('name', 'date', null, array(
- 'input' => 'string',
- 'widget' => 'choice',
- 'empty_value' => 'Change&Me',
- 'required' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_month"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- /following-sibling::select
- [@id="name_day"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- /following-sibling::select
- [@id="name_year"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- ]
- [count(./select)=3]
-'
- );
- }
-
- public function testDateChoiceWithEmptyValueOnYear()
- {
- $form = $this->factory->createNamed('name', 'date', null, array(
- 'input' => 'string',
- 'widget' => 'choice',
- 'required' => false,
- 'empty_value' => array('year' => 'Change&Me'),
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_month"]
- [./option[@value="1"]]
- /following-sibling::select
- [@id="name_day"]
- [./option[@value="1"]]
- /following-sibling::select
- [@id="name_year"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- ]
- [count(./select)=3]
-'
- );
- }
-
- public function testDateText()
- {
- $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
- 'input' => 'string',
- 'widget' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./input
- [@id="name_month"]
- [@type="text"]
- [@value="2"]
- /following-sibling::input
- [@id="name_day"]
- [@type="text"]
- [@value="3"]
- /following-sibling::input
- [@id="name_year"]
- [@type="text"]
- [@value="2011"]
- ]
- [count(./input)=3]
-'
- );
- }
-
- public function testDateSingleText()
- {
- $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
- 'input' => 'string',
- 'widget' => 'single_text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="date"]
- [@name="name"]
- [@value="2011-02-03"]
-'
- );
- }
-
- public function testDateErrorBubbling()
- {
- $form = $this->factory->createNamedBuilder('form', 'form')
- ->add('date', 'date')
- ->getForm();
- $form->get('date')->addError(new FormError('[trans]Error![/trans]'));
- $view = $form->createView();
-
- $this->assertEmpty($this->renderErrors($view));
- $this->assertNotEmpty($this->renderErrors($view['date']));
- }
-
- public function testBirthDay()
- {
- $form = $this->factory->createNamed('name', 'birthday', '2000-02-03', array(
- 'input' => 'string',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_month"]
- [./option[@value="2"][@selected="selected"]]
- /following-sibling::select
- [@id="name_day"]
- [./option[@value="3"][@selected="selected"]]
- /following-sibling::select
- [@id="name_year"]
- [./option[@value="2000"][@selected="selected"]]
- ]
- [count(./select)=3]
-'
- );
- }
-
- public function testBirthDayWithEmptyValue()
- {
- $form = $this->factory->createNamed('name', 'birthday', '1950-01-01', array(
- 'input' => 'string',
- 'empty_value' => '',
- 'required' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_month"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
- [./option[@value="1"][@selected="selected"]]
- /following-sibling::select
- [@id="name_day"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
- [./option[@value="1"][@selected="selected"]]
- /following-sibling::select
- [@id="name_year"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
- [./option[@value="1950"][@selected="selected"]]
- ]
- [count(./select)=3]
-'
- );
- }
-
- public function testEmail()
- {
- $form = $this->factory->createNamed('name', 'email', 'foo&bar');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="email"]
- [@name="name"]
- [@value="foo&bar"]
- [not(@maxlength)]
-'
- );
- }
-
- public function testEmailWithMaxLength()
- {
- $form = $this->factory->createNamed('name', 'email', 'foo&bar', array(
- 'max_length' => 123,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="email"]
- [@name="name"]
- [@value="foo&bar"]
- [@maxlength="123"]
-'
- );
- }
-
- public function testFile()
- {
- $form = $this->factory->createNamed('name', 'file');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="file"]
-'
- );
- }
-
- public function testHidden()
- {
- $form = $this->factory->createNamed('name', 'hidden', 'foo&bar');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="hidden"]
- [@name="name"]
- [@value="foo&bar"]
-'
- );
- }
-
- public function testReadOnly()
- {
- $form = $this->factory->createNamed('name', 'text', null, array(
- 'read_only' => true,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="text"]
- [@name="name"]
- [@readonly="readonly"]
-'
- );
- }
-
- public function testDisabled()
- {
- $form = $this->factory->createNamed('name', 'text', null, array(
- 'disabled' => true,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="text"]
- [@name="name"]
- [@disabled="disabled"]
-'
- );
- }
-
- public function testInteger()
- {
- $form = $this->factory->createNamed('name', 'integer', 123);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="number"]
- [@name="name"]
- [@value="123"]
-'
- );
- }
-
- public function testLanguage()
- {
- $form = $this->factory->createNamed('name', 'language', 'de');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [./option[@value="de"][@selected="selected"][.="[trans]German[/trans]"]]
- [count(./option)>200]
-'
- );
- }
-
- public function testLocale()
- {
- $form = $this->factory->createNamed('name', 'locale', 'de_AT');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [./option[@value="de_AT"][@selected="selected"][.="[trans]German (Austria)[/trans]"]]
- [count(./option)>200]
-'
- );
- }
-
- public function testMoney()
- {
- $form = $this->factory->createNamed('name', 'money', 1234.56, array(
- 'currency' => 'EUR',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="text"]
- [@name="name"]
- [@value="1234.56"]
- [contains(.., "€")]
-'
- );
- }
-
- public function testNumber()
- {
- $form = $this->factory->createNamed('name', 'number', 1234.56);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="text"]
- [@name="name"]
- [@value="1234.56"]
-'
- );
- }
-
- public function testPassword()
- {
- $form = $this->factory->createNamed('name', 'password', 'foo&bar');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="password"]
- [@name="name"]
-'
- );
- }
-
- public function testPasswordSubmittedWithNotAlwaysEmpty()
- {
- $form = $this->factory->createNamed('name', 'password', null, array(
- 'always_empty' => false,
- ));
- $form->submit('foo&bar');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="password"]
- [@name="name"]
- [@value="foo&bar"]
-'
- );
- }
-
- public function testPasswordWithMaxLength()
- {
- $form = $this->factory->createNamed('name', 'password', 'foo&bar', array(
- 'max_length' => 123,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="password"]
- [@name="name"]
- [@maxlength="123"]
-'
- );
- }
-
- public function testPercent()
- {
- $form = $this->factory->createNamed('name', 'percent', 0.1);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="text"]
- [@name="name"]
- [@value="10"]
- [contains(.., "%")]
-'
- );
- }
-
- public function testCheckedRadio()
- {
- $form = $this->factory->createNamed('name', 'radio', true);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="radio"]
- [@name="name"]
- [@checked="checked"]
- [@value="1"]
-'
- );
- }
-
- public function testUncheckedRadio()
- {
- $form = $this->factory->createNamed('name', 'radio', false);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="radio"]
- [@name="name"]
- [not(@checked)]
-'
- );
- }
-
- public function testRadioWithValue()
- {
- $form = $this->factory->createNamed('name', 'radio', false, array(
- 'value' => 'foo&bar',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="radio"]
- [@name="name"]
- [@value="foo&bar"]
-'
- );
- }
-
- public function testTextarea()
- {
- $form = $this->factory->createNamed('name', 'textarea', 'foo&bar', array(
- 'pattern' => 'foo',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/textarea
- [@name="name"]
- [not(@pattern)]
- [.="foo&bar"]
-'
- );
- }
-
- public function testText()
- {
- $form = $this->factory->createNamed('name', 'text', 'foo&bar');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="text"]
- [@name="name"]
- [@value="foo&bar"]
- [not(@maxlength)]
-'
- );
- }
-
- public function testTextWithMaxLength()
- {
- $form = $this->factory->createNamed('name', 'text', 'foo&bar', array(
- 'max_length' => 123,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="text"]
- [@name="name"]
- [@value="foo&bar"]
- [@maxlength="123"]
-'
- );
- }
-
- public function testSearch()
- {
- $form = $this->factory->createNamed('name', 'search', 'foo&bar');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="search"]
- [@name="name"]
- [@value="foo&bar"]
- [not(@maxlength)]
-'
- );
- }
-
- public function testTime()
- {
- $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
- 'input' => 'string',
- 'with_seconds' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_hour"]
- [not(@size)]
- [./option[@value="4"][@selected="selected"]]
- /following-sibling::select
- [@id="name_minute"]
- [not(@size)]
- [./option[@value="5"][@selected="selected"]]
- ]
- [count(./select)=2]
-'
- );
- }
-
- public function testTimeWithSeconds()
- {
- $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
- 'input' => 'string',
- 'with_seconds' => true,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_hour"]
- [not(@size)]
- [./option[@value="4"][@selected="selected"]]
- [count(./option)>23]
- /following-sibling::select
- [@id="name_minute"]
- [not(@size)]
- [./option[@value="5"][@selected="selected"]]
- [count(./option)>59]
- /following-sibling::select
- [@id="name_second"]
- [not(@size)]
- [./option[@value="6"][@selected="selected"]]
- [count(./option)>59]
- ]
- [count(./select)=3]
-'
- );
- }
-
- public function testTimeText()
- {
- $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
- 'input' => 'string',
- 'widget' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./input
- [@type="text"]
- [@id="name_hour"]
- [@name="name[hour]"]
- [@value="04"]
- [@size="1"]
- [@required="required"]
- /following-sibling::input
- [@type="text"]
- [@id="name_minute"]
- [@name="name[minute]"]
- [@value="05"]
- [@size="1"]
- [@required="required"]
- ]
- [count(./input)=2]
-'
- );
- }
-
- public function testTimeSingleText()
- {
- $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
- 'input' => 'string',
- 'widget' => 'single_text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="time"]
- [@name="name"]
- [@value="04:05"]
- [not(@size)]
-'
- );
- }
-
- public function testTimeWithEmptyValueGlobal()
- {
- $form = $this->factory->createNamed('name', 'time', null, array(
- 'input' => 'string',
- 'empty_value' => 'Change&Me',
- 'required' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_hour"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- [count(./option)>24]
- /following-sibling::select
- [@id="name_minute"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- [count(./option)>60]
- ]
- [count(./select)=2]
-'
- );
- }
-
- public function testTimeWithEmptyValueOnYear()
- {
- $form = $this->factory->createNamed('name', 'time', null, array(
- 'input' => 'string',
- 'required' => false,
- 'empty_value' => array('hour' => 'Change&Me'),
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/div
- [
- ./select
- [@id="name_hour"]
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
- [count(./option)>24]
- /following-sibling::select
- [@id="name_minute"]
- [./option[@value="1"]]
- [count(./option)>59]
- ]
- [count(./select)=2]
-'
- );
- }
-
- public function testTimeErrorBubbling()
- {
- $form = $this->factory->createNamedBuilder('form', 'form')
- ->add('time', 'time')
- ->getForm();
- $form->get('time')->addError(new FormError('[trans]Error![/trans]'));
- $view = $form->createView();
-
- $this->assertEmpty($this->renderErrors($view));
- $this->assertNotEmpty($this->renderErrors($view['time']));
- }
-
- public function testTimezone()
- {
- $form = $this->factory->createNamed('name', 'timezone', 'Europe/Vienna');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [@name="name"]
- [@required="required"]
- [./optgroup
- [@label="[trans]Europe[/trans]"]
- [./option[@value="Europe/Vienna"][@selected="selected"][.="[trans]Vienna[/trans]"]]
- ]
- [count(./optgroup)>10]
- [count(.//option)>200]
-'
- );
- }
-
- public function testTimezoneWithEmptyValue()
- {
- $form = $this->factory->createNamed('name', 'timezone', null, array(
- 'empty_value' => 'Select&Timezone',
- 'required' => false,
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/select
- [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Timezone[/trans]"]]
- [count(./optgroup)>10]
- [count(.//option)>201]
-'
- );
- }
-
- public function testUrl()
- {
- $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
- $form = $this->factory->createNamed('name', 'url', $url);
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/input
- [@type="url"]
- [@name="name"]
- [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
-'
- );
- }
-
- public function testCollectionPrototype()
- {
- $form = $this->factory->createNamedBuilder('name', 'form', array('items' => array('one', 'two', 'three')))
- ->add('items', 'collection', array('allow_add' => true))
- ->getForm()
- ->createView();
-
- $html = $this->renderWidget($form);
-
- $this->assertMatchesXpath($html,
- '//div[@id="name_items"][@data-prototype]
- |
- //table[@id="name_items"][@data-prototype]'
- );
- }
-
- public function testEmptyRootFormName()
- {
- $form = $this->factory->createNamedBuilder('', 'form')
- ->add('child', 'text')
- ->getForm();
-
- $this->assertMatchesXpath($this->renderWidget($form->createView()),
- '//input[@type="hidden"][@id="_token"][@name="_token"]
- |
- //input[@type="text"][@id="child"][@name="child"]'
- , 2);
- }
-
- public function testButton()
- {
- $form = $this->factory->createNamed('name', 'button');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
- '/button[@type="button"][@name="name"][.="[trans]Name[/trans]"]'
- );
- }
-
- public function testButtonLabelIsEmpty()
- {
- $form = $this->factory->createNamed('name', 'button');
-
- $this->assertSame('', $this->renderLabel($form->createView()));
- }
-
- public function testSubmit()
- {
- $form = $this->factory->createNamed('name', 'submit');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
- '/button[@type="submit"][@name="name"]'
- );
- }
-
- public function testReset()
- {
- $form = $this->factory->createNamed('name', 'reset');
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
- '/button[@type="reset"][@name="name"]'
- );
- }
-
- public function testStartTag()
- {
- $form = $this->factory->create('form', null, array(
- 'method' => 'get',
- 'action' => 'http://example.com/directory'
- ));
-
- $html = $this->renderStart($form->createView());
-
- $this->assertSame('<form method="get" action="http://example.com/directory">', $html);
- }
-
- public function testStartTagForPutRequest()
- {
- $form = $this->factory->create('form', null, array(
- 'method' => 'put',
- 'action' => 'http://example.com/directory'
- ));
-
- $html = $this->renderStart($form->createView());
-
- $this->assertMatchesXpath($html . '</form>',
-'/form
- [./input[@type="hidden"][@name="_method"][@value="PUT"]]
- [@method="post"]
- [@action="http://example.com/directory"]'
- );
- }
-
- public function testStartTagWithOverriddenVars()
- {
- $form = $this->factory->create('form', null, array(
- 'method' => 'put',
- 'action' => 'http://example.com/directory',
- ));
-
- $html = $this->renderStart($form->createView(), array(
- 'method' => 'post',
- 'action' => 'http://foo.com/directory'
- ));
-
- $this->assertSame('<form method="post" action="http://foo.com/directory">', $html);
- }
-
- public function testStartTagForMultipartForm()
- {
- $form = $this->factory->createBuilder('form', null, array(
- 'method' => 'get',
- 'action' => 'http://example.com/directory'
- ))
- ->add('file', 'file')
- ->getForm();
-
- $html = $this->renderStart($form->createView());
-
- $this->assertSame('<form method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
- }
-
- public function testStartTagWithExtraAttributes()
- {
- $form = $this->factory->create('form', null, array(
- 'method' => 'get',
- 'action' => 'http://example.com/directory'
- ));
-
- $html = $this->renderStart($form->createView(), array(
- 'attr' => array('class' => 'foobar'),
- ));
-
- $this->assertSame('<form method="get" action="http://example.com/directory" class="foobar">', $html);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractRequestHandlerTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \Symfony\Component\Form\RequestHandlerInterface
- */
- protected $requestHandler;
-
- protected $request;
-
- protected function setUp()
- {
- $this->requestHandler = $this->getRequestHandler();
- $this->request = null;
- }
-
- public function methodExceptGetProvider()
- {
- return array(
- array('POST'),
- array('PUT'),
- array('DELETE'),
- array('PATCH'),
- );
- }
-
- public function methodProvider()
- {
- return array_merge(array(
- array('GET'),
- ), $this->methodExceptGetProvider());
- }
-
- /**
- * @dataProvider methodProvider
- */
- public function testSubmitIfNameInRequest($method)
- {
- $form = $this->getMockForm('param1', $method);
-
- $this->setRequestData($method, array(
- 'param1' => 'DATA',
- ));
-
- $form->expects($this->once())
- ->method('submit')
- ->with('DATA', 'PATCH' !== $method);
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodProvider
- */
- public function testDoNotSubmitIfWrongRequestMethod($method)
- {
- $form = $this->getMockForm('param1', $method);
-
- $otherMethod = 'POST' === $method ? 'PUT' : 'POST';
-
- $this->setRequestData($otherMethod, array(
- 'param1' => 'DATA',
- ));
-
- $form->expects($this->never())
- ->method('submit');
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodExceptGetProvider
- */
- public function testSubmitSimpleFormWithNullIfNameNotInRequestAndNotGetRequest($method)
- {
- $form = $this->getMockForm('param1', $method, false);
-
- $this->setRequestData($method, array(
- 'paramx' => array(),
- ));
-
- $form->expects($this->once())
- ->method('submit')
- ->with($this->identicalTo(null), 'PATCH' !== $method);
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodExceptGetProvider
- */
- public function testSubmitCompoundFormWithArrayIfNameNotInRequestAndNotGetRequest($method)
- {
- $form = $this->getMockForm('param1', $method, true);
-
- $this->setRequestData($method, array(
- 'paramx' => array(),
- ));
-
- $form->expects($this->once())
- ->method('submit')
- ->with($this->identicalTo(array()), 'PATCH' !== $method);
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- public function testDoNotSubmitIfNameNotInRequestAndGetRequest()
- {
- $form = $this->getMockForm('param1', 'GET');
-
- $this->setRequestData('GET', array(
- 'paramx' => array(),
- ));
-
- $form->expects($this->never())
- ->method('submit');
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodProvider
- */
- public function testSubmitFormWithEmptyNameIfAtLeastOneFieldInRequest($method)
- {
- $form = $this->getMockForm('', $method);
- $form->expects($this->any())
- ->method('all')
- ->will($this->returnValue(array(
- 'param1' => $this->getMockForm('param1'),
- 'param2' => $this->getMockForm('param2'),
- )));
-
- $this->setRequestData($method, $requestData = array(
- 'param1' => 'submitted value',
- 'paramx' => 'submitted value',
- ));
-
- $form->expects($this->once())
- ->method('submit')
- ->with($requestData, 'PATCH' !== $method);
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodProvider
- */
- public function testDoNotSubmitFormWithEmptyNameIfNoFieldInRequest($method)
- {
- $form = $this->getMockForm('', $method);
- $form->expects($this->any())
- ->method('all')
- ->will($this->returnValue(array(
- 'param1' => $this->getMockForm('param1'),
- 'param2' => $this->getMockForm('param2'),
- )));
-
- $this->setRequestData($method, array(
- 'paramx' => 'submitted value',
- ));
-
- $form->expects($this->never())
- ->method('submit');
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodExceptGetProvider
- */
- public function testMergeParamsAndFiles($method)
- {
- $form = $this->getMockForm('param1', $method);
- $file = $this->getMockFile();
-
- $this->setRequestData($method, array(
- 'param1' => array(
- 'field1' => 'DATA',
- ),
- ), array(
- 'param1' => array(
- 'field2' => $file,
- ),
- ));
-
- $form->expects($this->once())
- ->method('submit')
- ->with(array(
- 'field1' => 'DATA',
- 'field2' => $file,
- ), 'PATCH' !== $method);
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodExceptGetProvider
- */
- public function testParamTakesPrecedenceOverFile($method)
- {
- $form = $this->getMockForm('param1', $method);
- $file = $this->getMockFile();
-
- $this->setRequestData($method, array(
- 'param1' => 'DATA',
- ), array(
- 'param1' => $file,
- ));
-
- $form->expects($this->once())
- ->method('submit')
- ->with('DATA', 'PATCH' !== $method);
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- /**
- * @dataProvider methodExceptGetProvider
- */
- public function testSubmitFileIfNoParam($method)
- {
- $form = $this->getMockForm('param1', $method);
- $file = $this->getMockFile();
-
- $this->setRequestData($method, array(
- 'param1' => null,
- ), array(
- 'param1' => $file,
- ));
-
- $form->expects($this->once())
- ->method('submit')
- ->with($file, 'PATCH' !== $method);
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- abstract protected function setRequestData($method, $data, $files = array());
-
- abstract protected function getRequestHandler();
-
- abstract protected function getMockFile();
-
- protected function getMockForm($name, $method = null, $compound = true)
- {
- $config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
- $config->expects($this->any())
- ->method('getMethod')
- ->will($this->returnValue($method));
- $config->expects($this->any())
- ->method('getCompound')
- ->will($this->returnValue($compound));
-
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $form->expects($this->any())
- ->method('getName')
- ->will($this->returnValue($name));
- $form->expects($this->any())
- ->method('getConfig')
- ->will($this->returnValue($config));
-
- return $form;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormError;
-
-abstract class AbstractTableLayoutTest extends AbstractLayoutTest
-{
- public function testRow()
- {
- $form = $this->factory->createNamed('name', 'text');
- $form->addError(new FormError('[trans]Error![/trans]'));
- $view = $form->createView();
- $html = $this->renderRow($view);
-
- $this->assertMatchesXpath($html,
-'/tr
- [
- ./td
- [./label[@for="name"]]
- /following-sibling::td
- [
- ./ul
- [./li[.="[trans]Error![/trans]"]]
- [count(./li)=1]
- /following-sibling::input[@id="name"]
- ]
- ]
-'
- );
- }
-
- public function testLabelIsNotRenderedWhenSetToFalse()
- {
- $form = $this->factory->createNamed('name', 'text', null, array(
- 'label' => false
- ));
- $html = $this->renderRow($form->createView());
-
- $this->assertMatchesXpath($html,
-'/tr
- [
- ./td
- [count(//label)=0]
- /following-sibling::td
- [./input[@id="name"]]
- ]
-'
- );
- }
-
- public function testRepeatedRow()
- {
- $form = $this->factory->createNamed('name', 'repeated');
- $html = $this->renderRow($form->createView());
-
- $this->assertMatchesXpath($html,
-'/tr
- [
- ./td
- [./label[@for="name_first"]]
- /following-sibling::td
- [./input[@id="name_first"]]
- ]
-/following-sibling::tr
- [
- ./td
- [./label[@for="name_second"]]
- /following-sibling::td
- [./input[@id="name_second"]]
- ]
-/following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- [count(../tr)=3]
-'
- );
- }
-
- public function testRepeatedRowWithErrors()
- {
- $form = $this->factory->createNamed('name', 'repeated');
- $form->addError(new FormError('[trans]Error![/trans]'));
- $view = $form->createView();
- $html = $this->renderRow($view);
-
- // The errors of the form are not rendered by intention!
- // In practice, repeated fields cannot have errors as all errors
- // on them are mapped to the first child.
- // (see RepeatedTypeValidatorExtension)
-
- $this->assertMatchesXpath($html,
-'/tr
- [
- ./td
- [./label[@for="name_first"]]
- /following-sibling::td
- [./input[@id="name_first"]]
- ]
-/following-sibling::tr
- [
- ./td
- [./label[@for="name_second"]]
- /following-sibling::td
- [./input[@id="name_second"]]
- ]
-/following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- [count(../tr)=3]
-'
- );
- }
-
- public function testButtonRow()
- {
- $form = $this->factory->createNamed('name', 'button');
- $view = $form->createView();
- $html = $this->renderRow($view);
-
- $this->assertMatchesXpath($html,
-'/tr
- [
- ./td
- [.=""]
- /following-sibling::td
- [./button[@type="button"][@name="name"]]
- ]
- [count(//label)=0]
-'
- );
- }
-
- public function testRest()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('field1', 'text')
- ->add('field2', 'repeated')
- ->add('field3', 'text')
- ->add('field4', 'text')
- ->getForm()
- ->createView();
-
- // Render field2 row -> does not implicitly call renderWidget because
- // it is a repeated field!
- $this->renderRow($view['field2']);
-
- // Render field3 widget
- $this->renderWidget($view['field3']);
-
- // Rest should only contain field1 and field4
- $html = $this->renderRest($view);
-
- $this->assertMatchesXpath($html,
-'/tr
- [
- ./td
- [./label[@for="name_field1"]]
- /following-sibling::td
- [./input[@id="name_field1"]]
- ]
-/following-sibling::tr
- [
- ./td
- [./label[@for="name_field4"]]
- /following-sibling::td
- [./input[@id="name_field4"]]
- ]
- [count(../tr)=3]
- [count(..//label)=2]
- [count(..//input)=3]
-/following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
-'
- );
- }
-
- public function testCollection()
- {
- $form = $this->factory->createNamed('name', 'collection', array('a', 'b'), array(
- 'type' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/table
- [
- ./tr[./td/input[@type="text"][@value="a"]]
- /following-sibling::tr[./td/input[@type="text"][@value="b"]]
- /following-sibling::tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="name__token"]]
- ]
- [count(./tr[./td/input])=3]
-'
- );
- }
-
- public function testEmptyCollection()
- {
- $form = $this->factory->createNamed('name', 'collection', array(), array(
- 'type' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/table
- [./tr[@style="display: none"][./td[@colspan="2"]/input[@type="hidden"][@id="name__token"]]]
- [count(./tr[./td/input])=1]
-'
- );
- }
-
- public function testForm()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->setMethod('PUT')
- ->setAction('http://example.com')
- ->add('firstName', 'text')
- ->add('lastName', 'text')
- ->getForm()
- ->createView();
-
- $html = $this->renderForm($view, array(
- 'id' => 'my&id',
- 'attr' => array('class' => 'my&class'),
- ));
-
- $this->assertMatchesXpath($html,
-'/form
- [
- ./input[@type="hidden"][@name="_method"][@value="PUT"]
- /following-sibling::table
- [
- ./tr
- [
- ./td
- [./label[@for="name_firstName"]]
- /following-sibling::td
- [./input[@id="name_firstName"]]
- ]
- /following-sibling::tr
- [
- ./td
- [./label[@for="name_lastName"]]
- /following-sibling::td
- [./input[@id="name_lastName"]]
- ]
- /following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- ]
- [count(.//input)=3]
- [@id="my&id"]
- [@class="my&class"]
- ]
- [@method="post"]
- [@action="http://example.com"]
- [@class="my&class"]
-'
- );
- }
-
- public function testFormWidget()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('firstName', 'text')
- ->add('lastName', 'text')
- ->getForm()
- ->createView();
-
- $this->assertWidgetMatchesXpath($view, array(),
-'/table
- [
- ./tr
- [
- ./td
- [./label[@for="name_firstName"]]
- /following-sibling::td
- [./input[@id="name_firstName"]]
- ]
- /following-sibling::tr
- [
- ./td
- [./label[@for="name_lastName"]]
- /following-sibling::td
- [./input[@id="name_lastName"]]
- ]
- /following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- ]
- [count(.//input)=3]
-'
- );
- }
-
- // https://github.com/symfony/symfony/issues/2308
- public function testNestedFormError()
- {
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->add($this->factory
- ->createNamedBuilder('child', 'form', null, array('error_bubbling' => false))
- ->add('grandChild', 'form')
- )
- ->getForm();
-
- $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/table
- [
- ./tr/td/ul[./li[.="[trans]Error![/trans]"]]
- /following-sibling::table[@id="name_child"]
- ]
- [count(.//li[.="[trans]Error![/trans]"])=1]
-'
- );
- }
-
- public function testCsrf()
- {
- $this->csrfProvider->expects($this->any())
- ->method('generateCsrfToken')
- ->will($this->returnValue('foo&bar'));
-
- $form = $this->factory->createNamedBuilder('name', 'form')
- ->add($this->factory
- // No CSRF protection on nested forms
- ->createNamedBuilder('child', 'form')
- ->add($this->factory->createNamedBuilder('grandchild', 'text'))
- )
- ->getForm();
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/table
- [
- ./tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- ]
- [count(.//input[@type="hidden"])=1]
-'
- );
- }
-
- public function testRepeated()
- {
- $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
- 'type' => 'text',
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/table
- [
- ./tr
- [
- ./td
- [./label[@for="name_first"]]
- /following-sibling::td
- [./input[@type="text"][@id="name_first"]]
- ]
- /following-sibling::tr
- [
- ./td
- [./label[@for="name_second"]]
- /following-sibling::td
- [./input[@type="text"][@id="name_second"]]
- ]
- /following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- ]
- [count(.//input)=3]
-'
- );
- }
-
- public function testRepeatedWithCustomOptions()
- {
- $form = $this->factory->createNamed('name', 'repeated', 'foobar', array(
- 'type' => 'password',
- 'first_options' => array('label' => 'Test', 'required' => false),
- 'second_options' => array('label' => 'Test2')
- ));
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/table
- [
- ./tr
- [
- ./td
- [./label[@for="name_first"][.="[trans]Test[/trans]"]]
- /following-sibling::td
- [./input[@type="password"][@id="name_first"][@required="required"]]
- ]
- /following-sibling::tr
- [
- ./td
- [./label[@for="name_second"][.="[trans]Test2[/trans]"]]
- /following-sibling::td
- [./input[@type="password"][@id="name_second"][@required="required"]]
- ]
- /following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- ]
- [count(.//input)=3]
-'
- );
- }
-
- /**
- * The block "_name_child_label" should be overridden in the theme of the
- * implemented driver.
- */
- public function testCollectionRowWithCustomBlock()
- {
- $collection = array('one', 'two', 'three');
- $form = $this->factory->createNamedBuilder('name', 'collection', $collection)
- ->getForm();
-
- $this->assertWidgetMatchesXpath($form->createView(), array(),
-'/table
- [
- ./tr[./td/label[.="Custom label: [trans]0[/trans]"]]
- /following-sibling::tr[./td/label[.="Custom label: [trans]1[/trans]"]]
- /following-sibling::tr[./td/label[.="Custom label: [trans]2[/trans]"]]
- ]
-'
- );
- }
-
- public function testFormEndWithRest()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('field1', 'text')
- ->add('field2', 'text')
- ->getForm()
- ->createView();
-
- $this->renderWidget($view['field1']);
-
- // Rest should only contain field2
- $html = $this->renderEnd($view);
-
- // Insert the start tag, the end tag should be rendered by the helper
- // Unfortunately this is not valid HTML, because the surrounding table
- // tag is missing. If someone renders a form with table layout
- // manually, she should call form_rest() explicitly within the <table>
- // tag.
- $this->assertMatchesXpath('<form>' . $html,
-'/form
- [
- ./tr
- [
- ./td
- [./label[@for="name_field2"]]
- /following-sibling::td
- [./input[@id="name_field2"]]
- ]
- /following-sibling::tr[@style="display: none"]
- [./td[@colspan="2"]/input
- [@type="hidden"]
- [@id="name__token"]
- ]
- ]
-'
- );
- }
-
- public function testFormEndWithoutRest()
- {
- $view = $this->factory->createNamedBuilder('name', 'form')
- ->add('field1', 'text')
- ->add('field2', 'text')
- ->getForm()
- ->createView();
-
- $this->renderWidget($view['field1']);
-
- // Rest should only contain field2, but isn't rendered
- $html = $this->renderEnd($view, array('render_rest' => false));
-
- $this->assertEquals('</form>', $html);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CompoundFormPerformanceTest extends \Symfony\Component\Form\Tests\FormPerformanceTestCase
-{
- /**
- * Create a compound form multiple times, as happens in a collection form
- *
- * @group benchmark
- */
- public function testArrayBasedForm()
- {
- $this->setMaxRunningTime(1);
-
- for ($i = 0; $i < 40; ++$i) {
- $form = $this->factory->createBuilder('form')
- ->add('firstName', 'text')
- ->add('lastName', 'text')
- ->add('gender', 'choice', array(
- 'choices' => array('male' => 'Male', 'female' => 'Female'),
- 'required' => false,
- ))
- ->add('age', 'number')
- ->add('birthDate', 'birthday')
- ->add('city', 'choice', array(
- // simulate 300 different cities
- 'choices' => range(1, 300),
- ))
- ->getForm();
-
- // load the form into a view
- $form->createView();
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\File\UploadedFile;
-use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
-
-class CompoundFormTest extends AbstractFormTest
-{
- public function testValidIfAllChildrenAreValid()
- {
- $this->form->add($this->getValidForm('firstName'));
- $this->form->add($this->getValidForm('lastName'));
-
- $this->form->submit(array(
- 'firstName' => 'Bernhard',
- 'lastName' => 'Schussek',
- ));
-
- $this->assertTrue($this->form->isValid());
- }
-
- public function testInvalidIfChildIsInvalid()
- {
- $this->form->add($this->getValidForm('firstName'));
- $this->form->add($this->getInvalidForm('lastName'));
-
- $this->form->submit(array(
- 'firstName' => 'Bernhard',
- 'lastName' => 'Schussek',
- ));
-
- $this->assertFalse($this->form->isValid());
- }
-
- public function testSubmitForwardsNullIfValueIsMissing()
- {
- $child = $this->getMockForm('firstName');
-
- $this->form->add($child);
-
- $child->expects($this->once())
- ->method('submit')
- ->with($this->equalTo(null));
-
- $this->form->submit(array());
- }
-
- public function testSubmitDoesNotForwardNullIfNotClearMissing()
- {
- $child = $this->getMockForm('firstName');
-
- $this->form->add($child);
-
- $child->expects($this->never())
- ->method('submit');
-
- $this->form->submit(array(), false);
- }
-
- public function testClearMissingFlagIsForwarded()
- {
- $child = $this->getMockForm('firstName');
-
- $this->form->add($child);
-
- $child->expects($this->once())
- ->method('submit')
- ->with($this->equalTo('foo'), false);
-
- $this->form->submit(array('firstName' => 'foo'), false);
- }
-
- public function testCloneChildren()
- {
- $child = $this->getBuilder('child')->getForm();
- $this->form->add($child);
-
- $clone = clone $this->form;
-
- $this->assertNotSame($this->form, $clone);
- $this->assertNotSame($child, $clone['child']);
- }
-
- public function testNotEmptyIfChildNotEmpty()
- {
- $child = $this->getMockForm();
- $child->expects($this->once())
- ->method('isEmpty')
- ->will($this->returnValue(false));
-
- $this->form->setData(null);
- $this->form->add($child);
-
- $this->assertFalse($this->form->isEmpty());
- }
-
- public function testValidIfSubmittedAndDisabledWithChildren()
- {
- $this->factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('name', 'text', null, array())
- ->will($this->returnValue($this->getBuilder('name')));
-
- $form = $this->getBuilder('person')
- ->setDisabled(true)
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->add('name', 'text')
- ->getForm();
- $form->submit(array('name' => 'Jacques Doe'));
-
- $this->assertTrue($form->isValid());
- }
-
- public function testNotValidIfChildNotValid()
- {
- $child = $this->getMockForm();
- $child->expects($this->once())
- ->method('isValid')
- ->will($this->returnValue(false));
-
- $this->form->add($child);
- $this->form->submit(array());
-
- $this->assertFalse($this->form->isValid());
- }
-
- public function testAdd()
- {
- $child = $this->getBuilder('foo')->getForm();
- $this->form->add($child);
-
- $this->assertTrue($this->form->has('foo'));
- $this->assertSame($this->form, $child->getParent());
- $this->assertSame(array('foo' => $child), $this->form->all());
- }
-
- public function testAddUsingNameAndType()
- {
- $child = $this->getBuilder('foo')->getForm();
-
- $this->factory->expects($this->once())
- ->method('createNamed')
- ->with('foo', 'text', null, array(
- 'bar' => 'baz',
- 'auto_initialize' => false,
- ))
- ->will($this->returnValue($child));
-
- $this->form->add('foo', 'text', array('bar' => 'baz'));
-
- $this->assertTrue($this->form->has('foo'));
- $this->assertSame($this->form, $child->getParent());
- $this->assertSame(array('foo' => $child), $this->form->all());
- }
-
- public function testAddUsingIntegerNameAndType()
- {
- $child = $this->getBuilder(0)->getForm();
-
- $this->factory->expects($this->once())
- ->method('createNamed')
- ->with('0', 'text', null, array(
- 'bar' => 'baz',
- 'auto_initialize' => false,
- ))
- ->will($this->returnValue($child));
-
- // in order to make casting unnecessary
- $this->form->add(0, 'text', array('bar' => 'baz'));
-
- $this->assertTrue($this->form->has(0));
- $this->assertSame($this->form, $child->getParent());
- $this->assertSame(array(0 => $child), $this->form->all());
- }
-
- public function testAddUsingNameButNoType()
- {
- $this->form = $this->getBuilder('name', null, '\stdClass')
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
-
- $child = $this->getBuilder('foo')->getForm();
-
- $this->factory->expects($this->once())
- ->method('createForProperty')
- ->with('\stdClass', 'foo')
- ->will($this->returnValue($child));
-
- $this->form->add('foo');
-
- $this->assertTrue($this->form->has('foo'));
- $this->assertSame($this->form, $child->getParent());
- $this->assertSame(array('foo' => $child), $this->form->all());
- }
-
- public function testAddUsingNameButNoTypeAndOptions()
- {
- $this->form = $this->getBuilder('name', null, '\stdClass')
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
-
- $child = $this->getBuilder('foo')->getForm();
-
- $this->factory->expects($this->once())
- ->method('createForProperty')
- ->with('\stdClass', 'foo', null, array(
- 'bar' => 'baz',
- 'auto_initialize' => false,
- ))
- ->will($this->returnValue($child));
-
- $this->form->add('foo', null, array('bar' => 'baz'));
-
- $this->assertTrue($this->form->has('foo'));
- $this->assertSame($this->form, $child->getParent());
- $this->assertSame(array('foo' => $child), $this->form->all());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
- */
- public function testAddThrowsExceptionIfAlreadySubmitted()
- {
- $this->form->submit(array());
- $this->form->add($this->getBuilder('foo')->getForm());
- }
-
- public function testRemove()
- {
- $child = $this->getBuilder('foo')->getForm();
- $this->form->add($child);
- $this->form->remove('foo');
-
- $this->assertNull($child->getParent());
- $this->assertCount(0, $this->form);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
- */
- public function testRemoveThrowsExceptionIfAlreadySubmitted()
- {
- $this->form->add($this->getBuilder('foo')->setCompound(false)->getForm());
- $this->form->submit(array('foo' => 'bar'));
- $this->form->remove('foo');
- }
-
- public function testRemoveIgnoresUnknownName()
- {
- $this->form->remove('notexisting');
- }
-
- public function testArrayAccess()
- {
- $child = $this->getBuilder('foo')->getForm();
-
- $this->form[] = $child;
-
- $this->assertTrue(isset($this->form['foo']));
- $this->assertSame($child, $this->form['foo']);
-
- unset($this->form['foo']);
-
- $this->assertFalse(isset($this->form['foo']));
- }
-
- public function testCountable()
- {
- $this->form->add($this->getBuilder('foo')->getForm());
- $this->form->add($this->getBuilder('bar')->getForm());
-
- $this->assertCount(2, $this->form);
- }
-
- public function testIterator()
- {
- $this->form->add($this->getBuilder('foo')->getForm());
- $this->form->add($this->getBuilder('bar')->getForm());
-
- $this->assertSame($this->form->all(), iterator_to_array($this->form));
- }
-
- public function testAddMapsViewDataToFormIfInitialized()
- {
- $test = $this;
- $mapper = $this->getDataMapper();
- $form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'foo' => 'bar',
- )))
- ->setData('foo')
- ->getForm();
-
- $child = $this->getBuilder()->getForm();
- $mapper->expects($this->once())
- ->method('mapDataToForms')
- ->with('bar', $this->isInstanceOf('\RecursiveIteratorIterator'))
- ->will($this->returnCallback(function ($data, \RecursiveIteratorIterator $iterator) use ($child, $test) {
- $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
- $test->assertSame(array($child), iterator_to_array($iterator));
- }));
-
- $form->initialize();
- $form->add($child);
- }
-
- public function testAddDoesNotMapViewDataToFormIfNotInitialized()
- {
- $mapper = $this->getDataMapper();
- $form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->getForm();
-
- $child = $this->getBuilder()->getForm();
- $mapper->expects($this->never())
- ->method('mapDataToForms');
-
- $form->add($child);
- }
-
- public function testAddDoesNotMapViewDataToFormIfInheritData()
- {
- $mapper = $this->getDataMapper();
- $form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->setInheritData(true)
- ->getForm();
-
- $child = $this->getBuilder()->getForm();
- $mapper->expects($this->never())
- ->method('mapDataToForms');
-
- $form->initialize();
- $form->add($child);
- }
-
- public function testSetDataMapsViewDataToChildren()
- {
- $test = $this;
- $mapper = $this->getDataMapper();
- $form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'foo' => 'bar',
- )))
- ->getForm();
-
- $form->add($child1 = $this->getBuilder('firstName')->getForm());
- $form->add($child2 = $this->getBuilder('lastName')->getForm());
-
- $mapper->expects($this->once())
- ->method('mapDataToForms')
- ->with('bar', $this->isInstanceOf('\RecursiveIteratorIterator'))
- ->will($this->returnCallback(function ($data, \RecursiveIteratorIterator $iterator) use ($child1, $child2, $test) {
- $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
- $test->assertSame(array('firstName' => $child1, 'lastName' => $child2), iterator_to_array($iterator));
- }));
-
- $form->setData('foo');
- }
-
- public function testSubmitMapsSubmittedChildrenOntoExistingViewData()
- {
- $test = $this;
- $mapper = $this->getDataMapper();
- $form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'foo' => 'bar',
- )))
- ->setData('foo')
- ->getForm();
-
- $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm());
- $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm());
-
- $mapper->expects($this->once())
- ->method('mapFormsToData')
- ->with($this->isInstanceOf('\RecursiveIteratorIterator'), 'bar')
- ->will($this->returnCallback(function (\RecursiveIteratorIterator $iterator) use ($child1, $child2, $test) {
- $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
- $test->assertSame(array('firstName' => $child1, 'lastName' => $child2), iterator_to_array($iterator));
- $test->assertEquals('Bernhard', $child1->getData());
- $test->assertEquals('Schussek', $child2->getData());
- }));
-
- $form->submit(array(
- 'firstName' => 'Bernhard',
- 'lastName' => 'Schussek',
- ));
- }
-
- public function testMapFormsToDataIsNotInvokedIfInheritData()
- {
- $mapper = $this->getDataMapper();
- $form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->setInheritData(true)
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'foo' => 'bar',
- )))
- ->getForm();
-
- $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm());
- $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm());
-
- $mapper->expects($this->never())
- ->method('mapFormsToData');
-
- $form->submit(array(
- 'firstName' => 'Bernhard',
- 'lastName' => 'Schussek',
- ));
- }
-
- /*
- * https://github.com/symfony/symfony/issues/4480
- */
- public function testSubmitRestoresViewDataIfCompoundAndEmpty()
- {
- $mapper = $this->getDataMapper();
- $object = new \stdClass();
- $form = $this->getBuilder('name', null, 'stdClass')
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->setData($object)
- ->getForm();
-
- $form->submit(array());
-
- $this->assertSame($object, $form->getData());
- }
-
- public function testSubmitMapsSubmittedChildrenOntoEmptyData()
- {
- $test = $this;
- $mapper = $this->getDataMapper();
- $object = new \stdClass();
- $form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($mapper)
- ->setEmptyData($object)
- ->setData(null)
- ->getForm();
-
- $form->add($child = $this->getBuilder('name')->setCompound(false)->getForm());
-
- $mapper->expects($this->once())
- ->method('mapFormsToData')
- ->with($this->isInstanceOf('\RecursiveIteratorIterator'), $object)
- ->will($this->returnCallback(function (\RecursiveIteratorIterator $iterator) use ($child, $test) {
- $test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
- $test->assertSame(array('name' => $child), iterator_to_array($iterator));
- }));
-
- $form->submit(array(
- 'name' => 'Bernhard',
- ));
- }
-
- public function requestMethodProvider()
- {
- return array(
- array('POST'),
- array('PUT'),
- array('DELETE'),
- array('PATCH'),
- );
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitPostOrPutRequest($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $path = tempnam(sys_get_temp_dir(), 'sf2');
- touch($path);
-
- $values = array(
- 'author' => array(
- 'name' => 'Bernhard',
- 'image' => array('filename' => 'foobar.png'),
- ),
- );
-
- $files = array(
- 'author' => array(
- 'error' => array('image' => UPLOAD_ERR_OK),
- 'name' => array('image' => 'upload.png'),
- 'size' => array('image' => 123),
- 'tmp_name' => array('image' => $path),
- 'type' => array('image' => 'image/png'),
- ),
- );
-
- $request = new Request(array(), $values, array(), array(), $files, array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $form = $this->getBuilder('author')
- ->setMethod($method)
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->setRequestHandler(new HttpFoundationRequestHandler())
- ->getForm();
- $form->add($this->getBuilder('name')->getForm());
- $form->add($this->getBuilder('image')->getForm());
-
- $form->handleRequest($request);
-
- $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
-
- $this->assertEquals('Bernhard', $form['name']->getData());
- $this->assertEquals($file, $form['image']->getData());
-
- unlink($path);
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitPostOrPutRequestWithEmptyRootFormName($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $path = tempnam(sys_get_temp_dir(), 'sf2');
- touch($path);
-
- $values = array(
- 'name' => 'Bernhard',
- 'extra' => 'data',
- );
-
- $files = array(
- 'image' => array(
- 'error' => UPLOAD_ERR_OK,
- 'name' => 'upload.png',
- 'size' => 123,
- 'tmp_name' => $path,
- 'type' => 'image/png',
- ),
- );
-
- $request = new Request(array(), $values, array(), array(), $files, array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $form = $this->getBuilder('')
- ->setMethod($method)
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->setRequestHandler(new HttpFoundationRequestHandler())
- ->getForm();
- $form->add($this->getBuilder('name')->getForm());
- $form->add($this->getBuilder('image')->getForm());
-
- $form->handleRequest($request);
-
- $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
-
- $this->assertEquals('Bernhard', $form['name']->getData());
- $this->assertEquals($file, $form['image']->getData());
- $this->assertEquals(array('extra' => 'data'), $form->getExtraData());
-
- unlink($path);
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitPostOrPutRequestWithSingleChildForm($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $path = tempnam(sys_get_temp_dir(), 'sf2');
- touch($path);
-
- $files = array(
- 'image' => array(
- 'error' => UPLOAD_ERR_OK,
- 'name' => 'upload.png',
- 'size' => 123,
- 'tmp_name' => $path,
- 'type' => 'image/png',
- ),
- );
-
- $request = new Request(array(), array(), array(), array(), $files, array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $form = $this->getBuilder('image')
- ->setMethod($method)
- ->setRequestHandler(new HttpFoundationRequestHandler())
- ->getForm();
-
- $form->handleRequest($request);
-
- $file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
-
- $this->assertEquals($file, $form->getData());
-
- unlink($path);
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitPostOrPutRequestWithSingleChildFormUploadedFile($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $path = tempnam(sys_get_temp_dir(), 'sf2');
- touch($path);
-
- $values = array(
- 'name' => 'Bernhard',
- );
-
- $request = new Request(array(), $values, array(), array(), array(), array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $form = $this->getBuilder('name')
- ->setMethod($method)
- ->setRequestHandler(new HttpFoundationRequestHandler())
- ->getForm();
-
- $form->handleRequest($request);
-
- $this->assertEquals('Bernhard', $form->getData());
-
- unlink($path);
- }
-
- public function testSubmitGetRequest()
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $values = array(
- 'author' => array(
- 'firstName' => 'Bernhard',
- 'lastName' => 'Schussek',
- ),
- );
-
- $request = new Request($values, array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => 'GET',
- ));
-
- $form = $this->getBuilder('author')
- ->setMethod('GET')
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->setRequestHandler(new HttpFoundationRequestHandler())
- ->getForm();
- $form->add($this->getBuilder('firstName')->getForm());
- $form->add($this->getBuilder('lastName')->getForm());
-
- $form->handleRequest($request);
-
- $this->assertEquals('Bernhard', $form['firstName']->getData());
- $this->assertEquals('Schussek', $form['lastName']->getData());
- }
-
- public function testSubmitGetRequestWithEmptyRootFormName()
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $values = array(
- 'firstName' => 'Bernhard',
- 'lastName' => 'Schussek',
- 'extra' => 'data'
- );
-
- $request = new Request($values, array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => 'GET',
- ));
-
- $form = $this->getBuilder('')
- ->setMethod('GET')
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->setRequestHandler(new HttpFoundationRequestHandler())
- ->getForm();
- $form->add($this->getBuilder('firstName')->getForm());
- $form->add($this->getBuilder('lastName')->getForm());
-
- $form->handleRequest($request);
-
- $this->assertEquals('Bernhard', $form['firstName']->getData());
- $this->assertEquals('Schussek', $form['lastName']->getData());
- $this->assertEquals(array('extra' => 'data'), $form->getExtraData());
- }
-
- public function testGetErrorsAsStringDeep()
- {
- $parent = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
-
- $this->form->addError(new FormError('Error!'));
-
- $parent->add($this->form);
- $parent->add($this->getBuilder('foo')->getForm());
-
- $this->assertEquals("name:\n ERROR: Error!\nfoo:\n No errors\n", $parent->getErrorsAsString());
- }
-
- protected function createForm()
- {
- return $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-class ChoiceListTest extends \PHPUnit_Framework_TestCase
-{
- private $obj1;
-
- private $obj2;
-
- private $obj3;
-
- private $obj4;
-
- private $list;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->obj1 = new \stdClass();
- $this->obj2 = new \stdClass();
- $this->obj3 = new \stdClass();
- $this->obj4 = new \stdClass();
-
- $this->list = new ChoiceList(
- array(
- 'Group 1' => array($this->obj1, $this->obj2),
- 'Group 2' => array($this->obj3, $this->obj4),
- ),
- array(
- 'Group 1' => array('A', 'B'),
- 'Group 2' => array('C', 'D'),
- ),
- array($this->obj2, $this->obj3)
- );
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->obj1 = null;
- $this->obj2 = null;
- $this->obj3 = null;
- $this->obj4 = null;
- $this->list = null;
- }
-
- public function testInitArray()
- {
- $this->list = new ChoiceList(
- array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
- array('A', 'B', 'C', 'D'),
- array($this->obj2)
- );
-
- $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
- $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
- $this->assertEquals(array(1 => new ChoiceView($this->obj2, '1', 'B')), $this->list->getPreferredViews());
- $this->assertEquals(array(0 => new ChoiceView($this->obj1, '0', 'A'), 2 => new ChoiceView($this->obj3, '2', 'C'), 3 => new ChoiceView($this->obj4, '3', 'D')), $this->list->getRemainingViews());
- }
-
- /**
- * Necessary for interoperability with MongoDB cursors or ORM relations as
- * choices parameter. A choice itself that is an object implementing \Traversable
- * is not treated as hierarchical structure, but as-is.
- */
- public function testInitNestedTraversable()
- {
- $traversableChoice = new \ArrayIterator(array($this->obj3, $this->obj4));
-
- $this->list = new ChoiceList(
- new \ArrayIterator(array(
- 'Group' => array($this->obj1, $this->obj2),
- 'Not a Group' => $traversableChoice
- )),
- array(
- 'Group' => array('A', 'B'),
- 'Not a Group' => 'C',
- ),
- array($this->obj2)
- );
-
- $this->assertSame(array($this->obj1, $this->obj2, $traversableChoice), $this->list->getChoices());
- $this->assertSame(array('0', '1', '2'), $this->list->getValues());
- $this->assertEquals(array(
- 'Group' => array(1 => new ChoiceView($this->obj2, '1', 'B'))
- ), $this->list->getPreferredViews());
- $this->assertEquals(array(
- 'Group' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
- 2 => new ChoiceView($traversableChoice, '2', 'C')
- ), $this->list->getRemainingViews());
- }
-
- public function testInitNestedArray()
- {
- $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
- $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
- $this->assertEquals(array(
- 'Group 1' => array(1 => new ChoiceView($this->obj2, '1', 'B')),
- 'Group 2' => array(2 => new ChoiceView($this->obj3, '2', 'C'))
- ), $this->list->getPreferredViews());
- $this->assertEquals(array(
- 'Group 1' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
- 'Group 2' => array(3 => new ChoiceView($this->obj4, '3', 'D'))
- ), $this->list->getRemainingViews());
- }
-
- public function testGetIndicesForChoices()
- {
- $choices = array($this->obj2, $this->obj3);
- $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
- }
-
- public function testGetIndicesForChoicesIgnoresNonExistingChoices()
- {
- $choices = array($this->obj2, $this->obj3, 'foobar');
- $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
- }
-
- public function testGetIndicesForValues()
- {
- // values and indices are always the same
- $values = array('1', '2');
- $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
- }
-
- public function testGetIndicesForValuesIgnoresNonExistingValues()
- {
- $values = array('1', '2', '5');
- $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
- }
-
- public function testGetChoicesForValues()
- {
- $values = array('1', '2');
- $this->assertSame(array($this->obj2, $this->obj3), $this->list->getChoicesForValues($values));
- }
-
- public function testGetChoicesForValuesCorrectOrderingOfResult()
- {
- $values = array('2', '1');
- $this->assertSame(array($this->obj3, $this->obj2), $this->list->getChoicesForValues($values));
- }
-
- public function testGetChoicesForValuesIgnoresNonExistingValues()
- {
- $values = array('1', '2', '5');
- $this->assertSame(array($this->obj2, $this->obj3), $this->list->getChoicesForValues($values));
- }
-
- public function testGetValuesForChoices()
- {
- $choices = array($this->obj2, $this->obj3);
- $this->assertSame(array('1', '2'), $this->list->getValuesForChoices($choices));
- }
-
- public function testGetValuesForChoicesIgnoresNonExistingChoices()
- {
- $choices = array($this->obj2, $this->obj3, 'foobar');
- $this->assertSame(array('1', '2'), $this->list->getValuesForChoices($choices));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testNonMatchingLabels()
- {
- $this->list = new ChoiceList(
- array($this->obj1, $this->obj2),
- array('A')
- );
- }
-
- public function testLabelsContainingNull()
- {
- $this->list = new ChoiceList(
- array($this->obj1, $this->obj2),
- array('A', null)
- );
-
- $this->assertEquals(
- array(0 => new ChoiceView($this->obj1, '0', 'A'), 1 => new ChoiceView($this->obj2, '1', null)),
- $this->list->getRemainingViews()
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
-use Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-class LazyChoiceListTest extends \PHPUnit_Framework_TestCase
-{
- private $list;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->list = new LazyChoiceListTest_Impl(new SimpleChoiceList(array(
- 'a' => 'A',
- 'b' => 'B',
- 'c' => 'C',
- ), array('b')));
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->list = null;
- }
-
- public function testGetChoices()
- {
- $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getChoices());
- }
-
- public function testGetValues()
- {
- $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getValues());
- }
-
- public function testGetPreferredViews()
- {
- $this->assertEquals(array(1 => new ChoiceView('b', 'b', 'B')), $this->list->getPreferredViews());
- }
-
- public function testGetRemainingViews()
- {
- $this->assertEquals(array(0 => new ChoiceView('a', 'a', 'A'), 2 => new ChoiceView('c', 'c', 'C')), $this->list->getRemainingViews());
- }
-
- public function testGetIndicesForChoices()
- {
- $choices = array('b', 'c');
- $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
- }
-
- public function testGetIndicesForValues()
- {
- $values = array('b', 'c');
- $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
- }
-
- public function testGetChoicesForValues()
- {
- $values = array('b', 'c');
- $this->assertSame(array('b', 'c'), $this->list->getChoicesForValues($values));
- }
-
- public function testGetValuesForChoices()
- {
- $choices = array('b', 'c');
- $this->assertSame(array('b', 'c'), $this->list->getValuesForChoices($choices));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
- */
- public function testLoadChoiceListShouldReturnChoiceList()
- {
- $list = new LazyChoiceListTest_InvalidImpl();
-
- $list->getChoices();
- }
-}
-
-class LazyChoiceListTest_Impl extends LazyChoiceList
-{
- private $choiceList;
-
- public function __construct($choiceList)
- {
- $this->choiceList = $choiceList;
- }
-
- protected function loadChoiceList()
- {
- return $this->choiceList;
- }
-}
-
-class LazyChoiceListTest_InvalidImpl extends LazyChoiceList
-{
- protected function loadChoiceList()
- {
- return new \stdClass();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-class ObjectChoiceListTest_EntityWithToString
-{
- private $property;
-
- public function __construct($property)
- {
- $this->property = $property;
- }
-
- public function __toString()
- {
- return $this->property;
- }
-}
-
-class ObjectChoiceListTest extends \PHPUnit_Framework_TestCase
-{
- private $obj1;
-
- private $obj2;
-
- private $obj3;
-
- private $obj4;
-
- /**
- * @var ObjectChoiceList
- */
- private $list;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->obj1 = (object) array('name' => 'A');
- $this->obj2 = (object) array('name' => 'B');
- $this->obj3 = (object) array('name' => 'C');
- $this->obj4 = (object) array('name' => 'D');
-
- $this->list = new ObjectChoiceList(
- array(
- 'Group 1' => array($this->obj1, $this->obj2),
- 'Group 2' => array($this->obj3, $this->obj4),
- ),
- 'name',
- array($this->obj2, $this->obj3)
- );
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->obj1 = null;
- $this->obj2 = null;
- $this->obj3 = null;
- $this->obj4 = null;
- $this->list = null;
- }
-
- public function testInitArray()
- {
- $this->list = new ObjectChoiceList(
- array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
- 'name',
- array($this->obj2)
- );
-
- $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
- $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
- $this->assertEquals(array(1 => new ChoiceView($this->obj2, '1', 'B')), $this->list->getPreferredViews());
- $this->assertEquals(array(0 => new ChoiceView($this->obj1, '0', 'A'), 2 => new ChoiceView($this->obj3, '2', 'C'), 3 => new ChoiceView($this->obj4, '3', 'D')), $this->list->getRemainingViews());
- }
-
- public function testInitNestedArray()
- {
- $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
- $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
- $this->assertEquals(array(
- 'Group 1' => array(1 => new ChoiceView($this->obj2, '1', 'B')),
- 'Group 2' => array(2 => new ChoiceView($this->obj3, '2', 'C'))
- ), $this->list->getPreferredViews());
- $this->assertEquals(array(
- 'Group 1' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
- 'Group 2' => array(3 => new ChoiceView($this->obj4, '3', 'D'))
- ), $this->list->getRemainingViews());
- }
-
- public function testInitArrayWithGroupPath()
- {
- $this->obj1 = (object) array('name' => 'A', 'category' => 'Group 1');
- $this->obj2 = (object) array('name' => 'B', 'category' => 'Group 1');
- $this->obj3 = (object) array('name' => 'C', 'category' => 'Group 2');
- $this->obj4 = (object) array('name' => 'D', 'category' => 'Group 2');
-
- // Objects with NULL groups are not grouped
- $obj5 = (object) array('name' => 'E', 'category' => null);
-
- // Objects without the group property are not grouped either
- // see https://github.com/symfony/symfony/commit/d9b7abb7c7a0f28e0ce970afc5e305dce5dccddf
- $obj6 = (object) array('name' => 'F');
-
- $this->list = new ObjectChoiceList(
- array($this->obj1, $this->obj2, $this->obj3, $this->obj4, $obj5, $obj6),
- 'name',
- array($this->obj2, $this->obj3),
- 'category'
- );
-
- $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4, $obj5, $obj6), $this->list->getChoices());
- $this->assertSame(array('0', '1', '2', '3', '4', '5'), $this->list->getValues());
- $this->assertEquals(array(
- 'Group 1' => array(1 => new ChoiceView($this->obj2, '1', 'B')),
- 'Group 2' => array(2 => new ChoiceView($this->obj3, '2', 'C'))
- ), $this->list->getPreferredViews());
- $this->assertEquals(array(
- 'Group 1' => array(0 => new ChoiceView($this->obj1, '0', 'A')),
- 'Group 2' => array(3 => new ChoiceView($this->obj4, '3', 'D')),
- 4 => new ChoiceView($obj5, '4', 'E'),
- 5 => new ChoiceView($obj6, '5', 'F'),
- ), $this->list->getRemainingViews());
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testInitArrayWithGroupPathThrowsExceptionIfNestedArray()
- {
- $this->obj1 = (object) array('name' => 'A', 'category' => 'Group 1');
- $this->obj2 = (object) array('name' => 'B', 'category' => 'Group 1');
- $this->obj3 = (object) array('name' => 'C', 'category' => 'Group 2');
- $this->obj4 = (object) array('name' => 'D', 'category' => 'Group 2');
-
- new ObjectChoiceList(
- array(
- 'Group 1' => array($this->obj1, $this->obj2),
- 'Group 2' => array($this->obj3, $this->obj4),
- ),
- 'name',
- array($this->obj2, $this->obj3),
- 'category'
- );
- }
-
- public function testInitArrayWithValuePath()
- {
- $this->obj1 = (object) array('name' => 'A', 'id' => 10);
- $this->obj2 = (object) array('name' => 'B', 'id' => 20);
- $this->obj3 = (object) array('name' => 'C', 'id' => 30);
- $this->obj4 = (object) array('name' => 'D', 'id' => 40);
-
- $this->list = new ObjectChoiceList(
- array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
- 'name',
- array($this->obj2, $this->obj3),
- null,
- 'id'
- );
-
- $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
- $this->assertSame(array('10', '20', '30', '40'), $this->list->getValues());
- $this->assertEquals(array(1 => new ChoiceView($this->obj2, '20', 'B'), 2 => new ChoiceView($this->obj3, '30', 'C')), $this->list->getPreferredViews());
- $this->assertEquals(array(0 => new ChoiceView($this->obj1, '10', 'A'), 3 => new ChoiceView($this->obj4, '40', 'D')), $this->list->getRemainingViews());
- }
-
- public function testInitArrayUsesToString()
- {
- $this->obj1 = new ObjectChoiceListTest_EntityWithToString('A');
- $this->obj2 = new ObjectChoiceListTest_EntityWithToString('B');
- $this->obj3 = new ObjectChoiceListTest_EntityWithToString('C');
- $this->obj4 = new ObjectChoiceListTest_EntityWithToString('D');
-
- $this->list = new ObjectChoiceList(
- array($this->obj1, $this->obj2, $this->obj3, $this->obj4)
- );
-
- $this->assertSame(array($this->obj1, $this->obj2, $this->obj3, $this->obj4), $this->list->getChoices());
- $this->assertSame(array('0', '1', '2', '3'), $this->list->getValues());
- $this->assertEquals(array(0 => new ChoiceView($this->obj1, '0', 'A'), 1 => new ChoiceView($this->obj2, '1', 'B'), 2 => new ChoiceView($this->obj3, '2', 'C'), 3 => new ChoiceView($this->obj4, '3', 'D')), $this->list->getRemainingViews());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\StringCastException
- */
- public function testInitArrayThrowsExceptionIfToStringNotFound()
- {
- $this->obj1 = new ObjectChoiceListTest_EntityWithToString('A');
- $this->obj2 = new ObjectChoiceListTest_EntityWithToString('B');
- $this->obj3 = (object) array('name' => 'C');
- $this->obj4 = new ObjectChoiceListTest_EntityWithToString('D');
-
- new ObjectChoiceList(
- array($this->obj1, $this->obj2, $this->obj3, $this->obj4)
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\ChoiceList;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
-use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-class SimpleChoiceListTest extends \PHPUnit_Framework_TestCase
-{
- private $list;
-
- private $numericList;
-
- protected function setUp()
- {
- parent::setUp();
-
- $choices = array(
- 'Group 1' => array('a' => 'A', 'b' => 'B'),
- 'Group 2' => array('c' => 'C', 'd' => 'D'),
- );
- $numericChoices = array(
- 'Group 1' => array(0 => 'A', 1 => 'B'),
- 'Group 2' => array(2 => 'C', 3 => 'D'),
- );
-
- $this->list = new SimpleChoiceList($choices, array('b', 'c'));
-
- // Use COPY_CHOICE strategy to test for the various associated problems
- $this->numericList = new SimpleChoiceList($numericChoices, array(1, 2));
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->list = null;
- $this->numericList = null;
- }
-
- public function testInitArray()
- {
- $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C');
- $this->list = new SimpleChoiceList($choices, array('b'));
-
- $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getChoices());
- $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c'), $this->list->getValues());
- $this->assertEquals(array(1 => new ChoiceView('b', 'b', 'B')), $this->list->getPreferredViews());
- $this->assertEquals(array(0 => new ChoiceView('a', 'a', 'A'), 2 => new ChoiceView('c', 'c', 'C')), $this->list->getRemainingViews());
- }
-
- public function testInitNestedArray()
- {
- $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $this->list->getChoices());
- $this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $this->list->getValues());
- $this->assertEquals(array(
- 'Group 1' => array(1 => new ChoiceView('b', 'b', 'B')),
- 'Group 2' => array(2 => new ChoiceView('c', 'c', 'C'))
- ), $this->list->getPreferredViews());
- $this->assertEquals(array(
- 'Group 1' => array(0 => new ChoiceView('a', 'a', 'A')),
- 'Group 2' => array(3 => new ChoiceView('d', 'd', 'D'))
- ), $this->list->getRemainingViews());
- }
-
- public function testGetIndicesForChoices()
- {
- $choices = array('b', 'c');
- $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
- }
-
- public function testGetIndicesForChoicesIgnoresNonExistingChoices()
- {
- $choices = array('b', 'c', 'foobar');
- $this->assertSame(array(1, 2), $this->list->getIndicesForChoices($choices));
- }
-
- public function testGetIndicesForChoicesDealsWithNumericChoices()
- {
- // Pass choices as strings although they are integers
- $choices = array('0', '1');
- $this->assertSame(array(0, 1), $this->numericList->getIndicesForChoices($choices));
- }
-
- public function testGetIndicesForValues()
- {
- $values = array('b', 'c');
- $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
- }
-
- public function testGetIndicesForValuesIgnoresNonExistingValues()
- {
- $values = array('b', 'c', '100');
- $this->assertSame(array(1, 2), $this->list->getIndicesForValues($values));
- }
-
- public function testGetIndicesForValuesDealsWithNumericValues()
- {
- // Pass values as strings although they are integers
- $values = array('0', '1');
- $this->assertSame(array(0, 1), $this->numericList->getIndicesForValues($values));
- }
-
- public function testGetChoicesForValues()
- {
- $values = array('b', 'c');
- $this->assertSame(array('b', 'c'), $this->list->getChoicesForValues($values));
- }
-
- public function testGetChoicesForValuesIgnoresNonExistingValues()
- {
- $values = array('b', 'c', '100');
- $this->assertSame(array('b', 'c'), $this->list->getChoicesForValues($values));
- }
-
- public function testGetChoicesForValuesDealsWithNumericValues()
- {
- // Pass values as strings although they are integers
- $values = array('0', '1');
- $this->assertSame(array(0, 1), $this->numericList->getChoicesForValues($values));
- }
-
- public function testGetValuesForChoices()
- {
- $choices = array('b', 'c');
- $this->assertSame(array('b', 'c'), $this->list->getValuesForChoices($choices));
- }
-
- public function testGetValuesForChoicesIgnoresNonExistingValues()
- {
- $choices = array('b', 'c', 'foobar');
- $this->assertSame(array('b', 'c'), $this->list->getValuesForChoices($choices));
- }
-
- public function testGetValuesForChoicesDealsWithNumericValues()
- {
- // Pass values as strings although they are integers
- $values = array('0', '1');
-
- $this->assertSame(array('0', '1'), $this->numericList->getValuesForChoices($values));
- }
-
- /**
- * @dataProvider dirtyValuesProvider
- */
- public function testGetValuesForChoicesDealsWithDirtyValues($choice, $value)
- {
- $choices = array(
- '0' => 'Zero',
- '1' => 'One',
- '' => 'Empty',
- '1.23' => 'Float',
- 'foo' => 'Foo',
- 'foo10' => 'Foo 10',
- );
-
- // use COPY_CHOICE strategy to test the problems
- $this->list = new SimpleChoiceList($choices, array());
-
- $this->assertSame(array($value), $this->list->getValuesForChoices(array($choice)));
- }
-
- public function dirtyValuesProvider()
- {
- return array(
- array(0, '0'),
- array('0', '0'),
- array('1', '1'),
- array(false, '0'),
- array(true, '1'),
- array('', ''),
- array(null, ''),
- array('1.23', '1.23'),
- array('foo', 'foo'),
- array('foo10', 'foo10'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataMapper;
-
-use Symfony\Component\Form\FormConfigBuilder;
-use Symfony\Component\Form\FormConfigInterface;
-use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
-
-class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var PropertyPathMapper
- */
- private $mapper;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $dispatcher;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $propertyAccessor;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- if (!class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) {
- $this->markTestSkipped('The "PropertyAccess" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->propertyAccessor = $this->getMock('Symfony\Component\PropertyAccess\PropertyAccessorInterface');
- $this->mapper = new PropertyPathMapper($this->propertyAccessor);
- }
-
- /**
- * @param $path
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getPropertyPath($path)
- {
- return $this->getMockBuilder('Symfony\Component\PropertyAccess\PropertyPath')
- ->setConstructorArgs(array($path))
- ->setMethods(array('getValue', 'setValue'))
- ->getMock();
- }
-
- /**
- * @param FormConfigInterface $config
- * @param Boolean $synchronized
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getForm(FormConfigInterface $config, $synchronized = true)
- {
- $form = $this->getMockBuilder('Symfony\Component\Form\Form')
- ->setConstructorArgs(array($config))
- ->setMethods(array('isSynchronized'))
- ->getMock();
-
- $form->expects($this->any())
- ->method('isSynchronized')
- ->will($this->returnValue($synchronized));
-
- return $form;
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getDataMapper()
- {
- return $this->getMock('Symfony\Component\Form\DataMapperInterface');
- }
-
- public function testMapDataToFormsPassesObjectRefIfByReference()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->once())
- ->method('getValue')
- ->with($car, $propertyPath)
- ->will($this->returnValue($engine));
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $form = $this->getForm($config);
-
- $this->mapper->mapDataToForms($car, array($form));
-
- // Can't use isIdentical() above because mocks always clone their
- // arguments which can't be disabled in PHPUnit 3.6
- $this->assertSame($engine, $form->getData());
- }
-
- public function testMapDataToFormsPassesObjectCloneIfNotByReference()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->once())
- ->method('getValue')
- ->with($car, $propertyPath)
- ->will($this->returnValue($engine));
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(false);
- $config->setPropertyPath($propertyPath);
- $form = $this->getForm($config);
-
- $this->mapper->mapDataToForms($car, array($form));
-
- $this->assertNotSame($engine, $form->getData());
- $this->assertEquals($engine, $form->getData());
- }
-
- public function testMapDataToFormsIgnoresEmptyPropertyPath()
- {
- $car = new \stdClass();
-
- $config = new FormConfigBuilder(null, '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $form = $this->getForm($config);
-
- $this->assertNull($form->getPropertyPath());
-
- $this->mapper->mapDataToForms($car, array($form));
-
- $this->assertNull($form->getData());
- }
-
- public function testMapDataToFormsIgnoresUnmapped()
- {
- $car = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->never())
- ->method('getValue');
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setMapped(false);
- $config->setPropertyPath($propertyPath);
- $form = $this->getForm($config);
-
- $this->mapper->mapDataToForms($car, array($form));
-
- $this->assertNull($form->getData());
- }
-
- public function testMapDataToFormsIgnoresEmptyData()
- {
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->never())
- ->method('getValue');
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $form = $this->getForm($config);
-
- $this->mapper->mapDataToForms(null, array($form));
-
- $this->assertNull($form->getData());
- }
-
- public function testMapFormsToDataWritesBackIfNotByReference()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->once())
- ->method('setValue')
- ->with($car, $propertyPath, $engine);
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(false);
- $config->setPropertyPath($propertyPath);
- $config->setData($engine);
- $form = $this->getForm($config);
-
- $this->mapper->mapFormsToData(array($form), $car);
- }
-
- public function testMapFormsToDataWritesBackIfByReferenceButNoReference()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->once())
- ->method('setValue')
- ->with($car, $propertyPath, $engine);
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $config->setData($engine);
- $form = $this->getForm($config);
-
- $this->mapper->mapFormsToData(array($form), $car);
- }
-
- public function testMapFormsToDataWritesBackIfByReferenceAndReference()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- // $car already contains the reference of $engine
- $this->propertyAccessor->expects($this->once())
- ->method('getValue')
- ->with($car, $propertyPath)
- ->will($this->returnValue($engine));
-
- $this->propertyAccessor->expects($this->never())
- ->method('setValue');
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $config->setData($engine);
- $form = $this->getForm($config);
-
- $this->mapper->mapFormsToData(array($form), $car);
- }
-
- public function testMapFormsToDataIgnoresUnmapped()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->never())
- ->method('setValue');
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $config->setData($engine);
- $config->setMapped(false);
- $form = $this->getForm($config);
-
- $this->mapper->mapFormsToData(array($form), $car);
- }
-
- public function testMapFormsToDataIgnoresEmptyData()
- {
- $car = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->never())
- ->method('setValue');
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $config->setData(null);
- $form = $this->getForm($config);
-
- $this->mapper->mapFormsToData(array($form), $car);
- }
-
- public function testMapFormsToDataIgnoresUnsynchronized()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->never())
- ->method('setValue');
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $config->setData($engine);
- $form = $this->getForm($config, false);
-
- $this->mapper->mapFormsToData(array($form), $car);
- }
-
- public function testMapFormsToDataIgnoresDisabled()
- {
- $car = new \stdClass();
- $engine = new \stdClass();
- $propertyPath = $this->getPropertyPath('engine');
-
- $this->propertyAccessor->expects($this->never())
- ->method('setValue');
-
- $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher);
- $config->setByReference(true);
- $config->setPropertyPath($propertyPath);
- $config->setData($engine);
- $config->setDisabled(true);
- $form = $this->getForm($config);
-
- $this->mapper->mapFormsToData(array($form), $car);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
-
-class ArrayToPartsTransformerTest extends \PHPUnit_Framework_TestCase
-{
- private $transformer;
-
- protected function setUp()
- {
- $this->transformer = new ArrayToPartsTransformer(array(
- 'first' => array('a', 'b', 'c'),
- 'second' => array('d', 'e', 'f'),
- ));
- }
-
- protected function tearDown()
- {
- $this->transformer = null;
- }
-
- public function testTransform()
- {
- $input = array(
- 'a' => '1',
- 'b' => '2',
- 'c' => '3',
- 'd' => '4',
- 'e' => '5',
- 'f' => '6',
- );
-
- $output = array(
- 'first' => array(
- 'a' => '1',
- 'b' => '2',
- 'c' => '3',
- ),
- 'second' => array(
- 'd' => '4',
- 'e' => '5',
- 'f' => '6',
- ),
- );
-
- $this->assertSame($output, $this->transformer->transform($input));
- }
-
- public function testTransformEmpty()
- {
- $output = array(
- 'first' => null,
- 'second' => null,
- );
-
- $this->assertSame($output, $this->transformer->transform(null));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testTransformRequiresArray()
- {
- $this->transformer->transform('12345');
- }
-
- public function testReverseTransform()
- {
- $input = array(
- 'first' => array(
- 'a' => '1',
- 'b' => '2',
- 'c' => '3',
- ),
- 'second' => array(
- 'd' => '4',
- 'e' => '5',
- 'f' => '6',
- ),
- );
-
- $output = array(
- 'a' => '1',
- 'b' => '2',
- 'c' => '3',
- 'd' => '4',
- 'e' => '5',
- 'f' => '6',
- );
-
- $this->assertSame($output, $this->transformer->reverseTransform($input));
- }
-
- public function testReverseTransformCompletelyEmpty()
- {
- $input = array(
- 'first' => '',
- 'second' => '',
- );
-
- $this->assertNull($this->transformer->reverseTransform($input));
- }
-
- public function testReverseTransformCompletelyNull()
- {
- $input = array(
- 'first' => null,
- 'second' => null,
- );
-
- $this->assertNull($this->transformer->reverseTransform($input));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyNull()
- {
- $input = array(
- 'first' => array(
- 'a' => '1',
- 'b' => '2',
- 'c' => '3',
- ),
- 'second' => null,
- );
-
- $this->transformer->reverseTransform($input);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformRequiresArray()
- {
- $this->transformer->reverseTransform('12345');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransformer;
-
-class BooleanToStringTransformerTest extends \PHPUnit_Framework_TestCase
-{
- const TRUE_VALUE = '1';
-
- protected $transformer;
-
- protected function setUp()
- {
- $this->transformer = new BooleanToStringTransformer(self::TRUE_VALUE);
- }
-
- protected function tearDown()
- {
- $this->transformer = null;
- }
-
- public function testTransform()
- {
- $this->assertEquals(self::TRUE_VALUE, $this->transformer->transform(true));
- $this->assertNull($this->transformer->transform(false));
- $this->assertNull($this->transformer->transform(null));
- }
-
- public function testTransformExpectsBoolean()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $this->transformer->transform('1');
- }
-
- public function testReverseTransformExpectsString()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $this->transformer->reverseTransform(1);
- }
-
- public function testReverseTransform()
- {
- $this->assertTrue($this->transformer->reverseTransform(self::TRUE_VALUE));
- $this->assertTrue($this->transformer->reverseTransform('foobar'));
- $this->assertTrue($this->transformer->reverseTransform(''));
- $this->assertFalse($this->transformer->reverseTransform(null));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
-use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
-
-class ChoiceToValueTransformerTest extends \PHPUnit_Framework_TestCase
-{
- protected $transformer;
-
- protected function setUp()
- {
- $list = new SimpleChoiceList(array('' => 'A', 0 => 'B', 1 => 'C'));
- $this->transformer = new ChoiceToValueTransformer($list);
- }
-
- protected function tearDown()
- {
- $this->transformer = null;
- }
-
- public function transformProvider()
- {
- return array(
- // more extensive test set can be found in FormUtilTest
- array(0, '0'),
- array(false, '0'),
- array('', ''),
- );
- }
-
- /**
- * @dataProvider transformProvider
- */
- public function testTransform($in, $out)
- {
- $this->assertSame($out, $this->transformer->transform($in));
- }
-
- public function reverseTransformProvider()
- {
- return array(
- // values are expected to be valid choice keys already and stay
- // the same
- array('0', 0),
- array('', null),
- array(null, null),
- );
- }
-
- /**
- * @dataProvider reverseTransformProvider
- */
- public function testReverseTransform($in, $out)
- {
- $this->assertSame($out, $this->transformer->reverseTransform($in));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformExpectsScalar()
- {
- $this->transformer->reverseTransform(array());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
-
-class ChoicesToValuesTransformerTest extends \PHPUnit_Framework_TestCase
-{
- protected $transformer;
-
- protected function setUp()
- {
- $list = new SimpleChoiceList(array(0 => 'A', 1 => 'B', 2 => 'C'));
- $this->transformer = new ChoicesToValuesTransformer($list);
- }
-
- protected function tearDown()
- {
- $this->transformer = null;
- }
-
- public function testTransform()
- {
- // Value strategy in SimpleChoiceList is to copy and convert to string
- $in = array(0, 1, 2);
- $out = array('0', '1', '2');
-
- $this->assertSame($out, $this->transformer->transform($in));
- }
-
- public function testTransformNull()
- {
- $this->assertSame(array(), $this->transformer->transform(null));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testTransformExpectsArray()
- {
- $this->transformer->transform('foobar');
- }
-
- public function testReverseTransform()
- {
- // values are expected to be valid choices and stay the same
- $in = array('0', '1', '2');
- $out = array(0, 1, 2);
-
- $this->assertSame($out, $this->transformer->reverseTransform($in));
- }
-
- public function testReverseTransformNull()
- {
- $this->assertSame(array(), $this->transformer->reverseTransform(null));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformExpectsArray()
- {
- $this->transformer->reverseTransform('foobar');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
-
-class DataTransformerChainTest extends \PHPUnit_Framework_TestCase
-{
- public function testTransform()
- {
- $transformer1 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
- $transformer1->expects($this->once())
- ->method('transform')
- ->with($this->identicalTo('foo'))
- ->will($this->returnValue('bar'));
- $transformer2 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
- $transformer2->expects($this->once())
- ->method('transform')
- ->with($this->identicalTo('bar'))
- ->will($this->returnValue('baz'));
-
- $chain = new DataTransformerChain(array($transformer1, $transformer2));
-
- $this->assertEquals('baz', $chain->transform('foo'));
- }
-
- public function testReverseTransform()
- {
- $transformer2 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
- $transformer2->expects($this->once())
- ->method('reverseTransform')
- ->with($this->identicalTo('foo'))
- ->will($this->returnValue('bar'));
- $transformer1 = $this->getMock('Symfony\Component\Form\DataTransformerInterface');
- $transformer1->expects($this->once())
- ->method('reverseTransform')
- ->with($this->identicalTo('bar'))
- ->will($this->returnValue('baz'));
-
- $chain = new DataTransformerChain(array($transformer1, $transformer2));
-
- $this->assertEquals('baz', $chain->reverseTransform('foo'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-abstract class DateTimeTestCase extends \PHPUnit_Framework_TestCase
-{
- public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual)
- {
- self::assertEquals($expected->format('c'), $actual->format('c'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
-
-class DateTimeToArrayTransformerTest extends DateTimeTestCase
-{
- public function testTransform()
- {
- $transformer = new DateTimeToArrayTransformer('UTC', 'UTC');
-
- $input = new \DateTime('2010-02-03 04:05:06 UTC');
-
- $output = array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- );
-
- $this->assertSame($output, $transformer->transform($input));
- }
-
- public function testTransformEmpty()
- {
- $transformer = new DateTimeToArrayTransformer();
-
- $output = array(
- 'year' => '',
- 'month' => '',
- 'day' => '',
- 'hour' => '',
- 'minute' => '',
- 'second' => '',
- );
-
- $this->assertSame($output, $transformer->transform(null));
- }
-
- public function testTransformEmptyWithFields()
- {
- $transformer = new DateTimeToArrayTransformer(null, null, array('year', 'minute', 'second'));
-
- $output = array(
- 'year' => '',
- 'minute' => '',
- 'second' => '',
- );
-
- $this->assertSame($output, $transformer->transform(null));
- }
-
- public function testTransformWithFields()
- {
- $transformer = new DateTimeToArrayTransformer('UTC', 'UTC', array('year', 'month', 'minute', 'second'));
-
- $input = new \DateTime('2010-02-03 04:05:06 UTC');
-
- $output = array(
- 'year' => '2010',
- 'month' => '2',
- 'minute' => '5',
- 'second' => '6',
- );
-
- $this->assertSame($output, $transformer->transform($input));
- }
-
- public function testTransformWithPadding()
- {
- $transformer = new DateTimeToArrayTransformer('UTC', 'UTC', null, true);
-
- $input = new \DateTime('2010-02-03 04:05:06 UTC');
-
- $output = array(
- 'year' => '2010',
- 'month' => '02',
- 'day' => '03',
- 'hour' => '04',
- 'minute' => '05',
- 'second' => '06',
- );
-
- $this->assertSame($output, $transformer->transform($input));
- }
-
- public function testTransformDifferentTimezones()
- {
- $transformer = new DateTimeToArrayTransformer('America/New_York', 'Asia/Hong_Kong');
-
- $input = new \DateTime('2010-02-03 04:05:06 America/New_York');
-
- $dateTime = new \DateTime('2010-02-03 04:05:06 America/New_York');
- $dateTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
- $output = array(
- 'year' => (string) (int) $dateTime->format('Y'),
- 'month' => (string) (int) $dateTime->format('m'),
- 'day' => (string) (int) $dateTime->format('d'),
- 'hour' => (string) (int) $dateTime->format('H'),
- 'minute' => (string) (int) $dateTime->format('i'),
- 'second' => (string) (int) $dateTime->format('s'),
- );
-
- $this->assertSame($output, $transformer->transform($input));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testTransformRequiresDateTime()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform('12345');
- }
-
- public function testReverseTransform()
- {
- $transformer = new DateTimeToArrayTransformer('UTC', 'UTC');
-
- $input = array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- );
-
- $output = new \DateTime('2010-02-03 04:05:06 UTC');
-
- $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
- }
-
- public function testReverseTransformWithSomeZero()
- {
- $transformer = new DateTimeToArrayTransformer('UTC', 'UTC');
-
- $input = array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '0',
- 'second' => '0',
- );
-
- $output = new \DateTime('2010-02-03 04:00:00 UTC');
-
- $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
- }
-
- public function testReverseTransformCompletelyEmpty()
- {
- $transformer = new DateTimeToArrayTransformer();
-
- $input = array(
- 'year' => '',
- 'month' => '',
- 'day' => '',
- 'hour' => '',
- 'minute' => '',
- 'second' => '',
- );
-
- $this->assertNull($transformer->reverseTransform($input));
- }
-
- public function testReverseTransformCompletelyEmptySubsetOfFields()
- {
- $transformer = new DateTimeToArrayTransformer(null, null, array('year', 'month', 'day'));
-
- $input = array(
- 'year' => '',
- 'month' => '',
- 'day' => '',
- );
-
- $this->assertNull($transformer->reverseTransform($input));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyEmptyYear()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyEmptyMonth()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyEmptyDay()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyEmptyHour()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyEmptyMinute()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyEmptySecond()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- ));
- }
-
- public function testReverseTransformNull()
- {
- $transformer = new DateTimeToArrayTransformer();
-
- $this->assertNull($transformer->reverseTransform(null));
- }
-
- public function testReverseTransformDifferentTimezones()
- {
- $transformer = new DateTimeToArrayTransformer('America/New_York', 'Asia/Hong_Kong');
-
- $input = array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- );
-
- $output = new \DateTime('2010-02-03 04:05:06 Asia/Hong_Kong');
- $output->setTimezone(new \DateTimeZone('America/New_York'));
-
- $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
- }
-
- public function testReverseTransformToDifferentTimezone()
- {
- $transformer = new DateTimeToArrayTransformer('Asia/Hong_Kong', 'UTC');
-
- $input = array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- );
-
- $output = new \DateTime('2010-02-03 04:05:06 UTC');
- $output->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
-
- $this->assertDateTimeEquals($output, $transformer->reverseTransform($input));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformRequiresArray()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform('12345');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNegativeYear()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '-1',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNegativeMonth()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '-1',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNegativeDay()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '-1',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNegativeHour()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '-1',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNegativeMinute()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '-1',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNegativeSecond()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '-1',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithInvalidMonth()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '13',
- 'day' => '3',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithInvalidDay()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => '31',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithStringDay()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => '2',
- 'day' => 'bazinga',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithStringMonth()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => '2010',
- 'month' => 'bazinga',
- 'day' => '31',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithStringYear()
- {
- $transformer = new DateTimeToArrayTransformer();
- $transformer->reverseTransform(array(
- 'year' => 'bazinga',
- 'month' => '2',
- 'day' => '31',
- 'hour' => '4',
- 'minute' => '5',
- 'second' => '6',
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase
-{
- protected $dateTime;
- protected $dateTimeWithoutSeconds;
-
- protected function setUp()
- {
- parent::setUp();
-
- // Since we test against "de_AT", we need the full implementation
- IntlTestHelper::requireFullIntl($this);
-
- \Locale::setDefault('de_AT');
-
- $this->dateTime = new \DateTime('2010-02-03 04:05:06 UTC');
- $this->dateTimeWithoutSeconds = new \DateTime('2010-02-03 04:05:00 UTC');
- }
-
- protected function tearDown()
- {
- $this->dateTime = null;
- $this->dateTimeWithoutSeconds = null;
- }
-
- public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
- {
- if ($expected instanceof \DateTime && $actual instanceof \DateTime) {
- $expected = $expected->format('c');
- $actual = $actual->format('c');
- }
-
- parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase);
- }
-
- public function dataProvider()
- {
- return array(
- array(\IntlDateFormatter::SHORT, null, null, '03.02.10 04:05', '2010-02-03 04:05:00 UTC'),
- array(\IntlDateFormatter::MEDIUM, null, null, '03.02.2010 04:05', '2010-02-03 04:05:00 UTC'),
- array(\IntlDateFormatter::LONG, null, null, '03. Februar 2010 04:05', '2010-02-03 04:05:00 UTC'),
- array(\IntlDateFormatter::FULL, null, null, 'Mittwoch, 03. Februar 2010 04:05', '2010-02-03 04:05:00 UTC'),
- array(\IntlDateFormatter::SHORT, \IntlDateFormatter::NONE, null, '03.02.10', '2010-02-03 00:00:00 UTC'),
- array(\IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE, null, '03.02.2010', '2010-02-03 00:00:00 UTC'),
- array(\IntlDateFormatter::LONG, \IntlDateFormatter::NONE, null, '03. Februar 2010', '2010-02-03 00:00:00 UTC'),
- array(\IntlDateFormatter::FULL, \IntlDateFormatter::NONE, null, 'Mittwoch, 03. Februar 2010', '2010-02-03 00:00:00 UTC'),
- array(null, \IntlDateFormatter::SHORT, null, '03.02.2010 04:05', '2010-02-03 04:05:00 UTC'),
- array(null, \IntlDateFormatter::MEDIUM, null, '03.02.2010 04:05:06', '2010-02-03 04:05:06 UTC'),
- array(null, \IntlDateFormatter::LONG, null, '03.02.2010 04:05:06 GMT', '2010-02-03 04:05:06 UTC'),
- // see below for extra test case for time format FULL
- array(\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT, null, '04:05', '1970-01-01 04:05:00 UTC'),
- array(\IntlDateFormatter::NONE, \IntlDateFormatter::MEDIUM, null, '04:05:06', '1970-01-01 04:05:06 UTC'),
- array(\IntlDateFormatter::NONE, \IntlDateFormatter::LONG, null, '04:05:06 GMT', '1970-01-01 04:05:06 UTC'),
- array(null, null, 'yyyy-MM-dd HH:mm:00', '2010-02-03 04:05:00', '2010-02-03 04:05:00 UTC'),
- array(null, null, 'yyyy-MM-dd HH:mm', '2010-02-03 04:05', '2010-02-03 04:05:00 UTC'),
- array(null, null, 'yyyy-MM-dd HH', '2010-02-03 04', '2010-02-03 04:00:00 UTC'),
- array(null, null, 'yyyy-MM-dd', '2010-02-03', '2010-02-03 00:00:00 UTC'),
- array(null, null, 'yyyy-MM', '2010-02', '2010-02-01 00:00:00 UTC'),
- array(null, null, 'yyyy', '2010', '2010-01-01 00:00:00 UTC'),
- array(null, null, 'dd-MM-yyyy', '03-02-2010', '2010-02-03 00:00:00 UTC'),
- array(null, null, 'HH:mm:ss', '04:05:06', '1970-01-01 04:05:06 UTC'),
- array(null, null, 'HH:mm:00', '04:05:00', '1970-01-01 04:05:00 UTC'),
- array(null, null, 'HH:mm', '04:05', '1970-01-01 04:05:00 UTC'),
- array(null, null, 'HH', '04', '1970-01-01 04:00:00 UTC'),
- );
- }
-
- /**
- * @dataProvider dataProvider
- */
- public function testTransform($dateFormat, $timeFormat, $pattern, $output, $input)
- {
- $transformer = new DateTimeToLocalizedStringTransformer(
- 'UTC',
- 'UTC',
- $dateFormat,
- $timeFormat,
- \IntlDateFormatter::GREGORIAN,
- $pattern
- );
-
- $input = new \DateTime($input);
-
- $this->assertEquals($output, $transformer->transform($input));
- }
-
- public function testTransformFullTime()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::FULL);
-
- $this->assertEquals('03.02.2010 04:05:06 GMT', $transformer->transform($this->dateTime));
- }
-
- public function testTransformToDifferentLocale()
- {
- \Locale::setDefault('en_US');
-
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC');
-
- $this->assertEquals('Feb 3, 2010, 4:05 AM', $transformer->transform($this->dateTime));
- }
-
- public function testTransformEmpty()
- {
- $transformer = new DateTimeToLocalizedStringTransformer();
-
- $this->assertSame('', $transformer->transform(null));
- }
-
- public function testTransformWithDifferentTimezones()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('America/New_York', 'Asia/Hong_Kong');
-
- $input = new \DateTime('2010-02-03 04:05:06 America/New_York');
-
- $dateTime = clone $input;
- $dateTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
-
- $this->assertEquals($dateTime->format('d.m.Y H:i'), $transformer->transform($input));
- }
-
- public function testTransformWithDifferentPatterns()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'MM*yyyy*dd HH|mm|ss');
-
- $this->assertEquals('02*2010*03 04|05|06', $transformer->transform($this->dateTime));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testTransformRequiresValidDateTime()
- {
- $transformer = new DateTimeToLocalizedStringTransformer();
- $transformer->transform('2010-01-01');
- }
-
- public function testTransformWrapsIntlErrors()
- {
- $transformer = new DateTimeToLocalizedStringTransformer();
-
- // HOW TO REPRODUCE?
-
- //$this->setExpectedException('Symfony\Component\Form\Extension\Core\DataTransformer\Transdate_formationFailedException');
-
- //$transformer->transform(1.5);
- }
-
- /**
- * @dataProvider dataProvider
- */
- public function testReverseTransform($dateFormat, $timeFormat, $pattern, $input, $output)
- {
- $transformer = new DateTimeToLocalizedStringTransformer(
- 'UTC',
- 'UTC',
- $dateFormat,
- $timeFormat,
- \IntlDateFormatter::GREGORIAN,
- $pattern
- );
-
- $output = new \DateTime($output);
-
- $this->assertEquals($output, $transformer->reverseTransform($input));
- }
-
- public function testReverseTransformFullTime()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::FULL);
-
- $this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('03.02.2010 04:05:06 GMT+00:00'));
- }
-
- public function testReverseTransformFromDifferentLocale()
- {
- \Locale::setDefault('en_US');
-
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC');
-
- $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('Feb 3, 2010, 04:05 AM'));
- }
-
- public function testReverseTransformWithDifferentTimezones()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('America/New_York', 'Asia/Hong_Kong');
-
- $dateTime = new \DateTime('2010-02-03 04:05:00 Asia/Hong_Kong');
- $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
-
- $this->assertDateTimeEquals($dateTime, $transformer->reverseTransform('03.02.2010 04:05'));
- }
-
- public function testReverseTransformWithDifferentPatterns()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'MM*yyyy*dd HH|mm|ss');
-
- $this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('02*2010*03 04|05|06'));
- }
-
- public function testReverseTransformEmpty()
- {
- $transformer = new DateTimeToLocalizedStringTransformer();
-
- $this->assertNull($transformer->reverseTransform(''));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformRequiresString()
- {
- $transformer = new DateTimeToLocalizedStringTransformer();
- $transformer->reverseTransform(12345);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWrapsIntlErrors()
- {
- $transformer = new DateTimeToLocalizedStringTransformer();
- $transformer->reverseTransform('12345');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testValidateDateFormatOption()
- {
- new DateTimeToLocalizedStringTransformer(null, null, 'foobar');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testValidateTimeFormatOption()
- {
- new DateTimeToLocalizedStringTransformer(null, null, null, 'foobar');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNonExistingDate()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::SHORT);
-
- $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('31.04.10 04:05'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformOutOfTimestampRange()
- {
- $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC');
- $transformer->reverseTransform('1789-07-14');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
-
-class DateTimeToRfc3339TransformerTest extends DateTimeTestCase
-{
- protected $dateTime;
- protected $dateTimeWithoutSeconds;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->dateTime = new \DateTime('2010-02-03 04:05:06 UTC');
- $this->dateTimeWithoutSeconds = new \DateTime('2010-02-03 04:05:00 UTC');
- }
-
- protected function tearDown()
- {
- $this->dateTime = null;
- $this->dateTimeWithoutSeconds = null;
- }
-
- public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE)
- {
- if ($expected instanceof \DateTime && $actual instanceof \DateTime) {
- $expected = $expected->format('c');
- $actual = $actual->format('c');
- }
-
- parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase);
- }
-
- public function allProvider()
- {
- return array(
- array('UTC', 'UTC', '2010-02-03 04:05:06 UTC', '2010-02-03T04:05:06Z'),
- array('UTC', 'UTC', null, ''),
- array('America/New_York', 'Asia/Hong_Kong', '2010-02-03 04:05:06 America/New_York', '2010-02-03T17:05:06+08:00'),
- array('America/New_York', 'Asia/Hong_Kong', null, ''),
- array('UTC', 'Asia/Hong_Kong', '2010-02-03 04:05:06 UTC', '2010-02-03T12:05:06+08:00'),
- array('America/New_York', 'UTC', '2010-02-03 04:05:06 America/New_York', '2010-02-03T09:05:06Z'),
- );
- }
-
- public function transformProvider()
- {
- return $this->allProvider();
- }
-
- public function reverseTransformProvider()
- {
- return array_merge($this->allProvider(), array(
- // format without seconds, as appears in some browsers
- array('UTC', 'UTC', '2010-02-03 04:05:00 UTC', '2010-02-03T04:05Z'),
- array('America/New_York', 'Asia/Hong_Kong', '2010-02-03 04:05:00 America/New_York', '2010-02-03T17:05+08:00'),
- ));
- }
-
- /**
- * @dataProvider transformProvider
- */
- public function testTransform($fromTz, $toTz, $from, $to)
- {
- $transformer = new DateTimeToRfc3339Transformer($fromTz, $toTz);
-
- $this->assertSame($to, $transformer->transform(null !== $from ? new \DateTime($from) : null));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testTransformRequiresValidDateTime()
- {
- $transformer = new DateTimeToRfc3339Transformer();
- $transformer->transform('2010-01-01');
- }
-
- /**
- * @dataProvider reverseTransformProvider
- */
- public function testReverseTransform($toTz, $fromTz, $to, $from)
- {
- $transformer = new DateTimeToRfc3339Transformer($toTz, $fromTz);
-
- if (null !== $to) {
- $this->assertDateTimeEquals(new \DateTime($to), $transformer->reverseTransform($from));
- } else {
- $this->assertSame($to, $transformer->reverseTransform($from));
- }
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformRequiresString()
- {
- $transformer = new DateTimeToRfc3339Transformer();
- $transformer->reverseTransform(12345);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformWithNonExistingDate()
- {
- $transformer = new DateTimeToRfc3339Transformer('UTC', 'UTC');
-
- $transformer->reverseTransform('2010-04-31T04:05Z');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformExpectsValidDateString()
- {
- $transformer = new DateTimeToRfc3339Transformer('UTC', 'UTC');
-
- $transformer->reverseTransform('2010-2010-2010');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
-
-class DateTimeToStringTransformerTest extends DateTimeTestCase
-{
- public function dataProvider()
- {
- $data = array(
- array('Y-m-d H:i:s', '2010-02-03 16:05:06', '2010-02-03 16:05:06 UTC'),
- array('Y-m-d H:i:00', '2010-02-03 16:05:00', '2010-02-03 16:05:00 UTC'),
- array('Y-m-d H:i', '2010-02-03 16:05', '2010-02-03 16:05:00 UTC'),
- array('Y-m-d H', '2010-02-03 16', '2010-02-03 16:00:00 UTC'),
- array('Y-m-d', '2010-02-03', '2010-02-03 00:00:00 UTC'),
- array('Y-m', '2010-12', '2010-12-01 00:00:00 UTC'),
- array('Y', '2010', '2010-01-01 00:00:00 UTC'),
- array('d-m-Y', '03-02-2010', '2010-02-03 00:00:00 UTC'),
- array('H:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
- array('H:i:00', '16:05:00', '1970-01-01 16:05:00 UTC'),
- array('H:i', '16:05', '1970-01-01 16:05:00 UTC'),
- array('H', '16', '1970-01-01 16:00:00 UTC'),
-
- // different day representations
- array('Y-m-j', '2010-02-3', '2010-02-03 00:00:00 UTC'),
- array('z', '33', '1970-02-03 00:00:00 UTC'),
-
- // not bijective
- // this will not work as php will use actual date to replace missing info
- // and after change of date will lookup for closest Wednesday
- // i.e. value: 2010-02, php value: 2010-02-(today i.e. 20), parsed date: 2010-02-24
- //array('Y-m-D', '2010-02-Wed', '2010-02-03 00:00:00 UTC'),
- //array('Y-m-l', '2010-02-Wednesday', '2010-02-03 00:00:00 UTC'),
-
- // different month representations
- array('Y-n-d', '2010-2-03', '2010-02-03 00:00:00 UTC'),
- array('Y-M-d', '2010-Feb-03', '2010-02-03 00:00:00 UTC'),
- array('Y-F-d', '2010-February-03', '2010-02-03 00:00:00 UTC'),
-
- // different year representations
- array('y-m-d', '10-02-03', '2010-02-03 00:00:00 UTC'),
-
- // different time representations
- array('G:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
- array('g:i:s a', '4:05:06 pm', '1970-01-01 16:05:06 UTC'),
- array('h:i:s a', '04:05:06 pm', '1970-01-01 16:05:06 UTC'),
-
- // seconds since unix
- array('U', '1265213106', '2010-02-03 16:05:06 UTC'),
- );
-
- // This test will fail < 5.3.9 - see https://bugs.php.net/51994
- if (version_compare(phpversion(), '5.3.9', '>=')) {
- $data[] = array('Y-z', '2010-33', '2010-02-03 00:00:00 UTC');
- }
-
- return $data;
- }
-
- /**
- * @dataProvider dataProvider
- */
- public function testTransform($format, $output, $input)
- {
- $transformer = new DateTimeToStringTransformer('UTC', 'UTC', $format);
-
- $input = new \DateTime($input);
-
- $this->assertEquals($output, $transformer->transform($input));
- }
-
- public function testTransformEmpty()
- {
- $transformer = new DateTimeToStringTransformer();
-
- $this->assertSame('', $transformer->transform(null));
- }
-
- public function testTransformWithDifferentTimezones()
- {
- $transformer = new DateTimeToStringTransformer('Asia/Hong_Kong', 'America/New_York', 'Y-m-d H:i:s');
-
- $input = new \DateTime('2010-02-03 12:05:06 America/New_York');
- $output = $input->format('Y-m-d H:i:s');
- $input->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
-
- $this->assertEquals($output, $transformer->transform($input));
- }
-
- public function testTransformExpectsDateTime()
- {
- $transformer = new DateTimeToStringTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $transformer->transform('1234');
- }
-
- /**
- * @dataProvider dataProvider
- */
- public function testReverseTransformUsingPipe($format, $input, $output)
- {
- if (version_compare(phpversion(), '5.3.7', '<')) {
- $this->markTestSkipped('Pipe usage requires PHP 5.3.7 or newer.');
- }
-
- $reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format, true);
-
- $output = new \DateTime($output);
-
- $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
- }
-
- /**
- * @dataProvider dataProvider
- */
- public function testReverseTransformWithoutUsingPipe($format, $input, $output)
- {
- $reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format, false);
-
- $output = new \DateTime($output);
-
- $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
- }
-
- public function testReverseTransformEmpty()
- {
- $reverseTransformer = new DateTimeToStringTransformer();
-
- $this->assertNull($reverseTransformer->reverseTransform(''));
- }
-
- public function testReverseTransformWithDifferentTimezones()
- {
- $reverseTransformer = new DateTimeToStringTransformer('America/New_York', 'Asia/Hong_Kong', 'Y-m-d H:i:s');
-
- $output = new \DateTime('2010-02-03 16:05:06 Asia/Hong_Kong');
- $input = $output->format('Y-m-d H:i:s');
- $output->setTimeZone(new \DateTimeZone('America/New_York'));
-
- $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
- }
-
- public function testReverseTransformExpectsString()
- {
- $reverseTransformer = new DateTimeToStringTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $reverseTransformer->reverseTransform(1234);
- }
-
- public function testReverseTransformExpectsValidDateString()
- {
- $reverseTransformer = new DateTimeToStringTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $reverseTransformer->reverseTransform('2010-2010-2010');
- }
-
- public function testReverseTransformWithNonExistingDate()
- {
- $reverseTransformer = new DateTimeToStringTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $reverseTransformer->reverseTransform('2010-04-31');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
-
-class DateTimeToTimestampTransformerTest extends DateTimeTestCase
-{
- public function testTransform()
- {
- $transformer = new DateTimeToTimestampTransformer('UTC', 'UTC');
-
- $input = new \DateTime('2010-02-03 04:05:06 UTC');
- $output = $input->format('U');
-
- $this->assertEquals($output, $transformer->transform($input));
- }
-
- public function testTransformEmpty()
- {
- $transformer = new DateTimeToTimestampTransformer();
-
- $this->assertNull($transformer->transform(null));
- }
-
- public function testTransformWithDifferentTimezones()
- {
- $transformer = new DateTimeToTimestampTransformer('Asia/Hong_Kong', 'America/New_York');
-
- $input = new \DateTime('2010-02-03 04:05:06 America/New_York');
- $output = $input->format('U');
- $input->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
-
- $this->assertEquals($output, $transformer->transform($input));
- }
-
- public function testTransformFromDifferentTimezone()
- {
- $transformer = new DateTimeToTimestampTransformer('Asia/Hong_Kong', 'UTC');
-
- $input = new \DateTime('2010-02-03 04:05:06 Asia/Hong_Kong');
-
- $dateTime = clone $input;
- $dateTime->setTimezone(new \DateTimeZone('UTC'));
- $output = $dateTime->format('U');
-
- $this->assertEquals($output, $transformer->transform($input));
- }
-
- public function testTransformExpectsDateTime()
- {
- $transformer = new DateTimeToTimestampTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $transformer->transform('1234');
- }
-
- public function testReverseTransform()
- {
- $reverseTransformer = new DateTimeToTimestampTransformer('UTC', 'UTC');
-
- $output = new \DateTime('2010-02-03 04:05:06 UTC');
- $input = $output->format('U');
-
- $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
- }
-
- public function testReverseTransformEmpty()
- {
- $reverseTransformer = new DateTimeToTimestampTransformer();
-
- $this->assertNull($reverseTransformer->reverseTransform(null));
- }
-
- public function testReverseTransformWithDifferentTimezones()
- {
- $reverseTransformer = new DateTimeToTimestampTransformer('Asia/Hong_Kong', 'America/New_York');
-
- $output = new \DateTime('2010-02-03 04:05:06 America/New_York');
- $input = $output->format('U');
- $output->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
-
- $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
- }
-
- public function testReverseTransformExpectsValidTimestamp()
- {
- $reverseTransformer = new DateTimeToTimestampTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $reverseTransformer->reverseTransform('2010-2010-2010');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class IntegerToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- // Since we test against "de_AT", we need the full implementation
- IntlTestHelper::requireFullIntl($this);
-
- \Locale::setDefault('de_AT');
- }
-
- public function testReverseTransform()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $this->assertEquals(1, $transformer->reverseTransform('1'));
- $this->assertEquals(1, $transformer->reverseTransform('1,5'));
- $this->assertEquals(1234, $transformer->reverseTransform('1234,5'));
- $this->assertEquals(12345, $transformer->reverseTransform('12345,912'));
- }
-
- public function testReverseTransformEmpty()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $this->assertNull($transformer->reverseTransform(''));
- }
-
- public function testReverseTransformWithGrouping()
- {
- $transformer = new IntegerToLocalizedStringTransformer(null, true);
-
- $this->assertEquals(1234, $transformer->reverseTransform('1.234,5'));
- $this->assertEquals(12345, $transformer->reverseTransform('12.345,912'));
- $this->assertEquals(1234, $transformer->reverseTransform('1234,5'));
- $this->assertEquals(12345, $transformer->reverseTransform('12345,912'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformExpectsString()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $transformer->reverseTransform(1);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformExpectsValidNumber()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $transformer->reverseTransform('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsNaN()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $transformer->reverseTransform('NaN');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsNaN2()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $transformer->reverseTransform('nan');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsInfinity()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $transformer->reverseTransform('∞');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsNegativeInfinity()
- {
- $transformer = new IntegerToLocalizedStringTransformer();
-
- $transformer->reverseTransform('-∞');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class MoneyToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- // Since we test against "de_AT", we need the full implementation
- IntlTestHelper::requireFullIntl($this);
-
- \Locale::setDefault('de_AT');
- }
-
- public function testTransform()
- {
- $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
-
- $this->assertEquals('1,23', $transformer->transform(123));
- }
-
- public function testTransformExpectsNumeric()
- {
- $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $transformer->transform('abcd');
- }
-
- public function testTransformEmpty()
- {
- $transformer = new MoneyToLocalizedStringTransformer();
-
- $this->assertSame('', $transformer->transform(null));
- }
-
- public function testReverseTransform()
- {
- $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
-
- $this->assertEquals(123, $transformer->reverseTransform('1,23'));
- }
-
- public function testReverseTransformExpectsString()
- {
- $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $transformer->reverseTransform(12345);
- }
-
- public function testReverseTransformEmpty()
- {
- $transformer = new MoneyToLocalizedStringTransformer();
-
- $this->assertNull($transformer->reverseTransform(''));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- // Since we test against "de_AT", we need the full implementation
- IntlTestHelper::requireFullIntl($this);
-
- \Locale::setDefault('de_AT');
- }
-
- public function provideTransformations()
- {
- return array(
- array(null, '', 'de_AT'),
- array(1, '1', 'de_AT'),
- array(1.5, '1,5', 'de_AT'),
- array(1234.5, '1234,5', 'de_AT'),
- array(12345.912, '12345,912', 'de_AT'),
- array(1234.5, '1234,5', 'ru'),
- array(1234.5, '1234,5', 'fi'),
- );
- }
-
- /**
- * @dataProvider provideTransformations
- */
- public function testTransform($from, $to, $locale)
- {
- \Locale::setDefault($locale);
-
- $transformer = new NumberToLocalizedStringTransformer();
-
- $this->assertSame($to, $transformer->transform($from));
- }
-
- public function provideTransformationsWithGrouping()
- {
- return array(
- array(1234.5, '1.234,5', 'de_AT'),
- array(12345.912, '12.345,912', 'de_AT'),
- array(1234.5, '1 234,5', 'fr'),
- array(1234.5, '1 234,5', 'ru'),
- array(1234.5, '1 234,5', 'fi'),
- );
- }
-
- /**
- * @dataProvider provideTransformationsWithGrouping
- */
- public function testTransformWithGrouping($from, $to, $locale)
- {
- \Locale::setDefault($locale);
-
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $this->assertSame($to, $transformer->transform($from));
- }
-
- public function testTransformWithPrecision()
- {
- $transformer = new NumberToLocalizedStringTransformer(2);
-
- $this->assertEquals('1234,50', $transformer->transform(1234.5));
- $this->assertEquals('678,92', $transformer->transform(678.916));
- }
-
- public function testTransformWithRoundingMode()
- {
- $transformer = new NumberToLocalizedStringTransformer(null, null, NumberToLocalizedStringTransformer::ROUND_DOWN);
- $this->assertEquals('1234,547', $transformer->transform(1234.547), '->transform() only applies rounding mode if precision set');
-
- $transformer = new NumberToLocalizedStringTransformer(2, null, NumberToLocalizedStringTransformer::ROUND_DOWN);
- $this->assertEquals('1234,54', $transformer->transform(1234.547), '->transform() rounding-mode works');
-
- }
-
- /**
- * @dataProvider provideTransformations
- */
- public function testReverseTransform($to, $from, $locale)
- {
- \Locale::setDefault($locale);
-
- $transformer = new NumberToLocalizedStringTransformer();
-
- $this->assertEquals($to, $transformer->reverseTransform($from));
- }
-
- /**
- * @dataProvider provideTransformationsWithGrouping
- */
- public function testReverseTransformWithGrouping($to, $from, $locale)
- {
- \Locale::setDefault($locale);
-
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $this->assertEquals($to, $transformer->reverseTransform($from));
- }
-
- // https://github.com/symfony/symfony/issues/7609
- public function testReverseTransformWithGroupingAndFixedSpaces()
- {
- if (!extension_loaded('mbstring')) {
- $this->markTestSkipped('The "mbstring" extension is required for this test.');
- }
-
- \Locale::setDefault('ru');
-
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $this->assertEquals(1234.5, $transformer->reverseTransform("1\xc2\xa0234,5"));
- }
-
- public function testReverseTransformWithGroupingButWithoutGroupSeparator()
- {
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- // omit group separator
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
- $this->assertEquals(12345.912, $transformer->reverseTransform('12345,912'));
- }
-
- public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsNotDot()
- {
- \Locale::setDefault('fr');
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- // completely valid format
- $this->assertEquals(1234.5, $transformer->reverseTransform('1 234,5'));
- // accept dots
- $this->assertEquals(1234.5, $transformer->reverseTransform('1 234.5'));
- // omit group separator
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot()
- {
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $transformer->reverseTransform('1.234.5');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDotWithNoGroupSep()
- {
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $transformer->reverseTransform('1234.5');
- }
-
- public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsDotButNoGroupingUsed()
- {
- \Locale::setDefault('fr');
- $transformer = new NumberToLocalizedStringTransformer();
-
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
- }
-
- public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsNotComma()
- {
- \Locale::setDefault('bg');
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- // completely valid format
- $this->assertEquals(1234.5, $transformer->reverseTransform('1 234.5'));
- // accept commas
- $this->assertEquals(1234.5, $transformer->reverseTransform('1 234,5'));
- // omit group separator
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsComma()
- {
- \Locale::setDefault('en');
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $transformer->reverseTransform('1,234,5');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsCommaWithNoGroupSep()
- {
- \Locale::setDefault('en');
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $transformer->reverseTransform('1234,5');
- }
-
- public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsCommaButNoGroupingUsed()
- {
- \Locale::setDefault('en');
- $transformer = new NumberToLocalizedStringTransformer();
-
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
- $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testTransformExpectsNumeric()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->transform('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformExpectsString()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform(1);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformExpectsValidNumber()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- * @link https://github.com/symfony/symfony/issues/3161
- */
- public function testReverseTransformDisallowsNaN()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('NaN');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsNaN2()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('nan');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsInfinity()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('∞');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsInfinity2()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('∞,123');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsNegativeInfinity()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('-∞');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsLeadingExtraCharacters()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('foo123');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- * @expectedExceptionMessage The number contains unrecognized characters: "foo3"
- */
- public function testReverseTransformDisallowsCenteredExtraCharacters()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('12foo3');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- * @expectedExceptionMessage The number contains unrecognized characters: "foo8"
- */
- public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte()
- {
- if (!extension_loaded('mbstring')) {
- $this->markTestSkipped('The "mbstring" extension is required for this test.');
- }
-
- \Locale::setDefault('ru');
-
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $transformer->reverseTransform("12\xc2\xa0345,67foo8");
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- * @expectedExceptionMessage The number contains unrecognized characters: "foo8"
- */
- public function testReverseTransformIgnoresTrailingSpacesInExceptionMessage()
- {
- if (!extension_loaded('mbstring')) {
- $this->markTestSkipped('The "mbstring" extension is required for this test.');
- }
-
- \Locale::setDefault('ru');
-
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $transformer->reverseTransform("12\xc2\xa0345,67foo8 \xc2\xa0\t");
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- * @expectedExceptionMessage The number contains unrecognized characters: "foo"
- */
- public function testReverseTransformDisallowsTrailingExtraCharacters()
- {
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('123foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- * @expectedExceptionMessage The number contains unrecognized characters: "foo"
- */
- public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
- {
- if (!extension_loaded('mbstring')) {
- $this->markTestSkipped('The "mbstring" extension is required for this test.');
- }
-
- \Locale::setDefault('ru');
-
- $transformer = new NumberToLocalizedStringTransformer(null, true);
-
- $transformer->reverseTransform("12\xc2\xa0345,678foo");
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class PercentToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- // Since we test against "de_AT", we need the full implementation
- IntlTestHelper::requireFullIntl($this);
-
- \Locale::setDefault('de_AT');
- }
-
- public function testTransform()
- {
- $transformer = new PercentToLocalizedStringTransformer();
-
- $this->assertEquals('10', $transformer->transform(0.1));
- $this->assertEquals('15', $transformer->transform(0.15));
- $this->assertEquals('12', $transformer->transform(0.1234));
- $this->assertEquals('200', $transformer->transform(2));
- }
-
- public function testTransformEmpty()
- {
- $transformer = new PercentToLocalizedStringTransformer();
-
- $this->assertEquals('', $transformer->transform(null));
- }
-
- public function testTransformWithInteger()
- {
- $transformer = new PercentToLocalizedStringTransformer(null, 'integer');
-
- $this->assertEquals('0', $transformer->transform(0.1));
- $this->assertEquals('1', $transformer->transform(1));
- $this->assertEquals('15', $transformer->transform(15));
- $this->assertEquals('16', $transformer->transform(15.9));
- }
-
- public function testTransformWithPrecision()
- {
- $transformer = new PercentToLocalizedStringTransformer(2);
-
- $this->assertEquals('12,34', $transformer->transform(0.1234));
- }
-
- public function testReverseTransform()
- {
- $transformer = new PercentToLocalizedStringTransformer();
-
- $this->assertEquals(0.1, $transformer->reverseTransform('10'));
- $this->assertEquals(0.15, $transformer->reverseTransform('15'));
- $this->assertEquals(0.12, $transformer->reverseTransform('12'));
- $this->assertEquals(2, $transformer->reverseTransform('200'));
- }
-
- public function testReverseTransformEmpty()
- {
- $transformer = new PercentToLocalizedStringTransformer();
-
- $this->assertNull($transformer->reverseTransform(''));
- }
-
- public function testReverseTransformWithInteger()
- {
- $transformer = new PercentToLocalizedStringTransformer(null, 'integer');
-
- $this->assertEquals(10, $transformer->reverseTransform('10'));
- $this->assertEquals(15, $transformer->reverseTransform('15'));
- $this->assertEquals(12, $transformer->reverseTransform('12'));
- $this->assertEquals(200, $transformer->reverseTransform('200'));
- }
-
- public function testReverseTransformWithPrecision()
- {
- $transformer = new PercentToLocalizedStringTransformer(2);
-
- $this->assertEquals(0.1234, $transformer->reverseTransform('12,34'));
- }
-
- public function testTransformExpectsNumeric()
- {
- $transformer = new PercentToLocalizedStringTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $transformer->transform('foo');
- }
-
- public function testReverseTransformExpectsString()
- {
- $transformer = new PercentToLocalizedStringTransformer();
-
- $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
-
- $transformer->reverseTransform(1);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
-
-use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer;
-
-class ValueToDuplicatesTransformerTest extends \PHPUnit_Framework_TestCase
-{
- private $transformer;
-
- protected function setUp()
- {
- $this->transformer = new ValueToDuplicatesTransformer(array('a', 'b', 'c'));
- }
-
- protected function tearDown()
- {
- $this->transformer = null;
- }
-
- public function testTransform()
- {
- $output = array(
- 'a' => 'Foo',
- 'b' => 'Foo',
- 'c' => 'Foo',
- );
-
- $this->assertSame($output, $this->transformer->transform('Foo'));
- }
-
- public function testTransformEmpty()
- {
- $output = array(
- 'a' => null,
- 'b' => null,
- 'c' => null,
- );
-
- $this->assertSame($output, $this->transformer->transform(null));
- }
-
- public function testReverseTransform()
- {
- $input = array(
- 'a' => 'Foo',
- 'b' => 'Foo',
- 'c' => 'Foo',
- );
-
- $this->assertSame('Foo', $this->transformer->reverseTransform($input));
- }
-
- public function testReverseTransformCompletelyEmpty()
- {
- $input = array(
- 'a' => '',
- 'b' => '',
- 'c' => '',
- );
-
- $this->assertNull($this->transformer->reverseTransform($input));
- }
-
- public function testReverseTransformCompletelyNull()
- {
- $input = array(
- 'a' => null,
- 'b' => null,
- 'c' => null,
- );
-
- $this->assertNull($this->transformer->reverseTransform($input));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformPartiallyNull()
- {
- $input = array(
- 'a' => 'Foo',
- 'b' => 'Foo',
- 'c' => null,
- );
-
- $this->transformer->reverseTransform($input);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDifferences()
- {
- $input = array(
- 'a' => 'Foo',
- 'b' => 'Bar',
- 'c' => 'Foo',
- );
-
- $this->transformer->reverseTransform($input);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformRequiresArray()
- {
- $this->transformer->reverseTransform('12345');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
-use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
-
-class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
-{
- private $choiceList;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- parent::setUp();
-
- $this->choiceList = new SimpleChoiceList(array('' => 'Empty', 0 => 'A', 1 => 'B'));
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $listener = null;
- }
-
- public function testFixRadio()
- {
- $data = '1';
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $listener = new FixRadioInputListener($this->choiceList, true);
- $listener->preSubmit($event);
-
- // Indices in SimpleChoiceList are zero-based generated integers
- $this->assertEquals(array(2 => '1'), $event->getData());
- }
-
- public function testFixZero()
- {
- $data = '0';
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $listener = new FixRadioInputListener($this->choiceList, true);
- $listener->preSubmit($event);
-
- // Indices in SimpleChoiceList are zero-based generated integers
- $this->assertEquals(array(1 => '0'), $event->getData());
- }
-
- public function testFixEmptyString()
- {
- $data = '';
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $listener = new FixRadioInputListener($this->choiceList, true);
- $listener->preSubmit($event);
-
- // Indices in SimpleChoiceList are zero-based generated integers
- $this->assertEquals(array(0 => ''), $event->getData());
- }
-
- public function testConvertEmptyStringToPlaceholderIfNotFound()
- {
- $list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
-
- $data = '';
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $listener = new FixRadioInputListener($list, true);
- $listener->preSubmit($event);
-
- $this->assertEquals(array('placeholder' => ''), $event->getData());
- }
-
- public function testDontConvertEmptyStringToPlaceholderIfNoPlaceholderUsed()
- {
- $list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
-
- $data = '';
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $listener = new FixRadioInputListener($list, false);
- $listener->preSubmit($event);
-
- $this->assertEquals(array(), $event->getData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener;
-
-class FixUrlProtocolListenerTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
- }
-
- public function testFixHttpUrl()
- {
- $data = "www.symfony.com";
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $filter = new FixUrlProtocolListener('http');
- $filter->onSubmit($event);
-
- $this->assertEquals('http://www.symfony.com', $event->getData());
- }
-
- public function testSkipKnownUrl()
- {
- $data = "http://www.symfony.com";
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $filter = new FixUrlProtocolListener('http');
- $filter->onSubmit($event);
-
- $this->assertEquals('http://www.symfony.com', $event->getData());
- }
-
- public function testSkipOtherProtocol()
- {
- $data = "ftp://www.symfony.com";
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $filter = new FixUrlProtocolListener('http');
- $filter->onSubmit($event);
-
- $this->assertEquals('ftp://www.symfony.com', $event->getData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormBuilder;
-
-class MergeCollectionListenerArrayObjectTest extends MergeCollectionListenerTest
-{
- protected function getData(array $data)
- {
- return new \ArrayObject($data);
- }
-
- protected function getBuilder($name = 'name')
- {
- return new FormBuilder($name, '\ArrayObject', $this->dispatcher, $this->factory);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormBuilder;
-
-class MergeCollectionListenerArrayTest extends MergeCollectionListenerTest
-{
- protected function getData(array $data)
- {
- return $data;
- }
-
- protected function getBuilder($name = 'name')
- {
- return new FormBuilder($name, null, $this->dispatcher, $this->factory);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\Tests\Fixtures\CustomArrayObject;
-use Symfony\Component\Form\FormBuilder;
-
-class MergeCollectionListenerCustomArrayObjectTest extends MergeCollectionListenerTest
-{
- protected function getData(array $data)
- {
- return new CustomArrayObject($data);
- }
-
- protected function getBuilder($name = 'name')
- {
- return new FormBuilder($name, 'Symfony\Component\Form\Tests\Fixtures\CustomArrayObject', $this->dispatcher, $this->factory);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
-
-abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase
-{
- protected $dispatcher;
- protected $factory;
- protected $form;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->form = $this->getForm('axes');
- }
-
- protected function tearDown()
- {
- $this->dispatcher = null;
- $this->factory = null;
- $this->form = null;
- }
-
- abstract protected function getBuilder($name = 'name');
-
- protected function getForm($name = 'name', $propertyPath = null)
- {
- $propertyPath = $propertyPath ?: $name;
-
- return $this->getBuilder($name)->setAttribute('property_path', $propertyPath)->getForm();
- }
-
- protected function getMockForm()
- {
- return $this->getMock('Symfony\Component\Form\Test\FormInterface');
- }
-
- public function getBooleanMatrix1()
- {
- return array(
- array(true),
- array(false),
- );
- }
-
- public function getBooleanMatrix2()
- {
- return array(
- array(true, true),
- array(true, false),
- array(false, true),
- array(false, false),
- );
- }
-
- abstract protected function getData(array $data);
-
- /**
- * @dataProvider getBooleanMatrix1
- */
- public function testAddExtraEntriesIfAllowAdd($allowDelete)
- {
- $originalData = $this->getData(array(1 => 'second'));
- $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
-
- $listener = new MergeCollectionListener(true, $allowDelete);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- // The original object was modified
- if (is_object($originalData)) {
- $this->assertSame($originalData, $event->getData());
- }
-
- // The original object matches the new object
- $this->assertEquals($newData, $event->getData());
- }
-
- /**
- * @dataProvider getBooleanMatrix1
- */
- public function testAddExtraEntriesIfAllowAddDontOverwriteExistingIndices($allowDelete)
- {
- $originalData = $this->getData(array(1 => 'first'));
- $newData = $this->getData(array(0 => 'first', 1 => 'second'));
-
- $listener = new MergeCollectionListener(true, $allowDelete);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- // The original object was modified
- if (is_object($originalData)) {
- $this->assertSame($originalData, $event->getData());
- }
-
- // The original object matches the new object
- $this->assertEquals($this->getData(array(1 => 'first', 2 => 'second')), $event->getData());
- }
-
- /**
- * @dataProvider getBooleanMatrix1
- */
- public function testDoNothingIfNotAllowAdd($allowDelete)
- {
- $originalDataArray = array(1 => 'second');
- $originalData = $this->getData($originalDataArray);
- $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
-
- $listener = new MergeCollectionListener(false, $allowDelete);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- // We still have the original object
- if (is_object($originalData)) {
- $this->assertSame($originalData, $event->getData());
- }
-
- // Nothing was removed
- $this->assertEquals($this->getData($originalDataArray), $event->getData());
- }
-
- /**
- * @dataProvider getBooleanMatrix1
- */
- public function testRemoveMissingEntriesIfAllowDelete($allowAdd)
- {
- $originalData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
- $newData = $this->getData(array(1 => 'second'));
-
- $listener = new MergeCollectionListener($allowAdd, true);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- // The original object was modified
- if (is_object($originalData)) {
- $this->assertSame($originalData, $event->getData());
- }
-
- // The original object matches the new object
- $this->assertEquals($newData, $event->getData());
- }
-
- /**
- * @dataProvider getBooleanMatrix1
- */
- public function testDoNothingIfNotAllowDelete($allowAdd)
- {
- $originalDataArray = array(0 => 'first', 1 => 'second', 2 => 'third');
- $originalData = $this->getData($originalDataArray);
- $newData = $this->getData(array(1 => 'second'));
-
- $listener = new MergeCollectionListener($allowAdd, false);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- // We still have the original object
- if (is_object($originalData)) {
- $this->assertSame($originalData, $event->getData());
- }
-
- // Nothing was removed
- $this->assertEquals($this->getData($originalDataArray), $event->getData());
- }
-
- /**
- * @dataProvider getBooleanMatrix2
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testRequireArrayOrTraversable($allowAdd, $allowDelete)
- {
- $newData = 'no array or traversable';
- $event = new FormEvent($this->form, $newData);
- $listener = new MergeCollectionListener($allowAdd, $allowDelete);
- $listener->onSubmit($event);
- }
-
- public function testDealWithNullData()
- {
- $originalData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
- $newData = null;
-
- $listener = new MergeCollectionListener(false, false);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- $this->assertSame($originalData, $event->getData());
- }
-
- /**
- * @dataProvider getBooleanMatrix1
- */
- public function testDealWithNullOriginalDataIfAllowAdd($allowDelete)
- {
- $originalData = null;
- $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
-
- $listener = new MergeCollectionListener(true, $allowDelete);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- $this->assertSame($newData, $event->getData());
- }
-
- /**
- * @dataProvider getBooleanMatrix1
- */
- public function testDontDealWithNullOriginalDataIfNotAllowAdd($allowDelete)
- {
- $originalData = null;
- $newData = $this->getData(array(0 => 'first', 1 => 'second', 2 => 'third'));
-
- $listener = new MergeCollectionListener(false, $allowDelete);
-
- $this->form->setData($originalData);
-
- $event = new FormEvent($this->form, $newData);
- $listener->onSubmit($event);
-
- $this->assertNull($event->getData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\FormEvent;
-
-class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
-{
- private $dispatcher;
- private $factory;
- private $form;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->form = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- }
-
- protected function tearDown()
- {
- $this->dispatcher = null;
- $this->factory = null;
- $this->form = null;
- }
-
- protected function getBuilder($name = 'name')
- {
- return new FormBuilder($name, null, $this->dispatcher, $this->factory);
- }
-
- protected function getForm($name = 'name')
- {
- return $this->getBuilder($name)->getForm();
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getDataMapper()
- {
- return $this->getMock('Symfony\Component\Form\DataMapperInterface');
- }
-
- protected function getMockForm()
- {
- return $this->getMock('Symfony\Component\Form\Test\FormInterface');
- }
-
- public function testPreSetDataResizesForm()
- {
- $this->form->add($this->getForm('0'));
- $this->form->add($this->getForm('1'));
-
- $this->factory->expects($this->at(0))
- ->method('createNamed')
- ->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10, 'auto_initialize' => false))
- ->will($this->returnValue($this->getForm('1')));
- $this->factory->expects($this->at(1))
- ->method('createNamed')
- ->with(2, 'text', null, array('property_path' => '[2]', 'max_length' => 10, 'auto_initialize' => false))
- ->will($this->returnValue($this->getForm('2')));
-
- $data = array(1 => 'string', 2 => 'string');
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array('max_length' => '10'), false, false);
- $listener->preSetData($event);
-
- $this->assertFalse($this->form->has('0'));
- $this->assertTrue($this->form->has('1'));
- $this->assertTrue($this->form->has('2'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testPreSetDataRequiresArrayOrTraversable()
- {
- $data = 'no array or traversable';
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, false);
- $listener->preSetData($event);
- }
-
- public function testPreSetDataDealsWithNullData()
- {
- $this->factory->expects($this->never())->method('createNamed');
-
- $data = null;
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, false);
- $listener->preSetData($event);
- }
-
- public function testPreSubmitResizesUpIfAllowAdd()
- {
- $this->form->add($this->getForm('0'));
-
- $this->factory->expects($this->once())
- ->method('createNamed')
- ->with(1, 'text', null, array('property_path' => '[1]', 'max_length' => 10, 'auto_initialize' => false))
- ->will($this->returnValue($this->getForm('1')));
-
- $data = array(0 => 'string', 1 => 'string');
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array('max_length' => 10), true, false);
- $listener->preSubmit($event);
-
- $this->assertTrue($this->form->has('0'));
- $this->assertTrue($this->form->has('1'));
- }
-
- public function testPreSubmitResizesDownIfAllowDelete()
- {
- $this->form->add($this->getForm('0'));
- $this->form->add($this->getForm('1'));
-
- $data = array(0 => 'string');
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, true);
- $listener->preSubmit($event);
-
- $this->assertTrue($this->form->has('0'));
- $this->assertFalse($this->form->has('1'));
- }
-
- // fix for https://github.com/symfony/symfony/pull/493
- public function testPreSubmitRemovesZeroKeys()
- {
- $this->form->add($this->getForm('0'));
-
- $data = array();
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, true);
- $listener->preSubmit($event);
-
- $this->assertFalse($this->form->has('0'));
- }
-
- public function testPreSubmitDoesNothingIfNotAllowAddNorAllowDelete()
- {
- $this->form->add($this->getForm('0'));
- $this->form->add($this->getForm('1'));
-
- $data = array(0 => 'string', 2 => 'string');
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, false);
- $listener->preSubmit($event);
-
- $this->assertTrue($this->form->has('0'));
- $this->assertTrue($this->form->has('1'));
- $this->assertFalse($this->form->has('2'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testPreSubmitRequiresArrayOrTraversable()
- {
- $data = 'no array or traversable';
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, false);
- $listener->preSubmit($event);
- }
-
- public function testPreSubmitDealsWithNullData()
- {
- $this->form->add($this->getForm('1'));
-
- $data = null;
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, true);
- $listener->preSubmit($event);
-
- $this->assertFalse($this->form->has('1'));
- }
-
- // fixes https://github.com/symfony/symfony/pull/40
- public function testPreSubmitDealsWithEmptyData()
- {
- $this->form->add($this->getForm('1'));
-
- $data = '';
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, true);
- $listener->preSubmit($event);
-
- $this->assertFalse($this->form->has('1'));
- }
-
- public function testOnSubmitNormDataRemovesEntriesMissingInTheFormIfAllowDelete()
- {
- $this->form->add($this->getForm('1'));
-
- $data = array(0 => 'first', 1 => 'second', 2 => 'third');
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, true);
- $listener->onSubmit($event);
-
- $this->assertEquals(array(1 => 'second'), $event->getData());
- }
-
- public function testOnSubmitNormDataDoesNothingIfNotAllowDelete()
- {
- $this->form->add($this->getForm('1'));
-
- $data = array(0 => 'first', 1 => 'second', 2 => 'third');
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, false);
- $listener->onSubmit($event);
-
- $this->assertEquals($data, $event->getData());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testOnSubmitNormDataRequiresArrayOrTraversable()
- {
- $data = 'no array or traversable';
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, false);
- $listener->onSubmit($event);
- }
-
- public function testOnSubmitNormDataDealsWithNullData()
- {
- $this->form->add($this->getForm('1'));
-
- $data = null;
- $event = new FormEvent($this->form, $data);
- $listener = new ResizeFormListener('text', array(), false, true);
- $listener->onSubmit($event);
-
- $this->assertEquals(array(), $event->getData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
-
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
-
-class TrimListenerTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
- }
-
- public function testTrim()
- {
- $data = " Foo! ";
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $filter = new TrimListener();
- $filter->preSubmit($event);
-
- $this->assertEquals('Foo!', $event->getData());
- }
-
- public function testTrimSkipNonStrings()
- {
- $data = 1234;
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $filter = new TrimListener();
- $filter->preSubmit($event);
-
- $this->assertSame(1234, $event->getData());
- }
-
- /**
- * @dataProvider codePointProvider
- */
- public function testTrimUtf8($chars)
- {
- if (!function_exists('mb_check_encoding')) {
- $this->markTestSkipped('The "mb_check_encoding" function is not available');
- }
-
- $data = mb_convert_encoding(pack('H*', implode('', $chars)), 'UTF-8', 'UCS-2BE');
- $data = $data."ab\ncd".$data;
-
- $form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $event = new FormEvent($form, $data);
-
- $filter = new TrimListener();
- $filter->preSubmit($event);
-
- $this->assertSame("ab\ncd", $event->getData(), 'TrimListener should trim character(s): '.implode(', ', $chars));
- }
-
- public function codePointProvider()
- {
- return array(
- 'General category: Separator' => array(array('0020', '00A0', '1680', '180E', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '200A', '2028', '2029', '202F', '205F', '3000')),
- 'General category: Other, control' => array(array('0009', '000A', '000B', '000C', '000D', '0085')),
- //'General category: Other, format. ZERO WIDTH SPACE' => array(array('200B')),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- public function testPassDisabledAsOption()
- {
- $form = $this->factory->create($this->getTestedType(), null, array('disabled' => true));
-
- $this->assertTrue($form->isDisabled());
- }
-
- public function testPassIdAndNameToView()
- {
- $view = $this->factory->createNamed('name', $this->getTestedType())
- ->createView();
-
- $this->assertEquals('name', $view->vars['id']);
- $this->assertEquals('name', $view->vars['name']);
- $this->assertEquals('name', $view->vars['full_name']);
- }
-
- public function testStripLeadingUnderscoresAndDigitsFromId()
- {
- $view = $this->factory->createNamed('_09name', $this->getTestedType())
- ->createView();
-
- $this->assertEquals('name', $view->vars['id']);
- $this->assertEquals('_09name', $view->vars['name']);
- $this->assertEquals('_09name', $view->vars['full_name']);
- }
-
- public function testPassIdAndNameToViewWithParent()
- {
- $view = $this->factory->createNamedBuilder('parent', 'form')
- ->add('child', $this->getTestedType())
- ->getForm()
- ->createView();
-
- $this->assertEquals('parent_child', $view['child']->vars['id']);
- $this->assertEquals('child', $view['child']->vars['name']);
- $this->assertEquals('parent[child]', $view['child']->vars['full_name']);
- }
-
- public function testPassIdAndNameToViewWithGrandParent()
- {
- $builder = $this->factory->createNamedBuilder('parent', 'form')
- ->add('child', 'form');
- $builder->get('child')->add('grand_child', $this->getTestedType());
- $view = $builder->getForm()->createView();
-
- $this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']);
- $this->assertEquals('grand_child', $view['child']['grand_child']->vars['name']);
- $this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->vars['full_name']);
- }
-
- public function testPassTranslationDomainToView()
- {
- $form = $this->factory->create($this->getTestedType(), null, array(
- 'translation_domain' => 'domain',
- ));
- $view = $form->createView();
-
- $this->assertSame('domain', $view->vars['translation_domain']);
- }
-
- public function testInheritTranslationDomainFromParent()
- {
- $view = $this->factory
- ->createNamedBuilder('parent', 'form', null, array(
- 'translation_domain' => 'domain',
- ))
- ->add('child', $this->getTestedType())
- ->getForm()
- ->createView();
-
- $this->assertEquals('domain', $view['child']->vars['translation_domain']);
- }
-
- public function testPreferOwnTranslationDomain()
- {
- $view = $this->factory
- ->createNamedBuilder('parent', 'form', null, array(
- 'translation_domain' => 'parent_domain',
- ))
- ->add('child', $this->getTestedType(), array(
- 'translation_domain' => 'domain',
- ))
- ->getForm()
- ->createView();
-
- $this->assertEquals('domain', $view['child']->vars['translation_domain']);
- }
-
- public function testDefaultTranslationDomain()
- {
- $view = $this->factory->createNamedBuilder('parent', 'form')
- ->add('child', $this->getTestedType())
- ->getForm()
- ->createView();
-
- $this->assertEquals('messages', $view['child']->vars['translation_domain']);
- }
-
- public function testPassLabelToView()
- {
- $form = $this->factory->createNamed('__test___field', $this->getTestedType(), null, array('label' => 'My label'));
- $view = $form->createView();
-
- $this->assertSame('My label', $view->vars['label']);
- }
-
- public function testPassMultipartFalseToView()
- {
- $form = $this->factory->create($this->getTestedType());
- $view = $form->createView();
-
- $this->assertFalse($view->vars['multipart']);
- }
-
- abstract protected function getTestedType();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ButtonTypeTest extends BaseTypeTest
-{
- public function testCreateButtonInstances()
- {
- $this->assertInstanceOf('Symfony\Component\Form\Button', $this->factory->create('button'));
- }
-
- protected function getTestedType()
- {
- return 'button';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\CallbackTransformer;
-
-class CheckboxTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- public function testPassValueToView()
- {
- $form = $this->factory->create('checkbox', null, array('value' => 'foobar'));
- $view = $form->createView();
-
- $this->assertEquals('foobar', $view->vars['value']);
- }
-
- public function testCheckedIfDataTrue()
- {
- $form = $this->factory->create('checkbox');
- $form->setData(true);
- $view = $form->createView();
-
- $this->assertTrue($view->vars['checked']);
- }
-
- public function testCheckedIfDataTrueWithEmptyValue()
- {
- $form = $this->factory->create('checkbox', null, array('value' => ''));
- $form->setData(true);
- $view = $form->createView();
-
- $this->assertTrue($view->vars['checked']);
- }
-
- public function testNotCheckedIfDataFalse()
- {
- $form = $this->factory->create('checkbox');
- $form->setData(false);
- $view = $form->createView();
-
- $this->assertFalse($view->vars['checked']);
- }
-
- public function testSubmitWithValueChecked()
- {
- $form = $this->factory->create('checkbox', null, array(
- 'value' => 'foobar',
- ));
- $form->submit('foobar');
-
- $this->assertTrue($form->getData());
- $this->assertEquals('foobar', $form->getViewData());
- }
-
- public function testSubmitWithRandomValueChecked()
- {
- $form = $this->factory->create('checkbox', null, array(
- 'value' => 'foobar',
- ));
- $form->submit('krixikraxi');
-
- $this->assertTrue($form->getData());
- $this->assertEquals('foobar', $form->getViewData());
- }
-
- public function testSubmitWithValueUnchecked()
- {
- $form = $this->factory->create('checkbox', null, array(
- 'value' => 'foobar',
- ));
- $form->submit(null);
-
- $this->assertFalse($form->getData());
- $this->assertNull($form->getViewData());
- }
-
- public function testSubmitWithEmptyValueChecked()
- {
- $form = $this->factory->create('checkbox', null, array(
- 'value' => '',
- ));
- $form->submit('');
-
- $this->assertTrue($form->getData());
- $this->assertSame('', $form->getViewData());
- }
-
- public function testSubmitWithEmptyValueUnchecked()
- {
- $form = $this->factory->create('checkbox', null, array(
- 'value' => '',
- ));
- $form->submit(null);
-
- $this->assertFalse($form->getData());
- $this->assertNull($form->getViewData());
- }
-
- public function testBindWithEmptyValueAndFalseUnchecked()
- {
- $form = $this->factory->create('checkbox', null, array(
- 'value' => '',
- ));
- $form->bind(false);
-
- $this->assertFalse($form->getData());
- $this->assertNull($form->getViewData());
- }
-
- public function testBindWithEmptyValueAndTrueChecked()
- {
- $form = $this->factory->create('checkbox', null, array(
- 'value' => '',
- ));
- $form->bind(true);
-
- $this->assertTrue($form->getData());
- $this->assertSame('', $form->getViewData());
- }
-
- /**
- * @dataProvider provideTransformedData
- */
- public function testTransformedData($data, $expected)
- {
- // present a binary status field as a checkbox
- $transformer = new CallbackTransformer(
- function ($value) {
- return 'expedited' == $value;
- },
- function ($value) {
- return $value ? 'expedited' : 'standard';
- }
- );
-
- $form = $this->builder
- ->create('expedited_shipping', 'checkbox')
- ->addModelTransformer($transformer)
- ->getForm();
- $form->setData($data);
- $view = $form->createView();
-
- $this->assertEquals($expected, $view->vars['checked']);
- }
-
- public function provideTransformedData()
- {
- return array(
- array('expedited', true),
- array('standard', false),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Test\FormPerformanceTestCase;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ChoiceTypePerformanceTest extends FormPerformanceTestCase
-{
- /**
- * This test case is realistic in collection forms where each
- * row contains the same choice field.
- *
- * @group benchmark
- */
- public function testSameChoiceFieldCreatedMultipleTimes()
- {
- $this->setMaxRunningTime(1);
- $choices = range(1, 300);
-
- for ($i = 0; $i < 100; ++$i) {
- $this->factory->create('choice', rand(1, 400), array(
- 'choices' => $choices,
- ));
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- private $choices = array(
- 'a' => 'Bernhard',
- 'b' => 'Fabien',
- 'c' => 'Kris',
- 'd' => 'Jon',
- 'e' => 'Roman',
- );
-
- private $numericChoices = array(
- 0 => 'Bernhard',
- 1 => 'Fabien',
- 2 => 'Kris',
- 3 => 'Jon',
- 4 => 'Roman',
- );
-
- private $objectChoices;
-
- protected $groupedChoices = array(
- 'Symfony' => array(
- 'a' => 'Bernhard',
- 'b' => 'Fabien',
- 'c' => 'Kris',
- ),
- 'Doctrine' => array(
- 'd' => 'Jon',
- 'e' => 'Roman',
- )
- );
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->objectChoices = array(
- (object) array('id' => 1, 'name' => 'Bernhard'),
- (object) array('id' => 2, 'name' => 'Fabien'),
- (object) array('id' => 3, 'name' => 'Kris'),
- (object) array('id' => 4, 'name' => 'Jon'),
- (object) array('id' => 5, 'name' => 'Roman'),
- );
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->objectChoices = null;
- }
-
- /**
- * @expectedException \PHPUnit_Framework_Error
- */
- public function testChoicesOptionExpectsArray()
- {
- $this->factory->create('choice', null, array(
- 'choices' => new \ArrayObject(),
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testChoiceListOptionExpectsChoiceListInterface()
- {
- $this->factory->create('choice', null, array(
- 'choice_list' => array('foo' => 'foo'),
- ));
- }
-
- public function testChoiceListAndChoicesCanBeEmpty()
- {
- $this->factory->create('choice');
- }
-
- public function testExpandedChoicesOptionsTurnIntoChildren()
- {
- $form = $this->factory->create('choice', null, array(
- 'expanded' => true,
- 'choices' => $this->choices,
- ));
-
- $this->assertCount(count($this->choices), $form, 'Each choice should become a new field');
- }
-
- public function testPlaceholderPresentOnNonRequiredExpandedSingleChoice()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => false,
- 'choices' => $this->choices,
- ));
-
- $this->assertTrue(isset($form['placeholder']));
- $this->assertCount(count($this->choices) + 1, $form, 'Each choice should become a new field');
- }
-
- public function testPlaceholderNotPresentIfRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => true,
- 'choices' => $this->choices,
- ));
-
- $this->assertFalse(isset($form['placeholder']));
- $this->assertCount(count($this->choices), $form, 'Each choice should become a new field');
- }
-
- public function testPlaceholderNotPresentIfMultiple()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => true,
- 'required' => false,
- 'choices' => $this->choices,
- ));
-
- $this->assertFalse(isset($form['placeholder']));
- $this->assertCount(count($this->choices), $form, 'Each choice should become a new field');
- }
-
- public function testPlaceholderNotPresentIfEmptyChoice()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => false,
- 'choices' => array(
- '' => 'Empty',
- 1 => 'Not empty',
- ),
- ));
-
- $this->assertFalse(isset($form['placeholder']));
- $this->assertCount(2, $form, 'Each choice should become a new field');
- }
-
- public function testExpandedChoicesOptionsAreFlattened()
- {
- $form = $this->factory->create('choice', null, array(
- 'expanded' => true,
- 'choices' => $this->groupedChoices,
- ));
-
- $flattened = array();
- foreach ($this->groupedChoices as $choices) {
- $flattened = array_merge($flattened, array_keys($choices));
- }
-
- $this->assertCount($form->count(), $flattened, 'Each nested choice should become a new field, not the groups');
-
- foreach ($flattened as $value => $choice) {
- $this->assertTrue($form->has($value), 'Flattened choice is named after it\'s value');
- }
- }
-
- public function testExpandedCheckboxesAreNeverRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => true,
- 'required' => true,
- 'choices' => $this->choices,
- ));
-
- foreach ($form as $child) {
- $this->assertFalse($child->isRequired());
- }
- }
-
- public function testExpandedRadiosAreRequiredIfChoiceChildIsRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => true,
- 'choices' => $this->choices,
- ));
-
- foreach ($form as $child) {
- $this->assertTrue($child->isRequired());
- }
- }
-
- public function testExpandedRadiosAreNotRequiredIfChoiceChildIsNotRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => false,
- 'choices' => $this->choices,
- ));
-
- foreach ($form as $child) {
- $this->assertFalse($child->isRequired());
- }
- }
-
- public function testSubmitSingleNonExpanded()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => false,
- 'choices' => $this->choices,
- ));
-
- $form->submit('b');
-
- $this->assertEquals('b', $form->getData());
- $this->assertEquals('b', $form->getViewData());
- }
-
- public function testSubmitSingleNonExpandedObjectChoices()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => false,
- 'choice_list' => new ObjectChoiceList(
- $this->objectChoices,
- // label path
- 'name',
- array(),
- null,
- // value path
- 'id'
- ),
- ));
-
- // "id" value of the second entry
- $form->submit('2');
-
- $this->assertEquals($this->objectChoices[1], $form->getData());
- $this->assertEquals('2', $form->getViewData());
- }
-
- public function testSubmitMultipleNonExpanded()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => false,
- 'choices' => $this->choices,
- ));
-
- $form->submit(array('a', 'b'));
-
- $this->assertEquals(array('a', 'b'), $form->getData());
- $this->assertEquals(array('a', 'b'), $form->getViewData());
- }
-
- public function testSubmitMultipleNonExpandedObjectChoices()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => false,
- 'choice_list' => new ObjectChoiceList(
- $this->objectChoices,
- // label path
- 'name',
- array(),
- null,
- // value path
- 'id'
- ),
- ));
-
- $form->submit(array('2', '3'));
-
- $this->assertEquals(array($this->objectChoices[1], $this->objectChoices[2]), $form->getData());
- $this->assertEquals(array('2', '3'), $form->getViewData());
- }
-
- public function testSubmitSingleExpandedRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => true,
- 'choices' => $this->choices,
- ));
-
- $form->submit('b');
-
- $this->assertSame('b', $form->getData());
- $this->assertSame(array(
- 0 => false,
- 1 => true,
- 2 => false,
- 3 => false,
- 4 => false,
- ), $form->getViewData());
-
- $this->assertFalse($form[0]->getData());
- $this->assertTrue($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertNull($form[0]->getViewData());
- $this->assertSame('b', $form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitSingleExpandedNonRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => false,
- 'choices' => $this->choices,
- ));
-
- $form->submit('b');
-
- $this->assertSame('b', $form->getData());
- $this->assertSame(array(
- 0 => false,
- 1 => true,
- 2 => false,
- 3 => false,
- 4 => false,
- 'placeholder' => false,
- ), $form->getViewData());
-
- $this->assertFalse($form['placeholder']->getData());
- $this->assertFalse($form[0]->getData());
- $this->assertTrue($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertNull($form['placeholder']->getViewData());
- $this->assertNull($form[0]->getViewData());
- $this->assertSame('b', $form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitSingleExpandedRequiredNothingChecked()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => true,
- 'choices' => $this->choices,
- ));
-
- $form->submit(null);
-
- $this->assertNull($form->getData());
- $this->assertSame(array(
- 0 => false,
- 1 => false,
- 2 => false,
- 3 => false,
- 4 => false,
- ), $form->getViewData());
-
- $this->assertFalse($form[0]->getData());
- $this->assertFalse($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertNull($form[0]->getViewData());
- $this->assertNull($form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitSingleExpandedNonRequiredNothingChecked()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => false,
- 'choices' => $this->choices,
- ));
-
- $form->submit(null);
-
- $this->assertNull($form->getData());
- $this->assertSame(array(
- 0 => false,
- 1 => false,
- 2 => false,
- 3 => false,
- 4 => false,
- 'placeholder' => true,
- ), $form->getViewData());
-
- $this->assertTrue($form['placeholder']->getData());
- $this->assertFalse($form[0]->getData());
- $this->assertFalse($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertSame('', $form['placeholder']->getViewData());
- $this->assertNull($form[0]->getViewData());
- $this->assertNull($form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitFalseToSingleExpandedRequiredDoesNotProduceExtraChildrenError()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => true,
- 'choices' => $this->choices,
- ));
-
- $form->submit(false);
-
- $this->assertEmpty($form->getExtraData());
- $this->assertNull($form->getData());
- }
-
- public function testSubmitFalseToSingleExpandedNonRequiredDoesNotProduceExtraChildrenError()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'required' => false,
- 'choices' => $this->choices,
- ));
-
- $form->submit(false);
-
- $this->assertEmpty($form->getExtraData());
- $this->assertNull($form->getData());
- }
-
- public function testSubmitSingleExpandedWithEmptyChild()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'choices' => array(
- '' => 'Empty',
- 1 => 'Not empty',
- ),
- ));
-
- $form->submit('');
-
- $this->assertNull($form->getData());
- $this->assertTrue($form[0]->getData());
- $this->assertFalse($form[1]->getData());
- $this->assertSame('', $form[0]->getViewData());
- $this->assertNull($form[1]->getViewData());
- }
-
- public function testSubmitSingleExpandedObjectChoices()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'choice_list' => new ObjectChoiceList(
- $this->objectChoices,
- // label path
- 'name',
- array(),
- null,
- // value path
- 'id'
- ),
- ));
-
- $form->submit('2');
-
- $this->assertSame($this->objectChoices[1], $form->getData());
- $this->assertFalse($form[0]->getData());
- $this->assertTrue($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertNull($form[0]->getViewData());
- $this->assertSame('2', $form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitSingleExpandedNumericChoices()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => true,
- 'choices' => $this->numericChoices,
- ));
-
- $form->submit('1');
-
- $this->assertSame(1, $form->getData());
- $this->assertFalse($form[0]->getData());
- $this->assertTrue($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertNull($form[0]->getViewData());
- $this->assertSame('1', $form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitMultipleExpanded()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => true,
- 'choices' => $this->choices,
- ));
-
- $form->submit(array('a', 'c'));
-
- $this->assertSame(array('a', 'c'), $form->getData());
- $this->assertTrue($form[0]->getData());
- $this->assertFalse($form[1]->getData());
- $this->assertTrue($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertSame('a', $form[0]->getViewData());
- $this->assertNull($form[1]->getViewData());
- $this->assertSame('c', $form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitMultipleExpandedEmpty()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => true,
- 'choices' => $this->choices,
- ));
-
- $form->submit(array());
-
- $this->assertSame(array(), $form->getData());
- $this->assertFalse($form[0]->getData());
- $this->assertFalse($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertNull($form[0]->getViewData());
- $this->assertNull($form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitMultipleExpandedWithEmptyChild()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => true,
- 'choices' => array(
- '' => 'Empty',
- 1 => 'Not Empty',
- 2 => 'Not Empty 2',
- )
- ));
-
- $form->submit(array('', '2'));
-
- $this->assertSame(array('', 2), $form->getData());
- $this->assertTrue($form[0]->getData());
- $this->assertFalse($form[1]->getData());
- $this->assertTrue($form[2]->getData());
- $this->assertSame('', $form[0]->getViewData());
- $this->assertNull($form[1]->getViewData());
- $this->assertSame('2', $form[2]->getViewData());
- }
-
- public function testSubmitMultipleExpandedObjectChoices()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => true,
- 'choice_list' => new ObjectChoiceList(
- $this->objectChoices,
- // label path
- 'name',
- array(),
- null,
- // value path
- 'id'
- ),
- ));
-
- $form->submit(array('1', '2'));
-
- $this->assertSame(array($this->objectChoices[0], $this->objectChoices[1]), $form->getData());
- $this->assertTrue($form[0]->getData());
- $this->assertTrue($form[1]->getData());
- $this->assertFalse($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertSame('1', $form[0]->getViewData());
- $this->assertSame('2', $form[1]->getViewData());
- $this->assertNull($form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- public function testSubmitMultipleExpandedNumericChoices()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => true,
- 'choices' => $this->numericChoices,
- ));
-
- $form->submit(array('1', '2'));
-
- $this->assertSame(array(1, 2), $form->getData());
- $this->assertFalse($form[0]->getData());
- $this->assertTrue($form[1]->getData());
- $this->assertTrue($form[2]->getData());
- $this->assertFalse($form[3]->getData());
- $this->assertFalse($form[4]->getData());
- $this->assertNull($form[0]->getViewData());
- $this->assertSame('1', $form[1]->getViewData());
- $this->assertSame('2', $form[2]->getViewData());
- $this->assertNull($form[3]->getViewData());
- $this->assertNull($form[4]->getViewData());
- }
-
- /*
- * We need this functionality to create choice fields for Boolean types,
- * e.g. false => 'No', true => 'Yes'
- */
- public function testSetDataSingleNonExpandedAcceptsBoolean()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'expanded' => false,
- 'choices' => $this->numericChoices,
- ));
-
- $form->setData(false);
-
- $this->assertFalse($form->getData());
- $this->assertEquals('0', $form->getViewData());
- }
-
- public function testSetDataMultipleNonExpandedAcceptsBoolean()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'expanded' => false,
- 'choices' => $this->numericChoices,
- ));
-
- $form->setData(array(false, true));
-
- $this->assertEquals(array(false, true), $form->getData());
- $this->assertEquals(array('0', '1'), $form->getViewData());
- }
-
- public function testPassRequiredToView()
- {
- $form = $this->factory->create('choice', null, array(
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertTrue($view->vars['required']);
- }
-
- public function testPassNonRequiredToView()
- {
- $form = $this->factory->create('choice', null, array(
- 'required' => false,
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertFalse($view->vars['required']);
- }
-
- public function testPassMultipleToView()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => true,
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertTrue($view->vars['multiple']);
- }
-
- public function testPassExpandedToView()
- {
- $form = $this->factory->create('choice', null, array(
- 'expanded' => true,
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertTrue($view->vars['expanded']);
- }
-
- public function testEmptyValueIsNullByDefaultIfRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'required' => true,
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertNull($view->vars['empty_value']);
- }
-
- public function testEmptyValueIsEmptyStringByDefaultIfNotRequired()
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => false,
- 'required' => false,
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertSame('', $view->vars['empty_value']);
- }
-
- /**
- * @dataProvider getOptionsWithEmptyValue
- */
- public function testPassEmptyValueToView($multiple, $expanded, $required, $emptyValue, $viewValue)
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => $multiple,
- 'expanded' => $expanded,
- 'required' => $required,
- 'empty_value' => $emptyValue,
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertEquals($viewValue, $view->vars['empty_value']);
- }
-
- /**
- * @dataProvider getOptionsWithEmptyValue
- */
- public function testDontPassEmptyValueIfContainedInChoices($multiple, $expanded, $required, $emptyValue, $viewValue)
- {
- $form = $this->factory->create('choice', null, array(
- 'multiple' => $multiple,
- 'expanded' => $expanded,
- 'required' => $required,
- 'empty_value' => $emptyValue,
- 'choices' => array('a' => 'A', '' => 'Empty'),
- ));
- $view = $form->createView();
-
- $this->assertNull($view->vars['empty_value']);
- }
-
- public function getOptionsWithEmptyValue()
- {
- return array(
- // single non-expanded
- array(false, false, false, 'foobar', 'foobar'),
- array(false, false, false, '', ''),
- array(false, false, false, null, null),
- array(false, false, false, false, null),
- array(false, false, true, 'foobar', 'foobar'),
- array(false, false, true, '', ''),
- array(false, false, true, null, null),
- array(false, false, true, false, null),
- // single expanded
- array(false, true, false, 'foobar', 'foobar'),
- // radios should never have an empty label
- array(false, true, false, '', 'None'),
- array(false, true, false, null, null),
- array(false, true, false, false, null),
- array(false, true, true, 'foobar', 'foobar'),
- // radios should never have an empty label
- array(false, true, true, '', 'None'),
- array(false, true, true, null, null),
- array(false, true, true, false, null),
- // multiple non-expanded
- array(true, false, false, 'foobar', null),
- array(true, false, false, '', null),
- array(true, false, false, null, null),
- array(true, false, false, false, null),
- array(true, false, true, 'foobar', null),
- array(true, false, true, '', null),
- array(true, false, true, null, null),
- array(true, false, true, false, null),
- // multiple expanded
- array(true, true, false, 'foobar', null),
- array(true, true, false, '', null),
- array(true, true, false, null, null),
- array(true, true, false, false, null),
- array(true, true, true, 'foobar', null),
- array(true, true, true, '', null),
- array(true, true, true, null, null),
- array(true, true, true, false, null),
- );
- }
-
- public function testPassChoicesToView()
- {
- $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D');
- $form = $this->factory->create('choice', null, array(
- 'choices' => $choices,
- ));
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('a', 'a', 'A'),
- new ChoiceView('b', 'b', 'B'),
- new ChoiceView('c', 'c', 'C'),
- new ChoiceView('d', 'd', 'D'),
- ), $view->vars['choices']);
- }
-
- public function testPassPreferredChoicesToView()
- {
- $choices = array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D');
- $form = $this->factory->create('choice', null, array(
- 'choices' => $choices,
- 'preferred_choices' => array('b', 'd'),
- ));
- $view = $form->createView();
-
- $this->assertEquals(array(
- 0 => new ChoiceView('a', 'a', 'A'),
- 2 => new ChoiceView('c', 'c', 'C'),
- ), $view->vars['choices']);
- $this->assertEquals(array(
- 1 => new ChoiceView('b', 'b', 'B'),
- 3 => new ChoiceView('d', 'd', 'D'),
- ), $view->vars['preferred_choices']);
- }
-
- public function testPassHierarchicalChoicesToView()
- {
- $form = $this->factory->create('choice', null, array(
- 'choices' => $this->groupedChoices,
- 'preferred_choices' => array('b', 'd'),
- ));
- $view = $form->createView();
-
- $this->assertEquals(array(
- 'Symfony' => array(
- 0 => new ChoiceView('a', 'a', 'Bernhard'),
- 2 => new ChoiceView('c', 'c', 'Kris'),
- ),
- 'Doctrine' => array(
- 4 => new ChoiceView('e', 'e', 'Roman'),
- ),
- ), $view->vars['choices']);
- $this->assertEquals(array(
- 'Symfony' => array(
- 1 => new ChoiceView('b', 'b', 'Fabien'),
- ),
- 'Doctrine' => array(
- 3 => new ChoiceView('d', 'd', 'Jon'),
- ),
- ), $view->vars['preferred_choices']);
- }
-
- public function testPassChoiceDataToView()
- {
- $obj1 = (object) array('value' => 'a', 'label' => 'A');
- $obj2 = (object) array('value' => 'b', 'label' => 'B');
- $obj3 = (object) array('value' => 'c', 'label' => 'C');
- $obj4 = (object) array('value' => 'd', 'label' => 'D');
- $form = $this->factory->create('choice', null, array(
- 'choice_list' => new ObjectChoiceList(array($obj1, $obj2, $obj3, $obj4), 'label', array(), null, 'value'),
- ));
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView($obj1, 'a', 'A'),
- new ChoiceView($obj2, 'b', 'B'),
- new ChoiceView($obj3, 'c', 'C'),
- new ChoiceView($obj4, 'd', 'D'),
- ), $view->vars['choices']);
- }
-
- public function testAdjustFullNameForMultipleNonExpanded()
- {
- $form = $this->factory->createNamed('name', 'choice', null, array(
- 'multiple' => true,
- 'expanded' => false,
- 'choices' => $this->choices,
- ));
- $view = $form->createView();
-
- $this->assertSame('name[]', $view->vars['full_name']);
- }
-
- // https://github.com/symfony/symfony/issues/3298
- public function testInitializeWithEmptyChoices()
- {
- $this->factory->createNamed('name', 'choice', null, array(
- 'choices' => array(),
- ));
- }
-
- public function testInitializeWithDefaultObjectChoice()
- {
- $obj1 = (object) array('value' => 'a', 'label' => 'A');
- $obj2 = (object) array('value' => 'b', 'label' => 'B');
- $obj3 = (object) array('value' => 'c', 'label' => 'C');
- $obj4 = (object) array('value' => 'd', 'label' => 'D');
-
- $form = $this->factory->create('choice', null, array(
- 'choice_list' => new ObjectChoiceList(array($obj1, $obj2, $obj3, $obj4), 'label', array(), null, 'value'),
- // Used to break because "data_class" was inferred, which needs to
- // remain null in every case (because it refers to the view format)
- 'data' => $obj3,
- ));
-
- // Trigger data initialization
- $form->getViewData();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Form;
-
-class CollectionTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- public function testContainsNoChildByDefault()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'text',
- ));
-
- $this->assertCount(0, $form);
- }
-
- public function testSetDataAdjustsSize()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'text',
- 'options' => array(
- 'max_length' => 20,
- ),
- ));
- $form->setData(array('foo@foo.com', 'foo@bar.com'));
-
- $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]);
- $this->assertInstanceOf('Symfony\Component\Form\Form', $form[1]);
- $this->assertCount(2, $form);
- $this->assertEquals('foo@foo.com', $form[0]->getData());
- $this->assertEquals('foo@bar.com', $form[1]->getData());
- $this->assertEquals(20, $form[0]->getConfig()->getOption('max_length'));
- $this->assertEquals(20, $form[1]->getConfig()->getOption('max_length'));
-
- $form->setData(array('foo@baz.com'));
- $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]);
- $this->assertFalse(isset($form[1]));
- $this->assertCount(1, $form);
- $this->assertEquals('foo@baz.com', $form[0]->getData());
- $this->assertEquals(20, $form[0]->getConfig()->getOption('max_length'));
- }
-
- public function testThrowsExceptionIfObjectIsNotTraversable()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'text',
- ));
- $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
- $form->setData(new \stdClass());
- }
-
- public function testNotResizedIfSubmittedWithMissingData()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'text',
- ));
- $form->setData(array('foo@foo.com', 'bar@bar.com'));
- $form->submit(array('foo@bar.com'));
-
- $this->assertTrue($form->has('0'));
- $this->assertTrue($form->has('1'));
- $this->assertEquals('foo@bar.com', $form[0]->getData());
- $this->assertEquals('', $form[1]->getData());
- }
-
- public function testResizedDownIfSubmittedWithMissingDataAndAllowDelete()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'text',
- 'allow_delete' => true,
- ));
- $form->setData(array('foo@foo.com', 'bar@bar.com'));
- $form->submit(array('foo@foo.com'));
-
- $this->assertTrue($form->has('0'));
- $this->assertFalse($form->has('1'));
- $this->assertEquals('foo@foo.com', $form[0]->getData());
- $this->assertEquals(array('foo@foo.com'), $form->getData());
- }
-
- public function testNotResizedIfSubmittedWithExtraData()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'text',
- ));
- $form->setData(array('foo@bar.com'));
- $form->submit(array('foo@foo.com', 'bar@bar.com'));
-
- $this->assertTrue($form->has('0'));
- $this->assertFalse($form->has('1'));
- $this->assertEquals('foo@foo.com', $form[0]->getData());
- }
-
- public function testResizedUpIfSubmittedWithExtraDataAndAllowAdd()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'text',
- 'allow_add' => true,
- ));
- $form->setData(array('foo@bar.com'));
- $form->submit(array('foo@bar.com', 'bar@bar.com'));
-
- $this->assertTrue($form->has('0'));
- $this->assertTrue($form->has('1'));
- $this->assertEquals('foo@bar.com', $form[0]->getData());
- $this->assertEquals('bar@bar.com', $form[1]->getData());
- $this->assertEquals(array('foo@bar.com', 'bar@bar.com'), $form->getData());
- }
-
- public function testAllowAddButNoPrototype()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'form',
- 'allow_add' => true,
- 'prototype' => false,
- ));
-
- $this->assertFalse($form->has('__name__'));
- }
-
- public function testPrototypeMultipartPropagation()
- {
- $form = $this->factory
- ->create('collection', null, array(
- 'type' => 'file',
- 'allow_add' => true,
- 'prototype' => true,
- ))
- ;
-
- $this->assertTrue($form->createView()->vars['multipart']);
- }
-
- public function testGetDataDoesNotContainsPrototypeNameBeforeDataAreSet()
- {
- $form = $this->factory->create('collection', array(), array(
- 'type' => 'file',
- 'prototype' => true,
- 'allow_add' => true,
- ));
-
- $data = $form->getData();
- $this->assertFalse(isset($data['__name__']));
- }
-
- public function testGetDataDoesNotContainsPrototypeNameAfterDataAreSet()
- {
- $form = $this->factory->create('collection', array(), array(
- 'type' => 'file',
- 'allow_add' => true,
- 'prototype' => true,
- ));
-
- $form->setData(array('foobar.png'));
- $data = $form->getData();
- $this->assertFalse(isset($data['__name__']));
- }
-
- public function testPrototypeNameOption()
- {
- $form = $this->factory->create('collection', null, array(
- 'type' => 'form',
- 'prototype' => true,
- 'allow_add' => true,
- ));
-
- $this->assertSame('__name__', $form->getConfig()->getAttribute('prototype')->getName(), '__name__ is the default');
-
- $form = $this->factory->create('collection', null, array(
- 'type' => 'form',
- 'prototype' => true,
- 'allow_add' => true,
- 'prototype_name' => '__test__',
- ));
-
- $this->assertSame('__test__', $form->getConfig()->getAttribute('prototype')->getName());
- }
-
- public function testPrototypeDefaultLabel()
- {
- $form = $this->factory->create('collection', array(), array(
- 'type' => 'file',
- 'allow_add' => true,
- 'prototype' => true,
- 'prototype_name' => '__test__',
- ));
-
- $this->assertSame('__test__label__', $form->createView()->vars['prototype']->vars['label']);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class CountryTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- public function testCountriesAreSelectable()
- {
- $form = $this->factory->create('country');
- $view = $form->createView();
- $choices = $view->vars['choices'];
-
- // Don't check objects for identity
- $this->assertContains(new ChoiceView('DE', 'DE', 'Germany'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('GB', 'GB', 'United Kingdom'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('US', 'US', 'United States'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('FR', 'FR', 'France'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('MY', 'MY', 'Malaysia'), $choices, '', false, false);
- }
-
- public function testUnknownCountryIsNotIncluded()
- {
- $form = $this->factory->create('country', 'country');
- $view = $form->createView();
- $choices = $view->vars['choices'];
-
- foreach ($choices as $choice) {
- if ('ZZ' === $choice->value) {
- $this->fail('Should not contain choice "ZZ"');
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class CurrencyTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- public function testCurrenciesAreSelectable()
- {
- $form = $this->factory->create('currency');
- $view = $form->createView();
- $choices = $view->vars['choices'];
-
- $this->assertContains(new ChoiceView('EUR', 'EUR', 'Euro'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('USD', 'USD', 'US Dollar'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('SIT', 'SIT', 'Slovenian Tolar'), $choices, '', false, false);
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class DateTimeTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- public function testSubmitDateTime()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'date_widget' => 'choice',
- 'time_widget' => 'choice',
- 'input' => 'datetime',
- ));
-
- $form->submit(array(
- 'date' => array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- ),
- 'time' => array(
- 'hour' => '3',
- 'minute' => '4',
- ),
- ));
-
- $dateTime = new \DateTime('2010-06-02 03:04:00 UTC');
-
- $this->assertDateTimeEquals($dateTime, $form->getData());
- }
-
- public function testSubmitString()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'string',
- 'date_widget' => 'choice',
- 'time_widget' => 'choice',
- ));
-
- $form->submit(array(
- 'date' => array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- ),
- 'time' => array(
- 'hour' => '3',
- 'minute' => '4',
- ),
- ));
-
- $this->assertEquals('2010-06-02 03:04:00', $form->getData());
- }
-
- public function testSubmitTimestamp()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'timestamp',
- 'date_widget' => 'choice',
- 'time_widget' => 'choice',
- ));
-
- $form->submit(array(
- 'date' => array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- ),
- 'time' => array(
- 'hour' => '3',
- 'minute' => '4',
- ),
- ));
-
- $dateTime = new \DateTime('2010-06-02 03:04:00 UTC');
-
- $this->assertEquals($dateTime->format('U'), $form->getData());
- }
-
- public function testSubmitWithoutMinutes()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'date_widget' => 'choice',
- 'time_widget' => 'choice',
- 'input' => 'datetime',
- 'with_minutes' => false,
- ));
-
- $form->setData(new \DateTime('2010-06-02 03:04:05 UTC'));
-
- $input = array(
- 'date' => array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- ),
- 'time' => array(
- 'hour' => '3',
- ),
- );
-
- $form->submit($input);
-
- $this->assertDateTimeEquals(new \DateTime('2010-06-02 03:00:00 UTC'), $form->getData());
- }
-
- public function testSubmitWithSeconds()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'date_widget' => 'choice',
- 'time_widget' => 'choice',
- 'input' => 'datetime',
- 'with_seconds' => true,
- ));
-
- $form->setData(new \DateTime('2010-06-02 03:04:05 UTC'));
-
- $input = array(
- 'date' => array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- ),
- 'time' => array(
- 'hour' => '3',
- 'minute' => '4',
- 'second' => '5',
- ),
- );
-
- $form->submit($input);
-
- $this->assertDateTimeEquals(new \DateTime('2010-06-02 03:04:05 UTC'), $form->getData());
- }
-
- public function testSubmitDifferentTimezones()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'America/New_York',
- 'view_timezone' => 'Pacific/Tahiti',
- 'date_widget' => 'choice',
- 'time_widget' => 'choice',
- 'input' => 'string',
- 'with_seconds' => true,
- ));
-
- $dateTime = new \DateTime('2010-06-02 03:04:05 Pacific/Tahiti');
-
- $form->submit(array(
- 'date' => array(
- 'day' => (int) $dateTime->format('d'),
- 'month' => (int) $dateTime->format('m'),
- 'year' => (int) $dateTime->format('Y'),
- ),
- 'time' => array(
- 'hour' => (int) $dateTime->format('H'),
- 'minute' => (int) $dateTime->format('i'),
- 'second' => (int) $dateTime->format('s'),
- ),
- ));
-
- $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
-
- $this->assertEquals($dateTime->format('Y-m-d H:i:s'), $form->getData());
- }
-
- public function testSubmitDifferentTimezonesDateTime()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'America/New_York',
- 'view_timezone' => 'Pacific/Tahiti',
- 'widget' => 'single_text',
- 'input' => 'datetime',
- ));
-
- $outputTime = new \DateTime('2010-06-02 03:04:00 Pacific/Tahiti');
-
- $form->submit('2010-06-02T03:04:00-10:00');
-
- $outputTime->setTimezone(new \DateTimeZone('America/New_York'));
-
- $this->assertDateTimeEquals($outputTime, $form->getData());
- $this->assertEquals('2010-06-02T03:04:00-10:00', $form->getViewData());
- }
-
- public function testSubmitStringSingleText()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'string',
- 'widget' => 'single_text',
- ));
-
- $form->submit('2010-06-02T03:04:00Z');
-
- $this->assertEquals('2010-06-02 03:04:00', $form->getData());
- $this->assertEquals('2010-06-02T03:04:00Z', $form->getViewData());
- }
-
- public function testSubmitStringSingleTextWithSeconds()
- {
- $form = $this->factory->create('datetime', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'string',
- 'widget' => 'single_text',
- 'with_seconds' => true,
- ));
-
- $form->submit('2010-06-02T03:04:05Z');
-
- $this->assertEquals('2010-06-02 03:04:05', $form->getData());
- $this->assertEquals('2010-06-02T03:04:05Z', $form->getViewData());
- }
-
- public function testSubmitDifferentPattern()
- {
- $form = $this->factory->create('datetime', null, array(
- 'date_format' => 'MM*yyyy*dd',
- 'date_widget' => 'single_text',
- 'time_widget' => 'single_text',
- 'input' => 'datetime',
- ));
-
- $dateTime = new \DateTime('2010-06-02 03:04');
-
- $form->submit(array(
- 'date' => '06*2010*02',
- 'time' => '03:04',
- ));
-
- $this->assertDateTimeEquals($dateTime, $form->getData());
- }
-
- // Bug fix
- public function testInitializeWithDateTime()
- {
- // Throws an exception if "data_class" option is not explicitly set
- // to null in the type
- $this->factory->create('datetime', new \DateTime());
- }
-
- public function testSingleTextWidgetShouldUseTheRightInputType()
- {
- $form = $this->factory->create('datetime', null, array(
- 'widget' => 'single_text',
- ));
-
- $view = $form->createView();
- $this->assertEquals('datetime', $view->vars['type']);
- }
-
- public function testPassDefaultEmptyValueToViewIfNotRequired()
- {
- $form = $this->factory->create('datetime', null, array(
- 'required' => false,
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('', $view['date']['year']->vars['empty_value']);
- $this->assertSame('', $view['date']['month']->vars['empty_value']);
- $this->assertSame('', $view['date']['day']->vars['empty_value']);
- $this->assertSame('', $view['time']['hour']->vars['empty_value']);
- $this->assertSame('', $view['time']['minute']->vars['empty_value']);
- $this->assertSame('', $view['time']['second']->vars['empty_value']);
- }
-
- public function testPassNoEmptyValueToViewIfRequired()
- {
- $form = $this->factory->create('datetime', null, array(
- 'required' => true,
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertNull($view['date']['year']->vars['empty_value']);
- $this->assertNull($view['date']['month']->vars['empty_value']);
- $this->assertNull($view['date']['day']->vars['empty_value']);
- $this->assertNull($view['time']['hour']->vars['empty_value']);
- $this->assertNull($view['time']['minute']->vars['empty_value']);
- $this->assertNull($view['time']['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsString()
- {
- $form = $this->factory->create('datetime', null, array(
- 'empty_value' => 'Empty',
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty', $view['date']['year']->vars['empty_value']);
- $this->assertSame('Empty', $view['date']['month']->vars['empty_value']);
- $this->assertSame('Empty', $view['date']['day']->vars['empty_value']);
- $this->assertSame('Empty', $view['time']['hour']->vars['empty_value']);
- $this->assertSame('Empty', $view['time']['minute']->vars['empty_value']);
- $this->assertSame('Empty', $view['time']['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsArray()
- {
- $form = $this->factory->create('datetime', null, array(
- 'empty_value' => array(
- 'year' => 'Empty year',
- 'month' => 'Empty month',
- 'day' => 'Empty day',
- 'hour' => 'Empty hour',
- 'minute' => 'Empty minute',
- 'second' => 'Empty second',
- ),
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty year', $view['date']['year']->vars['empty_value']);
- $this->assertSame('Empty month', $view['date']['month']->vars['empty_value']);
- $this->assertSame('Empty day', $view['date']['day']->vars['empty_value']);
- $this->assertSame('Empty hour', $view['time']['hour']->vars['empty_value']);
- $this->assertSame('Empty minute', $view['time']['minute']->vars['empty_value']);
- $this->assertSame('Empty second', $view['time']['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsPartialArrayAddEmptyIfNotRequired()
- {
- $form = $this->factory->create('datetime', null, array(
- 'required' => false,
- 'empty_value' => array(
- 'year' => 'Empty year',
- 'day' => 'Empty day',
- 'hour' => 'Empty hour',
- 'second' => 'Empty second',
- ),
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty year', $view['date']['year']->vars['empty_value']);
- $this->assertSame('', $view['date']['month']->vars['empty_value']);
- $this->assertSame('Empty day', $view['date']['day']->vars['empty_value']);
- $this->assertSame('Empty hour', $view['time']['hour']->vars['empty_value']);
- $this->assertSame('', $view['time']['minute']->vars['empty_value']);
- $this->assertSame('Empty second', $view['time']['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsPartialArrayAddNullIfRequired()
- {
- $form = $this->factory->create('datetime', null, array(
- 'required' => true,
- 'empty_value' => array(
- 'year' => 'Empty year',
- 'day' => 'Empty day',
- 'hour' => 'Empty hour',
- 'second' => 'Empty second',
- ),
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty year', $view['date']['year']->vars['empty_value']);
- $this->assertNull($view['date']['month']->vars['empty_value']);
- $this->assertSame('Empty day', $view['date']['day']->vars['empty_value']);
- $this->assertSame('Empty hour', $view['time']['hour']->vars['empty_value']);
- $this->assertNull($view['time']['minute']->vars['empty_value']);
- $this->assertSame('Empty second', $view['time']['second']->vars['empty_value']);
- }
-
- public function testPassHtml5TypeIfSingleTextAndHtml5Format()
- {
- $form = $this->factory->create('datetime', null, array(
- 'widget' => 'single_text',
- ));
-
- $view = $form->createView();
- $this->assertSame('datetime', $view->vars['type']);
- }
-
- public function testDontPassHtml5TypeIfNotHtml5Format()
- {
- $form = $this->factory->create('datetime', null, array(
- 'widget' => 'single_text',
- 'format' => 'yyyy-MM-dd HH:mm',
- ));
-
- $view = $form->createView();
- $this->assertFalse(isset($view->vars['type']));
- }
-
- public function testDontPassHtml5TypeIfNotSingleText()
- {
- $form = $this->factory->create('datetime', null, array(
- 'widget' => 'text',
- ));
-
- $view = $form->createView();
- $this->assertFalse(isset($view->vars['type']));
- }
-
- public function testDateTypeChoiceErrorsBubbleUp()
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('datetime', null);
-
- $form['date']->addError($error);
-
- $this->assertSame(array(), $form['date']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- public function testDateTypeSingleTextErrorsBubbleUp()
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('datetime', null, array(
- 'date_widget' => 'single_text'
- ));
-
- $form['date']->addError($error);
-
- $this->assertSame(array(), $form['date']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- public function testTimeTypeChoiceErrorsBubbleUp()
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('datetime', null);
-
- $form['time']->addError($error);
-
- $this->assertSame(array(), $form['time']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- public function testTimeTypeSingleTextErrorsBubbleUp()
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('datetime', null, array(
- 'time_widget' => 'single_text'
- ));
-
- $form['time']->addError($error);
-
- $this->assertSame(array(), $form['time']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class DateTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- // we test against "de_AT", so we need the full implementation
- IntlTestHelper::requireFullIntl($this);
-
- \Locale::setDefault('de_AT');
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testInvalidWidgetOption()
- {
- $this->factory->create('date', null, array(
- 'widget' => 'fake_widget',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testInvalidInputOption()
- {
- $this->factory->create('date', null, array(
- 'input' => 'fake_input',
- ));
- }
-
- public function testSubmitFromSingleTextDateTimeWithDefaultFormat()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'single_text',
- 'input' => 'datetime',
- ));
-
- $form->submit('2010-06-02');
-
- $this->assertDateTimeEquals(new \DateTime('2010-06-02 UTC'), $form->getData());
- $this->assertEquals('2010-06-02', $form->getViewData());
- }
-
- public function testSubmitFromSingleTextDateTime()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => \IntlDateFormatter::MEDIUM,
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'single_text',
- 'input' => 'datetime',
- ));
-
- $form->submit('2.6.2010');
-
- $this->assertDateTimeEquals(new \DateTime('2010-06-02 UTC'), $form->getData());
- $this->assertEquals('02.06.2010', $form->getViewData());
- }
-
- public function testSubmitFromSingleTextString()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => \IntlDateFormatter::MEDIUM,
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'single_text',
- 'input' => 'string',
- ));
-
- $form->submit('2.6.2010');
-
- $this->assertEquals('2010-06-02', $form->getData());
- $this->assertEquals('02.06.2010', $form->getViewData());
- }
-
- public function testSubmitFromSingleTextTimestamp()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => \IntlDateFormatter::MEDIUM,
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'single_text',
- 'input' => 'timestamp',
- ));
-
- $form->submit('2.6.2010');
-
- $dateTime = new \DateTime('2010-06-02 UTC');
-
- $this->assertEquals($dateTime->format('U'), $form->getData());
- $this->assertEquals('02.06.2010', $form->getViewData());
- }
-
- public function testSubmitFromSingleTextRaw()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => \IntlDateFormatter::MEDIUM,
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'single_text',
- 'input' => 'array',
- ));
-
- $form->submit('2.6.2010');
-
- $output = array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- );
-
- $this->assertEquals($output, $form->getData());
- $this->assertEquals('02.06.2010', $form->getViewData());
- }
-
- public function testSubmitFromText()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'text',
- ));
-
- $text = array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- );
-
- $form->submit($text);
-
- $dateTime = new \DateTime('2010-06-02 UTC');
-
- $this->assertDateTimeEquals($dateTime, $form->getData());
- $this->assertEquals($text, $form->getViewData());
- }
-
- public function testSubmitFromChoice()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'choice',
- ));
-
- $text = array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- );
-
- $form->submit($text);
-
- $dateTime = new \DateTime('2010-06-02 UTC');
-
- $this->assertDateTimeEquals($dateTime, $form->getData());
- $this->assertEquals($text, $form->getViewData());
- }
-
- public function testSubmitFromChoiceEmpty()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'choice',
- 'required' => false,
- ));
-
- $text = array(
- 'day' => '',
- 'month' => '',
- 'year' => '',
- );
-
- $form->submit($text);
-
- $this->assertNull($form->getData());
- $this->assertEquals($text, $form->getViewData());
- }
-
- public function testSubmitFromInputDateTimeDifferentPattern()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'format' => 'MM*yyyy*dd',
- 'widget' => 'single_text',
- 'input' => 'datetime',
- ));
-
- $form->submit('06*2010*02');
-
- $this->assertDateTimeEquals(new \DateTime('2010-06-02 UTC'), $form->getData());
- $this->assertEquals('06*2010*02', $form->getViewData());
- }
-
- public function testSubmitFromInputStringDifferentPattern()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'format' => 'MM*yyyy*dd',
- 'widget' => 'single_text',
- 'input' => 'string',
- ));
-
- $form->submit('06*2010*02');
-
- $this->assertEquals('2010-06-02', $form->getData());
- $this->assertEquals('06*2010*02', $form->getViewData());
- }
-
- public function testSubmitFromInputTimestampDifferentPattern()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'format' => 'MM*yyyy*dd',
- 'widget' => 'single_text',
- 'input' => 'timestamp',
- ));
-
- $form->submit('06*2010*02');
-
- $dateTime = new \DateTime('2010-06-02 UTC');
-
- $this->assertEquals($dateTime->format('U'), $form->getData());
- $this->assertEquals('06*2010*02', $form->getViewData());
- }
-
- public function testSubmitFromInputRawDifferentPattern()
- {
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'format' => 'MM*yyyy*dd',
- 'widget' => 'single_text',
- 'input' => 'array',
- ));
-
- $form->submit('06*2010*02');
-
- $output = array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- );
-
- $this->assertEquals($output, $form->getData());
- $this->assertEquals('06*2010*02', $form->getViewData());
- }
-
- /**
- * @dataProvider provideDateFormats
- */
- public function testDatePatternWithFormatOption($format, $pattern)
- {
- $form = $this->factory->create('date', null, array(
- 'format' => $format,
- ));
-
- $view = $form->createView();
-
- $this->assertEquals($pattern, $view->vars['date_pattern']);
- }
-
- public function provideDateFormats()
- {
- return array(
- array('dMy', '{{ day }}{{ month }}{{ year }}'),
- array('d-M-yyyy', '{{ day }}-{{ month }}-{{ year }}'),
- array('M d y', '{{ month }} {{ day }} {{ year }}'),
- );
- }
-
- /**
- * This test is to check that the strings '0', '1', '2', '3' are no accepted
- * as valid IntlDateFormatter constants for FULL, LONG, MEDIUM or SHORT respectively.
- *
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testThrowExceptionIfFormatIsNoPattern()
- {
- $this->factory->create('date', null, array(
- 'format' => '0',
- 'widget' => 'single_text',
- 'input' => 'string',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testThrowExceptionIfFormatDoesNotContainYearMonthAndDay()
- {
- $this->factory->create('date', null, array(
- 'months' => array(6, 7),
- 'format' => 'yy',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testThrowExceptionIfFormatIsNoConstant()
- {
- $this->factory->create('date', null, array(
- 'format' => 105,
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testThrowExceptionIfFormatIsInvalid()
- {
- $this->factory->create('date', null, array(
- 'format' => array(),
- ));
- }
-
- public function testSetDataWithDifferentTimezones()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => \IntlDateFormatter::MEDIUM,
- 'model_timezone' => 'America/New_York',
- 'view_timezone' => 'Pacific/Tahiti',
- 'input' => 'string',
- 'widget' => 'single_text',
- ));
-
- $form->setData('2010-06-02');
-
- $this->assertEquals('01.06.2010', $form->getViewData());
- }
-
- public function testSetDataWithDifferentTimezonesDateTime()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => \IntlDateFormatter::MEDIUM,
- 'model_timezone' => 'America/New_York',
- 'view_timezone' => 'Pacific/Tahiti',
- 'input' => 'datetime',
- 'widget' => 'single_text',
- ));
-
- $dateTime = new \DateTime('2010-06-02 America/New_York');
-
- $form->setData($dateTime);
-
- $this->assertDateTimeEquals($dateTime, $form->getData());
- $this->assertEquals('01.06.2010', $form->getViewData());
- }
-
- public function testYearsOption()
- {
- $form = $this->factory->create('date', null, array(
- 'years' => array(2010, 2011),
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('2010', '2010', '2010'),
- new ChoiceView('2011', '2011', '2011'),
- ), $view['year']->vars['choices']);
- }
-
- public function testMonthsOption()
- {
- $form = $this->factory->create('date', null, array(
- 'months' => array(6, 7),
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('6', '6', '06'),
- new ChoiceView('7', '7', '07'),
- ), $view['month']->vars['choices']);
- }
-
- public function testMonthsOptionShortFormat()
- {
- $form = $this->factory->create('date', null, array(
- 'months' => array(1, 4),
- 'format' => 'dd.MMM.yy',
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('1', '1', 'Jän'),
- new ChoiceView('4', '4', 'Apr.')
- ), $view['month']->vars['choices']);
- }
-
- public function testMonthsOptionLongFormat()
- {
- $form = $this->factory->create('date', null, array(
- 'months' => array(1, 4),
- 'format' => 'dd.MMMM.yy',
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('1', '1', 'Jänner'),
- new ChoiceView('4', '4', 'April'),
- ), $view['month']->vars['choices']);
- }
-
- public function testMonthsOptionLongFormatWithDifferentTimezone()
- {
- $form = $this->factory->create('date', null, array(
- 'months' => array(1, 4),
- 'format' => 'dd.MMMM.yy',
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('1', '1', 'Jänner'),
- new ChoiceView('4', '4', 'April'),
- ), $view['month']->vars['choices']);
- }
-
- public function testIsDayWithinRangeReturnsTrueIfWithin()
- {
- $form = $this->factory->create('date', null, array(
- 'days' => array(6, 7),
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('6', '6', '06'),
- new ChoiceView('7', '7', '07'),
- ), $view['day']->vars['choices']);
- }
-
- public function testIsPartiallyFilledReturnsFalseIfSingleText()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'single_text',
- ));
-
- $form->submit('7.6.2010');
-
- $this->assertFalse($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsFalseIfChoiceAndCompletelyEmpty()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'choice',
- ));
-
- $form->submit(array(
- 'day' => '',
- 'month' => '',
- 'year' => '',
- ));
-
- $this->assertFalse($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsFalseIfChoiceAndCompletelyFilled()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'choice',
- ));
-
- $form->submit(array(
- 'day' => '2',
- 'month' => '6',
- 'year' => '2010',
- ));
-
- $this->assertFalse($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsTrueIfChoiceAndDayEmpty()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('date', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'widget' => 'choice',
- ));
-
- $form->submit(array(
- 'day' => '',
- 'month' => '6',
- 'year' => '2010',
- ));
-
- $this->assertTrue($form->isPartiallyFilled());
- }
-
- public function testPassDatePatternToView()
- {
- $form = $this->factory->create('date');
- $view = $form->createView();
-
- $this->assertSame('{{ day }}{{ month }}{{ year }}', $view->vars['date_pattern']);
- }
-
- public function testPassDatePatternToViewDifferentFormat()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => \IntlDateFormatter::LONG,
- ));
-
- $view = $form->createView();
-
- $this->assertSame('{{ day }}{{ month }}{{ year }}', $view->vars['date_pattern']);
- }
-
- public function testPassDatePatternToViewDifferentPattern()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => 'MMyyyydd'
- ));
-
- $view = $form->createView();
-
- $this->assertSame('{{ month }}{{ year }}{{ day }}', $view->vars['date_pattern']);
- }
-
- public function testPassDatePatternToViewDifferentPatternWithSeparators()
- {
- $form = $this->factory->create('date', null, array(
- 'format' => 'MM*yyyy*dd'
- ));
-
- $view = $form->createView();
-
- $this->assertSame('{{ month }}*{{ year }}*{{ day }}', $view->vars['date_pattern']);
- }
-
- public function testDontPassDatePatternIfText()
- {
- $form = $this->factory->create('date', null, array(
- 'widget' => 'single_text',
- ));
- $view = $form->createView();
-
- $this->assertFalse(isset($view->vars['date_pattern']));
- }
-
- public function testPassWidgetToView()
- {
- $form = $this->factory->create('date', null, array(
- 'widget' => 'single_text',
- ));
- $view = $form->createView();
-
- $this->assertSame('single_text', $view->vars['widget']);
- }
-
- // Bug fix
- public function testInitializeWithDateTime()
- {
- // Throws an exception if "data_class" option is not explicitly set
- // to null in the type
- $this->factory->create('date', new \DateTime());
- }
-
- public function testSingleTextWidgetShouldUseTheRightInputType()
- {
- $form = $this->factory->create('date', null, array(
- 'widget' => 'single_text',
- ));
-
- $view = $form->createView();
- $this->assertEquals('date', $view->vars['type']);
- }
-
- public function testPassDefaultEmptyValueToViewIfNotRequired()
- {
- $form = $this->factory->create('date', null, array(
- 'required' => false,
- ));
-
- $view = $form->createView();
- $this->assertSame('', $view['year']->vars['empty_value']);
- $this->assertSame('', $view['month']->vars['empty_value']);
- $this->assertSame('', $view['day']->vars['empty_value']);
- }
-
- public function testPassNoEmptyValueToViewIfRequired()
- {
- $form = $this->factory->create('date', null, array(
- 'required' => true,
- ));
-
- $view = $form->createView();
- $this->assertNull($view['year']->vars['empty_value']);
- $this->assertNull($view['month']->vars['empty_value']);
- $this->assertNull($view['day']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsString()
- {
- $form = $this->factory->create('date', null, array(
- 'empty_value' => 'Empty',
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty', $view['year']->vars['empty_value']);
- $this->assertSame('Empty', $view['month']->vars['empty_value']);
- $this->assertSame('Empty', $view['day']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsArray()
- {
- $form = $this->factory->create('date', null, array(
- 'empty_value' => array(
- 'year' => 'Empty year',
- 'month' => 'Empty month',
- 'day' => 'Empty day',
- ),
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty year', $view['year']->vars['empty_value']);
- $this->assertSame('Empty month', $view['month']->vars['empty_value']);
- $this->assertSame('Empty day', $view['day']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsPartialArrayAddEmptyIfNotRequired()
- {
- $form = $this->factory->create('date', null, array(
- 'required' => false,
- 'empty_value' => array(
- 'year' => 'Empty year',
- 'day' => 'Empty day',
- ),
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty year', $view['year']->vars['empty_value']);
- $this->assertSame('', $view['month']->vars['empty_value']);
- $this->assertSame('Empty day', $view['day']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsPartialArrayAddNullIfRequired()
- {
- $form = $this->factory->create('date', null, array(
- 'required' => true,
- 'empty_value' => array(
- 'year' => 'Empty year',
- 'day' => 'Empty day',
- ),
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty year', $view['year']->vars['empty_value']);
- $this->assertNull($view['month']->vars['empty_value']);
- $this->assertSame('Empty day', $view['day']->vars['empty_value']);
- }
-
- public function testPassHtml5TypeIfSingleTextAndHtml5Format()
- {
- $form = $this->factory->create('date', null, array(
- 'widget' => 'single_text',
- ));
-
- $view = $form->createView();
- $this->assertSame('date', $view->vars['type']);
- }
-
- public function testDontPassHtml5TypeIfNotHtml5Format()
- {
- $form = $this->factory->create('date', null, array(
- 'widget' => 'single_text',
- 'format' => \IntlDateFormatter::MEDIUM,
- ));
-
- $view = $form->createView();
- $this->assertFalse(isset($view->vars['type']));
- }
-
- public function testDontPassHtml5TypeIfNotSingleText()
- {
- $form = $this->factory->create('date', null, array(
- 'widget' => 'text',
- ));
-
- $view = $form->createView();
- $this->assertFalse(isset($view->vars['type']));
- }
-
- public function provideCompoundWidgets()
- {
- return array(
- array('text'),
- array('choice'),
- );
- }
-
- /**
- * @dataProvider provideCompoundWidgets
- */
- public function testYearErrorsBubbleUp($widget)
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('date', null, array(
- 'widget' => $widget,
- ));
- $form['year']->addError($error);
-
- $this->assertSame(array(), $form['year']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- /**
- * @dataProvider provideCompoundWidgets
- */
- public function testMonthErrorsBubbleUp($widget)
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('date', null, array(
- 'widget' => $widget,
- ));
- $form['month']->addError($error);
-
- $this->assertSame(array(), $form['month']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- /**
- * @dataProvider provideCompoundWidgets
- */
- public function testDayErrorsBubbleUp($widget)
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('date', null, array(
- 'widget' => $widget,
- ));
- $form['day']->addError($error);
-
- $this->assertSame(array(), $form['day']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-class FileTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- // https://github.com/symfony/symfony/pull/5028
- public function testSetData()
- {
- $form = $this->factory->createBuilder('file')->getForm();
- $data = $this->createUploadedFileMock('abcdef', 'original.jpg', true);
-
- $form->setData($data);
-
- $this->assertSame($data, $form->getData());
- }
-
- public function testSubmit()
- {
- $form = $this->factory->createBuilder('file')->getForm();
- $data = $this->createUploadedFileMock('abcdef', 'original.jpg', true);
-
- $form->submit($data);
-
- $this->assertSame($data, $form->getData());
- }
-
- // https://github.com/symfony/symfony/issues/6134
- public function testSubmitEmpty()
- {
- $form = $this->factory->createBuilder('file')->getForm();
-
- $form->submit(null);
-
- $this->assertNull($form->getData());
- }
-
- public function testDontPassValueToView()
- {
- $form = $this->factory->create('file');
- $form->submit(array(
- 'file' => $this->createUploadedFileMock('abcdef', 'original.jpg', true),
- ));
- $view = $form->createView();
-
- $this->assertEquals('', $view->vars['value']);
- }
-
- private function createUploadedFileMock($name, $originalName, $valid)
- {
- $file = $this
- ->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
- ->disableOriginalConstructor()
- ->getMock()
- ;
- $file
- ->expects($this->any())
- ->method('getBasename')
- ->will($this->returnValue($name))
- ;
- $file
- ->expects($this->any())
- ->method('getClientOriginalName')
- ->will($this->returnValue($originalName))
- ;
- $file
- ->expects($this->any())
- ->method('isValid')
- ->will($this->returnValue($valid))
- ;
-
- return $file;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\PropertyAccess\PropertyPath;
-use Symfony\Component\Form\Form;
-use Symfony\Component\Form\CallbackTransformer;
-use Symfony\Component\Form\Tests\Fixtures\Author;
-use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
-use Symfony\Component\Form\FormError;
-
-class FormTest_AuthorWithoutRefSetter
-{
- protected $reference;
-
- protected $referenceCopy;
-
- public function __construct($reference)
- {
- $this->reference = $reference;
- $this->referenceCopy = $reference;
- }
-
- // The returned object should be modified by reference without having
- // to provide a setReference() method
- public function getReference()
- {
- return $this->reference;
- }
-
- // The returned object is a copy, so setReferenceCopy() must be used
- // to update it
- public function getReferenceCopy()
- {
- return is_object($this->referenceCopy) ? clone $this->referenceCopy : $this->referenceCopy;
- }
-
- public function setReferenceCopy($reference)
- {
- $this->referenceCopy = $reference;
- }
-}
-
-class FormTypeTest extends BaseTypeTest
-{
- public function testCreateFormInstances()
- {
- $this->assertInstanceOf('Symfony\Component\Form\Form', $this->factory->create('form'));
- }
-
- public function testPassRequiredAsOption()
- {
- $form = $this->factory->create('form', null, array('required' => false));
-
- $this->assertFalse($form->isRequired());
-
- $form = $this->factory->create('form', null, array('required' => true));
-
- $this->assertTrue($form->isRequired());
- }
-
- public function testSubmittedDataIsTrimmedBeforeTransforming()
- {
- $form = $this->factory->createBuilder('form')
- ->addViewTransformer(new FixedDataTransformer(array(
- null => '',
- 'reverse[a]' => 'a',
- )))
- ->setCompound(false)
- ->getForm();
-
- $form->submit(' a ');
-
- $this->assertEquals('a', $form->getViewData());
- $this->assertEquals('reverse[a]', $form->getData());
- }
-
- public function testSubmittedDataIsNotTrimmedBeforeTransformingIfNoTrimming()
- {
- $form = $this->factory->createBuilder('form', null, array('trim' => false))
- ->addViewTransformer(new FixedDataTransformer(array(
- null => '',
- 'reverse[ a ]' => ' a ',
- )))
- ->setCompound(false)
- ->getForm();
-
- $form->submit(' a ');
-
- $this->assertEquals(' a ', $form->getViewData());
- $this->assertEquals('reverse[ a ]', $form->getData());
- }
-
- public function testNonReadOnlyFormWithReadOnlyParentIsReadOnly()
- {
- $view = $this->factory->createNamedBuilder('parent', 'form', null, array('read_only' => true))
- ->add('child', 'form')
- ->getForm()
- ->createView();
-
- $this->assertTrue($view['child']->vars['read_only']);
- }
-
- public function testReadOnlyFormWithNonReadOnlyParentIsReadOnly()
- {
- $view = $this->factory->createNamedBuilder('parent', 'form')
- ->add('child', 'form', array('read_only' => true))
- ->getForm()
- ->createView();
-
- $this->assertTrue($view['child']->vars['read_only']);
- }
-
- public function testNonReadOnlyFormWithNonReadOnlyParentIsNotReadOnly()
- {
- $view = $this->factory->createNamedBuilder('parent', 'form')
- ->add('child', 'form')
- ->getForm()
- ->createView();
-
- $this->assertFalse($view['child']->vars['read_only']);
- }
-
- public function testPassMaxLengthToView()
- {
- $form = $this->factory->create('form', null, array('max_length' => 10));
- $view = $form->createView();
-
- $this->assertSame(10, $view->vars['max_length']);
- }
-
- public function testSubmitWithEmptyDataCreatesObjectIfClassAvailable()
- {
- $builder = $this->factory->createBuilder('form', null, array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'required' => false,
- ));
- $builder->add('firstName', 'text');
- $builder->add('lastName', 'text');
- $form = $builder->getForm();
-
- $form->setData(null);
- // partially empty, still an object is created
- $form->submit(array('firstName' => 'Bernhard', 'lastName' => ''));
-
- $author = new Author();
- $author->firstName = 'Bernhard';
- $author->setLastName('');
-
- $this->assertEquals($author, $form->getData());
- }
-
- public function testSubmitWithEmptyDataCreatesObjectIfInitiallySubmittedWithObject()
- {
- $builder = $this->factory->createBuilder('form', null, array(
- // data class is inferred from the passed object
- 'data' => new Author(),
- 'required' => false,
- ));
- $builder->add('firstName', 'text');
- $builder->add('lastName', 'text');
- $form = $builder->getForm();
-
- $form->setData(null);
- // partially empty, still an object is created
- $form->submit(array('firstName' => 'Bernhard', 'lastName' => ''));
-
- $author = new Author();
- $author->firstName = 'Bernhard';
- $author->setLastName('');
-
- $this->assertEquals($author, $form->getData());
- }
-
- public function testSubmitWithEmptyDataCreatesArrayIfDataClassIsNull()
- {
- $builder = $this->factory->createBuilder('form', null, array(
- 'data_class' => null,
- 'required' => false,
- ));
- $builder->add('firstName', 'text');
- $form = $builder->getForm();
-
- $form->setData(null);
- $form->submit(array('firstName' => 'Bernhard'));
-
- $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
- }
-
- public function testSubmitEmptyWithEmptyDataCreatesNoObjectIfNotRequired()
- {
- $builder = $this->factory->createBuilder('form', null, array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'required' => false,
- ));
- $builder->add('firstName', 'text');
- $builder->add('lastName', 'text');
- $form = $builder->getForm();
-
- $form->setData(null);
- $form->submit(array('firstName' => '', 'lastName' => ''));
-
- $this->assertNull($form->getData());
- }
-
- public function testSubmitEmptyWithEmptyDataCreatesObjectIfRequired()
- {
- $builder = $this->factory->createBuilder('form', null, array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'required' => true,
- ));
- $builder->add('firstName', 'text');
- $builder->add('lastName', 'text');
- $form = $builder->getForm();
-
- $form->setData(null);
- $form->submit(array('firstName' => '', 'lastName' => ''));
-
- $this->assertEquals(new Author(), $form->getData());
- }
-
- /*
- * We need something to write the field values into
- */
- public function testSubmitWithEmptyDataStoresArrayIfNoClassAvailable()
- {
- $form = $this->factory->createBuilder('form')
- ->add('firstName', 'text')
- ->getForm();
-
- $form->setData(null);
- $form->submit(array('firstName' => 'Bernhard'));
-
- $this->assertSame(array('firstName' => 'Bernhard'), $form->getData());
- }
-
- public function testSubmitWithEmptyDataPassesEmptyStringToTransformerIfNotCompound()
- {
- $form = $this->factory->createBuilder('form')
- ->addViewTransformer(new FixedDataTransformer(array(
- // required for the initial, internal setData(null)
- null => 'null',
- // required to test that submit(null) is converted to ''
- 'empty' => '',
- )))
- ->setCompound(false)
- ->getForm();
-
- $form->submit(null);
-
- $this->assertSame('empty', $form->getData());
- }
-
- public function testSubmitWithEmptyDataUsesEmptyDataOption()
- {
- $author = new Author();
-
- $builder = $this->factory->createBuilder('form', null, array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'empty_data' => $author,
- ));
- $builder->add('firstName', 'text');
- $form = $builder->getForm();
-
- $form->submit(array('firstName' => 'Bernhard'));
-
- $this->assertSame($author, $form->getData());
- $this->assertEquals('Bernhard', $author->firstName);
- }
-
- public function provideZeros()
- {
- return array(
- array(0, '0'),
- array('0', '0'),
- array('00000', '00000'),
- );
- }
-
- /**
- * @dataProvider provideZeros
- * @see https://github.com/symfony/symfony/issues/1986
- */
- public function testSetDataThroughParamsWithZero($data, $dataAsString)
- {
- $form = $this->factory->create('form', null, array(
- 'data' => $data,
- 'compound' => false,
- ));
- $view = $form->createView();
-
- $this->assertFalse($form->isEmpty());
-
- $this->assertSame($dataAsString, $view->vars['value']);
- $this->assertSame($dataAsString, $form->getData());
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testAttributesException()
- {
- $this->factory->create('form', null, array('attr' => ''));
- }
-
- public function testNameCanBeEmptyString()
- {
- $form = $this->factory->createNamed('', 'form');
-
- $this->assertEquals('', $form->getName());
- }
-
- public function testSubformDoesntCallSetters()
- {
- $author = new FormTest_AuthorWithoutRefSetter(new Author());
-
- $builder = $this->factory->createBuilder('form', $author);
- $builder->add('reference', 'form', array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- ));
- $builder->get('reference')->add('firstName', 'text');
- $form = $builder->getForm();
-
- $form->submit(array(
- // reference has a getter, but not setter
- 'reference' => array(
- 'firstName' => 'Foo',
- )
- ));
-
- $this->assertEquals('Foo', $author->getReference()->firstName);
- }
-
- public function testSubformCallsSettersIfTheObjectChanged()
- {
- // no reference
- $author = new FormTest_AuthorWithoutRefSetter(null);
- $newReference = new Author();
-
- $builder = $this->factory->createBuilder('form', $author);
- $builder->add('referenceCopy', 'form', array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- ));
- $builder->get('referenceCopy')->add('firstName', 'text');
- $form = $builder->getForm();
-
- $form['referenceCopy']->setData($newReference); // new author object
-
- $form->submit(array(
- // referenceCopy has a getter that returns a copy
- 'referenceCopy' => array(
- 'firstName' => 'Foo',
- )
- ));
-
- $this->assertEquals('Foo', $author->getReferenceCopy()->firstName);
- }
-
- public function testSubformCallsSettersIfByReferenceIsFalse()
- {
- $author = new FormTest_AuthorWithoutRefSetter(new Author());
-
- $builder = $this->factory->createBuilder('form', $author);
- $builder->add('referenceCopy', 'form', array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- 'by_reference' => false
- ));
- $builder->get('referenceCopy')->add('firstName', 'text');
- $form = $builder->getForm();
-
- $form->submit(array(
- // referenceCopy has a getter that returns a copy
- 'referenceCopy' => array(
- 'firstName' => 'Foo',
- )
- ));
-
- // firstName can only be updated if setReferenceCopy() was called
- $this->assertEquals('Foo', $author->getReferenceCopy()->firstName);
- }
-
- public function testSubformCallsSettersIfReferenceIsScalar()
- {
- $author = new FormTest_AuthorWithoutRefSetter('scalar');
-
- $builder = $this->factory->createBuilder('form', $author);
- $builder->add('referenceCopy', 'form');
- $builder->get('referenceCopy')->addViewTransformer(new CallbackTransformer(
- function () {},
- function ($value) { // reverseTransform
-
- return 'foobar';
- }
- ));
- $form = $builder->getForm();
-
- $form->submit(array(
- 'referenceCopy' => array(), // doesn't matter actually
- ));
-
- // firstName can only be updated if setReferenceCopy() was called
- $this->assertEquals('foobar', $author->getReferenceCopy());
- }
-
- public function testSubformAlwaysInsertsIntoArrays()
- {
- $ref1 = new Author();
- $ref2 = new Author();
- $author = array('referenceCopy' => $ref1);
-
- $builder = $this->factory->createBuilder('form');
- $builder->setData($author);
- $builder->add('referenceCopy', 'form');
- $builder->get('referenceCopy')->addViewTransformer(new CallbackTransformer(
- function () {},
- function ($value) use ($ref2) { // reverseTransform
-
- return $ref2;
- }
- ));
- $form = $builder->getForm();
-
- $form->submit(array(
- 'referenceCopy' => array('a' => 'b'), // doesn't matter actually
- ));
-
- // the new reference was inserted into the array
- $author = $form->getData();
- $this->assertSame($ref2, $author['referenceCopy']);
- }
-
- public function testPassMultipartTrueIfAnyChildIsMultipartToView()
- {
- $view = $this->factory->createBuilder('form')
- ->add('foo', 'text')
- ->add('bar', 'file')
- ->getForm()
- ->createView();
-
- $this->assertTrue($view->vars['multipart']);
- }
-
- public function testViewIsNotRenderedByDefault()
- {
- $view = $this->factory->createBuilder('form')
- ->add('foo', 'form')
- ->getForm()
- ->createView();
-
- $this->assertFalse($view->isRendered());
- }
-
- public function testErrorBubblingIfCompound()
- {
- $form = $this->factory->create('form', null, array(
- 'compound' => true,
- ));
-
- $this->assertTrue($form->getConfig()->getErrorBubbling());
- }
-
- public function testNoErrorBubblingIfNotCompound()
- {
- $form = $this->factory->create('form', null, array(
- 'compound' => false,
- ));
-
- $this->assertFalse($form->getConfig()->getErrorBubbling());
- }
-
- public function testOverrideErrorBubbling()
- {
- $form = $this->factory->create('form', null, array(
- 'compound' => false,
- 'error_bubbling' => true,
- ));
-
- $this->assertTrue($form->getConfig()->getErrorBubbling());
- }
-
- public function testPropertyPath()
- {
- $form = $this->factory->create('form', null, array(
- 'property_path' => 'foo',
- ));
-
- $this->assertEquals(new PropertyPath('foo'), $form->getPropertyPath());
- $this->assertTrue($form->getConfig()->getMapped());
- }
-
- public function testPropertyPathNullImpliesDefault()
- {
- $form = $this->factory->createNamed('name', 'form', null, array(
- 'property_path' => null,
- ));
-
- $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath());
- $this->assertTrue($form->getConfig()->getMapped());
- }
-
- public function testNotMapped()
- {
- $form = $this->factory->create('form', null, array(
- 'property_path' => 'foo',
- 'mapped' => false,
- ));
-
- $this->assertEquals(new PropertyPath('foo'), $form->getPropertyPath());
- $this->assertFalse($form->getConfig()->getMapped());
- }
-
- public function testViewValidNotSubmitted()
- {
- $form = $this->factory->create('form');
- $view = $form->createView();
- $this->assertTrue($view->vars['valid']);
- }
-
- public function testViewNotValidSubmitted()
- {
- $form = $this->factory->create('form');
- $form->submit(array());
- $form->addError(new FormError('An error'));
- $view = $form->createView();
- $this->assertFalse($view->vars['valid']);
- }
-
- public function testDataOptionSupersedesSetDataCalls()
- {
- $form = $this->factory->create('form', null, array(
- 'data' => 'default',
- 'compound' => false,
- ));
-
- $form->setData('foobar');
-
- $this->assertSame('default', $form->getData());
- }
-
- public function testNormDataIsPassedToView()
- {
- $view = $this->factory->createBuilder('form')
- ->addViewTransformer(new FixedDataTransformer(array(
- 'foo' => 'bar',
- )))
- ->setData('foo')
- ->getForm()
- ->createView();
-
- $this->assertSame('foo', $view->vars['data']);
- $this->assertSame('bar', $view->vars['value']);
- }
-
- // https://github.com/symfony/symfony/issues/6862
- public function testPassZeroLabelToView()
- {
- $view = $this->factory->create('form', null, array(
- 'label' => '0'
- ))
- ->createView();
-
- $this->assertSame('0', $view->vars['label']);
- }
-
- protected function getTestedType()
- {
- return 'form';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class IntegerTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- public function testSubmitCastsToInteger()
- {
- $form = $this->factory->create('integer');
-
- $form->submit('1.678');
-
- $this->assertSame(1, $form->getData());
- $this->assertSame('1', $form->getViewData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class LanguageTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- public function testCountriesAreSelectable()
- {
- $form = $this->factory->create('language');
- $view = $form->createView();
- $choices = $view->vars['choices'];
-
- $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('en_GB', 'en_GB', 'British English'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('en_US', 'en_US', 'U.S. English'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('fr', 'fr', 'French'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('my', 'my', 'Burmese'), $choices, '', false, false);
- }
-
- public function testMultipleLanguagesIsNotIncluded()
- {
- $form = $this->factory->create('language', 'language');
- $view = $form->createView();
- $choices = $view->vars['choices'];
-
- $this->assertNotContains(new ChoiceView('mul', 'mul', 'Mehrsprachig'), $choices, '', false, false);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class LocaleTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- public function testLocalesAreSelectable()
- {
- $form = $this->factory->create('locale');
- $view = $form->createView();
- $choices = $view->vars['choices'];
-
- $this->assertContains(new ChoiceView('en', 'en', 'English'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('en_GB', 'en_GB', 'English (United Kingdom)'), $choices, '', false, false);
- $this->assertContains(new ChoiceView('zh_Hant_MO', 'zh_Hant_MO', 'Chinese (Traditional, Macau SAR China)'), $choices, '', false, false);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class MoneyTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- // we test against different locales, so we need the full
- // implementation
- IntlTestHelper::requireFullIntl($this);
-
- parent::setUp();
- }
-
- public function testPassMoneyPatternToView()
- {
- \Locale::setDefault('de_DE');
-
- $form = $this->factory->create('money');
- $view = $form->createView();
-
- $this->assertSame('{{ widget }} €', $view->vars['money_pattern']);
- }
-
- public function testMoneyPatternWorksForYen()
- {
- \Locale::setDefault('en_US');
-
- $form = $this->factory->create('money', null, array('currency' => 'JPY'));
- $view = $form->createView();
- $this->assertTrue((Boolean) strstr($view->vars['money_pattern'], '¥'));
- }
-
- // https://github.com/symfony/symfony/issues/5458
- public function testPassDifferentPatternsForDifferentCurrencies()
- {
- \Locale::setDefault('de_DE');
-
- $form1 = $this->factory->create('money', null, array('currency' => 'GBP'));
- $form2 = $this->factory->create('money', null, array('currency' => 'EUR'));
- $view1 = $form1->createView();
- $view2 = $form2->createView();
-
- $this->assertSame('{{ widget }} £', $view1->vars['money_pattern']);
- $this->assertSame('{{ widget }} €', $view2->vars['money_pattern']);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class NumberTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- // we test against "de_DE", so we need the full implementation
- IntlTestHelper::requireFullIntl($this);
-
- \Locale::setDefault('de_DE');
- }
-
- public function testDefaultFormatting()
- {
- $form = $this->factory->create('number');
- $form->setData('12345.67890');
- $view = $form->createView();
-
- $this->assertSame('12345,679', $view->vars['value']);
- }
-
- public function testDefaultFormattingWithGrouping()
- {
- $form = $this->factory->create('number', null, array('grouping' => true));
- $form->setData('12345.67890');
- $view = $form->createView();
-
- $this->assertSame('12.345,679', $view->vars['value']);
- }
-
- public function testDefaultFormattingWithPrecision()
- {
- $form = $this->factory->create('number', null, array('precision' => 2));
- $form->setData('12345.67890');
- $view = $form->createView();
-
- $this->assertSame('12345,68', $view->vars['value']);
- }
-
- public function testDefaultFormattingWithRounding()
- {
- $form = $this->factory->create('number', null, array('precision' => 0, 'rounding_mode' => \NumberFormatter::ROUND_UP));
- $form->setData('12345.54321');
- $view = $form->createView();
-
- $this->assertSame('12346', $view->vars['value']);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-class PasswordTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- public function testEmptyIfNotSubmitted()
- {
- $form = $this->factory->create('password');
- $form->setData('pAs5w0rd');
- $view = $form->createView();
-
- $this->assertSame('', $view->vars['value']);
- }
-
- public function testEmptyIfSubmitted()
- {
- $form = $this->factory->create('password');
- $form->submit('pAs5w0rd');
- $view = $form->createView();
-
- $this->assertSame('', $view->vars['value']);
- }
-
- public function testNotEmptyIfSubmittedAndNotAlwaysEmpty()
- {
- $form = $this->factory->create('password', null, array('always_empty' => false));
- $form->submit('pAs5w0rd');
- $view = $form->createView();
-
- $this->assertSame('pAs5w0rd', $view->vars['value']);
- }
-
- public function testNotTrimmed()
- {
- $form = $this->factory->create('password', null);
- $form->submit(' pAs5w0rd ');
- $data = $form->getData();
-
- $this->assertSame(' pAs5w0rd ', $data);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-class RepeatedTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- protected $form;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->form = $this->factory->create('repeated', null, array(
- 'type' => 'text',
- ));
- $this->form->setData(null);
- }
-
- public function testSetData()
- {
- $this->form->setData('foobar');
-
- $this->assertEquals('foobar', $this->form['first']->getData());
- $this->assertEquals('foobar', $this->form['second']->getData());
- }
-
- public function testSetOptions()
- {
- $form = $this->factory->create('repeated', null, array(
- 'type' => 'text',
- 'options' => array('label' => 'Global'),
- ));
-
- $this->assertEquals('Global', $form['first']->getConfig()->getOption('label'));
- $this->assertEquals('Global', $form['second']->getConfig()->getOption('label'));
- $this->assertTrue($form['first']->isRequired());
- $this->assertTrue($form['second']->isRequired());
- }
-
- public function testSetOptionsPerChild()
- {
- $form = $this->factory->create('repeated', null, array(
- // the global required value cannot be overridden
- 'type' => 'text',
- 'first_options' => array('label' => 'Test', 'required' => false),
- 'second_options' => array('label' => 'Test2')
- ));
-
- $this->assertEquals('Test', $form['first']->getConfig()->getOption('label'));
- $this->assertEquals('Test2', $form['second']->getConfig()->getOption('label'));
- $this->assertTrue($form['first']->isRequired());
- $this->assertTrue($form['second']->isRequired());
- }
-
- public function testSetRequired()
- {
- $form = $this->factory->create('repeated', null, array(
- 'required' => false,
- 'type' => 'text',
- ));
-
- $this->assertFalse($form['first']->isRequired());
- $this->assertFalse($form['second']->isRequired());
- }
-
- public function testSetErrorBubblingToTrue()
- {
- $form = $this->factory->create('repeated', null, array(
- 'error_bubbling' => true,
- ));
-
- $this->assertTrue($form->getConfig()->getOption('error_bubbling'));
- $this->assertTrue($form['first']->getConfig()->getOption('error_bubbling'));
- $this->assertTrue($form['second']->getConfig()->getOption('error_bubbling'));
- }
-
- public function testSetErrorBubblingToFalse()
- {
- $form = $this->factory->create('repeated', null, array(
- 'error_bubbling' => false,
- ));
-
- $this->assertFalse($form->getConfig()->getOption('error_bubbling'));
- $this->assertFalse($form['first']->getConfig()->getOption('error_bubbling'));
- $this->assertFalse($form['second']->getConfig()->getOption('error_bubbling'));
- }
-
- public function testSetErrorBubblingIndividually()
- {
- $form = $this->factory->create('repeated', null, array(
- 'error_bubbling' => true,
- 'options' => array('error_bubbling' => false),
- 'second_options' => array('error_bubbling' => true),
- ));
-
- $this->assertTrue($form->getConfig()->getOption('error_bubbling'));
- $this->assertFalse($form['first']->getConfig()->getOption('error_bubbling'));
- $this->assertTrue($form['second']->getConfig()->getOption('error_bubbling'));
- }
-
- public function testSetOptionsPerChildAndOverwrite()
- {
- $form = $this->factory->create('repeated', null, array(
- 'type' => 'text',
- 'options' => array('label' => 'Label'),
- 'second_options' => array('label' => 'Second label')
- ));
-
- $this->assertEquals('Label', $form['first']->getConfig()->getOption('label'));
- $this->assertEquals('Second label', $form['second']->getConfig()->getOption('label'));
- $this->assertTrue($form['first']->isRequired());
- $this->assertTrue($form['second']->isRequired());
- }
-
- public function testSubmitUnequal()
- {
- $input = array('first' => 'foo', 'second' => 'bar');
-
- $this->form->submit($input);
-
- $this->assertEquals('foo', $this->form['first']->getViewData());
- $this->assertEquals('bar', $this->form['second']->getViewData());
- $this->assertFalse($this->form->isSynchronized());
- $this->assertEquals($input, $this->form->getViewData());
- $this->assertNull($this->form->getData());
- }
-
- public function testSubmitEqual()
- {
- $input = array('first' => 'foo', 'second' => 'foo');
-
- $this->form->submit($input);
-
- $this->assertEquals('foo', $this->form['first']->getViewData());
- $this->assertEquals('foo', $this->form['second']->getViewData());
- $this->assertTrue($this->form->isSynchronized());
- $this->assertEquals($input, $this->form->getViewData());
- $this->assertEquals('foo', $this->form->getData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SubmitTypeTest extends TypeTestCase
-{
- public function testCreateSubmitButtonInstances()
- {
- $this->assertInstanceOf('Symfony\Component\Form\SubmitButton', $this->factory->create('submit'));
- }
-
- public function testNotClickedByDefault()
- {
- $button = $this->factory->create('submit');
-
- $this->assertFalse($button->isClicked());
- }
-
- public function testNotClickedIfSubmittedWithNull()
- {
- $button = $this->factory->create('submit');
- $button->submit(null);
-
- $this->assertFalse($button->isClicked());
- }
-
- public function testClickedIfSubmittedWithEmptyString()
- {
- $button = $this->factory->create('submit');
- $button->submit('');
-
- $this->assertTrue($button->isClicked());
- }
-
- public function testClickedIfSubmittedWithUnemptyString()
- {
- $button = $this->factory->create('submit');
- $button->submit('foo');
-
- $this->assertTrue($button->isClicked());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-class TimeTypeTest extends TypeTestCase
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- public function testSubmitDateTime()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'datetime',
- ));
-
- $input = array(
- 'hour' => '3',
- 'minute' => '4',
- );
-
- $form->submit($input);
-
- $dateTime = new \DateTime('1970-01-01 03:04:00 UTC');
-
- $this->assertEquals($dateTime, $form->getData());
- $this->assertEquals($input, $form->getViewData());
- }
-
- public function testSubmitString()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'string',
- ));
-
- $input = array(
- 'hour' => '3',
- 'minute' => '4',
- );
-
- $form->submit($input);
-
- $this->assertEquals('03:04:00', $form->getData());
- $this->assertEquals($input, $form->getViewData());
- }
-
- public function testSubmitTimestamp()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'timestamp',
- ));
-
- $input = array(
- 'hour' => '3',
- 'minute' => '4',
- );
-
- $form->submit($input);
-
- $dateTime = new \DateTime('1970-01-01 03:04:00 UTC');
-
- $this->assertEquals($dateTime->format('U'), $form->getData());
- $this->assertEquals($input, $form->getViewData());
- }
-
- public function testSubmitArray()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'array',
- ));
-
- $input = array(
- 'hour' => '3',
- 'minute' => '4',
- );
-
- $form->submit($input);
-
- $this->assertEquals($input, $form->getData());
- $this->assertEquals($input, $form->getViewData());
- }
-
- public function testSubmitDatetimeSingleText()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'datetime',
- 'widget' => 'single_text',
- ));
-
- $form->submit('03:04');
-
- $this->assertEquals(new \DateTime('1970-01-01 03:04:00 UTC'), $form->getData());
- $this->assertEquals('03:04', $form->getViewData());
- }
-
- public function testSubmitDatetimeSingleTextWithoutMinutes()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'datetime',
- 'widget' => 'single_text',
- 'with_minutes' => false,
- ));
-
- $form->submit('03');
-
- $this->assertEquals(new \DateTime('1970-01-01 03:00:00 UTC'), $form->getData());
- $this->assertEquals('03', $form->getViewData());
- }
-
- public function testSubmitArraySingleText()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'array',
- 'widget' => 'single_text',
- ));
-
- $data = array(
- 'hour' => '3',
- 'minute' => '4',
- );
-
- $form->submit('03:04');
-
- $this->assertEquals($data, $form->getData());
- $this->assertEquals('03:04', $form->getViewData());
- }
-
- public function testSubmitArraySingleTextWithoutMinutes()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'array',
- 'widget' => 'single_text',
- 'with_minutes' => false,
- ));
-
- $data = array(
- 'hour' => '3',
- );
-
- $form->submit('03');
-
- $this->assertEquals($data, $form->getData());
- $this->assertEquals('03', $form->getViewData());
- }
-
- public function testSubmitArraySingleTextWithSeconds()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'array',
- 'widget' => 'single_text',
- 'with_seconds' => true,
- ));
-
- $data = array(
- 'hour' => '3',
- 'minute' => '4',
- 'second' => '5',
- );
-
- $form->submit('03:04:05');
-
- $this->assertEquals($data, $form->getData());
- $this->assertEquals('03:04:05', $form->getViewData());
- }
-
- public function testSubmitStringSingleText()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'string',
- 'widget' => 'single_text',
- ));
-
- $form->submit('03:04');
-
- $this->assertEquals('03:04:00', $form->getData());
- $this->assertEquals('03:04', $form->getViewData());
- }
-
- public function testSubmitStringSingleTextWithoutMinutes()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'string',
- 'widget' => 'single_text',
- 'with_minutes' => false,
- ));
-
- $form->submit('03');
-
- $this->assertEquals('03:00:00', $form->getData());
- $this->assertEquals('03', $form->getViewData());
- }
-
- public function testSetDataWithoutMinutes()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'datetime',
- 'with_minutes' => false,
- ));
-
- $form->setData(new \DateTime('03:04:05 UTC'));
-
- $this->assertEquals(array('hour' => 3), $form->getViewData());
- }
-
- public function testSetDataWithSeconds()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'UTC',
- 'view_timezone' => 'UTC',
- 'input' => 'datetime',
- 'with_seconds' => true,
- ));
-
- $form->setData(new \DateTime('03:04:05 UTC'));
-
- $this->assertEquals(array('hour' => 3, 'minute' => 4, 'second' => 5), $form->getViewData());
- }
-
- public function testSetDataDifferentTimezones()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'America/New_York',
- 'view_timezone' => 'Asia/Hong_Kong',
- 'input' => 'string',
- 'with_seconds' => true,
- ));
-
- $dateTime = new \DateTime('2013-01-01 12:04:05');
- $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
-
- $form->setData($dateTime->format('H:i:s'));
-
- $outputTime = clone $dateTime;
- $outputTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
-
- $displayedData = array(
- 'hour' => (int) $outputTime->format('H'),
- 'minute' => (int) $outputTime->format('i'),
- 'second' => (int) $outputTime->format('s')
- );
-
- $this->assertEquals($displayedData, $form->getViewData());
- }
-
- public function testSetDataDifferentTimezonesDateTime()
- {
- $form = $this->factory->create('time', null, array(
- 'model_timezone' => 'America/New_York',
- 'view_timezone' => 'Asia/Hong_Kong',
- 'input' => 'datetime',
- 'with_seconds' => true,
- ));
-
- $dateTime = new \DateTime('12:04:05');
- $dateTime->setTimezone(new \DateTimeZone('America/New_York'));
-
- $form->setData($dateTime);
-
- $outputTime = clone $dateTime;
- $outputTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
-
- $displayedData = array(
- 'hour' => (int) $outputTime->format('H'),
- 'minute' => (int) $outputTime->format('i'),
- 'second' => (int) $outputTime->format('s')
- );
-
- $this->assertDateTimeEquals($dateTime, $form->getData());
- $this->assertEquals($displayedData, $form->getViewData());
- }
-
- public function testHoursOption()
- {
- $form = $this->factory->create('time', null, array(
- 'hours' => array(6, 7),
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('6', '6', '06'),
- new ChoiceView('7', '7', '07'),
- ), $view['hour']->vars['choices']);
- }
-
- public function testIsMinuteWithinRangeReturnsTrueIfWithin()
- {
- $form = $this->factory->create('time', null, array(
- 'minutes' => array(6, 7),
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('6', '6', '06'),
- new ChoiceView('7', '7', '07'),
- ), $view['minute']->vars['choices']);
- }
-
- public function testIsSecondWithinRangeReturnsTrueIfWithin()
- {
- $form = $this->factory->create('time', null, array(
- 'seconds' => array(6, 7),
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
-
- $this->assertEquals(array(
- new ChoiceView('6', '6', '06'),
- new ChoiceView('7', '7', '07'),
- ), $view['second']->vars['choices']);
- }
-
- public function testIsPartiallyFilledReturnsFalseIfCompletelyEmpty()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('time', null, array(
- 'widget' => 'choice',
- ));
-
- $form->submit(array(
- 'hour' => '',
- 'minute' => '',
- ));
-
- $this->assertFalse($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsFalseIfCompletelyEmptyWithSeconds()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('time', null, array(
- 'widget' => 'choice',
- 'with_seconds' => true,
- ));
-
- $form->submit(array(
- 'hour' => '',
- 'minute' => '',
- 'second' => '',
- ));
-
- $this->assertFalse($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsFalseIfCompletelyFilled()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('time', null, array(
- 'widget' => 'choice',
- ));
-
- $form->submit(array(
- 'hour' => '0',
- 'minute' => '0',
- ));
-
- $this->assertFalse($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsFalseIfCompletelyFilledWithSeconds()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('time', null, array(
- 'widget' => 'choice',
- 'with_seconds' => true,
- ));
-
- $form->submit(array(
- 'hour' => '0',
- 'minute' => '0',
- 'second' => '0',
- ));
-
- $this->assertFalse($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsTrueIfChoiceAndHourEmpty()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('time', null, array(
- 'widget' => 'choice',
- 'with_seconds' => true,
- ));
-
- $form->submit(array(
- 'hour' => '',
- 'minute' => '0',
- 'second' => '0',
- ));
-
- $this->assertTrue($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsTrueIfChoiceAndMinuteEmpty()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('time', null, array(
- 'widget' => 'choice',
- 'with_seconds' => true,
- ));
-
- $form->submit(array(
- 'hour' => '0',
- 'minute' => '',
- 'second' => '0',
- ));
-
- $this->assertTrue($form->isPartiallyFilled());
- }
-
- public function testIsPartiallyFilledReturnsTrueIfChoiceAndSecondsEmpty()
- {
- $this->markTestIncomplete('Needs to be reimplemented using validators');
-
- $form = $this->factory->create('time', null, array(
- 'widget' => 'choice',
- 'with_seconds' => true,
- ));
-
- $form->submit(array(
- 'hour' => '0',
- 'minute' => '0',
- 'second' => '',
- ));
-
- $this->assertTrue($form->isPartiallyFilled());
- }
-
- // Bug fix
- public function testInitializeWithDateTime()
- {
- // Throws an exception if "data_class" option is not explicitly set
- // to null in the type
- $this->factory->create('time', new \DateTime());
- }
-
- public function testSingleTextWidgetShouldUseTheRightInputType()
- {
- $form = $this->factory->create('time', null, array(
- 'widget' => 'single_text',
- ));
-
- $view = $form->createView();
- $this->assertEquals('time', $view->vars['type']);
- }
-
- public function testPassDefaultEmptyValueToViewIfNotRequired()
- {
- $form = $this->factory->create('time', null, array(
- 'required' => false,
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('', $view['hour']->vars['empty_value']);
- $this->assertSame('', $view['minute']->vars['empty_value']);
- $this->assertSame('', $view['second']->vars['empty_value']);
- }
-
- public function testPassNoEmptyValueToViewIfRequired()
- {
- $form = $this->factory->create('time', null, array(
- 'required' => true,
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertNull($view['hour']->vars['empty_value']);
- $this->assertNull($view['minute']->vars['empty_value']);
- $this->assertNull($view['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsString()
- {
- $form = $this->factory->create('time', null, array(
- 'empty_value' => 'Empty',
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty', $view['hour']->vars['empty_value']);
- $this->assertSame('Empty', $view['minute']->vars['empty_value']);
- $this->assertSame('Empty', $view['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsArray()
- {
- $form = $this->factory->create('time', null, array(
- 'empty_value' => array(
- 'hour' => 'Empty hour',
- 'minute' => 'Empty minute',
- 'second' => 'Empty second',
- ),
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty hour', $view['hour']->vars['empty_value']);
- $this->assertSame('Empty minute', $view['minute']->vars['empty_value']);
- $this->assertSame('Empty second', $view['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsPartialArrayAddEmptyIfNotRequired()
- {
- $form = $this->factory->create('time', null, array(
- 'required' => false,
- 'empty_value' => array(
- 'hour' => 'Empty hour',
- 'second' => 'Empty second',
- ),
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty hour', $view['hour']->vars['empty_value']);
- $this->assertSame('', $view['minute']->vars['empty_value']);
- $this->assertSame('Empty second', $view['second']->vars['empty_value']);
- }
-
- public function testPassEmptyValueAsPartialArrayAddNullIfRequired()
- {
- $form = $this->factory->create('time', null, array(
- 'required' => true,
- 'empty_value' => array(
- 'hour' => 'Empty hour',
- 'second' => 'Empty second',
- ),
- 'with_seconds' => true,
- ));
-
- $view = $form->createView();
- $this->assertSame('Empty hour', $view['hour']->vars['empty_value']);
- $this->assertNull($view['minute']->vars['empty_value']);
- $this->assertSame('Empty second', $view['second']->vars['empty_value']);
- }
-
- public function provideCompoundWidgets()
- {
- return array(
- array('text'),
- array('choice'),
- );
- }
-
- /**
- * @dataProvider provideCompoundWidgets
- */
- public function testHourErrorsBubbleUp($widget)
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('time', null, array(
- 'widget' => $widget,
- ));
- $form['hour']->addError($error);
-
- $this->assertSame(array(), $form['hour']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- /**
- * @dataProvider provideCompoundWidgets
- */
- public function testMinuteErrorsBubbleUp($widget)
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('time', null, array(
- 'widget' => $widget,
- ));
- $form['minute']->addError($error);
-
- $this->assertSame(array(), $form['minute']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- /**
- * @dataProvider provideCompoundWidgets
- */
- public function testSecondErrorsBubbleUp($widget)
- {
- $error = new FormError('Invalid!');
- $form = $this->factory->create('time', null, array(
- 'widget' => $widget,
- 'with_seconds' => true,
- ));
- $form['second']->addError($error);
-
- $this->assertSame(array(), $form['second']->getErrors());
- $this->assertSame(array($error), $form->getErrors());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\InvalidConfigurationException
- */
- public function testInitializeWithSecondsAndWithoutMinutes()
- {
- $this->factory->create('time', null, array(
- 'with_minutes' => false,
- 'with_seconds' => true,
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-class TimezoneTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
-{
- public function testTimezonesAreSelectable()
- {
- $form = $this->factory->create('timezone');
- $view = $form->createView();
- $choices = $view->vars['choices'];
-
- $this->assertArrayHasKey('Africa', $choices);
- $this->assertContains(new ChoiceView('Africa/Kinshasa', 'Africa/Kinshasa', 'Kinshasa'), $choices['Africa'], '', false, false);
-
- $this->assertArrayHasKey('America', $choices);
- $this->assertContains(new ChoiceView('America/New_York', 'America/New_York', 'New York'), $choices['America'], '', false, false);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-use Symfony\Component\Form\Test\TypeTestCase as BaseTypeTestCase;
-
-/**
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use Symfony\Component\Form\Test\TypeTestCase instead.
- */
-abstract class TypeTestCase extends BaseTypeTestCase
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Core\Type;
-
-class UrlTypeTest extends TypeTestCase
-{
- public function testSubmitAddsDefaultProtocolIfNoneIsIncluded()
- {
- $form = $this->factory->create('url', 'name');
-
- $form->submit('www.domain.com');
-
- $this->assertSame('http://www.domain.com', $form->getData());
- $this->assertSame('http://www.domain.com', $form->getViewData());
- }
-
- public function testSubmitAddsNoDefaultProtocolIfAlreadyIncluded()
- {
- $form = $this->factory->create('url', null, array(
- 'default_protocol' => 'http',
- ));
-
- $form->submit('ftp://www.domain.com');
-
- $this->assertSame('ftp://www.domain.com', $form->getData());
- $this->assertSame('ftp://www.domain.com', $form->getViewData());
- }
-
- public function testSubmitAddsNoDefaultProtocolIfEmpty()
- {
- $form = $this->factory->create('url', null, array(
- 'default_protocol' => 'http',
- ));
-
- $form->submit('');
-
- $this->assertNull($form->getData());
- $this->assertSame('', $form->getViewData());
- }
-
- public function testSubmitAddsNoDefaultProtocolIfSetToNull()
- {
- $form = $this->factory->create('url', null, array(
- 'default_protocol' => null,
- ));
-
- $form->submit('www.domain.com');
-
- $this->assertSame('www.domain.com', $form->getData());
- $this->assertSame('www.domain.com', $form->getViewData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Csrf\CsrfProvider;
-
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider;
-
-/**
- * @runTestsInSeparateProcesses
- */
-class DefaultCsrfProviderTest extends \PHPUnit_Framework_TestCase
-{
- protected $provider;
-
- public static function setUpBeforeClass()
- {
- ini_set('session.save_handler', 'files');
- ini_set('session.save_path', sys_get_temp_dir());
- }
-
- protected function setUp()
- {
- $this->provider = new DefaultCsrfProvider('SECRET');
- }
-
- protected function tearDown()
- {
- $this->provider = null;
- }
-
- public function testGenerateCsrfToken()
- {
- session_start();
-
- $token = $this->provider->generateCsrfToken('foo');
-
- $this->assertEquals(sha1('SECRET'.'foo'.session_id()), $token);
- }
-
- public function testGenerateCsrfTokenOnUnstartedSession()
- {
- session_id('touti');
-
- if (!version_compare(PHP_VERSION, '5.4', '>=')) {
- $this->markTestSkipped('This test requires PHP >= 5.4');
- }
-
- $this->assertSame(PHP_SESSION_NONE, session_status());
-
- $token = $this->provider->generateCsrfToken('foo');
-
- $this->assertEquals(sha1('SECRET'.'foo'.session_id()), $token);
- $this->assertSame(PHP_SESSION_ACTIVE, session_status());
- }
-
- public function testIsCsrfTokenValidSucceeds()
- {
- session_start();
-
- $token = sha1('SECRET'.'foo'.session_id());
-
- $this->assertTrue($this->provider->isCsrfTokenValid('foo', $token));
- }
-
- public function testIsCsrfTokenValidFails()
- {
- session_start();
-
- $token = sha1('SECRET'.'bar'.session_id());
-
- $this->assertFalse($this->provider->isCsrfTokenValid('foo', $token));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Csrf\CsrfProvider;
-
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider;
-
-class SessionCsrfProviderTest extends \PHPUnit_Framework_TestCase
-{
- protected $provider;
- protected $session;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Session\Session')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $this->session = $this->getMock(
- 'Symfony\Component\HttpFoundation\Session\Session',
- array(),
- array(),
- '',
- false // don't call constructor
- );
- $this->provider = new SessionCsrfProvider($this->session, 'SECRET');
- }
-
- protected function tearDown()
- {
- $this->provider = null;
- $this->session = null;
- }
-
- public function testGenerateCsrfToken()
- {
- $this->session->expects($this->once())
- ->method('getId')
- ->will($this->returnValue('ABCDEF'));
-
- $token = $this->provider->generateCsrfToken('foo');
-
- $this->assertEquals(sha1('SECRET'.'foo'.'ABCDEF'), $token);
- }
-
- public function testIsCsrfTokenValidSucceeds()
- {
- $this->session->expects($this->once())
- ->method('getId')
- ->will($this->returnValue('ABCDEF'));
-
- $token = sha1('SECRET'.'foo'.'ABCDEF');
-
- $this->assertTrue($this->provider->isCsrfTokenValid('foo', $token));
- }
-
- public function testIsCsrfTokenValidFails()
- {
- $this->session->expects($this->once())
- ->method('getId')
- ->will($this->returnValue('ABCDEF'));
-
- $token = sha1('SECRET'.'bar'.'ABCDEF');
-
- $this->assertFalse($this->provider->isCsrfTokenValid('foo', $token));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener;
-
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
-
-class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase
-{
- protected $dispatcher;
- protected $factory;
- protected $csrfProvider;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
- $this->form = $this->getBuilder('post')
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- }
-
- protected function tearDown()
- {
- $this->dispatcher = null;
- $this->factory = null;
- $this->csrfProvider = null;
- $this->form = null;
- }
-
- protected function getBuilder($name = 'name')
- {
- return new FormBuilder($name, null, $this->dispatcher, $this->factory, array('compound' => true));
- }
-
- protected function getForm($name = 'name')
- {
- return $this->getBuilder($name)->getForm();
- }
-
- protected function getDataMapper()
- {
- return $this->getMock('Symfony\Component\Form\DataMapperInterface');
- }
-
- protected function getMockForm()
- {
- return $this->getMock('Symfony\Component\Form\Test\FormInterface');
- }
-
- // https://github.com/symfony/symfony/pull/5838
- public function testStringFormData()
- {
- $data = "XP4HUzmHPi";
- $event = new FormEvent($this->form, $data);
-
- $validation = new CsrfValidationListener('csrf', $this->csrfProvider, 'unknown', 'Invalid.');
- $validation->preSubmit($event);
-
- // Validate accordingly
- $this->assertSame($data, $event->getData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Csrf\Type;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Form\Test\TypeTestCase;
-use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
-
-class FormTypeCsrfExtensionTest_ChildType extends AbstractType
-{
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- // The form needs a child in order to trigger CSRF protection by
- // default
- $builder->add('name', 'text');
- }
-
- public function getName()
- {
- return 'csrf_collection_test';
- }
-}
-
-class FormTypeCsrfExtensionTest extends TypeTestCase
-{
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- protected $csrfProvider;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- protected $translator;
-
- protected function setUp()
- {
- $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
- $this->translator = $this->getMock('Symfony\Component\Translation\TranslatorInterface');
-
- parent::setUp();
- }
-
- protected function tearDown()
- {
- $this->csrfProvider = null;
- $this->translator = null;
-
- parent::tearDown();
- }
-
- protected function getExtensions()
- {
- return array_merge(parent::getExtensions(), array(
- new CsrfExtension($this->csrfProvider, $this->translator),
- ));
- }
-
- public function testCsrfProtectionByDefaultIfRootAndCompound()
- {
- $view = $this->factory
- ->create('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'compound' => true,
- ))
- ->createView();
-
- $this->assertTrue(isset($view['csrf']));
- }
-
- public function testNoCsrfProtectionByDefaultIfCompoundButNotRoot()
- {
- $view = $this->factory
- ->createNamedBuilder('root', 'form')
- ->add($this->factory
- ->createNamedBuilder('form', 'form', null, array(
- 'csrf_field_name' => 'csrf',
- 'compound' => true,
- ))
- )
- ->getForm()
- ->get('form')
- ->createView();
-
- $this->assertFalse(isset($view['csrf']));
- }
-
- public function testNoCsrfProtectionByDefaultIfRootButNotCompound()
- {
- $view = $this->factory
- ->create('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'compound' => false,
- ))
- ->createView();
-
- $this->assertFalse(isset($view['csrf']));
- }
-
- public function testCsrfProtectionCanBeDisabled()
- {
- $view = $this->factory
- ->create('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'csrf_protection' => false,
- 'compound' => true,
- ))
- ->createView();
-
- $this->assertFalse(isset($view['csrf']));
- }
-
- public function testGenerateCsrfToken()
- {
- $this->csrfProvider->expects($this->once())
- ->method('generateCsrfToken')
- ->with('%INTENTION%')
- ->will($this->returnValue('token'));
-
- $view = $this->factory
- ->create('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'csrf_provider' => $this->csrfProvider,
- 'intention' => '%INTENTION%',
- 'compound' => true,
- ))
- ->createView();
-
- $this->assertEquals('token', $view['csrf']->vars['value']);
- }
-
- public function provideBoolean()
- {
- return array(
- array(true),
- array(false),
- );
- }
-
- /**
- * @dataProvider provideBoolean
- */
- public function testValidateTokenOnSubmitIfRootAndCompound($valid)
- {
- $this->csrfProvider->expects($this->once())
- ->method('isCsrfTokenValid')
- ->with('%INTENTION%', 'token')
- ->will($this->returnValue($valid));
-
- $form = $this->factory
- ->createBuilder('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'csrf_provider' => $this->csrfProvider,
- 'intention' => '%INTENTION%',
- 'compound' => true,
- ))
- ->add('child', 'text')
- ->getForm();
-
- $form->submit(array(
- 'child' => 'foobar',
- 'csrf' => 'token',
- ));
-
- // Remove token from data
- $this->assertSame(array('child' => 'foobar'), $form->getData());
-
- // Validate accordingly
- $this->assertSame($valid, $form->isValid());
- }
-
- public function testFailIfRootAndCompoundAndTokenMissing()
- {
- $this->csrfProvider->expects($this->never())
- ->method('isCsrfTokenValid');
-
- $form = $this->factory
- ->createBuilder('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'csrf_provider' => $this->csrfProvider,
- 'intention' => '%INTENTION%',
- 'compound' => true,
- ))
- ->add('child', 'text')
- ->getForm();
-
- $form->submit(array(
- 'child' => 'foobar',
- // token is missing
- ));
-
- // Remove token from data
- $this->assertSame(array('child' => 'foobar'), $form->getData());
-
- // Validate accordingly
- $this->assertFalse($form->isValid());
- }
-
- public function testDontValidateTokenIfCompoundButNoRoot()
- {
- $this->csrfProvider->expects($this->never())
- ->method('isCsrfTokenValid');
-
- $form = $this->factory
- ->createNamedBuilder('root', 'form')
- ->add($this->factory
- ->createNamedBuilder('form', 'form', null, array(
- 'csrf_field_name' => 'csrf',
- 'csrf_provider' => $this->csrfProvider,
- 'intention' => '%INTENTION%',
- 'compound' => true,
- ))
- )
- ->getForm()
- ->get('form');
-
- $form->submit(array(
- 'child' => 'foobar',
- 'csrf' => 'token',
- ));
- }
-
- public function testDontValidateTokenIfRootButNotCompound()
- {
- $this->csrfProvider->expects($this->never())
- ->method('isCsrfTokenValid');
-
- $form = $this->factory
- ->create('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'csrf_provider' => $this->csrfProvider,
- 'intention' => '%INTENTION%',
- 'compound' => false,
- ));
-
- $form->submit(array(
- 'csrf' => 'token',
- ));
- }
-
- public function testNoCsrfProtectionOnPrototype()
- {
- $prototypeView = $this->factory
- ->create('collection', null, array(
- 'type' => new FormTypeCsrfExtensionTest_ChildType(),
- 'options' => array(
- 'csrf_field_name' => 'csrf',
- ),
- 'prototype' => true,
- 'allow_add' => true,
- ))
- ->createView()
- ->vars['prototype'];
-
- $this->assertFalse(isset($prototypeView['csrf']));
- $this->assertCount(1, $prototypeView);
- }
-
- public function testsTranslateCustomErrorMessage()
- {
- $this->csrfProvider->expects($this->once())
- ->method('isCsrfTokenValid')
- ->with('%INTENTION%', 'token')
- ->will($this->returnValue(false));
-
- $this->translator->expects($this->once())
- ->method('trans')
- ->with('Foobar')
- ->will($this->returnValue('[trans]Foobar[/trans]'));
-
- $form = $this->factory
- ->createBuilder('form', null, array(
- 'csrf_field_name' => 'csrf',
- 'csrf_provider' => $this->csrfProvider,
- 'csrf_message' => 'Foobar',
- 'intention' => '%INTENTION%',
- 'compound' => true,
- ))
- ->getForm();
-
- $form->submit(array(
- 'csrf' => 'token',
- ));
-
- $errors = $form->getErrors();
-
- $this->assertGreaterThan(0, count($errors));
- $this->assertEquals(new FormError('[trans]Foobar[/trans]'), $errors[0]);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\HttpFoundation\EventListener;
-
-use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
-use Symfony\Component\Form\Form;
-use Symfony\Component\Form\FormConfigBuilder;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Test\DeprecationErrorHandler;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\File\UploadedFile;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
-{
- private $values;
-
- private $filesPlain;
-
- private $filesNested;
-
- /**
- * @var UploadedFile
- */
- private $uploadedFile;
-
- protected function setUp()
- {
- $path = tempnam(sys_get_temp_dir(), 'sf2');
- touch($path);
-
- $this->values = array(
- 'name' => 'Bernhard',
- 'image' => array('filename' => 'foobar.png'),
- );
-
- $this->filesPlain = array(
- 'image' => array(
- 'error' => UPLOAD_ERR_OK,
- 'name' => 'upload.png',
- 'size' => 123,
- 'tmp_name' => $path,
- 'type' => 'image/png'
- ),
- );
-
- $this->filesNested = array(
- 'error' => array('image' => UPLOAD_ERR_OK),
- 'name' => array('image' => 'upload.png'),
- 'size' => array('image' => 123),
- 'tmp_name' => array('image' => $path),
- 'type' => array('image' => 'image/png'),
- );
-
- $this->uploadedFile = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
- }
-
- protected function tearDown()
- {
- unlink($this->uploadedFile->getRealPath());
- }
-
- public function requestMethodProvider()
- {
- return array(
- array('POST'),
- array('PUT'),
- array('DELETE'),
- array('PATCH'),
- );
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitRequest($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $values = array('author' => $this->values);
- $files = array('author' => $this->filesNested);
- $request = new Request(array(), $values, array(), array(), $files, array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('author', null, $dispatcher);
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- $this->assertEquals(array(
- 'name' => 'Bernhard',
- 'image' => $this->uploadedFile,
- ), $event->getData());
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitRequestWithEmptyName($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $request = new Request(array(), $this->values, array(), array(), $this->filesPlain, array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('', null, $dispatcher);
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- $this->assertEquals(array(
- 'name' => 'Bernhard',
- 'image' => $this->uploadedFile,
- ), $event->getData());
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitEmptyRequestToCompoundForm($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $request = new Request(array(), array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('author', null, $dispatcher);
- $config->setCompound(true);
- $config->setDataMapper($this->getMock('Symfony\Component\Form\DataMapperInterface'));
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- // Default to empty array
- $this->assertEquals(array(), $event->getData());
- }
-
- /**
- * @dataProvider requestMethodProvider
- */
- public function testSubmitEmptyRequestToSimpleForm($method)
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $request = new Request(array(), array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => $method,
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('author', null, $dispatcher);
- $config->setCompound(false);
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- // Default to null
- $this->assertNull($event->getData());
- }
-
- public function testSubmitGetRequest()
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $values = array('author' => $this->values);
- $request = new Request($values, array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => 'GET',
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('author', null, $dispatcher);
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- $this->assertEquals(array(
- 'name' => 'Bernhard',
- 'image' => array('filename' => 'foobar.png'),
- ), $event->getData());
- }
-
- public function testSubmitGetRequestWithEmptyName()
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $request = new Request($this->values, array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => 'GET',
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('', null, $dispatcher);
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- $this->assertEquals(array(
- 'name' => 'Bernhard',
- 'image' => array('filename' => 'foobar.png'),
- ), $event->getData());
- }
-
- public function testSubmitEmptyGetRequestToCompoundForm()
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $request = new Request(array(), array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => 'GET',
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('author', null, $dispatcher);
- $config->setCompound(true);
- $config->setDataMapper($this->getMock('Symfony\Component\Form\DataMapperInterface'));
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- $this->assertEquals(array(), $event->getData());
- }
-
- public function testSubmitEmptyGetRequestToSimpleForm()
- {
- if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
- $this->markTestSkipped('The "HttpFoundation" component is not available');
- }
-
- $request = new Request(array(), array(), array(), array(), array(), array(
- 'REQUEST_METHOD' => 'GET',
- ));
-
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $config = new FormConfigBuilder('author', null, $dispatcher);
- $config->setCompound(false);
- $form = new Form($config);
- $event = new FormEvent($form, $request);
-
- $listener = new BindRequestListener();
- DeprecationErrorHandler::preBind($listener, $event);
-
- $this->assertNull($event->getData());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\HttpFoundation;
-
-use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
-use Symfony\Component\Form\Tests\AbstractRequestHandlerTest;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class HttpFoundationRequestHandlerTest extends AbstractRequestHandlerTest
-{
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testRequestShouldNotBeNull()
- {
- $this->requestHandler->handleRequest($this->getMockForm('name', 'GET'));
- }
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testRequestShouldBeInstanceOfRequest()
- {
- $this->requestHandler->handleRequest($this->getMockForm('name', 'GET'), new \stdClass());
- }
-
- protected function setRequestData($method, $data, $files = array())
- {
- $this->request = Request::create('http://localhost', $method, $data, array(), $files);
- }
-
- protected function getRequestHandler()
- {
- return new HttpFoundationRequestHandler();
- }
-
- protected function getMockFile()
- {
- return $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
- ->disableOriginalConstructor()
- ->getMock();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Validator\Constraints;
-
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\CallbackTransformer;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Extension\Validator\Constraints\Form;
-use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
-use Symfony\Component\Form\SubmitButtonBuilder;
-use Symfony\Component\Validator\Constraint;
-use Symfony\Component\Validator\Constraints\NotNull;
-use Symfony\Component\Validator\Constraints\NotBlank;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormValidatorTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $dispatcher;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $factory;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $serverParams;
-
- /**
- * @var FormValidator
- */
- private $validator;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->serverParams = $this->getMock(
- 'Symfony\Component\Form\Extension\Validator\Util\ServerParams',
- array('getNormalizedIniPostMaxSize', 'getContentLength')
- );
- $this->validator = new FormValidator($this->serverParams);
- }
-
- public function testValidate()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $options = array('validation_groups' => array('group1', 'group2'));
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->getForm();
-
- $context->expects($this->at(0))
- ->method('validate')
- ->with($object, 'data', 'group1', true);
- $context->expects($this->at(1))
- ->method('validate')
- ->with($object, 'data', 'group2', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testValidateConstraints()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $constraint1 = new NotNull(array('groups' => array('group1', 'group2')));
- $constraint2 = new NotBlank(array('groups' => 'group2'));
-
- $options = array(
- 'validation_groups' => array('group1', 'group2'),
- 'constraints' => array($constraint1, $constraint2),
- );
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->getForm();
-
- // First default constraints
- $context->expects($this->at(0))
- ->method('validate')
- ->with($object, 'data', 'group1', true);
- $context->expects($this->at(1))
- ->method('validate')
- ->with($object, 'data', 'group2', true);
-
- // Then custom constraints
- $context->expects($this->at(2))
- ->method('validateValue')
- ->with($object, $constraint1, 'data', 'group1');
- $context->expects($this->at(3))
- ->method('validateValue')
- ->with($object, $constraint2, 'data', 'group2');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontValidateIfParentWithoutCascadeValidation()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $parent = $this->getBuilder('parent', null, array('cascade_validation' => false))
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $options = array('validation_groups' => array('group1', 'group2'));
- $form = $this->getBuilder('name', '\stdClass', $options)->getForm();
- $parent->add($form);
-
- $form->setData($object);
-
- $context->expects($this->never())
- ->method('validate');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testValidateConstraintsEvenIfNoCascadeValidation()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $constraint1 = new NotNull(array('groups' => array('group1', 'group2')));
- $constraint2 = new NotBlank(array('groups' => 'group2'));
-
- $parent = $this->getBuilder('parent', null, array('cascade_validation' => false))
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $options = array(
- 'validation_groups' => array('group1', 'group2'),
- 'constraints' => array($constraint1, $constraint2),
- );
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->getForm();
- $parent->add($form);
-
- $context->expects($this->at(0))
- ->method('validateValue')
- ->with($object, $constraint1, 'data', 'group1');
- $context->expects($this->at(1))
- ->method('validateValue')
- ->with($object, $constraint2, 'data', 'group2');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontValidateIfNoValidationGroups()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $form = $this->getBuilder('name', '\stdClass', array(
- 'validation_groups' => array(),
- ))
- ->setData($object)
- ->getForm();
-
- $form->setData($object);
-
- $context->expects($this->never())
- ->method('validate');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontValidateConstraintsIfNoValidationGroups()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint');
- $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint');
-
- $options = array(
- 'validation_groups' => array(),
- 'constraints' => array($constraint1, $constraint2),
- );
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->getForm();
-
- // Launch transformer
- $form->submit(array());
-
- $context->expects($this->never())
- ->method('validate');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontValidateIfNotSynchronized()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $form = $this->getBuilder('name', '\stdClass', array(
- 'invalid_message' => 'invalid_message_key',
- // Invalid message parameters must be supported, because the
- // invalid message can be a translation key
- // see https://github.com/symfony/symfony/issues/5144
- 'invalid_message_parameters' => array('{{ foo }}' => 'bar'),
- ))
- ->setData($object)
- ->addViewTransformer(new CallbackTransformer(
- function ($data) { return $data; },
- function () { throw new TransformationFailedException(); }
- ))
- ->getForm();
-
- // Launch transformer
- $form->submit('foo');
-
- $context->expects($this->never())
- ->method('validate');
-
- $context->expects($this->once())
- ->method('addViolation')
- ->with(
- 'invalid_message_key',
- array('{{ value }}' => 'foo', '{{ foo }}' => 'bar'),
- 'foo'
- );
- $context->expects($this->never())
- ->method('addViolationAt');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testAddInvalidErrorEvenIfNoValidationGroups()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $form = $this->getBuilder('name', '\stdClass', array(
- 'invalid_message' => 'invalid_message_key',
- // Invalid message parameters must be supported, because the
- // invalid message can be a translation key
- // see https://github.com/symfony/symfony/issues/5144
- 'invalid_message_parameters' => array('{{ foo }}' => 'bar'),
- 'validation_groups' => array(),
- ))
- ->setData($object)
- ->addViewTransformer(new CallbackTransformer(
- function ($data) { return $data; },
- function () { throw new TransformationFailedException(); }
- ))
- ->getForm();
-
- // Launch transformer
- $form->submit('foo');
-
- $context->expects($this->never())
- ->method('validate');
-
- $context->expects($this->once())
- ->method('addViolation')
- ->with(
- 'invalid_message_key',
- array('{{ value }}' => 'foo', '{{ foo }}' => 'bar'),
- 'foo'
- );
- $context->expects($this->never())
- ->method('addViolationAt');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontValidateConstraintsIfNotSynchronized()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint');
- $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint');
-
- $options = array(
- 'validation_groups' => array('group1', 'group2'),
- 'constraints' => array($constraint1, $constraint2),
- );
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->addViewTransformer(new CallbackTransformer(
- function ($data) { return $data; },
- function () { throw new TransformationFailedException(); }
- ))
- ->getForm();
-
- // Launch transformer
- $form->submit(array());
-
- $context->expects($this->never())
- ->method('validate');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- // https://github.com/symfony/symfony/issues/4359
- public function testDontMarkInvalidIfAnyChildIsNotSynchronized()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $failingTransformer = new CallbackTransformer(
- function ($data) { return $data; },
- function () { throw new TransformationFailedException(); }
- );
-
- $form = $this->getBuilder('name', '\stdClass')
- ->setData($object)
- ->addViewTransformer($failingTransformer)
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->add(
- $this->getBuilder('child')
- ->addViewTransformer($failingTransformer)
- )
- ->getForm();
-
- // Launch transformer
- $form->submit(array('child' => 'foo'));
-
- $context->expects($this->never())
- ->method('addViolation');
- $context->expects($this->never())
- ->method('addViolationAt');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testHandleCallbackValidationGroups()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $options = array('validation_groups' => array($this, 'getValidationGroups'));
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->getForm();
-
- $context->expects($this->at(0))
- ->method('validate')
- ->with($object, 'data', 'group1', true);
- $context->expects($this->at(1))
- ->method('validate')
- ->with($object, 'data', 'group2', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontExecuteFunctionNames()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $options = array('validation_groups' => 'header');
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->getForm();
-
- $context->expects($this->once())
- ->method('validate')
- ->with($object, 'data', 'header', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testHandleClosureValidationGroups()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $options = array('validation_groups' => function(FormInterface $form){
- return array('group1', 'group2');
- });
- $form = $this->getBuilder('name', '\stdClass', $options)
- ->setData($object)
- ->getForm();
-
- $context->expects($this->at(0))
- ->method('validate')
- ->with($object, 'data', 'group1', true);
- $context->expects($this->at(1))
- ->method('validate')
- ->with($object, 'data', 'group2', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testUseValidationGroupOfClickedButton()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $parent = $this->getBuilder('parent', null, array('cascade_validation' => true))
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getForm('name', '\stdClass', array(
- 'validation_groups' => 'form_group',
- ));
-
- $parent->add($form);
- $parent->add($this->getClickedSubmitButton('submit', array(
- 'validation_groups' => 'button_group',
- )));
-
- $form->setData($object);
-
- $context->expects($this->once())
- ->method('validate')
- ->with($object, 'data', 'button_group', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontUseValidationGroupOfUnclickedButton()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $parent = $this->getBuilder('parent', null, array('cascade_validation' => true))
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getForm('name', '\stdClass', array(
- 'validation_groups' => 'form_group',
- ));
-
- $parent->add($form);
- $parent->add($this->getSubmitButton('submit', array(
- 'validation_groups' => 'button_group',
- )));
-
- $form->setData($object);
-
- $context->expects($this->once())
- ->method('validate')
- ->with($object, 'data', 'form_group', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testUseInheritedValidationGroup()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $parentOptions = array(
- 'validation_groups' => 'group',
- 'cascade_validation' => true,
- );
- $parent = $this->getBuilder('parent', null, $parentOptions)
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getBuilder('name', '\stdClass')->getForm();
- $parent->add($form);
-
- $form->setData($object);
-
- $context->expects($this->once())
- ->method('validate')
- ->with($object, 'data', 'group', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testUseInheritedCallbackValidationGroup()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $parentOptions = array(
- 'validation_groups' => array($this, 'getValidationGroups'),
- 'cascade_validation' => true,
- );
- $parent = $this->getBuilder('parent', null, $parentOptions)
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getBuilder('name', '\stdClass')->getForm();
- $parent->add($form);
-
- $form->setData($object);
-
- $context->expects($this->at(0))
- ->method('validate')
- ->with($object, 'data', 'group1', true);
- $context->expects($this->at(1))
- ->method('validate')
- ->with($object, 'data', 'group2', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testUseInheritedClosureValidationGroup()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
-
- $parentOptions = array(
- 'validation_groups' => function(FormInterface $form){
- return array('group1', 'group2');
- },
- 'cascade_validation' => true,
- );
- $parent = $this->getBuilder('parent', null, $parentOptions)
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getBuilder('name', '\stdClass')->getForm();
- $parent->add($form);
-
- $form->setData($object);
-
- $context->expects($this->at(0))
- ->method('validate')
- ->with($object, 'data', 'group1', true);
- $context->expects($this->at(1))
- ->method('validate')
- ->with($object, 'data', 'group2', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testAppendPropertyPath()
- {
- $context = $this->getMockExecutionContext();
- $object = $this->getMock('\stdClass');
- $form = $this->getBuilder('name', '\stdClass')
- ->setData($object)
- ->getForm();
-
- $context->expects($this->once())
- ->method('validate')
- ->with($object, 'data', 'Default', true);
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testDontWalkScalars()
- {
- $context = $this->getMockExecutionContext();
-
- $form = $this->getBuilder()
- ->setData('scalar')
- ->getForm();
-
- $context->expects($this->never())
- ->method('validate');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function testViolationIfExtraData()
- {
- $context = $this->getMockExecutionContext();
-
- $form = $this->getBuilder('parent', null, array('extra_fields_message' => 'Extra!'))
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->add($this->getBuilder('child'))
- ->getForm();
-
- $form->submit(array('foo' => 'bar'));
-
- $context->expects($this->once())
- ->method('addViolation')
- ->with(
- 'Extra!',
- array('{{ extra_fields }}' => 'foo'),
- array('foo' => 'bar')
- );
- $context->expects($this->never())
- ->method('addViolationAt');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- /**
- * @dataProvider getPostMaxSizeFixtures
- */
- public function testPostMaxSizeViolation($contentLength, $iniMax, $nbViolation, array $params = array())
- {
- $this->serverParams->expects($this->once())
- ->method('getContentLength')
- ->will($this->returnValue($contentLength));
- $this->serverParams->expects($this->any())
- ->method('getNormalizedIniPostMaxSize')
- ->will($this->returnValue($iniMax));
-
- $context = $this->getMockExecutionContext();
- $options = array('post_max_size_message' => 'Max {{ max }}!');
- $form = $this->getBuilder('name', null, $options)->getForm();
-
- for ($i = 0; $i < $nbViolation; ++$i) {
- if (0 === $i && count($params) > 0) {
- $context->expects($this->at($i))
- ->method('addViolation')
- ->with($options['post_max_size_message'], $params);
- } else {
- $context->expects($this->at($i))
- ->method('addViolation');
- }
- }
-
- $context->expects($this->never())
- ->method('addViolationAt');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- public function getPostMaxSizeFixtures()
- {
- return array(
- array(pow(1024, 3) + 1, '1G', 1, array('{{ max }}' => '1G')),
- array(pow(1024, 3), '1G', 0),
- array(pow(1024, 2) + 1, '1M', 1, array('{{ max }}' => '1M')),
- array(pow(1024, 2), '1M', 0),
- array(1024 + 1, '1K', 1, array('{{ max }}' => '1K')),
- array(1024, '1K', 0),
- array(null, '1K', 0),
- array(1024, '', 0),
- array(1024, 0, 0),
- );
- }
-
- public function testNoViolationIfNotRoot()
- {
- $this->serverParams->expects($this->once())
- ->method('getContentLength')
- ->will($this->returnValue(1025));
- $this->serverParams->expects($this->never())
- ->method('getNormalizedIniPostMaxSize');
-
- $context = $this->getMockExecutionContext();
- $parent = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getForm();
- $parent->add($form);
-
- $context->expects($this->never())
- ->method('addViolation');
- $context->expects($this->never())
- ->method('addViolationAt');
-
- $this->validator->initialize($context);
- $this->validator->validate($form, new Form());
- }
-
- /**
- * Access has to be public, as this method is called via callback array
- * in {@link testValidateFormDataCanHandleCallbackValidationGroups()}
- * and {@link testValidateFormDataUsesInheritedCallbackValidationGroup()}
- */
- public function getValidationGroups(FormInterface $form)
- {
- return array('group1', 'group2');
- }
-
- private function getMockExecutionContext()
- {
- return $this->getMock('Symfony\Component\Validator\ExecutionContextInterface');
- }
-
- /**
- * @param string $name
- * @param string $dataClass
- * @param array $options
- *
- * @return FormBuilder
- */
- private function getBuilder($name = 'name', $dataClass = null, array $options = array())
- {
- $options = array_replace(array(
- 'constraints' => array(),
- 'invalid_message_parameters' => array(),
- ), $options);
-
- return new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory, $options);
- }
-
- private function getForm($name = 'name', $dataClass = null, array $options = array())
- {
- return $this->getBuilder($name, $dataClass, $options)->getForm();
- }
-
- private function getSubmitButton($name = 'name', array $options = array())
- {
- $builder = new SubmitButtonBuilder($name, $options);
-
- return $builder->getForm();
- }
-
- private function getClickedSubmitButton($name = 'name', array $options = array())
- {
- return $this->getSubmitButton($name, $options)->submit('');
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getDataMapper()
- {
- return $this->getMock('Symfony\Component\Form\DataMapperInterface');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener;
-
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\Extension\Validator\Constraints\Form;
-use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
-use Symfony\Component\PropertyAccess\PropertyPath;
-use Symfony\Component\Validator\ConstraintViolation;
-
-class ValidationListenerTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $dispatcher;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $factory;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $validator;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $violationMapper;
-
- /**
- * @var ValidationListener
- */
- private $listener;
-
- private $message;
-
- private $messageTemplate;
-
- private $params;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
- $this->violationMapper = $this->getMock('Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface');
- $this->listener = new ValidationListener($this->validator, $this->violationMapper);
- $this->message = 'Message';
- $this->messageTemplate = 'Message template';
- $this->params = array('foo' => 'bar');
- }
-
- private function getConstraintViolation($code = null)
- {
- return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code);
- }
-
- private function getBuilder($name = 'name', $propertyPath = null, $dataClass = null)
- {
- $builder = new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory);
- $builder->setPropertyPath(new PropertyPath($propertyPath ?: $name));
- $builder->setAttribute('error_mapping', array());
- $builder->setErrorBubbling(false);
- $builder->setMapped(true);
-
- return $builder;
- }
-
- private function getForm($name = 'name', $propertyPath = null, $dataClass = null)
- {
- return $this->getBuilder($name, $propertyPath, $dataClass)->getForm();
- }
-
- private function getMockForm()
- {
- return $this->getMock('Symfony\Component\Form\Test\FormInterface');
- }
-
- // More specific mapping tests can be found in ViolationMapperTest
- public function testMapViolation()
- {
- $violation = $this->getConstraintViolation();
- $form = $this->getForm('street');
-
- $this->validator->expects($this->once())
- ->method('validate')
- ->will($this->returnValue(array($violation)));
-
- $this->violationMapper->expects($this->once())
- ->method('mapViolation')
- ->with($violation, $form, false);
-
- $this->listener->validateForm(new FormEvent($form, null));
- }
-
- public function testMapViolationAllowsNonSyncIfInvalid()
- {
- $violation = $this->getConstraintViolation(Form::ERR_INVALID);
- $form = $this->getForm('street');
-
- $this->validator->expects($this->once())
- ->method('validate')
- ->will($this->returnValue(array($violation)));
-
- $this->violationMapper->expects($this->once())
- ->method('mapViolation')
- // pass true now
- ->with($violation, $form, true);
-
- $this->listener->validateForm(new FormEvent($form, null));
- }
-
- public function testValidateIgnoresNonRoot()
- {
- $form = $this->getMockForm();
- $form->expects($this->once())
- ->method('isRoot')
- ->will($this->returnValue(false));
-
- $this->validator->expects($this->never())
- ->method('validate');
-
- $this->violationMapper->expects($this->never())
- ->method('mapViolation');
-
- $this->listener->validateForm(new FormEvent($form, null));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
-
-use Symfony\Component\Form\FormInterface;
-
-class FormTypeValidatorExtensionTest extends TypeTestCase
-{
- public function testValidationGroupNullByDefault()
- {
- $form = $this->factory->create('form');
-
- $this->assertNull($form->getConfig()->getOption('validation_groups'));
- }
-
- public function testValidationGroupsTransformedToArray()
- {
- $form = $this->factory->create('form', null, array(
- 'validation_groups' => 'group',
- ));
-
- $this->assertEquals(array('group'), $form->getConfig()->getOption('validation_groups'));
- }
-
- public function testValidationGroupsCanBeSetToArray()
- {
- $form = $this->factory->create('form', null, array(
- 'validation_groups' => array('group1', 'group2'),
- ));
-
- $this->assertEquals(array('group1', 'group2'), $form->getConfig()->getOption('validation_groups'));
- }
-
- public function testValidationGroupsCanBeSetToFalse()
- {
- $form = $this->factory->create('form', null, array(
- 'validation_groups' => false,
- ));
-
- $this->assertEquals(array(), $form->getConfig()->getOption('validation_groups'));
- }
-
- public function testValidationGroupsCanBeSetToCallback()
- {
- $form = $this->factory->create('form', null, array(
- 'validation_groups' => array($this, 'testValidationGroupsCanBeSetToCallback'),
- ));
-
- $this->assertTrue(is_callable($form->getConfig()->getOption('validation_groups')));
- }
-
- public function testValidationGroupsCanBeSetToClosure()
- {
- $form = $this->factory->create('form', null, array(
- 'validation_groups' => function(FormInterface $form){ return null; },
- ));
-
- $this->assertTrue(is_callable($form->getConfig()->getOption('validation_groups')));
- }
-
- public function testSubmitValidatesData()
- {
- $builder = $this->factory->createBuilder('form', null, array(
- 'validation_groups' => 'group',
- ));
- $builder->add('firstName', 'form');
- $form = $builder->getForm();
-
- $this->validator->expects($this->once())
- ->method('validate')
- ->with($this->equalTo($form));
-
- // specific data is irrelevant
- $form->submit(array());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
-
-use Symfony\Component\Form\Test\TypeTestCase as BaseTypeTestCase;
-use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
-
-abstract class TypeTestCase extends BaseTypeTestCase
-{
- protected $validator;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Validator\Constraint')) {
- $this->markTestSkipped('The "Validator" component is not available');
- }
-
- $this->validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
- $metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface');
- $this->validator->expects($this->once())->method('getMetadataFactory')->will($this->returnValue($metadataFactory));
- $metadata = $this->getMockBuilder('Symfony\Component\Validator\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
- $metadataFactory->expects($this->once())->method('getMetadataFor')->will($this->returnValue($metadata));
-
- parent::setUp();
- }
-
- protected function tearDown()
- {
- $this->validator = null;
-
- parent::tearDown();
- }
-
- protected function getExtensions()
- {
- return array_merge(parent::getExtensions(), array(
- new ValidatorExtension($this->validator),
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Validator\Util;
-
-class ServerParamsTest extends \PHPUnit_Framework_TestCase
-{
- /** @dataProvider getGetPostMaxSizeTestData */
- public function testGetPostMaxSize($size, $bytes)
- {
- $serverParams = $this->getMock('Symfony\Component\Form\Extension\Validator\Util\ServerParams', array('getNormalizedIniPostMaxSize'));
- $serverParams
- ->expects($this->any())
- ->method('getNormalizedIniPostMaxSize')
- ->will($this->returnValue(strtoupper($size)));
-
- $this->assertEquals($bytes, $serverParams->getPostMaxSize());
- }
-
- public function getGetPostMaxSizeTestData()
- {
- return array(
- array('2k', 2048),
- array('2 k', 2048),
- array('8m', 8 * 1024 * 1024),
- array('+2 k', 2048),
- array('+2???k', 2048),
- array('0x10', 16),
- array('0xf', 15),
- array('010', 8),
- array('+0x10 k', 16 * 1024),
- array('1g', 1024 * 1024 * 1024),
- array('-1', -1),
- array('0', 0),
- array('2mk', 2048), // the unit must be the last char, so in this case 'k', not 'm'
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\Form\CallbackTransformer;
-use Symfony\Component\Form\Form;
-use Symfony\Component\Form\FormConfigBuilder;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\PropertyAccess\PropertyPath;
-use Symfony\Component\Validator\ConstraintViolation;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ViolationMapperTest extends \PHPUnit_Framework_TestCase
-{
- const LEVEL_0 = 0;
-
- const LEVEL_1 = 1;
-
- const LEVEL_1B = 2;
-
- const LEVEL_2 = 3;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $dispatcher;
-
- /**
- * @var ViolationMapper
- */
- private $mapper;
-
- /**
- * @var string
- */
- private $message;
-
- /**
- * @var string
- */
- private $messageTemplate;
-
- /**
- * @var array
- */
- private $params;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\Event')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->mapper = new ViolationMapper();
- $this->message = 'Message';
- $this->messageTemplate = 'Message template';
- $this->params = array('foo' => 'bar');
- }
-
- protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = array(), $inheritData = false, $synchronized = true)
- {
- $config = new FormConfigBuilder($name, $dataClass, $this->dispatcher, array(
- 'error_mapping' => $errorMapping,
- ));
- $config->setMapped(true);
- $config->setInheritData($inheritData);
- $config->setPropertyPath($propertyPath);
- $config->setCompound(true);
- $config->setDataMapper($this->getDataMapper());
-
- if (!$synchronized) {
- $config->addViewTransformer(new CallbackTransformer(
- function ($normData) { return $normData; },
- function () { throw new TransformationFailedException(); }
- ));
- }
-
- return new Form($config);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getDataMapper()
- {
- return $this->getMock('Symfony\Component\Form\DataMapperInterface');
- }
-
- /**
- * @param $propertyPath
- *
- * @return ConstraintViolation
- */
- protected function getConstraintViolation($propertyPath)
- {
- return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, $propertyPath, null);
- }
-
- /**
- * @return FormError
- */
- protected function getFormError()
- {
- return new FormError($this->message, $this->messageTemplate, $this->params);
- }
-
- public function testMapToFormInheritingParentDataIfDataDoesNotMatch()
- {
- $violation = $this->getConstraintViolation('children[address].data.foo');
- $parent = $this->getForm('parent');
- $child = $this->getForm('address', 'address', null, array(), true);
- $grandChild = $this->getForm('street');
-
- $parent->add($child);
- $child->add($grandChild);
-
- $this->mapper->mapViolation($violation, $parent);
-
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $child->getName().' should have an error, but has none');
- $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
- }
-
- public function testFollowDotRules()
- {
- $violation = $this->getConstraintViolation('data.foo');
- $parent = $this->getForm('parent', null, null, array(
- 'foo' => 'address',
- ));
- $child = $this->getForm('address', null, null, array(
- '.' => 'street',
- ));
- $grandChild = $this->getForm('street', null, null, array(
- '.' => 'name',
- ));
- $grandGrandChild = $this->getForm('name');
-
- $parent->add($child);
- $child->add($grandChild);
- $grandChild->add($grandGrandChild);
-
- $this->mapper->mapViolation($violation, $parent);
-
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandGrandChild->getErrors(), $grandGrandChild->getName().' should have an error, but has none');
- }
-
- public function testAbortMappingIfNotSynchronized()
- {
- $violation = $this->getConstraintViolation('children[address].data.street');
- $parent = $this->getForm('parent');
- $child = $this->getForm('address', 'address', null, array(), false, false);
- // even though "street" is synchronized, it should not have any errors
- // due to its parent not being synchronized
- $grandChild = $this->getForm('street' , 'street');
-
- $parent->add($child);
- $child->add($grandChild);
-
- // submit to invoke the transformer and mark the form unsynchronized
- $parent->submit(array());
-
- $this->mapper->mapViolation($violation, $parent);
-
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
- }
-
- public function testAbortDotRuleMappingIfNotSynchronized()
- {
- $violation = $this->getConstraintViolation('data.address');
- $parent = $this->getForm('parent');
- $child = $this->getForm('address', 'address', null, array(
- '.' => 'street',
- ), false, false);
- // even though "street" is synchronized, it should not have any errors
- // due to its parent not being synchronized
- $grandChild = $this->getForm('street');
-
- $parent->add($child);
- $child->add($grandChild);
-
- // submit to invoke the transformer and mark the form unsynchronized
- $parent->submit(array());
-
- $this->mapper->mapViolation($violation, $parent);
-
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
- }
-
- public function provideDefaultTests()
- {
- // The mapping must be deterministic! If a child has the property path "[street]",
- // "data[street]" should be mapped, but "data.street" should not!
- return array(
- // mapping target, child name, its property path, grand child name, its property path, violation path
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', ''),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data'),
-
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street].prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.address.street'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.address.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'data.address[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'data.address[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street].prop'),
-
- array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'children[address].data[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'data.address.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'data.address.street.prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'data.address[street]'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[street]', 'data.address[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address].street'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address].street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address][street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[street]', 'data[address][street].prop'),
-
- array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address].data'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address.street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address.street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address[street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'street', 'data.address[street].prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'data[address].street'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'street', 'data[address].street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'data[address][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'data[address][street].prop'),
-
- array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address.street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address.street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address[street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[street]', 'data.address[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'data[address].street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'data[address].street.prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'data[address][street]'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[street]', 'data[address][street].prop'),
-
- array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'children[address].data'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'children[address].data[street].prop'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'data.person.address.street'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', 'street', 'data.person.address.street.prop'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'data.person.address[street]'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', 'street', 'data.person.address[street].prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address].street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address].street.prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address][street]'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.person[address][street].prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address.street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address.street.prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address[street]'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person].address[street].prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address].street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address].street.prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address][street]'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'children[address].data[street].prop'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'data.person.address.street'),
- array(self::LEVEL_1, 'address', 'person.address', 'street', '[street]', 'data.person.address.street.prop'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'data.person.address[street]'),
- array(self::LEVEL_2, 'address', 'person.address', 'street', '[street]', 'data.person.address[street].prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address].street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address].street.prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address][street]'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data.person[address][street].prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address.street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address.street.prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address[street]'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person].address[street].prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address].street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address].street.prop'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address][street]'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', '[street]', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'children[address].data'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address.street'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address.street.prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address[street]'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data.person.address[street].prop'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'data.person[address].street'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', 'street', 'data.person[address].street.prop'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'data.person[address][street]'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', 'street', 'data.person[address][street].prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address.street'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address.street.prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address[street]'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person].address[street].prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address].street'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address].street.prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address][street]'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', 'street', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address.street'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address.street.prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address[street]'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data.person.address[street].prop'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'data.person[address].street'),
- array(self::LEVEL_1, 'address', 'person[address]', 'street', '[street]', 'data.person[address].street.prop'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'data.person[address][street]'),
- array(self::LEVEL_2, 'address', 'person[address]', 'street', '[street]', 'data.person[address][street].prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address.street'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address.street.prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address[street]'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person].address[street].prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address].street'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address].street.prop'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address][street]'),
- array(self::LEVEL_0, 'address', 'person[address]', 'street', '[street]', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'children[address].data'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address.street'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address.street.prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address[street]'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person.address[street].prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address].street'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address].street.prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address][street]'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data.person[address][street].prop'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'data[person].address.street'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', 'street', 'data[person].address.street.prop'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'data[person].address[street]'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', 'street', 'data[person].address[street].prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address].street'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address].street.prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address][street]'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', 'street', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address.street'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address.street.prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address[street]'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person.address[street].prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address].street'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address].street.prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address][street]'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data.person[address][street].prop'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'data[person].address.street'),
- array(self::LEVEL_1, 'address', '[person].address', 'street', '[street]', 'data[person].address.street.prop'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'data[person].address[street]'),
- array(self::LEVEL_2, 'address', '[person].address', 'street', '[street]', 'data[person].address[street].prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address].street'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address].street.prop'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address][street]'),
- array(self::LEVEL_0, 'address', '[person].address', 'street', '[street]', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address]'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address].data'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address.street'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address.street.prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address[street]'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person.address[street].prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address].street'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address].street.prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address][street]'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data.person[address][street].prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address.street'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address.street.prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address[street]'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', 'street', 'data[person].address[street].prop'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'data[person][address].street'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', 'street', 'data[person][address].street.prop'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'data[person][address][street]'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', 'street', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'children[address].data[street].prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address.street'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address.street.prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address[street]'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person.address[street].prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address].street'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address].street.prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address][street]'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data.person[address][street].prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address.street'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address.street.prop'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address[street]'),
- array(self::LEVEL_0, 'address', '[person][address]', 'street', '[street]', 'data[person].address[street].prop'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'data[person][address].street'),
- array(self::LEVEL_1, 'address', '[person][address]', 'street', '[street]', 'data[person][address].street.prop'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'data[person][address][street]'),
- array(self::LEVEL_2, 'address', '[person][address]', 'street', '[street]', 'data[person][address][street].prop'),
-
- array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.office'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].data.office.street'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'children[address].data.office.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.office[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office].street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office].street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data[office][street].prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'data.address.office.street'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office.street', 'data.address.office.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address.office[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address.office[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office].street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office].street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address[office][street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office.street'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office.street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office[street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address].office[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office].street'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office].street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office][street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office.street', 'data[address][office][street].prop'),
-
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data.office'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].data.office.street'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'children[address].data.office.street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data.office[street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office].street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office].street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'children[address].data[office][street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office.street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office.street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office[street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address.office[street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office].street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office].street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office][street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office.street', 'data.address[office][street].prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'data[address].office.street'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office.street', 'data[address].office.street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address].office[street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address].office[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office].street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office].street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office.street', 'data[address][office][street].prop'),
-
- array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data.office'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data.office.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data.office.street.prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].data.office[street]'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office].street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office].street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'children[address].data[office][street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address.office.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address.office.street.prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'data.address.office[street]'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'office[street]', 'data.address.office[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office].street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office].street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office[street]', 'data.address[office][street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office.street'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office.street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office[street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address].office[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office].street'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office].street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office][street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'office[street]', 'data[address][office][street].prop'),
-
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office.street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office.street.prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office[street]'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office].street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office].street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'children[address].data[office][street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office.street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office.street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office[street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address.office[street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office].street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office].street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office][street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', 'office[street]', 'data.address[office][street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address].office.street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address].office.street.prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'data[address].office[street]'),
- array(self::LEVEL_2, 'address', '[address]', 'street', 'office[street]', 'data[address].office[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office].street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office].street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'office[street]', 'data[address][office][street].prop'),
-
- array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data[office]'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].data[office].street'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'children[address].data[office].street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data[office][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'children[address].data[office][street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address.office[street].prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'data.address[office].street'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office].street', 'data.address[office].street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address[office][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office].street', 'data.address[office][street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office.street'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office.street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office[street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address].office[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office].street'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office].street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office][street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office].street', 'data[address][office][street].prop'),
-
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office.street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office.street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office[street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data[office]'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].data[office].street'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'children[address].data[office].street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data[office][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'children[address].data[office][street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office.street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office.street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office[street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address.office[street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office].street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office].street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office][street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office].street', 'data.address[office][street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office.street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office.street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office[street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address].office[street].prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'data[address][office].street'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office].street', 'data[address][office].street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address][office][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office].street', 'data[address][office][street].prop'),
-
- array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data[office]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data[office].street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'children[address].data[office].street.prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].data[office][street]'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'children[address].data[office][street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address.office[street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address[office].street'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[office][street]', 'data.address[office].street.prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'data.address[office][street]'),
- array(self::LEVEL_2, 'address', 'address', 'street', '[office][street]', 'data.address[office][street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office.street'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office.street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office[street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address].office[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office].street'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office].street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office][street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', '[office][street]', 'data[address][office][street].prop'),
-
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office.street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office.street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office[street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data.office[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office].street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office].street.prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office][street]'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'children[address].data[office][street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office.street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office.street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office[street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address.office[street].prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office].street'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office].street.prop'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office][street]'),
- array(self::LEVEL_0, 'address', '[address]', 'street', '[office][street]', 'data.address[office][street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office.street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office.street.prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office[street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address].office[street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address][office].street'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[office][street]', 'data[address][office].street.prop'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'data[address][office][street]'),
- array(self::LEVEL_2, 'address', '[address]', 'street', '[office][street]', 'data[address][office][street].prop'),
-
- // Edge cases which must not occur
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address][street].prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address][street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', '[street]', 'children[address][street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', 'street', 'children[address][street].prop'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address][street]'),
- array(self::LEVEL_1, 'address', '[address]', 'street', '[street]', 'children[address][street].prop'),
-
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'children[person].children[address].children[street]'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'children[person].children[address].data.street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'children[person].data.address.street'),
- array(self::LEVEL_0, 'address', 'person.address', 'street', 'street', 'data.address.street'),
-
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].children[office].children[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].children[office].data.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'children[address].data.street'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'office.street', 'data.address.street'),
- );
- }
-
- /**
- * @dataProvider provideDefaultTests
- */
- public function testDefaultErrorMapping($target, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
- {
- $violation = $this->getConstraintViolation($violationPath);
- $parent = $this->getForm('parent');
- $child = $this->getForm($childName, $childPath);
- $grandChild = $this->getForm($grandChildName, $grandChildPath);
-
- $parent->add($child);
- $child->add($grandChild);
-
- $this->mapper->mapViolation($violation, $parent);
-
- if (self::LEVEL_0 === $target) {
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } elseif (self::LEVEL_1 === $target) {
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } else {
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
- }
- }
-
- public function provideCustomDataErrorTests()
- {
- return array(
- // mapping target, error mapping, child name, its property path, grand child name, its property path, violation path
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo].prop'),
-
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address].prop'),
-
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].prop'),
-
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address]'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].prop'),
-
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo.street'),
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.foo[street].prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo].street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo].street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo][street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[foo][street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address.street'),
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', 'street', 'data.address[street].prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address].street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address].street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address][street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', 'street', 'data[address][street].prop'),
-
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street]'),
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street].prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street].prop'),
-
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address.street'),
- array(self::LEVEL_1, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address.street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address[street]'),
- array(self::LEVEL_2, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data.address[street].prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address].street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address].street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address][street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', 'address', 'street', '[street]', 'data[address][street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street].prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street].prop'),
-
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address.street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address.street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address[street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.address[street].prop'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address].street'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address].street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address][street]'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[address][street].prop'),
-
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street]'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street].prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street].prop'),
-
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street].prop'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street]'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street].prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street].prop'),
-
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address.street'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address.street.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address[street]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.address[street].prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address].street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address].street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address][street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[address][street].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[street].prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].street.prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street]'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][street].prop'),
-
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address.street'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address.street.prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address[street]'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data.address[street].prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address].street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address].street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address][street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', '[street]', 'data[address][street].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street].prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address.street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address.street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address[street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data.address[street].prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address].street'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address].street.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address][street]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', 'street', 'data[address][street].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo.street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.foo[street].prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo].street.prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street]'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[foo][street].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address.street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data.address[street].prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address].street.prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street]'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', '[address]', 'street', '[street]', 'data[address][street].prop'),
-
- array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
- array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
-
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
- array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
- array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
-
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
- array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
- array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
-
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
- array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
- array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
-
- array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
- array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
- array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
- array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
- array(self::LEVEL_1, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
- array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
- array(self::LEVEL_2, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
- array(self::LEVEL_0, 'foo.bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
- array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
- array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
- array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
- array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
- array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
- array(self::LEVEL_1, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
- array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
- array(self::LEVEL_2, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
- array(self::LEVEL_0, 'foo[bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
- array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
- array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
- array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
- array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
- array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
- array(self::LEVEL_1, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
- array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
- array(self::LEVEL_2, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
- array(self::LEVEL_0, '[foo].bar', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar.street.prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street]'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo.bar[street].prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar].street.prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street]'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data.foo[bar][street].prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar.street.prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street]'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo].bar[street].prop'),
- array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street'),
- array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar].street.prop'),
- array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street]'),
- array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', 'street', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar.street.prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street]'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo.bar[street].prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar].street.prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street]'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data.foo[bar][street].prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar.street.prop'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street]'),
- array(self::LEVEL_0, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo].bar[street].prop'),
- array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street'),
- array(self::LEVEL_1, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar].street.prop'),
- array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street]'),
- array(self::LEVEL_2, '[foo][bar]', 'address', 'address', 'address', 'street', '[street]', 'data[foo][bar][street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', 'street', 'data.foo'),
- array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', 'street', 'data.foo.prop'),
- array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo]'),
- array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo].prop'),
-
- array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo'),
- array(self::LEVEL_2, 'foo', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo.prop'),
- array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo]'),
- array(self::LEVEL_2, '[foo]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo].prop'),
-
- array(self::LEVEL_2, 'foo', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo'),
- array(self::LEVEL_2, 'foo', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo.prop'),
- array(self::LEVEL_2, '[foo]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo]'),
- array(self::LEVEL_2, '[foo]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo].prop'),
-
- array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', 'street', 'data.foo.bar'),
- array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', 'street', 'data.foo.bar.prop'),
- array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', 'street', 'data.foo[bar]'),
- array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', 'street', 'data.foo[bar].prop'),
- array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', 'street', 'data[foo].bar'),
- array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', 'street', 'data[foo].bar.prop'),
- array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo][bar]'),
- array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', 'street', 'data[foo][bar].prop'),
-
- array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo.bar'),
- array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo.bar.prop'),
- array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo[bar]'),
- array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data.foo[bar].prop'),
- array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo].bar'),
- array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo].bar.prop'),
- array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo][bar]'),
- array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', 'address', 'street', '[street]', 'data[foo][bar].prop'),
-
- array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo.bar'),
- array(self::LEVEL_2, 'foo.bar', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo.bar.prop'),
- array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo[bar]'),
- array(self::LEVEL_2, 'foo[bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data.foo[bar].prop'),
- array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo].bar'),
- array(self::LEVEL_2, '[foo].bar', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo].bar.prop'),
- array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo][bar]'),
- array(self::LEVEL_2, '[foo][bar]', 'address.street', 'address', '[address]', 'street', 'street', 'data[foo][bar].prop'),
-
- // Edge cases
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street'),
- array(self::LEVEL_2, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data.foo[street].prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo].street.prop'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street]'),
- array(self::LEVEL_0, 'foo', 'address', 'address', '[address]', 'street', 'street', 'data[foo][street].prop'),
-
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo.street.prop'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street]'),
- array(self::LEVEL_0, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data.foo[street].prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street'),
- array(self::LEVEL_2, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo].street.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street]'),
- array(self::LEVEL_1, '[foo]', 'address', 'address', 'address', 'street', 'street', 'data[foo][street].prop'),
- );
- }
-
- /**
- * @dataProvider provideCustomDataErrorTests
- */
- public function testCustomDataErrorMapping($target, $mapFrom, $mapTo, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
- {
- $violation = $this->getConstraintViolation($violationPath);
- $parent = $this->getForm('parent', null, null, array($mapFrom => $mapTo));
- $child = $this->getForm($childName, $childPath);
- $grandChild = $this->getForm($grandChildName, $grandChildPath);
-
- $parent->add($child);
- $child->add($grandChild);
-
- // Add a field mapped to the first element of $mapFrom
- // to try to distract the algorithm
- // Only add it if we expect the error to come up on a different
- // level than LEVEL_0, because in this case the error would
- // (correctly) be mapped to the distraction field
- if ($target !== self::LEVEL_0) {
- $mapFromPath = new PropertyPath($mapFrom);
- $mapFromPrefix = $mapFromPath->isIndex(0)
- ? '['.$mapFromPath->getElement(0).']'
- : $mapFromPath->getElement(0);
- $distraction = $this->getForm('distraction', $mapFromPrefix);
-
- $parent->add($distraction);
- }
-
- $this->mapper->mapViolation($violation, $parent);
-
- if ($target !== self::LEVEL_0) {
- $this->assertCount(0, $distraction->getErrors(), 'distraction should not have an error, but has one');
- }
-
- if (self::LEVEL_0 === $target) {
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } elseif (self::LEVEL_1 === $target) {
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } else {
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
- }
- }
-
- public function provideCustomFormErrorTests()
- {
- // This case is different than the data errors, because here the
- // left side of the mapping refers to the property path of the actual
- // children. In other words, a child error only works if
- // 1) the error actually maps to an existing child and
- // 2) the property path of that child (relative to the form providing
- // the mapping) matches the left side of the mapping
- return array(
- // mapping target, map from, map to, child name, its property path, grand child name, its property path, violation path
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street].prop'),
-
- // Property path of the erroneous field and mapping must match exactly
- array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
- array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
- array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
- array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
- array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
- array(self::LEVEL_1B, 'foo', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
-
- array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
- array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
- array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
- array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
- array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
- array(self::LEVEL_1B, '[foo]', 'address', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
-
- array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data'),
- array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].children[street].data.prop'),
- array(self::LEVEL_2, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street'),
- array(self::LEVEL_2, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data.street.prop'),
- array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street]'),
- array(self::LEVEL_1, '[foo]', 'address', 'foo', '[foo]', 'address', 'address', 'street', 'street', 'children[foo].data[street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].children[street].data'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].children[street].data.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data.street'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data.street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data[street]'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo].data[street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street].prop'),
-
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].children[street].data'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].children[street].data.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data.street'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo].data[street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].children[street].data'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].children[street].data.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data.street'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data.street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data[street]'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo].data[street].prop'),
-
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street].data.prop'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street.prop'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'foo', 'address', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street].prop'),
-
- // Map to a nested child
- array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[foo]'),
- array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[foo]'),
- array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[foo]'),
- array(self::LEVEL_2, 'foo', 'address.street', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[foo]'),
-
- // Map from a nested child
- array(self::LEVEL_1B, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_1B, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1B, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_2, 'address.street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
-
- array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1B, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1B, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1B, 'address[street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_2, 'address[street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
-
- array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_1B, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_1B, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1B, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_2, '[address].street', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
-
- array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', 'address', 'street', '[street]', 'children[address].data[street]'),
- array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].children[street]'),
- array(self::LEVEL_2, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_1B, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1B, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].children[street]'),
- array(self::LEVEL_1, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data.street'),
- array(self::LEVEL_1B, '[address][street]', 'foo', 'foo', 'foo', 'address', '[address]', 'street', '[street]', 'children[address].data[street]'),
- );
- }
-
- /**
- * @dataProvider provideCustomFormErrorTests
- */
- public function testCustomFormErrorMapping($target, $mapFrom, $mapTo, $errorName, $errorPath, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
- {
- $violation = $this->getConstraintViolation($violationPath);
- $parent = $this->getForm('parent', null, null, array($mapFrom => $mapTo));
- $child = $this->getForm($childName, $childPath);
- $grandChild = $this->getForm($grandChildName, $grandChildPath);
- $errorChild = $this->getForm($errorName, $errorPath);
-
- $parent->add($child);
- $parent->add($errorChild);
- $child->add($grandChild);
-
- $this->mapper->mapViolation($violation, $parent);
-
- if (self::LEVEL_0 === $target) {
- $this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } elseif (self::LEVEL_1 === $target) {
- $this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } elseif (self::LEVEL_1B === $target) {
- $this->assertEquals(array($this->getFormError()), $errorChild->getErrors(), $errorName.' should have an error, but has none');
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } else {
- $this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
- }
- }
-
- public function provideErrorTestsForFormInheritingParentData()
- {
- return array(
- // mapping target, child name, its property path, grand child name, its property path, violation path
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].children[street].data.prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'children[address].data.street.prop'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street]'),
- array(self::LEVEL_1, 'address', 'address', 'street', 'street', 'children[address].data[street].prop'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.street'),
- array(self::LEVEL_2, 'address', 'address', 'street', 'street', 'data.street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address.street'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address.street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address[street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data.address[street].prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address].street.prop'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street]'),
- array(self::LEVEL_0, 'address', 'address', 'street', 'street', 'data[address][street].prop'),
- );
- }
-
- /**
- * @dataProvider provideErrorTestsForFormInheritingParentData
- */
- public function testErrorMappingForFormInheritingParentData($target, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath)
- {
- $violation = $this->getConstraintViolation($violationPath);
- $parent = $this->getForm('parent');
- $child = $this->getForm($childName, $childPath, null, array(), true);
- $grandChild = $this->getForm($grandChildName, $grandChildPath);
-
- $parent->add($child);
- $child->add($grandChild);
-
- $this->mapper->mapViolation($violation, $parent);
-
- if (self::LEVEL_0 === $target) {
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } elseif (self::LEVEL_1 === $target) {
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
- $this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
- } else {
- $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper;
-
-use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationPath;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ViolationPathTest extends \PHPUnit_Framework_TestCase
-{
- public function providePaths()
- {
- return array(
- array('children[address]', array(
- array('address', true, true),
- )),
- array('children[address].children[street]', array(
- array('address', true, true),
- array('street', true, true),
- )),
- array('children[address][street]', array(
- array('address', true, true),
- ), 'children[address]'),
- array('children[address].data', array(
- array('address', true, true),
- ), 'children[address]'),
- array('children[address].data.street', array(
- array('address', true, true),
- array('street', false, false),
- )),
- array('children[address].data[street]', array(
- array('address', true, true),
- array('street', false, true),
- )),
- array('children[address].children[street].data.name', array(
- array('address', true, true),
- array('street', true, true),
- array('name', false, false),
- )),
- array('children[address].children[street].data[name]', array(
- array('address', true, true),
- array('street', true, true),
- array('name', false, true),
- )),
- array('data.address', array(
- array('address', false, false),
- )),
- array('data[address]', array(
- array('address', false, true),
- )),
- array('data.address.street', array(
- array('address', false, false),
- array('street', false, false),
- )),
- array('data[address].street', array(
- array('address', false, true),
- array('street', false, false),
- )),
- array('data.address[street]', array(
- array('address', false, false),
- array('street', false, true),
- )),
- array('data[address][street]', array(
- array('address', false, true),
- array('street', false, true),
- )),
- // A few invalid examples
- array('data', array(), ''),
- array('children', array(), ''),
- array('children.address', array(), ''),
- array('children.address[street]', array(), ''),
- );
- }
-
- /**
- * @dataProvider providePaths
- */
- public function testCreatePath($string, $entries, $slicedPath = null)
- {
- if (null === $slicedPath) {
- $slicedPath = $string;
- }
-
- $path = new ViolationPath($string);
-
- $this->assertSame($slicedPath, $path->__toString());
- $this->assertSame(count($entries), count($path->getElements()));
- $this->assertSame(count($entries), $path->getLength());
-
- foreach ($entries as $index => $entry) {
- $this->assertEquals($entry[0], $path->getElement($index));
- $this->assertSame($entry[1], $path->mapsForm($index));
- $this->assertSame($entry[2], $path->isIndex($index));
- $this->assertSame(!$entry[2], $path->isProperty($index));
- }
- }
-
- public function provideParents()
- {
- return array(
- array('children[address]', null),
- array('children[address].children[street]', 'children[address]'),
- array('children[address].data.street', 'children[address]'),
- array('children[address].data[street]', 'children[address]'),
- array('data.address', null),
- array('data.address.street', 'data.address'),
- array('data.address[street]', 'data.address'),
- array('data[address].street', 'data[address]'),
- array('data[address][street]', 'data[address]'),
- );
- }
-
- /**
- * @dataProvider provideParents
- */
- public function testGetParent($violationPath, $parentPath)
- {
- $path = new ViolationPath($violationPath);
- $parent = $parentPath === null ? null : new ViolationPath($parentPath);
-
- $this->assertEquals($parent, $path->getParent());
- }
-
- public function testGetElement()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $this->assertEquals('street', $path->getElement(1));
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testGetElementDoesNotAcceptInvalidIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->getElement(3);
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testGetElementDoesNotAcceptNegativeIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->getElement(-1);
- }
-
- public function testIsProperty()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $this->assertFalse($path->isProperty(1));
- $this->assertTrue($path->isProperty(2));
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testIsPropertyDoesNotAcceptInvalidIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->isProperty(3);
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testIsPropertyDoesNotAcceptNegativeIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->isProperty(-1);
- }
-
- public function testIsIndex()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $this->assertTrue($path->isIndex(1));
- $this->assertFalse($path->isIndex(2));
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testIsIndexDoesNotAcceptInvalidIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->isIndex(3);
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testIsIndexDoesNotAcceptNegativeIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->isIndex(-1);
- }
-
- public function testMapsForm()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $this->assertTrue($path->mapsForm(0));
- $this->assertFalse($path->mapsForm(1));
- $this->assertFalse($path->mapsForm(2));
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testMapsFormDoesNotAcceptInvalidIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->mapsForm(3);
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testMapsFormDoesNotAcceptNegativeIndices()
- {
- $path = new ViolationPath('children[address].data[street].name');
-
- $path->mapsForm(-1);
- }
-}
+++ /dev/null
-<?php
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\FormBuilderInterface;
-
-class AlternatingRowType extends AbstractType
-{
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $formFactory = $builder->getFormFactory();
-
- $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formFactory) {
- $form = $event->getForm();
- $type = $form->getName() % 2 === 0 ? 'text' : 'textarea';
- $form->add('title', $type);
- });
- }
-
- public function getName()
- {
- return 'alternating_row';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-class Author
-{
- public $firstName;
- private $lastName;
- private $australian;
- public $child;
- private $readPermissions;
-
- private $privateProperty;
-
- public function setLastName($lastName)
- {
- $this->lastName = $lastName;
- }
-
- public function getLastName()
- {
- return $this->lastName;
- }
-
- private function getPrivateGetter()
- {
- return 'foobar';
- }
-
- public function setAustralian($australian)
- {
- $this->australian = $australian;
- }
-
- public function isAustralian()
- {
- return $this->australian;
- }
-
- public function setReadPermissions($bool)
- {
- $this->readPermissions = $bool;
- }
-
- public function hasReadPermissions()
- {
- return $this->readPermissions;
- }
-
- private function isPrivateIsser()
- {
- return true;
- }
-
- public function getPrivateSetter()
- {
- }
-
- private function setPrivateSetter($data)
- {
- }
-}
+++ /dev/null
-<?php
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class AuthorType extends AbstractType
-{
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder
- ->add('firstName')
- ->add('lastName')
- ;
- }
-
- public function getName()
- {
- return 'author';
- }
-
- public function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setDefaults(array(
- 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
- ));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-/**
- * This class is a hand written simplified version of PHP native `ArrayObject`
- * class, to show that it behaves differently than the PHP native implementation.
- */
-class CustomArrayObject implements \ArrayAccess, \IteratorAggregate, \Countable, \Serializable
-{
- private $array;
-
- public function __construct(array $array = null)
- {
- $this->array = $array ?: array();
- }
-
- public function offsetExists($offset)
- {
- return array_key_exists($offset, $this->array);
- }
-
- public function offsetGet($offset)
- {
- return $this->array[$offset];
- }
-
- public function offsetSet($offset, $value)
- {
- if (null === $offset) {
- $this->array[] = $value;
- } else {
- $this->array[$offset] = $value;
- }
- }
-
- public function offsetUnset($offset)
- {
- unset($this->array[$offset]);
- }
-
- public function getIterator()
- {
- return new \ArrayIterator($this->array);
- }
-
- public function count()
- {
- return count($this->array);
- }
-
- public function serialize()
- {
- return serialize($this->array);
- }
-
- public function unserialize($serialized)
- {
- $this->array = (array) unserialize((string) $serialized);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\DataTransformerInterface;
-use Symfony\Component\Form\Exception\RuntimeException;
-
-class FixedDataTransformer implements DataTransformerInterface
-{
- private $mapping;
-
- public function __construct(array $mapping)
- {
- $this->mapping = $mapping;
- }
-
- public function transform($value)
- {
- if (!array_key_exists($value, $this->mapping)) {
- throw new RuntimeException(sprintf('No mapping for value "%s"', $value));
- }
-
- return $this->mapping[$value];
- }
-
- public function reverseTransform($value)
- {
- $result = array_search($value, $this->mapping, true);
-
- if ($result === false) {
- throw new RuntimeException(sprintf('No reverse mapping for value "%s"', $value));
- }
-
- return $result;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-class FixedFilterListener implements EventSubscriberInterface
-{
- private $mapping;
-
- public function __construct(array $mapping)
- {
- $this->mapping = array_merge(array(
- 'preSubmit' => array(),
- 'onSubmit' => array(),
- 'preSetData' => array(),
- ), $mapping);
- }
-
- public function preSubmit(FormEvent $event)
- {
- $data = $event->getData();
-
- if (isset($this->mapping['preSubmit'][$data])) {
- $event->setData($this->mapping['preSubmit'][$data]);
- }
- }
-
- public function onSubmit(FormEvent $event)
- {
- $data = $event->getData();
-
- if (isset($this->mapping['onSubmit'][$data])) {
- $event->setData($this->mapping['onSubmit'][$data]);
- }
- }
-
- public function preSetData(FormEvent $event)
- {
- $data = $event->getData();
-
- if (isset($this->mapping['preSetData'][$data])) {
- $event->setData($this->mapping['preSetData'][$data]);
- }
- }
-
- public static function getSubscribedEvents()
- {
- return array(
- FormEvents::PRE_SUBMIT => 'preSubmit',
- FormEvents::SUBMIT => 'onSubmit',
- FormEvents::PRE_SET_DATA => 'preSetData',
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormFactoryInterface;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class FooSubType extends AbstractType
-{
- public function getName()
- {
- return 'foo_sub_type';
- }
-
- public function getParent()
- {
- return 'foo';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormFactoryInterface;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class FooSubTypeWithParentInstance extends AbstractType
-{
- public function getName()
- {
- return 'foo_sub_type_parent_instance';
- }
-
- public function getParent()
- {
- return new FooType();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\Form\FormFactoryInterface;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-class FooType extends AbstractType
-{
- public function getName()
- {
- return 'foo';
- }
-
- public function getParent()
- {
- return null;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\Form\FormBuilderInterface;
-
-class FooTypeBarExtension extends AbstractTypeExtension
-{
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->setAttribute('bar', 'x');
- }
-
- public function getAllowedOptionValues()
- {
- return array(
- 'a_or_b' => array('c'),
- );
- }
-
- public function getExtendedType()
- {
- return 'foo';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\Form\FormBuilderInterface;
-
-class FooTypeBazExtension extends AbstractTypeExtension
-{
- public function buildForm(FormBuilderInterface $builder, array $options)
- {
- $builder->setAttribute('baz', 'x');
- }
-
- public function getExtendedType()
- {
- return 'foo';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Fixtures;
-
-use Symfony\Component\Form\FormTypeInterface;
-use Symfony\Component\Form\FormTypeExtensionInterface;
-use Symfony\Component\Form\FormTypeGuesserInterface;
-use Symfony\Component\Form\FormExtensionInterface;
-
-class TestExtension implements FormExtensionInterface
-{
- private $types = array();
-
- private $extensions = array();
-
- private $guesser;
-
- public function __construct(FormTypeGuesserInterface $guesser)
- {
- $this->guesser = $guesser;
- }
-
- public function addType(FormTypeInterface $type)
- {
- $this->types[$type->getName()] = $type;
- }
-
- public function getType($name)
- {
- return isset($this->types[$name]) ? $this->types[$name] : null;
- }
-
- public function hasType($name)
- {
- return isset($this->types[$name]);
- }
-
- public function addTypeExtension(FormTypeExtensionInterface $extension)
- {
- $type = $extension->getExtendedType();
-
- if (!isset($this->extensions[$type])) {
- $this->extensions[$type] = array();
- }
-
- $this->extensions[$type][] = $extension;
- }
-
- public function getTypeExtensions($name)
- {
- return isset($this->extensions[$name]) ? $this->extensions[$name] : array();
- }
-
- public function hasTypeExtensions($name)
- {
- return isset($this->extensions[$name]);
- }
-
- public function getTypeGuesser()
- {
- return $this->guesser;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormBuilder;
-
-class FormBuilderTest extends \PHPUnit_Framework_TestCase
-{
- private $dispatcher;
-
- private $factory;
-
- private $builder;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->builder = new FormBuilder('name', null, $this->dispatcher, $this->factory);
- }
-
- protected function tearDown()
- {
- $this->dispatcher = null;
- $this->factory = null;
- $this->builder = null;
- }
-
- /**
- * Changing the name is not allowed, otherwise the name and property path
- * are not synchronized anymore
- *
- * @see FormType::buildForm
- */
- public function testNoSetName()
- {
- $this->assertFalse(method_exists($this->builder, 'setName'));
- }
-
- public function testAddNameNoStringAndNoInteger()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
- $this->builder->add(true);
- }
-
- public function testAddTypeNoString()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
- $this->builder->add('foo', 1234);
- }
-
- public function testAddWithGuessFluent()
- {
- $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory);
- $builder = $this->builder->add('foo');
- $this->assertSame($builder, $this->builder);
- }
-
- public function testAddIsFluent()
- {
- $builder = $this->builder->add('foo', 'text', array('bar' => 'baz'));
- $this->assertSame($builder, $this->builder);
- }
-
- public function testAdd()
- {
- $this->assertFalse($this->builder->has('foo'));
- $this->builder->add('foo', 'text');
- $this->assertTrue($this->builder->has('foo'));
- }
-
- public function testAddIntegerName()
- {
- $this->assertFalse($this->builder->has(0));
- $this->builder->add(0, 'text');
- $this->assertTrue($this->builder->has(0));
- }
-
- public function testAll()
- {
- $this->factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('foo', 'text')
- ->will($this->returnValue(new FormBuilder('foo', null, $this->dispatcher, $this->factory)));
-
- $this->assertCount(0, $this->builder->all());
- $this->assertFalse($this->builder->has('foo'));
-
- $this->builder->add('foo', 'text');
- $children = $this->builder->all();
-
- $this->assertTrue($this->builder->has('foo'));
- $this->assertCount(1, $children);
- $this->assertArrayHasKey('foo', $children);
- }
-
- /*
- * https://github.com/symfony/symfony/issues/4693
- */
- public function testMaintainOrderOfLazyAndExplicitChildren()
- {
- $this->builder->add('foo', 'text');
- $this->builder->add($this->getFormBuilder('bar'));
- $this->builder->add('baz', 'text');
-
- $children = $this->builder->all();
-
- $this->assertSame(array('foo', 'bar', 'baz'), array_keys($children));
- }
-
- public function testAddFormType()
- {
- $this->assertFalse($this->builder->has('foo'));
- $this->builder->add('foo', $this->getMock('Symfony\Component\Form\FormTypeInterface'));
- $this->assertTrue($this->builder->has('foo'));
- }
-
- public function testRemove()
- {
- $this->builder->add('foo', 'text');
- $this->builder->remove('foo');
- $this->assertFalse($this->builder->has('foo'));
- }
-
- public function testRemoveUnknown()
- {
- $this->builder->remove('foo');
- $this->assertFalse($this->builder->has('foo'));
- }
-
- // https://github.com/symfony/symfony/pull/4826
- public function testRemoveAndGetForm()
- {
- $this->builder->add('foo', 'text');
- $this->builder->remove('foo');
- $form = $this->builder->getForm();
- $this->assertInstanceOf('Symfony\Component\Form\Form', $form);
- }
-
- public function testCreateNoTypeNo()
- {
- $this->factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('foo', 'text', null, array())
- ;
-
- $this->builder->create('foo');
- }
-
- public function testGetUnknown()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\InvalidArgumentException', 'The child with the name "foo" does not exist.');
- $this->builder->get('foo');
- }
-
- public function testGetExplicitType()
- {
- $expectedType = 'text';
- $expectedName = 'foo';
- $expectedOptions = array('bar' => 'baz');
-
- $this->factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with($expectedName, $expectedType, null, $expectedOptions)
- ->will($this->returnValue($this->getFormBuilder()));
-
- $this->builder->add($expectedName, $expectedType, $expectedOptions);
- $builder = $this->builder->get($expectedName);
-
- $this->assertNotSame($builder, $this->builder);
- }
-
- public function testGetGuessedType()
- {
- $expectedName = 'foo';
- $expectedOptions = array('bar' => 'baz');
-
- $this->factory->expects($this->once())
- ->method('createBuilderForProperty')
- ->with('stdClass', $expectedName, null, $expectedOptions)
- ->will($this->returnValue($this->getFormBuilder()));
-
- $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory);
- $this->builder->add($expectedName, null, $expectedOptions);
- $builder = $this->builder->get($expectedName);
-
- $this->assertNotSame($builder, $this->builder);
- }
-
- public function testGetFormConfigErasesReferences()
- {
- $builder = new FormBuilder('name', null, $this->dispatcher, $this->factory);
- $builder->add(new FormBuilder('child', null, $this->dispatcher, $this->factory));
-
- $config = $builder->getFormConfig();
- $reflClass = new \ReflectionClass($config);
- $children = $reflClass->getProperty('children');
- $unresolvedChildren = $reflClass->getProperty('unresolvedChildren');
-
- $children->setAccessible(true);
- $unresolvedChildren->setAccessible(true);
-
- $this->assertEmpty($children->getValue($config));
- $this->assertEmpty($unresolvedChildren->getValue($config));
- }
-
- private function getFormBuilder($name = 'name')
- {
- $mock = $this->getMockBuilder('Symfony\Component\Form\FormBuilder')
- ->disableOriginalConstructor()
- ->getMock();
-
- $mock->expects($this->any())
- ->method('getName')
- ->will($this->returnValue($name));
-
- return $mock;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\Exception\UnexpectedTypeException;
-use Symfony\Component\Form\FormConfigBuilder;
-use Symfony\Component\Form\Exception\InvalidArgumentException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormConfigTest extends \PHPUnit_Framework_TestCase
-{
- public function getHtml4Ids()
- {
- return array(
- array('z0', true),
- array('A0', true),
- array('A9', true),
- array('Z0', true),
- array('#', false),
- array('a#', false),
- array('a$', false),
- array('a%', false),
- array('a ', false),
- array("a\t", false),
- array("a\n", false),
- array('a-', true),
- array('a_', true),
- array('a:', true),
- // Periods are allowed by the HTML4 spec, but disallowed by us
- // because they break the generated property paths
- array('a.', false),
- // Contrary to the HTML4 spec, we allow names starting with a
- // number, otherwise naming fields by collection indices is not
- // possible.
- // For root forms, leading digits will be stripped from the
- // "id" attribute to produce valid HTML4.
- array('0', true),
- array('9', true),
- // Contrary to the HTML4 spec, we allow names starting with an
- // underscore, since this is already a widely used practice in
- // Symfony2.
- // For root forms, leading underscores will be stripped from the
- // "id" attribute to produce valid HTML4.
- array('_', true),
- // Integers are allowed
- array(0, true),
- array(123, true),
- // NULL is allowed
- array(null, true),
- // Other types are not
- array(1.23, false),
- array(5., false),
- array(true, false),
- array(new \stdClass(), false),
- );
- }
-
- /**
- * @dataProvider getHtml4Ids
- */
- public function testNameAcceptsOnlyNamesValidAsIdsInHtml4($name, $accepted)
- {
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
-
- try {
- new FormConfigBuilder($name, null, $dispatcher);
- if (!$accepted) {
- $this->fail(sprintf('The value "%s" should not be accepted', $name));
- }
- } catch (UnexpectedTypeException $e) {
- // if the value was not accepted, but should be, rethrow exception
- if ($accepted) {
- throw $e;
- }
- } catch (InvalidArgumentException $e) {
- // if the value was not accepted, but should be, rethrow exception
- if ($accepted) {
- throw $e;
- }
- }
- }
-
- public function testGetRequestHandlerCreatesNativeRequestHandlerIfNotSet()
- {
- $config = $this->getConfigBuilder()->getFormConfig();
-
- $this->assertInstanceOf('Symfony\Component\Form\NativeRequestHandler', $config->getRequestHandler());
- }
-
- public function testGetRequestHandlerReusesNativeRequestHandlerInstance()
- {
- $config1 = $this->getConfigBuilder()->getFormConfig();
- $config2 = $this->getConfigBuilder()->getFormConfig();
-
- $this->assertSame($config1->getRequestHandler(), $config2->getRequestHandler());
- }
-
- public function testSetMethodAllowsGet()
- {
- $this->getConfigBuilder()->setMethod('GET');
- }
-
- public function testSetMethodAllowsPost()
- {
- $this->getConfigBuilder()->setMethod('POST');
- }
-
- public function testSetMethodAllowsPut()
- {
- $this->getConfigBuilder()->setMethod('PUT');
- }
-
- public function testSetMethodAllowsDelete()
- {
- $this->getConfigBuilder()->setMethod('DELETE');
- }
-
- public function testSetMethodAllowsPatch()
- {
- $this->getConfigBuilder()->setMethod('PATCH');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
- */
- public function testSetMethodDoesNotAllowOtherValues()
- {
- $this->getConfigBuilder()->setMethod('foo');
- }
-
- private function getConfigBuilder($name = 'name')
- {
- $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
-
- return new FormConfigBuilder($name, null, $dispatcher);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormFactoryBuilder;
-use Symfony\Component\Form\Tests\Fixtures\FooType;
-
-class FormFactoryBuilderTest extends \PHPUnit_Framework_TestCase
-{
- private $registry;
- private $guesser;
- private $type;
-
- protected function setUp()
- {
- $factory = new \ReflectionClass('Symfony\Component\Form\FormFactory');
- $this->registry = $factory->getProperty('registry');
- $this->registry->setAccessible(true);
-
- $this->guesser = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
- $this->type = new FooType;
- }
-
- public function testAddType()
- {
- $factoryBuilder = new FormFactoryBuilder;
- $factoryBuilder->addType($this->type);
-
- $factory = $factoryBuilder->getFormFactory();
- $registry = $this->registry->getValue($factory);
- $extensions = $registry->getExtensions();
-
- $this->assertCount(1, $extensions);
- $this->assertTrue($extensions[0]->hasType($this->type->getName()));
- $this->assertNull($extensions[0]->getTypeGuesser());
- }
-
- public function testAddTypeGuesser()
- {
- $factoryBuilder = new FormFactoryBuilder;
- $factoryBuilder->addTypeGuesser($this->guesser);
-
- $factory = $factoryBuilder->getFormFactory();
- $registry = $this->registry->getValue($factory);
- $extensions = $registry->getExtensions();
-
- $this->assertCount(1, $extensions);
- $this->assertNotNull($extensions[0]->getTypeGuesser());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormTypeGuesserChain;
-use Symfony\Component\Form\FormFactory;
-use Symfony\Component\Form\Guess\Guess;
-use Symfony\Component\Form\Guess\ValueGuess;
-use Symfony\Component\Form\Guess\TypeGuess;
-use Symfony\Component\Form\Tests\Fixtures\Author;
-use Symfony\Component\Form\Tests\Fixtures\FooType;
-use Symfony\Component\Form\Tests\Fixtures\FooSubType;
-use Symfony\Component\Form\Tests\Fixtures\FooSubTypeWithParentInstance;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormFactoryTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $guesser1;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $guesser2;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $registry;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $resolvedTypeFactory;
-
- /**
- * @var FormFactory
- */
- private $factory;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->resolvedTypeFactory = $this->getMock('Symfony\Component\Form\ResolvedFormTypeFactoryInterface');
- $this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
- $this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
- $this->registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface');
- $this->factory = new FormFactory($this->registry, $this->resolvedTypeFactory);
-
- $this->registry->expects($this->any())
- ->method('getTypeGuesser')
- ->will($this->returnValue(new FormTypeGuesserChain(array(
- $this->guesser1,
- $this->guesser2,
- ))));
- }
-
- public function testCreateNamedBuilderWithTypeName()
- {
- $options = array('a' => '1', 'b' => '2');
- $resolvedType = $this->getMockResolvedType();
-
- $this->registry->expects($this->once())
- ->method('getType')
- ->with('type')
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $options)
- ->will($this->returnValue('BUILDER'));
-
- $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', null, $options));
- }
-
- public function testCreateNamedBuilderWithTypeInstance()
- {
- $options = array('a' => '1', 'b' => '2');
- $type = new FooType();
- $resolvedType = $this->getMockResolvedType();
-
- $this->resolvedTypeFactory->expects($this->once())
- ->method('createResolvedType')
- ->with($type)
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $options)
- ->will($this->returnValue('BUILDER'));
-
- $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
- }
-
- public function testCreateNamedBuilderWithTypeInstanceWithParentType()
- {
- $options = array('a' => '1', 'b' => '2');
- $type = new FooSubType();
- $resolvedType = $this->getMockResolvedType();
- $parentResolvedType = $this->getMockResolvedType();
-
- $this->registry->expects($this->once())
- ->method('getType')
- ->with('foo')
- ->will($this->returnValue($parentResolvedType));
-
- $this->resolvedTypeFactory->expects($this->once())
- ->method('createResolvedType')
- ->with($type, array(), $parentResolvedType)
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $options)
- ->will($this->returnValue('BUILDER'));
-
- $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
- }
-
- public function testCreateNamedBuilderWithTypeInstanceWithParentTypeInstance()
- {
- $options = array('a' => '1', 'b' => '2');
- $type = new FooSubTypeWithParentInstance();
- $resolvedType = $this->getMockResolvedType();
- $parentResolvedType = $this->getMockResolvedType();
-
- $this->resolvedTypeFactory->expects($this->at(0))
- ->method('createResolvedType')
- ->with($type->getParent())
- ->will($this->returnValue($parentResolvedType));
-
- $this->resolvedTypeFactory->expects($this->at(1))
- ->method('createResolvedType')
- ->with($type, array(), $parentResolvedType)
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $options)
- ->will($this->returnValue('BUILDER'));
-
- $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
- }
-
- public function testCreateNamedBuilderWithResolvedTypeInstance()
- {
- $options = array('a' => '1', 'b' => '2');
- $resolvedType = $this->getMockResolvedType();
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $options)
- ->will($this->returnValue('BUILDER'));
-
- $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $resolvedType, null, $options));
- }
-
- public function testCreateNamedBuilderFillsDataOption()
- {
- $givenOptions = array('a' => '1', 'b' => '2');
- $expectedOptions = array_merge($givenOptions, array('data' => 'DATA'));
- $resolvedType = $this->getMockResolvedType();
-
- $this->registry->expects($this->once())
- ->method('getType')
- ->with('type')
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $expectedOptions)
- ->will($this->returnValue('BUILDER'));
-
- $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $givenOptions));
- }
-
- public function testCreateNamedBuilderDoesNotOverrideExistingDataOption()
- {
- $options = array('a' => '1', 'b' => '2', 'data' => 'CUSTOM');
- $resolvedType = $this->getMockResolvedType();
-
- $this->registry->expects($this->once())
- ->method('getType')
- ->with('type')
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $options)
- ->will($this->returnValue('BUILDER'));
-
- $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $options));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- * @expectedExceptionMessage Expected argument of type "string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface", "stdClass" given
- */
- public function testCreateNamedBuilderThrowsUnderstandableException()
- {
- $this->factory->createNamedBuilder('name', new \stdClass());
- }
-
- public function testCreateUsesTypeNameIfTypeGivenAsString()
- {
- $options = array('a' => '1', 'b' => '2');
- $resolvedType = $this->getMockResolvedType();
- $builder = $this->getMockFormBuilder();
-
- $this->registry->expects($this->once())
- ->method('getType')
- ->with('TYPE')
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'TYPE', $options)
- ->will($this->returnValue($builder));
-
- $builder->expects($this->once())
- ->method('getForm')
- ->will($this->returnValue('FORM'));
-
- $this->assertSame('FORM', $this->factory->create('TYPE', null, $options));
- }
-
- public function testCreateUsesTypeNameIfTypeGivenAsObject()
- {
- $options = array('a' => '1', 'b' => '2');
- $resolvedType = $this->getMockResolvedType();
- $builder = $this->getMockFormBuilder();
-
- $resolvedType->expects($this->once())
- ->method('getName')
- ->will($this->returnValue('TYPE'));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'TYPE', $options)
- ->will($this->returnValue($builder));
-
- $builder->expects($this->once())
- ->method('getForm')
- ->will($this->returnValue('FORM'));
-
- $this->assertSame('FORM', $this->factory->create($resolvedType, null, $options));
- }
-
- public function testCreateNamed()
- {
- $options = array('a' => '1', 'b' => '2');
- $resolvedType = $this->getMockResolvedType();
- $builder = $this->getMockFormBuilder();
-
- $this->registry->expects($this->once())
- ->method('getType')
- ->with('type')
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->once())
- ->method('createBuilder')
- ->with($this->factory, 'name', $options)
- ->will($this->returnValue($builder));
-
- $builder->expects($this->once())
- ->method('getForm')
- ->will($this->returnValue('FORM'));
-
- $this->assertSame('FORM', $this->factory->createNamed('name', 'type', null, $options));
- }
-
- public function testCreateBuilderForPropertyWithoutTypeGuesser()
- {
- $registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface');
- $factory = $this->getMockBuilder('Symfony\Component\Form\FormFactory')
- ->setMethods(array('createNamedBuilder'))
- ->setConstructorArgs(array($registry, $this->resolvedTypeFactory))
- ->getMock();
-
- $factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('firstName', 'text', null, array())
- ->will($this->returnValue('builderInstance'));
-
- $builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
-
- $this->assertEquals('builderInstance', $builder);
- }
-
- public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence()
- {
- $this->guesser1->expects($this->once())
- ->method('guessType')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new TypeGuess(
- 'text',
- array('max_length' => 10),
- Guess::MEDIUM_CONFIDENCE
- )));
-
- $this->guesser2->expects($this->once())
- ->method('guessType')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new TypeGuess(
- 'password',
- array('max_length' => 7),
- Guess::HIGH_CONFIDENCE
- )));
-
- $factory = $this->getMockFactory(array('createNamedBuilder'));
-
- $factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('firstName', 'password', null, array('max_length' => 7))
- ->will($this->returnValue('builderInstance'));
-
- $builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
-
- $this->assertEquals('builderInstance', $builder);
- }
-
- public function testCreateBuilderCreatesTextFormIfNoGuess()
- {
- $this->guesser1->expects($this->once())
- ->method('guessType')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(null));
-
- $factory = $this->getMockFactory(array('createNamedBuilder'));
-
- $factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('firstName', 'text')
- ->will($this->returnValue('builderInstance'));
-
- $builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
-
- $this->assertEquals('builderInstance', $builder);
- }
-
- public function testOptionsCanBeOverridden()
- {
- $this->guesser1->expects($this->once())
- ->method('guessType')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new TypeGuess(
- 'text',
- array('max_length' => 10),
- Guess::MEDIUM_CONFIDENCE
- )));
-
- $factory = $this->getMockFactory(array('createNamedBuilder'));
-
- $factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('firstName', 'text', null, array('max_length' => 11))
- ->will($this->returnValue('builderInstance'));
-
- $builder = $factory->createBuilderForProperty(
- 'Application\Author',
- 'firstName',
- null,
- array('max_length' => 11)
- );
-
- $this->assertEquals('builderInstance', $builder);
- }
-
- public function testCreateBuilderUsesMaxLengthIfFound()
- {
- $this->guesser1->expects($this->once())
- ->method('guessMaxLength')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new ValueGuess(
- 15,
- Guess::MEDIUM_CONFIDENCE
- )));
-
- $this->guesser2->expects($this->once())
- ->method('guessMaxLength')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new ValueGuess(
- 20,
- Guess::HIGH_CONFIDENCE
- )));
-
- $factory = $this->getMockFactory(array('createNamedBuilder'));
-
- $factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('firstName', 'text', null, array('max_length' => 20))
- ->will($this->returnValue('builderInstance'));
-
- $builder = $factory->createBuilderForProperty(
- 'Application\Author',
- 'firstName'
- );
-
- $this->assertEquals('builderInstance', $builder);
- }
-
- public function testCreateBuilderUsesRequiredSettingWithHighestConfidence()
- {
- $this->guesser1->expects($this->once())
- ->method('guessRequired')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new ValueGuess(
- true,
- Guess::MEDIUM_CONFIDENCE
- )));
-
- $this->guesser2->expects($this->once())
- ->method('guessRequired')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new ValueGuess(
- false,
- Guess::HIGH_CONFIDENCE
- )));
-
- $factory = $this->getMockFactory(array('createNamedBuilder'));
-
- $factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('firstName', 'text', null, array('required' => false))
- ->will($this->returnValue('builderInstance'));
-
- $builder = $factory->createBuilderForProperty(
- 'Application\Author',
- 'firstName'
- );
-
- $this->assertEquals('builderInstance', $builder);
- }
-
- public function testCreateBuilderUsesPatternIfFound()
- {
- $this->guesser1->expects($this->once())
- ->method('guessPattern')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new ValueGuess(
- '[a-z]',
- Guess::MEDIUM_CONFIDENCE
- )));
-
- $this->guesser2->expects($this->once())
- ->method('guessPattern')
- ->with('Application\Author', 'firstName')
- ->will($this->returnValue(new ValueGuess(
- '[a-zA-Z]',
- Guess::HIGH_CONFIDENCE
- )));
-
- $factory = $this->getMockFactory(array('createNamedBuilder'));
-
- $factory->expects($this->once())
- ->method('createNamedBuilder')
- ->with('firstName', 'text', null, array('pattern' => '[a-zA-Z]'))
- ->will($this->returnValue('builderInstance'));
-
- $builder = $factory->createBuilderForProperty(
- 'Application\Author',
- 'firstName'
- );
-
- $this->assertEquals('builderInstance', $builder);
- }
-
- private function getMockFactory(array $methods = array())
- {
- return $this->getMockBuilder('Symfony\Component\Form\FormFactory')
- ->setMethods($methods)
- ->setConstructorArgs(array($this->registry, $this->resolvedTypeFactory))
- ->getMock();
- }
-
- private function getMockResolvedType()
- {
- return $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
- }
-
- private function getMockType()
- {
- return $this->getMock('Symfony\Component\Form\FormTypeInterface');
- }
-
- private function getMockFormBuilder()
- {
- return $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\Test\FormIntegrationTestCase as BaseFormIntegrationTestCase;
-
-/**
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use Symfony\Component\Form\Test\FormIntegrationTestCase instead.
- */
-abstract class FormIntegrationTestCase extends BaseFormIntegrationTestCase
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\Test\FormPerformanceTestCase as BaseFormPerformanceTestCase;
-
-/**
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use Symfony\Component\Form\Test\FormPerformanceTestCase instead.
- */
-abstract class FormPerformanceTestCase extends BaseFormPerformanceTestCase
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\FormRegistry;
-use Symfony\Component\Form\FormTypeGuesserChain;
-use Symfony\Component\Form\Tests\Fixtures\TestExtension;
-use Symfony\Component\Form\Tests\Fixtures\FooSubTypeWithParentInstance;
-use Symfony\Component\Form\Tests\Fixtures\FooSubType;
-use Symfony\Component\Form\Tests\Fixtures\FooTypeBazExtension;
-use Symfony\Component\Form\Tests\Fixtures\FooTypeBarExtension;
-use Symfony\Component\Form\Tests\Fixtures\FooType;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormRegistryTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var FormRegistry
- */
- private $registry;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $resolvedTypeFactory;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $guesser1;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $guesser2;
-
- /**
- * @var TestExtension
- */
- private $extension1;
-
- /**
- * @var TestExtension
- */
- private $extension2;
-
- protected function setUp()
- {
- $this->resolvedTypeFactory = $this->getMock('Symfony\Component\Form\ResolvedFormTypeFactory');
- $this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
- $this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
- $this->extension1 = new TestExtension($this->guesser1);
- $this->extension2 = new TestExtension($this->guesser2);
- $this->registry = new FormRegistry(array(
- $this->extension1,
- $this->extension2,
- ), $this->resolvedTypeFactory);
- }
-
- public function testGetTypeFromExtension()
- {
- $type = new FooType();
- $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
-
- $this->extension2->addType($type);
-
- $this->resolvedTypeFactory->expects($this->once())
- ->method('createResolvedType')
- ->with($type)
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->any())
- ->method('getName')
- ->will($this->returnValue('foo'));
-
- $resolvedType = $this->registry->getType('foo');
-
- $this->assertSame($resolvedType, $this->registry->getType('foo'));
- }
-
- public function testGetTypeWithTypeExtensions()
- {
- $type = new FooType();
- $ext1 = new FooTypeBarExtension();
- $ext2 = new FooTypeBazExtension();
- $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
-
- $this->extension2->addType($type);
- $this->extension1->addTypeExtension($ext1);
- $this->extension2->addTypeExtension($ext2);
-
- $this->resolvedTypeFactory->expects($this->once())
- ->method('createResolvedType')
- ->with($type, array($ext1, $ext2))
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->any())
- ->method('getName')
- ->will($this->returnValue('foo'));
-
- $this->assertSame($resolvedType, $this->registry->getType('foo'));
- }
-
- public function testGetTypeConnectsParent()
- {
- $parentType = new FooType();
- $type = new FooSubType();
- $parentResolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
- $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
-
- $this->extension1->addType($parentType);
- $this->extension2->addType($type);
-
- $this->resolvedTypeFactory->expects($this->at(0))
- ->method('createResolvedType')
- ->with($parentType)
- ->will($this->returnValue($parentResolvedType));
-
- $this->resolvedTypeFactory->expects($this->at(1))
- ->method('createResolvedType')
- ->with($type, array(), $parentResolvedType)
- ->will($this->returnValue($resolvedType));
-
- $parentResolvedType->expects($this->any())
- ->method('getName')
- ->will($this->returnValue('foo'));
-
- $resolvedType->expects($this->any())
- ->method('getName')
- ->will($this->returnValue('foo_sub_type'));
-
- $this->assertSame($resolvedType, $this->registry->getType('foo_sub_type'));
- }
-
- public function testGetTypeConnectsParentIfGetParentReturnsInstance()
- {
- $type = new FooSubTypeWithParentInstance();
- $parentResolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
- $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
-
- $this->extension1->addType($type);
-
- $this->resolvedTypeFactory->expects($this->at(0))
- ->method('createResolvedType')
- ->with($this->isInstanceOf('Symfony\Component\Form\Tests\Fixtures\FooType'))
- ->will($this->returnValue($parentResolvedType));
-
- $this->resolvedTypeFactory->expects($this->at(1))
- ->method('createResolvedType')
- ->with($type, array(), $parentResolvedType)
- ->will($this->returnValue($resolvedType));
-
- $parentResolvedType->expects($this->any())
- ->method('getName')
- ->will($this->returnValue('foo'));
-
- $resolvedType->expects($this->any())
- ->method('getName')
- ->will($this->returnValue('foo_sub_type_parent_instance'));
-
- $this->assertSame($resolvedType, $this->registry->getType('foo_sub_type_parent_instance'));
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testGetTypeThrowsExceptionIfParentNotFound()
- {
- $type = new FooSubType();
-
- $this->extension1->addType($type);
-
- $this->registry->getType($type);
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
- */
- public function testGetTypeThrowsExceptionIfTypeNotFound()
- {
- $this->registry->getType('bar');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testGetTypeThrowsExceptionIfNoString()
- {
- $this->registry->getType(array());
- }
-
- public function testHasTypeAfterLoadingFromExtension()
- {
- $type = new FooType();
- $resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
-
- $this->resolvedTypeFactory->expects($this->once())
- ->method('createResolvedType')
- ->with($type)
- ->will($this->returnValue($resolvedType));
-
- $resolvedType->expects($this->any())
- ->method('getName')
- ->will($this->returnValue('foo'));
-
- $this->assertFalse($this->registry->hasType('foo'));
-
- $this->extension2->addType($type);
-
- $this->assertTrue($this->registry->hasType('foo'));
- }
-
- public function testGetTypeGuesser()
- {
- $expectedGuesser = new FormTypeGuesserChain(array($this->guesser1, $this->guesser2));
-
- $this->assertEquals($expectedGuesser, $this->registry->getTypeGuesser());
-
- $registry = new FormRegistry(
- array($this->getMock('Symfony\Component\Form\FormExtensionInterface')),
- $this->resolvedTypeFactory);
-
- $this->assertNull($registry->getTypeGuesser());
- }
-
- public function testGetExtensions()
- {
- $expectedExtensions = array($this->extension1, $this->extension2);
-
- $this->assertEquals($expectedExtensions, $this->registry->getExtensions());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Test;
-
-class FormRendererTest extends \PHPUnit_Framework_TestCase
-{
- public function testHumanize()
- {
- $renderer = $this->getMockBuilder('Symfony\Component\Form\FormRenderer')
- ->setMethods(null)
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $this->assertEquals('Is active', $renderer->humanize('is_active'));
- $this->assertEquals('Is active', $renderer->humanize('isActive'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests\Guess;
-
-use Symfony\Component\Form\Guess\Guess;
-
-class TestGuess extends Guess {}
-
-class GuessTest extends \PHPUnit_Framework_TestCase
-{
- public function testGetBestGuessReturnsGuessWithHighestConfidence()
- {
- $guess1 = new TestGuess(Guess::MEDIUM_CONFIDENCE);
- $guess2 = new TestGuess(Guess::LOW_CONFIDENCE);
- $guess3 = new TestGuess(Guess::HIGH_CONFIDENCE);
-
- $this->assertSame($guess3, Guess::getBestGuess(array($guess1, $guess2, $guess3)));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testGuessExpectsValidConfidence()
- {
- new TestGuess(5);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\NativeRequestHandler;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class NativeRequestHandlerTest extends AbstractRequestHandlerTest
-{
- private static $serverBackup;
-
- public static function setUpBeforeClass()
- {
- self::$serverBackup = $_SERVER;
- }
-
- protected function setUp()
- {
- parent::setUp();
-
- $_GET = array();
- $_POST = array();
- $_FILES = array();
- $_SERVER = array(
- // PHPUnit needs this entry
- 'SCRIPT_NAME' => self::$serverBackup['SCRIPT_NAME'],
- );
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $_GET = array();
- $_POST = array();
- $_FILES = array();
- $_SERVER = self::$serverBackup;
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
- */
- public function testRequestShouldBeNull()
- {
- $this->requestHandler->handleRequest($this->getMockForm('name', 'GET'), 'request');
- }
-
- public function testMethodOverrideHeaderTakesPrecedenceIfPost()
- {
- $form = $this->getMockForm('param1', 'PUT');
-
- $this->setRequestData('POST', array(
- 'param1' => 'DATA',
- ));
-
- $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT';
-
- $form->expects($this->once())
- ->method('submit')
- ->with('DATA');
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- public function testConvertEmptyUploadedFilesToNull()
- {
- $form = $this->getMockForm('param1', 'POST', false);
-
- $this->setRequestData('POST', array(), array('param1' => array(
- 'name' => '',
- 'type' => '',
- 'tmp_name' => '',
- 'error' => UPLOAD_ERR_NO_FILE,
- 'size' => 0
- )));
-
- $form->expects($this->once())
- ->method('submit')
- ->with($this->identicalTo(null));
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- public function testFixBuggyFilesArray()
- {
- $form = $this->getMockForm('param1', 'POST', false);
-
- $this->setRequestData('POST', array(), array('param1' => array(
- 'name' => array(
- 'field' => 'upload.txt',
- ),
- 'type' => array(
- 'field' => 'text/plain',
- ),
- 'tmp_name' => array(
- 'field' => 'owfdskjasdfsa',
- ),
- 'error' => array(
- 'field' => UPLOAD_ERR_OK,
- ),
- 'size' => array(
- 'field' => 100,
- ),
- )));
-
- $form->expects($this->once())
- ->method('submit')
- ->with(array(
- 'field' => array(
- 'name' => 'upload.txt',
- 'type' => 'text/plain',
- 'tmp_name' => 'owfdskjasdfsa',
- 'error' => UPLOAD_ERR_OK,
- 'size' => 100,
- ),
- ));
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- public function testFixBuggyNestedFilesArray()
- {
- $form = $this->getMockForm('param1', 'POST');
-
- $this->setRequestData('POST', array(), array('param1' => array(
- 'name' => array(
- 'field' => array('subfield' => 'upload.txt'),
- ),
- 'type' => array(
- 'field' => array('subfield' => 'text/plain'),
- ),
- 'tmp_name' => array(
- 'field' => array('subfield' => 'owfdskjasdfsa'),
- ),
- 'error' => array(
- 'field' => array('subfield' => UPLOAD_ERR_OK),
- ),
- 'size' => array(
- 'field' => array('subfield' => 100),
- ),
- )));
-
- $form->expects($this->once())
- ->method('submit')
- ->with(array(
- 'field' => array(
- 'subfield' => array(
- 'name' => 'upload.txt',
- 'type' => 'text/plain',
- 'tmp_name' => 'owfdskjasdfsa',
- 'error' => UPLOAD_ERR_OK,
- 'size' => 100,
- ),
- ),
- ));
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- public function testMethodOverrideHeaderIgnoredIfNotPost()
- {
- $form = $this->getMockForm('param1', 'POST');
-
- $this->setRequestData('GET', array(
- 'param1' => 'DATA',
- ));
-
- $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT';
-
- $form->expects($this->never())
- ->method('submit');
-
- $this->requestHandler->handleRequest($form, $this->request);
- }
-
- protected function setRequestData($method, $data, $files = array())
- {
- if ('GET' === $method) {
- $_GET = $data;
- $_FILES = array();
- } else {
- $_POST = $data;
- $_FILES = $files;
- }
-
- $_SERVER = array(
- 'REQUEST_METHOD' => $method,
- // PHPUnit needs this entry
- 'SCRIPT_NAME' => self::$serverBackup['SCRIPT_NAME'],
- );
- }
-
- protected function getRequestHandler()
- {
- return new NativeRequestHandler();
- }
-
- protected function getMockFile()
- {
- return array(
- 'name' => 'upload.txt',
- 'type' => 'text/plain',
- 'tmp_name' => 'owfdskjasdfsa',
- 'error' => UPLOAD_ERR_OK,
- 'size' => 100,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\ResolvedFormType;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\Form;
-use Symfony\Component\OptionsResolver\OptionsResolverInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $dispatcher;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $factory;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $dataMapper;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\OptionsResolver\OptionsResolver')) {
- $this->markTestSkipped('The "OptionsResolver" component is not available');
- }
-
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
- $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- $this->dataMapper = $this->getMock('Symfony\Component\Form\DataMapperInterface');
- }
-
- public function testCreateBuilder()
- {
- if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) {
- $this->markTestSkipped('This test requires PHPUnit 3.7.');
- }
-
- $parentType = $this->getMockFormType();
- $type = $this->getMockFormType();
- $extension1 = $this->getMockFormTypeExtension();
- $extension2 = $this->getMockFormTypeExtension();
-
- $parentResolvedType = new ResolvedFormType($parentType);
- $resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType);
-
- $test = $this;
- $i = 0;
-
- $assertIndex = function ($index) use (&$i, $test) {
- return function () use (&$i, $test, $index) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals($index, $i, 'Executed at index '.$index);
-
- ++$i;
- };
- };
-
- $assertIndexAndAddOption = function ($index, $option, $default) use ($assertIndex) {
- $assertIndex = $assertIndex($index);
-
- return function (OptionsResolverInterface $resolver) use ($assertIndex, $index, $option, $default) {
- $assertIndex();
-
- $resolver->setDefaults(array($option => $default));
- };
- };
-
- // First the default options are generated for the super type
- $parentType->expects($this->once())
- ->method('setDefaultOptions')
- ->will($this->returnCallback($assertIndexAndAddOption(0, 'a', 'a_default')));
-
- // The form type itself
- $type->expects($this->once())
- ->method('setDefaultOptions')
- ->will($this->returnCallback($assertIndexAndAddOption(1, 'b', 'b_default')));
-
- // And its extensions
- $extension1->expects($this->once())
- ->method('setDefaultOptions')
- ->will($this->returnCallback($assertIndexAndAddOption(2, 'c', 'c_default')));
-
- $extension2->expects($this->once())
- ->method('setDefaultOptions')
- ->will($this->returnCallback($assertIndexAndAddOption(3, 'd', 'd_default')));
-
- $givenOptions = array('a' => 'a_custom', 'c' => 'c_custom');
- $resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default');
-
- // Then the form is built for the super type
- $parentType->expects($this->once())
- ->method('buildForm')
- ->with($this->anything(), $resolvedOptions)
- ->will($this->returnCallback($assertIndex(4)));
-
- // Then the type itself
- $type->expects($this->once())
- ->method('buildForm')
- ->with($this->anything(), $resolvedOptions)
- ->will($this->returnCallback($assertIndex(5)));
-
- // Then its extensions
- $extension1->expects($this->once())
- ->method('buildForm')
- ->with($this->anything(), $resolvedOptions)
- ->will($this->returnCallback($assertIndex(6)));
-
- $extension2->expects($this->once())
- ->method('buildForm')
- ->with($this->anything(), $resolvedOptions)
- ->will($this->returnCallback($assertIndex(7)));
-
- $factory = $this->getMockFormFactory();
- $builder = $resolvedType->createBuilder($factory, 'name', $givenOptions);
-
- $this->assertSame($resolvedType, $builder->getType());
- }
-
- public function testCreateView()
- {
- $parentType = $this->getMockFormType();
- $type = $this->getMockFormType();
- $field1Type = $this->getMockFormType();
- $field2Type = $this->getMockFormType();
- $extension1 = $this->getMockFormTypeExtension();
- $extension2 = $this->getMockFormTypeExtension();
-
- $parentResolvedType = new ResolvedFormType($parentType);
- $resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType);
- $field1ResolvedType = new ResolvedFormType($field1Type);
- $field2ResolvedType = new ResolvedFormType($field2Type);
-
- $options = array('a' => '1', 'b' => '2');
- $form = $this->getBuilder('name', $options)
- ->setCompound(true)
- ->setDataMapper($this->dataMapper)
- ->setType($resolvedType)
- ->add($this->getBuilder('foo')->setType($field1ResolvedType))
- ->add($this->getBuilder('bar')->setType($field2ResolvedType))
- ->getForm();
-
- $test = $this;
- $i = 0;
-
- $assertIndexAndNbOfChildViews = function ($index, $nbOfChildViews) use (&$i, $test) {
- return function (FormView $view) use (&$i, $test, $index, $nbOfChildViews) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals($index, $i, 'Executed at index '.$index);
- $test->assertCount($nbOfChildViews, $view);
-
- ++$i;
- };
- };
-
- // First the super type
- $parentType->expects($this->once())
- ->method('buildView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(0, 0)));
-
- // Then the type itself
- $type->expects($this->once())
- ->method('buildView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(1, 0)));
-
- // Then its extensions
- $extension1->expects($this->once())
- ->method('buildView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(2, 0)));
-
- $extension2->expects($this->once())
- ->method('buildView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(3, 0)));
-
- // Now the first child form
- $field1Type->expects($this->once())
- ->method('buildView')
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(4, 0)));
- $field1Type->expects($this->once())
- ->method('finishView')
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(5, 0)));
-
- // And the second child form
- $field2Type->expects($this->once())
- ->method('buildView')
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(6, 0)));
- $field2Type->expects($this->once())
- ->method('finishView')
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(7, 0)));
-
- // Again first the parent
- $parentType->expects($this->once())
- ->method('finishView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(8, 2)));
-
- // Then the type itself
- $type->expects($this->once())
- ->method('finishView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(9, 2)));
-
- // Then its extensions
- $extension1->expects($this->once())
- ->method('finishView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(10, 2)));
-
- $extension2->expects($this->once())
- ->method('finishView')
- ->with($this->anything(), $form, $options)
- ->will($this->returnCallback($assertIndexAndNbOfChildViews(11, 2)));
-
- $parentView = new FormView();
- $view = $resolvedType->createView($form, $parentView);
-
- $this->assertSame($parentView, $view->parent);
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getMockFormType()
- {
- return $this->getMock('Symfony\Component\Form\FormTypeInterface');
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getMockFormTypeExtension()
- {
- return $this->getMock('Symfony\Component\Form\FormTypeExtensionInterface');
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject
- */
- private function getMockFormFactory()
- {
- return $this->getMock('Symfony\Component\Form\FormFactoryInterface');
- }
-
- /**
- * @param string $name
- * @param array $options
- *
- * @return FormBuilder
- */
- protected function getBuilder($name = 'name', array $options = array())
- {
- return new FormBuilder($name, null, $this->dispatcher, $this->factory, $options);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\Form;
-use Symfony\Component\Form\FormEvent;
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\PropertyAccess\PropertyPath;
-use Symfony\Component\Form\FormConfigBuilder;
-use Symfony\Component\Form\FormError;
-use Symfony\Component\Form\Exception\TransformationFailedException;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
-use Symfony\Component\Form\Tests\Fixtures\FixedFilterListener;
-
-class SimpleFormTest_Countable implements \Countable
-{
- private $count;
-
- public function __construct($count)
- {
- $this->count = $count;
- }
-
- public function count()
- {
- return $this->count;
- }
-}
-
-class SimpleFormTest_Traversable implements \IteratorAggregate
-{
- private $iterator;
-
- public function __construct($count)
- {
- $this->iterator = new \ArrayIterator($count > 0 ? array_fill(0, $count, 'Foo') : array());
- }
-
- public function getIterator()
- {
- return $this->iterator;
- }
-}
-
-class SimpleFormTest extends AbstractFormTest
-{
- public function testDataIsInitializedToConfiguredValue()
- {
- $model = new FixedDataTransformer(array(
- 'default' => 'foo',
- ));
- $view = new FixedDataTransformer(array(
- 'foo' => 'bar',
- ));
-
- $config = new FormConfigBuilder('name', null, $this->dispatcher);
- $config->addViewTransformer($view);
- $config->addModelTransformer($model);
- $config->setData('default');
- $form = new Form($config);
-
- $this->assertSame('default', $form->getData());
- $this->assertSame('foo', $form->getNormData());
- $this->assertSame('bar', $form->getViewData());
- }
-
- // https://github.com/symfony/symfony/commit/d4f4038f6daf7cf88ca7c7ab089473cce5ebf7d8#commitcomment-1632879
- public function testDataIsInitializedFromSubmit()
- {
- $mock = $this->getMockBuilder('\stdClass')
- ->setMethods(array('preSetData', 'preSubmit'))
- ->getMock();
- $mock->expects($this->at(0))
- ->method('preSetData');
- $mock->expects($this->at(1))
- ->method('preSubmit');
-
- $config = new FormConfigBuilder('name', null, $this->dispatcher);
- $config->addEventListener(FormEvents::PRE_SET_DATA, array($mock, 'preSetData'));
- $config->addEventListener(FormEvents::PRE_SUBMIT, array($mock, 'preSubmit'));
- $form = new Form($config);
-
- // no call to setData() or similar where the object would be
- // initialized otherwise
-
- $form->submit('foobar');
- }
-
- // https://github.com/symfony/symfony/pull/7789
- public function testFalseIsConvertedToNull()
- {
- $mock = $this->getMockBuilder('\stdClass')
- ->setMethods(array('preBind'))
- ->getMock();
- $mock->expects($this->once())
- ->method('preBind')
- ->with($this->callback(function ($event) {
- return null === $event->getData();
- }));
-
- $config = new FormConfigBuilder('name', null, $this->dispatcher);
- $config->addEventListener(FormEvents::PRE_BIND, array($mock, 'preBind'));
- $form = new Form($config);
-
- $form->bind(false);
-
- $this->assertTrue($form->isValid());
- $this->assertNull($form->getData());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
- */
- public function testSubmitThrowsExceptionIfAlreadySubmitted()
- {
- $this->form->submit(array());
- $this->form->submit(array());
- }
-
- public function testSubmitIsIgnoredIfDisabled()
- {
- $form = $this->getBuilder()
- ->setDisabled(true)
- ->setData('initial')
- ->getForm();
-
- $form->submit('new');
-
- $this->assertEquals('initial', $form->getData());
- $this->assertTrue($form->isSubmitted());
- }
-
- public function testNeverRequiredIfParentNotRequired()
- {
- $parent = $this->getBuilder()->setRequired(false)->getForm();
- $child = $this->getBuilder()->setRequired(true)->getForm();
-
- $child->setParent($parent);
-
- $this->assertFalse($child->isRequired());
- }
-
- public function testRequired()
- {
- $parent = $this->getBuilder()->setRequired(true)->getForm();
- $child = $this->getBuilder()->setRequired(true)->getForm();
-
- $child->setParent($parent);
-
- $this->assertTrue($child->isRequired());
- }
-
- public function testNotRequired()
- {
- $parent = $this->getBuilder()->setRequired(true)->getForm();
- $child = $this->getBuilder()->setRequired(false)->getForm();
-
- $child->setParent($parent);
-
- $this->assertFalse($child->isRequired());
- }
-
- public function testAlwaysDisabledIfParentDisabled()
- {
- $parent = $this->getBuilder()->setDisabled(true)->getForm();
- $child = $this->getBuilder()->setDisabled(false)->getForm();
-
- $child->setParent($parent);
-
- $this->assertTrue($child->isDisabled());
- }
-
- public function testDisabled()
- {
- $parent = $this->getBuilder()->setDisabled(false)->getForm();
- $child = $this->getBuilder()->setDisabled(true)->getForm();
-
- $child->setParent($parent);
-
- $this->assertTrue($child->isDisabled());
- }
-
- public function testNotDisabled()
- {
- $parent = $this->getBuilder()->setDisabled(false)->getForm();
- $child = $this->getBuilder()->setDisabled(false)->getForm();
-
- $child->setParent($parent);
-
- $this->assertFalse($child->isDisabled());
- }
-
- public function testGetRootReturnsRootOfParent()
- {
- $parent = $this->getMockForm();
- $parent->expects($this->once())
- ->method('getRoot')
- ->will($this->returnValue('ROOT'));
-
- $this->form->setParent($parent);
-
- $this->assertEquals('ROOT', $this->form->getRoot());
- }
-
- public function testGetRootReturnsSelfIfNoParent()
- {
- $this->assertSame($this->form, $this->form->getRoot());
- }
-
- public function testEmptyIfEmptyArray()
- {
- $this->form->setData(array());
-
- $this->assertTrue($this->form->isEmpty());
- }
-
- public function testEmptyIfEmptyCountable()
- {
- $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher));
-
- $this->form->setData(new SimpleFormTest_Countable(0));
-
- $this->assertTrue($this->form->isEmpty());
- }
-
- public function testNotEmptyIfFilledCountable()
- {
- $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher));
-
- $this->form->setData(new SimpleFormTest_Countable(1));
-
- $this->assertFalse($this->form->isEmpty());
- }
-
- public function testEmptyIfEmptyTraversable()
- {
- $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher));
-
- $this->form->setData(new SimpleFormTest_Traversable(0));
-
- $this->assertTrue($this->form->isEmpty());
- }
-
- public function testNotEmptyIfFilledTraversable()
- {
- $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher));
-
- $this->form->setData(new SimpleFormTest_Traversable(1));
-
- $this->assertFalse($this->form->isEmpty());
- }
-
- public function testEmptyIfNull()
- {
- $this->form->setData(null);
-
- $this->assertTrue($this->form->isEmpty());
- }
-
- public function testEmptyIfEmptyString()
- {
- $this->form->setData('');
-
- $this->assertTrue($this->form->isEmpty());
- }
-
- public function testNotEmptyIfText()
- {
- $this->form->setData('foobar');
-
- $this->assertFalse($this->form->isEmpty());
- }
-
- public function testValidIfSubmitted()
- {
- $form = $this->getBuilder()->getForm();
- $form->submit('foobar');
-
- $this->assertTrue($form->isValid());
- }
-
- public function testValidIfSubmittedAndDisabled()
- {
- $form = $this->getBuilder()->setDisabled(true)->getForm();
- $form->submit('foobar');
-
- $this->assertTrue($form->isValid());
- }
-
- public function testNotValidIfNotSubmitted()
- {
- $this->assertFalse($this->form->isValid());
- }
-
- public function testNotValidIfErrors()
- {
- $form = $this->getBuilder()->getForm();
- $form->submit('foobar');
- $form->addError(new FormError('Error!'));
-
- $this->assertFalse($form->isValid());
- }
-
- public function testHasErrors()
- {
- $this->form->addError(new FormError('Error!'));
-
- $this->assertCount(1, $this->form->getErrors());
- }
-
- public function testHasNoErrors()
- {
- $this->assertCount(0, $this->form->getErrors());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
- */
- public function testSetParentThrowsExceptionIfAlreadySubmitted()
- {
- $this->form->submit(array());
- $this->form->setParent($this->getBuilder('parent')->getForm());
- }
-
- public function testSubmitted()
- {
- $form = $this->getBuilder()->getForm();
- $form->submit('foobar');
-
- $this->assertTrue($form->isSubmitted());
- }
-
- public function testNotSubmitted()
- {
- $this->assertFalse($this->form->isSubmitted());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\AlreadySubmittedException
- */
- public function testSetDataThrowsExceptionIfAlreadySubmitted()
- {
- $this->form->submit(array());
- $this->form->setData(null);
- }
-
- public function testSetDataClonesObjectIfNotByReference()
- {
- $data = new \stdClass();
- $form = $this->getBuilder('name', null, '\stdClass')->setByReference(false)->getForm();
- $form->setData($data);
-
- $this->assertNotSame($data, $form->getData());
- $this->assertEquals($data, $form->getData());
- }
-
- public function testSetDataDoesNotCloneObjectIfByReference()
- {
- $data = new \stdClass();
- $form = $this->getBuilder('name', null, '\stdClass')->setByReference(true)->getForm();
- $form->setData($data);
-
- $this->assertSame($data, $form->getData());
- }
-
- public function testSetDataExecutesTransformationChain()
- {
- // use real event dispatcher now
- $form = $this->getBuilder('name', new EventDispatcher())
- ->addEventSubscriber(new FixedFilterListener(array(
- 'preSetData' => array(
- 'app' => 'filtered',
- ),
- )))
- ->addModelTransformer(new FixedDataTransformer(array(
- '' => '',
- 'filtered' => 'norm',
- )))
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'norm' => 'client',
- )))
- ->getForm();
-
- $form->setData('app');
-
- $this->assertEquals('filtered', $form->getData());
- $this->assertEquals('norm', $form->getNormData());
- $this->assertEquals('client', $form->getViewData());
- }
-
- public function testSetDataExecutesViewTransformersInOrder()
- {
- $form = $this->getBuilder()
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'first' => 'second',
- )))
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'second' => 'third',
- )))
- ->getForm();
-
- $form->setData('first');
-
- $this->assertEquals('third', $form->getViewData());
- }
-
- public function testSetDataExecutesModelTransformersInReverseOrder()
- {
- $form = $this->getBuilder()
- ->addModelTransformer(new FixedDataTransformer(array(
- '' => '',
- 'second' => 'third',
- )))
- ->addModelTransformer(new FixedDataTransformer(array(
- '' => '',
- 'first' => 'second',
- )))
- ->getForm();
-
- $form->setData('first');
-
- $this->assertEquals('third', $form->getNormData());
- }
-
- /*
- * When there is no data transformer, the data must have the same format
- * in all three representations
- */
- public function testSetDataConvertsScalarToStringIfNoTransformer()
- {
- $form = $this->getBuilder()->getForm();
-
- $form->setData(1);
-
- $this->assertSame('1', $form->getData());
- $this->assertSame('1', $form->getNormData());
- $this->assertSame('1', $form->getViewData());
- }
-
- /*
- * Data in client format should, if possible, always be a string to
- * facilitate differentiation between '0' and ''
- */
- public function testSetDataConvertsScalarToStringIfOnlyModelTransformer()
- {
- $form = $this->getBuilder()
- ->addModelTransformer(new FixedDataTransformer(array(
- '' => '',
- 1 => 23,
- )))
- ->getForm();
-
- $form->setData(1);
-
- $this->assertSame(1, $form->getData());
- $this->assertSame(23, $form->getNormData());
- $this->assertSame('23', $form->getViewData());
- }
-
- /*
- * NULL remains NULL in app and norm format to remove the need to treat
- * empty values and NULL explicitly in the application
- */
- public function testSetDataConvertsNullToStringIfNoTransformer()
- {
- $form = $this->getBuilder()->getForm();
-
- $form->setData(null);
-
- $this->assertNull($form->getData());
- $this->assertNull($form->getNormData());
- $this->assertSame('', $form->getViewData());
- }
-
- public function testSetDataIsIgnoredIfDataIsLocked()
- {
- $form = $this->getBuilder()
- ->setData('default')
- ->setDataLocked(true)
- ->getForm();
-
- $form->setData('foobar');
-
- $this->assertSame('default', $form->getData());
- }
-
- public function testSubmitConvertsEmptyToNullIfNoTransformer()
- {
- $form = $this->getBuilder()->getForm();
-
- $form->submit('');
-
- $this->assertNull($form->getData());
- $this->assertNull($form->getNormData());
- $this->assertSame('', $form->getViewData());
- }
-
- public function testSubmitExecutesTransformationChain()
- {
- // use real event dispatcher now
- $form = $this->getBuilder('name', new EventDispatcher())
- ->addEventSubscriber(new FixedFilterListener(array(
- 'preSubmit' => array(
- 'client' => 'filteredclient',
- ),
- 'onSubmit' => array(
- 'norm' => 'filterednorm',
- ),
- )))
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- // direction is reversed!
- 'norm' => 'filteredclient',
- 'filterednorm' => 'cleanedclient'
- )))
- ->addModelTransformer(new FixedDataTransformer(array(
- '' => '',
- // direction is reversed!
- 'app' => 'filterednorm',
- )))
- ->getForm();
-
- $form->submit('client');
-
- $this->assertEquals('app', $form->getData());
- $this->assertEquals('filterednorm', $form->getNormData());
- $this->assertEquals('cleanedclient', $form->getViewData());
- }
-
- public function testSubmitExecutesViewTransformersInReverseOrder()
- {
- $form = $this->getBuilder()
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'third' => 'second',
- )))
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'second' => 'first',
- )))
- ->getForm();
-
- $form->submit('first');
-
- $this->assertEquals('third', $form->getNormData());
- }
-
- public function testSubmitExecutesModelTransformersInOrder()
- {
- $form = $this->getBuilder()
- ->addModelTransformer(new FixedDataTransformer(array(
- '' => '',
- 'second' => 'first',
- )))
- ->addModelTransformer(new FixedDataTransformer(array(
- '' => '',
- 'third' => 'second',
- )))
- ->getForm();
-
- $form->submit('first');
-
- $this->assertEquals('third', $form->getData());
- }
-
- public function testSynchronizedByDefault()
- {
- $this->assertTrue($this->form->isSynchronized());
- }
-
- public function testSynchronizedAfterSubmission()
- {
- $this->form->submit('foobar');
-
- $this->assertTrue($this->form->isSynchronized());
- }
-
- public function testNotSynchronizedIfViewReverseTransformationFailed()
- {
- $transformer = $this->getDataTransformer();
- $transformer->expects($this->once())
- ->method('reverseTransform')
- ->will($this->throwException(new TransformationFailedException()));
-
- $form = $this->getBuilder()
- ->addViewTransformer($transformer)
- ->getForm();
-
- $form->submit('foobar');
-
- $this->assertFalse($form->isSynchronized());
- }
-
- public function testNotSynchronizedIfModelReverseTransformationFailed()
- {
- $transformer = $this->getDataTransformer();
- $transformer->expects($this->once())
- ->method('reverseTransform')
- ->will($this->throwException(new TransformationFailedException()));
-
- $form = $this->getBuilder()
- ->addModelTransformer($transformer)
- ->getForm();
-
- $form->submit('foobar');
-
- $this->assertFalse($form->isSynchronized());
- }
-
- public function testEmptyDataCreatedBeforeTransforming()
- {
- $form = $this->getBuilder()
- ->setEmptyData('foo')
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- // direction is reversed!
- 'bar' => 'foo',
- )))
- ->getForm();
-
- $form->submit('');
-
- $this->assertEquals('bar', $form->getData());
- }
-
- public function testEmptyDataFromClosure()
- {
- $test = $this;
- $form = $this->getBuilder()
- ->setEmptyData(function ($form) use ($test) {
- // the form instance is passed to the closure to allow use
- // of form data when creating the empty value
- $test->assertInstanceOf('Symfony\Component\Form\FormInterface', $form);
-
- return 'foo';
- })
- ->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- // direction is reversed!
- 'bar' => 'foo',
- )))
- ->getForm();
-
- $form->submit('');
-
- $this->assertEquals('bar', $form->getData());
- }
-
- public function testSubmitResetsErrors()
- {
- $this->form->addError(new FormError('Error!'));
- $this->form->submit('foobar');
-
- $this->assertSame(array(), $this->form->getErrors());
- }
-
- public function testCreateView()
- {
- $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
- $view = $this->getMock('Symfony\Component\Form\FormView');
- $form = $this->getBuilder()->setType($type)->getForm();
-
- $type->expects($this->once())
- ->method('createView')
- ->with($form)
- ->will($this->returnValue($view));
-
- $this->assertSame($view, $form->createView());
- }
-
- public function testCreateViewWithParent()
- {
- $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
- $view = $this->getMock('Symfony\Component\Form\FormView');
- $parentForm = $this->getMock('Symfony\Component\Form\Test\FormInterface');
- $parentView = $this->getMock('Symfony\Component\Form\FormView');
- $form = $this->getBuilder()->setType($type)->getForm();
- $form->setParent($parentForm);
-
- $parentForm->expects($this->once())
- ->method('createView')
- ->will($this->returnValue($parentView));
-
- $type->expects($this->once())
- ->method('createView')
- ->with($form, $parentView)
- ->will($this->returnValue($view));
-
- $this->assertSame($view, $form->createView());
- }
-
- public function testCreateViewWithExplicitParent()
- {
- $type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
- $view = $this->getMock('Symfony\Component\Form\FormView');
- $parentView = $this->getMock('Symfony\Component\Form\FormView');
- $form = $this->getBuilder()->setType($type)->getForm();
-
- $type->expects($this->once())
- ->method('createView')
- ->with($form, $parentView)
- ->will($this->returnValue($view));
-
- $this->assertSame($view, $form->createView($parentView));
- }
-
- public function testGetErrorsAsString()
- {
- $this->form->addError(new FormError('Error!'));
-
- $this->assertEquals("ERROR: Error!\n", $this->form->getErrorsAsString());
- }
-
- public function testFormCanHaveEmptyName()
- {
- $form = $this->getBuilder('')->getForm();
-
- $this->assertEquals('', $form->getName());
- }
-
- public function testSetNullParentWorksWithEmptyName()
- {
- $form = $this->getBuilder('')->getForm();
- $form->setParent(null);
-
- $this->assertNull($form->getParent());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\LogicException
- * @expectedExceptionMessage A form with an empty name cannot have a parent form.
- */
- public function testFormCannotHaveEmptyNameNotInRootLevel()
- {
- $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->add($this->getBuilder(''))
- ->getForm();
- }
-
- public function testGetPropertyPathReturnsConfiguredPath()
- {
- $form = $this->getBuilder()->setPropertyPath('address.street')->getForm();
-
- $this->assertEquals(new PropertyPath('address.street'), $form->getPropertyPath());
- }
-
- // see https://github.com/symfony/symfony/issues/3903
- public function testGetPropertyPathDefaultsToNameIfParentHasDataClass()
- {
- $parent = $this->getBuilder(null, null, 'stdClass')
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getBuilder('name')->getForm();
- $parent->add($form);
-
- $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath());
- }
-
- // see https://github.com/symfony/symfony/issues/3903
- public function testGetPropertyPathDefaultsToIndexedNameIfParentDataClassIsNull()
- {
- $parent = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getBuilder('name')->getForm();
- $parent->add($form);
-
- $this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath());
- }
-
- public function testGetPropertyPathDefaultsToNameIfFirstParentWithoutInheritDataHasDataClass()
- {
- $grandParent = $this->getBuilder(null, null, 'stdClass')
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $parent = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->setInheritData(true)
- ->getForm();
- $form = $this->getBuilder('name')->getForm();
- $grandParent->add($parent);
- $parent->add($form);
-
- $this->assertEquals(new PropertyPath('name'), $form->getPropertyPath());
- }
-
- public function testGetPropertyPathDefaultsToIndexedNameIfDataClassOfFirstParentWithoutInheritDataIsNull()
- {
- $grandParent = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $parent = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->setInheritData(true)
- ->getForm();
- $form = $this->getBuilder('name')->getForm();
- $grandParent->add($parent);
- $parent->add($form);
-
- $this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\LogicException
- */
- public function testViewDataMustNotBeObjectIfDataClassIsNull()
- {
- $config = new FormConfigBuilder('name', null, $this->dispatcher);
- $config->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'foo' => new \stdClass(),
- )));
- $form = new Form($config);
-
- $form->setData('foo');
- }
-
- public function testViewDataMayBeArrayAccessIfDataClassIsNull()
- {
- $arrayAccess = $this->getMock('\ArrayAccess');
- $config = new FormConfigBuilder('name', null, $this->dispatcher);
- $config->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'foo' => $arrayAccess,
- )));
- $form = new Form($config);
-
- $form->setData('foo');
-
- $this->assertSame($arrayAccess, $form->getViewData());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\LogicException
- */
- public function testViewDataMustBeObjectIfDataClassIsSet()
- {
- $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher);
- $config->addViewTransformer(new FixedDataTransformer(array(
- '' => '',
- 'foo' => array('bar' => 'baz'),
- )));
- $form = new Form($config);
-
- $form->setData('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\RuntimeException
- */
- public function testSetDataCannotInvokeItself()
- {
- // Cycle detection to prevent endless loops
- $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher);
- $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
- $event->getForm()->setData('bar');
- });
- $form = new Form($config);
-
- $form->setData('foo');
- }
-
- public function testSubmittingWrongDataIsIgnored()
- {
- $test = $this;
-
- $child = $this->getBuilder('child', $this->dispatcher);
- $child->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($test) {
- // child form doesn't receive the wrong data that is submitted on parent
- $test->assertNull($event->getData());
- });
-
- $parent = $this->getBuilder('parent', new EventDispatcher())
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->add($child)
- ->getForm();
-
- $parent->submit('not-an-array');
- }
-
- public function testHandleRequestForwardsToRequestHandler()
- {
- $handler = $this->getMock('Symfony\Component\Form\RequestHandlerInterface');
-
- $form = $this->getBuilder()
- ->setRequestHandler($handler)
- ->getForm();
-
- $handler->expects($this->once())
- ->method('handleRequest')
- ->with($this->identicalTo($form), 'REQUEST');
-
- $this->assertSame($form, $form->handleRequest('REQUEST'));
- }
-
- public function testFormInheritsParentData()
- {
- $child = $this->getBuilder('child')
- ->setInheritData(true);
-
- $parent = $this->getBuilder('parent')
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->setData('foo')
- ->addModelTransformer(new FixedDataTransformer(array(
- 'foo' => 'norm[foo]',
- )))
- ->addViewTransformer(new FixedDataTransformer(array(
- 'norm[foo]' => 'view[foo]',
- )))
- ->add($child)
- ->getForm();
-
- $this->assertSame('foo', $parent->get('child')->getData());
- $this->assertSame('norm[foo]', $parent->get('child')->getNormData());
- $this->assertSame('view[foo]', $parent->get('child')->getViewData());
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\RuntimeException
- */
- public function testInheritDataDisallowsSetData()
- {
- $form = $this->getBuilder()
- ->setInheritData(true)
- ->getForm();
-
- $form->setData('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\RuntimeException
- */
- public function testGetDataRequiresParentToBeSetIfInheritData()
- {
- $form = $this->getBuilder()
- ->setInheritData(true)
- ->getForm();
-
- $form->getData();
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\RuntimeException
- */
- public function testGetNormDataRequiresParentToBeSetIfInheritData()
- {
- $form = $this->getBuilder()
- ->setInheritData(true)
- ->getForm();
-
- $form->getNormData();
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\RuntimeException
- */
- public function testGetViewDataRequiresParentToBeSetIfInheritData()
- {
- $form = $this->getBuilder()
- ->setInheritData(true)
- ->getForm();
-
- $form->getViewData();
- }
-
- public function testPostSubmitDataIsNullIfInheritData()
- {
- $test = $this;
- $form = $this->getBuilder()
- ->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($test) {
- $test->assertNull($event->getData());
- })
- ->setInheritData(true)
- ->getForm();
-
- $form->submit('foo');
- }
-
- public function testSubmitIsNeverFiredIfInheritData()
- {
- $test = $this;
- $form = $this->getBuilder()
- ->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use ($test) {
- $test->fail('The SUBMIT event should not be fired');
- })
- ->setInheritData(true)
- ->getForm();
-
- $form->submit('foo');
- }
-
- public function testInitializeSetsDefaultData()
- {
- $config = $this->getBuilder()->setData('DEFAULT')->getFormConfig();
- $form = $this->getMock('Symfony\Component\Form\Form', array('setData'), array($config));
-
- $form->expects($this->once())
- ->method('setData')
- ->with($this->identicalTo('DEFAULT'));
-
- /* @var Form $form */
- $form->initialize();
- }
-
- /**
- * @expectedException \Symfony\Component\Form\Exception\RuntimeException
- */
- public function testInitializeFailsIfParent()
- {
- $parent = $this->getBuilder()->setRequired(false)->getForm();
- $child = $this->getBuilder()->setRequired(true)->getForm();
-
- $child->setParent($parent);
-
- $child->initialize();
- }
-
- protected function createForm()
- {
- return $this->getBuilder()->getForm();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Util;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormUtil
-{
- /**
- * This class should not be instantiated
- */
- private function __construct() {}
-
- /**
- * Returns whether the given data is empty.
- *
- * This logic is reused multiple times throughout the processing of
- * a form and needs to be consistent. PHP's keyword `empty` cannot
- * be used as it also considers 0 and "0" to be empty.
- *
- * @param mixed $data
- *
- * @return Boolean
- */
- public static function isEmpty($data)
- {
- // Should not do a check for array() === $data!!!
- // This method is used in occurrences where arrays are
- // not considered to be empty, ever.
- return null === $data || '' === $data;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Util;
-
-/**
- * Iterator that returns only forms from a form tree that do not inherit their
- * parent data.
- *
- * If the iterator encounters a form that inherits its parent data, it enters
- * the form and traverses its children as well.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class InheritDataAwareIterator extends VirtualFormAwareIterator
-{
- /**
- * Creates a new iterator.
- *
- * @param \Symfony\Component\Form\FormInterface[] $forms An array
- */
- public function __construct(array $forms)
- {
- // Skip the deprecation error
- \ArrayIterator::__construct($forms);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Util;
-
-/**
- * Iterator that returns only forms from a form tree that do not inherit their
- * parent data.
- *
- * If the iterator encounters a form that inherits its parent data, it enters
- * the form and traverses its children as well.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link InheritDataAwareIterator} instead.
- */
-class VirtualFormAwareIterator extends \ArrayIterator implements \RecursiveIterator
-{
- /**
- * Creates a new iterator.
- *
- * @param \Symfony\Component\Form\FormInterface[] $forms An array
- */
- public function __construct(array $forms)
- {
- // Uncomment this as soon as the deprecation note should be shown
- // trigger_error('VirtualFormAwareIterator is deprecated since version 2.3 and will be removed in 3.0. Use InheritDataAwareIterator instead.', E_USER_DEPRECATED);
-
- parent::__construct($forms);
- }
-
- public function getChildren()
- {
- return new static($this->current()->all());
- }
-
- public function hasChildren()
- {
- return $this->current()->getConfig()->getInheritData();
- }
-}
+++ /dev/null
-{
- "name": "symfony/form",
- "type": "library",
- "description": "Symfony Form Component",
- "keywords": [],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3",
- "symfony/event-dispatcher": "~2.1",
- "symfony/intl": "~2.3",
- "symfony/options-resolver": "~2.1",
- "symfony/property-access": "~2.2"
- },
- "require-dev": {
- "symfony/validator": "~2.2",
- "symfony/http-foundation": "~2.2"
- },
- "suggest": {
- "symfony/validator": "",
- "symfony/http-foundation": ""
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\Form\\": "" }
- },
- "target-dir": "Symfony/Component/Form",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony Form Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./Tests</directory>
- <directory>./vendor</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Icu;
-
-use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
-
-/**
- * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\CurrencyBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuCurrencyBundle extends CurrencyBundle
-{
- public function __construct(StructuredBundleReaderInterface $reader)
- {
- parent::__construct(realpath(IcuData::getResourceDirectory() . '/curr'), $reader);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Icu;
-
-use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuData
-{
- /**
- * Returns the version of the bundled ICU data.
- *
- * @return string The version string.
- */
- public static function getVersion()
- {
- return trim(file_get_contents(__DIR__ . '/Resources/data/version.txt'));
- }
-
- /**
- * Returns whether the ICU data is stubbed.
- *
- * @return Boolean Returns true if the ICU data is stubbed, false if it is
- * loaded from ICU .res files.
- */
- public static function isStubbed()
- {
- return true;
- }
-
- /**
- * Returns the path to the directory where the resource bundles are stored.
- *
- * @return string The absolute path to the resource directory.
- */
- public static function getResourceDirectory()
- {
- return realpath(__DIR__ . '/Resources/data');
- }
-
- /**
- * Returns a reader for reading resource bundles in this component.
- *
- * @return \Symfony\Component\Intl\ResourceBundle\Reader\BundleReaderInterface
- */
- public static function getBundleReader()
- {
- return new PhpBundleReader();
- }
-
- /**
- * This class must not be instantiated.
- */
- private function __construct() {}
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Icu;
-
-use Symfony\Component\Intl\ResourceBundle\LanguageBundle;
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
-
-/**
- * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuLanguageBundle extends LanguageBundle
-{
- public function __construct(StructuredBundleReaderInterface $reader)
- {
- parent::__construct(realpath(IcuData::getResourceDirectory() . '/lang'), $reader);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Icu;
-
-use Symfony\Component\Intl\ResourceBundle\LocaleBundle;
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
-
-/**
- * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\LocaleBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuLocaleBundle extends LocaleBundle
-{
- public function __construct(StructuredBundleReaderInterface $reader)
- {
- parent::__construct(realpath(IcuData::getResourceDirectory() . '/locales'), $reader);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Icu;
-
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
-use Symfony\Component\Intl\ResourceBundle\RegionBundle;
-
-/**
- * A stub implementation of {@link \Symfony\Component\Intl\ResourceBundle\RegionBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuRegionBundle extends RegionBundle
-{
- public function __construct(StructuredBundleReaderInterface $reader)
- {
- parent::__construct(realpath(IcuData::getResourceDirectory() . '/region'), $reader);
- }
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-Icu Component
-=============
-
-Contains data of the ICU library in a specific version.
-
-You should not directly use this component. Use it through the API of the
-[Intl component] [1] instead.
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/Icu/
- $ composer.phar install --dev
- $ phpunit
-
-[1]: https://github.com/symfony/Intl
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return array(
- 'Currencies' => array(
- 'XUA' => array(
- 0 => 'ADB Unit of Account',
- 1 => 'XUA',
- 2 => 2,
- 3 => 0,
- ),
- 'AFN' => array(
- 0 => 'Afghan Afghani',
- 1 => 'AFN',
- 2 => 0,
- 3 => 0,
- ),
- 'AFA' => array(
- 0 => 'Afghan Afghani (1927-2002)',
- 1 => 'AFA',
- 2 => 2,
- 3 => 0,
- ),
- 'ALL' => array(
- 0 => 'Albanian Lek',
- 1 => 'ALL',
- 2 => 0,
- 3 => 0,
- ),
- 'ALK' => array(
- 0 => 'Albanian Lek (1946-1965)',
- 1 => 'ALK',
- 2 => 2,
- 3 => 0,
- ),
- 'DZD' => array(
- 0 => 'Algerian Dinar',
- 1 => 'DZD',
- 2 => 2,
- 3 => 0,
- ),
- 'ADP' => array(
- 0 => 'Andorran Peseta',
- 1 => 'ADP',
- 2 => 0,
- 3 => 0,
- ),
- 'AOA' => array(
- 0 => 'Angolan Kwanza',
- 1 => 'AOA',
- 2 => 2,
- 3 => 0,
- ),
- 'AOK' => array(
- 0 => 'Angolan Kwanza (1977-1991)',
- 1 => 'AOK',
- 2 => 2,
- 3 => 0,
- ),
- 'AON' => array(
- 0 => 'Angolan New Kwanza (1990-2000)',
- 1 => 'AON',
- 2 => 2,
- 3 => 0,
- ),
- 'AOR' => array(
- 0 => 'Angolan Readjusted Kwanza (1995-1999)',
- 1 => 'AOR',
- 2 => 2,
- 3 => 0,
- ),
- 'ARA' => array(
- 0 => 'Argentine Austral',
- 1 => 'ARA',
- 2 => 2,
- 3 => 0,
- ),
- 'ARS' => array(
- 0 => 'Argentine Peso',
- 1 => 'ARS',
- 2 => 2,
- 3 => 0,
- ),
- 'ARM' => array(
- 0 => 'Argentine Peso (1881-1970)',
- 1 => 'ARM',
- 2 => 2,
- 3 => 0,
- ),
- 'ARP' => array(
- 0 => 'Argentine Peso (1983-1985)',
- 1 => 'ARP',
- 2 => 2,
- 3 => 0,
- ),
- 'ARL' => array(
- 0 => 'Argentine Peso Ley (1970-1983)',
- 1 => 'ARL',
- 2 => 2,
- 3 => 0,
- ),
- 'AMD' => array(
- 0 => 'Armenian Dram',
- 1 => 'AMD',
- 2 => 0,
- 3 => 0,
- ),
- 'AWG' => array(
- 0 => 'Aruban Florin',
- 1 => 'AWG',
- 2 => 2,
- 3 => 0,
- ),
- 'AUD' => array(
- 0 => 'Australian Dollar',
- 1 => 'A$',
- 2 => 2,
- 3 => 0,
- ),
- 'ATS' => array(
- 0 => 'Austrian Schilling',
- 1 => 'ATS',
- 2 => 2,
- 3 => 0,
- ),
- 'AZN' => array(
- 0 => 'Azerbaijani Manat',
- 1 => 'AZN',
- 2 => 2,
- 3 => 0,
- ),
- 'AZM' => array(
- 0 => 'Azerbaijani Manat (1993-2006)',
- 1 => 'AZM',
- 2 => 2,
- 3 => 0,
- ),
- 'BSD' => array(
- 0 => 'Bahamian Dollar',
- 1 => 'BSD',
- 2 => 2,
- 3 => 0,
- ),
- 'BHD' => array(
- 0 => 'Bahraini Dinar',
- 1 => 'BHD',
- 2 => 3,
- 3 => 0,
- ),
- 'BDT' => array(
- 0 => 'Bangladeshi Taka',
- 1 => 'BDT',
- 2 => 2,
- 3 => 0,
- ),
- 'BBD' => array(
- 0 => 'Barbadian Dollar',
- 1 => 'BBD',
- 2 => 2,
- 3 => 0,
- ),
- 'BYB' => array(
- 0 => 'Belarusian New Ruble (1994-1999)',
- 1 => 'BYB',
- 2 => 2,
- 3 => 0,
- ),
- 'BYR' => array(
- 0 => 'Belarusian Ruble',
- 1 => 'BYR',
- 2 => 0,
- 3 => 0,
- ),
- 'BEF' => array(
- 0 => 'Belgian Franc',
- 1 => 'BEF',
- 2 => 2,
- 3 => 0,
- ),
- 'BEC' => array(
- 0 => 'Belgian Franc (convertible)',
- 1 => 'BEC',
- 2 => 2,
- 3 => 0,
- ),
- 'BEL' => array(
- 0 => 'Belgian Franc (financial)',
- 1 => 'BEL',
- 2 => 2,
- 3 => 0,
- ),
- 'BZD' => array(
- 0 => 'Belize Dollar',
- 1 => 'BZD',
- 2 => 2,
- 3 => 0,
- ),
- 'BMD' => array(
- 0 => 'Bermudan Dollar',
- 1 => 'BMD',
- 2 => 2,
- 3 => 0,
- ),
- 'BTN' => array(
- 0 => 'Bhutanese Ngultrum',
- 1 => 'BTN',
- 2 => 2,
- 3 => 0,
- ),
- 'BOB' => array(
- 0 => 'Bolivian Boliviano',
- 1 => 'BOB',
- 2 => 2,
- 3 => 0,
- ),
- 'BOL' => array(
- 0 => 'Bolivian Boliviano (1863-1963)',
- 1 => 'BOL',
- 2 => 2,
- 3 => 0,
- ),
- 'BOV' => array(
- 0 => 'Bolivian Mvdol',
- 1 => 'BOV',
- 2 => 2,
- 3 => 0,
- ),
- 'BOP' => array(
- 0 => 'Bolivian Peso',
- 1 => 'BOP',
- 2 => 2,
- 3 => 0,
- ),
- 'BAM' => array(
- 0 => 'Bosnia-Herzegovina Convertible Mark',
- 1 => 'BAM',
- 2 => 2,
- 3 => 0,
- ),
- 'BAD' => array(
- 0 => 'Bosnia-Herzegovina Dinar (1992-1994)',
- 1 => 'BAD',
- 2 => 2,
- 3 => 0,
- ),
- 'BAN' => array(
- 0 => 'Bosnia-Herzegovina New Dinar (1994-1997)',
- 1 => 'BAN',
- 2 => 2,
- 3 => 0,
- ),
- 'BWP' => array(
- 0 => 'Botswanan Pula',
- 1 => 'BWP',
- 2 => 2,
- 3 => 0,
- ),
- 'BRC' => array(
- 0 => 'Brazilian Cruzado (1986-1989)',
- 1 => 'BRC',
- 2 => 2,
- 3 => 0,
- ),
- 'BRZ' => array(
- 0 => 'Brazilian Cruzeiro (1942-1967)',
- 1 => 'BRZ',
- 2 => 2,
- 3 => 0,
- ),
- 'BRE' => array(
- 0 => 'Brazilian Cruzeiro (1990-1993)',
- 1 => 'BRE',
- 2 => 2,
- 3 => 0,
- ),
- 'BRR' => array(
- 0 => 'Brazilian Cruzeiro (1993-1994)',
- 1 => 'BRR',
- 2 => 2,
- 3 => 0,
- ),
- 'BRN' => array(
- 0 => 'Brazilian New Cruzado (1989-1990)',
- 1 => 'BRN',
- 2 => 2,
- 3 => 0,
- ),
- 'BRB' => array(
- 0 => 'Brazilian New Cruzeiro (1967-1986)',
- 1 => 'BRB',
- 2 => 2,
- 3 => 0,
- ),
- 'BRL' => array(
- 0 => 'Brazilian Real',
- 1 => 'R$',
- 2 => 2,
- 3 => 0,
- ),
- 'GBP' => array(
- 0 => 'British Pound Sterling',
- 1 => '£',
- 2 => 2,
- 3 => 0,
- ),
- 'BND' => array(
- 0 => 'Brunei Dollar',
- 1 => 'BND',
- 2 => 2,
- 3 => 0,
- ),
- 'BGL' => array(
- 0 => 'Bulgarian Hard Lev',
- 1 => 'BGL',
- 2 => 2,
- 3 => 0,
- ),
- 'BGN' => array(
- 0 => 'Bulgarian Lev',
- 1 => 'BGN',
- 2 => 2,
- 3 => 0,
- ),
- 'BGO' => array(
- 0 => 'Bulgarian Lev (1879-1952)',
- 1 => 'BGO',
- 2 => 2,
- 3 => 0,
- ),
- 'BGM' => array(
- 0 => 'Bulgarian Socialist Lev',
- 1 => 'BGM',
- 2 => 2,
- 3 => 0,
- ),
- 'BUK' => array(
- 0 => 'Burmese Kyat',
- 1 => 'BUK',
- 2 => 2,
- 3 => 0,
- ),
- 'BIF' => array(
- 0 => 'Burundian Franc',
- 1 => 'BIF',
- 2 => 0,
- 3 => 0,
- ),
- 'KHR' => array(
- 0 => 'Cambodian Riel',
- 1 => 'KHR',
- 2 => 2,
- 3 => 0,
- ),
- 'CAD' => array(
- 0 => 'Canadian Dollar',
- 1 => 'CA$',
- 2 => 2,
- 3 => 0,
- ),
- 'CVE' => array(
- 0 => 'Cape Verdean Escudo',
- 1 => 'CVE',
- 2 => 2,
- 3 => 0,
- ),
- 'KYD' => array(
- 0 => 'Cayman Islands Dollar',
- 1 => 'KYD',
- 2 => 2,
- 3 => 0,
- ),
- 'XOF' => array(
- 0 => 'CFA Franc BCEAO',
- 1 => 'CFA',
- 2 => 0,
- 3 => 0,
- ),
- 'XAF' => array(
- 0 => 'CFA Franc BEAC',
- 1 => 'FCFA',
- 2 => 0,
- 3 => 0,
- ),
- 'XPF' => array(
- 0 => 'CFP Franc',
- 1 => 'CFPF',
- 2 => 0,
- 3 => 0,
- ),
- 'CLE' => array(
- 0 => 'Chilean Escudo',
- 1 => 'CLE',
- 2 => 2,
- 3 => 0,
- ),
- 'CLP' => array(
- 0 => 'Chilean Peso',
- 1 => 'CLP',
- 2 => 0,
- 3 => 0,
- ),
- 'CLF' => array(
- 0 => 'Chilean Unit of Account (UF)',
- 1 => 'CLF',
- 2 => 0,
- 3 => 0,
- ),
- 'CNX' => array(
- 0 => 'Chinese People’s Bank Dollar',
- 1 => 'CNX',
- 2 => 2,
- 3 => 0,
- ),
- 'CNY' => array(
- 0 => 'Chinese Yuan',
- 1 => 'CN¥',
- 2 => 2,
- 3 => 0,
- ),
- 'COP' => array(
- 0 => 'Colombian Peso',
- 1 => 'COP',
- 2 => 0,
- 3 => 0,
- ),
- 'COU' => array(
- 0 => 'Colombian Real Value Unit',
- 1 => 'COU',
- 2 => 2,
- 3 => 0,
- ),
- 'KMF' => array(
- 0 => 'Comorian Franc',
- 1 => 'KMF',
- 2 => 0,
- 3 => 0,
- ),
- 'CDF' => array(
- 0 => 'Congolese Franc',
- 1 => 'CDF',
- 2 => 2,
- 3 => 0,
- ),
- 'CRC' => array(
- 0 => 'Costa Rican Colón',
- 1 => 'CRC',
- 2 => 0,
- 3 => 0,
- ),
- 'HRD' => array(
- 0 => 'Croatian Dinar',
- 1 => 'HRD',
- 2 => 2,
- 3 => 0,
- ),
- 'HRK' => array(
- 0 => 'Croatian Kuna',
- 1 => 'HRK',
- 2 => 2,
- 3 => 0,
- ),
- 'CUC' => array(
- 0 => 'Cuban Convertible Peso',
- 1 => 'CUC',
- 2 => 2,
- 3 => 0,
- ),
- 'CUP' => array(
- 0 => 'Cuban Peso',
- 1 => 'CUP',
- 2 => 2,
- 3 => 0,
- ),
- 'CYP' => array(
- 0 => 'Cypriot Pound',
- 1 => 'CYP',
- 2 => 2,
- 3 => 0,
- ),
- 'CZK' => array(
- 0 => 'Czech Republic Koruna',
- 1 => 'CZK',
- 2 => 2,
- 3 => 0,
- ),
- 'CSK' => array(
- 0 => 'Czechoslovak Hard Koruna',
- 1 => 'CSK',
- 2 => 2,
- 3 => 0,
- ),
- 'DKK' => array(
- 0 => 'Danish Krone',
- 1 => 'DKK',
- 2 => 2,
- 3 => 0,
- ),
- 'DJF' => array(
- 0 => 'Djiboutian Franc',
- 1 => 'DJF',
- 2 => 0,
- 3 => 0,
- ),
- 'DOP' => array(
- 0 => 'Dominican Peso',
- 1 => 'DOP',
- 2 => 2,
- 3 => 0,
- ),
- 'NLG' => array(
- 0 => 'Dutch Guilder',
- 1 => 'NLG',
- 2 => 2,
- 3 => 0,
- ),
- 'XCD' => array(
- 0 => 'East Caribbean Dollar',
- 1 => 'EC$',
- 2 => 2,
- 3 => 0,
- ),
- 'DDM' => array(
- 0 => 'East German Mark',
- 1 => 'DDM',
- 2 => 2,
- 3 => 0,
- ),
- 'ECS' => array(
- 0 => 'Ecuadorian Sucre',
- 1 => 'ECS',
- 2 => 2,
- 3 => 0,
- ),
- 'ECV' => array(
- 0 => 'Ecuadorian Unit of Constant Value',
- 1 => 'ECV',
- 2 => 2,
- 3 => 0,
- ),
- 'EGP' => array(
- 0 => 'Egyptian Pound',
- 1 => 'EGP',
- 2 => 2,
- 3 => 0,
- ),
- 'GQE' => array(
- 0 => 'Equatorial Guinean Ekwele',
- 1 => 'GQE',
- 2 => 2,
- 3 => 0,
- ),
- 'ERN' => array(
- 0 => 'Eritrean Nakfa',
- 1 => 'ERN',
- 2 => 2,
- 3 => 0,
- ),
- 'EEK' => array(
- 0 => 'Estonian Kroon',
- 1 => 'EEK',
- 2 => 2,
- 3 => 0,
- ),
- 'ETB' => array(
- 0 => 'Ethiopian Birr',
- 1 => 'ETB',
- 2 => 2,
- 3 => 0,
- ),
- 'EUR' => array(
- 0 => 'Euro',
- 1 => '€',
- 2 => 2,
- 3 => 0,
- ),
- 'XBA' => array(
- 0 => 'European Composite Unit',
- 1 => 'XBA',
- 2 => 2,
- 3 => 0,
- ),
- 'XEU' => array(
- 0 => 'European Currency Unit',
- 1 => 'XEU',
- 2 => 2,
- 3 => 0,
- ),
- 'XBB' => array(
- 0 => 'European Monetary Unit',
- 1 => 'XBB',
- 2 => 2,
- 3 => 0,
- ),
- 'XBC' => array(
- 0 => 'European Unit of Account (XBC)',
- 1 => 'XBC',
- 2 => 2,
- 3 => 0,
- ),
- 'XBD' => array(
- 0 => 'European Unit of Account (XBD)',
- 1 => 'XBD',
- 2 => 2,
- 3 => 0,
- ),
- 'FKP' => array(
- 0 => 'Falkland Islands Pound',
- 1 => 'FKP',
- 2 => 2,
- 3 => 0,
- ),
- 'FJD' => array(
- 0 => 'Fijian Dollar',
- 1 => 'FJD',
- 2 => 2,
- 3 => 0,
- ),
- 'FIM' => array(
- 0 => 'Finnish Markka',
- 1 => 'FIM',
- 2 => 2,
- 3 => 0,
- ),
- 'FRF' => array(
- 0 => 'French Franc',
- 1 => 'FRF',
- 2 => 2,
- 3 => 0,
- ),
- 'XFO' => array(
- 0 => 'French Gold Franc',
- 1 => 'XFO',
- 2 => 2,
- 3 => 0,
- ),
- 'XFU' => array(
- 0 => 'French UIC-Franc',
- 1 => 'XFU',
- 2 => 2,
- 3 => 0,
- ),
- 'GMD' => array(
- 0 => 'Gambian Dalasi',
- 1 => 'GMD',
- 2 => 2,
- 3 => 0,
- ),
- 'GEK' => array(
- 0 => 'Georgian Kupon Larit',
- 1 => 'GEK',
- 2 => 2,
- 3 => 0,
- ),
- 'GEL' => array(
- 0 => 'Georgian Lari',
- 1 => 'GEL',
- 2 => 2,
- 3 => 0,
- ),
- 'DEM' => array(
- 0 => 'German Mark',
- 1 => 'DEM',
- 2 => 2,
- 3 => 0,
- ),
- 'GHS' => array(
- 0 => 'Ghanaian Cedi',
- 1 => 'GHS',
- 2 => 2,
- 3 => 0,
- ),
- 'GHC' => array(
- 0 => 'Ghanaian Cedi (1979-2007)',
- 1 => 'GHC',
- 2 => 2,
- 3 => 0,
- ),
- 'GIP' => array(
- 0 => 'Gibraltar Pound',
- 1 => 'GIP',
- 2 => 2,
- 3 => 0,
- ),
- 'XAU' => array(
- 0 => 'Gold',
- 1 => 'XAU',
- 2 => 2,
- 3 => 0,
- ),
- 'GRD' => array(
- 0 => 'Greek Drachma',
- 1 => 'GRD',
- 2 => 2,
- 3 => 0,
- ),
- 'GTQ' => array(
- 0 => 'Guatemalan Quetzal',
- 1 => 'GTQ',
- 2 => 2,
- 3 => 0,
- ),
- 'GWP' => array(
- 0 => 'Guinea-Bissau Peso',
- 1 => 'GWP',
- 2 => 2,
- 3 => 0,
- ),
- 'GNF' => array(
- 0 => 'Guinean Franc',
- 1 => 'GNF',
- 2 => 0,
- 3 => 0,
- ),
- 'GNS' => array(
- 0 => 'Guinean Syli',
- 1 => 'GNS',
- 2 => 2,
- 3 => 0,
- ),
- 'GYD' => array(
- 0 => 'Guyanaese Dollar',
- 1 => 'GYD',
- 2 => 0,
- 3 => 0,
- ),
- 'HTG' => array(
- 0 => 'Haitian Gourde',
- 1 => 'HTG',
- 2 => 2,
- 3 => 0,
- ),
- 'HNL' => array(
- 0 => 'Honduran Lempira',
- 1 => 'HNL',
- 2 => 2,
- 3 => 0,
- ),
- 'HKD' => array(
- 0 => 'Hong Kong Dollar',
- 1 => 'HK$',
- 2 => 2,
- 3 => 0,
- ),
- 'HUF' => array(
- 0 => 'Hungarian Forint',
- 1 => 'HUF',
- 2 => 0,
- 3 => 0,
- ),
- 'ISK' => array(
- 0 => 'Icelandic Króna',
- 1 => 'ISK',
- 2 => 0,
- 3 => 0,
- ),
- 'ISJ' => array(
- 0 => 'Icelandic Króna (1918-1981)',
- 1 => 'ISJ',
- 2 => 2,
- 3 => 0,
- ),
- 'INR' => array(
- 0 => 'Indian Rupee',
- 1 => '₹',
- 2 => 2,
- 3 => 0,
- ),
- 'IDR' => array(
- 0 => 'Indonesian Rupiah',
- 1 => 'IDR',
- 2 => 0,
- 3 => 0,
- ),
- 'IRR' => array(
- 0 => 'Iranian Rial',
- 1 => 'IRR',
- 2 => 0,
- 3 => 0,
- ),
- 'IQD' => array(
- 0 => 'Iraqi Dinar',
- 1 => 'IQD',
- 2 => 0,
- 3 => 0,
- ),
- 'IEP' => array(
- 0 => 'Irish Pound',
- 1 => 'IEP',
- 2 => 2,
- 3 => 0,
- ),
- 'ILS' => array(
- 0 => 'Israeli New Sheqel',
- 1 => '₪',
- 2 => 2,
- 3 => 0,
- ),
- 'ILP' => array(
- 0 => 'Israeli Pound',
- 1 => 'ILP',
- 2 => 2,
- 3 => 0,
- ),
- 'ILR' => array(
- 0 => 'Israeli Sheqel (1980-1985)',
- 1 => 'ILR',
- 2 => 2,
- 3 => 0,
- ),
- 'ITL' => array(
- 0 => 'Italian Lira',
- 1 => 'ITL',
- 2 => 0,
- 3 => 0,
- ),
- 'JMD' => array(
- 0 => 'Jamaican Dollar',
- 1 => 'JMD',
- 2 => 2,
- 3 => 0,
- ),
- 'JPY' => array(
- 0 => 'Japanese Yen',
- 1 => '¥',
- 2 => 0,
- 3 => 0,
- ),
- 'JOD' => array(
- 0 => 'Jordanian Dinar',
- 1 => 'JOD',
- 2 => 3,
- 3 => 0,
- ),
- 'KZT' => array(
- 0 => 'Kazakhstani Tenge',
- 1 => 'KZT',
- 2 => 2,
- 3 => 0,
- ),
- 'KES' => array(
- 0 => 'Kenyan Shilling',
- 1 => 'KES',
- 2 => 2,
- 3 => 0,
- ),
- 'KWD' => array(
- 0 => 'Kuwaiti Dinar',
- 1 => 'KWD',
- 2 => 3,
- 3 => 0,
- ),
- 'KGS' => array(
- 0 => 'Kyrgystani Som',
- 1 => 'KGS',
- 2 => 2,
- 3 => 0,
- ),
- 'LAK' => array(
- 0 => 'Laotian Kip',
- 1 => 'LAK',
- 2 => 0,
- 3 => 0,
- ),
- 'LVL' => array(
- 0 => 'Latvian Lats',
- 1 => 'LVL',
- 2 => 2,
- 3 => 0,
- ),
- 'LVR' => array(
- 0 => 'Latvian Ruble',
- 1 => 'LVR',
- 2 => 2,
- 3 => 0,
- ),
- 'LBP' => array(
- 0 => 'Lebanese Pound',
- 1 => 'LBP',
- 2 => 0,
- 3 => 0,
- ),
- 'LSL' => array(
- 0 => 'Lesotho Loti',
- 1 => 'LSL',
- 2 => 2,
- 3 => 0,
- ),
- 'LRD' => array(
- 0 => 'Liberian Dollar',
- 1 => 'LRD',
- 2 => 2,
- 3 => 0,
- ),
- 'LYD' => array(
- 0 => 'Libyan Dinar',
- 1 => 'LYD',
- 2 => 3,
- 3 => 0,
- ),
- 'LTL' => array(
- 0 => 'Lithuanian Litas',
- 1 => 'LTL',
- 2 => 2,
- 3 => 0,
- ),
- 'LTT' => array(
- 0 => 'Lithuanian Talonas',
- 1 => 'LTT',
- 2 => 2,
- 3 => 0,
- ),
- 'LUL' => array(
- 0 => 'Luxembourg Financial Franc',
- 1 => 'LUL',
- 2 => 2,
- 3 => 0,
- ),
- 'LUC' => array(
- 0 => 'Luxembourgian Convertible Franc',
- 1 => 'LUC',
- 2 => 2,
- 3 => 0,
- ),
- 'LUF' => array(
- 0 => 'Luxembourgian Franc',
- 1 => 'LUF',
- 2 => 0,
- 3 => 0,
- ),
- 'MOP' => array(
- 0 => 'Macanese Pataca',
- 1 => 'MOP',
- 2 => 2,
- 3 => 0,
- ),
- 'MKD' => array(
- 0 => 'Macedonian Denar',
- 1 => 'MKD',
- 2 => 2,
- 3 => 0,
- ),
- 'MKN' => array(
- 0 => 'Macedonian Denar (1992-1993)',
- 1 => 'MKN',
- 2 => 2,
- 3 => 0,
- ),
- 'MGA' => array(
- 0 => 'Malagasy Ariary',
- 1 => 'MGA',
- 2 => 0,
- 3 => 0,
- ),
- 'MGF' => array(
- 0 => 'Malagasy Franc',
- 1 => 'MGF',
- 2 => 0,
- 3 => 0,
- ),
- 'MWK' => array(
- 0 => 'Malawian Kwacha',
- 1 => 'MWK',
- 2 => 2,
- 3 => 0,
- ),
- 'MYR' => array(
- 0 => 'Malaysian Ringgit',
- 1 => 'MYR',
- 2 => 2,
- 3 => 0,
- ),
- 'MVR' => array(
- 0 => 'Maldivian Rufiyaa',
- 1 => 'MVR',
- 2 => 2,
- 3 => 0,
- ),
- 'MVP' => array(
- 0 => 'Maldivian Rupee',
- 1 => 'MVP',
- 2 => 2,
- 3 => 0,
- ),
- 'MLF' => array(
- 0 => 'Malian Franc',
- 1 => 'MLF',
- 2 => 2,
- 3 => 0,
- ),
- 'MTL' => array(
- 0 => 'Maltese Lira',
- 1 => 'MTL',
- 2 => 2,
- 3 => 0,
- ),
- 'MTP' => array(
- 0 => 'Maltese Pound',
- 1 => 'MTP',
- 2 => 2,
- 3 => 0,
- ),
- 'MRO' => array(
- 0 => 'Mauritanian Ouguiya',
- 1 => 'MRO',
- 2 => 0,
- 3 => 0,
- ),
- 'MUR' => array(
- 0 => 'Mauritian Rupee',
- 1 => 'MUR',
- 2 => 0,
- 3 => 0,
- ),
- 'MXV' => array(
- 0 => 'Mexican Investment Unit',
- 1 => 'MXV',
- 2 => 2,
- 3 => 0,
- ),
- 'MXN' => array(
- 0 => 'Mexican Peso',
- 1 => 'MX$',
- 2 => 2,
- 3 => 0,
- ),
- 'MXP' => array(
- 0 => 'Mexican Silver Peso (1861-1992)',
- 1 => 'MXP',
- 2 => 2,
- 3 => 0,
- ),
- 'MDC' => array(
- 0 => 'Moldovan Cupon',
- 1 => 'MDC',
- 2 => 2,
- 3 => 0,
- ),
- 'MDL' => array(
- 0 => 'Moldovan Leu',
- 1 => 'MDL',
- 2 => 2,
- 3 => 0,
- ),
- 'MCF' => array(
- 0 => 'Monegasque Franc',
- 1 => 'MCF',
- 2 => 2,
- 3 => 0,
- ),
- 'MNT' => array(
- 0 => 'Mongolian Tugrik',
- 1 => 'MNT',
- 2 => 0,
- 3 => 0,
- ),
- 'MAD' => array(
- 0 => 'Moroccan Dirham',
- 1 => 'MAD',
- 2 => 2,
- 3 => 0,
- ),
- 'MAF' => array(
- 0 => 'Moroccan Franc',
- 1 => 'MAF',
- 2 => 2,
- 3 => 0,
- ),
- 'MZE' => array(
- 0 => 'Mozambican Escudo',
- 1 => 'MZE',
- 2 => 2,
- 3 => 0,
- ),
- 'MZN' => array(
- 0 => 'Mozambican Metical',
- 1 => 'MZN',
- 2 => 2,
- 3 => 0,
- ),
- 'MZM' => array(
- 0 => 'Mozambican Metical (1980-2006)',
- 1 => 'MZM',
- 2 => 2,
- 3 => 0,
- ),
- 'MMK' => array(
- 0 => 'Myanma Kyat',
- 1 => 'MMK',
- 2 => 0,
- 3 => 0,
- ),
- 'NAD' => array(
- 0 => 'Namibian Dollar',
- 1 => 'NAD',
- 2 => 2,
- 3 => 0,
- ),
- 'NPR' => array(
- 0 => 'Nepalese Rupee',
- 1 => 'NPR',
- 2 => 2,
- 3 => 0,
- ),
- 'ANG' => array(
- 0 => 'Netherlands Antillean Guilder',
- 1 => 'ANG',
- 2 => 2,
- 3 => 0,
- ),
- 'TWD' => array(
- 0 => 'New Taiwan Dollar',
- 1 => 'NT$',
- 2 => 2,
- 3 => 0,
- ),
- 'NZD' => array(
- 0 => 'New Zealand Dollar',
- 1 => 'NZ$',
- 2 => 2,
- 3 => 0,
- ),
- 'NIO' => array(
- 0 => 'Nicaraguan Córdoba',
- 1 => 'NIO',
- 2 => 2,
- 3 => 0,
- ),
- 'NIC' => array(
- 0 => 'Nicaraguan Córdoba (1988-1991)',
- 1 => 'NIC',
- 2 => 2,
- 3 => 0,
- ),
- 'NGN' => array(
- 0 => 'Nigerian Naira',
- 1 => 'NGN',
- 2 => 2,
- 3 => 0,
- ),
- 'KPW' => array(
- 0 => 'North Korean Won',
- 1 => 'KPW',
- 2 => 0,
- 3 => 0,
- ),
- 'NOK' => array(
- 0 => 'Norwegian Krone',
- 1 => 'NOK',
- 2 => 2,
- 3 => 0,
- ),
- 'OMR' => array(
- 0 => 'Omani Rial',
- 1 => 'OMR',
- 2 => 3,
- 3 => 0,
- ),
- 'PKR' => array(
- 0 => 'Pakistani Rupee',
- 1 => 'PKR',
- 2 => 0,
- 3 => 0,
- ),
- 'XPD' => array(
- 0 => 'Palladium',
- 1 => 'XPD',
- 2 => 2,
- 3 => 0,
- ),
- 'PAB' => array(
- 0 => 'Panamanian Balboa',
- 1 => 'PAB',
- 2 => 2,
- 3 => 0,
- ),
- 'PGK' => array(
- 0 => 'Papua New Guinean Kina',
- 1 => 'PGK',
- 2 => 2,
- 3 => 0,
- ),
- 'PYG' => array(
- 0 => 'Paraguayan Guarani',
- 1 => 'PYG',
- 2 => 0,
- 3 => 0,
- ),
- 'PEI' => array(
- 0 => 'Peruvian Inti',
- 1 => 'PEI',
- 2 => 2,
- 3 => 0,
- ),
- 'PEN' => array(
- 0 => 'Peruvian Nuevo Sol',
- 1 => 'PEN',
- 2 => 2,
- 3 => 0,
- ),
- 'PES' => array(
- 0 => 'Peruvian Sol (1863-1965)',
- 1 => 'PES',
- 2 => 2,
- 3 => 0,
- ),
- 'PHP' => array(
- 0 => 'Philippine Peso',
- 1 => 'PHP',
- 2 => 2,
- 3 => 0,
- ),
- 'XPT' => array(
- 0 => 'Platinum',
- 1 => 'XPT',
- 2 => 2,
- 3 => 0,
- ),
- 'PLN' => array(
- 0 => 'Polish Zloty',
- 1 => 'PLN',
- 2 => 2,
- 3 => 0,
- ),
- 'PLZ' => array(
- 0 => 'Polish Zloty (1950-1995)',
- 1 => 'PLZ',
- 2 => 2,
- 3 => 0,
- ),
- 'PTE' => array(
- 0 => 'Portuguese Escudo',
- 1 => 'PTE',
- 2 => 2,
- 3 => 0,
- ),
- 'GWE' => array(
- 0 => 'Portuguese Guinea Escudo',
- 1 => 'GWE',
- 2 => 2,
- 3 => 0,
- ),
- 'QAR' => array(
- 0 => 'Qatari Rial',
- 1 => 'QAR',
- 2 => 2,
- 3 => 0,
- ),
- 'RHD' => array(
- 0 => 'Rhodesian Dollar',
- 1 => 'RHD',
- 2 => 2,
- 3 => 0,
- ),
- 'XRE' => array(
- 0 => 'RINET Funds',
- 1 => 'XRE',
- 2 => 2,
- 3 => 0,
- ),
- 'RON' => array(
- 0 => 'Romanian Leu',
- 1 => 'RON',
- 2 => 2,
- 3 => 0,
- ),
- 'ROL' => array(
- 0 => 'Romanian Leu (1952-2006)',
- 1 => 'ROL',
- 2 => 2,
- 3 => 0,
- ),
- 'RUB' => array(
- 0 => 'Russian Ruble',
- 1 => 'RUB',
- 2 => 2,
- 3 => 0,
- ),
- 'RUR' => array(
- 0 => 'Russian Ruble (1991-1998)',
- 1 => 'RUR',
- 2 => 2,
- 3 => 0,
- ),
- 'RWF' => array(
- 0 => 'Rwandan Franc',
- 1 => 'RWF',
- 2 => 0,
- 3 => 0,
- ),
- 'SHP' => array(
- 0 => 'Saint Helena Pound',
- 1 => 'SHP',
- 2 => 2,
- 3 => 0,
- ),
- 'SVC' => array(
- 0 => 'Salvadoran Colón',
- 1 => 'SVC',
- 2 => 2,
- 3 => 0,
- ),
- 'WST' => array(
- 0 => 'Samoan Tala',
- 1 => 'WST',
- 2 => 2,
- 3 => 0,
- ),
- 'STD' => array(
- 0 => 'São Tomé and Príncipe Dobra',
- 1 => 'STD',
- 2 => 0,
- 3 => 0,
- ),
- 'SAR' => array(
- 0 => 'Saudi Riyal',
- 1 => 'SAR',
- 2 => 2,
- 3 => 0,
- ),
- 'RSD' => array(
- 0 => 'Serbian Dinar',
- 1 => 'RSD',
- 2 => 0,
- 3 => 0,
- ),
- 'CSD' => array(
- 0 => 'Serbian Dinar (2002-2006)',
- 1 => 'CSD',
- 2 => 2,
- 3 => 0,
- ),
- 'SCR' => array(
- 0 => 'Seychellois Rupee',
- 1 => 'SCR',
- 2 => 2,
- 3 => 0,
- ),
- 'SLL' => array(
- 0 => 'Sierra Leonean Leone',
- 1 => 'SLL',
- 2 => 0,
- 3 => 0,
- ),
- 'XAG' => array(
- 0 => 'Silver',
- 1 => 'XAG',
- 2 => 2,
- 3 => 0,
- ),
- 'SGD' => array(
- 0 => 'Singapore Dollar',
- 1 => 'SGD',
- 2 => 2,
- 3 => 0,
- ),
- 'SKK' => array(
- 0 => 'Slovak Koruna',
- 1 => 'SKK',
- 2 => 2,
- 3 => 0,
- ),
- 'SIT' => array(
- 0 => 'Slovenian Tolar',
- 1 => 'SIT',
- 2 => 2,
- 3 => 0,
- ),
- 'SBD' => array(
- 0 => 'Solomon Islands Dollar',
- 1 => 'SBD',
- 2 => 2,
- 3 => 0,
- ),
- 'SOS' => array(
- 0 => 'Somali Shilling',
- 1 => 'SOS',
- 2 => 0,
- 3 => 0,
- ),
- 'ZAR' => array(
- 0 => 'South African Rand',
- 1 => 'ZAR',
- 2 => 2,
- 3 => 0,
- ),
- 'ZAL' => array(
- 0 => 'South African Rand (financial)',
- 1 => 'ZAL',
- 2 => 2,
- 3 => 0,
- ),
- 'KRH' => array(
- 0 => 'South Korean Hwan (1953-1962)',
- 1 => 'KRH',
- 2 => 2,
- 3 => 0,
- ),
- 'KRW' => array(
- 0 => 'South Korean Won',
- 1 => '₩',
- 2 => 0,
- 3 => 0,
- ),
- 'KRO' => array(
- 0 => 'South Korean Won (1945-1953)',
- 1 => 'KRO',
- 2 => 2,
- 3 => 0,
- ),
- 'SSP' => array(
- 0 => 'South Sudanese Pound',
- 1 => 'SSP',
- 2 => 2,
- 3 => 0,
- ),
- 'SUR' => array(
- 0 => 'Soviet Rouble',
- 1 => 'SUR',
- 2 => 2,
- 3 => 0,
- ),
- 'ESP' => array(
- 0 => 'Spanish Peseta',
- 1 => 'ESP',
- 2 => 0,
- 3 => 0,
- ),
- 'ESA' => array(
- 0 => 'Spanish Peseta (A account)',
- 1 => 'ESA',
- 2 => 2,
- 3 => 0,
- ),
- 'ESB' => array(
- 0 => 'Spanish Peseta (convertible account)',
- 1 => 'ESB',
- 2 => 2,
- 3 => 0,
- ),
- 'XDR' => array(
- 0 => 'Special Drawing Rights',
- 1 => 'XDR',
- 2 => 2,
- 3 => 0,
- ),
- 'LKR' => array(
- 0 => 'Sri Lankan Rupee',
- 1 => 'LKR',
- 2 => 2,
- 3 => 0,
- ),
- 'XSU' => array(
- 0 => 'Sucre',
- 1 => 'XSU',
- 2 => 2,
- 3 => 0,
- ),
- 'SDD' => array(
- 0 => 'Sudanese Dinar (1992-2007)',
- 1 => 'SDD',
- 2 => 2,
- 3 => 0,
- ),
- 'SDG' => array(
- 0 => 'Sudanese Pound',
- 1 => 'SDG',
- 2 => 2,
- 3 => 0,
- ),
- 'SDP' => array(
- 0 => 'Sudanese Pound (1957-1998)',
- 1 => 'SDP',
- 2 => 2,
- 3 => 0,
- ),
- 'SRD' => array(
- 0 => 'Surinamese Dollar',
- 1 => 'SRD',
- 2 => 2,
- 3 => 0,
- ),
- 'SRG' => array(
- 0 => 'Surinamese Guilder',
- 1 => 'SRG',
- 2 => 2,
- 3 => 0,
- ),
- 'SZL' => array(
- 0 => 'Swazi Lilangeni',
- 1 => 'SZL',
- 2 => 2,
- 3 => 0,
- ),
- 'SEK' => array(
- 0 => 'Swedish Krona',
- 1 => 'SEK',
- 2 => 2,
- 3 => 0,
- ),
- 'CHF' => array(
- 0 => 'Swiss Franc',
- 1 => 'CHF',
- 2 => 2,
- 3 => 5,
- ),
- 'SYP' => array(
- 0 => 'Syrian Pound',
- 1 => 'SYP',
- 2 => 0,
- 3 => 0,
- ),
- 'TJR' => array(
- 0 => 'Tajikistani Ruble',
- 1 => 'TJR',
- 2 => 2,
- 3 => 0,
- ),
- 'TJS' => array(
- 0 => 'Tajikistani Somoni',
- 1 => 'TJS',
- 2 => 2,
- 3 => 0,
- ),
- 'TZS' => array(
- 0 => 'Tanzanian Shilling',
- 1 => 'TZS',
- 2 => 0,
- 3 => 0,
- ),
- 'XTS' => array(
- 0 => 'Testing Currency Code',
- 1 => 'XTS',
- 2 => 2,
- 3 => 0,
- ),
- 'THB' => array(
- 0 => 'Thai Baht',
- 1 => '฿',
- 2 => 2,
- 3 => 0,
- ),
- 'TPE' => array(
- 0 => 'Timorese Escudo',
- 1 => 'TPE',
- 2 => 2,
- 3 => 0,
- ),
- 'TOP' => array(
- 0 => 'Tongan Paʻanga',
- 1 => 'TOP',
- 2 => 2,
- 3 => 0,
- ),
- 'TTD' => array(
- 0 => 'Trinidad and Tobago Dollar',
- 1 => 'TTD',
- 2 => 2,
- 3 => 0,
- ),
- 'TND' => array(
- 0 => 'Tunisian Dinar',
- 1 => 'TND',
- 2 => 3,
- 3 => 0,
- ),
- 'TRY' => array(
- 0 => 'Turkish Lira',
- 1 => 'TRY',
- 2 => 2,
- 3 => 0,
- ),
- 'TRL' => array(
- 0 => 'Turkish Lira (1922-2005)',
- 1 => 'TRL',
- 2 => 0,
- 3 => 0,
- ),
- 'TMT' => array(
- 0 => 'Turkmenistani Manat',
- 1 => 'TMT',
- 2 => 2,
- 3 => 0,
- ),
- 'TMM' => array(
- 0 => 'Turkmenistani Manat (1993-2009)',
- 1 => 'TMM',
- 2 => 0,
- 3 => 0,
- ),
- 'UGX' => array(
- 0 => 'Ugandan Shilling',
- 1 => 'UGX',
- 2 => 0,
- 3 => 0,
- ),
- 'UGS' => array(
- 0 => 'Ugandan Shilling (1966-1987)',
- 1 => 'UGS',
- 2 => 2,
- 3 => 0,
- ),
- 'UAH' => array(
- 0 => 'Ukrainian Hryvnia',
- 1 => 'UAH',
- 2 => 2,
- 3 => 0,
- ),
- 'UAK' => array(
- 0 => 'Ukrainian Karbovanets',
- 1 => 'UAK',
- 2 => 2,
- 3 => 0,
- ),
- 'AED' => array(
- 0 => 'United Arab Emirates Dirham',
- 1 => 'AED',
- 2 => 2,
- 3 => 0,
- ),
- 'XXX' => array(
- 0 => 'Unknown Currency',
- 1 => 'XXX',
- 2 => 2,
- 3 => 0,
- ),
- 'UYU' => array(
- 0 => 'Uruguayan Peso',
- 1 => 'UYU',
- 2 => 2,
- 3 => 0,
- ),
- 'UYP' => array(
- 0 => 'Uruguayan Peso (1975-1993)',
- 1 => 'UYP',
- 2 => 2,
- 3 => 0,
- ),
- 'UYI' => array(
- 0 => 'Uruguayan Peso (Indexed Units)',
- 1 => 'UYI',
- 2 => 2,
- 3 => 0,
- ),
- 'USD' => array(
- 0 => 'US Dollar',
- 1 => '$',
- 2 => 2,
- 3 => 0,
- ),
- 'USN' => array(
- 0 => 'US Dollar (Next day)',
- 1 => 'USN',
- 2 => 2,
- 3 => 0,
- ),
- 'USS' => array(
- 0 => 'US Dollar (Same day)',
- 1 => 'USS',
- 2 => 2,
- 3 => 0,
- ),
- 'UZS' => array(
- 0 => 'Uzbekistan Som',
- 1 => 'UZS',
- 2 => 0,
- 3 => 0,
- ),
- 'VUV' => array(
- 0 => 'Vanuatu Vatu',
- 1 => 'VUV',
- 2 => 0,
- 3 => 0,
- ),
- 'VEF' => array(
- 0 => 'Venezuelan Bolívar',
- 1 => 'VEF',
- 2 => 2,
- 3 => 0,
- ),
- 'VEB' => array(
- 0 => 'Venezuelan Bolívar (1871-2008)',
- 1 => 'VEB',
- 2 => 2,
- 3 => 0,
- ),
- 'VND' => array(
- 0 => 'Vietnamese Dong',
- 1 => '₫',
- 2 => 0,
- 3 => 0,
- ),
- 'VNN' => array(
- 0 => 'Vietnamese Dong (1978-1985)',
- 1 => 'VNN',
- 2 => 2,
- 3 => 0,
- ),
- 'CHE' => array(
- 0 => 'WIR Euro',
- 1 => 'CHE',
- 2 => 2,
- 3 => 0,
- ),
- 'CHW' => array(
- 0 => 'WIR Franc',
- 1 => 'CHW',
- 2 => 2,
- 3 => 0,
- ),
- 'YDD' => array(
- 0 => 'Yemeni Dinar',
- 1 => 'YDD',
- 2 => 2,
- 3 => 0,
- ),
- 'YER' => array(
- 0 => 'Yemeni Rial',
- 1 => 'YER',
- 2 => 0,
- 3 => 0,
- ),
- 'YUN' => array(
- 0 => 'Yugoslavian Convertible Dinar (1990-1992)',
- 1 => 'YUN',
- 2 => 2,
- 3 => 0,
- ),
- 'YUD' => array(
- 0 => 'Yugoslavian Hard Dinar (1966-1990)',
- 1 => 'YUD',
- 2 => 2,
- 3 => 0,
- ),
- 'YUM' => array(
- 0 => 'Yugoslavian New Dinar (1994-2002)',
- 1 => 'YUM',
- 2 => 2,
- 3 => 0,
- ),
- 'YUR' => array(
- 0 => 'Yugoslavian Reformed Dinar (1992-1993)',
- 1 => 'YUR',
- 2 => 2,
- 3 => 0,
- ),
- 'ZRN' => array(
- 0 => 'Zairean New Zaire (1993-1998)',
- 1 => 'ZRN',
- 2 => 2,
- 3 => 0,
- ),
- 'ZRZ' => array(
- 0 => 'Zairean Zaire (1971-1993)',
- 1 => 'ZRZ',
- 2 => 2,
- 3 => 0,
- ),
- 'ZMK' => array(
- 0 => 'Zambian Kwacha',
- 1 => 'ZMK',
- 2 => 0,
- 3 => 0,
- ),
- 'ZWD' => array(
- 0 => 'Zimbabwean Dollar (1980-2008)',
- 1 => 'ZWD',
- 2 => 0,
- 3 => 0,
- ),
- 'ZWR' => array(
- 0 => 'Zimbabwean Dollar (2008)',
- 1 => 'ZWR',
- 2 => 2,
- 3 => 0,
- ),
- 'ZWL' => array(
- 0 => 'Zimbabwean Dollar (2009)',
- 1 => 'ZWL',
- 2 => 2,
- 3 => 0,
- ),
- ),
-);
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return array(
- 'Languages' => array(
- 'ab' => 'Abkhazian',
- 'ace' => 'Achinese',
- 'ach' => 'Acoli',
- 'ada' => 'Adangme',
- 'ady' => 'Adyghe',
- 'aa' => 'Afar',
- 'afh' => 'Afrihili',
- 'af' => 'Afrikaans',
- 'afa' => 'Afro-Asiatic Language',
- 'agq' => 'Aghem',
- 'ain' => 'Ainu',
- 'ak' => 'Akan',
- 'akk' => 'Akkadian',
- 'bss' => 'Akoose',
- 'sq' => 'Albanian',
- 'ale' => 'Aleut',
- 'alg' => 'Algonquian Language',
- 'tut' => 'Altaic Language',
- 'am' => 'Amharic',
- 'egy' => 'Ancient Egyptian',
- 'grc' => 'Ancient Greek',
- 'anp' => 'Angika',
- 'apa' => 'Apache Language',
- 'ar' => 'Arabic',
- 'an' => 'Aragonese',
- 'arc' => 'Aramaic',
- 'arp' => 'Arapaho',
- 'arw' => 'Arawak',
- 'hy' => 'Armenian',
- 'rup' => 'Aromanian',
- 'art' => 'Artificial Language',
- 'as' => 'Assamese',
- 'ast' => 'Asturian',
- 'asa' => 'Asu',
- 'ath' => 'Athapascan Language',
- 'cch' => 'Atsam',
- 'en_AU' => 'Australian English',
- 'aus' => 'Australian Language',
- 'de_AT' => 'Austrian German',
- 'map' => 'Austronesian Language',
- 'av' => 'Avaric',
- 'ae' => 'Avestan',
- 'awa' => 'Awadhi',
- 'ay' => 'Aymara',
- 'az' => 'Azerbaijani',
- 'ksf' => 'Bafia',
- 'bfd' => 'Bafut',
- 'ban' => 'Balinese',
- 'bat' => 'Baltic Language',
- 'bal' => 'Baluchi',
- 'bm' => 'Bambara',
- 'bai' => 'Bamileke Language',
- 'bax' => 'Bamun',
- 'bad' => 'Banda',
- 'bnt' => 'Bantu',
- 'bas' => 'Basaa',
- 'ba' => 'Bashkir',
- 'eu' => 'Basque',
- 'btk' => 'Batak',
- 'bej' => 'Beja',
- 'be' => 'Belarusian',
- 'bem' => 'Bemba',
- 'bez' => 'Bena',
- 'bn' => 'Bengali',
- 'ber' => 'Berber',
- 'bho' => 'Bhojpuri',
- 'bh' => 'Bihari',
- 'bik' => 'Bikol',
- 'bin' => 'Bini',
- 'bi' => 'Bislama',
- 'byn' => 'Blin',
- 'zbl' => 'Blissymbols',
- 'brx' => 'Bodo',
- 'bs' => 'Bosnian',
- 'bra' => 'Braj',
- 'pt_BR' => 'Brazilian Portuguese',
- 'br' => 'Breton',
- 'en_GB' => 'British English',
- 'bug' => 'Buginese',
- 'bg' => 'Bulgarian',
- 'bum' => 'Bulu',
- 'bua' => 'Buriat',
- 'my' => 'Burmese',
- 'cad' => 'Caddo',
- 'en_CA' => 'Canadian English',
- 'fr_CA' => 'Canadian French',
- 'yue' => 'Cantonese',
- 'car' => 'Carib',
- 'ca' => 'Catalan',
- 'cau' => 'Caucasian Language',
- 'cay' => 'Cayuga',
- 'ceb' => 'Cebuano',
- 'cel' => 'Celtic Language',
- 'cai' => 'Central American Indian Language',
- 'tzm' => 'Central Atlas Tamazight',
- 'shu' => 'Chadian Arabic',
- 'chg' => 'Chagatai',
- 'cmc' => 'Chamic Language',
- 'ch' => 'Chamorro',
- 'ce' => 'Chechen',
- 'chr' => 'Cherokee',
- 'chy' => 'Cheyenne',
- 'chb' => 'Chibcha',
- 'cgg' => 'Chiga',
- 'zh' => 'Chinese',
- 'chn' => 'Chinook Jargon',
- 'chp' => 'Chipewyan',
- 'cho' => 'Choctaw',
- 'cu' => 'Church Slavic',
- 'chk' => 'Chuukese',
- 'cv' => 'Chuvash',
- 'nwc' => 'Classical Newari',
- 'syc' => 'Classical Syriac',
- 'ksh' => 'Colognian',
- 'swb' => 'Comorian',
- 'swc' => 'Congo Swahili',
- 'cop' => 'Coptic',
- 'kw' => 'Cornish',
- 'co' => 'Corsican',
- 'cr' => 'Cree',
- 'mus' => 'Creek',
- 'crp' => 'Creole or Pidgin',
- 'crh' => 'Crimean Turkish',
- 'hr' => 'Croatian',
- 'cus' => 'Cushitic Language',
- 'cs' => 'Czech',
- 'dak' => 'Dakota',
- 'da' => 'Danish',
- 'dar' => 'Dargwa',
- 'day' => 'Dayak',
- 'dzg' => 'Dazaga',
- 'del' => 'Delaware',
- 'din' => 'Dinka',
- 'dv' => 'Divehi',
- 'doi' => 'Dogri',
- 'dgr' => 'Dogrib',
- 'dra' => 'Dravidian Language',
- 'dua' => 'Duala',
- 'nl' => 'Dutch',
- 'dyu' => 'Dyula',
- 'dz' => 'Dzongkha',
- 'frs' => 'Eastern Frisian',
- 'efi' => 'Efik',
- 'eka' => 'Ekajuk',
- 'elx' => 'Elamite',
- 'ebu' => 'Embu',
- 'en' => 'English',
- 'cpe' => 'English-based Creole or Pidgin',
- 'myv' => 'Erzya',
- 'eo' => 'Esperanto',
- 'et' => 'Estonian',
- 'pt_PT' => 'European Portuguese',
- 'es_ES' => 'European Spanish',
- 'ee' => 'Ewe',
- 'ewo' => 'Ewondo',
- 'fan' => 'Fang',
- 'fat' => 'Fanti',
- 'fo' => 'Faroese',
- 'fj' => 'Fijian',
- 'fil' => 'Filipino',
- 'fi' => 'Finnish',
- 'fiu' => 'Finno-Ugrian Language',
- 'nl_BE' => 'Flemish',
- 'fon' => 'Fon',
- 'fr' => 'French',
- 'cpf' => 'French-based Creole or Pidgin',
- 'fur' => 'Friulian',
- 'ff' => 'Fulah',
- 'gaa' => 'Ga',
- 'gl' => 'Galician',
- 'lg' => 'Ganda',
- 'gay' => 'Gayo',
- 'gba' => 'Gbaya',
- 'gez' => 'Geez',
- 'ka' => 'Georgian',
- 'de' => 'German',
- 'gem' => 'Germanic Language',
- 'bbj' => 'Ghomala',
- 'gil' => 'Gilbertese',
- 'gon' => 'Gondi',
- 'gor' => 'Gorontalo',
- 'got' => 'Gothic',
- 'grb' => 'Grebo',
- 'el' => 'Greek',
- 'gn' => 'Guarani',
- 'gu' => 'Gujarati',
- 'guz' => 'Gusii',
- 'gwi' => 'Gwichʼin',
- 'hai' => 'Haida',
- 'ht' => 'Haitian',
- 'ha' => 'Hausa',
- 'haw' => 'Hawaiian',
- 'he' => 'Hebrew',
- 'hz' => 'Herero',
- 'hil' => 'Hiligaynon',
- 'him' => 'Himachali',
- 'hi' => 'Hindi',
- 'ho' => 'Hiri Motu',
- 'hit' => 'Hittite',
- 'hmn' => 'Hmong',
- 'hu' => 'Hungarian',
- 'hup' => 'Hupa',
- 'iba' => 'Iban',
- 'ibb' => 'Ibibio',
- 'is' => 'Icelandic',
- 'io' => 'Ido',
- 'ig' => 'Igbo',
- 'ijo' => 'Ijo',
- 'ilo' => 'Iloko',
- 'smn' => 'Inari Sami',
- 'inc' => 'Indic Language',
- 'ine' => 'Indo-European Language',
- 'id' => 'Indonesian',
- 'inh' => 'Ingush',
- 'ia' => 'Interlingua',
- 'ie' => 'Interlingue',
- 'iu' => 'Inuktitut',
- 'ik' => 'Inupiaq',
- 'ira' => 'Iranian Language',
- 'ga' => 'Irish',
- 'iro' => 'Iroquoian Language',
- 'it' => 'Italian',
- 'ja' => 'Japanese',
- 'jv' => 'Javanese',
- 'kaj' => 'Jju',
- 'dyo' => 'Jola-Fonyi',
- 'jrb' => 'Judeo-Arabic',
- 'jpr' => 'Judeo-Persian',
- 'kbd' => 'Kabardian',
- 'kea' => 'Kabuverdianu',
- 'kab' => 'Kabyle',
- 'kac' => 'Kachin',
- 'kkj' => 'Kako',
- 'kl' => 'Kalaallisut',
- 'kln' => 'Kalenjin',
- 'xal' => 'Kalmyk',
- 'kam' => 'Kamba',
- 'kbl' => 'Kanembu',
- 'kn' => 'Kannada',
- 'kr' => 'Kanuri',
- 'kaa' => 'Kara-Kalpak',
- 'krc' => 'Karachay-Balkar',
- 'krl' => 'Karelian',
- 'kar' => 'Karen',
- 'ks' => 'Kashmiri',
- 'csb' => 'Kashubian',
- 'kaw' => 'Kawi',
- 'kk' => 'Kazakh',
- 'kha' => 'Khasi',
- 'km' => 'Khmer',
- 'khi' => 'Khoisan Language',
- 'kho' => 'Khotanese',
- 'ki' => 'Kikuyu',
- 'kmb' => 'Kimbundu',
- 'rw' => 'Kinyarwanda',
- 'ky' => 'Kirghiz',
- 'tlh' => 'Klingon',
- 'bkm' => 'Kom',
- 'kv' => 'Komi',
- 'kg' => 'Kongo',
- 'kok' => 'Konkani',
- 'ko' => 'Korean',
- 'kfo' => 'Koro',
- 'kos' => 'Kosraean',
- 'khq' => 'Koyra Chiini',
- 'ses' => 'Koyraboro Senni',
- 'kpe' => 'Kpelle',
- 'kro' => 'Kru',
- 'kj' => 'Kuanyama',
- 'kum' => 'Kumyk',
- 'ku' => 'Kurdish',
- 'kru' => 'Kurukh',
- 'kut' => 'Kutenai',
- 'nmg' => 'Kwasio',
- 'lad' => 'Ladino',
- 'lah' => 'Lahnda',
- 'lam' => 'Lamba',
- 'lag' => 'Langi',
- 'lo' => 'Lao',
- 'la' => 'Latin',
- 'es_419' => 'Latin American Spanish',
- 'lv' => 'Latvian',
- 'lez' => 'Lezghian',
- 'li' => 'Limburgish',
- 'ln' => 'Lingala',
- 'lt' => 'Lithuanian',
- 'jbo' => 'Lojban',
- 'nds' => 'Low German',
- 'dsb' => 'Lower Sorbian',
- 'loz' => 'Lozi',
- 'lu' => 'Luba-Katanga',
- 'lua' => 'Luba-Lulua',
- 'lui' => 'Luiseno',
- 'smj' => 'Lule Sami',
- 'lun' => 'Lunda',
- 'luo' => 'Luo',
- 'lb' => 'Luxembourgish',
- 'luy' => 'Luyia',
- 'mde' => 'Maba',
- 'mk' => 'Macedonian',
- 'jmc' => 'Machame',
- 'mad' => 'Madurese',
- 'maf' => 'Mafa',
- 'mag' => 'Magahi',
- 'mai' => 'Maithili',
- 'mak' => 'Makasar',
- 'mgh' => 'Makhuwa-Meetto',
- 'kde' => 'Makonde',
- 'mg' => 'Malagasy',
- 'ms' => 'Malay',
- 'ml' => 'Malayalam',
- 'mt' => 'Maltese',
- 'mnc' => 'Manchu',
- 'mdr' => 'Mandar',
- 'man' => 'Mandingo',
- 'mni' => 'Manipuri',
- 'mno' => 'Manobo Language',
- 'gv' => 'Manx',
- 'mi' => 'Maori',
- 'arn' => 'Mapuche',
- 'mr' => 'Marathi',
- 'chm' => 'Mari',
- 'mh' => 'Marshallese',
- 'mwr' => 'Marwari',
- 'mas' => 'Masai',
- 'myn' => 'Mayan Language',
- 'byv' => 'Medumba',
- 'men' => 'Mende',
- 'mer' => 'Meru',
- 'mgo' => 'Meta\'',
- 'mic' => 'Micmac',
- 'dum' => 'Middle Dutch',
- 'enm' => 'Middle English',
- 'frm' => 'Middle French',
- 'gmh' => 'Middle High German',
- 'mga' => 'Middle Irish',
- 'min' => 'Minangkabau',
- 'mwl' => 'Mirandese',
- 'mis' => 'Miscellaneous Language',
- 'lus' => 'Mizo',
- 'ar_001' => 'Modern Standard Arabic',
- 'moh' => 'Mohawk',
- 'mdf' => 'Moksha',
- 'mo' => 'Moldavian',
- 'mkh' => 'Mon-Khmer Language',
- 'lol' => 'Mongo',
- 'mn' => 'Mongolian',
- 'mfe' => 'Morisyen',
- 'mos' => 'Mossi',
- 'mun' => 'Munda Language',
- 'mua' => 'Mundang',
- 'mye' => 'Myene',
- 'nqo' => 'N’Ko',
- 'nah' => 'Nahuatl',
- 'naq' => 'Nama',
- 'na' => 'Nauru',
- 'nv' => 'Navajo',
- 'ng' => 'Ndonga',
- 'nap' => 'Neapolitan',
- 'ne' => 'Nepali',
- 'new' => 'Newari',
- 'sba' => 'Ngambay',
- 'nnh' => 'Ngiemboon',
- 'jgo' => 'Ngomba',
- 'nia' => 'Nias',
- 'nic' => 'Niger-Kordofanian Language',
- 'ssa' => 'Nilo-Saharan Language',
- 'niu' => 'Niuean',
- 'zxx' => 'No linguistic content',
- 'nog' => 'Nogai',
- 'nai' => 'North American Indian Language',
- 'nd' => 'North Ndebele',
- 'frr' => 'Northern Frisian',
- 'se' => 'Northern Sami',
- 'nso' => 'Northern Sotho',
- 'no' => 'Norwegian',
- 'nb' => 'Norwegian Bokmål',
- 'nn' => 'Norwegian Nynorsk',
- 'nub' => 'Nubian Language',
- 'nus' => 'Nuer',
- 'nym' => 'Nyamwezi',
- 'ny' => 'Nyanja',
- 'nyn' => 'Nyankole',
- 'tog' => 'Nyasa Tonga',
- 'nyo' => 'Nyoro',
- 'nzi' => 'Nzima',
- 'oc' => 'Occitan',
- 'oj' => 'Ojibwa',
- 'ang' => 'Old English',
- 'fro' => 'Old French',
- 'goh' => 'Old High German',
- 'sga' => 'Old Irish',
- 'non' => 'Old Norse',
- 'peo' => 'Old Persian',
- 'pro' => 'Old Provençal',
- 'or' => 'Oriya',
- 'om' => 'Oromo',
- 'osa' => 'Osage',
- 'os' => 'Ossetic',
- 'oto' => 'Otomian Language',
- 'ota' => 'Ottoman Turkish',
- 'pal' => 'Pahlavi',
- 'pau' => 'Palauan',
- 'pi' => 'Pali',
- 'pam' => 'Pampanga',
- 'pag' => 'Pangasinan',
- 'pap' => 'Papiamento',
- 'paa' => 'Papuan Language',
- 'ps' => 'Pashto',
- 'fa' => 'Persian',
- 'phi' => 'Philippine Language',
- 'phn' => 'Phoenician',
- 'pon' => 'Pohnpeian',
- 'pl' => 'Polish',
- 'pt' => 'Portuguese',
- 'cpp' => 'Portuguese-based Creole or Pidgin',
- 'pra' => 'Prakrit Language',
- 'pa' => 'Punjabi',
- 'qu' => 'Quechua',
- 'raj' => 'Rajasthani',
- 'rap' => 'Rapanui',
- 'rar' => 'Rarotongan',
- 'roa' => 'Romance Language',
- 'ro' => 'Romanian',
- 'rm' => 'Romansh',
- 'rom' => 'Romany',
- 'rof' => 'Rombo',
- 'root' => 'Root',
- 'rn' => 'Rundi',
- 'ru' => 'Russian',
- 'rwk' => 'Rwa',
- 'ssy' => 'Saho',
- 'sah' => 'Sakha',
- 'sal' => 'Salishan Language',
- 'sam' => 'Samaritan Aramaic',
- 'saq' => 'Samburu',
- 'smi' => 'Sami Language',
- 'sm' => 'Samoan',
- 'sad' => 'Sandawe',
- 'sg' => 'Sango',
- 'sbp' => 'Sangu',
- 'sa' => 'Sanskrit',
- 'sat' => 'Santali',
- 'sc' => 'Sardinian',
- 'sas' => 'Sasak',
- 'sco' => 'Scots',
- 'gd' => 'Scottish Gaelic',
- 'sel' => 'Selkup',
- 'sem' => 'Semitic Language',
- 'seh' => 'Sena',
- 'see' => 'Seneca',
- 'sr' => 'Serbian',
- 'sh' => 'Serbo-Croatian',
- 'srr' => 'Serer',
- 'ksb' => 'Shambala',
- 'shn' => 'Shan',
- 'sn' => 'Shona',
- 'ii' => 'Sichuan Yi',
- 'scn' => 'Sicilian',
- 'sid' => 'Sidamo',
- 'sgn' => 'Sign Language',
- 'bla' => 'Siksika',
- 'zh_Hans' => 'Simplified Chinese',
- 'sd' => 'Sindhi',
- 'si' => 'Sinhala',
- 'sit' => 'Sino-Tibetan Language',
- 'sio' => 'Siouan Language',
- 'sms' => 'Skolt Sami',
- 'den' => 'Slave',
- 'sla' => 'Slavic Language',
- 'sk' => 'Slovak',
- 'sl' => 'Slovenian',
- 'xog' => 'Soga',
- 'sog' => 'Sogdien',
- 'so' => 'Somali',
- 'son' => 'Songhai',
- 'snk' => 'Soninke',
- 'ckb' => 'Sorani Kurdish',
- 'wen' => 'Sorbian Language',
- 'sai' => 'South American Indian Language',
- 'nr' => 'South Ndebele',
- 'alt' => 'Southern Altai',
- 'sma' => 'Southern Sami',
- 'st' => 'Southern Sotho',
- 'es' => 'Spanish',
- 'srn' => 'Sranan Tongo',
- 'suk' => 'Sukuma',
- 'sux' => 'Sumerian',
- 'su' => 'Sundanese',
- 'sus' => 'Susu',
- 'sw' => 'Swahili',
- 'ss' => 'Swati',
- 'sv' => 'Swedish',
- 'fr_CH' => 'Swiss French',
- 'gsw' => 'Swiss German',
- 'de_CH' => 'Swiss High German',
- 'syr' => 'Syriac',
- 'shi' => 'Tachelhit',
- 'tl' => 'Tagalog',
- 'ty' => 'Tahitian',
- 'tai' => 'Tai Language',
- 'dav' => 'Taita',
- 'tg' => 'Tajik',
- 'tmh' => 'Tamashek',
- 'ta' => 'Tamil',
- 'trv' => 'Taroko',
- 'twq' => 'Tasawaq',
- 'tt' => 'Tatar',
- 'te' => 'Telugu',
- 'ter' => 'Tereno',
- 'teo' => 'Teso',
- 'tet' => 'Tetum',
- 'th' => 'Thai',
- 'bo' => 'Tibetan',
- 'tig' => 'Tigre',
- 'ti' => 'Tigrinya',
- 'tem' => 'Timne',
- 'tiv' => 'Tiv',
- 'tli' => 'Tlingit',
- 'tpi' => 'Tok Pisin',
- 'tkl' => 'Tokelau',
- 'to' => 'Tongan',
- 'zh_Hant' => 'Traditional Chinese',
- 'tsi' => 'Tsimshian',
- 'ts' => 'Tsonga',
- 'tn' => 'Tswana',
- 'tum' => 'Tumbuka',
- 'tup' => 'Tupi Language',
- 'tr' => 'Turkish',
- 'tk' => 'Turkmen',
- 'tvl' => 'Tuvalu',
- 'tyv' => 'Tuvinian',
- 'tw' => 'Twi',
- 'kcg' => 'Tyap',
- 'en_US' => 'U.S. English',
- 'udm' => 'Udmurt',
- 'uga' => 'Ugaritic',
- 'ug' => 'Uighur',
- 'uk' => 'Ukrainian',
- 'umb' => 'Umbundu',
- 'und' => 'Unknown Language',
- 'hsb' => 'Upper Sorbian',
- 'ur' => 'Urdu',
- 'uz' => 'Uzbek',
- 'vai' => 'Vai',
- 've' => 'Venda',
- 'vi' => 'Vietnamese',
- 'vo' => 'Volapük',
- 'vot' => 'Votic',
- 'vun' => 'Vunjo',
- 'wak' => 'Wakashan Language',
- 'wa' => 'Walloon',
- 'wae' => 'Walser',
- 'war' => 'Waray',
- 'was' => 'Washo',
- 'cy' => 'Welsh',
- 'fy' => 'Western Frisian',
- 'wal' => 'Wolaytta',
- 'wo' => 'Wolof',
- 'xh' => 'Xhosa',
- 'yav' => 'Yangben',
- 'yao' => 'Yao',
- 'yap' => 'Yapese',
- 'ybb' => 'Yemba',
- 'yi' => 'Yiddish',
- 'yo' => 'Yoruba',
- 'ypk' => 'Yupik Language',
- 'znd' => 'Zande',
- 'zap' => 'Zapotec',
- 'dje' => 'Zarma',
- 'zza' => 'Zaza',
- 'zen' => 'Zenaga',
- 'za' => 'Zhuang',
- 'zu' => 'Zulu',
- 'zun' => 'Zuni',
- ),
- 'Scripts' => array(
- 'Afak' => 'Afaka',
- 'Hluw' => 'Anatolian Hieroglyphs',
- 'Arab' => 'Arabic',
- 'Armn' => 'Armenian',
- 'Avst' => 'Avestan',
- 'Bali' => 'Balinese',
- 'Bamu' => 'Bamum',
- 'Bass' => 'Bassa Vah',
- 'Batk' => 'Batak',
- 'Beng' => 'Bengali',
- 'Blis' => 'Blissymbols',
- 'Phlv' => 'Book Pahlavi',
- 'Bopo' => 'Bopomofo',
- 'Brah' => 'Brahmi',
- 'Brai' => 'Braille',
- 'Bugi' => 'Buginese',
- 'Buhd' => 'Buhid',
- 'Cari' => 'Carian',
- 'Cakm' => 'Chakma',
- 'Cham' => 'Cham',
- 'Cher' => 'Cherokee',
- 'Cirt' => 'Cirth',
- 'Zyyy' => 'Common',
- 'Copt' => 'Coptic',
- 'Cprt' => 'Cypriot',
- 'Cyrl' => 'Cyrillic',
- 'Dsrt' => 'Deseret',
- 'Deva' => 'Devanagari',
- 'Dupl' => 'Duployan shorthand',
- 'Syrn' => 'Eastern Syriac',
- 'Egyd' => 'Egyptian demotic',
- 'Egyh' => 'Egyptian hieratic',
- 'Egyp' => 'Egyptian hieroglyphs',
- 'Syre' => 'Estrangelo Syriac',
- 'Ethi' => 'Ethiopic',
- 'Latf' => 'Fraktur Latin',
- 'Lisu' => 'Fraser',
- 'Latg' => 'Gaelic Latin',
- 'Geor' => 'Georgian',
- 'Geok' => 'Georgian Khutsuri',
- 'Glag' => 'Glagolitic',
- 'Goth' => 'Gothic',
- 'Gran' => 'Grantha',
- 'Grek' => 'Greek',
- 'Gujr' => 'Gujarati',
- 'Guru' => 'Gurmukhi',
- 'Hani' => 'Han',
- 'Hang' => 'Hangul',
- 'Hano' => 'Hanunoo',
- 'Hebr' => 'Hebrew',
- 'Hira' => 'Hiragana',
- 'Armi' => 'Imperial Aramaic',
- 'Inds' => 'Indus',
- 'Zinh' => 'Inherited',
- 'Phli' => 'Inscriptional Pahlavi',
- 'Prti' => 'Inscriptional Parthian',
- 'Jpan' => 'Japanese',
- 'Hrkt' => 'Japanese syllabaries',
- 'Java' => 'Javanese',
- 'Jurc' => 'Jurchen',
- 'Kthi' => 'Kaithi',
- 'Knda' => 'Kannada',
- 'Kana' => 'Katakana',
- 'Kali' => 'Kayah Li',
- 'Khar' => 'Kharoshthi',
- 'Khmr' => 'Khmer',
- 'Khoj' => 'Khojki',
- 'Sind' => 'Khudawadi',
- 'Kore' => 'Korean',
- 'Kpel' => 'Kpelle',
- 'Lana' => 'Lanna',
- 'Laoo' => 'Lao',
- 'Latn' => 'Latin',
- 'Lepc' => 'Lepcha',
- 'Limb' => 'Limbu',
- 'Lina' => 'Linear A',
- 'Linb' => 'Linear B',
- 'Loma' => 'Loma',
- 'Lyci' => 'Lycian',
- 'Lydi' => 'Lydian',
- 'Mlym' => 'Malayalam',
- 'Mand' => 'Mandaean',
- 'Mani' => 'Manichaean',
- 'Zmth' => 'Mathematical Notation',
- 'Maya' => 'Mayan hieroglyphs',
- 'Mtei' => 'Meitei Mayek',
- 'Mend' => 'Mende',
- 'Mero' => 'Meroitic',
- 'Merc' => 'Meroitic Cursive',
- 'Mong' => 'Mongolian',
- 'Moon' => 'Moon',
- 'Mroo' => 'Mro',
- 'Mymr' => 'Myanmar',
- 'Nkoo' => 'N’Ko',
- 'Nbat' => 'Nabataean',
- 'Nkgb' => 'Naxi Geba',
- 'Talu' => 'New Tai Lue',
- 'Nshu' => 'Nüshu',
- 'Ogam' => 'Ogham',
- 'Olck' => 'Ol Chiki',
- 'Cyrs' => 'Old Church Slavonic Cyrillic',
- 'Hung' => 'Old Hungarian',
- 'Ital' => 'Old Italic',
- 'Narb' => 'Old North Arabian',
- 'Perm' => 'Old Permic',
- 'Xpeo' => 'Old Persian',
- 'Sarb' => 'Old South Arabian',
- 'Orya' => 'Oriya',
- 'Orkh' => 'Orkhon',
- 'Osma' => 'Osmanya',
- 'Hmng' => 'Pahawh Hmong',
- 'Palm' => 'Palmyrene',
- 'Phag' => 'Phags-pa',
- 'Phnx' => 'Phoenician',
- 'Plrd' => 'Pollard Phonetic',
- 'Phlp' => 'Psalter Pahlavi',
- 'Rjng' => 'Rejang',
- 'Roro' => 'Rongorongo',
- 'Runr' => 'Runic',
- 'Samr' => 'Samaritan',
- 'Sara' => 'Sarati',
- 'Saur' => 'Saurashtra',
- 'Shrd' => 'Sharada',
- 'Shaw' => 'Shavian',
- 'Sgnw' => 'SignWriting',
- 'Hans' => 'Simplified',
- 'Sinh' => 'Sinhala',
- 'Sora' => 'Sora Sompeng',
- 'Xsux' => 'Sumero-Akkadian Cuneiform',
- 'Sund' => 'Sundanese',
- 'Sylo' => 'Syloti Nagri',
- 'Zsym' => 'Symbols',
- 'Syrc' => 'Syriac',
- 'Tglg' => 'Tagalog',
- 'Tagb' => 'Tagbanwa',
- 'Tale' => 'Tai Le',
- 'Tavt' => 'Tai Viet',
- 'Takr' => 'Takri',
- 'Taml' => 'Tamil',
- 'Tang' => 'Tangut',
- 'Telu' => 'Telugu',
- 'Teng' => 'Tengwar',
- 'Thaa' => 'Thaana',
- 'Thai' => 'Thai',
- 'Tibt' => 'Tibetan',
- 'Tfng' => 'Tifinagh',
- 'Tirh' => 'Tirhuta',
- 'Hant' => 'Traditional',
- 'Ugar' => 'Ugaritic',
- 'Cans' => 'Unified Canadian Aboriginal Syllabics',
- 'Zzzz' => 'Unknown Script',
- 'Zxxx' => 'Unwritten',
- 'Vaii' => 'Vai',
- 'Wara' => 'Varang Kshiti',
- 'Visp' => 'Visible Speech',
- 'Syrj' => 'Western Syriac',
- 'Wole' => 'Woleai',
- 'Yiii' => 'Yi',
- ),
-);
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return array(
- 'Locales' => array(
- 'af' => 'Afrikaans',
- 'af_NA' => 'Afrikaans (Namibia)',
- 'agq' => 'Aghem',
- 'ak' => 'Akan',
- 'sq' => 'Albanian',
- 'am' => 'Amharic',
- 'ar' => 'Arabic',
- 'ar_DZ' => 'Arabic (Algeria)',
- 'ar_IQ' => 'Arabic (Iraq)',
- 'ar_JO' => 'Arabic (Jordan)',
- 'ar_LB' => 'Arabic (Lebanon)',
- 'ar_LY' => 'Arabic (Libya)',
- 'ar_MR' => 'Arabic (Mauritania)',
- 'ar_MA' => 'Arabic (Morocco)',
- 'ar_PS' => 'Arabic (Palestinian Territories)',
- 'ar_QA' => 'Arabic (Qatar)',
- 'ar_SA' => 'Arabic (Saudi Arabia)',
- 'ar_SY' => 'Arabic (Syria)',
- 'ar_TN' => 'Arabic (Tunisia)',
- 'ar_EH' => 'Arabic (Western Sahara)',
- 'ar_YE' => 'Arabic (Yemen)',
- 'hy' => 'Armenian',
- 'as' => 'Assamese',
- 'asa' => 'Asu',
- 'az' => 'Azerbaijani',
- 'az_Cyrl' => 'Azerbaijani (Cyrillic)',
- 'az_Latn' => 'Azerbaijani (Latin)',
- 'ksf' => 'Bafia',
- 'bm' => 'Bambara',
- 'bas' => 'Basaa',
- 'eu' => 'Basque',
- 'be' => 'Belarusian',
- 'bem' => 'Bemba',
- 'bez' => 'Bena',
- 'bn' => 'Bengali',
- 'bn_IN' => 'Bengali (India)',
- 'brx' => 'Bodo',
- 'bs' => 'Bosnian',
- 'bs_Cyrl' => 'Bosnian (Cyrillic)',
- 'br' => 'Breton',
- 'bg' => 'Bulgarian',
- 'my' => 'Burmese',
- 'my_MM' => 'Burmese (Myanmar [Burma])',
- 'ca' => 'Catalan',
- 'tzm' => 'Central Atlas Tamazight',
- 'tzm_Latn' => 'Central Atlas Tamazight (Latin)',
- 'chr' => 'Cherokee',
- 'chr_US' => 'Cherokee (United States)',
- 'cgg' => 'Chiga',
- 'zh' => 'Chinese',
- 'zh_Hans_HK' => 'Chinese (Simplified, Hong Kong SAR China)',
- 'zh_Hans_MO' => 'Chinese (Simplified, Macau SAR China)',
- 'zh_Hans_SG' => 'Chinese (Simplified, Singapore)',
- 'zh_Hans' => 'Chinese (Simplified)',
- 'zh_Hant_HK' => 'Chinese (Traditional, Hong Kong SAR China)',
- 'zh_Hant_MO' => 'Chinese (Traditional, Macau SAR China)',
- 'zh_Hant' => 'Chinese (Traditional)',
- 'swc' => 'Congo Swahili',
- 'kw' => 'Cornish',
- 'hr' => 'Croatian',
- 'cs' => 'Czech',
- 'da' => 'Danish',
- 'dua' => 'Duala',
- 'nl' => 'Dutch',
- 'nl_BE' => 'Dutch (Belgium)',
- 'dz' => 'Dzongkha',
- 'ebu' => 'Embu',
- 'en' => 'English',
- 'en_AU' => 'English (Australia)',
- 'en_BE' => 'English (Belgium)',
- 'en_BZ' => 'English (Belize)',
- 'en_BW' => 'English (Botswana)',
- 'en_CA' => 'English (Canada)',
- 'en_GI' => 'English (Gibraltar)',
- 'en_GG' => 'English (Guernsey)',
- 'en_HK' => 'English (Hong Kong SAR China)',
- 'en_IN' => 'English (India)',
- 'en_IE' => 'English (Ireland)',
- 'en_IM' => 'English (Isle of Man)',
- 'en_JM' => 'English (Jamaica)',
- 'en_JE' => 'English (Jersey)',
- 'en_LR' => 'English (Liberia)',
- 'en_MT' => 'English (Malta)',
- 'en_NA' => 'English (Namibia)',
- 'en_NZ' => 'English (New Zealand)',
- 'en_PK' => 'English (Pakistan)',
- 'en_PH' => 'English (Philippines)',
- 'en_PR' => 'English (Puerto Rico)',
- 'en_SG' => 'English (Singapore)',
- 'en_ZA' => 'English (South Africa)',
- 'en_TT' => 'English (Trinidad and Tobago)',
- 'en_GB' => 'English (United Kingdom)',
- 'en_US' => 'English (United States)',
- 'en_ZW' => 'English (Zimbabwe)',
- 'eo' => 'Esperanto',
- 'et' => 'Estonian',
- 'ee' => 'Ewe',
- 'ewo' => 'Ewondo',
- 'fo' => 'Faroese',
- 'fil' => 'Filipino',
- 'fil_PH' => 'Filipino (Philippines)',
- 'fi' => 'Finnish',
- 'fr' => 'French',
- 'fr_BE' => 'French (Belgium)',
- 'fr_CA' => 'French (Canada)',
- 'fr_LU' => 'French (Luxembourg)',
- 'fr_CH' => 'French (Switzerland)',
- 'ff' => 'Fulah',
- 'gl' => 'Galician',
- 'lg' => 'Ganda',
- 'ka' => 'Georgian',
- 'de' => 'German',
- 'de_AT' => 'German (Austria)',
- 'de_LI' => 'German (Liechtenstein)',
- 'de_CH' => 'German (Switzerland)',
- 'el' => 'Greek',
- 'el_CY' => 'Greek (Cyprus)',
- 'gu' => 'Gujarati',
- 'guz' => 'Gusii',
- 'ha' => 'Hausa',
- 'ha_Latn' => 'Hausa (Latin)',
- 'haw' => 'Hawaiian',
- 'haw_US' => 'Hawaiian (United States)',
- 'he' => 'Hebrew',
- 'hi' => 'Hindi',
- 'hu' => 'Hungarian',
- 'is' => 'Icelandic',
- 'ig' => 'Igbo',
- 'id' => 'Indonesian',
- 'ga' => 'Irish',
- 'it' => 'Italian',
- 'it_CH' => 'Italian (Switzerland)',
- 'ja' => 'Japanese',
- 'dyo' => 'Jola-Fonyi',
- 'kea' => 'Kabuverdianu',
- 'kab' => 'Kabyle',
- 'kl' => 'Kalaallisut',
- 'kln' => 'Kalenjin',
- 'kam' => 'Kamba',
- 'kn' => 'Kannada',
- 'ks' => 'Kashmiri',
- 'ks_Arab' => 'Kashmiri (Arabic)',
- 'kk' => 'Kazakh',
- 'kk_Cyrl' => 'Kazakh (Cyrillic)',
- 'km' => 'Khmer',
- 'ki' => 'Kikuyu',
- 'rw' => 'Kinyarwanda',
- 'kok' => 'Konkani',
- 'ko' => 'Korean',
- 'khq' => 'Koyra Chiini',
- 'ses' => 'Koyraboro Senni',
- 'nmg' => 'Kwasio',
- 'lag' => 'Langi',
- 'lo' => 'Lao',
- 'lv' => 'Latvian',
- 'ln' => 'Lingala',
- 'lt' => 'Lithuanian',
- 'lu' => 'Luba-Katanga',
- 'luo' => 'Luo',
- 'luy' => 'Luyia',
- 'mk' => 'Macedonian',
- 'jmc' => 'Machame',
- 'mgh' => 'Makhuwa-Meetto',
- 'kde' => 'Makonde',
- 'mg' => 'Malagasy',
- 'ms' => 'Malay',
- 'ms_BN' => 'Malay (Brunei)',
- 'ml' => 'Malayalam',
- 'mt' => 'Maltese',
- 'gv' => 'Manx',
- 'mr' => 'Marathi',
- 'mas' => 'Masai',
- 'mer' => 'Meru',
- 'mgo' => 'Meta\'',
- 'mfe' => 'Morisyen',
- 'mua' => 'Mundang',
- 'naq' => 'Nama',
- 'ne' => 'Nepali',
- 'ne_IN' => 'Nepali (India)',
- 'jgo' => 'Ngomba',
- 'nd' => 'North Ndebele',
- 'nb' => 'Norwegian Bokmål',
- 'nn' => 'Norwegian Nynorsk',
- 'nus' => 'Nuer',
- 'nyn' => 'Nyankole',
- 'or' => 'Oriya',
- 'om' => 'Oromo',
- 'ps' => 'Pashto',
- 'fa' => 'Persian',
- 'fa_AF' => 'Persian (Afghanistan)',
- 'pl' => 'Polish',
- 'pt' => 'Portuguese',
- 'pt_AO' => 'Portuguese (Angola)',
- 'pt_CV' => 'Portuguese (Cape Verde)',
- 'pt_GW' => 'Portuguese (Guinea-Bissau)',
- 'pt_MO' => 'Portuguese (Macau SAR China)',
- 'pt_MZ' => 'Portuguese (Mozambique)',
- 'pt_PT' => 'Portuguese (Portugal)',
- 'pt_ST' => 'Portuguese (São Tomé and Príncipe)',
- 'pt_TL' => 'Portuguese (Timor-Leste)',
- 'pa' => 'Punjabi',
- 'pa_Arab' => 'Punjabi (Arabic)',
- 'pa_Guru' => 'Punjabi (Gurmukhi)',
- 'ro' => 'Romanian',
- 'rm' => 'Romansh',
- 'rof' => 'Rombo',
- 'rn' => 'Rundi',
- 'ru' => 'Russian',
- 'ru_UA' => 'Russian (Ukraine)',
- 'rwk' => 'Rwa',
- 'saq' => 'Samburu',
- 'sg' => 'Sango',
- 'sbp' => 'Sangu',
- 'seh' => 'Sena',
- 'sr' => 'Serbian',
- 'sr_Cyrl_BA' => 'Serbian (Cyrillic, Bosnia and Herzegovina)',
- 'sr_Cyrl' => 'Serbian (Cyrillic)',
- 'sr_Latn_ME' => 'Serbian (Latin, Montenegro)',
- 'sr_Latn' => 'Serbian (Latin)',
- 'ksb' => 'Shambala',
- 'sn' => 'Shona',
- 'ii' => 'Sichuan Yi',
- 'si' => 'Sinhala',
- 'sk' => 'Slovak',
- 'sl' => 'Slovenian',
- 'xog' => 'Soga',
- 'so' => 'Somali',
- 'es' => 'Spanish',
- 'es_AR' => 'Spanish (Argentina)',
- 'es_BO' => 'Spanish (Bolivia)',
- 'es_CL' => 'Spanish (Chile)',
- 'es_CO' => 'Spanish (Colombia)',
- 'es_CR' => 'Spanish (Costa Rica)',
- 'es_CU' => 'Spanish (Cuba)',
- 'es_DO' => 'Spanish (Dominican Republic)',
- 'es_EC' => 'Spanish (Ecuador)',
- 'es_SV' => 'Spanish (El Salvador)',
- 'es_GQ' => 'Spanish (Equatorial Guinea)',
- 'es_GT' => 'Spanish (Guatemala)',
- 'es_HN' => 'Spanish (Honduras)',
- 'es_MX' => 'Spanish (Mexico)',
- 'es_NI' => 'Spanish (Nicaragua)',
- 'es_PA' => 'Spanish (Panama)',
- 'es_PY' => 'Spanish (Paraguay)',
- 'es_PE' => 'Spanish (Peru)',
- 'es_PH' => 'Spanish (Philippines)',
- 'es_PR' => 'Spanish (Puerto Rico)',
- 'es_US' => 'Spanish (United States)',
- 'es_UY' => 'Spanish (Uruguay)',
- 'es_VE' => 'Spanish (Venezuela)',
- 'sw' => 'Swahili',
- 'sw_KE' => 'Swahili (Kenya)',
- 'sv' => 'Swedish',
- 'sv_FI' => 'Swedish (Finland)',
- 'gsw' => 'Swiss German',
- 'shi' => 'Tachelhit',
- 'shi_Latn' => 'Tachelhit (Latin)',
- 'shi_Tfng' => 'Tachelhit (Tifinagh)',
- 'dav' => 'Taita',
- 'ta' => 'Tamil',
- 'ta_MY' => 'Tamil (Malaysia)',
- 'ta_SG' => 'Tamil (Singapore)',
- 'twq' => 'Tasawaq',
- 'te' => 'Telugu',
- 'teo' => 'Teso',
- 'th' => 'Thai',
- 'bo' => 'Tibetan',
- 'ti' => 'Tigrinya',
- 'ti_ER' => 'Tigrinya (Eritrea)',
- 'to' => 'Tongan',
- 'tr' => 'Turkish',
- 'uk' => 'Ukrainian',
- 'ur' => 'Urdu',
- 'ur_IN' => 'Urdu (India)',
- 'uz' => 'Uzbek',
- 'uz_Arab' => 'Uzbek (Arabic)',
- 'uz_Cyrl' => 'Uzbek (Cyrillic)',
- 'uz_Latn' => 'Uzbek (Latin)',
- 'vai' => 'Vai',
- 'vai_Latn_LR' => 'Vai (Latin, Liberia)',
- 'vai_Latn' => 'Vai (Latin)',
- 'vai_Vaii_LR' => 'Vai (Vai, Liberia)',
- 'vai_Vaii' => 'Vai (Vai)',
- 'vi' => 'Vietnamese',
- 'vun' => 'Vunjo',
- 'cy' => 'Welsh',
- 'yav' => 'Yangben',
- 'yo' => 'Yoruba',
- 'dje' => 'Zarma',
- 'zu' => 'Zulu',
- ),
-);
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return array(
- 'Countries' => array(
- 'AF' => 'Afghanistan',
- 'AX' => 'Åland Islands',
- 'AL' => 'Albania',
- 'DZ' => 'Algeria',
- 'AS' => 'American Samoa',
- 'AD' => 'Andorra',
- 'AO' => 'Angola',
- 'AI' => 'Anguilla',
- 'AQ' => 'Antarctica',
- 'AG' => 'Antigua and Barbuda',
- 'AR' => 'Argentina',
- 'AM' => 'Armenia',
- 'AW' => 'Aruba',
- 'AC' => 'Ascension Island',
- 'AU' => 'Australia',
- 'AT' => 'Austria',
- 'AZ' => 'Azerbaijan',
- 'BS' => 'Bahamas',
- 'BH' => 'Bahrain',
- 'BD' => 'Bangladesh',
- 'BB' => 'Barbados',
- 'BY' => 'Belarus',
- 'BE' => 'Belgium',
- 'BZ' => 'Belize',
- 'BJ' => 'Benin',
- 'BM' => 'Bermuda',
- 'BT' => 'Bhutan',
- 'BO' => 'Bolivia',
- 'BA' => 'Bosnia and Herzegovina',
- 'BW' => 'Botswana',
- 'BV' => 'Bouvet Island',
- 'BR' => 'Brazil',
- 'IO' => 'British Indian Ocean Territory',
- 'VG' => 'British Virgin Islands',
- 'BN' => 'Brunei',
- 'BG' => 'Bulgaria',
- 'BF' => 'Burkina Faso',
- 'BI' => 'Burundi',
- 'KH' => 'Cambodia',
- 'CM' => 'Cameroon',
- 'CA' => 'Canada',
- 'IC' => 'Canary Islands',
- 'CV' => 'Cape Verde',
- 'BQ' => 'Caribbean Netherlands',
- 'KY' => 'Cayman Islands',
- 'CF' => 'Central African Republic',
- 'EA' => 'Ceuta and Melilla',
- 'TD' => 'Chad',
- 'CL' => 'Chile',
- 'CN' => 'China',
- 'CX' => 'Christmas Island',
- 'CP' => 'Clipperton Island',
- 'CC' => 'Cocos [Keeling] Islands',
- 'CO' => 'Colombia',
- 'KM' => 'Comoros',
- 'CG' => 'Congo - Brazzaville',
- 'CD' => 'Congo - Kinshasa',
- 'CK' => 'Cook Islands',
- 'CR' => 'Costa Rica',
- 'CI' => 'Côte d’Ivoire',
- 'HR' => 'Croatia',
- 'CU' => 'Cuba',
- 'CW' => 'Curaçao',
- 'CY' => 'Cyprus',
- 'CZ' => 'Czech Republic',
- 'DK' => 'Denmark',
- 'DG' => 'Diego Garcia',
- 'DJ' => 'Djibouti',
- 'DM' => 'Dominica',
- 'DO' => 'Dominican Republic',
- 'EC' => 'Ecuador',
- 'EG' => 'Egypt',
- 'SV' => 'El Salvador',
- 'GQ' => 'Equatorial Guinea',
- 'ER' => 'Eritrea',
- 'EE' => 'Estonia',
- 'ET' => 'Ethiopia',
- 'EU' => 'European Union',
- 'FK' => 'Falkland Islands',
- 'FO' => 'Faroe Islands',
- 'FJ' => 'Fiji',
- 'FI' => 'Finland',
- 'FR' => 'France',
- 'GF' => 'French Guiana',
- 'PF' => 'French Polynesia',
- 'TF' => 'French Southern Territories',
- 'GA' => 'Gabon',
- 'GM' => 'Gambia',
- 'GE' => 'Georgia',
- 'DE' => 'Germany',
- 'GH' => 'Ghana',
- 'GI' => 'Gibraltar',
- 'GR' => 'Greece',
- 'GL' => 'Greenland',
- 'GD' => 'Grenada',
- 'GP' => 'Guadeloupe',
- 'GU' => 'Guam',
- 'GT' => 'Guatemala',
- 'GG' => 'Guernsey',
- 'GN' => 'Guinea',
- 'GW' => 'Guinea-Bissau',
- 'GY' => 'Guyana',
- 'HT' => 'Haiti',
- 'HM' => 'Heard Island and McDonald Islands',
- 'HN' => 'Honduras',
- 'HK' => 'Hong Kong SAR China',
- 'HU' => 'Hungary',
- 'IS' => 'Iceland',
- 'IN' => 'India',
- 'ID' => 'Indonesia',
- 'IR' => 'Iran',
- 'IQ' => 'Iraq',
- 'IE' => 'Ireland',
- 'IM' => 'Isle of Man',
- 'IL' => 'Israel',
- 'IT' => 'Italy',
- 'JM' => 'Jamaica',
- 'JP' => 'Japan',
- 'JE' => 'Jersey',
- 'JO' => 'Jordan',
- 'KZ' => 'Kazakhstan',
- 'KE' => 'Kenya',
- 'KI' => 'Kiribati',
- 'KW' => 'Kuwait',
- 'KG' => 'Kyrgyzstan',
- 'LA' => 'Laos',
- 'LV' => 'Latvia',
- 'LB' => 'Lebanon',
- 'LS' => 'Lesotho',
- 'LR' => 'Liberia',
- 'LY' => 'Libya',
- 'LI' => 'Liechtenstein',
- 'LT' => 'Lithuania',
- 'LU' => 'Luxembourg',
- 'MO' => 'Macau SAR China',
- 'MK' => 'Macedonia',
- 'MG' => 'Madagascar',
- 'MW' => 'Malawi',
- 'MY' => 'Malaysia',
- 'MV' => 'Maldives',
- 'ML' => 'Mali',
- 'MT' => 'Malta',
- 'MH' => 'Marshall Islands',
- 'MQ' => 'Martinique',
- 'MR' => 'Mauritania',
- 'MU' => 'Mauritius',
- 'YT' => 'Mayotte',
- 'MX' => 'Mexico',
- 'FM' => 'Micronesia',
- 'MD' => 'Moldova',
- 'MC' => 'Monaco',
- 'MN' => 'Mongolia',
- 'ME' => 'Montenegro',
- 'MS' => 'Montserrat',
- 'MA' => 'Morocco',
- 'MZ' => 'Mozambique',
- 'MM' => 'Myanmar [Burma]',
- 'NA' => 'Namibia',
- 'NR' => 'Nauru',
- 'NP' => 'Nepal',
- 'NL' => 'Netherlands',
- 'AN' => 'Netherlands Antilles',
- 'NC' => 'New Caledonia',
- 'NZ' => 'New Zealand',
- 'NI' => 'Nicaragua',
- 'NE' => 'Niger',
- 'NG' => 'Nigeria',
- 'NU' => 'Niue',
- 'NF' => 'Norfolk Island',
- 'KP' => 'North Korea',
- 'MP' => 'Northern Mariana Islands',
- 'NO' => 'Norway',
- 'OM' => 'Oman',
- 'QO' => 'Outlying Oceania',
- 'PK' => 'Pakistan',
- 'PW' => 'Palau',
- 'PS' => 'Palestinian Territories',
- 'PA' => 'Panama',
- 'PG' => 'Papua New Guinea',
- 'PY' => 'Paraguay',
- 'PE' => 'Peru',
- 'PH' => 'Philippines',
- 'PN' => 'Pitcairn Islands',
- 'PL' => 'Poland',
- 'PT' => 'Portugal',
- 'PR' => 'Puerto Rico',
- 'QA' => 'Qatar',
- 'RE' => 'Réunion',
- 'RO' => 'Romania',
- 'RU' => 'Russia',
- 'RW' => 'Rwanda',
- 'BL' => 'Saint Barthélemy',
- 'SH' => 'Saint Helena',
- 'KN' => 'Saint Kitts and Nevis',
- 'LC' => 'Saint Lucia',
- 'MF' => 'Saint Martin',
- 'PM' => 'Saint Pierre and Miquelon',
- 'VC' => 'Saint Vincent and the Grenadines',
- 'WS' => 'Samoa',
- 'SM' => 'San Marino',
- 'ST' => 'São Tomé and Príncipe',
- 'SA' => 'Saudi Arabia',
- 'SN' => 'Senegal',
- 'RS' => 'Serbia',
- 'SC' => 'Seychelles',
- 'SL' => 'Sierra Leone',
- 'SG' => 'Singapore',
- 'SX' => 'Sint Maarten',
- 'SK' => 'Slovakia',
- 'SI' => 'Slovenia',
- 'SB' => 'Solomon Islands',
- 'SO' => 'Somalia',
- 'ZA' => 'South Africa',
- 'GS' => 'South Georgia and the South Sandwich Islands',
- 'KR' => 'South Korea',
- 'SS' => 'South Sudan',
- 'ES' => 'Spain',
- 'LK' => 'Sri Lanka',
- 'SD' => 'Sudan',
- 'SR' => 'Suriname',
- 'SJ' => 'Svalbard and Jan Mayen',
- 'SZ' => 'Swaziland',
- 'SE' => 'Sweden',
- 'CH' => 'Switzerland',
- 'SY' => 'Syria',
- 'TW' => 'Taiwan',
- 'TJ' => 'Tajikistan',
- 'TZ' => 'Tanzania',
- 'TH' => 'Thailand',
- 'TL' => 'Timor-Leste',
- 'TG' => 'Togo',
- 'TK' => 'Tokelau',
- 'TO' => 'Tonga',
- 'TT' => 'Trinidad and Tobago',
- 'TA' => 'Tristan da Cunha',
- 'TN' => 'Tunisia',
- 'TR' => 'Turkey',
- 'TM' => 'Turkmenistan',
- 'TC' => 'Turks and Caicos Islands',
- 'TV' => 'Tuvalu',
- 'UM' => 'U.S. Outlying Islands',
- 'VI' => 'U.S. Virgin Islands',
- 'UG' => 'Uganda',
- 'UA' => 'Ukraine',
- 'AE' => 'United Arab Emirates',
- 'GB' => 'United Kingdom',
- 'US' => 'United States',
- 'UY' => 'Uruguay',
- 'UZ' => 'Uzbekistan',
- 'VU' => 'Vanuatu',
- 'VA' => 'Vatican City',
- 'VE' => 'Venezuela',
- 'VN' => 'Vietnam',
- 'WF' => 'Wallis and Futuna',
- 'EH' => 'Western Sahara',
- 'YE' => 'Yemen',
- 'ZM' => 'Zambia',
- 'ZW' => 'Zimbabwe',
- ),
-);
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Icu\Tests;
-
-use Symfony\Component\Icu\IcuCurrencyBundle;
-use Symfony\Component\Icu\IcuLanguageBundle;
-use Symfony\Component\Icu\IcuLocaleBundle;
-use Symfony\Component\Icu\IcuRegionBundle;
-use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader;
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader;
-
-/**
- * Verifies that the data files can actually be read.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuIntegrationTest extends \PHPUnit_Framework_TestCase
-{
- public function testCurrencyBundle()
- {
- $bundle = new IcuCurrencyBundle(new StructuredBundleReader(new PhpBundleReader()));
-
- $this->assertSame('€', $bundle->getCurrencySymbol('EUR', 'en'));
- }
-
- public function testLanguageBundle()
- {
- $bundle = new IcuLanguageBundle(new StructuredBundleReader(new PhpBundleReader()));
-
- $this->assertSame('German', $bundle->getLanguageName('de', null, 'en'));
- }
-
- public function testLocaleBundle()
- {
- $bundle = new IcuLocaleBundle(new StructuredBundleReader(new PhpBundleReader()));
-
- $this->assertSame('Azerbaijani', $bundle->getLocaleName('az', 'en'));
- }
-
- public function testRegionBundle()
- {
- $bundle = new IcuRegionBundle(new StructuredBundleReader(new PhpBundleReader()));
-
- $this->assertSame('United Kingdom', $bundle->getCountryName('GB', 'en'));
- }
-}
+++ /dev/null
-{
- "name": "symfony/icu",
- "type": "library",
- "description": "Contains an excerpt of the ICU data and classes to load it.",
- "keywords": ["icu", "intl"],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3",
- "symfony/intl": "~2.3"
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\Icu\\": "" }
- },
- "target-dir": "Symfony/Component/Icu"
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony Icu Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./Tests</directory>
- <directory>./vendor</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
+++ /dev/null
-Contributing to the Intl component
-==================================
-
-A very good way of contributing to the Intl component is by updating the
-included data for the ICU version you have installed on your system.
-
-Preparation
------------
-
-To prepare, you need to install the development dependencies of the component.
-
- $ cd /path/to/Symfony/Component/Intl
- $ composer.phar install --dev
-
-Determining your ICU version
----------------------------
-
-The ICU version installed in your PHP environment can be found by running
-icu-version.php:
-
- $ php Resources/bin/icu-version.php
-
-Updating the ICU data
----------------------
-
-To update the data files, run the update-icu-component.php script:
-
- $ php Resources/bin/update-icu-component.php
-
-The script needs the binaries "svn" and "make" to be available on your system.
-It will download the latest version of the ICU sources for the ICU version
-installed in your PHP environment. The script will then compile the "genrb"
-binary and use it to compile the ICU data files to binaries. The binaries are
-copied to the Resources/ directory of the Icu component found in the
-vendor/symfony/icu/ directory.
-
-Updating the stub data
-----------------------
-
-In the previous step you updated the Icu component for the ICU version
-installed on your system. If you are using the latest ICU version, you should
-also create the stub data files which will be used by people who don't have
-the intl extension installed.
-
-To update the stub files, run the update-stubs.php script:
-
- $ php Resources/bin/update-stubs.php
-
-The script will fail if you don't have the latest ICU version. If you want to
-upgrade the ICU version, adjust the return value of the
-`Intl::getIcuStubVersion()` before you run the script.
-
-The script creates copies of the binary resource bundles in the Icu component
-and stores them in the Resources/ directory of the Intl component. The copies
-are made for the locale "en" only and are stored in .php files, so that they
-can be read even if the intl extension is not available.
-
-Creating a pull request
------------------------
-
-You need to create up to two pull requests:
-
-* If you updated the Icu component, you need to push that change and create a
- pull request in the `symfony/Icu` repository. Make sure to submit the pull
- request to the correct master branch. If you updated the ICU data for version
- 4.8, your pull request goes to branch `48-master`, for version 49 to
- `49-master` and so on.
-
-* If you updated the stub files of the Intl component, you need to push that
- change and create a pull request in the `symfony/symfony` repository. The
- pull request should be based on the `master` branch.
-
-Combining .res files to a .dat-package
---------------------------------------
-
-The individual *.res files can be combined into a single .dat-file.
-Unfortunately, PHP's `ResourceBundle` class is currently not able to handle
-.dat-files.
-
-Once it is, the following steps have to be followed to build the .dat-file:
-
-1. Package the resource bundles into a single file
-
- $ find . -name *.res | sed -e "s/\.\///g" > packagelist.txt
- $ pkgdata -p region -T build -d . packagelist.txt
-
-2. Clean up
-
- $ rm -rf build packagelist.txt
-
-3. You can now move region.dat to replace the version bundled with Symfony2.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Collator;
-
-use Symfony\Component\Intl\Exception\MethodNotImplementedException;
-use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
-use Symfony\Component\Intl\Globals\IntlGlobals;
-use Symfony\Component\Intl\Locale\Locale;
-
-/**
- * Replacement for PHP's native {@link \Collator} class.
- *
- * The only methods currently supported in this class are:
- *
- * - {@link \__construct}
- * - {@link create}
- * - {@link asort}
- * - {@link getErrorCode}
- * - {@link getErrorMessage}
- * - {@link getLocale}
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Collator
-{
- /* Attribute constants */
- const FRENCH_COLLATION = 0;
- const ALTERNATE_HANDLING = 1;
- const CASE_FIRST = 2;
- const CASE_LEVEL = 3;
- const NORMALIZATION_MODE = 4;
- const STRENGTH = 5;
- const HIRAGANA_QUATERNARY_MODE = 6;
- const NUMERIC_COLLATION = 7;
-
- /* Attribute constants values */
- const DEFAULT_VALUE = -1;
-
- const PRIMARY = 0;
- const SECONDARY = 1;
- const TERTIARY = 2;
- const DEFAULT_STRENGTH = 2;
- const QUATERNARY = 3;
- const IDENTICAL = 15;
-
- const OFF = 16;
- const ON = 17;
-
- const SHIFTED = 20;
- const NON_IGNORABLE = 21;
-
- const LOWER_FIRST = 24;
- const UPPER_FIRST = 25;
-
- /* Sorting options */
- const SORT_REGULAR = 0;
- const SORT_NUMERIC = 2;
- const SORT_STRING = 1;
-
- /**
- * Constructor
- *
- * @param string $locale The locale code. The only currently supported locale is "en".
- *
- * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
- */
- public function __construct($locale)
- {
- if ('en' != $locale) {
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the locale "en" is supported');
- }
- }
-
- /**
- * Static constructor
- *
- * @param string $locale The locale code. The only currently supported locale is "en".
- *
- * @return Collator
- *
- * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
- */
- public static function create($locale)
- {
- return new self($locale);
- }
-
- /**
- * Sort array maintaining index association
- *
- * @param array &$array Input array
- * @param integer $sortFlag Flags for sorting, can be one of the following:
- * Collator::SORT_REGULAR - compare items normally (don't change types)
- * Collator::SORT_NUMERIC - compare items numerically
- * Collator::SORT_STRING - compare items as strings
- *
- * @return Boolean True on success or false on failure
- */
- public function asort(&$array, $sortFlag = self::SORT_REGULAR)
- {
- $intlToPlainFlagMap = array(
- self::SORT_REGULAR => \SORT_REGULAR,
- self::SORT_NUMERIC => \SORT_NUMERIC,
- self::SORT_STRING => \SORT_STRING,
- );
-
- $plainSortFlag = isset($intlToPlainFlagMap[$sortFlag]) ? $intlToPlainFlagMap[$sortFlag] : self::SORT_REGULAR;
-
- return asort($array, $plainSortFlag);
- }
-
- /**
- * Not supported. Compare two Unicode strings
- *
- * @param string $str1 The first string to compare
- * @param string $str2 The second string to compare
- *
- * @return Boolean|int Return the comparison result or false on failure:
- * 1 if $str1 is greater than $str2
- * 0 if $str1 is equal than $str2
- * -1 if $str1 is less than $str2
- *
- * @see http://www.php.net/manual/en/collator.compare.php
- *
- * @throws MethodNotImplementedException
- */
- public function compare($str1, $str2)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Get a value of an integer collator attribute
- *
- * @param int $attr An attribute specifier, one of the attribute constants
- *
- * @return Boolean|int The attribute value on success or false on error
- *
- * @see http://www.php.net/manual/en/collator.getattribute.php
- *
- * @throws MethodNotImplementedException
- */
- public function getAttribute($attr)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Returns collator's last error code. Always returns the U_ZERO_ERROR class constant value
- *
- * @return int The error code from last collator call
- */
- public function getErrorCode()
- {
- return IntlGlobals::U_ZERO_ERROR;
- }
-
- /**
- * Returns collator's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
- *
- * @return string The error message from last collator call
- */
- public function getErrorMessage()
- {
- return 'U_ZERO_ERROR';
- }
-
- /**
- * Returns the collator's locale
- *
- * @param int $type Not supported. The locale name type to return (Locale::VALID_LOCALE or Locale::ACTUAL_LOCALE)
- *
- * @return string The locale used to create the collator. Currently always
- * returns "en".
- */
- public function getLocale($type = Locale::ACTUAL_LOCALE)
- {
- return 'en';
- }
-
- /**
- * Not supported. Get sorting key for a string
- *
- * @param string $string The string to produce the key from
- *
- * @return string The collation key for $string
- *
- * @see http://www.php.net/manual/en/collator.getsortkey.php
- *
- * @throws MethodNotImplementedException
- */
- public function getSortKey($string)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Get current collator's strength
- *
- * @return Boolean|int The current collator's strength or false on failure
- *
- * @see http://www.php.net/manual/en/collator.getstrength.php
- *
- * @throws MethodNotImplementedException
- */
- public function getStrength()
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Set a collator's attribute
- *
- * @param int $attr An attribute specifier, one of the attribute constants
- * @param int $val The attribute value, one of the attribute value constants
- *
- * @return Boolean True on success or false on failure
- *
- * @see http://www.php.net/manual/en/collator.setattribute.php
- *
- * @throws MethodNotImplementedException
- */
- public function setAttribute($attr, $val)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Set the collator's strength
- *
- * @param int $strength Strength to set, possible values:
- * Collator::PRIMARY
- * Collator::SECONDARY
- * Collator::TERTIARY
- * Collator::QUATERNARY
- * Collator::IDENTICAL
- * Collator::DEFAULT
- *
- * @return Boolean True on success or false on failure
- *
- * @see http://www.php.net/manual/en/collator.setstrength.php
- *
- * @throws MethodNotImplementedException
- */
- public function setStrength($strength)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Sort array using specified collator and sort keys
- *
- * @param array &$arr Array of strings to sort
- *
- * @return Boolean True on success or false on failure
- *
- * @see http://www.php.net/manual/en/collator.sortwithsortkeys.php
- *
- * @throws MethodNotImplementedException
- */
- public function sortWithSortKeys(&$arr)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Sort array using specified collator
- *
- * @param array &$arr Array of string to sort
- * @param int $sortFlag Optional sorting type, one of the following:
- * Collator::SORT_REGULAR
- * Collator::SORT_NUMERIC
- * Collator::SORT_STRING
- *
- * @return Boolean True on success or false on failure
- *
- * @see http://www.php.net/manual/en/collator.sort.php
- *
- * @throws MethodNotImplementedException
- */
- public function sort(&$arr, $sortFlag = self::SORT_REGULAR)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for AM/PM markers format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class AmPmTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- return $dateTime->format('A');
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return 'AM|PM';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'marker' => $matched
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for day of week format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class DayOfWeekTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $dayOfWeek = $dateTime->format('l');
- switch ($length) {
- case 4:
- return $dayOfWeek;
- case 5:
- return $dayOfWeek[0];
- default:
- return substr($dayOfWeek, 0, 3);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- switch ($length) {
- case 4:
- return 'Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday';
- case 5:
- return '[MTWFS]';
- default:
- return 'Mon|Tue|Wed|Thu|Fri|Sat|Sun';
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for day of year format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class DayOfYearTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $dayOfYear = $dateTime->format('z') + 1;
-
- return $this->padLeft($dayOfYear, $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return '\d{'.$length.'}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for day format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class DayTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- return $this->padLeft($dateTime->format('j'), $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'day' => (int) $matched,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-use Symfony\Component\Intl\Exception\NotImplementedException;
-use Symfony\Component\Intl\Globals\IntlGlobals;
-use Symfony\Component\Intl\DateFormatter\DateFormat\MonthTransformer;
-
-/**
- * Parser and formatter for date formats
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class FullTransformer
-{
- private $quoteMatch = "'(?:[^']+|'')*'";
- private $implementedChars = 'MLydQqhDEaHkKmsz';
- private $notImplementedChars = 'GYuwWFgecSAZvVW';
- private $regExp;
-
- /**
- * @var Transformer[]
- */
- private $transformers;
-
- private $pattern;
- private $timezone;
-
- /**
- * Constructor
- *
- * @param string $pattern The pattern to be used to format and/or parse values
- * @param string $timezone The timezone to perform the date/time calculations
- */
- public function __construct($pattern, $timezone)
- {
- $this->pattern = $pattern;
- $this->timezone = $timezone;
-
- $implementedCharsMatch = $this->buildCharsMatch($this->implementedChars);
- $notImplementedCharsMatch = $this->buildCharsMatch($this->notImplementedChars);
- $this->regExp = "/($this->quoteMatch|$implementedCharsMatch|$notImplementedCharsMatch)/";
-
- $this->transformers = array(
- 'M' => new MonthTransformer(),
- 'L' => new MonthTransformer(),
- 'y' => new YearTransformer(),
- 'd' => new DayTransformer(),
- 'q' => new QuarterTransformer(),
- 'Q' => new QuarterTransformer(),
- 'h' => new Hour1201Transformer(),
- 'D' => new DayOfYearTransformer(),
- 'E' => new DayOfWeekTransformer(),
- 'a' => new AmPmTransformer(),
- 'H' => new Hour2400Transformer(),
- 'K' => new Hour1200Transformer(),
- 'k' => new Hour2401Transformer(),
- 'm' => new MinuteTransformer(),
- 's' => new SecondTransformer(),
- 'z' => new TimeZoneTransformer(),
- );
- }
-
- /**
- * Return the array of Transformer objects
- *
- * @return Transformer[] Associative array of Transformer objects (format char => Transformer)
- */
- public function getTransformers()
- {
- return $this->transformers;
- }
-
- /**
- * Format a DateTime using ICU dateformat pattern
- *
- * @param \DateTime $dateTime A DateTime object to be used to generate the formatted value
- *
- * @return string The formatted value
- */
- public function format(\DateTime $dateTime)
- {
- $that = $this;
-
- $formatted = preg_replace_callback($this->regExp, function($matches) use ($that, $dateTime) {
- return $that->formatReplace($matches[0], $dateTime);
- }, $this->pattern);
-
- return $formatted;
- }
-
- /**
- * Return the formatted ICU value for the matched date characters
- *
- * @param string $dateChars The date characters to be replaced with a formatted ICU value
- * @param DateTime $dateTime A DateTime object to be used to generate the formatted value
- *
- * @return string The formatted value
- *
- * @throws NotImplementedException When it encounters a not implemented date character
- */
- public function formatReplace($dateChars, $dateTime)
- {
- $length = strlen($dateChars);
-
- if ($this->isQuoteMatch($dateChars)) {
- return $this->replaceQuoteMatch($dateChars);
- }
-
- if (isset($this->transformers[$dateChars[0]])) {
- $transformer = $this->transformers[$dateChars[0]];
-
- return $transformer->format($dateTime, $length);
- }
-
- // handle unimplemented characters
- if (false !== strpos($this->notImplementedChars, $dateChars[0])) {
- throw new NotImplementedException(sprintf("Unimplemented date character '%s' in format '%s'", $dateChars[0], $this->pattern));
- }
- }
-
- /**
- * Parse a pattern based string to a timestamp value
- *
- * @param \DateTime $dateTime A configured DateTime object to use to perform the date calculation
- * @param string $value String to convert to a time value
- *
- * @return int The corresponding Unix timestamp
- *
- * @throws \InvalidArgumentException When the value can not be matched with pattern
- */
- public function parse(\DateTime $dateTime, $value)
- {
- $reverseMatchingRegExp = $this->getReverseMatchingRegExp($this->pattern);
- $reverseMatchingRegExp = '/^'.$reverseMatchingRegExp.'$/';
-
- $options = array();
-
- if (preg_match($reverseMatchingRegExp, $value, $matches)) {
- $matches = $this->normalizeArray($matches);
-
- foreach ($this->transformers as $char => $transformer) {
- if (isset($matches[$char])) {
- $length = strlen($matches[$char]['pattern']);
- $options = array_merge($options, $transformer->extractDateOptions($matches[$char]['value'], $length));
- }
- }
-
- // reset error code and message
- IntlGlobals::setError(IntlGlobals::U_ZERO_ERROR);
-
- return $this->calculateUnixTimestamp($dateTime, $options);
- }
-
- // behave like the intl extension
- IntlGlobals::setError(IntlGlobals::U_PARSE_ERROR, 'Date parsing failed');
-
- return false;
- }
-
- /**
- * Retrieve a regular expression to match with a formatted value.
- *
- * @param string $pattern The pattern to create the reverse matching regular expression
- *
- * @return string The reverse matching regular expression with named captures being formed by the
- * transformer index in the $transformer array
- */
- public function getReverseMatchingRegExp($pattern)
- {
- $that = $this;
-
- $escapedPattern = preg_quote($pattern, '/');
-
- // ICU 4.8 recognizes slash ("/") in a value to be parsed as a dash ("-") and vice-versa
- // when parsing a date/time value
- $escapedPattern = preg_replace('/\\\[\-|\/]/', '[\/\-]', $escapedPattern);
-
- $reverseMatchingRegExp = preg_replace_callback($this->regExp, function($matches) use ($that) {
- $length = strlen($matches[0]);
- $transformerIndex = $matches[0][0];
-
- $dateChars = $matches[0];
- if ($that->isQuoteMatch($dateChars)) {
- return $that->replaceQuoteMatch($dateChars);
- }
-
- $transformers = $that->getTransformers();
- if (isset($transformers[$transformerIndex])) {
- $transformer = $transformers[$transformerIndex];
- $captureName = str_repeat($transformerIndex, $length);
-
- return "(?P<$captureName>".$transformer->getReverseMatchingRegExp($length).')';
- }
- }, $escapedPattern);
-
- return $reverseMatchingRegExp;
- }
-
- /**
- * Check if the first char of a string is a single quote
- *
- * @param string $quoteMatch The string to check
- *
- * @return Boolean true if matches, false otherwise
- */
- public function isQuoteMatch($quoteMatch)
- {
- return ("'" === $quoteMatch[0]);
- }
-
- /**
- * Replaces single quotes at the start or end of a string with two single quotes
- *
- * @param string $quoteMatch The string to replace the quotes
- *
- * @return string A string with the single quotes replaced
- */
- public function replaceQuoteMatch($quoteMatch)
- {
- if (preg_match("/^'+$/", $quoteMatch)) {
- return str_replace("''", "'", $quoteMatch);
- }
-
- return str_replace("''", "'", substr($quoteMatch, 1, -1));
- }
-
- /**
- * Builds a chars match regular expression
- *
- * @param string $specialChars A string of chars to build the regular expression
- *
- * @return string The chars match regular expression
- */
- protected function buildCharsMatch($specialChars)
- {
- $specialCharsArray = str_split($specialChars);
-
- $specialCharsMatch = implode('|', array_map(function($char) {
- return $char.'+';
- }, $specialCharsArray));
-
- return $specialCharsMatch;
- }
-
- /**
- * Normalize a preg_replace match array, removing the numeric keys and returning an associative array
- * with the value and pattern values for the matched Transformer
- *
- * @param array $data
- *
- * @return array
- */
- protected function normalizeArray(array $data)
- {
- $ret = array();
-
- foreach ($data as $key => $value) {
- if (!is_string($key)) {
- continue;
- }
-
- $ret[$key[0]] = array(
- 'value' => $value,
- 'pattern' => $key
- );
- }
-
- return $ret;
- }
-
- /**
- * Calculates the Unix timestamp based on the matched values by the reverse matching regular
- * expression of parse()
- *
- * @param \DateTime $dateTime The DateTime object to be used to calculate the timestamp
- * @param array $options An array with the matched values to be used to calculate the timestamp
- *
- * @return Boolean|int The calculated timestamp or false if matched date is invalid
- */
- protected function calculateUnixTimestamp(\DateTime $dateTime, array $options)
- {
- $options = $this->getDefaultValueForOptions($options);
-
- $year = $options['year'];
- $month = $options['month'];
- $day = $options['day'];
- $hour = $options['hour'];
- $hourInstance = $options['hourInstance'];
- $minute = $options['minute'];
- $second = $options['second'];
- $marker = $options['marker'];
- $timezone = $options['timezone'];
-
- // If month is false, return immediately (intl behavior)
- if (false === $month) {
- IntlGlobals::setError(IntlGlobals::U_PARSE_ERROR, 'Date parsing failed');
-
- return false;
- }
-
- // Normalize hour
- if ($hourInstance instanceof HourTransformer) {
- $hour = $hourInstance->normalizeHour($hour, $marker);
- }
-
- // Set the timezone if different from the default one
- if (null !== $timezone && $timezone !== $this->timezone) {
- $dateTime->setTimezone(new \DateTimeZone($timezone));
- }
-
- // Normalize yy year
- preg_match_all($this->regExp, $this->pattern, $matches);
- if (in_array('yy', $matches[0])) {
- $dateTime->setTimestamp(time());
- $year = $year > $dateTime->format('y') + 20 ? 1900 + $year : 2000 + $year;
- }
-
- $dateTime->setDate($year, $month, $day);
- $dateTime->setTime($hour, $minute, $second);
-
- return $dateTime->getTimestamp();
- }
-
- /**
- * Add sensible default values for missing items in the extracted date/time options array. The values
- * are base in the beginning of the Unix era
- *
- * @param array $options
- *
- * @return array
- */
- private function getDefaultValueForOptions(array $options)
- {
- return array(
- 'year' => isset($options['year']) ? $options['year'] : 1970,
- 'month' => isset($options['month']) ? $options['month'] : 1,
- 'day' => isset($options['day']) ? $options['day'] : 1,
- 'hour' => isset($options['hour']) ? $options['hour'] : 0,
- 'hourInstance' => isset($options['hourInstance']) ? $options['hourInstance'] : null,
- 'minute' => isset($options['minute']) ? $options['minute'] : 0,
- 'second' => isset($options['second']) ? $options['second'] : 0,
- 'marker' => isset($options['marker']) ? $options['marker'] : null,
- 'timezone' => isset($options['timezone']) ? $options['timezone'] : null,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for 12 hour format (0-11)
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class Hour1200Transformer extends HourTransformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $hourOfDay = $dateTime->format('g');
- $hourOfDay = '12' == $hourOfDay ? '0' : $hourOfDay;
-
- return $this->padLeft($hourOfDay, $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function normalizeHour($hour, $marker = null)
- {
- if ('PM' === $marker) {
- $hour += 12;
- }
-
- return $hour;
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return '\d{1,2}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'hour' => (int) $matched,
- 'hourInstance' => $this
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for 12 hour format (1-12)
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class Hour1201Transformer extends HourTransformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- return $this->padLeft($dateTime->format('g'), $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function normalizeHour($hour, $marker = null)
- {
- if ('PM' !== $marker && 12 === $hour) {
- $hour = 0;
- } elseif ('PM' === $marker && 12 !== $hour) {
- // If PM and hour is not 12 (1-12), sum 12 hour
- $hour += 12;
- }
-
- return $hour;
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return '\d{1,2}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'hour' => (int) $matched,
- 'hourInstance' => $this
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for 24 hour format (0-23)
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class Hour2400Transformer extends HourTransformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- return $this->padLeft($dateTime->format('G'), $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function normalizeHour($hour, $marker = null)
- {
- if ('AM' == $marker) {
- $hour = 0;
- } elseif ('PM' == $marker) {
- $hour = 12;
- }
-
- return $hour;
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return '\d{1,2}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'hour' => (int) $matched,
- 'hourInstance' => $this
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for 24 hour format (1-24)
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class Hour2401Transformer extends HourTransformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $hourOfDay = $dateTime->format('G');
- $hourOfDay = ('0' == $hourOfDay) ? '24' : $hourOfDay;
-
- return $this->padLeft($hourOfDay, $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function normalizeHour($hour, $marker = null)
- {
- if ((null === $marker && 24 === $hour) || 'AM' == $marker) {
- $hour = 0;
- } elseif ('PM' == $marker) {
- $hour = 12;
- }
-
- return $hour;
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return '\d{1,2}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'hour' => (int) $matched,
- 'hourInstance' => $this
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Base class for hour transformers
- *
- * @author Eriksen Costa <eriksen.costa@infranology.com.br>
- */
-abstract class HourTransformer extends Transformer
-{
- /**
- * Returns a normalized hour value suitable for the hour transformer type
- *
- * @param int $hour The hour value
- * @param string $marker An optional AM/PM marker
- *
- * @return int The normalized hour value
- */
- abstract public function normalizeHour($hour, $marker = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for minute format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class MinuteTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $minuteOfHour = (int) $dateTime->format('i');
-
- return $this->padLeft($minuteOfHour, $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'minute' => (int) $matched,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for month format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class MonthTransformer extends Transformer
-{
- /**
- * @var array
- */
- protected static $months = array(
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December'
- );
-
- /**
- * Short months names (first 3 letters)
- * @var array
- */
- protected static $shortMonths = array();
-
- /**
- * Flipped $months array, $name => $index
- * @var array
- */
- protected static $flippedMonths = array();
-
- /**
- * Flipped $shortMonths array, $name => $index
- * @var array
- */
- protected static $flippedShortMonths = array();
-
- /**
- * Constructor
- */
- public function __construct()
- {
- if (0 === count(self::$shortMonths)) {
- self::$shortMonths = array_map(function($month) {
- return substr($month, 0, 3);
- }, self::$months);
-
- self::$flippedMonths = array_flip(self::$months);
- self::$flippedShortMonths = array_flip(self::$shortMonths);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $matchLengthMap = array(
- 1 => 'n',
- 2 => 'm',
- 3 => 'M',
- 4 => 'F',
- );
-
- if (isset($matchLengthMap[$length])) {
- return $dateTime->format($matchLengthMap[$length]);
- }
-
- if (5 === $length) {
- return substr($dateTime->format('M'), 0, 1);
- }
-
- return $this->padLeft($dateTime->format('m'), $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- switch ($length) {
- case 1:
- $regExp = '\d{1,2}';
- break;
- case 3:
- $regExp = implode('|', self::$shortMonths);
- break;
- case 4:
- $regExp = implode('|', self::$months);
- break;
- case 5:
- $regExp = '[JFMASOND]';
- break;
- default:
- $regExp = '\d{'.$length.'}';
- break;
- }
-
- return $regExp;
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- if (!is_numeric($matched)) {
- if (3 === $length) {
- $matched = self::$flippedShortMonths[$matched] + 1;
- } elseif (4 === $length) {
- $matched = self::$flippedMonths[$matched] + 1;
- } elseif (5 === $length) {
- // IntlDateFormatter::parse() always returns false for MMMMM or LLLLL
- $matched = false;
- }
- } else {
- $matched = (int) $matched;
- }
-
- return array(
- 'month' => $matched,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for quarter format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class QuarterTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $month = (int) $dateTime->format('n');
- $quarter = (int) floor(($month - 1) / 3) + 1;
- switch ($length) {
- case 1:
- case 2:
- return $this->padLeft($quarter, $length);
- case 3:
- return 'Q'.$quarter;
- default:
- $map = array(1 => '1st quarter', 2 => '2nd quarter', 3 => '3rd quarter', 4 => '4th quarter');
-
- return $map[$quarter];
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- switch ($length) {
- case 1:
- case 2:
- return '\d{'.$length.'}';
- case 3:
- return 'Q\d';
- default:
- return '(?:1st|2nd|3rd|4th) quarter';
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for the second format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class SecondTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- $secondOfMinute = (int) $dateTime->format('s');
-
- return $this->padLeft($secondOfMinute, $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'second' => (int) $matched,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-use Symfony\Component\Intl\Exception\NotImplementedException;
-
-/**
- * Parser and formatter for time zone format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class TimeZoneTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- *
- * @throws NotImplementedException When time zone is different than UTC or GMT (Etc/GMT)
- */
- public function format(\DateTime $dateTime, $length)
- {
- $timeZone = substr($dateTime->getTimezone()->getName(), 0, 3);
-
- if (!in_array($timeZone, array('Etc', 'UTC'))) {
- throw new NotImplementedException('Time zone different than GMT or UTC is not supported as a formatting output.');
- }
-
- // From ICU >= 4.8, the zero offset is not more used, example: GMT instead of GMT+00:00
- $format = (0 !== (int) $dateTime->format('O')) ? '\G\M\TP' : '\G\M\T';
-
- return $dateTime->format($format);
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return 'GMT[+-]\d{2}:?\d{2}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'timezone' => self::getEtcTimeZoneId($matched)
- );
- }
-
- /**
- * Get an Etc/GMT timezone identifier for the specified timezone
- *
- * The PHP documentation for timezones states to not use the 'Other' time zones because them exists
- * "for backwards compatibility". However all Etc/GMT time zones are in the tz database 'etcetera' file,
- * which indicates they are not deprecated (neither are old names).
- *
- * Only GMT, Etc/Universal, Etc/Zulu, Etc/Greenwich, Etc/GMT-0, Etc/GMT+0 and Etc/GMT0 are old names and
- * are linked to Etc/GMT or Etc/UTC.
- *
- * @param string $formattedTimeZone A GMT timezone string (GMT-03:00, e.g.)
- *
- * @return string A timezone identifier
- *
- * @see http://php.net/manual/en/timezones.others.php
- * @see http://www.twinsun.com/tz/tz-link.htm
- *
- * @throws NotImplementedException When the GMT time zone have minutes offset different than zero
- * @throws \InvalidArgumentException When the value can not be matched with pattern
- */
- public static function getEtcTimeZoneId($formattedTimeZone)
- {
- if (preg_match('/GMT(?P<signal>[+-])(?P<hours>\d{2}):?(?P<minutes>\d{2})/', $formattedTimeZone, $matches)) {
- $hours = (int) $matches['hours'];
- $minutes = (int) $matches['minutes'];
- $signal = $matches['signal'] == '-' ? '+' : '-';
-
- if (0 < $minutes) {
- throw new NotImplementedException(sprintf(
- 'It is not possible to use a GMT time zone with minutes offset different than zero (0). GMT time zone tried: %s.',
- $formattedTimeZone
- ));
- }
-
- return 'Etc/GMT'.($hours !== 0 ? $signal.$hours : '');
- }
-
- throw new \InvalidArgumentException('The GMT time zone \'%s\' does not match with the supported formats GMT[+-]HH:MM or GMT[+-]HHMM.');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for date formats
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-abstract class Transformer
-{
- /**
- * Format a value using a configured DateTime as date/time source
- *
- *
- * @param \DateTime $dateTime A DateTime object to be used to generate the formatted value
- * @param int $length The formatted value string length
- *
- * @return string The formatted value
- */
- abstract public function format(\DateTime $dateTime, $length);
-
- /**
- * Returns a reverse matching regular expression of a string generated by format()
- *
- * @param int $length The length of the value to be reverse matched
- *
- * @return string The reverse matching regular expression
- */
- abstract public function getReverseMatchingRegExp($length);
-
- /**
- * Extract date options from a matched value returned by the processing of the reverse matching
- * regular expression
- *
- * @param string $matched The matched value
- * @param int $length The length of the Transformer pattern string
- *
- * @return array An associative array
- */
- abstract public function extractDateOptions($matched, $length);
-
- /**
- * Pad a string with zeros to the left
- *
- * @param string $value The string to be padded
- * @param int $length The length to pad
- *
- * @return string The padded string
- */
- protected function padLeft($value, $length)
- {
- return str_pad($value, $length, '0', STR_PAD_LEFT);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter\DateFormat;
-
-/**
- * Parser and formatter for year format
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- */
-class YearTransformer extends Transformer
-{
- /**
- * {@inheritDoc}
- */
- public function format(\DateTime $dateTime, $length)
- {
- if (2 === $length) {
- return $dateTime->format('y');
- }
-
- return $this->padLeft($dateTime->format('Y'), $length);
- }
-
- /**
- * {@inheritDoc}
- */
- public function getReverseMatchingRegExp($length)
- {
- return 2 === $length ? '\d{2}' : '\d{4}';
- }
-
- /**
- * {@inheritDoc}
- */
- public function extractDateOptions($matched, $length)
- {
- return array(
- 'year' => (int) $matched,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\DateFormatter;
-
-use Symfony\Component\Intl\Globals\IntlGlobals;
-use Symfony\Component\Intl\DateFormatter\DateFormat\FullTransformer;
-use Symfony\Component\Intl\Exception\MethodNotImplementedException;
-use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException;
-use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
-use Symfony\Component\Intl\Locale\Locale;
-
-/**
- * Replacement for PHP's native {@link \IntlDateFormatter} class.
- *
- * The only methods currently supported in this class are:
- *
- * - {@link __construct}
- * - {@link create}
- * - {@link format}
- * - {@link getCalendar}
- * - {@link getDateType}
- * - {@link getErrorCode}
- * - {@link getErrorMessage}
- * - {@link getLocale}
- * - {@link getPattern}
- * - {@link getTimeType}
- * - {@link getTimeZoneId}
- * - {@link isLenient}
- * - {@link parse}
- * - {@link setLenient}
- * - {@link setPattern}
- * - {@link setTimeZoneId}
- * - {@link setTimeZone}
- *
- * @author Igor Wiedler <igor@wiedler.ch>
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IntlDateFormatter
-{
- /**
- * The error code from the last operation
- *
- * @var integer
- */
- protected $errorCode = IntlGlobals::U_ZERO_ERROR;
-
- /**
- * The error message from the last operation
- *
- * @var string
- */
- protected $errorMessage = 'U_ZERO_ERROR';
-
- /* date/time format types */
- const NONE = -1;
- const FULL = 0;
- const LONG = 1;
- const MEDIUM = 2;
- const SHORT = 3;
-
- /* calendar formats */
- const TRADITIONAL = 0;
- const GREGORIAN = 1;
-
- /**
- * Patterns used to format the date when no pattern is provided
- *
- * @var array
- */
- private $defaultDateFormats = array(
- self::NONE => '',
- self::FULL => 'EEEE, LLLL d, y',
- self::LONG => 'LLLL d, y',
- self::MEDIUM => 'LLL d, y',
- self::SHORT => 'M/d/yy',
- );
-
- /**
- * Patterns used to format the time when no pattern is provided
- *
- * @var array
- */
- private $defaultTimeFormats = array(
- self::FULL => 'h:mm:ss a zzzz',
- self::LONG => 'h:mm:ss a z',
- self::MEDIUM => 'h:mm:ss a',
- self::SHORT => 'h:mm a',
- );
-
- /**
- * @var int
- */
- private $datetype;
-
- /**
- * @var int
- */
- private $timetype;
-
- /**
- * @var string
- */
- private $pattern;
-
- /**
- * @var \DateTimeZone
- */
- private $dateTimeZone;
-
- /**
- * @var Boolean
- */
- private $unitializedTimeZoneId = false;
-
- /**
- * @var string
- */
- private $timeZoneId;
-
- /**
- * Constructor
- *
- * @param string $locale The locale code. The only currently supported locale is "en".
- * @param int $datetype Type of date formatting, one of the format type constants
- * @param int $timetype Type of time formatting, one of the format type constants
- * @param string $timezone Timezone identifier
- * @param int $calendar Calendar to use for formatting or parsing. The only currently
- * supported value is IntlDateFormatter::GREGORIAN.
- * @param string $pattern Optional pattern to use when formatting
- *
- * @see http://www.php.net/manual/en/intldateformatter.create.php
- * @see http://userguide.icu-project.org/formatparse/datetime
- *
- * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
- * @throws MethodArgumentValueNotImplementedException When $calendar different than GREGORIAN is passed
- */
- public function __construct($locale, $datetype, $timetype, $timezone = null, $calendar = self::GREGORIAN, $pattern = null)
- {
- if ('en' !== $locale) {
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the locale "en" is supported');
- }
-
- if (self::GREGORIAN !== $calendar) {
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'calendar', $calendar, 'Only the GREGORIAN calendar is supported');
- }
-
- $this->datetype = $datetype;
- $this->timetype = $timetype;
-
- $this->setPattern($pattern);
- $this->setTimeZoneId($timezone);
- }
-
- /**
- * Static constructor
- *
- * @param string $locale The locale code. The only currently supported locale is "en".
- * @param int $datetype Type of date formatting, one of the format type constants
- * @param int $timetype Type of time formatting, one of the format type constants
- * @param string $timezone Timezone identifier
- * @param int $calendar Calendar to use for formatting or parsing; default is Gregorian.
- * One of the calendar constants.
- * @param string $pattern Optional pattern to use when formatting
- *
- * @return IntlDateFormatter
- *
- * @see http://www.php.net/manual/en/intldateformatter.create.php
- * @see http://userguide.icu-project.org/formatparse/datetime
- *
- * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
- * @throws MethodArgumentValueNotImplementedException When $calendar different than GREGORIAN is passed
- */
- public static function create($locale, $datetype, $timetype, $timezone = null, $calendar = self::GREGORIAN, $pattern = null)
- {
- return new self($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
- }
-
- /**
- * Format the date/time value (timestamp) as a string
- *
- * @param integer|\DateTime $timestamp The timestamp to format. \DateTime objects
- * are supported as of PHP 5.3.4.
- *
- * @return string|Boolean The formatted value or false if formatting failed.
- *
- * @see http://www.php.net/manual/en/intldateformatter.format.php
- *
- * @throws MethodArgumentValueNotImplementedException If one of the formatting characters is not implemented
- */
- public function format($timestamp)
- {
- // intl allows timestamps to be passed as arrays - we don't
- if (is_array($timestamp)) {
- $message = version_compare(PHP_VERSION, '5.3.4', '>=') ?
- 'Only integer unix timestamps and DateTime objects are supported' :
- 'Only integer unix timestamps are supported';
-
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'timestamp', $timestamp, $message);
- }
-
- // behave like the intl extension
- $argumentError = null;
- if (version_compare(PHP_VERSION, '5.3.4', '<') && !is_int($timestamp)) {
- $argumentError = 'datefmt_format: takes either an array or an integer timestamp value ';
- } elseif (version_compare(PHP_VERSION, '5.3.4', '>=') && !is_int($timestamp) && !$timestamp instanceof \DateTime) {
- $argumentError = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object';
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=') && !is_int($timestamp)) {
- $argumentError = sprintf('datefmt_format: string \'%s\' is not numeric, which would be required for it to be a valid date', $timestamp);
- }
- }
-
- if (null !== $argumentError) {
- IntlGlobals::setError(IntlGlobals::U_ILLEGAL_ARGUMENT_ERROR, $argumentError);
- $this->errorCode = IntlGlobals::getErrorCode();
- $this->errorMessage = IntlGlobals::getErrorMessage();
-
- return false;
- }
-
- // As of PHP 5.3.4, IntlDateFormatter::format() accepts DateTime instances
- if (version_compare(PHP_VERSION, '5.3.4', '>=') && $timestamp instanceof \DateTime) {
- $timestamp = $timestamp->getTimestamp();
- }
-
- $transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
- $formatted = $transformer->format($this->createDateTime($timestamp));
-
- // behave like the intl extension
- IntlGlobals::setError(IntlGlobals::U_ZERO_ERROR);
- $this->errorCode = IntlGlobals::getErrorCode();
- $this->errorMessage = IntlGlobals::getErrorMessage();
-
- return $formatted;
- }
-
- /**
- * Not supported. Formats an object
- *
- * @param object $object
- * @param mixed $format
- * @param string $locale
- *
- * @return string The formatted value
- *
- * @see http://www.php.net/manual/en/intldateformatter.formatobject.php
- *
- * @throws MethodNotImplementedException
- */
- public function formatObject($object, $format = null, $locale = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Returns the formatter's calendar
- *
- * @return int The calendar being used by the formatter. Currently always returns
- * IntlDateFormatter::GREGORIAN.
- *
- * @see http://www.php.net/manual/en/intldateformatter.getcalendar.php
- */
- public function getCalendar()
- {
- return self::GREGORIAN;
- }
-
- /**
- * Not supported. Returns the formatter's calendar object
- *
- * @return object The calendar's object being used by the formatter
- *
- * @see http://www.php.net/manual/en/intldateformatter.getcalendarobject.php
- *
- * @throws MethodNotImplementedException
- */
- public function getCalendarObject()
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Returns the formatter's datetype
- *
- * @return int The current value of the formatter
- *
- * @see http://www.php.net/manual/en/intldateformatter.getdatetype.php
- */
- public function getDateType()
- {
- return $this->datetype;
- }
-
- /**
- * Returns formatter's last error code. Always returns the U_ZERO_ERROR class constant value
- *
- * @return int The error code from last formatter call
- *
- * @see http://www.php.net/manual/en/intldateformatter.geterrorcode.php
- */
- public function getErrorCode()
- {
- return $this->errorCode;
- }
-
- /**
- * Returns formatter's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
- *
- * @return string The error message from last formatter call
- *
- * @see http://www.php.net/manual/en/intldateformatter.geterrormessage.php
- */
- public function getErrorMessage()
- {
- return $this->errorMessage;
- }
-
- /**
- * Returns the formatter's locale
- *
- * @param int $type Not supported. The locale name type to return (Locale::VALID_LOCALE or Locale::ACTUAL_LOCALE)
- *
- * @return string The locale used to create the formatter. Currently always
- * returns "en".
- *
- * @see http://www.php.net/manual/en/intldateformatter.getlocale.php
- */
- public function getLocale($type = Locale::ACTUAL_LOCALE)
- {
- return 'en';
- }
-
- /**
- * Returns the formatter's pattern
- *
- * @return string The pattern string used by the formatter
- *
- * @see http://www.php.net/manual/en/intldateformatter.getpattern.php
- */
- public function getPattern()
- {
- return $this->pattern;
- }
-
- /**
- * Returns the formatter's time type
- *
- * @return string The time type used by the formatter
- *
- * @see http://www.php.net/manual/en/intldateformatter.gettimetype.php
- */
- public function getTimeType()
- {
- return $this->timetype;
- }
-
- /**
- * Returns the formatter's timezone identifier
- *
- * @return string The timezone identifier used by the formatter
- *
- * @see http://www.php.net/manual/en/intldateformatter.gettimezoneid.php
- */
- public function getTimeZoneId()
- {
- if (!$this->unitializedTimeZoneId) {
- return $this->timeZoneId;
- }
-
- // In PHP 5.5 default timezone depends on `date_default_timezone_get()` method
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- return date_default_timezone_get();
- }
-
- return null;
- }
-
- /**
- * Not supported. Returns the formatter's timezone
- *
- * @return mixed The timezone used by the formatter
- *
- * @see http://www.php.net/manual/en/intldateformatter.gettimezone.php
- *
- * @throws MethodNotImplementedException
- */
- public function getTimeZone()
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Returns whether the formatter is lenient
- *
- * @return Boolean Currently always returns false.
- *
- * @see http://www.php.net/manual/en/intldateformatter.islenient.php
- *
- * @throws MethodNotImplementedException
- */
- public function isLenient()
- {
- return false;
- }
-
- /**
- * Not supported. Parse string to a field-based time value
- *
- * @param string $value String to convert to a time value
- * @param int $position Position at which to start the parsing in $value (zero-based).
- * If no error occurs before $value is consumed, $parse_pos will
- * contain -1 otherwise it will contain the position at which parsing
- * ended. If $parse_pos > strlen($value), the parse fails immediately.
- *
- * @return string Localtime compatible array of integers: contains 24 hour clock value in tm_hour field
- *
- * @see http://www.php.net/manual/en/intldateformatter.localtime.php
- *
- * @throws MethodNotImplementedException
- */
- public function localtime($value, &$position = 0)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Parse string to a timestamp value
- *
- * @param string $value String to convert to a time value
- * @param int $position Not supported. Position at which to start the parsing in $value (zero-based).
- * If no error occurs before $value is consumed, $parse_pos will
- * contain -1 otherwise it will contain the position at which parsing
- * ended. If $parse_pos > strlen($value), the parse fails immediately.
- *
- * @return string Parsed value as a timestamp
- *
- * @see http://www.php.net/manual/en/intldateformatter.parse.php
- *
- * @throws MethodArgumentNotImplementedException When $position different than null, behavior not implemented
- */
- public function parse($value, &$position = null)
- {
- // We don't calculate the position when parsing the value
- if (null !== $position) {
- throw new MethodArgumentNotImplementedException(__METHOD__, 'position');
- }
-
- $dateTime = $this->createDateTime(0);
- $transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
-
- $timestamp = $transformer->parse($dateTime, $value);
-
- // behave like the intl extension. FullTransformer::parse() set the proper error
- $this->errorCode = IntlGlobals::getErrorCode();
- $this->errorMessage = IntlGlobals::getErrorMessage();
-
- return $timestamp;
- }
-
- /**
- * Not supported. Set the formatter's calendar
- *
- * @param string $calendar The calendar to use. Default is IntlDateFormatter::GREGORIAN.
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/intldateformatter.setcalendar.php
- *
- * @throws MethodNotImplementedException
- */
- public function setCalendar($calendar)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Set the leniency of the parser
- *
- * Define if the parser is strict or lenient in interpreting inputs that do not match the pattern
- * exactly. Enabling lenient parsing allows the parser to accept otherwise flawed date or time
- * patterns, parsing as much as possible to obtain a value. Extra space, unrecognized tokens, or
- * invalid values ("February 30th") are not accepted.
- *
- * @param Boolean $lenient Sets whether the parser is lenient or not. Currently
- * only false (strict) is supported.
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/intldateformatter.setlenient.php
- *
- * @throws MethodArgumentValueNotImplementedException When $lenient is true
- */
- public function setLenient($lenient)
- {
- if ($lenient) {
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'lenient', $lenient, 'Only the strict parser is supported');
- }
-
- return true;
- }
-
- /**
- * Set the formatter's pattern
- *
- * @param string $pattern A pattern string in conformance with the ICU IntlDateFormatter documentation
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/intldateformatter.setpattern.php
- * @see http://userguide.icu-project.org/formatparse/datetime
- */
- public function setPattern($pattern)
- {
- if (null === $pattern) {
- $pattern = $this->getDefaultPattern();
- }
-
- $this->pattern = $pattern;
-
- return true;
- }
-
- /**
- * Set the formatter's timezone identifier
- *
- * @param string $timeZoneId The time zone ID string of the time zone to use.
- * If NULL or the empty string, the default time zone for the
- * runtime is used.
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/intldateformatter.settimezoneid.php
- */
- public function setTimeZoneId($timeZoneId)
- {
- if (null === $timeZoneId) {
- // In PHP 5.5 if $timeZoneId is null it fallbacks to `date_default_timezone_get()` method
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $timeZoneId = date_default_timezone_get();
- } else {
- // TODO: changes were made to ext/intl in PHP 5.4.4 release that need to be investigated since it will
- // use ini's date.timezone when the time zone is not provided. As a not well tested workaround, uses UTC.
- // See the first two items of the commit message for more information:
- // https://github.com/php/php-src/commit/eb346ef0f419b90739aadfb6cc7b7436c5b521d9
- $timeZoneId = getenv('TZ') ?: 'UTC';
- }
-
- $this->unitializedTimeZoneId = true;
- }
-
- // Backup original passed time zone
- $timeZone = $timeZoneId;
-
- // Get an Etc/GMT time zone that is accepted for \DateTimeZone
- if ('GMT' !== $timeZoneId && 0 === strpos($timeZoneId, 'GMT')) {
- try {
- $timeZoneId = DateFormat\TimeZoneTransformer::getEtcTimeZoneId($timeZoneId);
- } catch (\InvalidArgumentException $e) {
- // Does nothing, will fallback to UTC
- }
- }
-
- try {
- $this->dateTimeZone = new \DateTimeZone($timeZoneId);
- } catch (\Exception $e) {
- $this->dateTimeZone = new \DateTimeZone('UTC');
- }
-
- $this->timeZoneId = $timeZone;
-
- return true;
- }
-
- /**
- * This method was added in PHP 5.5 as replacement for `setTimeZoneId()`
- *
- * @param mixed $timeZone
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/intldateformatter.settimezone.php
- */
- public function setTimeZone($timeZone)
- {
- return $this->setTimeZoneId($timeZone);
- }
-
- /**
- * Create and returns a DateTime object with the specified timestamp and with the
- * current time zone
- *
- * @param int $timestamp
- *
- * @return \DateTime
- */
- protected function createDateTime($timestamp)
- {
- $dateTime = new \DateTime();
- $dateTime->setTimestamp($timestamp);
- $dateTime->setTimezone($this->dateTimeZone);
-
- return $dateTime;
- }
-
- /**
- * Returns a pattern string based in the datetype and timetype values
- *
- * @return string
- */
- protected function getDefaultPattern()
- {
- $patternParts = array();
- if (self::NONE !== $this->datetype) {
- $patternParts[] = $this->defaultDateFormats[$this->datetype];
- }
- if (self::NONE !== $this->timetype) {
- $patternParts[] = $this->defaultTimeFormats[$this->timetype];
- }
- $pattern = implode(' ', $patternParts);
-
- return $pattern;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-/**
- * Base BadMethodCallException for the Intl component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-/**
- * Base ExceptionInterface for the Intl component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-/**
- * InvalidArgumentException for the Intl component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-use Symfony\Component\Intl\Exception\NotImplementedException;
-
-/**
- * @author Eriksen Costa <eriksen.costa@infranology.com.br>
- */
-class MethodArgumentNotImplementedException extends NotImplementedException
-{
- /**
- * Constructor
- *
- * @param string $methodName The method name that raised the exception
- * @param string $argName The argument name that is not implemented
- */
- public function __construct($methodName, $argName)
- {
- $message = sprintf('The %s() method\'s argument $%s behavior is not implemented.', $methodName, $argName);
- parent::__construct($message);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-use Symfony\Component\Intl\Exception\NotImplementedException;
-
-/**
- * @author Eriksen Costa <eriksen.costa@infranology.com.br>
- */
-class MethodArgumentValueNotImplementedException extends NotImplementedException
-{
- /**
- * Constructor
- *
- * @param string $methodName The method name that raised the exception
- * @param string $argName The argument name
- * @param string $argValue The argument value that is not implemented
- * @param string $additionalMessage An optional additional message to append to the exception message
- */
- public function __construct($methodName, $argName, $argValue, $additionalMessage = '')
- {
- $message = sprintf(
- 'The %s() method\'s argument $%s value %s behavior is not implemented.%s',
- $methodName,
- $argName,
- var_export($argValue, true),
- $additionalMessage !== '' ? ' '.$additionalMessage.'. ' : ''
- );
-
- parent::__construct($message);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-/**
- * @author Eriksen Costa <eriksen.costa@infranology.com.br>
- */
-class MethodNotImplementedException extends NotImplementedException
-{
- /**
- * Constructor
- *
- * @param string $methodName The name of the method
- */
- public function __construct($methodName)
- {
- parent::__construct(sprintf('The %s() is not implemented.', $methodName));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-/**
- * Base exception class for not implemented behaviors of the intl extension in the Locale component.
- *
- * @author Eriksen Costa <eriksen.costa@infranology.com.br>
- */
-class NotImplementedException extends RuntimeException
-{
- const INTL_INSTALL_MESSAGE = 'Please install the "intl" extension for full localization capabilities.';
-
- /**
- * Constructor
- *
- * @param string $message The exception message. A note to install the intl extension is appended to this string
- */
- public function __construct($message)
- {
- parent::__construct($message.' '.self::INTL_INSTALL_MESSAGE);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-/**
- * Base OutOfBoundsException for the Intl component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Exception;
-
-/**
- * RuntimeException for the Intl component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RuntimeException extends \RuntimeException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Globals;
-
-/**
- * Provides fake static versions of the global functions in the intl extension
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class IntlGlobals
-{
- /**
- * Indicates that no error occurred
- *
- * @var integer
- */
- const U_ZERO_ERROR = 0;
-
- /**
- * Indicates that an invalid argument was passed
- *
- * @var integer
- */
- const U_ILLEGAL_ARGUMENT_ERROR = 1;
-
- /**
- * Indicates that the parse() operation failed
- *
- * @var integer
- */
- const U_PARSE_ERROR = 9;
-
- /**
- * All known error codes
- *
- * @var array
- */
- private static $errorCodes = array(
- self::U_ZERO_ERROR => 'U_ZERO_ERROR',
- self::U_ILLEGAL_ARGUMENT_ERROR => 'U_ILLEGAL_ARGUMENT_ERROR',
- self::U_PARSE_ERROR => 'U_PARSE_ERROR',
- );
-
- /**
- * The error code of the last operation
- *
- * @var integer
- */
- private static $errorCode = self::U_ZERO_ERROR;
-
- /**
- * The error code of the last operation
- *
- * @var integer
- */
- private static $errorMessage = 'U_ZERO_ERROR';
-
- /**
- * Returns whether the error code indicates a failure
- *
- * @param integer $errorCode The error code returned by IntlGlobals::getErrorCode()
- *
- * @return Boolean
- */
- public static function isFailure($errorCode)
- {
- return isset(self::$errorCodes[$errorCode])
- && $errorCode > self::U_ZERO_ERROR;
- }
-
- /**
- * Returns the error code of the last operation
- *
- * Returns IntlGlobals::U_ZERO_ERROR if no error occurred.
- *
- * @return integer
- */
- public static function getErrorCode()
- {
- return self::$errorCode;
- }
-
- /**
- * Returns the error message of the last operation
- *
- * Returns "U_ZERO_ERROR" if no error occurred.
- *
- * @return string
- */
- public static function getErrorMessage()
- {
- return self::$errorMessage;
- }
-
- /**
- * Returns the symbolic name for a given error code
- *
- * @param integer $code The error code returned by IntlGlobals::getErrorCode()
- *
- * @return string
- */
- public static function getErrorName($code)
- {
- if (isset(self::$errorCodes[$code])) {
- return self::$errorCodes[$code];
- }
-
- return '[BOGUS UErrorCode]';
- }
-
- /**
- * Sets the current error
- *
- * @param integer $code One of the error constants in this class
- * @param string $message The ICU class error message
- *
- * @throws \InvalidArgumentException If the code is not one of the error constants in this class
- */
- public static function setError($code, $message = '')
- {
- if (!isset(self::$errorCodes[$code])) {
- throw new \InvalidArgumentException(sprintf('No such error code: "%s"', $code));
- }
-
- self::$errorMessage = $message ? sprintf('%s: %s', $message, self::$errorCodes[$code]) : self::$errorCodes[$code];
- self::$errorCode = $code;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl;
-
-use Symfony\Component\Icu\IcuCurrencyBundle;
-use Symfony\Component\Icu\IcuData;
-use Symfony\Component\Icu\IcuLanguageBundle;
-use Symfony\Component\Icu\IcuLocaleBundle;
-use Symfony\Component\Icu\IcuRegionBundle;
-use Symfony\Component\Intl\ResourceBundle\Reader\BufferedBundleReader;
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader;
-
-/**
- * Gives access to internationalization data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Intl
-{
- /**
- * The number of resource bundles to buffer. Loading the same resource
- * bundle for n locales takes up n spots in the buffer.
- */
- const BUFFER_SIZE = 10;
-
- /**
- * @var ResourceBundle\CurrencyBundleInterface
- */
- private static $currencyBundle;
-
- /**
- * @var ResourceBundle\LanguageBundleInterface
- */
- private static $languageBundle;
-
- /**
- * @var ResourceBundle\LocaleBundleInterface
- */
- private static $localeBundle;
-
- /**
- * @var ResourceBundle\RegionBundleInterface
- */
- private static $regionBundle;
-
- /**
- * @var string|Boolean|null
- */
- private static $icuVersion = false;
-
- /**
- * @var string
- */
- private static $icuDataVersion = false;
-
- /**
- * @var ResourceBundle\Reader\StructuredBundleReaderInterface
- */
- private static $bundleReader;
-
- /**
- * Returns whether the intl extension is installed.
- *
- * @return Boolean Returns true if the intl extension is installed, false otherwise.
- */
- public static function isExtensionLoaded()
- {
- return class_exists('\ResourceBundle');
- }
-
- /**
- * Returns the bundle containing currency information.
- *
- * @return ResourceBundle\CurrencyBundleInterface The currency resource bundle.
- */
- public static function getCurrencyBundle()
- {
- if (null === self::$currencyBundle) {
- self::$currencyBundle = new IcuCurrencyBundle(self::getBundleReader());
- }
-
- return self::$currencyBundle;
- }
-
- /**
- * Returns the bundle containing language information.
- *
- * @return ResourceBundle\LanguageBundleInterface The language resource bundle.
- */
- public static function getLanguageBundle()
- {
- if (null === self::$languageBundle) {
- self::$languageBundle = new IcuLanguageBundle(self::getBundleReader());
- }
-
- return self::$languageBundle;
- }
-
- /**
- * Returns the bundle containing locale information.
- *
- * @return ResourceBundle\LocaleBundleInterface The locale resource bundle.
- */
- public static function getLocaleBundle()
- {
- if (null === self::$localeBundle) {
- self::$localeBundle = new IcuLocaleBundle(self::getBundleReader());
- }
-
- return self::$localeBundle;
- }
-
- /**
- * Returns the bundle containing region information.
- *
- * @return ResourceBundle\RegionBundleInterface The region resource bundle.
- */
- public static function getRegionBundle()
- {
- if (null === self::$regionBundle) {
- self::$regionBundle = new IcuRegionBundle(self::getBundleReader());
- }
-
- return self::$regionBundle;
- }
-
- /**
- * Returns the version of the installed ICU library.
- *
- * @return null|string The ICU version or NULL if it could not be determined.
- */
- public static function getIcuVersion()
- {
- if (false === self::$icuVersion) {
- if (!self::isExtensionLoaded()) {
- self::$icuVersion = self::getIcuStubVersion();
- } elseif (defined('INTL_ICU_VERSION')) {
- self::$icuVersion = INTL_ICU_VERSION;
- } else {
- try {
- $reflector = new \ReflectionExtension('intl');
- ob_start();
- $reflector->info();
- $output = strip_tags(ob_get_clean());
- preg_match('/^ICU version (?:=>)?(.*)$/m', $output, $matches);
-
- self::$icuVersion = trim($matches[1]);
- } catch (\ReflectionException $e) {
- self::$icuVersion = null;
- }
- }
- }
-
- return self::$icuVersion;
- }
-
- /**
- * Returns the version of the installed ICU data.
- *
- * @return string The version of the installed ICU data.
- */
- public static function getIcuDataVersion()
- {
- if (false === self::$icuDataVersion) {
- self::$icuDataVersion = IcuData::getVersion();
- }
-
- return self::$icuDataVersion;
- }
-
- /**
- * Returns the ICU version that the stub classes mimic.
- *
- * @return string The ICU version of the stub classes.
- */
- public static function getIcuStubVersion()
- {
- return '50.1.2';
- }
-
- /**
- * Returns a resource bundle reader for .php resource bundle files.
- *
- * @return ResourceBundle\Reader\StructuredBundleReaderInterface The resource reader.
- */
- private static function getBundleReader()
- {
- if (null === self::$bundleReader) {
- self::$bundleReader = new StructuredBundleReader(new BufferedBundleReader(
- IcuData::getBundleReader(),
- self::BUFFER_SIZE
- ));
- }
-
- return self::$bundleReader;
- }
-
- /**
- * This class must not be instantiated.
- */
- private function __construct() {}
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Locale;
-
-use Symfony\Component\Intl\Exception\MethodNotImplementedException;
-
-/**
- * Replacement for PHP's native {@link \Locale} class.
- *
- * The only method supported in this class is {@link getDefault}. This method
- * will always return "en". All other methods will throw an exception when used.
- *
- * @author Eriksen Costa <eriksen.costa@infranology.com.br>
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Locale
-{
- const DEFAULT_LOCALE = null;
-
- /* Locale method constants */
- const ACTUAL_LOCALE = 0;
- const VALID_LOCALE = 1;
-
- /* Language tags constants */
- const LANG_TAG = 'language';
- const EXTLANG_TAG = 'extlang';
- const SCRIPT_TAG = 'script';
- const REGION_TAG = 'region';
- const VARIANT_TAG = 'variant';
- const GRANDFATHERED_LANG_TAG = 'grandfathered';
- const PRIVATE_TAG = 'private';
-
- /**
- * Not supported. Returns the best available locale based on HTTP "Accept-Language" header according to RFC 2616
- *
- * @param string $header The string containing the "Accept-Language" header value
- *
- * @return string The corresponding locale code
- *
- * @see http://www.php.net/manual/en/locale.acceptfromhttp.php
- *
- * @throws MethodNotImplementedException
- */
- public static function acceptFromHttp($header)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns a correctly ordered and delimited locale code
- *
- * @param array $subtags A keyed array where the keys identify the particular locale code subtag
- *
- * @return string The corresponding locale code
- *
- * @see http://www.php.net/manual/en/locale.composelocale.php
- *
- * @throws MethodNotImplementedException
- */
- public static function composeLocale(array $subtags)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Checks if a language tag filter matches with locale
- *
- * @param string $langtag The language tag to check
- * @param string $locale The language range to check against
- * @param Boolean $canonicalize
- *
- * @return string The corresponding locale code
- *
- * @see http://www.php.net/manual/en/locale.filtermatches.php
- *
- * @throws MethodNotImplementedException
- */
- public static function filterMatches($langtag, $locale, $canonicalize = false)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the variants for the input locale
- *
- * @param string $locale The locale to extract the variants from
- *
- * @return array The locale variants
- *
- * @see http://www.php.net/manual/en/locale.getallvariants.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getAllVariants($locale)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Returns the default locale
- *
- * @return string The default locale code. Always returns 'en'
- *
- * @see http://www.php.net/manual/en/locale.getdefault.php
- */
- public static function getDefault()
- {
- return 'en';
- }
-
- /**
- * Not supported. Returns the localized display name for the locale language
- *
- * @param string $locale The locale code to return the display language from
- * @param string $inLocale Optional format locale code to use to display the language name
- *
- * @return string The localized language display name
- *
- * @see http://www.php.net/manual/en/locale.getdisplaylanguage.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getDisplayLanguage($locale, $inLocale = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the localized display name for the locale
- *
- * @param string $locale The locale code to return the display locale name from
- * @param string $inLocale Optional format locale code to use to display the locale name
- *
- * @return string The localized locale display name
- *
- * @see http://www.php.net/manual/en/locale.getdisplayname.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getDisplayName($locale, $inLocale = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the localized display name for the locale region
- *
- * @param string $locale The locale code to return the display region from
- * @param string $inLocale Optional format locale code to use to display the region name
- *
- * @return string The localized region display name
- *
- * @see http://www.php.net/manual/en/locale.getdisplayregion.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getDisplayRegion($locale, $inLocale = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the localized display name for the locale script
- *
- * @param string $locale The locale code to return the display script from
- * @param string $inLocale Optional format locale code to use to display the script name
- *
- * @return string The localized script display name
- *
- * @see http://www.php.net/manual/en/locale.getdisplayscript.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getDisplayScript($locale, $inLocale = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the localized display name for the locale variant
- *
- * @param string $locale The locale code to return the display variant from
- * @param string $inLocale Optional format locale code to use to display the variant name
- *
- * @return string The localized variant display name
- *
- * @see http://www.php.net/manual/en/locale.getdisplayvariant.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getDisplayVariant($locale, $inLocale = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the keywords for the locale
- *
- * @param string $locale The locale code to extract the keywords from
- *
- * @return array Associative array with the extracted variants
- *
- * @see http://www.php.net/manual/en/locale.getkeywords.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getKeywords($locale)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the primary language for the locale
- *
- * @param string $locale The locale code to extract the language code from
- *
- * @return string|null The extracted language code or null in case of error
- *
- * @see http://www.php.net/manual/en/locale.getprimarylanguage.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getPrimaryLanguage($locale)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the region for the locale
- *
- * @param string $locale The locale code to extract the region code from
- *
- * @return string|null The extracted region code or null if not present
- *
- * @see http://www.php.net/manual/en/locale.getregion.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getRegion($locale)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the script for the locale
- *
- * @param string $locale The locale code to extract the script code from
- *
- * @return string|null The extracted script code or null if not present
- *
- * @see http://www.php.net/manual/en/locale.getscript.php
- *
- * @throws MethodNotImplementedException
- */
- public static function getScript($locale)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns the closest language tag for the locale
- *
- * @param array $langtag A list of the language tags to compare to locale
- * @param string $locale The locale to use as the language range when matching
- * @param Boolean $canonicalize If true, the arguments will be converted to canonical form before matching
- * @param string $default The locale to use if no match is found
- *
- * @see http://www.php.net/manual/en/locale.lookup.php
- *
- * @throws MethodNotImplementedException
- */
- public static function lookup(array $langtag, $locale, $canonicalize = false, $default = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns an associative array of locale identifier subtags
- *
- * @param string $locale The locale code to extract the subtag array from
- *
- * @return array Associative array with the extracted subtags
- *
- * @see http://www.php.net/manual/en/locale.parselocale.php
- *
- * @throws MethodNotImplementedException
- */
- public static function parseLocale($locale)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Sets the default runtime locale
- *
- * @param string $locale The locale code
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/locale.parselocale.php
- *
- * @throws MethodNotImplementedException
- */
- public static function setDefault($locale)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\NumberFormatter;
-
-use Symfony\Component\Intl\Exception\NotImplementedException;
-use Symfony\Component\Intl\Exception\MethodNotImplementedException;
-use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException;
-use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
-use Symfony\Component\Intl\Globals\IntlGlobals;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\Locale\Locale;
-
-/**
- * Replacement for PHP's native {@link \NumberFormatter} class.
- *
- * The only methods currently supported in this class are:
- *
- * - {@link __construct}
- * - {@link create}
- * - {@link formatCurrency}
- * - {@link format}
- * - {@link getAttribute}
- * - {@link getErrorCode}
- * - {@link getErrorMessage}
- * - {@link getLocale}
- * - {@link parse}
- * - {@link setAttribute}
- *
- * @author Eriksen Costa <eriksen.costa@infranology.com.br>
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class NumberFormatter
-{
- /* Format style constants */
- const PATTERN_DECIMAL = 0;
- const DECIMAL = 1;
- const CURRENCY = 2;
- const PERCENT = 3;
- const SCIENTIFIC = 4;
- const SPELLOUT = 5;
- const ORDINAL = 6;
- const DURATION = 7;
- const PATTERN_RULEBASED = 9;
- const IGNORE = 0;
- const DEFAULT_STYLE = 1;
-
- /* Format type constants */
- const TYPE_DEFAULT = 0;
- const TYPE_INT32 = 1;
- const TYPE_INT64 = 2;
- const TYPE_DOUBLE = 3;
- const TYPE_CURRENCY = 4;
-
- /* Numeric attribute constants */
- const PARSE_INT_ONLY = 0;
- const GROUPING_USED = 1;
- const DECIMAL_ALWAYS_SHOWN = 2;
- const MAX_INTEGER_DIGITS = 3;
- const MIN_INTEGER_DIGITS = 4;
- const INTEGER_DIGITS = 5;
- const MAX_FRACTION_DIGITS = 6;
- const MIN_FRACTION_DIGITS = 7;
- const FRACTION_DIGITS = 8;
- const MULTIPLIER = 9;
- const GROUPING_SIZE = 10;
- const ROUNDING_MODE = 11;
- const ROUNDING_INCREMENT = 12;
- const FORMAT_WIDTH = 13;
- const PADDING_POSITION = 14;
- const SECONDARY_GROUPING_SIZE = 15;
- const SIGNIFICANT_DIGITS_USED = 16;
- const MIN_SIGNIFICANT_DIGITS = 17;
- const MAX_SIGNIFICANT_DIGITS = 18;
- const LENIENT_PARSE = 19;
-
- /* Text attribute constants */
- const POSITIVE_PREFIX = 0;
- const POSITIVE_SUFFIX = 1;
- const NEGATIVE_PREFIX = 2;
- const NEGATIVE_SUFFIX = 3;
- const PADDING_CHARACTER = 4;
- const CURRENCY_CODE = 5;
- const DEFAULT_RULESET = 6;
- const PUBLIC_RULESETS = 7;
-
- /* Format symbol constants */
- const DECIMAL_SEPARATOR_SYMBOL = 0;
- const GROUPING_SEPARATOR_SYMBOL = 1;
- const PATTERN_SEPARATOR_SYMBOL = 2;
- const PERCENT_SYMBOL = 3;
- const ZERO_DIGIT_SYMBOL = 4;
- const DIGIT_SYMBOL = 5;
- const MINUS_SIGN_SYMBOL = 6;
- const PLUS_SIGN_SYMBOL = 7;
- const CURRENCY_SYMBOL = 8;
- const INTL_CURRENCY_SYMBOL = 9;
- const MONETARY_SEPARATOR_SYMBOL = 10;
- const EXPONENTIAL_SYMBOL = 11;
- const PERMILL_SYMBOL = 12;
- const PAD_ESCAPE_SYMBOL = 13;
- const INFINITY_SYMBOL = 14;
- const NAN_SYMBOL = 15;
- const SIGNIFICANT_DIGIT_SYMBOL = 16;
- const MONETARY_GROUPING_SEPARATOR_SYMBOL = 17;
-
- /* Rounding mode values used by NumberFormatter::setAttribute() with NumberFormatter::ROUNDING_MODE attribute */
- const ROUND_CEILING = 0;
- const ROUND_FLOOR = 1;
- const ROUND_DOWN = 2;
- const ROUND_UP = 3;
- const ROUND_HALFEVEN = 4;
- const ROUND_HALFDOWN = 5;
- const ROUND_HALFUP = 6;
-
- /* Pad position values used by NumberFormatter::setAttribute() with NumberFormatter::PADDING_POSITION attribute */
- const PAD_BEFORE_PREFIX = 0;
- const PAD_AFTER_PREFIX = 1;
- const PAD_BEFORE_SUFFIX = 2;
- const PAD_AFTER_SUFFIX = 3;
-
- /**
- * The error code from the last operation
- *
- * @var integer
- */
- protected $errorCode = IntlGlobals::U_ZERO_ERROR;
-
- /**
- * The error message from the last operation
- *
- * @var string
- */
- protected $errorMessage = 'U_ZERO_ERROR';
-
- /**
- * @var int
- */
- private $style;
-
- /**
- * Default values for the en locale
- *
- * @var array
- */
- private $attributes = array(
- self::FRACTION_DIGITS => 0,
- self::GROUPING_USED => 1,
- self::ROUNDING_MODE => self::ROUND_HALFEVEN
- );
-
- /**
- * Holds the initialized attributes code
- *
- * @var array
- */
- private $initializedAttributes = array();
-
- /**
- * The supported styles to the constructor $styles argument
- *
- * @var array
- */
- private static $supportedStyles = array(
- 'CURRENCY' => self::CURRENCY,
- 'DECIMAL' => self::DECIMAL
- );
-
- /**
- * Supported attributes to the setAttribute() $attr argument
- *
- * @var array
- */
- private static $supportedAttributes = array(
- 'FRACTION_DIGITS' => self::FRACTION_DIGITS,
- 'GROUPING_USED' => self::GROUPING_USED,
- 'ROUNDING_MODE' => self::ROUNDING_MODE
- );
-
- /**
- * The available rounding modes for setAttribute() usage with
- * NumberFormatter::ROUNDING_MODE. NumberFormatter::ROUND_DOWN
- * and NumberFormatter::ROUND_UP does not have a PHP only equivalent
- *
- * @var array
- */
- private static $roundingModes = array(
- 'ROUND_HALFEVEN' => self::ROUND_HALFEVEN,
- 'ROUND_HALFDOWN' => self::ROUND_HALFDOWN,
- 'ROUND_HALFUP' => self::ROUND_HALFUP
- );
-
- /**
- * The mapping between NumberFormatter rounding modes to the available
- * modes in PHP's round() function.
- *
- * @see http://www.php.net/manual/en/function.round.php
- *
- * @var array
- */
- private static $phpRoundingMap = array(
- self::ROUND_HALFDOWN => \PHP_ROUND_HALF_DOWN,
- self::ROUND_HALFEVEN => \PHP_ROUND_HALF_EVEN,
- self::ROUND_HALFUP => \PHP_ROUND_HALF_UP
- );
-
- /**
- * The maximum values of the integer type in 32 bit platforms.
- *
- * @var array
- */
- private static $int32Range = array(
- 'positive' => 2147483647,
- 'negative' => -2147483648
- );
-
- /**
- * The maximum values of the integer type in 64 bit platforms.
- *
- * @var array
- */
- private static $int64Range = array(
- 'positive' => 9223372036854775807,
- 'negative' => -9223372036854775808
- );
-
- /**
- * Constructor.
- *
- * @param string $locale The locale code. The only currently supported locale is "en".
- * @param int $style Style of the formatting, one of the format style constants.
- * The only supported styles are NumberFormatter::DECIMAL
- * and NumberFormatter::CURRENCY.
- * @param string $pattern Not supported. A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
- * NumberFormat::PATTERN_RULEBASED. It must conform to the syntax
- * described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
- *
- * @see http://www.php.net/manual/en/numberformatter.create.php
- * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
- * @see http://www.icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html#_details
- *
- * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
- * @throws MethodArgumentValueNotImplementedException When the $style is not supported
- * @throws MethodArgumentNotImplementedException When the pattern value is different than null
- */
- public function __construct($locale = 'en', $style = null, $pattern = null)
- {
- if ('en' != $locale) {
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the locale "en" is supported');
- }
-
- if (!in_array($style, self::$supportedStyles)) {
- $message = sprintf('The available styles are: %s.', implode(', ', array_keys(self::$supportedStyles)));
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'style', $style, $message);
- }
-
- if (null !== $pattern) {
- throw new MethodArgumentNotImplementedException(__METHOD__, 'pattern');
- }
-
- $this->style = $style;
- }
-
- /**
- * Static constructor.
- *
- * @param string $locale The locale code. The only supported locale is "en".
- * @param int $style Style of the formatting, one of the format style constants.
- * The only currently supported styles are NumberFormatter::DECIMAL
- * and NumberFormatter::CURRENCY.
- * @param string $pattern Not supported. A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
- * NumberFormat::PATTERN_RULEBASED. It must conform to the syntax
- * described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
- *
- * @return NumberFormatter
- *
- * @see http://www.php.net/manual/en/numberformatter.create.php
- * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
- * @see http://www.icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html#_details
- *
- * @throws MethodArgumentValueNotImplementedException When $locale different than "en" is passed
- * @throws MethodArgumentValueNotImplementedException When the $style is not supported
- * @throws MethodArgumentNotImplementedException When the pattern value is different than null
- */
- public static function create($locale = 'en', $style = null, $pattern = null)
- {
- return new self($locale, $style, $pattern);
- }
-
- /**
- * Format a currency value
- *
- * @param float $value The numeric currency value
- * @param string $currency The 3-letter ISO 4217 currency code indicating the currency to use
- *
- * @return string The formatted currency value
- *
- * @see http://www.php.net/manual/en/numberformatter.formatcurrency.php
- * @see http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm
- */
- public function formatCurrency($value, $currency)
- {
- if ($this->style == self::DECIMAL) {
- return $this->format($value);
- }
-
- $symbol = Intl::getCurrencyBundle()->getCurrencySymbol($currency, 'en');
- $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency);
-
- $value = $this->roundCurrency($value, $currency);
-
- $negative = false;
- if (0 > $value) {
- $negative = true;
- $value *= -1;
- }
-
- $value = $this->formatNumber($value, $fractionDigits);
-
- $ret = $symbol.$value;
-
- return $negative ? '('.$ret.')' : $ret;
- }
-
- /**
- * Format a number
- *
- * @param number $value The value to format
- * @param int $type Type of the formatting, one of the format type constants.
- * Only type NumberFormatter::TYPE_DEFAULT is currently supported.
- *
- * @return Boolean|string The formatted value or false on error
- *
- * @see http://www.php.net/manual/en/numberformatter.format.php
- *
- * @throws NotImplementedException If the method is called with the class $style 'CURRENCY'
- * @throws MethodArgumentValueNotImplementedException If the $type is different than TYPE_DEFAULT
- */
- public function format($value, $type = self::TYPE_DEFAULT)
- {
- // The original NumberFormatter does not support this format type
- if ($type == self::TYPE_CURRENCY) {
- trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
-
- return false;
- }
-
- if ($this->style == self::CURRENCY) {
- throw new NotImplementedException(sprintf(
- '%s() method does not support the formatting of currencies (instance with CURRENCY style). %s',
- __METHOD__, NotImplementedException::INTL_INSTALL_MESSAGE
- ));
- }
-
- // Only the default type is supported.
- if ($type != self::TYPE_DEFAULT) {
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'type', $type, 'Only TYPE_DEFAULT is supported');
- }
-
- $fractionDigits = $this->getAttribute(self::FRACTION_DIGITS);
-
- $value = $this->round($value, $fractionDigits);
- $value = $this->formatNumber($value, $fractionDigits);
-
- // behave like the intl extension
- $this->resetError();
-
- return $value;
- }
-
- /**
- * Returns an attribute value
- *
- * @param int $attr An attribute specifier, one of the numeric attribute constants
- *
- * @return Boolean|int The attribute value on success or false on error
- *
- * @see http://www.php.net/manual/en/numberformatter.getattribute.php
- */
- public function getAttribute($attr)
- {
- return isset($this->attributes[$attr]) ? $this->attributes[$attr] : null;
- }
-
- /**
- * Returns formatter's last error code. Always returns the U_ZERO_ERROR class constant value
- *
- * @return int The error code from last formatter call
- *
- * @see http://www.php.net/manual/en/numberformatter.geterrorcode.php
- */
- public function getErrorCode()
- {
- return $this->errorCode;
- }
-
- /**
- * Returns formatter's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
- *
- * @return string The error message from last formatter call
- *
- * @see http://www.php.net/manual/en/numberformatter.geterrormessage.php
- */
- public function getErrorMessage()
- {
- return $this->errorMessage;
- }
-
- /**
- * Returns the formatter's locale
- *
- * The parameter $type is currently ignored.
- *
- * @param int $type Not supported. The locale name type to return (Locale::VALID_LOCALE or Locale::ACTUAL_LOCALE)
- *
- * @return string The locale used to create the formatter. Currently always
- * returns "en".
- *
- * @see http://www.php.net/manual/en/numberformatter.getlocale.php
- */
- public function getLocale($type = Locale::ACTUAL_LOCALE)
- {
- return 'en';
- }
-
- /**
- * Not supported. Returns the formatter's pattern
- *
- * @return Boolean|string The pattern string used by the formatter or false on error
- *
- * @see http://www.php.net/manual/en/numberformatter.getpattern.php
- *
- * @throws MethodNotImplementedException
- */
- public function getPattern()
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns a formatter symbol value
- *
- * @param int $attr A symbol specifier, one of the format symbol constants
- *
- * @return Boolean|string The symbol value or false on error
- *
- * @see http://www.php.net/manual/en/numberformatter.getsymbol.php
- *
- * @throws MethodNotImplementedException
- */
- public function getSymbol($attr)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Returns a formatter text attribute value
- *
- * @param int $attr An attribute specifier, one of the text attribute constants
- *
- * @return Boolean|string The attribute value or false on error
- *
- * @see http://www.php.net/manual/en/numberformatter.gettextattribute.php
- *
- * @throws MethodNotImplementedException
- */
- public function getTextAttribute($attr)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Parse a currency number
- *
- * @param string $value The value to parse
- * @param string $currency Parameter to receive the currency name (reference)
- * @param int $position Offset to begin the parsing on return this value will hold the offset at which the parsing ended
- *
- * @return Boolean|string The parsed numeric value of false on error
- *
- * @see http://www.php.net/manual/en/numberformatter.parsecurrency.php
- *
- * @throws MethodNotImplementedException
- */
- public function parseCurrency($value, &$currency, &$position = null)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Parse a number
- *
- * @param string $value The value to parse
- * @param int $type Type of the formatting, one of the format type constants.
- * The only currently supported types are NumberFormatter::TYPE_DOUBLE,
- * NumberFormatter::TYPE_INT32 and NumberFormatter::TYPE_INT64.
- * @param int $position Not supported. Offset to begin the parsing on return this value will hold the offset at which the parsing ended
- *
- * @return Boolean|string The parsed value of false on error
- *
- * @see http://www.php.net/manual/en/numberformatter.parse.php
- *
- * @throws MethodArgumentNotImplementedException When $position different than null, behavior not implemented
- */
- public function parse($value, $type = self::TYPE_DOUBLE, &$position = null)
- {
- if ($type == self::TYPE_DEFAULT || $type == self::TYPE_CURRENCY) {
- trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
-
- return false;
- }
-
- // We don't calculate the position when parsing the value
- if (null !== $position) {
- throw new MethodArgumentNotImplementedException(__METHOD__, 'position');
- }
-
- preg_match('/^([^0-9\-]{0,})(.*)/', $value, $matches);
-
- // Any string before the numeric value causes error in the parsing
- if (isset($matches[1]) && !empty($matches[1])) {
- IntlGlobals::setError(IntlGlobals::U_PARSE_ERROR, 'Number parsing failed');
- $this->errorCode = IntlGlobals::getErrorCode();
- $this->errorMessage = IntlGlobals::getErrorMessage();
-
- return false;
- }
-
- // Remove everything that is not number or dot (.)
- $value = preg_replace('/[^0-9\.\-]/', '', $value);
- $value = $this->convertValueDataType($value, $type);
-
- // behave like the intl extension
- $this->resetError();
-
- return $value;
- }
-
- /**
- * Set an attribute
- *
- * @param int $attr An attribute specifier, one of the numeric attribute constants.
- * The only currently supported attributes are NumberFormatter::FRACTION_DIGITS,
- * NumberFormatter::GROUPING_USED and NumberFormatter::ROUNDING_MODE.
- * @param int $value The attribute value. The only currently supported rounding modes are
- * NumberFormatter::ROUND_HALFEVEN, NumberFormatter::ROUND_HALFDOWN and
- * NumberFormatter::ROUND_HALFUP.
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/numberformatter.setattribute.php
- *
- * @throws MethodArgumentValueNotImplementedException When the $attr is not supported
- * @throws MethodArgumentValueNotImplementedException When the $value is not supported
- */
- public function setAttribute($attr, $value)
- {
- if (!in_array($attr, self::$supportedAttributes)) {
- $message = sprintf(
- 'The available attributes are: %s',
- implode(', ', array_keys(self::$supportedAttributes))
- );
-
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attr', $value, $message);
- }
-
- if (self::$supportedAttributes['ROUNDING_MODE'] == $attr && $this->isInvalidRoundingMode($value)) {
- $message = sprintf(
- 'The supported values for ROUNDING_MODE are: %s',
- implode(', ', array_keys(self::$roundingModes))
- );
-
- throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attr', $value, $message);
- }
-
- if (self::$supportedAttributes['GROUPING_USED'] == $attr) {
- $value = $this->normalizeGroupingUsedValue($value);
- }
-
- if (self::$supportedAttributes['FRACTION_DIGITS'] == $attr) {
- $value = $this->normalizeFractionDigitsValue($value);
- }
-
- $this->attributes[$attr] = $value;
- $this->initializedAttributes[$attr] = true;
-
- return true;
- }
-
- /**
- * Not supported. Set the formatter's pattern
- *
- * @param string $pattern A pattern string in conformance with the ICU DecimalFormat documentation
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/numberformatter.setpattern.php
- * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
- *
- * @throws MethodNotImplementedException
- */
- public function setPattern($pattern)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Set the formatter's symbol
- *
- * @param int $attr A symbol specifier, one of the format symbol constants
- * @param string $value The value for the symbol
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/numberformatter.setsymbol.php
- *
- * @throws MethodNotImplementedException
- */
- public function setSymbol($attr, $value)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Not supported. Set a text attribute
- *
- * @param int $attr An attribute specifier, one of the text attribute constants
- * @param int $value The attribute value
- *
- * @return Boolean true on success or false on failure
- *
- * @see http://www.php.net/manual/en/numberformatter.settextattribute.php
- *
- * @throws MethodNotImplementedException
- */
- public function setTextAttribute($attr, $value)
- {
- throw new MethodNotImplementedException(__METHOD__);
- }
-
- /**
- * Set the error to the default U_ZERO_ERROR
- */
- protected function resetError()
- {
- IntlGlobals::setError(IntlGlobals::U_ZERO_ERROR);
- $this->errorCode = IntlGlobals::getErrorCode();
- $this->errorMessage = IntlGlobals::getErrorMessage();
- }
-
- /**
- * Rounds a currency value, applying increment rounding if applicable
- *
- * When a currency have a rounding increment, an extra round is made after the first one. The rounding factor is
- * determined in the ICU data and is explained as of:
- *
- * "the rounding increment is given in units of 10^(-fraction_digits)"
- *
- * The only actual rounding data as of this writing, is CHF.
- *
- * @param float $value The numeric currency value
- * @param string $currency The 3-letter ISO 4217 currency code indicating the currency to use
- *
- * @return string The rounded numeric currency value
- *
- * @see http://en.wikipedia.org/wiki/Swedish_rounding
- * @see http://www.docjar.com/html/api/com/ibm/icu/util/Currency.java.html#1007
- */
- private function roundCurrency($value, $currency)
- {
- $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency);
- $roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement($currency);
-
- // Round with the formatter rounding mode
- $value = $this->round($value, $fractionDigits);
-
- // Swiss rounding
- if (0 < $roundingIncrement && 0 < $fractionDigits) {
- $roundingFactor = $roundingIncrement / pow(10, $fractionDigits);
- $value = round($value / $roundingFactor) * $roundingFactor;
- }
-
- return $value;
- }
-
- /**
- * Rounds a value.
- *
- * @param integer|float $value The value to round
- * @param int $precision The number of decimal digits to round to
- *
- * @return integer|float The rounded value
- */
- private function round($value, $precision)
- {
- $precision = $this->getUnitializedPrecision($value, $precision);
-
- $roundingMode = self::$phpRoundingMap[$this->getAttribute(self::ROUNDING_MODE)];
- $value = round($value, $precision, $roundingMode);
-
- return $value;
- }
-
- /**
- * Formats a number.
- *
- * @param integer|float $value The numeric value to format
- * @param int $precision The number of decimal digits to use
- *
- * @return string The formatted number
- */
- private function formatNumber($value, $precision)
- {
- $precision = $this->getUnitializedPrecision($value, $precision);
-
- return number_format($value, $precision, '.', $this->getAttribute(self::GROUPING_USED) ? ',' : '');
- }
-
- /**
- * Returns the precision value if the DECIMAL style is being used and the FRACTION_DIGITS attribute is unitialized.
- *
- * @param integer|float $value The value to get the precision from if the FRACTION_DIGITS attribute is unitialized
- * @param int $precision The precision value to returns if the FRACTION_DIGITS attribute is initialized
- *
- * @return int The precision value
- */
- private function getUnitializedPrecision($value, $precision)
- {
- if ($this->style == self::CURRENCY) {
- return $precision;
- }
-
- if (!$this->isInitializedAttribute(self::FRACTION_DIGITS)) {
- preg_match('/.*\.(.*)/', (string) $value, $digits);
- if (isset($digits[1])) {
- $precision = strlen($digits[1]);
- }
- }
-
- return $precision;
- }
-
- /**
- * Check if the attribute is initialized (value set by client code).
- *
- * @param string $attr The attribute name
- *
- * @return Boolean true if the value was set by client, false otherwise
- */
- private function isInitializedAttribute($attr)
- {
- return isset($this->initializedAttributes[$attr]);
- }
-
- /**
- * Returns the numeric value using the $type to convert to the right data type.
- *
- * @param mixed $value The value to be converted
- * @param int $type The type to convert. Can be TYPE_DOUBLE (float) or TYPE_INT32 (int)
- *
- * @return integer|float The converted value
- */
- private function convertValueDataType($value, $type)
- {
- if ($type == self::TYPE_DOUBLE) {
- $value = (float) $value;
- } elseif ($type == self::TYPE_INT32) {
- $value = $this->getInt32Value($value);
- } elseif ($type == self::TYPE_INT64) {
- $value = $this->getInt64Value($value);
- }
-
- return $value;
- }
-
- /**
- * Convert the value data type to int or returns false if the value is out of the integer value range.
- *
- * @param mixed $value The value to be converted
- *
- * @return int The converted value
- */
- private function getInt32Value($value)
- {
- if ($value > self::$int32Range['positive'] || $value < self::$int32Range['negative']) {
- return false;
- }
-
- return (int) $value;
- }
-
- /**
- * Convert the value data type to int or returns false if the value is out of the integer value range.
- *
- * @param mixed $value The value to be converted
- *
- * @return int|float The converted value
- *
- * @see https://bugs.php.net/bug.php?id=59597 Bug #59597
- */
- private function getInt64Value($value)
- {
- if ($value > self::$int64Range['positive'] || $value < self::$int64Range['negative']) {
- return false;
- }
-
- if (PHP_INT_SIZE !== 8 && ($value > self::$int32Range['positive'] || $value <= self::$int32Range['negative'])) {
- // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
- // The negative PHP_INT_MAX was being converted to float
- if (
- $value == self::$int32Range['negative'] &&
- (
- (version_compare(PHP_VERSION, '5.4.0', '<') && version_compare(PHP_VERSION, '5.3.14', '>=')) ||
- version_compare(PHP_VERSION, '5.4.4', '>=')
- )
- ) {
- return (int) $value;
- }
-
- return (float) $value;
- }
-
- if (PHP_INT_SIZE === 8) {
- // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
- // A 32 bit integer was being generated instead of a 64 bit integer
- if (
- ($value > self::$int32Range['positive'] || $value < self::$int32Range['negative']) &&
- (
- (version_compare(PHP_VERSION, '5.3.14', '<')) ||
- (version_compare(PHP_VERSION, '5.4.0', '>=') && version_compare(PHP_VERSION, '5.4.4', '<'))
- )
- ) {
- $value = (-2147483648 - ($value % -2147483648)) * ($value / abs($value));
- }
- }
-
- return (int) $value;
- }
-
- /**
- * Check if the rounding mode is invalid.
- *
- * @param int $value The rounding mode value to check
- *
- * @return Boolean true if the rounding mode is invalid, false otherwise
- */
- private function isInvalidRoundingMode($value)
- {
- if (in_array($value, self::$roundingModes, true)) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Returns the normalized value for the GROUPING_USED attribute. Any value that can be converted to int will be
- * cast to Boolean and then to int again. This way, negative values are converted to 1 and string values to 0.
- *
- * @param mixed $value The value to be normalized
- *
- * @return int The normalized value for the attribute (0 or 1)
- */
- private function normalizeGroupingUsedValue($value)
- {
- return (int) (Boolean) (int) $value;
- }
-
- /**
- * Returns the normalized value for the FRACTION_DIGITS attribute. The value is converted to int and if negative,
- * the returned value will be 0.
- *
- * @param mixed $value The value to be normalized
- *
- * @return int The normalized value for the attribute
- */
- private function normalizeFractionDigitsValue($value)
- {
- $value = (int) $value;
-
- return (0 > $value) ? 0 : $value;
- }
-}
+++ /dev/null
-Intl Component
-=============
-
-A PHP replacement layer for the C intl extension that includes additional data
-from the ICU library.
-
-The replacement layer is limited to the locale "en". If you want to use other
-locales, you should [install the intl extension] [1] instead.
-
-Documentation
--------------
-
-The documentation for the component can be found [online] [2].
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/Intl/
- $ composer.phar install --dev
- $ phpunit
-
-[0]: http://www.php.net/manual/en/intl.setup.php
-[1]: http://symfony.com/doc/2.3/components/intl.html
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
-
-/**
- * Base class for {@link ResourceBundleInterface} implementations.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractBundle implements ResourceBundleInterface
-{
- /**
- * @var string
- */
- private $path;
-
- /**
- * @var StructuredBundleReaderInterface
- */
- private $reader;
-
- /**
- * Creates a bundle at the given path using the given reader for reading
- * bundle entries.
- *
- * @param string $path The path to the bundle.
- * @param StructuredBundleReaderInterface $reader The reader for reading
- * the bundle.
- */
- public function __construct($path, StructuredBundleReaderInterface $reader)
- {
- $this->path = $path;
- $this->reader = $reader;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLocales()
- {
- return $this->reader->getLocales($this->path);
- }
-
- /**
- * Proxy method for {@link StructuredBundleReaderInterface#read}.
- */
- protected function read($locale)
- {
- return $this->reader->read($this->path, $locale);
- }
-
- /**
- * Proxy method for {@link StructuredBundleReaderInterface#readEntry}.
- */
- protected function readEntry($locale, array $indices, $mergeFallback = false)
- {
- return $this->reader->readEntry($this->path, $locale, $indices, $mergeFallback);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Compiler;
-
-use Symfony\Component\Intl\Exception\RuntimeException;
-
-/**
- * Compiles .txt resource bundles to binary .res files.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BundleCompiler implements BundleCompilerInterface
-{
- /**
- * @var string The path to the "genrb" executable.
- */
- private $genrb;
-
- /**
- * Creates a new compiler based on the "genrb" executable.
- *
- * @param string $genrb Optional. The path to the "genrb" executable.
- * @param string $envVars Optional. Environment variables to be loaded when
- * running "genrb".
- *
- * @throws RuntimeException If the "genrb" cannot be found.
- */
- public function __construct($genrb = 'genrb', $envVars = '')
- {
- exec('which ' . $genrb, $output, $status);
-
- if (0 !== $status) {
- throw new RuntimeException(sprintf(
- 'The command "%s" is not installed',
- $genrb
- ));
- }
-
- $this->genrb = ($envVars ? $envVars . ' ' : '') . $genrb;
- }
-
- /**
- * {@inheritdoc}
- */
- public function compile($sourcePath, $targetDir)
- {
- if (is_dir($sourcePath)) {
- $sourcePath .= '/*.txt';
- }
-
- exec($this->genrb.' --quiet -e UTF-8 -d '.$targetDir.' '.$sourcePath, $output, $status);
-
- if ($status !== 0) {
- throw new RuntimeException(sprintf(
- 'genrb failed with status %d while compiling %s to %s.',
- $status,
- $sourcePath,
- $targetDir
- ));
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Compiler;
-
-/**
- * Compiles a resource bundle.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface BundleCompilerInterface
-{
- /**
- * Compiles a resource bundle at the given source to the given target
- * directory.
- *
- * @param string $sourcePath
- * @param string $targetDir
- */
- public function compile($sourcePath, $targetDir);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Default implementation of {@link CurrencyBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CurrencyBundle extends AbstractBundle implements CurrencyBundleInterface
-{
- const INDEX_NAME = 0;
-
- const INDEX_SYMBOL = 1;
-
- const INDEX_FRACTION_DIGITS = 2;
-
- const INDEX_ROUNDING_INCREMENT = 3;
-
- /**
- * {@inheritdoc}
- */
- public function getCurrencySymbol($currency, $locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- return $this->readEntry($locale, array('Currencies', $currency, static::INDEX_SYMBOL));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCurrencyName($currency, $locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- return $this->readEntry($locale, array('Currencies', $currency, static::INDEX_NAME));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCurrencyNames($locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- if (null === ($currencies = $this->readEntry($locale, array('Currencies')))) {
- return array();
- }
-
- if ($currencies instanceof \Traversable) {
- $currencies = iterator_to_array($currencies);
- }
-
- $index = static::INDEX_NAME;
-
- array_walk($currencies, function (&$value) use ($index) {
- $value = $value[$index];
- });
-
- return $currencies;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFractionDigits($currency)
- {
- return $this->readEntry('en', array('Currencies', $currency, static::INDEX_FRACTION_DIGITS));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRoundingIncrement($currency)
- {
- return $this->readEntry('en', array('Currencies', $currency, static::INDEX_ROUNDING_INCREMENT));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Gives access to currency-related ICU data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface CurrencyBundleInterface extends ResourceBundleInterface
-{
- /**
- * Returns the symbol used for a currency.
- *
- * @param string $currency A currency code (e.g. "EUR").
- * @param string $locale Optional. The locale to return the result in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string|null The currency symbol or NULL if not found.
- */
- public function getCurrencySymbol($currency, $locale = null);
-
- /**
- * Returns the name of a currency.
- *
- * @param string $currency A currency code (e.g. "EUR").
- * @param string $locale Optional. The locale to return the name in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string|null The name of the currency or NULL if not found.
- */
- public function getCurrencyName($currency, $locale = null);
-
- /**
- * Returns the names of all known currencies.
- *
- * @param string $locale Optional. The locale to return the names in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string[] A list of currency names indexed by currency codes.
- */
- public function getCurrencyNames($locale = null);
-
- /**
- * Returns the number of digits after the comma of a currency.
- *
- * @param string $currency A currency code (e.g. "EUR").
- *
- * @return integer|null The number of digits after the comma or NULL if not found.
- */
- public function getFractionDigits($currency);
-
- /**
- * Returns the rounding increment of a currency.
- *
- * The rounding increment indicates to which number a currency is rounded.
- * For example, 1230 rounded to the nearest 50 is 1250. 1.234 rounded to the
- * nearest 0.65 is 1.3.
- *
- * @param string $currency A currency code (e.g. "EUR").
- *
- * @return float|integer|null The rounding increment or NULL if not found.
- */
- public function getRoundingIncrement($currency);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Default implementation of {@link LanguageBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class LanguageBundle extends AbstractBundle implements LanguageBundleInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getLanguageName($lang, $region = null, $locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- if (null === ($languages = $this->readEntry($locale, array('Languages')))) {
- return null;
- }
-
- // Some languages are translated together with their region,
- // i.e. "en_GB" is translated as "British English"
- if (null !== $region && isset($languages[$lang.'_'.$region])) {
- return $languages[$lang.'_'.$region];
- }
-
- return $languages[$lang];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLanguageNames($locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- if (null === ($languages = $this->readEntry($locale, array('Languages')))) {
- return array();
- }
-
- if ($languages instanceof \Traversable) {
- $languages = iterator_to_array($languages);
- }
-
- return $languages;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getScriptName($script, $lang = null, $locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- $data = $this->read($locale);
-
- // Some languages are translated together with their script,
- // e.g. "zh_Hans" is translated as "Simplified Chinese"
- if (null !== $lang && isset($data['Languages'][$lang.'_'.$script])) {
- $langName = $data['Languages'][$lang.'_'.$script];
-
- // If the script is appended in braces, extract it, e.g. "zh_Hans"
- // is translated as "Chinesisch (vereinfacht)" in locale "de"
- if (strpos($langName, '(') !== false) {
- list($langName, $scriptName) = preg_split('/[\s()]/', $langName, null, PREG_SPLIT_NO_EMPTY);
-
- return $scriptName;
- }
- }
-
- // "af" (Afrikaans) has no "Scripts" block
- if (!isset($data['Scripts'][$script])) {
- return null;
- }
-
- return $data['Scripts'][$script];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getScriptNames($locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- if (null === ($scripts = $this->readEntry($locale, array('Scripts')))) {
- return array();
- }
-
- if ($scripts instanceof \Traversable) {
- $scripts = iterator_to_array($scripts);
- }
-
- return $scripts;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Gives access to language-related ICU data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface LanguageBundleInterface extends ResourceBundleInterface
-{
- /**
- * Returns the name of a language.
- *
- * @param string $lang A language code (e.g. "en").
- * @param string|null $region Optional. A region code (e.g. "US").
- * @param string $locale Optional. The locale to return the name in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string|null The name of the language or NULL if not found.
- */
- public function getLanguageName($lang, $region = null, $locale = null);
-
- /**
- * Returns the names of all known languages.
- *
- * @param string $locale Optional. The locale to return the names in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string[] A list of language names indexed by language codes.
- */
- public function getLanguageNames($locale = null);
-
- /**
- * Returns the name of a script.
- *
- * @param string $script A script code (e.g. "Hans").
- * @param string $lang Optional. A language code (e.g. "zh").
- * @param string $locale Optional. The locale to return the name in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string|null The name of the script or NULL if not found.
- */
- public function getScriptName($script, $lang = null, $locale = null);
-
- /**
- * Returns the names of all known scripts.
- *
- * @param string $locale Optional. The locale to return the names in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string[] A list of script names indexed by script codes.
- */
- public function getScriptNames($locale = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Default implementation of {@link LocaleBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class LocaleBundle extends AbstractBundle implements LocaleBundleInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getLocaleName($ofLocale, $locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- return $this->readEntry($locale, array('Locales', $ofLocale));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLocaleNames($locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- if (null === ($locales = $this->readEntry($locale, array('Locales')))) {
- return array();
- }
-
- if ($locales instanceof \Traversable) {
- $locales = iterator_to_array($locales);
- }
-
- return $locales;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Gives access to locale-related ICU data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface LocaleBundleInterface extends ResourceBundleInterface
-{
- /**
- * Returns the name of a locale.
- *
- * @param string $ofLocale The locale to return the name of (e.g. "de_AT").
- * @param string $locale Optional. The locale to return the name in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string|null The name of the locale or NULL if not found.
- */
- public function getLocaleName($ofLocale, $locale = null);
-
- /**
- * Returns the names of all known locales.
- *
- * @param string $locale Optional. The locale to return the names in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string[] A list of locale names indexed by locale codes.
- */
- public function getLocaleNames($locale = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Reader;
-
-/**
- * Base class for {@link BundleReaderInterface} implementations.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractBundleReader implements BundleReaderInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getLocales($path)
- {
- $extension = '.' . $this->getFileExtension();
- $locales = glob($path . '/*' . $extension);
-
- // Remove file extension and sort
- array_walk($locales, function (&$locale) use ($extension) { $locale = basename($locale, $extension); });
- sort($locales);
-
- return $locales;
- }
-
- /**
- * Returns the extension of locale files in this bundle.
- *
- * @return string The file extension (without leading dot).
- */
- abstract protected function getFileExtension();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Reader;
-
-use Symfony\Component\Intl\Exception\RuntimeException;
-use Symfony\Component\Intl\ResourceBundle\Util\ArrayAccessibleResourceBundle;
-
-/**
- * Reads binary .res resource bundles.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BinaryBundleReader extends AbstractBundleReader implements BundleReaderInterface
-{
- /**
- * {@inheritdoc}
- */
- public function read($path, $locale)
- {
- // Point for future extension: Modify this class so that it works also
- // if the \ResourceBundle class is not available.
- $bundle = new \ResourceBundle($locale, $path);
-
- if (null === $bundle) {
- throw new RuntimeException(sprintf(
- 'Could not load the resource bundle "%s/%s.res".',
- $path,
- $locale
- ));
- }
-
- return new ArrayAccessibleResourceBundle($bundle);
- }
-
- /**
- * {@inheritdoc}
- */
- protected function getFileExtension()
- {
- return 'res';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Reader;
-
-use Symfony\Component\Intl\ResourceBundle\Util\RingBuffer;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BufferedBundleReader implements BundleReaderInterface
-{
- /**
- * @var BundleReaderInterface
- */
- private $reader;
-
- private $buffer;
-
- /**
- * Buffers a given reader.
- *
- * @param BundleReaderInterface $reader The reader to buffer.
- * @param integer $bufferSize The number of entries to store
- * in the buffer.
- */
- public function __construct(BundleReaderInterface $reader, $bufferSize)
- {
- $this->reader = $reader;
- $this->buffer = new RingBuffer($bufferSize);
- }
-
- /**
- * {@inheritdoc}
- */
- public function read($path, $locale)
- {
- $hash = $path . '//' . $locale;
-
- if (!isset($this->buffer[$hash])) {
- $this->buffer[$hash] = $this->reader->read($path, $locale);
- }
-
- return $this->buffer[$hash];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLocales($path)
- {
- return $this->reader->getLocales($path);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Reader;
-
-/**
- * Reads resource bundle files.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface BundleReaderInterface
-{
- /**
- * Reads a resource bundle.
- *
- * @param string $path The path to the resource bundle.
- * @param string $locale The locale to read.
- *
- * @return mixed Returns an array or {@link \ArrayAccess} instance for
- * complex data, a scalar value otherwise.
- */
- public function read($path, $locale);
-
- /**
- * Reads the available locales of a resource bundle.
- *
- * @param string $path The path to the resource bundle.
- *
- * @return string[] A list of supported locale codes.
- */
- public function getLocales($path);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Reader;
-
-use Symfony\Component\Intl\Exception\InvalidArgumentException;
-use Symfony\Component\Intl\Exception\RuntimeException;
-
-/**
- * Reads .php resource bundles.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PhpBundleReader extends AbstractBundleReader implements BundleReaderInterface
-{
- /**
- * {@inheritdoc}
- */
- public function read($path, $locale)
- {
- if ('en' !== $locale) {
- throw new InvalidArgumentException('Only the locale "en" is supported.');
- }
-
- $fileName = $path . '/' . $locale . '.php';
-
- if (!file_exists($fileName)) {
- throw new RuntimeException(sprintf(
- 'The resource bundle "%s/%s.php" does not exist.',
- $path,
- $locale
- ));
- }
-
- if (!is_file($fileName)) {
- throw new RuntimeException(sprintf(
- 'The resource bundle "%s/%s.php" is not a file.',
- $path,
- $locale
- ));
- }
-
- return include $fileName;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function getFileExtension()
- {
- return 'php';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Reader;
-
-use Symfony\Component\Intl\ResourceBundle\Util\RecursiveArrayAccess;
-
-/**
- * A structured reader wrapping an existing resource bundle reader.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see StructuredResourceBundleBundleReaderInterface
- */
-class StructuredBundleReader implements StructuredBundleReaderInterface
-{
- /**
- * @var BundleReaderInterface
- */
- private $reader;
-
- /**
- * Creates an entry reader based on the given resource bundle reader.
- *
- * @param BundleReaderInterface $reader A resource bundle reader to use.
- */
- public function __construct(BundleReaderInterface $reader)
- {
- $this->reader = $reader;
- }
-
- /**
- * {@inheritdoc}
- */
- public function read($path, $locale)
- {
- return $this->reader->read($path, $locale);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLocales($path)
- {
- return $this->reader->getLocales($path);
- }
-
- /**
- * {@inheritdoc}
- */
- public function readEntry($path, $locale, array $indices, $fallback = true)
- {
- $data = $this->reader->read($path, $locale);
-
- $entry = RecursiveArrayAccess::get($data, $indices);
- $multivalued = is_array($entry) || $entry instanceof \Traversable;
-
- if (!($fallback && (null === $entry || $multivalued))) {
- return $entry;
- }
-
- if (null !== ($fallbackLocale = $this->getFallbackLocale($locale))) {
- $parentEntry = $this->readEntry($path, $fallbackLocale, $indices, true);
-
- if ($entry || $parentEntry) {
- $multivalued = $multivalued || is_array($parentEntry) || $parentEntry instanceof \Traversable;
-
- if ($multivalued) {
- if ($entry instanceof \Traversable) {
- $entry = iterator_to_array($entry);
- }
-
- if ($parentEntry instanceof \Traversable) {
- $parentEntry = iterator_to_array($parentEntry);
- }
-
- $entry = array_merge(
- $parentEntry ?: array(),
- $entry ?: array()
- );
- } else {
- $entry = null === $entry ? $parentEntry : $entry;
- }
- }
- }
-
- return $entry;
- }
-
- /**
- * Returns the fallback locale for a given locale, if any
- *
- * @param string $locale The locale to find the fallback for.
- *
- * @return string|null The fallback locale, or null if no parent exists
- */
- private function getFallbackLocale($locale)
- {
- if (false === $pos = strrpos($locale, '_')) {
- return null;
- }
-
- return substr($locale, 0, $pos);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Reader;
-
-/**
- * Reads individual entries of a resource file.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface StructuredBundleReaderInterface extends BundleReaderInterface
-{
- /**
- * Reads an entry from a resource bundle.
- *
- * An entry can be selected from the resource bundle by passing the path
- * to that entry in the bundle. For example, if the bundle is structured
- * like this:
- *
- * TopLevel
- * NestedLevel
- * Entry: Value
- *
- * Then the value can be read by calling:
- *
- * $reader->readEntry('...', 'en', array('TopLevel', 'NestedLevel', 'Entry'));
- *
- * @param string $path The path to the resource bundle.
- * @param string $locale The locale to read.
- * @param string[] $indices The indices to read from the bundle.
- * @param Boolean $fallback Whether to merge the value with the value from
- * the fallback locale (e.g. "en" for "en_GB").
- * Only applicable if the result is multivalued
- * (i.e. array or \ArrayAccess) or cannot be found
- * in the requested locale.
- *
- * @return mixed Returns an array or {@link \ArrayAccess} instance for
- * complex data, a scalar value for simple data and NULL
- * if the given path could not be accessed.
- */
- public function readEntry($path, $locale, array $indices, $fallback = true);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Default implementation of {@link RegionBundleInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RegionBundle extends AbstractBundle implements RegionBundleInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getCountryName($country, $locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- return $this->readEntry($locale, array('Countries', $country));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCountryNames($locale = null)
- {
- if (null === $locale) {
- $locale = \Locale::getDefault();
- }
-
- if (null === ($countries = $this->readEntry($locale, array('Countries')))) {
- return array();
- }
-
- if ($countries instanceof \Traversable) {
- $countries = iterator_to_array($countries);
- }
-
- return $countries;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Gives access to region-related ICU data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface RegionBundleInterface extends ResourceBundleInterface
-{
- /**
- * Returns the name of a country.
- *
- * @param string $country A country code (e.g. "US").
- * @param string $locale Optional. The locale to return the name in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string|null The name of the country or NULL if not found.
- */
- public function getCountryName($country, $locale = null);
-
- /**
- * Returns the names of all known countries.
- *
- * @param string $locale Optional. The locale to return the names in.
- * Defaults to {@link \Locale::getDefault()}.
- *
- * @return string[] A list of country names indexed by country codes.
- */
- public function getCountryNames($locale = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle;
-
-/**
- * Gives access to ICU data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ResourceBundleInterface
-{
- /**
- * Returns the list of locales that this bundle supports.
- *
- * @return string[] A list of locale codes.
- */
- public function getLocales();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer;
-
-use Symfony\Component\Intl\Exception\RuntimeException;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\TransformationRuleInterface;
-use Symfony\Component\Intl\ResourceBundle\Writer\PhpBundleWriter;
-
-/**
- * Compiles a number of resource bundles based on predefined compilation rules.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BundleTransformer
-{
- /**
- * @var TransformationRuleInterface[]
- */
- private $rules = array();
-
- /**
- * Adds a new compilation rule.
- *
- * @param TransformationRuleInterface $rule The compilation rule.
- */
- public function addRule(TransformationRuleInterface $rule)
- {
- $this->rules[] = $rule;
- }
-
- /**
- * Runs the compilation with the given compilation context.
- *
- * @param CompilationContextInterface $context The context storing information
- * needed to run the compilation.
- *
- * @throws RuntimeException If any of the files to be compiled by the loaded
- * compilation rules does not exist.
- */
- public function compileBundles(CompilationContextInterface $context)
- {
- $filesystem = $context->getFilesystem();
- $compiler = $context->getCompiler();
-
- $filesystem->remove($context->getBinaryDir());
- $filesystem->mkdir($context->getBinaryDir());
-
- foreach ($this->rules as $rule) {
- $filesystem->mkdir($context->getBinaryDir() . '/' . $rule->getBundleName());
-
- $resources = (array) $rule->beforeCompile($context);
-
- foreach ($resources as $resource) {
- if (!file_exists($resource)) {
- throw new RuntimeException(sprintf(
- 'The file "%s" to be compiled by %s does not exist.',
- $resource,
- get_class($rule)
- ));
- }
-
- $compiler->compile($resource, $context->getBinaryDir() . '/' . $rule->getBundleName());
- }
-
- $rule->afterCompile($context);
- }
- }
-
- public function createStubs(StubbingContextInterface $context)
- {
- $filesystem = $context->getFilesystem();
- $phpWriter = new PhpBundleWriter();
-
- $filesystem->remove($context->getStubDir());
- $filesystem->mkdir($context->getStubDir());
-
- foreach ($this->rules as $rule) {
- $filesystem->mkdir($context->getStubDir() . '/' . $rule->getBundleName());
-
- $data = $rule->beforeCreateStub($context);
-
- $phpWriter->write($context->getStubDir() . '/' . $rule->getBundleName(), 'en', $data);
-
- $rule->afterCreateStub($context);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer;
-
-use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompilerInterface;
-
-/**
- * Default implementation of {@link CompilationContextInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CompilationContext implements CompilationContextInterface
-{
- /**
- * @var string
- */
- private $sourceDir;
-
- /**
- * @var string
- */
- private $binaryDir;
-
- /**
- * @var FileSystem
- */
- private $filesystem;
-
- /**
- * @var BundleCompilerInterface
- */
- private $compiler;
-
- /**
- * @var string
- */
- private $icuVersion;
-
- public function __construct($sourceDir, $binaryDir, Filesystem $filesystem, BundleCompilerInterface $compiler, $icuVersion)
- {
- $this->sourceDir = $sourceDir;
- $this->binaryDir = $binaryDir;
- $this->filesystem = $filesystem;
- $this->compiler = $compiler;
- $this->icuVersion = $icuVersion;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSourceDir()
- {
- return $this->sourceDir;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getBinaryDir()
- {
- return $this->binaryDir;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFilesystem()
- {
- return $this->filesystem;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCompiler()
- {
- return $this->compiler;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIcuVersion()
- {
- return $this->icuVersion;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer;
-
-/**
- * Stores contextual information for resource bundle compilation.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface CompilationContextInterface
-{
- /**
- * Returns the directory where the source versions of the resource bundles
- * are stored.
- *
- * @return string An absolute path to a directory.
- */
- public function getSourceDir();
-
- /**
- * Returns the directory where the binary resource bundles are stored.
- *
- * @return string An absolute path to a directory.
- */
- public function getBinaryDir();
-
- /**
- * Returns a tool for manipulating the filesystem.
- *
- * @return \Symfony\Component\Filesystem\Filesystem The filesystem manipulator.
- */
- public function getFilesystem();
-
- /**
- * Returns a resource bundle compiler.
- *
- * @return \Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompilerInterface The loaded resource bundle compiler.
- */
- public function getCompiler();
-
- /**
- * Returns the ICU version of the bundles being converted.
- *
- * @return string The ICU version string.
- */
- public function getIcuVersion();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
-
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
-use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
-use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
-use Symfony\Component\Intl\Util\IcuVersion;
-
-/**
- * The rule for compiling the currency bundle.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CurrencyBundleTransformationRule implements TransformationRuleInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getBundleName()
- {
- return 'curr';
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCompile(CompilationContextInterface $context)
- {
- // The currency data is contained in the locales and misc bundles
- // in ICU <= 4.2
- if (IcuVersion::compare($context->getIcuVersion(), '4.2', '<=', 1)) {
- return array(
- $context->getSourceDir() . '/misc/supplementalData.txt',
- $context->getSourceDir() . '/locales'
- );
- }
-
- return $context->getSourceDir() . '/curr';
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCompile(CompilationContextInterface $context)
- {
- // \ResourceBundle does not like locale names with uppercase chars, so rename
- // the resource file
- // See: http://bugs.php.net/bug.php?id=54025
- $fileName = $context->getBinaryDir() . '/curr/supplementalData.res';
- $fileNameLower = $context->getBinaryDir() . '/curr/supplementaldata.res';
-
- $context->getFilesystem()->rename($fileName, $fileNameLower);
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCreateStub(StubbingContextInterface $context)
- {
- $currencies = array();
- $currencyBundle = Intl::getCurrencyBundle();
-
- foreach ($currencyBundle->getCurrencyNames('en') as $code => $name) {
- $currencies[$code] = array(
- CurrencyBundle::INDEX_NAME => $name,
- CurrencyBundle::INDEX_SYMBOL => $currencyBundle->getCurrencySymbol($code, 'en'),
- CurrencyBundle::INDEX_FRACTION_DIGITS => $currencyBundle->getFractionDigits($code),
- CurrencyBundle::INDEX_ROUNDING_INCREMENT => $currencyBundle->getRoundingIncrement($code),
- );
- }
-
- return array(
- 'Currencies' => $currencies,
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCreateStub(StubbingContextInterface $context)
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
-
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
-use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
-use Symfony\Component\Intl\Util\IcuVersion;
-
-/**
- * The rule for compiling the language bundle.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class LanguageBundleTransformationRule implements TransformationRuleInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getBundleName()
- {
- return 'lang';
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCompile(CompilationContextInterface $context)
- {
- // The language data is contained in the locales bundle in ICU <= 4.2
- if (IcuVersion::compare($context->getIcuVersion(), '4.2', '<=', 1)) {
- return $context->getSourceDir() . '/locales';
- }
-
- return $context->getSourceDir() . '/lang';
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCompile(CompilationContextInterface $context)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCreateStub(StubbingContextInterface $context)
- {
- return array(
- 'Languages' => Intl::getLanguageBundle()->getLanguageNames('en'),
- 'Scripts' => Intl::getLanguageBundle()->getScriptNames('en'),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCreateStub(StubbingContextInterface $context)
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
-
-use Symfony\Component\Intl\Exception\RuntimeException;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
-use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
-use Symfony\Component\Intl\ResourceBundle\Writer\TextBundleWriter;
-
-/**
- * The rule for compiling the locale bundle.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class LocaleBundleTransformationRule implements TransformationRuleInterface
-{
- /**
- * @var \Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface
- */
- private $languageBundle;
-
- /**
- * @var \Symfony\Component\Intl\ResourceBundle\RegionBundleInterface
- */
- private $regionBundle;
-
- public function __construct()
- {
- $this->languageBundle = Intl::getLanguageBundle();
- $this->regionBundle = Intl::getRegionBundle();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getBundleName()
- {
- return 'locales';
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCompile(CompilationContextInterface $context)
- {
- $tempDir = sys_get_temp_dir() . '/icu-data-locales';
-
- $context->getFilesystem()->remove($tempDir);
- $context->getFilesystem()->mkdir($tempDir);
-
- $this->generateTextFiles($tempDir, $this->scanLocales($context));
-
- return $tempDir;
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCompile(CompilationContextInterface $context)
- {
- $context->getFilesystem()->remove(sys_get_temp_dir() . '/icu-data-locales');
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCreateStub(StubbingContextInterface $context)
- {
- return array(
- 'Locales' => Intl::getLocaleBundle()->getLocaleNames('en'),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCreateStub(StubbingContextInterface $context)
- {
- }
-
- private function scanLocales(CompilationContextInterface $context)
- {
- $tempDir = sys_get_temp_dir() . '/icu-data-locales-source';
-
- $context->getFilesystem()->remove($tempDir);
- $context->getFilesystem()->mkdir($tempDir);
-
- // Temporarily generate the resource bundles
- $context->getCompiler()->compile($context->getSourceDir() . '/locales', $tempDir);
-
- // Discover the list of supported locales, which are the names of the resource
- // bundles in the "locales" directory
- $locales = glob($tempDir . '/*.res');
-
- // Remove file extension and sort
- array_walk($locales, function (&$locale) { $locale = basename($locale, '.res'); });
- sort($locales);
-
- // Delete unneeded locales
- foreach ($locales as $key => $locale) {
- // Delete all aliases from the list
- // i.e., "az_AZ" is an alias for "az_Latn_AZ"
- $content = file_get_contents($context->getSourceDir() . '/locales/' . $locale . '.txt');
-
- // The key "%%ALIAS" is not accessible through the \ResourceBundle class,
- // so look in the original .txt file instead
- if (strpos($content, '%%ALIAS') !== false) {
- unset($locales[$key]);
- }
-
- // Delete locales that have no content (i.e. only "Version" key)
- $bundle = new \ResourceBundle($locale, $tempDir);
-
- if (null === $bundle) {
- throw new RuntimeException('The resource bundle for locale ' . $locale . ' could not be loaded from directory ' . $tempDir);
- }
-
- // There seems to be no other way for identifying all keys in this specific
- // resource bundle
- if (array_keys(iterator_to_array($bundle)) === array('Version')) {
- unset($locales[$key]);
- }
- }
-
- $context->getFilesystem()->remove($tempDir);
-
- return $locales;
- }
-
- private function generateTextFiles($targetDirectory, array $locales)
- {
- $displayLocales = array_unique(array_merge(
- $this->languageBundle->getLocales(),
- $this->regionBundle->getLocales()
- ));
-
- $txtWriter = new TextBundleWriter();
-
- // Generate a list of locale names in the language of each display locale
- // Each locale name has the form: "Language (Script, Region, Variant1, ...)
- // Script, Region and Variants are optional. If none of them is available,
- // the braces are not printed.
- foreach ($displayLocales as $displayLocale) {
- // Don't include ICU's root resource bundle
- if ('root' === $displayLocale) {
- continue;
- }
-
- $names = array();
-
- foreach ($locales as $locale) {
- // Don't include ICU's root resource bundle
- if ($locale === 'root') {
- continue;
- }
-
- if (null !== ($name = $this->generateLocaleName($locale, $displayLocale))) {
- $names[$locale] = $name;
- }
- }
-
- // If no names could be generated for the current locale, skip it
- if (0 === count($names)) {
- continue;
- }
-
- $txtWriter->write($targetDirectory, $displayLocale, array('Locales' => $names));
- }
- }
-
- private function generateLocaleName($locale, $displayLocale)
- {
- $name = null;
-
- $lang = \Locale::getPrimaryLanguage($locale);
- $script = \Locale::getScript($locale);
- $region = \Locale::getRegion($locale);
- $variants = \Locale::getAllVariants($locale);
-
- // Currently the only available variant is POSIX, which we don't want
- // to include in the list
- if (count($variants) > 0) {
- return null;
- }
-
- // Some languages are translated together with their region,
- // i.e. "en_GB" is translated as "British English"
- // we don't include these languages though because they mess up
- // the name sorting
- // $name = $this->langBundle->getLanguageName($displayLocale, $lang, $region);
-
- // Some languages are simply not translated
- // Example: "az" (Azerbaijani) has no translation in "af" (Afrikaans)
- if (null === ($name = $this->languageBundle->getLanguageName($lang, null, $displayLocale))) {
- return null;
- }
-
- // "as" (Assamese) has no "Variants" block
- //if (!$langBundle->get('Variants')) {
- // continue;
- //}
-
- $extras = array();
-
- // Discover the name of the script part of the locale
- // i.e. in zh_Hans_MO, "Hans" is the script
- if ($script) {
- // Some scripts are not translated into every language
- if (null === ($scriptName = $this->languageBundle->getScriptName($script, $lang, $displayLocale))) {
- return null;
- }
-
- $extras[] = $scriptName;
- }
-
- // Discover the name of the region part of the locale
- // i.e. in de_AT, "AT" is the region
- if ($region) {
- // Some regions are not translated into every language
- if (null === ($regionName = $this->regionBundle->getCountryName($region, $displayLocale))) {
- return null;
- }
-
- $extras[] = $regionName;
- }
-
- if (count($extras) > 0) {
- // Remove any existing extras
- // For example, in German, zh_Hans is "Chinesisch (vereinfacht)".
- // The latter is the script part which is already included in the
- // extras and will be appended again with the other extras.
- if (preg_match('/^(.+)\s+\([^\)]+\)$/', $name, $matches)) {
- $name = $matches[1];
- }
-
- $name .= ' ('.implode(', ', $extras).')';
- }
-
- return $name;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
-
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
-use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
-use Symfony\Component\Intl\Util\IcuVersion;
-
-/**
- * The rule for compiling the region bundle.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RegionBundleTransformationRule implements TransformationRuleInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getBundleName()
- {
- return 'region';
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCompile(CompilationContextInterface $context)
- {
- // The region data is contained in the locales bundle in ICU <= 4.2
- if (IcuVersion::compare($context->getIcuVersion(), '4.2', '<=', 1)) {
- return $context->getSourceDir() . '/locales';
- }
-
- return $context->getSourceDir() . '/region';
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCompile(CompilationContextInterface $context)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function beforeCreateStub(StubbingContextInterface $context)
- {
- return array(
- 'Countries' => Intl::getRegionBundle()->getCountryNames('en'),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function afterCreateStub(StubbingContextInterface $context)
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
-
-use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
-use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
-
-/**
- * Contains instruction for compiling a resource bundle.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface TransformationRuleInterface
-{
- /**
- * Returns the name of the compiled resource bundle.
- *
- * @return string The name of the bundle.
- */
- public function getBundleName();
-
- /**
- * Runs instructions to be executed before compiling the sources of the
- * resource bundle.
- *
- * @param CompilationContextInterface $context The contextual information of
- * the compilation.
- *
- * @return string[] The source directories/files of the bundle.
- */
- public function beforeCompile(CompilationContextInterface $context);
-
- /**
- * Runs instructions to be executed after compiling the sources of the
- * resource bundle.
- *
- * @param CompilationContextInterface $context The contextual information of
- * the compilation.
- */
- public function afterCompile(CompilationContextInterface $context);
-
- /**
- * Runs instructions to be executed before creating the stub version of the
- * resource bundle.
- *
- * @param StubbingContextInterface $context The contextual information of
- * the compilation.
- *
- * @return mixed The data to include in the stub version.
- */
- public function beforeCreateStub(StubbingContextInterface $context);
-
- /**
- * Runs instructions to be executed after creating the stub version of the
- * resource bundle.
- *
- * @param StubbingContextInterface $context The contextual information of
- * the compilation.
- */
- public function afterCreateStub(StubbingContextInterface $context);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer;
-
-use Symfony\Component\Filesystem\Filesystem;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class StubbingContext implements StubbingContextInterface
-{
- /**
- * @var string
- */
- private $binaryDir;
-
- /**
- * @var string
- */
- private $stubDir;
-
- /**
- * @var Filesystem
- */
- private $filesystem;
-
- /**
- * @var string
- */
- private $icuVersion;
-
- public function __construct($binaryDir, $stubDir, Filesystem $filesystem, $icuVersion)
- {
- $this->binaryDir = $binaryDir;
- $this->stubDir = $stubDir;
- $this->filesystem = $filesystem;
- $this->icuVersion = $icuVersion;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getBinaryDir()
- {
- return $this->binaryDir;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getStubDir()
- {
- return $this->stubDir;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFilesystem()
- {
- return $this->filesystem;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getIcuVersion()
- {
- return $this->icuVersion;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Transformer;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface StubbingContextInterface
-{
- /**
- * Returns the directory where the binary resource bundles are stored.
- *
- * @return string An absolute path to a directory.
- */
- public function getBinaryDir();
-
- /**
- * Returns the directory where the stub resource bundles are stored.
- *
- * @return string An absolute path to a directory.
- */
- public function getStubDir();
-
- /**
- * Returns a tool for manipulating the filesystem.
- *
- * @return \Symfony\Component\Filesystem\Filesystem The filesystem manipulator.
- */
- public function getFilesystem();
-
- /**
- * Returns the ICU version of the bundles being converted.
- *
- * @return string The ICU version string.
- */
- public function getIcuVersion();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Util;
-
-use Symfony\Component\Intl\Exception\BadMethodCallException;
-
-/**
- * Work-around for a bug in PHP's \ResourceBundle implementation.
- *
- * More information can be found on https://bugs.php.net/bug.php?id=64356.
- * This class can be removed once that bug is fixed.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class ArrayAccessibleResourceBundle implements \ArrayAccess, \IteratorAggregate, \Countable
-{
- private $bundleImpl;
-
- public function __construct(\ResourceBundle $bundleImpl)
- {
- $this->bundleImpl = $bundleImpl;
- }
-
- public function get($offset, $fallback = null)
- {
- $value = $this->bundleImpl->get($offset, $fallback);
-
- return $value instanceof \ResourceBundle ? new static($value) : $value;
- }
-
- public function offsetExists($offset)
- {
- return null !== $this->bundleImpl[$offset];
- }
-
- public function offsetGet($offset)
- {
- return $this->get($offset);
- }
-
- public function offsetSet($offset, $value)
- {
- throw new BadMethodCallException('Resource bundles cannot be modified.');
- }
-
- public function offsetUnset($offset)
- {
- throw new BadMethodCallException('Resource bundles cannot be modified.');
- }
-
- public function getIterator()
- {
- return $this->bundleImpl;
- }
-
- public function count()
- {
- return $this->bundleImpl->count();
- }
-
- public function getErrorCode()
- {
- return $this->bundleImpl->getErrorCode();
- }
-
- public function getErrorMessage()
- {
- return $this->bundleImpl->getErrorMessage();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Util;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RecursiveArrayAccess
-{
- public static function get($array, array $indices)
- {
- foreach ($indices as $index) {
- if (!$array instanceof \ArrayAccess && !is_array($array)) {
- return null;
- }
-
- $array = $array[$index];
- }
-
- return $array;
- }
-
- private function __construct() {}
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Util;
-
-use Symfony\Component\Intl\Exception\OutOfBoundsException;
-
-/**
- * Implements a ring buffer.
- *
- * A ring buffer is an array-like structure with a fixed size. If the buffer
- * is full, the next written element overwrites the first bucket in the buffer,
- * then the second and so on.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RingBuffer implements \ArrayAccess
-{
- private $values = array();
-
- private $indices = array();
-
- private $cursor = 0;
-
- private $size;
-
- public function __construct($size)
- {
- $this->size = $size;
- }
-
- /**
- * {@inheritdoc}
- */
- public function offsetExists($key)
- {
- return isset($this->indices[$key]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function offsetGet($key)
- {
- if (!isset($this->indices[$key])) {
- throw new OutOfBoundsException(sprintf(
- 'The index "%s" does not exist.',
- $key
- ));
- }
-
- return $this->values[$this->indices[$key]];
- }
-
- /**
- * {@inheritdoc}
- */
- public function offsetSet($key, $value)
- {
- if (false !== ($keyToRemove = array_search($this->cursor, $this->indices))) {
- unset($this->indices[$keyToRemove]);
- }
-
- $this->values[$this->cursor] = $value;
- $this->indices[$key] = $this->cursor;
-
- $this->cursor = ($this->cursor + 1) % $this->size;
- }
-
- /**
- * {@inheritdoc}
- */
- public function offsetUnset($key)
- {
- if (isset($this->indices[$key])) {
- $this->values[$this->indices[$key]] = null;
- unset($this->indices[$key]);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Writer;
-
-/**
- * Writes resource bundle files.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface BundleWriterInterface
-{
- /**
- * Writes data to a resource bundle.
- *
- * @param string $path The path to the resource bundle.
- * @param string $locale The locale to (over-)write.
- * @param mixed $data The data to write.
- */
- public function write($path, $locale, $data);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Writer;
-
-/**
- * Writes .php resource bundles.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PhpBundleWriter implements BundleWriterInterface
-{
- /**
- * {@inheritdoc}
- */
- public function write($path, $locale, $data)
- {
- $template = <<<TEMPLATE
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return %s;
-
-TEMPLATE;
-
- $data = var_export($data, true);
- $data = preg_replace('/array \(/', 'array(', $data);
- $data = preg_replace('/\n {1,10}array\(/', 'array(', $data);
- $data = preg_replace('/ /', ' ', $data);
- $data = sprintf($template, $data);
-
- file_put_contents($path.'/'.$locale.'.php', $data);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\ResourceBundle\Writer;
-
-/**
- * Writes .txt resource bundles.
- *
- * The resulting files can be converted to binary .res files using the
- * {@link \Symfony\Component\Intl\ResourceBundle\Transformer\BundleCompiler}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
-class TextBundleWriter implements BundleWriterInterface
-{
- /**
- * {@inheritdoc}
- */
- public function write($path, $locale, $data)
- {
- $file = fopen($path.'/'.$locale.'.txt', 'w');
-
- $this->writeResourceBundle($file, $locale, $data);
-
- fclose($file);
- }
-
- /**
- * Writes a "resourceBundle" node.
- *
- * @param resource $file The file handle to write to.
- * @param string $bundleName The name of the bundle.
- * @param mixed $value The value of the node.
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
- private function writeResourceBundle($file, $bundleName, $value)
- {
- fwrite($file, $bundleName);
-
- $this->writeTable($file, $value, 0);
-
- fwrite($file, "\n");
- }
-
- /**
- * Writes a "resource" node.
- *
- * @param resource $file The file handle to write to.
- * @param mixed $value The value of the node.
- * @param integer $indentation The number of levels to indent.
- * @param Boolean $requireBraces Whether to require braces to be printed
- * around the value.
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
- private function writeResource($file, $value, $indentation, $requireBraces = true)
- {
- if (is_int($value)) {
- $this->writeInteger($file, $value);
-
- return;
- }
-
- if (is_array($value)) {
- if (count($value) === count(array_filter($value, 'is_int'))) {
- $this->writeIntVector($file, $value, $indentation);
-
- return;
- }
-
- $keys = array_keys($value);
-
- if (count($keys) === count(array_filter($keys, 'is_int'))) {
- $this->writeArray($file, $value, $indentation);
-
- return;
- }
-
- $this->writeTable($file, $value, $indentation);
-
- return;
- }
-
- if (is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
-
- $this->writeString($file, (string) $value, $requireBraces);
- }
-
- /**
- * Writes an "integer" node.
- *
- * @param resource $file The file handle to write to.
- * @param integer $value The value of the node.
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
- private function writeInteger($file, $value)
- {
- fprintf($file, ':int{%d}', $value);
- }
-
- /**
- * Writes an "intvector" node.
- *
- * @param resource $file The file handle to write to.
- * @param array $value The value of the node.
- * @param integer $indentation The number of levels to indent.
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
- private function writeIntVector($file, array $value, $indentation)
- {
- fwrite($file, ":intvector{\n");
-
- foreach ($value as $int) {
- fprintf($file, "%s%d,\n", str_repeat(' ', $indentation + 1), $int);
- }
-
- fprintf($file, "%s}", str_repeat(' ', $indentation));
- }
-
- /**
- * Writes a "string" node.
- *
- * @param resource $file The file handle to write to.
- * @param string $value The value of the node.
- * @param Boolean $requireBraces Whether to require braces to be printed
- * around the value.
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
- private function writeString($file, $value, $requireBraces = true)
- {
- if ($requireBraces) {
- fprintf($file, '{"%s"}', $value);
-
- return;
- }
-
- fprintf($file, '"%s"', $value);
- }
-
- /**
- * Writes an "array" node.
- *
- * @param resource $file The file handle to write to.
- * @param array $value The value of the node.
- * @param integer $indentation The number of levels to indent.
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
- private function writeArray($file, array $value, $indentation)
- {
- fwrite($file, "{\n");
-
- foreach ($value as $entry) {
- fwrite($file, str_repeat(' ', $indentation + 1));
-
- $this->writeResource($file, $entry, $indentation + 1, false);
-
- fwrite($file, ",\n");
- }
-
- fprintf($file, '%s}', str_repeat(' ', $indentation));
- }
-
- /**
- * Writes a "table" node.
- *
- * @param resource $file The file handle to write to.
- * @param array $value The value of the node.
- * @param integer $indentation The number of levels to indent.
- */
- private function writeTable($file, array $value, $indentation)
- {
- fwrite($file, "{\n");
-
- foreach ($value as $key => $entry) {
- fwrite($file, str_repeat(' ', $indentation + 1));
- fwrite($file, $key);
-
- $this->writeResource($file, $entry, $indentation + 1);
-
- fwrite($file, "\n");
- }
-
- fprintf($file, '%s}', str_repeat(' ', $indentation));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-$autoload = __DIR__ . '/../../vendor/autoload.php';
-
-if (!file_exists($autoload)) {
- bailout('You should run "composer install --dev" in the component before running this script.');
-}
-
-require_once realpath($autoload);
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-define('LINE_WIDTH', 75);
-
-define('LINE', str_repeat('-', LINE_WIDTH) . "\n");
-
-function bailout($message)
-{
- echo wordwrap($message, LINE_WIDTH) . " Aborting.\n";
-
- exit(1);
-}
-
-function strip_minor_versions($version)
-{
- preg_match('/^(?P<version>[0-9]\.[0-9]|[0-9]{2,})/', $version, $matches);
-
- return $matches['version'];
-}
-
-function centered($text)
-{
- $padding = (int) ((LINE_WIDTH - strlen($text))/2);
-
- return str_repeat(' ', $padding) . $text;
-}
-
-function cd($dir)
-{
- if (false === chdir($dir)) {
- bailout("Could not switch to directory $dir.");
- }
-}
-
-function run($command)
-{
- exec($command, $output, $status);
-
- if (0 !== $status) {
- $output = implode("\n", $output);
- echo "Error while running:\n " . getcwd() . '$ ' . $command . "\nOutput:\n" . LINE . "$output\n" . LINE;
-
- bailout("\"$command\" failed.");
- }
-}
-
-function get_icu_version_from_genrb($genrb)
-{
- exec($genrb . ' --version 2>&1', $output, $status);
-
- if (0 !== $status) {
- bailout($genrb . ' failed.');
- }
-
- if (!preg_match('/ICU version ([\d\.]+)/', implode('', $output), $matches)) {
- return null;
- }
-
- return $matches[1];
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\Icu\IcuData;
-use Symfony\Component\Intl\Intl;
-
-require_once __DIR__ . '/common.php';
-require_once __DIR__ . '/autoload.php';
-
-if (1 !== $GLOBALS['argc']) {
- bailout(<<<MESSAGE
-Usage: php copy-stubs-to-component.php
-
-Copies stub files created with create-stubs.php to the Icu component.
-
-For running this script, the intl extension must be loaded and all vendors
-must have been installed through composer:
-
- composer install --dev
-
-MESSAGE
- );
-}
-
-echo LINE;
-echo centered("ICU Resource Bundle Stub Update") . "\n";
-echo LINE;
-
-if (!class_exists('\Symfony\Component\Icu\IcuData')) {
- bailout('You must run "composer update --dev" before running this script.');
-}
-
-$stubBranch = '1.0.x';
-
-if (!IcuData::isStubbed()) {
- bailout("Please switch to the Icu component branch $stubBranch.");
-}
-
-$filesystem = new Filesystem();
-
-$sourceDir = sys_get_temp_dir() . '/icu-stubs';
-$targetDir = IcuData::getResourceDirectory();
-
-if (!$filesystem->exists($sourceDir)) {
- bailout("The directory $sourceDir does not exist. Please run create-stubs.php first.");
-}
-
-$filesystem->remove($targetDir);
-
-echo "Copying files from $sourceDir to $targetDir...\n";
-
-$filesystem->mirror($sourceDir, $targetDir);
-
-echo "Done.\n";
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\Icu\IcuData;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\ResourceBundle\Transformer\BundleTransformer;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\CurrencyBundleTransformationRule;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LanguageBundleTransformationRule;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LocaleBundleTransformationRule;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\RegionBundleTransformationRule;
-use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContext;
-
-require_once __DIR__ . '/common.php';
-require_once __DIR__ . '/autoload.php';
-
-if (1 !== $GLOBALS['argc']) {
- bailout(<<<MESSAGE
-Usage: php create-stubs.php
-
-Creates resource bundle stubs from the resource bundles in the Icu component.
-
-For running this script, the intl extension must be loaded and all vendors
-must have been installed through composer:
-
- composer install --dev
-
-MESSAGE
- );
-}
-
-echo LINE;
-echo centered("ICU Resource Bundle Stub Creation") . "\n";
-echo LINE;
-
-if (!Intl::isExtensionLoaded()) {
- bailout('The intl extension for PHP is not installed.');
-}
-
-if (!class_exists('\Symfony\Component\Icu\IcuData')) {
- bailout('You must run "composer update --dev" before running this script.');
-}
-
-$stubBranch = '1.0.x';
-
-if (IcuData::isStubbed()) {
- bailout("Please switch to a branch of the Icu component that contains .res files (anything but $stubBranch).");
-}
-
-$shortIcuVersionInPhp = strip_minor_versions(Intl::getIcuVersion());
-$shortIcuVersionInIntlComponent = strip_minor_versions(Intl::getIcuStubVersion());
-$shortIcuVersionInIcuComponent = strip_minor_versions(IcuData::getVersion());
-
-if ($shortIcuVersionInPhp !== $shortIcuVersionInIcuComponent) {
- bailout("The ICU version of the component ($shortIcuVersionInIcuComponent) does not match the ICU version in the intl extension ($shortIcuVersionInPhp).");
-}
-
-if ($shortIcuVersionInIntlComponent !== $shortIcuVersionInIcuComponent) {
- bailout("The ICU version of the component ($shortIcuVersionInIcuComponent) does not match the ICU version of the stub classes in the Intl component ($shortIcuVersionInIntlComponent).");
-}
-
-echo wordwrap("Make sure that you don't have any ICU development files " .
- "installed. If the build fails, try to run:\n", LINE_WIDTH);
-
-echo "\n sudo apt-get remove libicu-dev\n\n";
-
-$icuVersionInIcuComponent = IcuData::getVersion();
-
-echo "Compiling stubs for ICU version $icuVersionInIcuComponent.\n";
-
-echo "Preparing stub creation...\n";
-
-$targetDir = sys_get_temp_dir() . '/icu-stubs';
-
-$context = new StubbingContext(
- IcuData::getResourceDirectory(),
- $targetDir,
- new Filesystem(),
- $icuVersionInIcuComponent
-);
-
-$transformer = new BundleTransformer();
-$transformer->addRule(new LanguageBundleTransformationRule());
-$transformer->addRule(new RegionBundleTransformationRule());
-$transformer->addRule(new CurrencyBundleTransformationRule());
-$transformer->addRule(new LocaleBundleTransformationRule());
-
-echo "Starting stub creation...\n";
-
-$transformer->createStubs($context);
-
-echo "Wrote stubs to $targetDir.\n";
-
-$versionFile = $context->getStubDir() . '/version.txt';
-
-file_put_contents($versionFile, "$icuVersionInIcuComponent\n");
-
-echo "Wrote $versionFile.\n";
-
-echo "Done.\n";
-
-echo wordwrap("Please change the Icu component to branch $stubBranch now and run:\n", LINE_WIDTH);
-
-echo "\n php copy-stubs-to-component.php\n";
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use Symfony\Component\Intl\Intl;
-
-require_once __DIR__ . '/common.php';
-require_once __DIR__ . '/autoload.php';
-
-echo "ICU version: ";
-echo Intl::getIcuVersion() . "\n";
+++ /dev/null
-; ICU data source URLs
-; We use always the latest release of a major version.
-4.0 = http://source.icu-project.org/repos/icu/icu/tags/release-4-0-1/source
-4.2 = http://source.icu-project.org/repos/icu/icu/tags/release-4-2-1/source
-4.4 = http://source.icu-project.org/repos/icu/icu/tags/release-4-4-2/source
-4.6 = http://source.icu-project.org/repos/icu/icu/tags/release-4-6-1/source
-4.8 = http://source.icu-project.org/repos/icu/icu/tags/release-4-8-1-1/source
-49 = http://source.icu-project.org/repos/icu/icu/tags/release-49-1-2/source
-50 = http://source.icu-project.org/repos/icu/icu/tags/release-50-1-2/source
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use Symfony\Component\Intl\Intl;
-
-require_once __DIR__ . '/common.php';
-require_once __DIR__ . '/autoload.php';
-
-if (1 !== $GLOBALS['argc']) {
- bailout(<<<MESSAGE
-Usage: php test-compat.php
-
-Tests the compatibility of the current ICU version (bundled in ext/intl) with
-different versions of symfony/icu.
-
-For running this script, the intl extension must be loaded and all vendors
-must have been installed through composer:
-
- composer install --dev
-
-MESSAGE
- );
-}
-
-echo LINE;
-echo centered("ICU Compatibility Test") . "\n";
-echo LINE;
-
-echo "Your ICU version: " . Intl::getIcuVersion() . "\n";
-
-echo "Compatibility with symfony/icu:\n";
-
-$branches = array(
- '1.1.x',
- '1.2.x',
-);
-
-cd(__DIR__ . '/../../vendor/symfony/icu/Symfony/Component/Icu');
-
-foreach ($branches as $branch) {
- run('git checkout ' . $branch . ' 2>&1');
-
- exec('php ' . __DIR__ . '/util/test-compat-helper.php > /dev/null 2> /dev/null', $output, $status);
-
- echo "$branch: " . (0 === $status ? "YES" : "NO") . "\n";
-}
-
-echo "Done.\n";
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use Symfony\Component\Icu\IcuData;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompiler;
-use Symfony\Component\Intl\ResourceBundle\Transformer\BundleTransformer;
-use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContext;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\CurrencyBundleTransformationRule;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LanguageBundleTransformationRule;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LocaleBundleTransformationRule;
-use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\RegionBundleTransformationRule;
-use Symfony\Component\Intl\Util\SvnRepository;
-use Symfony\Component\Filesystem\Filesystem;
-
-require_once __DIR__ . '/common.php';
-require_once __DIR__ . '/autoload.php';
-
-if ($GLOBALS['argc'] > 3 || 2 === $GLOBALS['argc'] && '-h' === $GLOBALS['argv'][1]) {
- bailout(<<<MESSAGE
-Usage: php update-icu-component.php <path/to/icu/source> <path/to/icu/build>
-
-Updates the ICU data for Symfony2 to the latest version of the ICU version
-included in the intl extension. For example, if your intl extension includes
-ICU 4.8, the script will download the latest data available for ICU 4.8.
-
-If you downloaded the SVN repository before, you can pass the path to the
-repository source in the first optional argument.
-
-If you also built the repository before, you can pass the directory where that
-build is stored in the second parameter. The build directory needs to contain
-the subdirectories bin/ and lib/.
-
-For running this script, the intl extension must be loaded and all vendors
-must have been installed through composer:
-
- composer install --dev
-
-MESSAGE
- );
-}
-
-echo LINE;
-echo centered("ICU Resource Bundle Compilation") . "\n";
-echo LINE;
-
-if (!Intl::isExtensionLoaded()) {
- bailout('The intl extension for PHP is not installed.');
-}
-
-if (!class_exists('\Symfony\Component\Icu\IcuData')) {
- bailout('You must run "composer update --dev" before running this script.');
-}
-
-$filesystem = new Filesystem();
-
-$icuVersionInPhp = Intl::getIcuVersion();
-
-echo "Found intl extension with ICU version $icuVersionInPhp.\n";
-
-$shortIcuVersion = strip_minor_versions($icuVersionInPhp);
-$urls = parse_ini_file(__DIR__ . '/icu.ini');
-
-if (!isset($urls[$shortIcuVersion])) {
- bailout('The version ' . $shortIcuVersion . ' is not available in the icu.ini file.');
-}
-
-echo "icu.ini parsed. Available versions:\n";
-
-foreach ($urls as $urlVersion => $url) {
- echo " $urlVersion\n";
-}
-
-if ($GLOBALS['argc'] >= 2) {
- $sourceDir = $GLOBALS['argv'][1];
- $svn = new SvnRepository($sourceDir);
-
- echo "Using existing SVN repository at {$sourceDir}.\n";
-} else {
- echo "Starting SVN checkout for version $shortIcuVersion. This may take a while...\n";
-
- $sourceDir = sys_get_temp_dir() . '/icu-data/' . $shortIcuVersion . '/source';
- $svn = SvnRepository::download($urls[$shortIcuVersion], $sourceDir);
-
- echo "SVN checkout to {$sourceDir} complete.\n";
-}
-
-if ($GLOBALS['argc'] >= 3) {
- $buildDir = $GLOBALS['argv'][2];
-} else {
- // Always build genrb so that we can determine the ICU version of the
- // download by running genrb --version
- echo "Building genrb.\n";
-
- cd($sourceDir);
-
- echo "Running configure...\n";
-
- $buildDir = sys_get_temp_dir() . '/icu-data/' . $shortIcuVersion . '/build';
-
- $filesystem->remove($buildDir);
- $filesystem->mkdir($buildDir);
-
- run('./configure --prefix=' . $buildDir . ' 2>&1');
-
- echo "Running make...\n";
-
- // If the directory "lib" does not exist in the download, create it or we
- // will run into problems when building libicuuc.so.
- $filesystem->mkdir($sourceDir . '/lib');
-
- // If the directory "bin" does not exist in the download, create it or we
- // will run into problems when building genrb.
- $filesystem->mkdir($sourceDir . '/bin');
-
- echo "[1/5] libicudata.so...";
-
- cd($sourceDir . '/stubdata');
- run('make 2>&1 && make install 2>&1');
-
- echo " ok.\n";
-
- echo "[2/5] libicuuc.so...";
-
- cd($sourceDir . '/common');
- run('make 2>&1 && make install 2>&1');
-
- echo " ok.\n";
-
- echo "[3/5] libicui18n.so...";
-
- cd($sourceDir . '/i18n');
- run('make 2>&1 && make install 2>&1');
-
- echo " ok.\n";
-
- echo "[4/5] libicutu.so...";
-
- cd($sourceDir . '/tools/toolutil');
- run('make 2>&1 && make install 2>&1');
-
- echo " ok.\n";
-
- echo "[5/5] genrb...";
-
- cd($sourceDir . '/tools/genrb');
- run('make 2>&1 && make install 2>&1');
-
- echo " ok.\n";
-}
-
-$genrb = $buildDir . '/bin/genrb';
-$genrbEnv = 'LD_LIBRARY_PATH=' . $buildDir . '/lib ';
-
-echo "Using $genrb.\n";
-
-$icuVersionInDownload = get_icu_version_from_genrb($genrbEnv . ' ' . $genrb);
-
-echo "Preparing resource bundle compilation (version $icuVersionInDownload)...\n";
-
-$context = new CompilationContext(
- $sourceDir . '/data',
- IcuData::getResourceDirectory(),
- $filesystem,
- new BundleCompiler($genrb, $genrbEnv),
- $icuVersionInDownload
-);
-
-$transformer = new BundleTransformer();
-$transformer->addRule(new LanguageBundleTransformationRule());
-$transformer->addRule(new RegionBundleTransformationRule());
-$transformer->addRule(new CurrencyBundleTransformationRule());
-$transformer->addRule(new LocaleBundleTransformationRule());
-
-echo "Starting resource bundle compilation. This may take a while...\n";
-
-$transformer->compileBundles($context);
-
-echo "Resource bundle compilation complete.\n";
-
-$svnInfo = <<<SVN_INFO
-SVN information
-===============
-
-URL: {$svn->getUrl()}
-Revision: {$svn->getLastCommit()->getRevision()}
-Author: {$svn->getLastCommit()->getAuthor()}
-Date: {$svn->getLastCommit()->getDate()}
-
-SVN_INFO;
-
-$svnInfoFile = $context->getBinaryDir() . '/svn-info.txt';
-
-file_put_contents($svnInfoFile, $svnInfo);
-
-echo "Wrote $svnInfoFile.\n";
-
-$versionFile = $context->getBinaryDir() . '/version.txt';
-
-file_put_contents($versionFile, "$icuVersionInDownload\n");
-
-echo "Wrote $versionFile.\n";
-
-echo "Done.\n";
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use Symfony\Component\Icu\IcuData;
-use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader;
-
-require_once __DIR__ . '/../common.php';
-require_once __DIR__ . '/../autoload.php';
-
-$reader = new BinaryBundleReader();
-
-$reader->read(IcuData::getResourceDirectory() . '/curr', 'en');
-$reader->read(IcuData::getResourceDirectory() . '/lang', 'en');
-$reader->read(IcuData::getResourceDirectory() . '/locales', 'en');
-$reader->read(IcuData::getResourceDirectory() . '/region', 'en');
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Stub implementation for the Collator class of the intl extension
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see \Symfony\Component\Intl\Collator\StubCollator
- */
-class Collator extends \Symfony\Component\Intl\Collator\Collator
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Stub implementation for the IntlDateFormatter class of the intl extension
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see \Symfony\Component\Intl\DateFormatter\IntlDateFormatter
- */
-class IntlDateFormatter extends \Symfony\Component\Intl\DateFormatter\IntlDateFormatter
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Stub implementation for the Locale class of the intl extension
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see \Symfony\Component\Intl\Locale\Locale
- */
-class Locale extends \Symfony\Component\Intl\Locale\Locale
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Stub implementation for the NumberFormatter class of the intl extension
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see \Symfony\Component\Intl\NumberFormatter\NumberFormatter
- */
-class NumberFormatter extends \Symfony\Component\Intl\NumberFormatter\NumberFormatter
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use Symfony\Component\Intl\Globals\IntlGlobals;
-
-if (!function_exists('intl_is_failure')) {
-
- /**
- * Stub implementation for the {@link intl_is_failure()} function of the intl
- * extension.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @param integer $errorCode The error code returned by intl_get_error_code().
- *
- * @return Boolean Whether the error code indicates an error.
- *
- * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::isFailure
- */
- function intl_is_failure($errorCode)
- {
- return IntlGlobals::isFailure($errorCode);
- }
-
- /**
- * Stub implementation for the {@link intl_get_error_code()} function of the
- * intl extension.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @return Boolean The error code of the last intl function call or
- * IntlGlobals::U_ZERO_ERROR if no error occurred.
- *
- * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorCode
- */
- function intl_get_error_code()
- {
- return IntlGlobals::getErrorCode();
- }
-
- /**
- * Stub implementation for the {@link intl_get_error_code()} function of the
- * intl extension.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @return Boolean The error message of the last intl function call or
- * "U_ZERO_ERROR" if no error occurred.
- *
- * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorMessage
- */
- function intl_get_error_message()
- {
- return IntlGlobals::getErrorMessage();
- }
-
- /**
- * Stub implementation for the {@link intl_error_name()} function of the intl
- * extension.
- *
- * @param integer $errorCode The error code.
- *
- * @return string The name of the error code constant.
- *
- * @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorName
- */
- function intl_error_name($errorCode)
- {
- return IntlGlobals::getErrorName($errorCode);
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Collator;
-
-use Symfony\Component\Intl\Collator\Collator;
-use Symfony\Component\Intl\Locale;
-
-/**
- * Test case for Collator implementations.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractCollatorTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider asortProvider
- */
- public function testAsort($array, $sortFlag, $expected)
- {
- $collator = $this->getCollator('en');
- $collator->asort($array, $sortFlag);
- $this->assertSame($expected, $array);
- }
-
- public function asortProvider()
- {
- return array(
- /* array, sortFlag, expected */
- array(
- array('a', 'b', 'c'),
- Collator::SORT_REGULAR,
- array('a', 'b', 'c'),
- ),
- array(
- array('c', 'b', 'a'),
- Collator::SORT_REGULAR,
- array(2 => 'a', 1 => 'b', 0 => 'c'),
- ),
- array(
- array('b', 'c', 'a'),
- Collator::SORT_REGULAR,
- array(2 => 'a', 0 => 'b', 1 => 'c'),
- ),
- );
- }
-
- /**
- * @param string $locale
- *
- * @return \Collator
- */
- abstract protected function getCollator($locale);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Collator;
-
-use Symfony\Component\Intl\Collator\Collator;
-use Symfony\Component\Intl\Globals\IntlGlobals;
-
-class CollatorTest extends AbstractCollatorTest
-{
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testConstructorWithUnsupportedLocale()
- {
- new Collator('pt_BR');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testCompare()
- {
- $collator = $this->getCollator('en');
- $collator->compare('a', 'b');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetAttribute()
- {
- $collator = $this->getCollator('en');
- $collator->getAttribute(Collator::NUMERIC_COLLATION);
- }
-
- public function testGetErrorCode()
- {
- $collator = $this->getCollator('en');
- $this->assertEquals(IntlGlobals::U_ZERO_ERROR, $collator->getErrorCode());
- }
-
- public function testGetErrorMessage()
- {
- $collator = $this->getCollator('en');
- $this->assertEquals('U_ZERO_ERROR', $collator->getErrorMessage());
- }
-
- public function testGetLocale()
- {
- $collator = $this->getCollator('en');
- $this->assertEquals('en', $collator->getLocale());
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetSortKey()
- {
- $collator = $this->getCollator('en');
- $collator->getSortKey('Hello');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetStrength()
- {
- $collator = $this->getCollator('en');
- $collator->getStrength();
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testSetAttribute()
- {
- $collator = $this->getCollator('en');
- $collator->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testSetStrength()
- {
- $collator = $this->getCollator('en');
- $collator->setStrength(Collator::PRIMARY);
- }
-
- public function testStaticCreate()
- {
- $collator = Collator::create('en');
- $this->assertInstanceOf('\Symfony\Component\Intl\Collator\Collator', $collator);
- }
-
- protected function getCollator($locale)
- {
- return new Collator($locale);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Collator\Verification;
-
-use Symfony\Component\Intl\Locale;
-use Symfony\Component\Intl\Tests\Collator\AbstractCollatorTest;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * Verifies that {@link AbstractCollatorTest} matches the behavior of the
- * {@link \Collator} class in a specific version of ICU.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CollatorTest extends AbstractCollatorTest
-{
- protected function setUp()
- {
- IntlTestHelper::requireFullIntl($this);
-
- parent::setUp();
- }
-
- protected function getCollator($locale)
- {
- return new \Collator($locale);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\DateFormatter;
-
-use Symfony\Component\Intl\DateFormatter\IntlDateFormatter;
-use Symfony\Component\Intl\Globals\IntlGlobals;
-use Symfony\Component\Intl\Intl;
-
-/**
- * Test case for IntlDateFormatter implementations.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * When a time zone is not specified, it uses the system default however it returns null in the getter method
- * @covers Symfony\Component\Intl\DateFormatter\IntlDateFormatter::getTimeZoneId
- * @see StubIntlDateFormatterTest::testDefaultTimeZoneIntl()
- */
- public function testConstructorDefaultTimeZone()
- {
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
-
- // In PHP 5.5 default timezone depends on `date_default_timezone_get()` method
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $this->assertEquals(date_default_timezone_get(), $formatter->getTimeZoneId());
- } else {
- $this->assertNull($formatter->getTimeZoneId());
- }
- }
-
- /**
- * @dataProvider formatProvider
- */
- public function testFormat($pattern, $timestamp, $expected)
- {
- $errorCode = IntlGlobals::U_ZERO_ERROR;
- $errorMessage = 'U_ZERO_ERROR';
-
- $formatter = $this->getDefaultDateFormatter($pattern);
- $this->assertSame($expected, $formatter->format($timestamp));
- $this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
- }
-
- public function formatProvider()
- {
- $formatData = array(
- /* general */
- array('y-M-d', 0, '1970-1-1'),
- array("EEE, MMM d, ''yy", 0, "Thu, Jan 1, '70"),
- array('h:mm a', 0, '12:00 AM'),
- array('yyyyy.MMMM.dd hh:mm aaa', 0, '01970.January.01 12:00 AM'),
-
- /* escaping */
- array("'M'", 0, 'M'),
- array("'yy'", 0, 'yy'),
- array("'''yy'", 0, "'yy"),
- array("''y", 0, "'1970"),
- array("''yy", 0, "'70"),
- array("H 'o'' clock'", 0, "0 o' clock"),
-
- /* month */
- array('M', 0, '1'),
- array('MM', 0, '01'),
- array('MMM', 0, 'Jan'),
- array('MMMM', 0, 'January'),
- array('MMMMM', 0, 'J'),
- array('MMMMMM', 0, '000001'),
-
- array('L', 0, '1'),
- array('LL', 0, '01'),
- array('LLL', 0, 'Jan'),
- array('LLLL', 0, 'January'),
- array('LLLLL', 0, 'J'),
- array('LLLLLL', 0, '000001'),
-
- /* year */
- array('y', 0, '1970'),
- array('yy', 0, '70'),
- array('yyy', 0, '1970'),
- array('yyyy', 0, '1970'),
- array('yyyyy', 0, '01970'),
- array('yyyyyy', 0, '001970'),
-
- /* day */
- array('d', 0, '1'),
- array('dd', 0, '01'),
- array('ddd', 0, '001'),
-
- /* quarter */
- array('Q', 0, '1'),
- array('QQ', 0, '01'),
- array('QQQ', 0, 'Q1'),
- array('QQQQ', 0, '1st quarter'),
- array('QQQQQ', 0, '1st quarter'),
-
- array('q', 0, '1'),
- array('qq', 0, '01'),
- array('qqq', 0, 'Q1'),
- array('qqqq', 0, '1st quarter'),
- array('qqqqq', 0, '1st quarter'),
-
- // 4 months
- array('Q', 7776000, '2'),
- array('QQ', 7776000, '02'),
- array('QQQ', 7776000, 'Q2'),
- array('QQQQ', 7776000, '2nd quarter'),
-
- // 7 months
- array('QQQQ', 15638400, '3rd quarter'),
-
- // 10 months
- array('QQQQ', 23587200, '4th quarter'),
-
- /* 12-hour (1-12) */
- array('h', 0, '12'),
- array('hh', 0, '12'),
- array('hhh', 0, '012'),
-
- array('h', 1, '12'),
- array('h', 3600, '1'),
- array('h', 43200, '12'), // 12 hours
-
- /* day of year */
- array('D', 0, '1'),
- array('D', 86400, '2'), // 1 day
- array('D', 31536000, '1'), // 1 year
- array('D', 31622400, '2'), // 1 year + 1 day
-
- /* day of week */
- array('E', 0, 'Thu'),
- array('EE', 0, 'Thu'),
- array('EEE', 0, 'Thu'),
- array('EEEE', 0, 'Thursday'),
- array('EEEEE', 0, 'T'),
- array('EEEEEE', 0, 'Thu'),
-
- array('E', 1296540000, 'Tue'), // 2011-02-01
- array('E', 1296950400, 'Sun'), // 2011-02-06
-
- /* am/pm marker */
- array('a', 0, 'AM'),
- array('aa', 0, 'AM'),
- array('aaa', 0, 'AM'),
- array('aaaa', 0, 'AM'),
-
- // 12 hours
- array('a', 43200, 'PM'),
- array('aa', 43200, 'PM'),
- array('aaa', 43200, 'PM'),
- array('aaaa', 43200, 'PM'),
-
- /* 24-hour (0-23) */
- array('H', 0, '0'),
- array('HH', 0, '00'),
- array('HHH', 0, '000'),
-
- array('H', 1, '0'),
- array('H', 3600, '1'),
- array('H', 43200, '12'),
- array('H', 46800, '13'),
-
- /* 24-hour (1-24) */
- array('k', 0, '24'),
- array('kk', 0, '24'),
- array('kkk', 0, '024'),
-
- array('k', 1, '24'),
- array('k', 3600, '1'),
- array('k', 43200, '12'),
- array('k', 46800, '13'),
-
- /* 12-hour (0-11) */
- array('K', 0, '0'),
- array('KK', 0, '00'),
- array('KKK', 0, '000'),
-
- array('K', 1, '0'),
- array('K', 3600, '1'),
- array('K', 43200, '0'), // 12 hours
-
- /* minute */
- array('m', 0, '0'),
- array('mm', 0, '00'),
- array('mmm', 0, '000'),
-
- array('m', 1, '0'),
- array('m', 60, '1'),
- array('m', 120, '2'),
- array('m', 180, '3'),
- array('m', 3600, '0'),
- array('m', 3660, '1'),
- array('m', 43200, '0'), // 12 hours
-
- /* second */
- array('s', 0, '0'),
- array('ss', 0, '00'),
- array('sss', 0, '000'),
-
- array('s', 1, '1'),
- array('s', 2, '2'),
- array('s', 5, '5'),
- array('s', 30, '30'),
- array('s', 59, '59'),
- array('s', 60, '0'),
- array('s', 120, '0'),
- array('s', 180, '0'),
- array('s', 3600, '0'),
- array('s', 3601, '1'),
- array('s', 3630, '30'),
- array('s', 43200, '0'), // 12 hours
-
- // general
- array("yyyy.MM.dd 'at' HH:mm:ss zzz", 0, '1970.01.01 at 00:00:00 GMT'),
- array('K:mm a, z', 0, '0:00 AM, GMT'),
-
- // timezone
- array('z', 0, 'GMT'),
- array('zz', 0, 'GMT'),
- array('zzz', 0, 'GMT'),
- array('zzzz', 0, 'GMT'),
- array('zzzzz', 0, 'GMT'),
- );
-
- // As of PHP 5.3.4, IntlDateFormatter::format() accepts DateTime instances
- if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
- $dateTime = new \DateTime('@0');
-
- /* general, DateTime */
- $formatData[] = array('y-M-d', $dateTime, '1970-1-1');
- $formatData[] = array("EEE, MMM d, ''yy", $dateTime, "Thu, Jan 1, '70");
- $formatData[] = array('h:mm a', $dateTime, '12:00 AM');
- $formatData[] = array('yyyyy.MMMM.dd hh:mm aaa', $dateTime, '01970.January.01 12:00 AM');
-
- $formatData[] = array("yyyy.MM.dd 'at' HH:mm:ss zzz", $dateTime, '1970.01.01 at 00:00:00 GMT');
- $formatData[] = array('K:mm a, z', $dateTime, '0:00 AM, GMT');
- }
-
- return $formatData;
- }
-
- /**
- * @dataProvider formatErrorProvider
- */
- public function testFormatIllegalArgumentError($pattern, $timestamp, $errorMessage)
- {
- $errorCode = IntlGlobals::U_ILLEGAL_ARGUMENT_ERROR;
-
- $formatter = $this->getDefaultDateFormatter($pattern);
- $this->assertFalse($formatter->format($timestamp));
- $this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
- }
-
- public function formatErrorProvider()
- {
- // With PHP 5.5 IntlDateFormatter accepts empty values ('0')
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- return array(
- array('y-M-d', 'foobar', 'datefmt_format: string \'foobar\' is not numeric, which would be required for it to be a valid date: U_ILLEGAL_ARGUMENT_ERROR')
- );
- }
-
- $message = 'datefmt_format: takes either an array or an integer timestamp value : U_ILLEGAL_ARGUMENT_ERROR';
-
- if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
- $message = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object: U_ILLEGAL_ARGUMENT_ERROR';
- }
-
- return array(
- array('y-M-d', '0', $message),
- array('y-M-d', 'foobar', $message),
- );
- }
-
- /**
- * @dataProvider formatWithTimezoneProvider
- */
- public function testFormatWithTimezone($timestamp, $timezone, $expected)
- {
- $pattern = 'yyyy-MM-dd HH:mm:ss';
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, $timezone, IntlDateFormatter::GREGORIAN, $pattern);
- $this->assertSame($expected, $formatter->format($timestamp));
- }
-
- public function formatWithTimezoneProvider()
- {
- $data = array(
- array(0, 'UTC', '1970-01-01 00:00:00'),
- array(0, 'GMT', '1970-01-01 00:00:00'),
- array(0, 'GMT-03:00', '1969-12-31 21:00:00'),
- array(0, 'GMT+03:00', '1970-01-01 03:00:00'),
- array(0, 'Europe/Zurich', '1970-01-01 01:00:00'),
- array(0, 'Europe/Paris', '1970-01-01 01:00:00'),
- array(0, 'Africa/Cairo', '1970-01-01 02:00:00'),
- array(0, 'Africa/Casablanca', '1970-01-01 00:00:00'),
- array(0, 'Africa/Djibouti', '1970-01-01 03:00:00'),
- array(0, 'Africa/Johannesburg', '1970-01-01 02:00:00'),
- array(0, 'America/Antigua', '1969-12-31 20:00:00'),
- array(0, 'America/Toronto', '1969-12-31 19:00:00'),
- array(0, 'America/Vancouver', '1969-12-31 16:00:00'),
- array(0, 'Asia/Aqtau', '1970-01-01 05:00:00'),
- array(0, 'Asia/Bangkok', '1970-01-01 07:00:00'),
- array(0, 'Asia/Dubai', '1970-01-01 04:00:00'),
- array(0, 'Australia/Brisbane', '1970-01-01 10:00:00'),
- array(0, 'Australia/Eucla', '1970-01-01 08:45:00'),
- array(0, 'Australia/Melbourne', '1970-01-01 10:00:00'),
- array(0, 'Europe/Berlin', '1970-01-01 01:00:00'),
- array(0, 'Europe/Dublin', '1970-01-01 01:00:00'),
- array(0, 'Europe/Warsaw', '1970-01-01 01:00:00'),
- array(0, 'Pacific/Fiji', '1970-01-01 12:00:00'),
- );
-
- // As of PHP 5.5, intl ext no longer fallbacks invalid time zones to UTC
- if (!version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- // When time zone not exists, uses UTC by default
- $data[] = array(0, 'Foo/Bar', '1970-01-01 00:00:00');
- $data[] = array(0, 'UTC+04:30', '1970-01-01 00:00:00');
- $data[] = array(0, 'UTC+04:AA', '1970-01-01 00:00:00');
- }
-
- return $data;
- }
-
- public function testFormatWithGmtTimezone()
- {
- $formatter = $this->getDefaultDateFormatter('zzzz');
-
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $formatter->setTimeZone('GMT+03:00');
- } else {
- $formatter->setTimeZoneId('GMT+03:00');
- }
-
- $this->assertEquals('GMT+03:00', $formatter->format(0));
- }
-
- public function testFormatWithGmtTimeZoneAndMinutesOffset()
- {
- $formatter = $this->getDefaultDateFormatter('zzzz');
-
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $formatter->setTimeZone('GMT+00:30');
- } else {
- $formatter->setTimeZoneId('GMT+00:30');
- }
-
- $this->assertEquals('GMT+00:30', $formatter->format(0));
- }
-
- public function testFormatWithNonStandardTimezone()
- {
- $formatter = $this->getDefaultDateFormatter('zzzz');
-
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $formatter->setTimeZone('Pacific/Fiji');
- } else {
- $formatter->setTimeZoneId('Pacific/Fiji');
- }
-
- $this->assertEquals('Fiji Standard Time', $formatter->format(0));
- }
-
- public function testFormatWithConstructorTimezone()
- {
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC');
- $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
-
- $this->assertEquals(
- $this->getDateTime(0)->format('Y-m-d H:i:s'),
- $formatter->format(0)
- );
- }
-
- public function testFormatWithTimezoneFromEnvironmentVariable()
- {
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $this->markTestSkipped('IntlDateFormatter in PHP 5.5 no longer depends on TZ environment.');
- }
-
- $tz = getenv('TZ');
- putenv('TZ=Europe/London');
-
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
- $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
-
- $this->assertEquals(
- $this->getDateTime(0)->format('Y-m-d H:i:s'),
- $formatter->format(0)
- );
-
- $this->assertEquals('Europe/London', getenv('TZ'));
-
- // Restores TZ.
- putenv('TZ='.$tz);
- }
-
- public function testFormatWithTimezoneFromPhp()
- {
- if (!version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $this->markTestSkipped('Only in PHP 5.5 IntlDateFormatter depends on default timezone (`date_default_timezone_get()`).');
- }
-
- $tz = date_default_timezone_get();
- date_default_timezone_set('Europe/London');
-
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
- $formatter->setPattern('yyyy-MM-dd HH:mm:ss');
-
- $this->assertEquals(
- $this->getDateTime(0)->format('Y-m-d H:i:s'),
- $formatter->format(0)
- );
-
- $this->assertEquals('Europe/London', date_default_timezone_get());
-
- // Restores TZ.
- date_default_timezone_set($tz);
- }
-
- /**
- * @dataProvider dateAndTimeTypeProvider
- */
- public function testDateAndTimeType($timestamp, $datetype, $timetype, $expected)
- {
- $formatter = $this->getDateFormatter('en', $datetype, $timetype, 'UTC');
- $this->assertSame($expected, $formatter->format($timestamp));
- }
-
- public function dateAndTimeTypeProvider()
- {
- return array(
- array(0, IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'Thursday, January 1, 1970'),
- array(0, IntlDateFormatter::LONG, IntlDateFormatter::NONE, 'January 1, 1970'),
- array(0, IntlDateFormatter::MEDIUM, IntlDateFormatter::NONE, 'Jan 1, 1970'),
- array(0, IntlDateFormatter::SHORT, IntlDateFormatter::NONE, '1/1/70'),
- array(0, IntlDateFormatter::NONE, IntlDateFormatter::FULL, '12:00:00 AM GMT'),
- array(0, IntlDateFormatter::NONE, IntlDateFormatter::LONG, '12:00:00 AM GMT'),
- array(0, IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM, '12:00:00 AM'),
- array(0, IntlDateFormatter::NONE, IntlDateFormatter::SHORT, '12:00 AM'),
- );
- }
-
- public function testGetCalendar()
- {
- $formatter = $this->getDefaultDateFormatter();
- $this->assertEquals(IntlDateFormatter::GREGORIAN, $formatter->getCalendar());
- }
-
- public function testGetDateType()
- {
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::FULL, IntlDateFormatter::NONE);
- $this->assertEquals(IntlDateFormatter::FULL, $formatter->getDateType());
- }
-
- public function testGetLocale()
- {
- $formatter = $this->getDefaultDateFormatter();
- $this->assertEquals('en', $formatter->getLocale());
- }
-
- public function testGetPattern()
- {
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'UTC', IntlDateFormatter::GREGORIAN, 'yyyy-MM-dd');
- $this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
- }
-
- public function testGetTimeType()
- {
- $formatter = $this->getDateFormatter('en', IntlDateFormatter::NONE, IntlDateFormatter::FULL);
- $this->assertEquals(IntlDateFormatter::FULL, $formatter->getTimeType());
- }
-
- /**
- * @dataProvider parseProvider
- */
- public function testParse($pattern, $value, $expected)
- {
- $errorCode = IntlGlobals::U_ZERO_ERROR;
- $errorMessage = 'U_ZERO_ERROR';
-
- $formatter = $this->getDefaultDateFormatter($pattern);
- $this->assertSame($expected, $formatter->parse($value));
- $this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
- }
-
- public function parseProvider()
- {
- return array_merge(
- $this->parseYearProvider(),
- $this->parseQuarterProvider(),
- $this->parseMonthProvider(),
- $this->parseStandaloneMonthProvider(),
- $this->parseDayProvider(),
- $this->parseDayOfWeekProvider(),
- $this->parseDayOfYearProvider(),
- $this->parseHour12ClockOneBasedProvider(),
- $this->parseHour12ClockZeroBasedProvider(),
- $this->parseHour24ClockOneBasedProvider(),
- $this->parseHour24ClockZeroBasedProvider(),
- $this->parseMinuteProvider(),
- $this->parseSecondProvider(),
- $this->parseTimezoneProvider(),
- $this->parseAmPmProvider(),
- $this->parseStandaloneAmPmProvider(),
- $this->parseRegexMetaCharsProvider(),
- $this->parseQuoteCharsProvider(),
- $this->parseDashSlashProvider()
- );
- }
-
- public function parseYearProvider()
- {
- return array(
- array('y-M-d', '1970-1-1', 0),
- array('yy-M-d', '70-1-1', 0),
- );
- }
-
- public function parseQuarterProvider()
- {
- return array(
- array('Q', '1', 0),
- array('QQ', '01', 0),
- array('QQQ', 'Q1', 0),
- array('QQQQ', '1st quarter', 0),
- array('QQQQQ', '1st quarter', 0),
-
- array('Q', '2', 7776000),
- array('QQ', '02', 7776000),
- array('QQQ', 'Q2', 7776000),
- array('QQQQ', '2nd quarter', 7776000),
- array('QQQQQ', '2nd quarter', 7776000),
-
- array('q', '1', 0),
- array('qq', '01', 0),
- array('qqq', 'Q1', 0),
- array('qqqq', '1st quarter', 0),
- array('qqqqq', '1st quarter', 0),
- );
- }
-
- public function parseMonthProvider()
- {
- return array(
- array('y-M-d', '1970-1-1', 0),
- array('y-MMM-d', '1970-Jan-1', 0),
- array('y-MMMM-d', '1970-January-1', 0),
- );
- }
-
- public function parseStandaloneMonthProvider()
- {
- return array(
- array('y-L-d', '1970-1-1', 0),
- array('y-LLL-d', '1970-Jan-1', 0),
- array('y-LLLL-d', '1970-January-1', 0),
- );
- }
-
- public function parseDayProvider()
- {
- return array(
- array('y-M-d', '1970-1-1', 0),
- array('y-M-dd', '1970-1-01', 0),
- array('y-M-ddd', '1970-1-001', 0),
- );
- }
-
- public function parseDayOfWeekProvider()
- {
- return array(
- array('E', 'Thu', 0),
- array('EE', 'Thu', 0),
- array('EEE', 'Thu', 0),
- array('EEEE', 'Thursday', 0),
- array('EEEEE', 'T', 432000),
- array('EEEEEE', 'Thu', 0),
- );
- }
-
- public function parseDayOfYearProvider()
- {
- return array(
- array('D', '1', 0),
- array('D', '2', 86400),
- );
- }
-
- public function parseHour12ClockOneBasedProvider()
- {
- return array(
- // 12 hours (1-12)
- array('y-M-d h', '1970-1-1 1', 3600),
- array('y-M-d h', '1970-1-1 10', 36000),
- array('y-M-d hh', '1970-1-1 11', 39600),
- array('y-M-d hh', '1970-1-1 12', 0),
- array('y-M-d hh a', '1970-1-1 0 AM', 0),
- array('y-M-d hh a', '1970-1-1 1 AM', 3600),
- array('y-M-d hh a', '1970-1-1 10 AM', 36000),
- array('y-M-d hh a', '1970-1-1 11 AM', 39600),
- array('y-M-d hh a', '1970-1-1 12 AM', 0),
- array('y-M-d hh a', '1970-1-1 23 AM', 82800),
- array('y-M-d hh a', '1970-1-1 24 AM', 86400),
- array('y-M-d hh a', '1970-1-1 0 PM', 43200),
- array('y-M-d hh a', '1970-1-1 1 PM', 46800),
- array('y-M-d hh a', '1970-1-1 10 PM', 79200),
- array('y-M-d hh a', '1970-1-1 11 PM', 82800),
- array('y-M-d hh a', '1970-1-1 12 PM', 43200),
- array('y-M-d hh a', '1970-1-1 23 PM', 126000),
- array('y-M-d hh a', '1970-1-1 24 PM', 129600),
- );
- }
-
- public function parseHour12ClockZeroBasedProvider()
- {
- return array(
- // 12 hours (0-11)
- array('y-M-d K', '1970-1-1 1', 3600),
- array('y-M-d K', '1970-1-1 10', 36000),
- array('y-M-d KK', '1970-1-1 11', 39600),
- array('y-M-d KK', '1970-1-1 12', 43200),
- array('y-M-d KK a', '1970-1-1 0 AM', 0),
- array('y-M-d KK a', '1970-1-1 1 AM', 3600),
- array('y-M-d KK a', '1970-1-1 10 AM', 36000),
- array('y-M-d KK a', '1970-1-1 11 AM', 39600),
- array('y-M-d KK a', '1970-1-1 12 AM', 43200),
- array('y-M-d KK a', '1970-1-1 23 AM', 82800),
- array('y-M-d KK a', '1970-1-1 24 AM', 86400),
- array('y-M-d KK a', '1970-1-1 0 PM', 43200),
- array('y-M-d KK a', '1970-1-1 1 PM', 46800),
- array('y-M-d KK a', '1970-1-1 10 PM', 79200),
- array('y-M-d KK a', '1970-1-1 11 PM', 82800),
- array('y-M-d KK a', '1970-1-1 12 PM', 86400),
- array('y-M-d KK a', '1970-1-1 23 PM', 126000),
- array('y-M-d KK a', '1970-1-1 24 PM', 129600),
- );
- }
-
- public function parseHour24ClockOneBasedProvider()
- {
- return array(
- // 24 hours (1-24)
- array('y-M-d k', '1970-1-1 1', 3600),
- array('y-M-d k', '1970-1-1 10', 36000),
- array('y-M-d kk', '1970-1-1 11', 39600),
- array('y-M-d kk', '1970-1-1 12', 43200),
- array('y-M-d kk', '1970-1-1 23', 82800),
- array('y-M-d kk', '1970-1-1 24', 0),
- array('y-M-d kk a', '1970-1-1 0 AM', 0),
- array('y-M-d kk a', '1970-1-1 1 AM', 0),
- array('y-M-d kk a', '1970-1-1 10 AM', 0),
- array('y-M-d kk a', '1970-1-1 11 AM', 0),
- array('y-M-d kk a', '1970-1-1 12 AM', 0),
- array('y-M-d kk a', '1970-1-1 23 AM', 0),
- array('y-M-d kk a', '1970-1-1 24 AM', 0),
- array('y-M-d kk a', '1970-1-1 0 PM', 43200),
- array('y-M-d kk a', '1970-1-1 1 PM', 43200),
- array('y-M-d kk a', '1970-1-1 10 PM', 43200),
- array('y-M-d kk a', '1970-1-1 11 PM', 43200),
- array('y-M-d kk a', '1970-1-1 12 PM', 43200),
- array('y-M-d kk a', '1970-1-1 23 PM', 43200),
- array('y-M-d kk a', '1970-1-1 24 PM', 43200),
- );
- }
-
- public function parseHour24ClockZeroBasedProvider()
- {
- return array(
- // 24 hours (0-23)
- array('y-M-d H', '1970-1-1 0', 0),
- array('y-M-d H', '1970-1-1 1', 3600),
- array('y-M-d H', '1970-1-1 10', 36000),
- array('y-M-d HH', '1970-1-1 11', 39600),
- array('y-M-d HH', '1970-1-1 12', 43200),
- array('y-M-d HH', '1970-1-1 23', 82800),
- array('y-M-d HH a', '1970-1-1 0 AM', 0),
- array('y-M-d HH a', '1970-1-1 1 AM', 0),
- array('y-M-d HH a', '1970-1-1 10 AM', 0),
- array('y-M-d HH a', '1970-1-1 11 AM', 0),
- array('y-M-d HH a', '1970-1-1 12 AM', 0),
- array('y-M-d HH a', '1970-1-1 23 AM', 0),
- array('y-M-d HH a', '1970-1-1 24 AM', 0),
- array('y-M-d HH a', '1970-1-1 0 PM', 43200),
- array('y-M-d HH a', '1970-1-1 1 PM', 43200),
- array('y-M-d HH a', '1970-1-1 10 PM', 43200),
- array('y-M-d HH a', '1970-1-1 11 PM', 43200),
- array('y-M-d HH a', '1970-1-1 12 PM', 43200),
- array('y-M-d HH a', '1970-1-1 23 PM', 43200),
- array('y-M-d HH a', '1970-1-1 24 PM', 43200),
- );
- }
-
- public function parseMinuteProvider()
- {
- return array(
- array('y-M-d HH:m', '1970-1-1 0:1', 60),
- array('y-M-d HH:mm', '1970-1-1 0:10', 600),
- );
- }
-
- public function parseSecondProvider()
- {
- return array(
- array('y-M-d HH:mm:s', '1970-1-1 00:01:1', 61),
- array('y-M-d HH:mm:ss', '1970-1-1 00:01:10', 70),
- );
- }
-
- public function parseTimezoneProvider()
- {
- return array(
- array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-03:00', 10800),
- array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-04:00', 14400),
- array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-00:00', 0),
- array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+03:00', -10800),
- array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+04:00', -14400),
- array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-0300', 10800),
- array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+0300', -10800),
-
- // a previous timezone parsing should not change the timezone for the next parsing
- array('y-M-d HH:mm:ss', '1970-1-1 00:00:00', 0),
- );
- }
-
- public function parseAmPmProvider()
- {
- return array(
- // AM/PM (already covered by hours tests)
- array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 AM', 0),
- array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 PM', 43200),
- );
- }
-
- public function parseStandaloneAmPmProvider()
- {
- return array(
- array('a', 'AM', 0),
- array('a', 'PM', 43200),
- );
- }
-
- public function parseRegexMetaCharsProvider()
- {
- return array(
- // regexp meta chars in the pattern string
- array('y[M-d', '1970[1-1', 0),
- array('y[M/d', '1970[1/1', 0),
- );
- }
-
- public function parseQuoteCharsProvider()
- {
- return array(
- array("'M'", 'M', 0),
- array("'yy'", 'yy', 0),
- array("'''yy'", "'yy", 0),
- array("''y", "'1970", 0),
- array("H 'o'' clock'", "0 o' clock", 0),
- );
- }
-
- public function parseDashSlashProvider()
- {
- return array(
- array('y-M-d', '1970/1/1', 0),
- array('yy-M-d', '70/1/1', 0),
- array('y/M/d', '1970-1-1', 0),
- array('yy/M/d', '70-1-1', 0),
- );
- }
-
- /**
- * @dataProvider parseErrorProvider
- */
- public function testParseError($pattern, $value)
- {
- $errorCode = IntlGlobals::U_PARSE_ERROR;
- $errorMessage = 'Date parsing failed: U_PARSE_ERROR';
-
- $formatter = $this->getDefaultDateFormatter($pattern);
- $this->assertFalse($formatter->parse($value));
- $this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
- }
-
- public function parseErrorProvider()
- {
- return array(
- // 1 char month
- array('y-MMMMM-d', '1970-J-1'),
- array('y-MMMMM-d', '1970-S-1'),
-
- // standalone 1 char month
- array('y-LLLLL-d', '1970-J-1'),
- array('y-LLLLL-d', '1970-S-1'),
- );
- }
-
- /*
- * https://github.com/symfony/symfony/issues/4242
- */
- public function testParseAfterError()
- {
- $this->testParseError('y-MMMMM-d', '1970-J-1');
- $this->testParse('y-M-d', '1970-1-1', 0);
- }
-
- public function testParseWithNullPositionValue()
- {
- $position = null;
- $formatter = $this->getDefaultDateFormatter('y');
- $this->assertSame(0, $formatter->parse('1970', $position));
- $this->assertNull($position);
- }
-
- public function testSetPattern()
- {
- $formatter = $this->getDefaultDateFormatter();
- $formatter->setPattern('yyyy-MM-dd');
- $this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
- }
-
- /**
- * @covers Symfony\Component\Intl\DateFormatter\IntlDateFormatter::getTimeZoneId
- * @dataProvider setTimeZoneIdProvider
- */
- public function testSetTimeZoneId($timeZoneId, $expectedTimeZoneId)
- {
- $formatter = $this->getDefaultDateFormatter();
-
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $formatter->setTimeZone($timeZoneId);
- } else {
- $formatter->setTimeZoneId($timeZoneId);
- }
-
- $this->assertEquals($expectedTimeZoneId, $formatter->getTimeZoneId());
- }
-
- public function setTimeZoneIdProvider()
- {
- return array(
- array('UTC', 'UTC'),
- array('GMT', 'GMT'),
- array('GMT-03:00', 'GMT-03:00'),
- array('Europe/Zurich', 'Europe/Zurich'),
- array('GMT-0300', 'GMT-0300'),
- array('Foo/Bar', 'Foo/Bar'),
- array('GMT+00:AA', 'GMT+00:AA'),
- array('GMT+00AA', 'GMT+00AA'),
- );
- }
-
- protected function getDefaultDateFormatter($pattern = null)
- {
- return $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, $pattern);
- }
-
- protected function getDateTime($timestamp = null)
- {
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $timeZone = date_default_timezone_get();
- } else {
- $timeZone = getenv('TZ') ?: 'UTC';
- }
-
- $dateTime = new \DateTime();
- $dateTime->setTimestamp(null === $timestamp ? time() : $timestamp);
- $dateTime->setTimeZone(new \DateTimeZone($timeZone));
-
- return $dateTime;
- }
-
- protected function assertIsIntlFailure($formatter, $errorMessage, $errorCode)
- {
- $this->assertSame($errorMessage, $this->getIntlErrorMessage());
- $this->assertSame($errorCode, $this->getIntlErrorCode());
- $this->assertTrue($this->isIntlFailure($this->getIntlErrorCode()));
- $this->assertSame($errorMessage, $formatter->getErrorMessage());
- $this->assertSame($errorCode, $formatter->getErrorCode());
- $this->assertTrue($this->isIntlFailure($formatter->getErrorCode()));
- }
-
- protected function assertIsIntlSuccess($formatter, $errorMessage, $errorCode)
- {
- /* @var IntlDateFormatter $formatter */
- $this->assertSame($errorMessage, $this->getIntlErrorMessage());
- $this->assertSame($errorCode, $this->getIntlErrorCode());
- $this->assertFalse($this->isIntlFailure($this->getIntlErrorCode()));
- $this->assertSame($errorMessage, $formatter->getErrorMessage());
- $this->assertSame($errorCode, $formatter->getErrorCode());
- $this->assertFalse($this->isIntlFailure($formatter->getErrorCode()));
- }
-
- /**
- * @param $locale
- * @param $datetype
- * @param $timetype
- * @param null $timezone
- * @param int $calendar
- * @param null $pattern
- *
- * @return mixed
- */
- abstract protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null);
-
- /**
- * @return string
- */
- abstract protected function getIntlErrorMessage();
-
- /**
- * @return integer
- */
- abstract protected function getIntlErrorCode();
-
- /**
- * @param integer $errorCode
- *
- * @return Boolean
- */
- abstract protected function isIntlFailure($errorCode);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\DateFormatter;
-
-use Symfony\Component\Intl\DateFormatter\IntlDateFormatter;
-use Symfony\Component\Intl\Globals\IntlGlobals;
-
-class IntlDateFormatterTest extends AbstractIntlDateFormatterTest
-{
- public function testConstructor()
- {
- $formatter = new IntlDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, 'y-M-d');
- $this->assertEquals('y-M-d', $formatter->getPattern());
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testConstructorWithUnsupportedLocale()
- {
- new IntlDateFormatter('pt_BR', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
- }
-
- public function testStaticCreate()
- {
- $formatter = IntlDateFormatter::create('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT);
- $this->assertInstanceOf('\Symfony\Component\Intl\DateFormatter\IntlDateFormatter', $formatter);
- }
-
- public function testFormatWithUnsupportedTimestampArgument()
- {
- $formatter = $this->getDefaultDateFormatter();
-
- $localtime = array(
- 'tm_sec' => 59,
- 'tm_min' => 3,
- 'tm_hour' => 15,
- 'tm_mday' => 15,
- 'tm_mon' => 3,
- 'tm_year' => 112,
- 'tm_wday' => 0,
- 'tm_yday' => 105,
- 'tm_isdst' => 0
- );
-
- try {
- $formatter->format($localtime);
- } catch (\Exception $e) {
- $this->assertInstanceOf('Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException', $e);
-
- if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
- $this->assertStringEndsWith('Only integer unix timestamps and DateTime objects are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage());
- } else {
- $this->assertStringEndsWith('Only integer unix timestamps are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage());
- }
- }
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
- */
- public function testFormatWithUnimplementedChars()
- {
- $pattern = 'Y';
- $formatter = new IntlDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN, $pattern);
- $formatter->format(0);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
- */
- public function testFormatWithNonIntegerTimestamp()
- {
- $formatter = $this->getDefaultDateFormatter();
- $formatter->format(array());
- }
-
- public function testGetErrorCode()
- {
- $formatter = $this->getDefaultDateFormatter();
- $this->assertEquals(IntlGlobals::getErrorCode(), $formatter->getErrorCode());
- }
-
- public function testGetErrorMessage()
- {
- $formatter = $this->getDefaultDateFormatter();
- $this->assertEquals(IntlGlobals::getErrorMessage(), $formatter->getErrorMessage());
- }
-
- public function testIsLenient()
- {
- $formatter = $this->getDefaultDateFormatter();
- $this->assertFalse($formatter->isLenient());
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testLocaltime()
- {
- $formatter = $this->getDefaultDateFormatter();
- $formatter->localtime('Wednesday, December 31, 1969 4:00:00 PM PT');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException
- */
- public function testParseWithNotNullPositionValue()
- {
- $position = 0;
- $formatter = $this->getDefaultDateFormatter('y');
- $this->assertSame(0, $formatter->parse('1970', $position));
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testSetCalendar()
- {
- $formatter = $this->getDefaultDateFormatter();
- $formatter->setCalendar(IntlDateFormatter::GREGORIAN);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testSetLenient()
- {
- $formatter = $this->getDefaultDateFormatter();
- $formatter->setLenient(true);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
- */
- public function testFormatWithGmtTimeZoneAndMinutesOffset()
- {
- parent::testFormatWithGmtTimeZoneAndMinutesOffset();
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
- */
- public function testFormatWithNonStandardTimezone()
- {
- parent::testFormatWithNonStandardTimezone();
- }
-
- public function parseStandaloneAmPmProvider()
- {
- return $this->notImplemented(parent::parseStandaloneAmPmProvider());
- }
-
- public function parseDayOfWeekProvider()
- {
- return $this->notImplemented(parent::parseDayOfWeekProvider());
- }
-
- public function parseDayOfYearProvider()
- {
- return $this->notImplemented(parent::parseDayOfYearProvider());
- }
-
- public function parseQuarterProvider()
- {
- return $this->notImplemented(parent::parseQuarterProvider());
- }
-
- protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null)
- {
- return new IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
- }
-
- protected function getIntlErrorMessage()
- {
- return IntlGlobals::getErrorMessage();
- }
-
- protected function getIntlErrorCode()
- {
- return IntlGlobals::getErrorCode();
- }
-
- protected function isIntlFailure($errorCode)
- {
- return IntlGlobals::isFailure($errorCode);
- }
-
- /**
- * Just to document the differences between the stub and the intl
- * implementations. The intl can parse any of the tested formats alone. The
- * stub does not implement them as it would be needed to add more
- * abstraction, passing more context to the transformers objects. Any of the
- * formats are ignored alone or with date/time data (years, months, days,
- * hours, minutes and seconds).
- *
- * Also in intl, format like 'ss E' for '10 2' (2nd day of year
- * + 10 seconds) are added, then we have 86,400 seconds (24h * 60min * 60s)
- * + 10 seconds
- *
- * @param array $dataSets
- *
- * @return array
- */
- private function notImplemented(array $dataSets)
- {
- return array_map(function ($row) {
- return array($row[0], $row[1], 0);
- }, $dataSets);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\DateFormatter\Verification;
-
-use Symfony\Component\Intl\DateFormatter\IntlDateFormatter;
-use Symfony\Component\Intl\Tests\DateFormatter\AbstractIntlDateFormatterTest;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * Verifies that {@link AbstractIntlDateFormatterTest} matches the behavior of
- * the {@link \IntlDateFormatter} class in a specific version of ICU.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IntlDateFormatterTest extends AbstractIntlDateFormatterTest
-{
- protected function setUp()
- {
- IntlTestHelper::requireFullIntl($this);
-
- parent::setUp();
- }
-
- /**
- * It seems IntlDateFormatter caches the timezone id when not explicitly set via constructor or by the
- * setTimeZoneId() method. Since testFormatWithDefaultTimezoneIntl() runs using the default environment
- * time zone, this test would use it too if not running in a separated process.
- *
- * @runInSeparateProcess
- */
- public function testFormatWithTimezoneFromEnvironmentVariable()
- {
- parent::testFormatWithTimezoneFromEnvironmentVariable();
- }
-
- protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null)
- {
- return new \IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
- }
-
- protected function getIntlErrorMessage()
- {
- return intl_get_error_message();
- }
-
- protected function getIntlErrorCode()
- {
- return intl_get_error_code();
- }
-
- protected function isIntlFailure($errorCode)
- {
- return intl_is_failure($errorCode);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Globals;
-
-/**
- * Test case for intl function implementations.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractIntlGlobalsTest extends \PHPUnit_Framework_TestCase
-{
- public function errorNameProvider()
- {
- return array (
- array(-129, '[BOGUS UErrorCode]'),
- array(0, 'U_ZERO_ERROR'),
- array(1, 'U_ILLEGAL_ARGUMENT_ERROR'),
- array(9, 'U_PARSE_ERROR'),
- array(129, '[BOGUS UErrorCode]'),
- );
- }
-
- /**
- * @dataProvider errorNameProvider
- */
- public function testGetErrorName($errorCode, $errorName)
- {
- $this->assertSame($errorName, $this->getIntlErrorName($errorCode));
- }
-
- abstract protected function getIntlErrorName($errorCode);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Globals;
-
-use Symfony\Component\Intl\Globals\IntlGlobals;
-
-class IntlGlobalsTest extends AbstractIntlGlobalsTest
-{
- protected function getIntlErrorName($errorCode)
- {
- return IntlGlobals::getErrorName($errorCode);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Globals\Verification;
-
-use Symfony\Component\Intl\Tests\Globals\AbstractIntlGlobalsTest;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * Verifies that {@link AbstractIntlGlobalsTest} matches the behavior of the
- * intl functions with a specific version of ICU.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IntlGlobalsTest extends AbstractIntlGlobalsTest
-{
- protected function setUp()
- {
- IntlTestHelper::requireFullIntl($this);
-
- parent::setUp();
- }
-
- protected function getIntlErrorName($errorCode)
- {
- return intl_error_name($errorCode);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Locale;
-
-/**
- * Test case for Locale implementations.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-abstract class AbstractLocaleTest extends \PHPUnit_Framework_TestCase
-{
- public function testSetDefault()
- {
- $this->call('setDefault', 'en_GB');
-
- $this->assertSame('en_GB', $this->call('getDefault'));
- }
-
- abstract protected function call($methodName);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Locale;
-
-class LocaleTest extends AbstractLocaleTest
-{
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testAcceptFromHttp()
- {
- $this->call('acceptFromHttp', 'pt-br,en-us;q=0.7,en;q=0.5');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testComposeLocale()
- {
- $subtags = array(
- 'language' => 'pt',
- 'script' => 'Latn',
- 'region' => 'BR'
- );
- $this->call('composeLocale', $subtags);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testFilterMatches()
- {
- $this->call('filterMatches', 'pt-BR', 'pt-BR');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetAllVariants()
- {
- $this->call('getAllVariants', 'pt_BR_Latn');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetDisplayLanguage()
- {
- $this->call('getDisplayLanguage', 'pt-Latn-BR', 'en');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetDisplayName()
- {
- $this->call('getDisplayName', 'pt-Latn-BR', 'en');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetDisplayRegion()
- {
- $this->call('getDisplayRegion', 'pt-Latn-BR', 'en');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetDisplayScript()
- {
- $this->call('getDisplayScript', 'pt-Latn-BR', 'en');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetDisplayVariant()
- {
- $this->call('getDisplayVariant', 'pt-Latn-BR', 'en');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetKeywords()
- {
- $this->call('getKeywords', 'pt-BR@currency=BRL');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetPrimaryLanguage()
- {
- $this->call('getPrimaryLanguage', 'pt-Latn-BR');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetRegion()
- {
- $this->call('getRegion', 'pt-Latn-BR');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetScript()
- {
- $this->call('getScript', 'pt-Latn-BR');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testLookup()
- {
- $langtag = array(
- 'pt-Latn-BR',
- 'pt-BR'
- );
- $this->call('lookup', $langtag, 'pt-BR-x-priv1');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testParseLocale()
- {
- $this->call('parseLocale', 'pt-Latn-BR');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testSetDefault()
- {
- $this->call('setDefault', 'pt_BR');
- }
-
- protected function call($methodName)
- {
- $args = array_slice(func_get_args(), 1);
-
- return call_user_func_array(array('Symfony\Component\Intl\Locale\Locale', $methodName), $args);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Locale\Verification;
-
-use Symfony\Component\Intl\Tests\Locale\AbstractLocaleTest;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * Verifies that {@link AbstractLocaleTest} matches the behavior of the
- * {@link Locale} class with a specific version of ICU.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class LocaleTest extends AbstractLocaleTest
-{
- protected function setUp()
- {
- IntlTestHelper::requireFullIntl($this);
-
- parent::setUp();
- }
-
- protected function call($methodName)
- {
- $args = array_slice(func_get_args(), 1);
-
- return call_user_func_array(array('Locale', $methodName), $args);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\NumberFormatter;
-
-use Symfony\Component\Intl\Globals\IntlGlobals;
-use Symfony\Component\Intl\Intl;
-use Symfony\Component\Intl\Locale;
-use Symfony\Component\Intl\NumberFormatter\NumberFormatter;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * Note that there are some values written like -2147483647 - 1. This is the lower 32bit int max and is a known
- * behavior of PHP.
- */
-abstract class AbstractNumberFormatterTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider formatCurrencyWithDecimalStyleProvider
- */
- public function testFormatCurrencyWithDecimalStyle($value, $currency, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $this->assertEquals($expected, $formatter->formatCurrency($value, $currency));
- }
-
- public function formatCurrencyWithDecimalStyleProvider()
- {
- return array(
- array(100, 'ALL', '100'),
- array(100, 'BRL', '100.00'),
- array(100, 'CRC', '100'),
- array(100, 'JPY', '100'),
- array(100, 'CHF', '100'),
- array(-100, 'ALL', '-100'),
- array(-100, 'BRL', '-100'),
- array(-100, 'CRC', '-100'),
- array(-100, 'JPY', '-100'),
- array(-100, 'CHF', '-100'),
- array(1000.12, 'ALL', '1,000.12'),
- array(1000.12, 'BRL', '1,000.12'),
- array(1000.12, 'CRC', '1,000.12'),
- array(1000.12, 'JPY', '1,000.12'),
- array(1000.12, 'CHF', '1,000.12')
- );
- }
-
- /**
- * @dataProvider formatCurrencyWithCurrencyStyleProvider
- */
- public function testFormatCurrencyWithCurrencyStyle($value, $currency, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
- $this->assertEquals($expected, $formatter->formatCurrency($value, $currency));
- }
-
- public function formatCurrencyWithCurrencyStyleProvider()
- {
- return array(
- array(100, 'ALL', 'ALL100'),
- array(-100, 'ALL', '(ALL100)'),
- array(1000.12, 'ALL', 'ALL1,000'),
-
- array(100, 'JPY', '¥100'),
- array(-100, 'JPY', '(¥100)'),
- array(1000.12, 'JPY', '¥1,000'),
-
- array(100, 'EUR', '€100.00'),
- array(-100, 'EUR', '(€100.00)'),
- array(1000.12, 'EUR', '€1,000.12'),
- );
- }
-
- /**
- * @dataProvider formatCurrencyWithCurrencyStyleCostaRicanColonsRoundingProvider
- */
- public function testFormatCurrencyWithCurrencyStyleCostaRicanColonsRounding($value, $currency, $symbol, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
- $this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
- }
-
- public function formatCurrencyWithCurrencyStyleCostaRicanColonsRoundingProvider()
- {
- return array(
- array(100, 'CRC', 'CRC', '%s100'),
- array(-100, 'CRC', 'CRC', '(%s100)'),
- array(1000.12, 'CRC', 'CRC', '%s1,000'),
- );
- }
-
- /**
- * @dataProvider formatCurrencyWithCurrencyStyleBrazilianRealRoundingProvider
- */
- public function testFormatCurrencyWithCurrencyStyleBrazilianRealRounding($value, $currency, $symbol, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
- $this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
- }
-
- public function formatCurrencyWithCurrencyStyleBrazilianRealRoundingProvider()
- {
- return array(
- array(100, 'BRL', 'R', '%s$100.00'),
- array(-100, 'BRL', 'R', '(%s$100.00)'),
- array(1000.12, 'BRL', 'R', '%s$1,000.12'),
-
- // Rounding checks
- array(1000.121, 'BRL', 'R', '%s$1,000.12'),
- array(1000.123, 'BRL', 'R', '%s$1,000.12'),
- array(1000.125, 'BRL', 'R', '%s$1,000.12'),
- array(1000.127, 'BRL', 'R', '%s$1,000.13'),
- array(1000.129, 'BRL', 'R', '%s$1,000.13'),
- array(11.50999, 'BRL', 'R', '%s$11.51'),
- array(11.9999464, 'BRL', 'R', '%s$12.00')
- );
- }
-
- /**
- * @dataProvider formatCurrencyWithCurrencyStyleSwissRoundingProvider
- */
- public function testFormatCurrencyWithCurrencyStyleSwissRounding($value, $currency, $symbol, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
- $this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
- }
-
- public function formatCurrencyWithCurrencyStyleSwissRoundingProvider()
- {
- return array(
- array(100, 'CHF', 'CHF', '%s100.00'),
- array(-100, 'CHF', 'CHF', '(%s100.00)'),
- array(1000.12, 'CHF', 'CHF', '%s1,000.10'),
- array('1000.12', 'CHF', 'CHF', '%s1,000.10'),
-
- // Rounding checks
- array(1000.121, 'CHF', 'CHF', '%s1,000.10'),
- array(1000.123, 'CHF', 'CHF', '%s1,000.10'),
- array(1000.125, 'CHF', 'CHF', '%s1,000.10'),
- array(1000.127, 'CHF', 'CHF', '%s1,000.15'),
- array(1000.129, 'CHF', 'CHF', '%s1,000.15'),
-
- array(1200000.00, 'CHF', 'CHF', '%s1,200,000.00'),
- array(1200000.1, 'CHF', 'CHF', '%s1,200,000.10'),
- array(1200000.10, 'CHF', 'CHF', '%s1,200,000.10'),
- array(1200000.101, 'CHF', 'CHF', '%s1,200,000.10')
- );
- }
-
- public function testFormat()
- {
- $errorCode = IntlGlobals::U_ZERO_ERROR;
- $errorMessage = 'U_ZERO_ERROR';
-
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $this->assertSame('9.555', $formatter->format(9.555));
-
- $this->assertSame($errorMessage, $this->getIntlErrorMessage());
- $this->assertSame($errorCode, $this->getIntlErrorCode());
- $this->assertFalse($this->isIntlFailure($this->getIntlErrorCode()));
- $this->assertSame($errorMessage, $formatter->getErrorMessage());
- $this->assertSame($errorCode, $formatter->getErrorCode());
- $this->assertFalse($this->isIntlFailure($formatter->getErrorCode()));
- }
-
- public function testFormatWithCurrencyStyle()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
- $this->assertEquals('¤1.00', $formatter->format(1));
- }
-
- /**
- * @dataProvider formatTypeInt32Provider
- */
- public function testFormatTypeInt32($formatter, $value, $expected, $message = '')
- {
- $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT32);
- $this->assertEquals($expected, $formattedValue, $message);
- }
-
- public function formatTypeInt32Provider()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- $message = '->format() TYPE_INT32 formats inconsistently an integer if out of the 32 bit range.';
-
- return array(
- array($formatter, 1, '1'),
- array($formatter, 1.1, '1'),
- array($formatter, 2147483648, '-2,147,483,648', $message),
- array($formatter, -2147483649, '2,147,483,647', $message),
- );
- }
-
- /**
- * @dataProvider formatTypeInt32WithCurrencyStyleProvider
- */
- public function testFormatTypeInt32WithCurrencyStyle($formatter, $value, $expected, $message = '')
- {
- $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT32);
- $this->assertEquals($expected, $formattedValue, $message);
- }
-
- public function formatTypeInt32WithCurrencyStyleProvider()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
-
- $message = '->format() TYPE_INT32 formats inconsistently an integer if out of the 32 bit range.';
-
- return array(
- array($formatter, 1, '¤1.00'),
- array($formatter, 1.1, '¤1.00'),
- array($formatter, 2147483648, '(¤2,147,483,648.00)', $message),
- array($formatter, -2147483649, '¤2,147,483,647.00', $message)
- );
- }
-
- /**
- * The parse() method works differently with integer out of the 32 bit range. format() works fine.
- * @dataProvider formatTypeInt64Provider
- */
- public function testFormatTypeInt64($formatter, $value, $expected)
- {
- $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT64);
- $this->assertEquals($expected, $formattedValue);
- }
-
- public function formatTypeInt64Provider()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- return array(
- array($formatter, 1, '1'),
- array($formatter, 1.1, '1'),
- array($formatter, 2147483648, '2,147,483,648'),
- array($formatter, -2147483649, '-2,147,483,649'),
- );
- }
-
- /**
- * @dataProvider formatTypeInt64WithCurrencyStyleProvider
- */
- public function testFormatTypeInt64WithCurrencyStyle($formatter, $value, $expected)
- {
- $formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT64);
- $this->assertEquals($expected, $formattedValue);
- }
-
- public function formatTypeInt64WithCurrencyStyleProvider()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
-
- return array(
- array($formatter, 1, '¤1.00'),
- array($formatter, 1.1, '¤1.00'),
- array($formatter, 2147483648, '¤2,147,483,648.00'),
- array($formatter, -2147483649, '(¤2,147,483,649.00)')
- );
- }
-
- /**
- * @dataProvider formatTypeDoubleProvider
- */
- public function testFormatTypeDouble($formatter, $value, $expected)
- {
- $formattedValue = $formatter->format($value, NumberFormatter::TYPE_DOUBLE);
- $this->assertEquals($expected, $formattedValue);
- }
-
- public function formatTypeDoubleProvider()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- return array(
- array($formatter, 1, '1'),
- array($formatter, 1.1, '1.1'),
- );
- }
-
- /**
- * @dataProvider formatTypeDoubleWithCurrencyStyleProvider
- */
- public function testFormatTypeDoubleWithCurrencyStyle($formatter, $value, $expected)
- {
- $formattedValue = $formatter->format($value, NumberFormatter::TYPE_DOUBLE);
- $this->assertEquals($expected, $formattedValue);
- }
-
- public function formatTypeDoubleWithCurrencyStyleProvider()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
-
- return array(
- array($formatter, 1, '¤1.00'),
- array($formatter, 1.1, '¤1.10'),
- );
- }
-
- /**
- * @dataProvider formatTypeCurrencyProvider
- * @expectedException \PHPUnit_Framework_Error_Warning
- */
- public function testFormatTypeCurrency($formatter, $value)
- {
- $formatter->format($value, NumberFormatter::TYPE_CURRENCY);
- }
-
- /**
- * @dataProvider formatTypeCurrencyProvider
- */
- public function testFormatTypeCurrencyReturn($formatter, $value)
- {
- $this->assertFalse(@$formatter->format($value, NumberFormatter::TYPE_CURRENCY));
- }
-
- public function formatTypeCurrencyProvider()
- {
- $df = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $cf = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
-
- return array(
- array($df, 1),
- array($cf, 1),
- );
- }
-
- /**
- * @dataProvider formatFractionDigitsProvider
- */
- public function testFormatFractionDigits($value, $expected, $fractionDigits = null, $expectedFractionDigits = 1)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- if (null !== $fractionDigits) {
- $attributeRet = $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $fractionDigits);
- }
-
- $formattedValue = $formatter->format($value);
- $this->assertSame($expected, $formattedValue);
- $this->assertSame($expectedFractionDigits, $formatter->getAttribute(NumberFormatter::FRACTION_DIGITS));
-
- if (isset($attributeRet)) {
- $this->assertTrue($attributeRet);
- }
- }
-
- public function formatFractionDigitsProvider()
- {
- return array(
- array(1.123, '1.123', null, 0),
- array(1.123, '1', 0, 0),
- array(1.123, '1.1', 1, 1),
- array(1.123, '1.12', 2, 2),
- array(1.123, '1', -1, 0),
- array(1.123, '1', 'abc', 0)
- );
- }
-
- /**
- * @dataProvider formatGroupingUsedProvider
- */
- public function testFormatGroupingUsed($value, $expected, $groupingUsed = null, $expectedGroupingUsed = 1)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- if (null !== $groupingUsed) {
- $attributeRet = $formatter->setAttribute(NumberFormatter::GROUPING_USED, $groupingUsed);
- }
-
- $formattedValue = $formatter->format($value);
- $this->assertSame($expected, $formattedValue);
- $this->assertSame($expectedGroupingUsed, $formatter->getAttribute(NumberFormatter::GROUPING_USED));
-
- if (isset($attributeRet)) {
- $this->assertTrue($attributeRet);
- }
- }
-
- public function formatGroupingUsedProvider()
- {
- return array(
- array(1000, '1,000', null, 1),
- array(1000, '1000', 0, 0),
- array(1000, '1,000', 1, 1),
- array(1000, '1,000', 2, 1),
- array(1000, '1000', 'abc', 0),
- array(1000, '1,000', -1, 1),
- );
- }
-
- /**
- * @dataProvider formatRoundingModeRoundHalfUpProvider
- */
- public function testFormatRoundingModeHalfUp($value, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
-
- $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFUP);
- $this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFUP rounding mode.');
- }
-
- public function formatRoundingModeRoundHalfUpProvider()
- {
- // The commented value is differently rounded by intl's NumberFormatter in 32 and 64 bit architectures
- return array(
- array(1.121, '1.12'),
- array(1.123, '1.12'),
- // array(1.125, '1.13'),
- array(1.127, '1.13'),
- array(1.129, '1.13'),
- );
- }
-
- /**
- * @dataProvider formatRoundingModeRoundHalfDownProvider
- */
- public function testFormatRoundingModeHalfDown($value, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
-
- $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFDOWN);
- $this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFDOWN rounding mode.');
- }
-
- public function formatRoundingModeRoundHalfDownProvider()
- {
- return array(
- array(1.121, '1.12'),
- array(1.123, '1.12'),
- array(1.125, '1.12'),
- array(1.127, '1.13'),
- array(1.129, '1.13'),
- );
- }
-
- /**
- * @dataProvider formatRoundingModeRoundHalfEvenProvider
- */
- public function testFormatRoundingModeHalfEven($value, $expected)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
-
- $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFEVEN);
- $this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFEVEN rounding mode.');
- }
-
- public function formatRoundingModeRoundHalfEvenProvider()
- {
- return array(
- array(1.121, '1.12'),
- array(1.123, '1.12'),
- array(1.125, '1.12'),
- array(1.127, '1.13'),
- array(1.129, '1.13'),
- );
- }
-
- public function testGetLocale()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $this->assertEquals('en', $formatter->getLocale());
- }
-
- /**
- * @dataProvider parseProvider
- */
- public function testParse($value, $expected, $message = '')
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $parsedValue = $formatter->parse($value, NumberFormatter::TYPE_DOUBLE);
- $this->assertSame($expected, $parsedValue, $message);
-
- if ($expected === false) {
- $errorCode = IntlGlobals::U_PARSE_ERROR;
- $errorMessage = 'Number parsing failed: U_PARSE_ERROR';
- } else {
- $errorCode = IntlGlobals::U_ZERO_ERROR;
- $errorMessage = 'U_ZERO_ERROR';
- }
-
- $this->assertSame($errorMessage, $this->getIntlErrorMessage());
- $this->assertSame($errorCode, $this->getIntlErrorCode());
- $this->assertSame($errorCode !== 0, $this->isIntlFailure($this->getIntlErrorCode()));
- $this->assertSame($errorMessage, $formatter->getErrorMessage());
- $this->assertSame($errorCode, $formatter->getErrorCode());
- $this->assertSame($errorCode !== 0, $this->isIntlFailure($formatter->getErrorCode()));
- }
-
- public function parseProvider()
- {
- return array(
- array('prefix1', false, '->parse() does not parse a number with a string prefix.'),
- array('1suffix', (float) 1, '->parse() parses a number with a string suffix.'),
- );
- }
-
- /**
- * @expectedException \PHPUnit_Framework_Error_Warning
- */
- public function testParseTypeDefault()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->parse('1', NumberFormatter::TYPE_DEFAULT);
- }
-
- /**
- * @dataProvider parseTypeInt32Provider
- */
- public function testParseTypeInt32($value, $expected, $message = '')
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $parsedValue = $formatter->parse($value, NumberFormatter::TYPE_INT32);
- $this->assertSame($expected, $parsedValue);
- }
-
- public function parseTypeInt32Provider()
- {
- return array(
- array('1', 1),
- array('1.1', 1),
- array('2,147,483,647', 2147483647),
- array('-2,147,483,648', -2147483647 - 1),
- array('2,147,483,648', false, '->parse() TYPE_INT32 returns false when the number is greater than the integer positive range.'),
- array('-2,147,483,649', false, '->parse() TYPE_INT32 returns false when the number is greater than the integer negative range.')
- );
- }
-
- public function testParseTypeInt64With32BitIntegerInPhp32Bit()
- {
- IntlTestHelper::require32Bit($this);
-
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- $parsedValue = $formatter->parse('2,147,483,647', NumberFormatter::TYPE_INT64);
- $this->assertInternalType('integer', $parsedValue);
- $this->assertEquals(2147483647, $parsedValue);
-
- $parsedValue = $formatter->parse('-2,147,483,648', NumberFormatter::TYPE_INT64);
-
- // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
- // The negative PHP_INT_MAX was being converted to float
- if (
- (version_compare(PHP_VERSION, '5.4.0', '<') && version_compare(PHP_VERSION, '5.3.14', '>=')) ||
- version_compare(PHP_VERSION, '5.4.4', '>=')
- ) {
- $this->assertInternalType('int', $parsedValue);
- } else {
- $this->assertInternalType('float', $parsedValue);
- }
-
- $this->assertEquals(-2147483648, $parsedValue);
- }
-
- public function testParseTypeInt64With32BitIntegerInPhp64Bit()
- {
- IntlTestHelper::require64Bit($this);
-
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- $parsedValue = $formatter->parse('2,147,483,647', NumberFormatter::TYPE_INT64);
- $this->assertInternalType('integer', $parsedValue);
- $this->assertEquals(2147483647, $parsedValue);
-
- $parsedValue = $formatter->parse('-2,147,483,648', NumberFormatter::TYPE_INT64);
- $this->assertInternalType('integer', $parsedValue);
- $this->assertEquals(-2147483647 - 1, $parsedValue);
- }
-
- /**
- * If PHP is compiled in 32bit mode, the returned value for a 64bit integer are float numbers.
- */
- public function testParseTypeInt64With64BitIntegerInPhp32Bit()
- {
- IntlTestHelper::require32Bit($this);
-
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- // int 64 using only 32 bit range strangeness
- $parsedValue = $formatter->parse('2,147,483,648', NumberFormatter::TYPE_INT64);
- $this->assertInternalType('float', $parsedValue);
- $this->assertEquals(2147483648, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range.');
-
- $parsedValue = $formatter->parse('-2,147,483,649', NumberFormatter::TYPE_INT64);
- $this->assertInternalType('float', $parsedValue);
- $this->assertEquals(-2147483649, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range.');
- }
-
- /**
- * If PHP is compiled in 64bit mode, the returned value for a 64bit integer are 32bit integer numbers.
- */
- public function testParseTypeInt64With64BitIntegerInPhp64Bit()
- {
- IntlTestHelper::require64Bit($this);
-
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
-
- $parsedValue = $formatter->parse('2,147,483,648', NumberFormatter::TYPE_INT64);
- $this->assertInternalType('integer', $parsedValue);
-
- // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
- // A 32 bit integer was being generated instead of a 64 bit integer
- if (
- (version_compare(PHP_VERSION, '5.3.14', '<')) ||
- (version_compare(PHP_VERSION, '5.4.0', '>=') && version_compare(PHP_VERSION, '5.4.4', '<'))
- ) {
- $this->assertEquals(-2147483648, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range (PHP < 5.3.14 and PHP < 5.4.4).');
- } else {
- $this->assertEquals(2147483648, $parsedValue, '->parse() TYPE_INT64 uses true 64 bit integers (PHP >= 5.3.14 and PHP >= 5.4.4).');
- }
-
- $parsedValue = $formatter->parse('-2,147,483,649', NumberFormatter::TYPE_INT64);
- $this->assertInternalType('integer', $parsedValue);
-
- // Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
- // A 32 bit integer was being generated instead of a 64 bit integer
- if (
- (version_compare(PHP_VERSION, '5.3.14', '<')) ||
- (version_compare(PHP_VERSION, '5.4.0', '>=') && version_compare(PHP_VERSION, '5.4.4', '<'))
- ) {
- $this->assertEquals(2147483647, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range (PHP < 5.3.14 and PHP < 5.4.4).');
- } else {
- $this->assertEquals(-2147483649, $parsedValue, '->parse() TYPE_INT64 uses true 64 bit integers (PHP >= 5.3.14 and PHP >= 5.4.4).');
- }
- }
-
- /**
- * @dataProvider parseTypeDoubleProvider
- */
- public function testParseTypeDouble($value, $expectedValue)
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $parsedValue = $formatter->parse($value, NumberFormatter::TYPE_DOUBLE);
- $this->assertSame($expectedValue, $parsedValue);
- }
-
- public function parseTypeDoubleProvider()
- {
- return array(
- array('1', (float) 1),
- array('1.1', 1.1),
- array('9,223,372,036,854,775,808', 9223372036854775808),
- array('-9,223,372,036,854,775,809', -9223372036854775809),
- );
- }
-
- /**
- * @expectedException \PHPUnit_Framework_Error_Warning
- */
- public function testParseTypeCurrency()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->parse('1', NumberFormatter::TYPE_CURRENCY);
- }
-
- public function testParseWithNullPositionValue()
- {
- $position = null;
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->parse('123', NumberFormatter::TYPE_INT32, $position);
- $this->assertNull($position);
- }
-
- public function testParseWithNotNullPositionValue()
- {
- $position = 1;
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->parse('123', NumberFormatter::TYPE_DOUBLE, $position);
- $this->assertEquals(3, $position);
- }
-
- /**
- * @param string $locale
- * @param null $style
- * @param null $pattern
- *
- * @return \NumberFormatter
- */
- abstract protected function getNumberFormatter($locale = 'en', $style = null, $pattern = null);
-
- /**
- * @return string
- */
- abstract protected function getIntlErrorMessage();
-
- /**
- * @return integer
- */
- abstract protected function getIntlErrorCode();
-
- /**
- * @param integer $errorCode
- *
- * @return Boolean
- */
- abstract protected function isIntlFailure($errorCode);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\NumberFormatter;
-
-use Symfony\Component\Intl\Globals\IntlGlobals;
-use Symfony\Component\Intl\NumberFormatter\NumberFormatter;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * Note that there are some values written like -2147483647 - 1. This is the lower 32bit int max and is a known
- * behavior of PHP.
- */
-class NumberFormatterTest extends AbstractNumberFormatterTest
-{
- protected function setUp()
- {
- IntlTestHelper::requireIntl($this);
-
- parent::setUp();
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testConstructorWithUnsupportedLocale()
- {
- new NumberFormatter('pt_BR');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testConstructorWithUnsupportedStyle()
- {
- new NumberFormatter('en', NumberFormatter::PATTERN_DECIMAL);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException
- */
- public function testConstructorWithPatternDifferentThanNull()
- {
- new NumberFormatter('en', NumberFormatter::DECIMAL, '');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testSetAttributeWithUnsupportedAttribute()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setAttribute(NumberFormatter::LENIENT_PARSE, null);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testSetAttributeInvalidRoundingMode()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, null);
- }
-
- public function testCreate()
- {
- $this->assertInstanceOf(
- '\Symfony\Component\Intl\NumberFormatter\NumberFormatter',
- NumberFormatter::create('en', NumberFormatter::DECIMAL)
- );
- }
-
- /**
- * @expectedException \RuntimeException
- */
- public function testFormatWithCurrencyStyle()
- {
- parent::testFormatWithCurrencyStyle();
- }
-
- /**
- * @dataProvider formatTypeInt32Provider
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testFormatTypeInt32($formatter, $value, $expected, $message = '')
- {
- parent::testFormatTypeInt32($formatter, $value, $expected, $message);
- }
-
- /**
- * @dataProvider formatTypeInt32WithCurrencyStyleProvider
- * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
- */
- public function testFormatTypeInt32WithCurrencyStyle($formatter, $value, $expected, $message = '')
- {
- parent::testFormatTypeInt32WithCurrencyStyle($formatter, $value, $expected, $message);
- }
-
- /**
- * @dataProvider formatTypeInt64Provider
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testFormatTypeInt64($formatter, $value, $expected)
- {
- parent::testFormatTypeInt64($formatter, $value, $expected);
- }
-
- /**
- * @dataProvider formatTypeInt64WithCurrencyStyleProvider
- * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
- */
- public function testFormatTypeInt64WithCurrencyStyle($formatter, $value, $expected)
- {
- parent::testFormatTypeInt64WithCurrencyStyle($formatter, $value, $expected);
- }
-
- /**
- * @dataProvider formatTypeDoubleProvider
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
- */
- public function testFormatTypeDouble($formatter, $value, $expected)
- {
- parent::testFormatTypeDouble($formatter, $value, $expected);
- }
-
- /**
- * @dataProvider formatTypeDoubleWithCurrencyStyleProvider
- * @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
- */
- public function testFormatTypeDoubleWithCurrencyStyle($formatter, $value, $expected)
- {
- parent::testFormatTypeDoubleWithCurrencyStyle($formatter, $value, $expected);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetPattern()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->getPattern();
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetSymbol()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->getSymbol(null);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testGetTextAttribute()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->getTextAttribute(null);
- }
-
- public function testGetErrorCode()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $this->assertEquals(IntlGlobals::U_ZERO_ERROR, $formatter->getErrorCode());
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testParseCurrency()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->parseCurrency(null, $currency);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException
- */
- public function testParseWithNotNullPositionValue()
- {
- parent::testParseWithNotNullPositionValue();
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testSetPattern()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setPattern(null);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testSetSymbol()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setSymbol(null, null);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
- */
- public function testSetTextAttribute()
- {
- $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
- $formatter->setTextAttribute(null, null);
- }
-
- protected function getNumberFormatter($locale = 'en', $style = null, $pattern = null)
- {
- return new NumberFormatter($locale, $style, $pattern);
- }
-
- protected function getIntlErrorMessage()
- {
- return IntlGlobals::getErrorMessage();
- }
-
- protected function getIntlErrorCode()
- {
- return IntlGlobals::getErrorCode();
- }
-
- protected function isIntlFailure($errorCode)
- {
- return IntlGlobals::isFailure($errorCode);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\NumberFormatter\Verification;
-
-use Symfony\Component\Intl\Tests\NumberFormatter\AbstractNumberFormatterTest;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * Note that there are some values written like -2147483647 - 1. This is the lower 32bit int max and is a known
- * behavior of PHP.
- */
-class NumberFormatterTest extends AbstractNumberFormatterTest
-{
- protected function setUp()
- {
- IntlTestHelper::requireFullIntl($this);
-
- parent::setUp();
- }
-
- public function testCreate()
- {
- $this->assertInstanceOf('\NumberFormatter', \NumberFormatter::create('en', \NumberFormatter::DECIMAL));
- }
-
- protected function getNumberFormatter($locale = 'en', $style = null, $pattern = null)
- {
- return new \NumberFormatter($locale, $style, $pattern);
- }
-
- protected function getIntlErrorMessage()
- {
- return intl_get_error_message();
- }
-
- protected function getIntlErrorCode()
- {
- return intl_get_error_code();
- }
-
- protected function isIntlFailure($errorCode)
- {
- return intl_is_failure($errorCode);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class AbstractBundleTest extends \PHPUnit_Framework_TestCase
-{
- const RES_DIR = '/base/dirName';
-
- /**
- * @var \Symfony\Component\Intl\ResourceBundle\AbstractBundle
- */
- private $bundle;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $reader;
-
- protected function setUp()
- {
- $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
- $this->bundle = $this->getMockForAbstractClass(
- 'Symfony\Component\Intl\ResourceBundle\AbstractBundle',
- array(self::RES_DIR, $this->reader)
- );
-
- $this->bundle->expects($this->any())
- ->method('getDirectoryName')
- ->will($this->returnValue('dirName'));
- }
-
- public function testGetLocales()
- {
- $locales = array('de', 'en', 'fr');
-
- $this->reader->expects($this->once())
- ->method('getLocales')
- ->with(self::RES_DIR)
- ->will($this->returnValue($locales));
-
- $this->assertSame($locales, $this->bundle->getLocales());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle;
-
-use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class CurrencyBundleTest extends \PHPUnit_Framework_TestCase
-{
- const RES_DIR = '/base/curr';
-
- /**
- * @var CurrencyBundle
- */
- private $bundle;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $reader;
-
- protected function setUp()
- {
- $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
- $this->bundle = new CurrencyBundle(self::RES_DIR, $this->reader);
- }
-
- public function testGetCurrencySymbol()
- {
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 1))
- ->will($this->returnValue('€'));
-
- $this->assertSame('€', $this->bundle->getCurrencySymbol('EUR', 'en'));
- }
-
- public function testGetCurrencyName()
- {
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 0))
- ->will($this->returnValue('Euro'));
-
- $this->assertSame('Euro', $this->bundle->getCurrencyName('EUR', 'en'));
- }
-
- public function testGetCurrencyNames()
- {
- $sortedCurrencies = array(
- 'USD' => array(0 => 'Dollar'),
- 'EUR' => array(0 => 'Euro'),
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Currencies'))
- ->will($this->returnValue($sortedCurrencies));
-
- $sortedNames = array(
- 'USD' => 'Dollar',
- 'EUR' => 'Euro',
- );
-
- $this->assertSame($sortedNames, $this->bundle->getCurrencyNames('en'));
- }
-
- public function testGetFractionDigits()
- {
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 2))
- ->will($this->returnValue(123));
-
- $this->assertSame(123, $this->bundle->getFractionDigits('EUR'));
- }
-
- public function testGetRoundingIncrement()
- {
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Currencies', 'EUR', 3))
- ->will($this->returnValue(123));
-
- $this->assertSame(123, $this->bundle->getRoundingIncrement('EUR'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle;
-
-use Symfony\Component\Intl\ResourceBundle\LanguageBundle;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class LanguageBundleTest extends \PHPUnit_Framework_TestCase
-{
- const RES_DIR = '/base/lang';
-
- /**
- * @var LanguageBundle
- */
- private $bundle;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $reader;
-
- protected function setUp()
- {
- $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
- $this->bundle = new LanguageBundle(self::RES_DIR, $this->reader);
- }
-
- public function testGetLanguageName()
- {
- $languages = array(
- 'de' => 'German',
- 'en' => 'English',
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Languages'))
- ->will($this->returnValue($languages));
-
- $this->assertSame('German', $this->bundle->getLanguageName('de', null, 'en'));
- }
-
- public function testGetLanguageNameWithRegion()
- {
- $languages = array(
- 'de' => 'German',
- 'en' => 'English',
- 'en_GB' => 'British English',
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Languages'))
- ->will($this->returnValue($languages));
-
- $this->assertSame('British English', $this->bundle->getLanguageName('en', 'GB', 'en'));
- }
-
- public function testGetLanguageNameWithUntranslatedRegion()
- {
- $languages = array(
- 'de' => 'German',
- 'en' => 'English',
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Languages'))
- ->will($this->returnValue($languages));
-
- $this->assertSame('English', $this->bundle->getLanguageName('en', 'US', 'en'));
- }
-
- public function testGetLanguageNames()
- {
- $sortedLanguages = array(
- 'en' => 'English',
- 'de' => 'German',
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Languages'))
- ->will($this->returnValue($sortedLanguages));
-
- $this->assertSame($sortedLanguages, $this->bundle->getLanguageNames('en'));
- }
-
- public function testGetScriptName()
- {
- $data = array(
- 'Languages' => array(
- 'de' => 'German',
- 'en' => 'English',
- ),
- 'Scripts' => array(
- 'Latn' => 'latin',
- 'Cyrl' => 'cyrillique',
- ),
- );
-
- $this->reader->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- $this->assertSame('latin', $this->bundle->getScriptName('Latn', null, 'en'));
- }
-
- public function testGetScriptNameIncludedInLanguage()
- {
- $data = array(
- 'Languages' => array(
- 'de' => 'German',
- 'en' => 'English',
- 'zh_Hans' => 'Simplified Chinese',
- ),
- 'Scripts' => array(
- 'Latn' => 'latin',
- 'Cyrl' => 'cyrillique',
- ),
- );
-
- $this->reader->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- // Null because the script is included in the language anyway
- $this->assertNull($this->bundle->getScriptName('Hans', 'zh', 'en'));
- }
-
- public function testGetScriptNameIncludedInLanguageInBraces()
- {
- $data = array(
- 'Languages' => array(
- 'de' => 'German',
- 'en' => 'English',
- 'zh_Hans' => 'Chinese (simplified)',
- ),
- 'Scripts' => array(
- 'Latn' => 'latin',
- 'Cyrl' => 'cyrillique',
- ),
- );
-
- $this->reader->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- $this->assertSame('simplified', $this->bundle->getScriptName('Hans', 'zh', 'en'));
- }
-
- public function testGetScriptNameNoScriptsBlock()
- {
- $data = array(
- 'Languages' => array(
- 'de' => 'German',
- 'en' => 'English',
- ),
- );
-
- $this->reader->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- $this->assertNull($this->bundle->getScriptName('Latn', null, 'en'));
- }
-
- public function testGetScriptNames()
- {
- $sortedScripts = array(
- 'Cyrl' => 'cyrillique',
- 'Latn' => 'latin',
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Scripts'))
- ->will($this->returnValue($sortedScripts));
-
- $this->assertSame($sortedScripts, $this->bundle->getScriptNames('en'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle;
-
-use Symfony\Component\Intl\ResourceBundle\LocaleBundle;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class LocaleBundleTest extends \PHPUnit_Framework_TestCase
-{
- const RES_DIR = '/base/locales';
-
- /**
- * @var LocaleBundle
- */
- private $bundle;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $reader;
-
- protected function setUp()
- {
- $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
- $this->bundle = new LocaleBundle(self::RES_DIR, $this->reader);
- }
-
- public function testGetLocaleName()
- {
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Locales', 'de_AT'))
- ->will($this->returnValue('German (Austria)'));
-
- $this->assertSame('German (Austria)', $this->bundle->getLocaleName('de_AT', 'en'));
- }
-
- public function testGetLocaleNames()
- {
- $sortedLocales = array(
- 'en_IE' => 'English (Ireland)',
- 'en_GB' => 'English (United Kingdom)',
- 'en_US' => 'English (United States)',
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Locales'))
- ->will($this->returnValue($sortedLocales));
-
- $this->assertSame($sortedLocales, $this->bundle->getLocaleNames('en'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
-
-use Symfony\Component\Filesystem\Filesystem;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class AbstractBundleReaderTest extends \PHPUnit_Framework_TestCase
-{
- private $directory;
-
- /**
- * @var Filesystem
- */
- private $filesystem;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $reader;
-
- protected function setUp()
- {
- $this->directory = sys_get_temp_dir() . '/AbstractBundleReaderTest/' . rand(1000, 9999);
- $this->filesystem = new Filesystem();
- $this->reader = $this->getMockForAbstractClass('Symfony\Component\Intl\ResourceBundle\Reader\AbstractBundleReader');
-
- $this->filesystem->mkdir($this->directory);
- }
-
- protected function tearDown()
- {
- $this->filesystem->remove($this->directory);
- }
-
- public function testGetLocales()
- {
- $this->filesystem->touch($this->directory . '/en.foo');
- $this->filesystem->touch($this->directory . '/de.foo');
- $this->filesystem->touch($this->directory . '/fr.foo');
- $this->filesystem->touch($this->directory . '/bo.txt');
- $this->filesystem->touch($this->directory . '/gu.bin');
- $this->filesystem->touch($this->directory . '/s.lol');
-
- $this->reader->expects($this->any())
- ->method('getFileExtension')
- ->will($this->returnValue('foo'));
-
- $sortedLocales = array('de', 'en', 'fr');
-
- $this->assertSame($sortedLocales, $this->reader->getLocales($this->directory));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
-
-use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader;
-use Symfony\Component\Intl\Util\IntlTestHelper;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class BinaryBundleReaderTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var BinaryBundleReader
- */
- private $reader;
-
- protected function setUp()
- {
- IntlTestHelper::requireFullIntl($this);
-
- $this->reader = new BinaryBundleReader();
- }
-
- public function testReadReturnsArrayAccess()
- {
- $data = $this->reader->read(__DIR__ . '/Fixtures', 'en');
-
- $this->assertInstanceOf('\ArrayAccess', $data);
- $this->assertSame('Bar', $data['Foo']);
- $this->assertFalse(isset($data['ExistsNot']));
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
- */
- public function testReadFailsIfNonExistingLocale()
- {
- $this->reader->read(__DIR__ . '/Fixtures', 'foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
- */
- public function testReadFailsIfNonExistingDirectory()
- {
- $this->reader->read(__DIR__ . '/foo', 'en');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return array(
- 'Foo' => 'Bar',
-);
+++ /dev/null
-en{
- Foo{"Bar"}
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
-
-use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PhpBundleReaderTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var PhpBundleReader
- */
- private $reader;
-
- protected function setUp()
- {
- $this->reader = new PhpBundleReader();
- }
-
- public function testReadReturnsArray()
- {
- $data = $this->reader->read(__DIR__ . '/Fixtures', 'en');
-
- $this->assertTrue(is_array($data));
- $this->assertSame('Bar', $data['Foo']);
- $this->assertFalse(isset($data['ExistsNot']));
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\InvalidArgumentException
- */
- public function testReadFailsIfLocaleOtherThanEn()
- {
- $this->reader->read(__DIR__ . '/Fixtures', 'foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
- */
- public function testReadFailsIfNonExistingDirectory()
- {
- $this->reader->read(__DIR__ . '/foo', 'en');
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\RuntimeException
- */
- public function testReadFailsIfNotAFile()
- {
- $this->reader->read(__DIR__ . '/Fixtures/NotAFile', 'en');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle\Reader;
-
-use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class StructuredBundleReaderTest extends \PHPUnit_Framework_TestCase
-{
- const RES_DIR = '/res/dir';
-
- /**
- * @var StructuredBundleReader
- */
- private $reader;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $readerImpl;
-
- protected function setUp()
- {
- $this->readerImpl = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
- $this->reader = new StructuredBundleReader($this->readerImpl);
- }
-
- public function testGetLocales()
- {
- $locales = array('en', 'de', 'fr');
-
- $this->readerImpl->expects($this->once())
- ->method('getLocales')
- ->with(self::RES_DIR)
- ->will($this->returnValue($locales));
-
- $this->assertSame($locales, $this->reader->getLocales(self::RES_DIR));
- }
-
- public function testRead()
- {
- $data = array('foo', 'bar');
-
- $this->readerImpl->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- $this->assertSame($data, $this->reader->read(self::RES_DIR, 'en'));
- }
-
- public function testReadEntryNoParams()
- {
- $data = array('foo', 'bar');
-
- $this->readerImpl->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- $this->assertSame($data, $this->reader->readEntry(self::RES_DIR, 'en', array()));
- }
-
- public function testReadEntryWithParam()
- {
- $data = array('Foo' => array('Bar' => 'Baz'));
-
- $this->readerImpl->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- $this->assertSame('Baz', $this->reader->readEntry(self::RES_DIR, 'en', array('Foo', 'Bar')));
- }
-
- public function testReadEntryWithUnresolvablePath()
- {
- $data = array('Foo' => 'Baz');
-
- $this->readerImpl->expects($this->once())
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($data));
-
- $this->assertNull($this->reader->readEntry(self::RES_DIR, 'en', array('Foo', 'Bar')));
- }
-
- public function readMergedEntryProvider()
- {
- return array(
- array('foo', null, 'foo'),
- array(null, 'foo', 'foo'),
- array(array('foo', 'bar'), null, array('foo', 'bar')),
- array(array('foo', 'bar'), array(), array('foo', 'bar')),
- array(null, array('baz'), array('baz')),
- array(array(), array('baz'), array('baz')),
- array(array('foo', 'bar'), array('baz'), array('baz', 'foo', 'bar')),
- );
- }
-
- /**
- * @dataProvider readMergedEntryProvider
- */
- public function testReadMergedEntryNoParams($childData, $parentData, $result)
- {
- $this->readerImpl->expects($this->at(0))
- ->method('read')
- ->with(self::RES_DIR, 'en_GB')
- ->will($this->returnValue($childData));
-
- if (null === $childData || is_array($childData)) {
- $this->readerImpl->expects($this->at(1))
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue($parentData));
- }
-
- $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array(), true));
- }
-
- /**
- * @dataProvider readMergedEntryProvider
- */
- public function testReadMergedEntryWithParams($childData, $parentData, $result)
- {
- $this->readerImpl->expects($this->at(0))
- ->method('read')
- ->with(self::RES_DIR, 'en_GB')
- ->will($this->returnValue(array('Foo' => array('Bar' => $childData))));
-
- if (null === $childData || is_array($childData)) {
- $this->readerImpl->expects($this->at(1))
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue(array('Foo' => array('Bar' => $parentData))));
- }
-
- $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
- }
-
- public function testReadMergedEntryWithUnresolvablePath()
- {
- $this->readerImpl->expects($this->at(0))
- ->method('read')
- ->with(self::RES_DIR, 'en_GB')
- ->will($this->returnValue(array('Foo' => 'Baz')));
-
- $this->readerImpl->expects($this->at(1))
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue(array('Foo' => 'Bar')));
-
- $this->assertNull($this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
- }
-
- public function testReadMergedEntryWithUnresolvablePathInParent()
- {
- $this->readerImpl->expects($this->at(0))
- ->method('read')
- ->with(self::RES_DIR, 'en_GB')
- ->will($this->returnValue(array('Foo' => array('Bar' => array('three')))));
-
- $this->readerImpl->expects($this->at(1))
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue(array('Foo' => 'Bar')));
-
- $result = array('three');
-
- $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
- }
-
- public function testReadMergedEntryWithUnresolvablePathInChild()
- {
- $this->readerImpl->expects($this->at(0))
- ->method('read')
- ->with(self::RES_DIR, 'en_GB')
- ->will($this->returnValue(array('Foo' => 'Baz')));
-
- $this->readerImpl->expects($this->at(1))
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue(array('Foo' => array('Bar' => array('one', 'two')))));
-
- $result = array('one', 'two');
-
- $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
- }
-
- /**
- * @dataProvider readMergedEntryProvider
- */
- public function testReadMergedEntryWithTraversables($childData, $parentData, $result)
- {
- $parentData = is_array($parentData) ? new \ArrayObject($parentData) : $parentData;
- $childData = is_array($childData) ? new \ArrayObject($childData) : $childData;
-
- $this->readerImpl->expects($this->at(0))
- ->method('read')
- ->with(self::RES_DIR, 'en_GB')
- ->will($this->returnValue(array('Foo' => array('Bar' => $childData))));
-
- if (null === $childData || $childData instanceof \ArrayObject) {
- $this->readerImpl->expects($this->at(1))
- ->method('read')
- ->with(self::RES_DIR, 'en')
- ->will($this->returnValue(array('Foo' => array('Bar' => $parentData))));
- }
-
- $this->assertSame($result, $this->reader->readEntry(self::RES_DIR, 'en_GB', array('Foo', 'Bar'), true));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle;
-
-use Symfony\Component\Intl\ResourceBundle\RegionBundle;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RegionBundleTest extends \PHPUnit_Framework_TestCase
-{
- const RES_DIR = '/base/region';
-
- /**
- * @var RegionBundle
- */
- private $bundle;
-
- /**
- * @var \PHPUnit_Framework_MockObject_MockObject
- */
- private $reader;
-
- protected function setUp()
- {
- $this->reader = $this->getMock('Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface');
- $this->bundle = new RegionBundle(self::RES_DIR, $this->reader);
- }
-
- public function testGetCountryName()
- {
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Countries', 'AT'))
- ->will($this->returnValue('Austria'));
-
- $this->assertSame('Austria', $this->bundle->getCountryName('AT', 'en'));
- }
-
- public function testGetCountryNames()
- {
- $sortedCountries = array(
- 'AT' => 'Austria',
- 'DE' => 'Germany',
- );
-
- $this->reader->expects($this->once())
- ->method('readEntry')
- ->with(self::RES_DIR, 'en', array('Countries'))
- ->will($this->returnValue($sortedCountries));
-
- $this->assertSame($sortedCountries, $this->bundle->getCountryNames('en'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle\Util;
-
-use Symfony\Component\Intl\ResourceBundle\Util\RingBuffer;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RingBufferTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var RingBuffer
- */
- private $buffer;
-
- protected function setUp()
- {
- $this->buffer = new RingBuffer(2);
- }
-
- public function testWriteWithinBuffer()
- {
- $this->buffer[0] = 'foo';
- $this->buffer['bar'] = 'baz';
-
- $this->assertTrue(isset($this->buffer[0]));
- $this->assertTrue(isset($this->buffer['bar']));
- $this->assertSame('foo', $this->buffer[0]);
- $this->assertSame('baz', $this->buffer['bar']);
- }
-
- public function testWritePastBuffer()
- {
- $this->buffer[0] = 'foo';
- $this->buffer['bar'] = 'baz';
- $this->buffer[2] = 'bam';
-
- $this->assertTrue(isset($this->buffer['bar']));
- $this->assertTrue(isset($this->buffer[2]));
- $this->assertSame('baz', $this->buffer['bar']);
- $this->assertSame('bam', $this->buffer[2]);
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\OutOfBoundsException
- */
- public function testReadNonExistingFails()
- {
- $this->buffer['foo'];
- }
-
- public function testQueryNonExisting()
- {
- $this->assertFalse(isset($this->buffer['foo']));
- }
-
- public function testUnsetNonExistingSucceeds()
- {
- unset($this->buffer['foo']);
-
- $this->assertFalse(isset($this->buffer['foo']));
- }
-
- /**
- * @expectedException \Symfony\Component\Intl\Exception\OutOfBoundsException
- */
- public function testReadOverwrittenFails()
- {
- $this->buffer[0] = 'foo';
- $this->buffer['bar'] = 'baz';
- $this->buffer[2] = 'bam';
-
- $this->buffer[0];
- }
-
- public function testQueryOverwritten()
- {
- $this->assertFalse(isset($this->buffer[0]));
- }
-
- public function testUnsetOverwrittenSucceeds()
- {
- $this->buffer[0] = 'foo';
- $this->buffer['bar'] = 'baz';
- $this->buffer[2] = 'bam';
-
- unset($this->buffer[0]);
-
- $this->assertFalse(isset($this->buffer[0]));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return array(
- 'Entry1' => array(
- 'Array' => array(
- 0 => 'foo',
- 1 => 'bar',
- ),
- 'Integer' => 5,
- 'Boolean' => false,
- 'Float' => 1.23,
- ),
- 'Entry2' => 'String',
-);
+++ /dev/null
-en{
- Entry1{
- Array{
- "foo",
- "bar",
- {
- Key{"value"}
- },
- }
- Integer:int{5}
- IntVector:intvector{
- 0,
- 1,
- 2,
- 3,
- }
- FalseBoolean{"false"}
- TrueBoolean{"true"}
- Null{""}
- Float{"1.23"}
- }
- Entry2{"String"}
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle\Writer;
-
-use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\Intl\ResourceBundle\Writer\PhpBundleWriter;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PhpBundleWriterTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var PhpBundleWriter
- */
- private $writer;
-
- private $directory;
-
- /**
- * @var Filesystem
- */
- private $filesystem;
-
- protected function setUp()
- {
- $this->writer = new PhpBundleWriter();
- $this->directory = sys_get_temp_dir() . '/PhpBundleWriterTest/' . rand(1000, 9999);
- $this->filesystem = new Filesystem();
-
- $this->filesystem->mkdir($this->directory);
- }
-
- protected function tearDown()
- {
- $this->filesystem->remove($this->directory);
- }
-
- public function testWrite()
- {
- $this->writer->write($this->directory, 'en', array(
- 'Entry1' => array(
- 'Array' => array('foo', 'bar'),
- 'Integer' => 5,
- 'Boolean' => false,
- 'Float' => 1.23,
- ),
- 'Entry2' => 'String',
- ));
-
- $this->assertFileEquals(__DIR__ . '/Fixtures/en.php', $this->directory . '/en.php');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\ResourceBundle\Writer;
-
-use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\Intl\ResourceBundle\Writer\TextBundleWriter;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
- */
-class TextBundleWriterTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var TextBundleWriter
- */
- private $writer;
-
- private $directory;
-
- /**
- * @var Filesystem
- */
- private $filesystem;
-
- protected function setUp()
- {
- $this->writer = new TextBundleWriter();
- $this->directory = sys_get_temp_dir() . '/TextBundleWriterTest/' . rand(1000, 9999);
- $this->filesystem = new Filesystem();
-
- $this->filesystem->mkdir($this->directory);
- }
-
- protected function tearDown()
- {
- $this->filesystem->remove($this->directory);
- }
-
- public function testWrite()
- {
- $this->writer->write($this->directory, 'en', array(
- 'Entry1' => array(
- 'Array' => array('foo', 'bar', array('Key' => 'value')),
- 'Integer' => 5,
- 'IntVector' => array(0, 1, 2, 3),
- 'FalseBoolean' => false,
- 'TrueBoolean' => true,
- 'Null' => null,
- 'Float' => 1.23,
- ),
- 'Entry2' => 'String',
- ));
-
- $this->assertFileEquals(__DIR__ . '/Fixtures/en.txt', $this->directory . '/en.txt');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Util;
-
-use Symfony\Component\Intl\Util\IcuVersion;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuVersionTest extends \PHPUnit_Framework_TestCase
-{
- public function normalizeProvider()
- {
- return array(
- array(null, '1', '10'),
- array(null, '1.2', '12'),
- array(null, '1.2.3', '12.3'),
- array(null, '1.2.3.4', '12.3.4'),
- array(1, '1', '10'),
- array(1, '1.2', '12'),
- array(1, '1.2.3', '12'),
- array(1, '1.2.3.4', '12'),
- array(2, '1', '10'),
- array(2, '1.2', '12'),
- array(2, '1.2.3', '12.3'),
- array(2, '1.2.3.4', '12.3'),
- array(3, '1', '10'),
- array(3, '1.2', '12'),
- array(3, '1.2.3', '12.3'),
- array(3, '1.2.3.4', '12.3.4'),
- );
- }
-
- /**
- * @dataProvider normalizeProvider
- */
- public function testNormalize($precision, $version, $result)
- {
- $this->assertSame($result, IcuVersion::normalize($version, $precision));
- }
-
- public function compareProvider()
- {
- return array(
- array(null, '1', '==', '1', true),
- array(null, '1.0', '==', '1.1', false),
- array(null, '1.0.0', '==', '1.0.1', false),
- array(null, '1.0.0.0', '==', '1.0.0.1', false),
- array(null, '1.0.0.0.0', '==', '1.0.0.0.1', false),
-
- array(null, '1', '==', '10', true),
- array(null, '1.0', '==', '11', false),
- array(null, '1.0.0', '==', '10.1', false),
- array(null, '1.0.0.0', '==', '10.0.1', false),
- array(null, '1.0.0.0.0', '==', '10.0.0.1', false),
-
- array(1, '1', '==', '1', true),
- array(1, '1.0', '==', '1.1', false),
- array(1, '1.0.0', '==', '1.0.1', true),
- array(1, '1.0.0.0', '==', '1.0.0.1', true),
- array(1, '1.0.0.0.0', '==', '1.0.0.0.1', true),
-
- array(1, '1', '==', '10', true),
- array(1, '1.0', '==', '11', false),
- array(1, '1.0.0', '==', '10.1', true),
- array(1, '1.0.0.0', '==', '10.0.1', true),
- array(1, '1.0.0.0.0', '==', '10.0.0.1', true),
-
- array(2, '1', '==', '1', true),
- array(2, '1.0', '==', '1.1', false),
- array(2, '1.0.0', '==', '1.0.1', false),
- array(2, '1.0.0.0', '==', '1.0.0.1', true),
- array(2, '1.0.0.0.0', '==', '1.0.0.0.1', true),
-
- array(2, '1', '==', '10', true),
- array(2, '1.0', '==', '11', false),
- array(2, '1.0.0', '==', '10.1', false),
- array(2, '1.0.0.0', '==', '10.0.1', true),
- array(2, '1.0.0.0.0', '==', '10.0.0.1', true),
-
- array(3, '1', '==', '1', true),
- array(3, '1.0', '==', '1.1', false),
- array(3, '1.0.0', '==', '1.0.1', false),
- array(3, '1.0.0.0', '==', '1.0.0.1', false),
- array(3, '1.0.0.0.0', '==', '1.0.0.0.1', true),
-
- array(3, '1', '==', '10', true),
- array(3, '1.0', '==', '11', false),
- array(3, '1.0.0', '==', '10.1', false),
- array(3, '1.0.0.0', '==', '10.0.1', false),
- array(3, '1.0.0.0.0', '==', '10.0.0.1', true),
- );
- }
-
- /**
- * @dataProvider compareProvider
- */
- public function testCompare($precision, $version1, $operator, $version2, $result)
- {
- $this->assertSame($result, IcuVersion::compare($version1, $version2, $operator, $precision));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Tests\Util;
-
-use Symfony\Component\Intl\Util\Version;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class VersionTest extends \PHPUnit_Framework_TestCase
-{
- public function normalizeProvider()
- {
- return array(
- array(null, '1', '1'),
- array(null, '1.2', '1.2'),
- array(null, '1.2.3', '1.2.3'),
- array(null, '1.2.3.4', '1.2.3.4'),
- array(1, '1', '1'),
- array(1, '1.2', '1'),
- array(1, '1.2.3', '1'),
- array(1, '1.2.3.4', '1'),
- array(2, '1', '1'),
- array(2, '1.2', '1.2'),
- array(2, '1.2.3', '1.2'),
- array(2, '1.2.3.4', '1.2'),
- array(3, '1', '1'),
- array(3, '1.2', '1.2'),
- array(3, '1.2.3', '1.2.3'),
- array(3, '1.2.3.4', '1.2.3'),
- array(4, '1', '1'),
- array(4, '1.2', '1.2'),
- array(4, '1.2.3', '1.2.3'),
- array(4, '1.2.3.4', '1.2.3.4'),
- );
- }
-
- /**
- * @dataProvider normalizeProvider
- */
- public function testNormalize($precision, $version, $result)
- {
- $this->assertSame($result, Version::normalize($version, $precision));
- }
-
- public function compareProvider()
- {
- return array(
- array(null, '1', '==', '1', true),
- array(null, '1.0', '==', '1.1', false),
- array(null, '1.0.0', '==', '1.0.1', false),
- array(null, '1.0.0.0', '==', '1.0.0.1', false),
-
- array(1, '1', '==', '1', true),
- array(1, '1.0', '==', '1.1', true),
- array(1, '1.0.0', '==', '1.0.1', true),
- array(1, '1.0.0.0', '==', '1.0.0.1', true),
-
- array(2, '1', '==', '1', true),
- array(2, '1.0', '==', '1.1', false),
- array(2, '1.0.0', '==', '1.0.1', true),
- array(2, '1.0.0.0', '==', '1.0.0.1', true),
-
- array(3, '1', '==', '1', true),
- array(3, '1.0', '==', '1.1', false),
- array(3, '1.0.0', '==', '1.0.1', false),
- array(3, '1.0.0.0', '==', '1.0.0.1', true),
- );
- }
-
- /**
- * @dataProvider compareProvider
- */
- public function testCompare($precision, $version1, $operator, $version2, $result)
- {
- $this->assertSame($result, Version::compare($version1, $version2, $operator, $precision));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Util;
-
-/**
- * Facilitates the comparison of ICU version strings.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IcuVersion
-{
- /**
- * Compares two ICU versions with an operator.
- *
- * This method is identical to {@link version_compare()}, except that you
- * can pass the number of regarded version components in the last argument
- * $precision.
- *
- * Also, a single digit release version and a single digit major version
- * are contracted to a two digit release version. If no major version
- * is given, it is substituted by zero.
- *
- * Examples:
- *
- * IcuVersion::compare('1.2.3', '1.2.4', '==')
- * // => false
- *
- * IcuVersion::compare('1.2.3', '1.2.4', '==', 2)
- * // => true
- *
- * IcuVersion::compare('1.2.3', '12.3', '==')
- * // => true
- *
- * IcuVersion::compare('1', '10', '==')
- * // => true
- *
- * @param string $version1 A version string.
- * @param string $version2 A version string to compare.
- * @param string $operator The comparison operator.
- * @param integer|null $precision The number of components to compare. Pass
- * NULL to compare the versions unchanged.
- *
- * @return Boolean Whether the comparison succeeded.
- *
- * @see normalize()
- */
- public static function compare($version1, $version2, $operator, $precision = null)
- {
- $version1 = self::normalize($version1, $precision);
- $version2 = self::normalize($version2, $precision);
-
- return version_compare($version1, $version2, $operator);
- }
-
- /**
- * Normalizes a version string to the number of components given in the
- * parameter $precision.
- *
- * A single digit release version and a single digit major version are
- * contracted to a two digit release version. If no major version is given,
- * it is substituted by zero.
- *
- * Examples:
- *
- * IcuVersion::normalize('1.2.3.4');
- * // => '12.3.4'
- *
- * IcuVersion::normalize('1.2.3.4', 1);
- * // => '12'
- *
- * IcuVersion::normalize('1.2.3.4', 2);
- * // => '12.3'
- *
- * @param string $version An ICU version string.
- * @param integer|null $precision The number of components to include. Pass
- * NULL to return the version unchanged.
- *
- * @return string|null The normalized ICU version or NULL if it couldn't be
- * normalized.
- */
- public static function normalize($version, $precision)
- {
- $version = preg_replace('/^(\d)\.(\d)/', '$1$2', $version);
-
- if (1 === strlen($version)) {
- $version .= '0';
- }
-
- return Version::normalize($version, $precision);
- }
-
- /**
- * Must not be instantiated.
- */
- private function __construct() {}
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Util;
-
-use Symfony\Component\Intl\Intl;
-
-/**
- * Helper class for preparing test cases that rely on the Intl component.
- *
- * Any test that tests functionality relying on either the intl classes or
- * the resource bundle data should call either of the methods
- * {@link requireIntl()} or {@link requireFullIntl()}. Calling
- * {@link requireFullIntl()} is only necessary if you use functionality in the
- * test that is not provided by the stub intl implementation.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class IntlTestHelper
-{
- /**
- * Should be called before tests that work fine with the stub implementation.
- *
- * @param \PhpUnit_Framework_TestCase $testCase
- */
- public static function requireIntl(\PhpUnit_Framework_TestCase $testCase)
- {
- // We only run tests if the version is *one specific version*.
- // This condition is satisfied if
- //
- // * the intl extension is loaded with version Intl::getIcuStubVersion()
- // * the intl extension is not loaded
-
- if (IcuVersion::compare(Intl::getIcuVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
- $testCase->markTestSkipped('Please change ICU version to ' . Intl::getIcuStubVersion());
- }
-
- if (IcuVersion::compare(Intl::getIcuDataVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
- $testCase->markTestSkipped('Please change the Icu component to version 1.0.x or 1.' . IcuVersion::normalize(Intl::getIcuStubVersion(), 1) . '.x');
- }
-
- // Normalize the default locale in case this is not done explicitly
- // in the test
- \Locale::setDefault('en');
-
- // Consequently, tests will
- //
- // * run only for one ICU version (see Intl::getIcuStubVersion())
- // there is no need to add control structures to your tests that
- // change the test depending on the ICU version.
- //
- // Tests should only rely on functionality that is implemented in the
- // stub classes.
- }
-
- /**
- * Should be called before tests that require a feature-complete intl
- * implementation.
- *
- * @param \PhpUnit_Framework_TestCase $testCase
- */
- public static function requireFullIntl(\PhpUnit_Framework_TestCase $testCase)
- {
- // We only run tests if the intl extension is loaded...
- if (!Intl::isExtensionLoaded()) {
- $testCase->markTestSkipped('The intl extension is not available.');
- }
-
- // ... and only if the version is *one specific version* ...
- if (IcuVersion::compare(Intl::getIcuVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
- $testCase->markTestSkipped('Please change ICU version to ' . Intl::getIcuStubVersion());
- }
-
- // ... and only if the data in the Icu component matches that version.
- if (IcuVersion::compare(Intl::getIcuDataVersion(), Intl::getIcuStubVersion(), '!=', 1)) {
- $testCase->markTestSkipped('Please change the Icu component to version 1.0.x or 1.' . IcuVersion::normalize(Intl::getIcuStubVersion(), 1) . '.x');
- }
-
- // Normalize the default locale in case this is not done explicitly
- // in the test
- \Locale::setDefault('en');
-
- // Consequently, tests will
- //
- // * run only for one ICU version (see Intl::getIcuStubVersion())
- // there is no need to add control structures to your tests that
- // change the test depending on the ICU version.
- // * always use the C intl classes
- // * always use the binary resource bundles (any locale is allowed)
- }
-
- /**
- * Skips the test unless the current system has a 32bit architecture.
- *
- * @param \PhpUnit_Framework_TestCase $testCase
- */
- public static function require32Bit(\PhpUnit_Framework_TestCase $testCase)
- {
- if (4 !== PHP_INT_SIZE) {
- $testCase->markTestSkipped('PHP must be compiled in 32 bit mode to run this test');
- }
- }
-
- /**
- * Skips the test unless the current system has a 64bit architecture.
- *
- * @param \PhpUnit_Framework_TestCase $testCase
- */
- public static function require64Bit(\PhpUnit_Framework_TestCase $testCase)
- {
- if (8 !== PHP_INT_SIZE) {
- $testCase->markTestSkipped('PHP must be compiled in 64 bit mode to run this test');
- }
- }
-
- /**
- * Must not be instantiated.
- */
- private function __construct() {}
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Util;
-
-/**
- * An SVN commit.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SvnCommit
-{
- /**
- * @var \SimpleXMLElement
- */
- private $svnInfo;
-
- /**
- * Creates a commit from the given "svn info" data.
- *
- * @param \SimpleXMLElement $svnInfo The XML result from the "svn info"
- * command.
- */
- public function __construct(\SimpleXMLElement $svnInfo)
- {
- $this->svnInfo = $svnInfo;
- }
-
- /**
- * Returns the revision of the commit.
- *
- * @return string The revision of the commit.
- */
- public function getRevision()
- {
- return (string) $this->svnInfo['revision'];
- }
-
- /**
- * Returns the author of the commit.
- *
- * @return string The author name.
- */
- public function getAuthor()
- {
- return (string) $this->svnInfo->author;
- }
-
- /**
- * Returns the date of the commit.
- *
- * @return string The commit date.
- */
- public function getDate()
- {
- return (string) $this->svnInfo->date;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Util;
-
-use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\Intl\Exception\RuntimeException;
-
-/**
- * A SVN repository containing ICU data.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SvnRepository
-{
- /**
- * @var string The path to the repository.
- */
- private $path;
-
- /**
- * @var \SimpleXMLElement
- */
- private $svnInfo;
-
- /**
- * @var SvnCommit
- */
- private $lastCommit;
-
- /**
- * Downloads the ICU data for the given version.
- *
- * @param string $url The URL to download from.
- * @param string $targetDir The directory in which to store the repository.
- *
- * @return SvnRepository The directory where the data is stored.
- *
- * @throws RuntimeException If an error occurs during the download.
- */
- public static function download($url, $targetDir)
- {
- exec('which svn', $output, $result);
-
- if ($result !== 0) {
- throw new RuntimeException('The command "svn" is not installed.');
- }
-
- $filesystem = new Filesystem();
-
- if (!$filesystem->exists($targetDir . '/.svn')) {
- $filesystem->remove($targetDir);
- $filesystem->mkdir($targetDir);
-
- exec('svn checkout ' . $url . ' ' . $targetDir, $output, $result);
-
- if ($result !== 0) {
- throw new RuntimeException('The SVN checkout of ' . $url . 'failed.');
- }
- }
-
- return new static(realpath($targetDir));
- }
-
- /**
- * Reads the SVN repository at the given path.
- *
- * @param string $path The path to the repository.
- */
- public function __construct($path)
- {
- $this->path = $path;
- }
-
- /**
- * Returns the path to the repository.
- *
- * @return string The path to the repository.
- */
- public function getPath()
- {
- return $this->path;
- }
-
- /**
- * Returns the URL of the repository.
- *
- * @return string The URL of the repository.
- */
- public function getUrl()
- {
- return (string) $this->getSvnInfo()->entry->url;
- }
-
- /**
- * Returns the last commit of the repository.
- *
- * @return SvnCommit The last commit.
- */
- public function getLastCommit()
- {
- if (null === $this->lastCommit) {
- $this->lastCommit = new SvnCommit($this->getSvnInfo()->entry->commit);
- }
-
- return $this->lastCommit;
- }
-
- /**
- * Returns information about the SVN repository.
- *
- * @return \SimpleXMLElement The XML result from the "svn info" command.
- *
- * @throws RuntimeException If the "svn info" command failed.
- */
- private function getSvnInfo()
- {
- if (null === $this->svnInfo) {
- exec('svn info --xml '.$this->path, $output, $result);
-
- $svnInfo = simplexml_load_string(implode("\n", $output));
-
- if ($result !== 0) {
- throw new RuntimeException('svn info failed');
- }
-
- $this->svnInfo = $svnInfo;
- }
-
- return $this->svnInfo;
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Intl\Util;
-
-/**
- * Facilitates the comparison of version strings.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Version
-{
- /**
- * Compares two versions with an operator.
- *
- * This method is identical to {@link version_compare()}, except that you
- * can pass the number of regarded version components in the last argument
- * $precision.
- *
- * Examples:
- *
- * Version::compare('1.2.3', '1.2.4', '==')
- * // => false
- *
- * Version::compare('1.2.3', '1.2.4', '==', 2)
- * // => true
- *
- * @param string $version1 A version string.
- * @param string $version2 A version string to compare.
- * @param string $operator The comparison operator.
- * @param integer|null $precision The number of components to compare. Pass
- * NULL to compare the versions unchanged.
- *
- * @return Boolean Whether the comparison succeeded.
- *
- * @see normalize()
- */
- public static function compare($version1, $version2, $operator, $precision = null)
- {
- $version1 = self::normalize($version1, $precision);
- $version2 = self::normalize($version2, $precision);
-
- return version_compare($version1, $version2, $operator);
- }
-
- /**
- * Normalizes a version string to the number of components given in the
- * parameter $precision.
- *
- * Examples:
- *
- * Version::normalize('1.2.3', 1);
- * // => '1'
- *
- * Version::normalize('1.2.3', 2);
- * // => '1.2'
- *
- * @param string $version A version string.
- * @param integer|null $precision The number of components to include. Pass
- * NULL to return the version unchanged.
- *
- * @return string|null The normalized version or NULL if it couldn't be
- * normalized.
- */
- public static function normalize($version, $precision)
- {
- if (null === $precision) {
- return $version;
- }
-
- $pattern = '[^\.]+';
-
- for ($i = 2; $i <= $precision; ++$i) {
- $pattern = sprintf('[^\.]+(\.%s)?', $pattern);
- }
-
- if (!preg_match('/^' . $pattern . '/', $version, $matches)) {
- return null;
- }
-
- return $matches[0];
- }
-
- /**
- * Must not be instantiated.
- */
- private function __construct() {}
-}
+++ /dev/null
-{
- "name": "symfony/intl",
- "type": "library",
- "description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
- "keywords": ["intl", "icu", "internationalization", "localization", "i18n", "l10n"],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- },
- {
- "name": "Eriksen Costa",
- "email": "eriksen.costa@infranology.com.br"
- },
- {
- "name": "Igor Wiedler",
- "email": "igor@wiedler.ch"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3",
- "symfony/icu": "~1.0-RC"
- },
- "require-dev": {
- "symfony/filesystem": ">=2.1"
- },
- "suggest": {
- "ext-intl": "to use the component with locales other than \"en\""
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\Intl\\": "" },
- "classmap": [ "Symfony/Component/Intl/Resources/stubs" ],
- "files": [ "Symfony/Component/Intl/Resources/stubs/functions.php" ]
- },
- "target-dir": "Symfony/Component/Intl",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony Intl Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./Tests</directory>
- <directory>./vendor</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver\Exception;
-
-/**
- * Marker interface for the Options component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver\Exception;
-
-/**
- * Exception thrown when an invalid option is passed.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class InvalidOptionsException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver\Exception;
-
-/**
- * Exception thrown when a required option is missing.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class MissingOptionsException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver\Exception;
-
-/**
- * Thrown when an option definition is invalid.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class OptionDefinitionException extends \RuntimeException implements ExceptionInterface
-{
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver;
-
-use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException;
-
-/**
- * Container for resolving inter-dependent options.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class Options implements \ArrayAccess, \Iterator, \Countable
-{
- /**
- * A list of option values.
- * @var array
- */
- private $options = array();
-
- /**
- * A list of normalizer closures.
- * @var array
- */
- private $normalizers = array();
-
- /**
- * A list of closures for evaluating lazy options.
- * @var array
- */
- private $lazy = array();
-
- /**
- * A list containing the currently locked options.
- * @var array
- */
- private $lock = array();
-
- /**
- * Whether at least one option has already been read.
- *
- * Once read, the options cannot be changed anymore. This is
- * necessary in order to avoid inconsistencies during the resolving
- * process. If any option is changed after being read, all evaluated
- * lazy options that depend on this option would become invalid.
- *
- * @var Boolean
- */
- private $reading = false;
-
- /**
- * Sets the value of a given option.
- *
- * You can set lazy options by passing a closure with the following
- * signature:
- *
- * <code>
- * function (Options $options)
- * </code>
- *
- * This closure will be evaluated once the option is read using
- * {@link get()}. The closure has access to the resolved values of
- * other options through the passed {@link Options} instance.
- *
- * @param string $option The name of the option.
- * @param mixed $value The value of the option.
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- */
- public function set($option, $value)
- {
- // Setting is not possible once an option is read, because then lazy
- // options could manipulate the state of the object, leading to
- // inconsistent results.
- if ($this->reading) {
- throw new OptionDefinitionException('Options cannot be set anymore once options have been read.');
- }
-
- // Setting is equivalent to overloading while discarding the previous
- // option value
- unset($this->options[$option]);
- unset($this->lazy[$option]);
-
- $this->overload($option, $value);
- }
-
- /**
- * Sets the normalizer for a given option.
- *
- * Normalizers should be closures with the following signature:
- *
- * <code>
- * function (Options $options, $value)
- * </code>
- *
- * This closure will be evaluated once the option is read using
- * {@link get()}. The closure has access to the resolved values of
- * other options through the passed {@link Options} instance.
- *
- * @param string $option The name of the option.
- * @param \Closure $normalizer The normalizer.
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- */
- public function setNormalizer($option, \Closure $normalizer)
- {
- if ($this->reading) {
- throw new OptionDefinitionException('Normalizers cannot be added anymore once options have been read.');
- }
-
- $this->normalizers[$option] = $normalizer;
- }
-
- /**
- * Replaces the contents of the container with the given options.
- *
- * This method is a shortcut for {@link clear()} with subsequent
- * calls to {@link set()}.
- *
- * @param array $options The options to set.
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- */
- public function replace(array $options)
- {
- if ($this->reading) {
- throw new OptionDefinitionException('Options cannot be replaced anymore once options have been read.');
- }
-
- $this->options = array();
- $this->lazy = array();
- $this->normalizers = array();
-
- foreach ($options as $option => $value) {
- $this->overload($option, $value);
- }
- }
-
- /**
- * Overloads the value of a given option.
- *
- * Contrary to {@link set()}, this method keeps the previous default
- * value of the option so that you can access it if you pass a closure.
- * Passed closures should have the following signature:
- *
- * <code>
- * function (Options $options, $value)
- * </code>
- *
- * The second parameter passed to the closure is the current default
- * value of the option.
- *
- * @param string $option The option name.
- * @param mixed $value The option value.
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- */
- public function overload($option, $value)
- {
- if ($this->reading) {
- throw new OptionDefinitionException('Options cannot be overloaded anymore once options have been read.');
- }
-
- // If an option is a closure that should be evaluated lazily, store it
- // in the "lazy" property.
- if ($value instanceof \Closure) {
- $reflClosure = new \ReflectionFunction($value);
- $params = $reflClosure->getParameters();
-
- if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && __CLASS__ === $class->name) {
- // Initialize the option if no previous value exists
- if (!isset($this->options[$option])) {
- $this->options[$option] = null;
- }
-
- // Ignore previous lazy options if the closure has no second parameter
- if (!isset($this->lazy[$option]) || !isset($params[1])) {
- $this->lazy[$option] = array();
- }
-
- // Store closure for later evaluation
- $this->lazy[$option][] = $value;
-
- return;
- }
- }
-
- // Remove lazy options by default
- unset($this->lazy[$option]);
-
- $this->options[$option] = $value;
- }
-
- /**
- * Returns the value of the given option.
- *
- * If the option was a lazy option, it is evaluated now.
- *
- * @param string $option The option name.
- *
- * @return mixed The option value.
- *
- * @throws \OutOfBoundsException If the option does not exist.
- * @throws OptionDefinitionException If a cyclic dependency is detected
- * between two lazy options.
- */
- public function get($option)
- {
- $this->reading = true;
-
- if (!array_key_exists($option, $this->options)) {
- throw new \OutOfBoundsException(sprintf('The option "%s" does not exist.', $option));
- }
-
- if (isset($this->lazy[$option])) {
- $this->resolve($option);
- }
-
- if (isset($this->normalizers[$option])) {
- $this->normalize($option);
- }
-
- return $this->options[$option];
- }
-
- /**
- * Returns whether the given option exists.
- *
- * @param string $option The option name.
- *
- * @return Boolean Whether the option exists.
- */
- public function has($option)
- {
- return array_key_exists($option, $this->options);
- }
-
- /**
- * Removes the option with the given name.
- *
- * @param string $option The option name.
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- */
- public function remove($option)
- {
- if ($this->reading) {
- throw new OptionDefinitionException('Options cannot be removed anymore once options have been read.');
- }
-
- unset($this->options[$option]);
- unset($this->lazy[$option]);
- unset($this->normalizers[$option]);
- }
-
- /**
- * Removes all options.
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- */
- public function clear()
- {
- if ($this->reading) {
- throw new OptionDefinitionException('Options cannot be cleared anymore once options have been read.');
- }
-
- $this->options = array();
- $this->lazy = array();
- $this->normalizers = array();
- }
-
- /**
- * Returns the values of all options.
- *
- * Lazy options are evaluated at this point.
- *
- * @return array The option values.
- */
- public function all()
- {
- $this->reading = true;
-
- // Performance-wise this is slightly better than
- // while (null !== $option = key($this->lazy))
- foreach ($this->lazy as $option => $closures) {
- // Double check, in case the option has already been resolved
- // by cascade in the previous cycles
- if (isset($this->lazy[$option])) {
- $this->resolve($option);
- }
- }
-
- foreach ($this->normalizers as $option => $normalizer) {
- if (isset($this->normalizers[$option])) {
- $this->normalize($option);
- }
- }
-
- return $this->options;
- }
-
- /**
- * Equivalent to {@link has()}.
- *
- * @param string $option The option name.
- *
- * @return Boolean Whether the option exists.
- *
- * @see \ArrayAccess::offsetExists()
- */
- public function offsetExists($option)
- {
- return $this->has($option);
- }
-
- /**
- * Equivalent to {@link get()}.
- *
- * @param string $option The option name.
- *
- * @return mixed The option value.
- *
- * @throws \OutOfBoundsException If the option does not exist.
- * @throws OptionDefinitionException If a cyclic dependency is detected
- * between two lazy options.
- *
- * @see \ArrayAccess::offsetGet()
- */
- public function offsetGet($option)
- {
- return $this->get($option);
- }
-
- /**
- * Equivalent to {@link set()}.
- *
- * @param string $option The name of the option.
- * @param mixed $value The value of the option. May be a closure with a
- * signature as defined in DefaultOptions::add().
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- *
- * @see \ArrayAccess::offsetSet()
- */
- public function offsetSet($option, $value)
- {
- $this->set($option, $value);
- }
-
- /**
- * Equivalent to {@link remove()}.
- *
- * @param string $option The option name.
- *
- * @throws OptionDefinitionException If options have already been read.
- * Once options are read, the container
- * becomes immutable.
- *
- * @see \ArrayAccess::offsetUnset()
- */
- public function offsetUnset($option)
- {
- $this->remove($option);
- }
-
- /**
- * {@inheritdoc}
- */
- public function current()
- {
- return $this->get($this->key());
- }
-
- /**
- * {@inheritdoc}
- */
- public function next()
- {
- next($this->options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function key()
- {
- return key($this->options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function valid()
- {
- return null !== $this->key();
- }
-
- /**
- * {@inheritdoc}
- */
- public function rewind()
- {
- reset($this->options);
- }
-
- /**
- * {@inheritdoc}
- */
- public function count()
- {
- return count($this->options);
- }
-
- /**
- * Evaluates the given lazy option.
- *
- * The evaluated value is written into the options array. The closure for
- * evaluating the option is discarded afterwards.
- *
- * @param string $option The option to evaluate.
- *
- * @throws OptionDefinitionException If the option has a cyclic dependency
- * on another option.
- */
- private function resolve($option)
- {
- // The code duplication with normalize() exists for performance
- // reasons, in order to save a method call.
- // Remember that this method is potentially called a couple of thousand
- // times and needs to be as efficient as possible.
- if (isset($this->lock[$option])) {
- $conflicts = array();
-
- foreach ($this->lock as $option => $locked) {
- if ($locked) {
- $conflicts[] = $option;
- }
- }
-
- throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', $conflicts)));
- }
-
- $this->lock[$option] = true;
- foreach ($this->lazy[$option] as $closure) {
- $this->options[$option] = $closure($this, $this->options[$option]);
- }
- unset($this->lock[$option]);
-
- // The option now isn't lazy anymore
- unset($this->lazy[$option]);
- }
-
- /**
- * Normalizes the given option.
- *
- * The evaluated value is written into the options array.
- *
- * @param string $option The option to normalizer.
- *
- * @throws OptionDefinitionException If the option has a cyclic dependency
- * on another option.
- */
- private function normalize($option)
- {
- // The code duplication with resolve() exists for performance
- // reasons, in order to save a method call.
- // Remember that this method is potentially called a couple of thousand
- // times and needs to be as efficient as possible.
- if (isset($this->lock[$option])) {
- $conflicts = array();
-
- foreach ($this->lock as $option => $locked) {
- if ($locked) {
- $conflicts[] = $option;
- }
- }
-
- throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', $conflicts)));
- }
-
- /** @var \Closure $normalizer */
- $normalizer = $this->normalizers[$option];
-
- $this->lock[$option] = true;
- $this->options[$option] = $normalizer($this, array_key_exists($option, $this->options) ? $this->options[$option] : null);
- unset($this->lock[$option]);
-
- // The option is now normalized
- unset($this->normalizers[$option]);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver;
-
-use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException;
-use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
-use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
-
-/**
- * Helper for merging default and concrete option values.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Tobias Schultze <http://tobion.de>
- */
-class OptionsResolver implements OptionsResolverInterface
-{
- /**
- * The default option values.
- * @var Options
- */
- private $defaultOptions;
-
- /**
- * The options known by the resolver.
- * @var array
- */
- private $knownOptions = array();
-
- /**
- * The options without defaults that are required to be passed to resolve().
- * @var array
- */
- private $requiredOptions = array();
-
- /**
- * A list of accepted values for each option.
- * @var array
- */
- private $allowedValues = array();
-
- /**
- * A list of accepted types for each option.
- * @var array
- */
- private $allowedTypes = array();
-
- /**
- * Creates a new instance.
- */
- public function __construct()
- {
- $this->defaultOptions = new Options();
- }
-
- /**
- * Clones the resolver.
- */
- public function __clone()
- {
- $this->defaultOptions = clone $this->defaultOptions;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaults(array $defaultValues)
- {
- foreach ($defaultValues as $option => $value) {
- $this->defaultOptions->overload($option, $value);
- $this->knownOptions[$option] = true;
- unset($this->requiredOptions[$option]);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function replaceDefaults(array $defaultValues)
- {
- foreach ($defaultValues as $option => $value) {
- $this->defaultOptions->set($option, $value);
- $this->knownOptions[$option] = true;
- unset($this->requiredOptions[$option]);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setOptional(array $optionNames)
- {
- foreach ($optionNames as $key => $option) {
- if (!is_int($key)) {
- throw new OptionDefinitionException('You should not pass default values to setOptional()');
- }
-
- $this->knownOptions[$option] = true;
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRequired(array $optionNames)
- {
- foreach ($optionNames as $key => $option) {
- if (!is_int($key)) {
- throw new OptionDefinitionException('You should not pass default values to setRequired()');
- }
-
- $this->knownOptions[$option] = true;
- // set as required if no default has been set already
- if (!isset($this->defaultOptions[$option])) {
- $this->requiredOptions[$option] = true;
- }
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAllowedValues(array $allowedValues)
- {
- $this->validateOptionsExistence($allowedValues);
-
- $this->allowedValues = array_replace($this->allowedValues, $allowedValues);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addAllowedValues(array $allowedValues)
- {
- $this->validateOptionsExistence($allowedValues);
-
- $this->allowedValues = array_merge_recursive($this->allowedValues, $allowedValues);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAllowedTypes(array $allowedTypes)
- {
- $this->validateOptionsExistence($allowedTypes);
-
- $this->allowedTypes = array_replace($this->allowedTypes, $allowedTypes);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addAllowedTypes(array $allowedTypes)
- {
- $this->validateOptionsExistence($allowedTypes);
-
- $this->allowedTypes = array_merge_recursive($this->allowedTypes, $allowedTypes);
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setNormalizers(array $normalizers)
- {
- $this->validateOptionsExistence($normalizers);
-
- foreach ($normalizers as $option => $normalizer) {
- $this->defaultOptions->setNormalizer($option, $normalizer);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isKnown($option)
- {
- return isset($this->knownOptions[$option]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function isRequired($option)
- {
- return isset($this->requiredOptions[$option]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function resolve(array $options = array())
- {
- $this->validateOptionsExistence($options);
- $this->validateOptionsCompleteness($options);
-
- // Make sure this method can be called multiple times
- $combinedOptions = clone $this->defaultOptions;
-
- // Override options set by the user
- foreach ($options as $option => $value) {
- $combinedOptions->set($option, $value);
- }
-
- // Resolve options
- $resolvedOptions = $combinedOptions->all();
-
- $this->validateOptionValues($resolvedOptions);
- $this->validateOptionTypes($resolvedOptions);
-
- return $resolvedOptions;
- }
-
- /**
- * Validates that the given option names exist and throws an exception
- * otherwise.
- *
- * @param array $options An list of option names as keys.
- *
- * @throws InvalidOptionsException If any of the options has not been defined.
- */
- private function validateOptionsExistence(array $options)
- {
- $diff = array_diff_key($options, $this->knownOptions);
-
- if (count($diff) > 0) {
- ksort($this->knownOptions);
- ksort($diff);
-
- throw new InvalidOptionsException(sprintf(
- (count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Known options are: "%s"',
- implode('", "', array_keys($diff)),
- implode('", "', array_keys($this->knownOptions))
- ));
- }
- }
-
- /**
- * Validates that all required options are given and throws an exception
- * otherwise.
- *
- * @param array $options An list of option names as keys.
- *
- * @throws MissingOptionsException If a required option is missing.
- */
- private function validateOptionsCompleteness(array $options)
- {
- $diff = array_diff_key($this->requiredOptions, $options);
-
- if (count($diff) > 0) {
- ksort($diff);
-
- throw new MissingOptionsException(sprintf(
- count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.',
- implode('", "', array_keys($diff))
- ));
- }
- }
-
- /**
- * Validates that the given option values match the allowed values and
- * throws an exception otherwise.
- *
- * @param array $options A list of option values.
- *
- * @throws InvalidOptionsException If any of the values does not match the
- * allowed values of the option.
- */
- private function validateOptionValues(array $options)
- {
- foreach ($this->allowedValues as $option => $allowedValues) {
- if (isset($options[$option]) && !in_array($options[$option], $allowedValues, true)) {
- throw new InvalidOptionsException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', $allowedValues)));
- }
- }
- }
-
- /**
- * Validates that the given options match the allowed types and
- * throws an exception otherwise.
- *
- * @param array $options A list of options.
- *
- * @throws InvalidOptionsException If any of the types does not match the
- * allowed types of the option.
- */
- private function validateOptionTypes(array $options)
- {
- foreach ($this->allowedTypes as $option => $allowedTypes) {
- if (!array_key_exists($option, $options)) {
- continue;
- }
-
- $value = $options[$option];
- $allowedTypes = (array) $allowedTypes;
-
- foreach ($allowedTypes as $type) {
- $isFunction = 'is_'.$type;
-
- if (function_exists($isFunction) && $isFunction($value)) {
- continue 2;
- } elseif ($value instanceof $type) {
- continue 2;
- }
- }
-
- $printableValue = is_object($value)
- ? get_class($value)
- : (is_array($value)
- ? 'Array'
- : (string) $value);
-
- throw new InvalidOptionsException(sprintf(
- 'The option "%s" with value "%s" is expected to be of type "%s"',
- $option,
- $printableValue,
- implode('", "', $allowedTypes)
- ));
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface OptionsResolverInterface
-{
- /**
- * Sets default option values.
- *
- * The options can either be values of any types or closures that
- * evaluate the option value lazily. These closures must have one
- * of the following signatures:
- *
- * <code>
- * function (Options $options)
- * function (Options $options, $value)
- * </code>
- *
- * The second parameter passed to the closure is the previously
- * set default value, in case you are overwriting an existing
- * default value.
- *
- * The closures should return the lazily created option value.
- *
- * @param array $defaultValues A list of option names as keys and default
- * values or closures as values.
- *
- * @return OptionsResolverInterface The resolver instance.
- */
- public function setDefaults(array $defaultValues);
-
- /**
- * Replaces default option values.
- *
- * Old defaults are erased, which means that closures passed here cannot
- * access the previous default value. This may be useful to improve
- * performance if the previous default value is calculated by an expensive
- * closure.
- *
- * @param array $defaultValues A list of option names as keys and default
- * values or closures as values.
- *
- * @return OptionsResolverInterface The resolver instance.
- */
- public function replaceDefaults(array $defaultValues);
-
- /**
- * Sets optional options.
- *
- * This method declares valid option names without setting default values for them.
- * If these options are not passed to {@link resolve()} and no default has been set
- * for them, they will be missing in the final options array. This can be helpful
- * if you want to determine whether an option has been set or not because otherwise
- * {@link resolve()} would trigger an exception for unknown options.
- *
- * @param array $optionNames A list of option names.
- *
- * @return OptionsResolverInterface The resolver instance.
- *
- * @throws Exception\OptionDefinitionException When trying to pass default values.
- */
- public function setOptional(array $optionNames);
-
- /**
- * Sets required options.
- *
- * If these options are not passed to {@link resolve()} and no default has been set for
- * them, an exception will be thrown.
- *
- * @param array $optionNames A list of option names.
- *
- * @return OptionsResolverInterface The resolver instance.
- *
- * @throws Exception\OptionDefinitionException When trying to pass default values.
- */
- public function setRequired(array $optionNames);
-
- /**
- * Sets allowed values for a list of options.
- *
- * @param array $allowedValues A list of option names as keys and arrays
- * with values acceptable for that option as
- * values.
- *
- * @return OptionsResolverInterface The resolver instance.
- *
- * @throws Exception\InvalidOptionsException If an option has not been defined
- * (see {@link isKnown()}) for which
- * an allowed value is set.
- */
- public function setAllowedValues(array $allowedValues);
-
- /**
- * Adds allowed values for a list of options.
- *
- * The values are merged with the allowed values defined previously.
- *
- * @param array $allowedValues A list of option names as keys and arrays
- * with values acceptable for that option as
- * values.
- *
- * @return OptionsResolverInterface The resolver instance.
- *
- * @throws Exception\InvalidOptionsException If an option has not been defined
- * (see {@link isKnown()}) for which
- * an allowed value is set.
- */
- public function addAllowedValues(array $allowedValues);
-
- /**
- * Sets allowed types for a list of options.
- *
- * @param array $allowedTypes A list of option names as keys and type
- * names passed as string or array as values.
- *
- * @return OptionsResolverInterface The resolver instance.
- *
- * @throws Exception\InvalidOptionsException If an option has not been defined for
- * which an allowed type is set.
- */
- public function setAllowedTypes(array $allowedTypes);
-
- /**
- * Adds allowed types for a list of options.
- *
- * The types are merged with the allowed types defined previously.
- *
- * @param array $allowedTypes A list of option names as keys and type
- * names passed as string or array as values.
- *
- * @return OptionsResolverInterface The resolver instance.
- *
- * @throws Exception\InvalidOptionsException If an option has not been defined for
- * which an allowed type is set.
- */
- public function addAllowedTypes(array $allowedTypes);
-
- /**
- * Sets normalizers that are applied on resolved options.
- *
- * The normalizers should be closures with the following signature:
- *
- * <code>
- * function (Options $options, $value)
- * </code>
- *
- * The second parameter passed to the closure is the value of
- * the option.
- *
- * The closure should return the normalized value.
- *
- * @param array $normalizers An array of closures.
- *
- * @return OptionsResolverInterface The resolver instance.
- */
- public function setNormalizers(array $normalizers);
-
- /**
- * Returns whether an option is known.
- *
- * An option is known if it has been passed to either {@link setDefaults()},
- * {@link setRequired()} or {@link setOptional()} before.
- *
- * @param string $option The name of the option.
- *
- * @return Boolean Whether the option is known.
- */
- public function isKnown($option);
-
- /**
- * Returns whether an option is required.
- *
- * An option is required if it has been passed to {@link setRequired()},
- * but not to {@link setDefaults()}. That is, the option has been declared
- * as required and no default value has been set.
- *
- * @param string $option The name of the option.
- *
- * @return Boolean Whether the option is required.
- */
- public function isRequired($option);
-
- /**
- * Returns the combination of the default and the passed options.
- *
- * @param array $options The custom option values.
- *
- * @return array A list of options and their values.
- *
- * @throws Exception\InvalidOptionsException If any of the passed options has not
- * been defined or does not contain an
- * allowed value.
- * @throws Exception\MissingOptionsException If a required option is missing.
- * @throws Exception\OptionDefinitionException If a cyclic dependency is detected
- * between two lazy options.
- */
- public function resolve(array $options = array());
-}
+++ /dev/null
-OptionsResolver Component
-=========================
-
-OptionsResolver helps at configuring objects with option arrays.
-
-It supports default values on different levels of your class hierarchy,
-option constraints (required vs. optional, allowed values) and lazy options
-whose default value depends on the value of another option.
-
-The following example demonstrates a Person class with two required options
-"firstName" and "lastName" and two optional options "age" and "gender", where
-the default value of "gender" is derived from the passed first name, if
-possible, and may only be one of "male" and "female".
-
- use Symfony\Component\OptionsResolver\OptionsResolver;
- use Symfony\Component\OptionsResolver\OptionsResolverInterface;
- use Symfony\Component\OptionsResolver\Options;
-
- class Person
- {
- protected $options;
-
- public function __construct(array $options = array())
- {
- $resolver = new OptionsResolver();
- $this->setDefaultOptions($resolver);
-
- $this->options = $resolver->resolve($options);
- }
-
- protected function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- $resolver->setRequired(array(
- 'firstName',
- 'lastName',
- ));
-
- $resolver->setDefaults(array(
- 'age' => null,
- 'gender' => function (Options $options) {
- if (self::isKnownMaleName($options['firstName'])) {
- return 'male';
- }
-
- return 'female';
- },
- ));
-
- $resolver->setAllowedValues(array(
- 'gender' => array('male', 'female'),
- ));
- }
- }
-
-We can now easily instantiate a Person object:
-
- // 'gender' is implicitly set to 'female'
- $person = new Person(array(
- 'firstName' => 'Jane',
- 'lastName' => 'Doe',
- ));
-
-We can also override the default values of the optional options:
-
- $person = new Person(array(
- 'firstName' => 'Abdullah',
- 'lastName' => 'Mogashi',
- 'gender' => 'male',
- 'age' => 30,
- ));
-
-Options can be added or changed in subclasses by overriding the `setDefaultOptions`
-method:
-
- use Symfony\Component\OptionsResolver\OptionsResolver;
- use Symfony\Component\OptionsResolver\Options;
-
- class Employee extends Person
- {
- protected function setDefaultOptions(OptionsResolverInterface $resolver)
- {
- parent::setDefaultOptions($resolver);
-
- $resolver->setRequired(array(
- 'birthDate',
- ));
-
- $resolver->setDefaults(array(
- // $previousValue contains the default value configured in the
- // parent class
- 'age' => function (Options $options, $previousValue) {
- return self::calculateAge($options['birthDate']);
- }
- ));
- }
- }
-
-
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/OptionsResolver/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver\Tests;
-
-use Symfony\Component\OptionsResolver\OptionsResolver;
-use Symfony\Component\OptionsResolver\Options;
-
-class OptionsResolverTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var OptionsResolver
- */
- private $resolver;
-
- protected function setUp()
- {
- $this->resolver = new OptionsResolver();
- }
-
- public function testResolve()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- 'two' => '2',
- ));
-
- $options = array(
- 'two' => '20',
- );
-
- $this->assertEquals(array(
- 'one' => '1',
- 'two' => '20',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveLazy()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- 'two' => function (Options $options) {
- return '20';
- },
- ));
-
- $this->assertEquals(array(
- 'one' => '1',
- 'two' => '20',
- ), $this->resolver->resolve(array()));
- }
-
- public function testResolveLazyDependencyOnOptional()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- 'two' => function (Options $options) {
- return $options['one'].'2';
- },
- ));
-
- $options = array(
- 'one' => '10',
- );
-
- $this->assertEquals(array(
- 'one' => '10',
- 'two' => '102',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveLazyDependencyOnMissingOptionalWithoutDefault()
- {
- $test = $this;
-
- $this->resolver->setOptional(array(
- 'one',
- ));
-
- $this->resolver->setDefaults(array(
- 'two' => function (Options $options) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertFalse(isset($options['one']));
-
- return '2';
- },
- ));
-
- $options = array(
- );
-
- $this->assertEquals(array(
- 'two' => '2',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveLazyDependencyOnOptionalWithoutDefault()
- {
- $test = $this;
-
- $this->resolver->setOptional(array(
- 'one',
- ));
-
- $this->resolver->setDefaults(array(
- 'two' => function (Options $options) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertTrue(isset($options['one']));
-
- return $options['one'].'2';
- },
- ));
-
- $options = array(
- 'one' => '10',
- );
-
- $this->assertEquals(array(
- 'one' => '10',
- 'two' => '102',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveLazyDependencyOnRequired()
- {
- $this->resolver->setRequired(array(
- 'one',
- ));
- $this->resolver->setDefaults(array(
- 'two' => function (Options $options) {
- return $options['one'].'2';
- },
- ));
-
- $options = array(
- 'one' => '10',
- );
-
- $this->assertEquals(array(
- 'one' => '10',
- 'two' => '102',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveLazyReplaceDefaults()
- {
- $test = $this;
-
- $this->resolver->setDefaults(array(
- 'one' => function (Options $options) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->fail('Previous closure should not be executed');
- },
- ));
-
- $this->resolver->replaceDefaults(array(
- 'one' => function (Options $options, $previousValue) {
- return '1';
- },
- ));
-
- $this->assertEquals(array(
- 'one' => '1',
- ), $this->resolver->resolve(array()));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testResolveFailsIfNonExistingOption()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setRequired(array(
- 'two',
- ));
-
- $this->resolver->setOptional(array(
- 'three',
- ));
-
- $this->resolver->resolve(array(
- 'foo' => 'bar',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
- */
- public function testResolveFailsIfMissingRequiredOption()
- {
- $this->resolver->setRequired(array(
- 'one',
- ));
-
- $this->resolver->setDefaults(array(
- 'two' => '2',
- ));
-
- $this->resolver->resolve(array(
- 'two' => '20',
- ));
- }
-
- public function testResolveSucceedsIfOptionValueAllowed()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedValues(array(
- 'one' => array('1', 'one'),
- ));
-
- $options = array(
- 'one' => 'one',
- );
-
- $this->assertEquals(array(
- 'one' => 'one',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveSucceedsIfOptionValueAllowed2()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- 'two' => '2',
- ));
-
- $this->resolver->setAllowedValues(array(
- 'one' => '1',
- 'two' => '2',
- ));
- $this->resolver->addAllowedValues(array(
- 'one' => 'one',
- 'two' => 'two',
- ));
-
- $options = array(
- 'one' => '1',
- 'two' => 'two',
- );
-
- $this->assertEquals(array(
- 'one' => '1',
- 'two' => 'two',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveSucceedsIfOptionalWithAllowedValuesNotSet()
- {
- $this->resolver->setRequired(array(
- 'one',
- ));
-
- $this->resolver->setOptional(array(
- 'two',
- ));
-
- $this->resolver->setAllowedValues(array(
- 'one' => array('1', 'one'),
- 'two' => array('2', 'two'),
- ));
-
- $options = array(
- 'one' => '1',
- );
-
- $this->assertEquals(array(
- 'one' => '1',
- ), $this->resolver->resolve($options));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testResolveFailsIfOptionValueNotAllowed()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedValues(array(
- 'one' => array('1', 'one'),
- ));
-
- $this->resolver->resolve(array(
- 'one' => '2',
- ));
- }
-
- public function testResolveSucceedsIfOptionTypeAllowed()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => 'string',
- ));
-
- $options = array(
- 'one' => 'one',
- );
-
- $this->assertEquals(array(
- 'one' => 'one',
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveSucceedsIfOptionTypeAllowedPassArray()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => array('string', 'bool'),
- ));
-
- $options = array(
- 'one' => true,
- );
-
- $this->assertEquals(array(
- 'one' => true,
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveSucceedsIfOptionTypeAllowedPassObject()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => 'object',
- ));
-
- $object = new \stdClass();
- $options = array(
- 'one' => $object,
- );
-
- $this->assertEquals(array(
- 'one' => $object,
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveSucceedsIfOptionTypeAllowedPassClass()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => '\stdClass',
- ));
-
- $object = new \stdClass();
- $options = array(
- 'one' => $object,
- );
-
- $this->assertEquals(array(
- 'one' => $object,
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveSucceedsIfOptionTypeAllowedAddTypes()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- 'two' => '2',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => 'string',
- 'two' => 'bool',
- ));
- $this->resolver->addAllowedTypes(array(
- 'one' => 'float',
- 'two' => 'integer',
- ));
-
- $options = array(
- 'one' => 1.23,
- 'two' => false,
- );
-
- $this->assertEquals(array(
- 'one' => 1.23,
- 'two' => false,
- ), $this->resolver->resolve($options));
- }
-
- public function testResolveSucceedsIfOptionalWithTypeAndWithoutValue()
- {
- $this->resolver->setOptional(array(
- 'one',
- 'two',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => 'string',
- 'two' => 'int',
- ));
-
- $options = array(
- 'two' => 1,
- );
-
- $this->assertEquals(array(
- 'two' => 1,
- ), $this->resolver->resolve($options));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testResolveFailsIfOptionTypeNotAllowed()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => array('string', 'bool'),
- ));
-
- $this->resolver->resolve(array(
- 'one' => 1.23,
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testResolveFailsIfOptionTypeNotAllowedMultipleOptions()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- 'two' => '2',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => 'string',
- 'two' => 'bool',
- ));
-
- $this->resolver->resolve(array(
- 'one' => 'foo',
- 'two' => 1.23,
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- */
- public function testResolveFailsIfOptionTypeNotAllowedAddTypes()
- {
- $this->resolver->setDefaults(array(
- 'one' => '1',
- ));
-
- $this->resolver->setAllowedTypes(array(
- 'one' => 'string',
- ));
- $this->resolver->addAllowedTypes(array(
- 'one' => 'bool',
- ));
-
- $this->resolver->resolve(array(
- 'one' => 1.23,
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testSetRequiredFailsIfDefaultIsPassed()
- {
- $this->resolver->setRequired(array(
- 'one' => '1',
- ));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testSetOptionalFailsIfDefaultIsPassed()
- {
- $this->resolver->setOptional(array(
- 'one' => '1',
- ));
- }
-
- public function testFluidInterface()
- {
- $this->resolver->setDefaults(array('one' => '1'))
- ->replaceDefaults(array('one' => '2'))
- ->setAllowedValues(array('one' => array('1', '2')))
- ->addAllowedValues(array('one' => array('3')))
- ->setRequired(array('two'))
- ->setOptional(array('three'));
-
- $options = array(
- 'two' => '2',
- );
-
- $this->assertEquals(array(
- 'one' => '2',
- 'two' => '2',
- ), $this->resolver->resolve($options));
- }
-
- public function testKnownIfDefaultWasSet()
- {
- $this->assertFalse($this->resolver->isKnown('foo'));
-
- $this->resolver->setDefaults(array(
- 'foo' => 'bar',
- ));
-
- $this->assertTrue($this->resolver->isKnown('foo'));
- }
-
- public function testKnownIfRequired()
- {
- $this->assertFalse($this->resolver->isKnown('foo'));
-
- $this->resolver->setRequired(array(
- 'foo',
- ));
-
- $this->assertTrue($this->resolver->isKnown('foo'));
- }
-
- public function testKnownIfOptional()
- {
- $this->assertFalse($this->resolver->isKnown('foo'));
-
- $this->resolver->setOptional(array(
- 'foo',
- ));
-
- $this->assertTrue($this->resolver->isKnown('foo'));
- }
-
- public function testRequiredIfRequired()
- {
- $this->assertFalse($this->resolver->isRequired('foo'));
-
- $this->resolver->setRequired(array(
- 'foo',
- ));
-
- $this->assertTrue($this->resolver->isRequired('foo'));
- }
-
- public function testNotRequiredIfRequiredAndDefaultValue()
- {
- $this->assertFalse($this->resolver->isRequired('foo'));
-
- $this->resolver->setRequired(array(
- 'foo',
- ));
- $this->resolver->setDefaults(array(
- 'foo' => 'bar',
- ));
-
- $this->assertFalse($this->resolver->isRequired('foo'));
- }
-
- public function testNormalizersTransformFinalOptions()
- {
- $this->resolver->setDefaults(array(
- 'foo' => 'bar',
- 'bam' => 'baz',
- ));
- $this->resolver->setNormalizers(array(
- 'foo' => function (Options $options, $value) {
- return $options['bam'].'['.$value.']';
- },
- ));
-
- $expected = array(
- 'foo' => 'baz[bar]',
- 'bam' => 'baz',
- );
-
- $this->assertEquals($expected, $this->resolver->resolve(array()));
-
- $expected = array(
- 'foo' => 'boo[custom]',
- 'bam' => 'boo',
- );
-
- $this->assertEquals($expected, $this->resolver->resolve(array(
- 'foo' => 'custom',
- 'bam' => 'boo',
- )));
- }
-
- public function testResolveWithoutOptionSucceedsIfRequiredAndDefaultValue()
- {
- $this->resolver->setRequired(array(
- 'foo',
- ));
- $this->resolver->setDefaults(array(
- 'foo' => 'bar',
- ));
-
- $this->assertEquals(array(
- 'foo' => 'bar'
- ), $this->resolver->resolve(array()));
- }
-
- public function testResolveWithoutOptionSucceedsIfDefaultValueAndRequired()
- {
- $this->resolver->setDefaults(array(
- 'foo' => 'bar',
- ));
- $this->resolver->setRequired(array(
- 'foo',
- ));
-
- $this->assertEquals(array(
- 'foo' => 'bar'
- ), $this->resolver->resolve(array()));
- }
-
- public function testResolveSucceedsIfOptionRequiredAndValueAllowed()
- {
- $this->resolver->setRequired(array(
- 'one', 'two',
- ));
- $this->resolver->setAllowedValues(array(
- 'two' => array('2'),
- ));
-
- $options = array(
- 'one' => '1',
- 'two' => '2'
- );
-
- $this->assertEquals($options, $this->resolver->resolve($options));
- }
-
- public function testClone()
- {
- $this->resolver->setDefaults(array('one' => '1'));
-
- $clone = clone $this->resolver;
-
- // Changes after cloning don't affect each other
- $this->resolver->setDefaults(array('two' => '2'));
- $clone->setDefaults(array('three' => '3'));
-
- $this->assertEquals(array(
- 'one' => '1',
- 'two' => '2',
- ), $this->resolver->resolve());
-
- $this->assertEquals(array(
- 'one' => '1',
- 'three' => '3',
- ), $clone->resolve());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\OptionsResolver\Tests;
-
-use Symfony\Component\OptionsResolver\Options;
-
-class OptionsTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var Options
- */
- private $options;
-
- protected function setUp()
- {
- $this->options = new Options();
- }
-
- public function testArrayAccess()
- {
- $this->assertFalse(isset($this->options['foo']));
- $this->assertFalse(isset($this->options['bar']));
-
- $this->options['foo'] = 0;
- $this->options['bar'] = 1;
-
- $this->assertTrue(isset($this->options['foo']));
- $this->assertTrue(isset($this->options['bar']));
-
- unset($this->options['bar']);
-
- $this->assertTrue(isset($this->options['foo']));
- $this->assertFalse(isset($this->options['bar']));
- $this->assertEquals(0, $this->options['foo']);
- }
-
- public function testCountable()
- {
- $this->options->set('foo', 0);
- $this->options->set('bar', 1);
-
- $this->assertCount(2, $this->options);
- }
-
- /**
- * @expectedException \OutOfBoundsException
- */
- public function testGetNonExisting()
- {
- $this->options->get('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testSetNotSupportedAfterGet()
- {
- $this->options->set('foo', 'bar');
- $this->options->get('foo');
- $this->options->set('foo', 'baz');
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testRemoveNotSupportedAfterGet()
- {
- $this->options->set('foo', 'bar');
- $this->options->get('foo');
- $this->options->remove('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testSetNormalizerNotSupportedAfterGet()
- {
- $this->options->set('foo', 'bar');
- $this->options->get('foo');
- $this->options->setNormalizer('foo', function () {});
- }
-
- public function testSetLazyOption()
- {
- $test = $this;
-
- $this->options->set('foo', function (Options $options) use ($test) {
- return 'dynamic';
- });
-
- $this->assertEquals('dynamic', $this->options->get('foo'));
- }
-
- public function testSetDiscardsPreviousValue()
- {
- $test = $this;
-
- // defined by superclass
- $this->options->set('foo', 'bar');
-
- // defined by subclass
- $this->options->set('foo', function (Options $options, $previousValue) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertNull($previousValue);
-
- return 'dynamic';
- });
-
- $this->assertEquals('dynamic', $this->options->get('foo'));
- }
-
- public function testOverloadKeepsPreviousValue()
- {
- $test = $this;
-
- // defined by superclass
- $this->options->set('foo', 'bar');
-
- // defined by subclass
- $this->options->overload('foo', function (Options $options, $previousValue) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals('bar', $previousValue);
-
- return 'dynamic';
- });
-
- $this->assertEquals('dynamic', $this->options->get('foo'));
- }
-
- public function testPreviousValueIsEvaluatedIfLazy()
- {
- $test = $this;
-
- // defined by superclass
- $this->options->set('foo', function (Options $options) {
- return 'bar';
- });
-
- // defined by subclass
- $this->options->overload('foo', function (Options $options, $previousValue) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals('bar', $previousValue);
-
- return 'dynamic';
- });
-
- $this->assertEquals('dynamic', $this->options->get('foo'));
- }
-
- public function testPreviousValueIsNotEvaluatedIfNoSecondArgument()
- {
- $test = $this;
-
- // defined by superclass
- $this->options->set('foo', function (Options $options) use ($test) {
- $test->fail('Should not be called');
- });
-
- // defined by subclass, no $previousValue argument defined!
- $this->options->overload('foo', function (Options $options) use ($test) {
- return 'dynamic';
- });
-
- $this->assertEquals('dynamic', $this->options->get('foo'));
- }
-
- public function testLazyOptionCanAccessOtherOptions()
- {
- $test = $this;
-
- $this->options->set('foo', 'bar');
-
- $this->options->set('bam', function (Options $options) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals('bar', $options->get('foo'));
-
- return 'dynamic';
- });
-
- $this->assertEquals('bar', $this->options->get('foo'));
- $this->assertEquals('dynamic', $this->options->get('bam'));
- }
-
- public function testLazyOptionCanAccessOtherLazyOptions()
- {
- $test = $this;
-
- $this->options->set('foo', function (Options $options) {
- return 'bar';
- });
-
- $this->options->set('bam', function (Options $options) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals('bar', $options->get('foo'));
-
- return 'dynamic';
- });
-
- $this->assertEquals('bar', $this->options->get('foo'));
- $this->assertEquals('dynamic', $this->options->get('bam'));
- }
-
- public function testNormalizer()
- {
- $this->options->set('foo', 'bar');
-
- $this->options->setNormalizer('foo', function () {
- return 'normalized';
- });
-
- $this->assertEquals('normalized', $this->options->get('foo'));
- }
-
- public function testNormalizerReceivesUnnormalizedValue()
- {
- $this->options->set('foo', 'bar');
-
- $this->options->setNormalizer('foo', function (Options $options, $value) {
- return 'normalized['.$value.']';
- });
-
- $this->assertEquals('normalized[bar]', $this->options->get('foo'));
- }
-
- public function testNormalizerCanAccessOtherOptions()
- {
- $test = $this;
-
- $this->options->set('foo', 'bar');
- $this->options->set('bam', 'baz');
-
- $this->options->setNormalizer('bam', function (Options $options) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals('bar', $options->get('foo'));
-
- return 'normalized';
- });
-
- $this->assertEquals('bar', $this->options->get('foo'));
- $this->assertEquals('normalized', $this->options->get('bam'));
- }
-
- public function testNormalizerCanAccessOtherLazyOptions()
- {
- $test = $this;
-
- $this->options->set('foo', function (Options $options) {
- return 'bar';
- });
- $this->options->set('bam', 'baz');
-
- $this->options->setNormalizer('bam', function (Options $options) use ($test) {
- /* @var \PHPUnit_Framework_TestCase $test */
- $test->assertEquals('bar', $options->get('foo'));
-
- return 'normalized';
- });
-
- $this->assertEquals('bar', $this->options->get('foo'));
- $this->assertEquals('normalized', $this->options->get('bam'));
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testFailForCyclicDependencies()
- {
- $this->options->set('foo', function (Options $options) {
- $options->get('bam');
- });
-
- $this->options->set('bam', function (Options $options) {
- $options->get('foo');
- });
-
- $this->options->get('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testFailForCyclicDependenciesBetweenNormalizers()
- {
- $this->options->set('foo', 'bar');
- $this->options->set('bam', 'baz');
-
- $this->options->setNormalizer('foo', function (Options $options) {
- $options->get('bam');
- });
-
- $this->options->setNormalizer('bam', function (Options $options) {
- $options->get('foo');
- });
-
- $this->options->get('foo');
- }
-
- /**
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testFailForCyclicDependenciesBetweenNormalizerAndLazyOption()
- {
- $this->options->set('foo', function (Options $options) {
- $options->get('bam');
- });
- $this->options->set('bam', 'baz');
-
- $this->options->setNormalizer('bam', function (Options $options) {
- $options->get('foo');
- });
-
- $this->options->get('foo');
- }
-
- public function testAllInvokesEachLazyOptionOnlyOnce()
- {
- $test = $this;
- $i = 1;
-
- $this->options->set('foo', function (Options $options) use ($test, &$i) {
- $test->assertSame(1, $i);
- ++$i;
-
- // Implicitly invoke lazy option for "bam"
- $options->get('bam');
- });
- $this->options->set('bam', function (Options $options) use ($test, &$i) {
- $test->assertSame(2, $i);
- ++$i;
- });
-
- $this->options->all();
- }
-
- public function testAllInvokesEachNormalizerOnlyOnce()
- {
- $test = $this;
- $i = 1;
-
- $this->options->set('foo', 'bar');
- $this->options->set('bam', 'baz');
-
- $this->options->setNormalizer('foo', function (Options $options) use ($test, &$i) {
- $test->assertSame(1, $i);
- ++$i;
-
- // Implicitly invoke normalizer for "bam"
- $options->get('bam');
- });
- $this->options->setNormalizer('bam', function (Options $options) use ($test, &$i) {
- $test->assertSame(2, $i);
- ++$i;
- });
-
- $this->options->all();
- }
-
- public function testReplaceClearsAndSets()
- {
- $this->options->set('one', '1');
-
- $this->options->replace(array(
- 'two' => '2',
- 'three' => function (Options $options) {
- return '2' === $options['two'] ? '3' : 'foo';
- }
- ));
-
- $this->assertEquals(array(
- 'two' => '2',
- 'three' => '3',
- ), $this->options->all());
- }
-
- public function testClearRemovesAllOptions()
- {
- $this->options->set('one', 1);
- $this->options->set('two', 2);
-
- $this->options->clear();
-
- $this->assertEmpty($this->options->all());
-
- }
-
- /**
- * @covers Symfony\Component\OptionsResolver\Options::replace
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testCannotReplaceAfterOptionWasRead()
- {
- $this->options->set('one', 1);
- $this->options->all();
-
- $this->options->replace(array(
- 'two' => '2',
- ));
- }
-
- /**
- * @covers Symfony\Component\OptionsResolver\Options::overload
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testCannotOverloadAfterOptionWasRead()
- {
- $this->options->set('one', 1);
- $this->options->all();
-
- $this->options->overload('one', 2);
- }
-
- /**
- * @covers Symfony\Component\OptionsResolver\Options::clear
- * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
- */
- public function testCannotClearAfterOptionWasRead()
- {
- $this->options->set('one', 1);
- $this->options->all();
-
- $this->options->clear();
- }
-
- public function testOverloadCannotBeEvaluatedLazilyWithoutExpectedClosureParams()
- {
- $this->options->set('foo', 'bar');
-
- $this->options->overload('foo', function () {
- return 'test';
- });
-
- $this->assertNotEquals('test', $this->options->get('foo'));
- $this->assertTrue(is_callable($this->options->get('foo')));
- }
-
- public function testOverloadCannotBeEvaluatedLazilyWithoutFirstParamTypeHint()
- {
- $this->options->set('foo', 'bar');
-
- $this->options->overload('foo', function ($object) {
- return 'test';
- });
-
- $this->assertNotEquals('test', $this->options->get('foo'));
- $this->assertTrue(is_callable($this->options->get('foo')));
- }
-
- public function testOptionsIteration()
- {
- $this->options->set('foo', 'bar');
- $this->options->set('foo1', 'bar1');
- $expectedResult = array('foo' => 'bar', 'foo1' => 'bar1');
-
- $this->assertEquals($expectedResult, iterator_to_array($this->options, true));
- }
-
- public function testHasWithNullValue()
- {
- $this->options->set('foo', null);
-
- $this->assertTrue($this->options->has('foo'));
- }
-
- public function testRemoveOptionAndNormalizer()
- {
- $this->options->set('foo1', 'bar');
- $this->options->setNormalizer('foo1', function (Options $options) {
- return '';
- });
- $this->options->set('foo2', 'bar');
- $this->options->setNormalizer('foo2', function (Options $options) {
- return '';
- });
-
- $this->options->remove('foo2');
- $this->assertEquals(array('foo1' => ''), $this->options->all());
- }
-
- public function testReplaceOptionAndNormalizer()
- {
- $this->options->set('foo1', 'bar');
- $this->options->setNormalizer('foo1', function (Options $options) {
- return '';
- });
- $this->options->set('foo2', 'bar');
- $this->options->setNormalizer('foo2', function (Options $options) {
- return '';
- });
-
- $this->options->replace(array('foo1' => 'new'));
- $this->assertEquals(array('foo1' => 'new'), $this->options->all());
- }
-
- public function testClearOptionAndNormalizer()
- {
- $this->options->set('foo1', 'bar');
- $this->options->setNormalizer('foo1', function (Options $options) {
- return '';
- });
- $this->options->set('foo2', 'bar');
- $this->options->setNormalizer('foo2', function (Options $options) {
- return '';
- });
-
- $this->options->clear();
- $this->assertEmpty($this->options->all());
- }
-
- public function testNormalizerWithoutCorrespondingOption()
- {
- $test = $this;
-
- $this->options->setNormalizer('foo', function (Options $options, $previousValue) use ($test) {
- $test->assertNull($previousValue);
-
- return '';
- });
- $this->assertEquals(array('foo' => ''), $this->options->all());
- }
-}
+++ /dev/null
-{
- "name": "symfony/options-resolver",
- "type": "library",
- "description": "Symfony OptionsResolver Component",
- "keywords": ["options", "config", "configuration"],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3"
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\OptionsResolver\\": "" }
- },
- "target-dir": "Symfony/Component/OptionsResolver",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony OptionsResolver Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./Resources</directory>
- <directory>./Tests</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-/Tests export-ignore
-phpunit.xml.dist export-ignore
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-CHANGELOG
-=========
-
-2.3.0
-------
-
- * added PropertyAccessorBuilder, to enable or disable the support of "__call"
- * added support for "__call" in the PropertyAccessor (disabled by default)
- * [BC BREAK] changed PropertyAccessor to continue its search for a property or
- method even if a non-public match was found. Before, a PropertyAccessDeniedException
- was thrown in this case. Class PropertyAccessDeniedException was removed
- now.
- * deprecated PropertyAccess::getPropertyAccessor
- * added PropertyAccess::createPropertyAccessor and PropertyAccess::createPropertyAccessorBuilder
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess\Exception;
-
-/**
- * Marker interface for the PropertyAccess component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess\Exception;
-
-/**
- * Thrown when a property path is malformed.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class InvalidPropertyPathException extends RuntimeException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess\Exception;
-
-/**
- * Thrown when a property cannot be found.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class NoSuchPropertyException extends RuntimeException
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess\Exception;
-
-/**
- * Base OutOfBoundsException for the PropertyAccess component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess\Exception;
-
-/**
- * Base RuntimeException for the PropertyAccess component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RuntimeException extends \RuntimeException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess\Exception;
-
-/**
- * Thrown when a value does not match an expected type.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class UnexpectedTypeException extends RuntimeException
-{
- public function __construct($value, $expectedType)
- {
- parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
- }
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-/**
- * Entry point of the PropertyAccess component.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-final class PropertyAccess
-{
- /**
- * Creates a property accessor with the default configuration.
- *
- * @return PropertyAccessor The new property accessor
- */
- public static function createPropertyAccessor()
- {
- return self::createPropertyAccessorBuilder()->getPropertyAccessor();
- }
-
- /**
- * Creates a property accessor builder.
- *
- * @return PropertyAccessorBuilder The new property accessor builder
- */
- public static function createPropertyAccessorBuilder()
- {
- return new PropertyAccessorBuilder();
- }
-
- /**
- * Alias of {@link getPropertyAccessor}.
- *
- * @return PropertyAccessor The new property accessor
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * {@link createPropertyAccessor()} instead.
- */
- public static function getPropertyAccessor()
- {
- return self::createPropertyAccessor();
- }
-
- /**
- * This class cannot be instantiated.
- */
- private function __construct()
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
-use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
-
-/**
- * Default implementation of {@link PropertyAccessorInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PropertyAccessor implements PropertyAccessorInterface
-{
- const VALUE = 0;
- const IS_REF = 1;
-
- private $magicCall;
-
- /**
- * Should not be used by application code. Use
- * {@link PropertyAccess::getPropertyAccessor()} instead.
- */
- public function __construct($magicCall = false)
- {
- $this->magicCall = $magicCall;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getValue($objectOrArray, $propertyPath)
- {
- if (is_string($propertyPath)) {
- $propertyPath = new PropertyPath($propertyPath);
- } elseif (!$propertyPath instanceof PropertyPathInterface) {
- throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface');
- }
-
- $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength());
-
- return $propertyValues[count($propertyValues) - 1][self::VALUE];
- }
-
- /**
- * {@inheritdoc}
- */
- public function setValue(&$objectOrArray, $propertyPath, $value)
- {
- if (is_string($propertyPath)) {
- $propertyPath = new PropertyPath($propertyPath);
- } elseif (!$propertyPath instanceof PropertyPathInterface) {
- throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface');
- }
-
- $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 1);
- $overwrite = true;
-
- // Add the root object to the list
- array_unshift($propertyValues, array(
- self::VALUE => &$objectOrArray,
- self::IS_REF => true,
- ));
-
- for ($i = count($propertyValues) - 1; $i >= 0; --$i) {
- $objectOrArray =& $propertyValues[$i][self::VALUE];
-
- if ($overwrite) {
- if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
- throw new UnexpectedTypeException($objectOrArray, 'object or array');
- }
-
- $property = $propertyPath->getElement($i);
- //$singular = $propertyPath->singulars[$i];
- $singular = null;
-
- if ($propertyPath->isIndex($i)) {
- $this->writeIndex($objectOrArray, $property, $value);
- } else {
- $this->writeProperty($objectOrArray, $property, $singular, $value);
- }
- }
-
- $value =& $objectOrArray;
- $overwrite = !$propertyValues[$i][self::IS_REF];
- }
- }
-
- /**
- * Reads the path from an object up to a given path index.
- *
- * @param object|array $objectOrArray The object or array to read from
- * @param PropertyPathInterface $propertyPath The property path to read
- * @param integer $lastIndex The index up to which should be read
- *
- * @return array The values read in the path.
- *
- * @throws UnexpectedTypeException If a value within the path is neither object nor array.
- */
- private function &readPropertiesUntil(&$objectOrArray, PropertyPathInterface $propertyPath, $lastIndex)
- {
- $propertyValues = array();
-
- for ($i = 0; $i < $lastIndex; ++$i) {
- if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
- throw new UnexpectedTypeException($objectOrArray, 'object or array');
- }
-
- $property = $propertyPath->getElement($i);
- $isIndex = $propertyPath->isIndex($i);
- $isArrayAccess = is_array($objectOrArray) || $objectOrArray instanceof \ArrayAccess;
-
- // Create missing nested arrays on demand
- if ($isIndex && $isArrayAccess && !isset($objectOrArray[$property])) {
- $objectOrArray[$property] = $i + 1 < $propertyPath->getLength() ? array() : null;
- }
-
- if ($isIndex) {
- $propertyValue =& $this->readIndex($objectOrArray, $property);
- } else {
- $propertyValue =& $this->readProperty($objectOrArray, $property);
- }
-
- $objectOrArray =& $propertyValue[self::VALUE];
-
- $propertyValues[] =& $propertyValue;
- }
-
- return $propertyValues;
- }
-
- /**
- * Reads a key from an array-like structure.
- *
- * @param \ArrayAccess|array $array The array or \ArrayAccess object to read from
- * @param string|integer $index The key to read
- *
- * @return mixed The value of the key
- *
- * @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array
- */
- private function &readIndex(&$array, $index)
- {
- if (!$array instanceof \ArrayAccess && !is_array($array)) {
- throw new NoSuchPropertyException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array)));
- }
-
- // Use an array instead of an object since performance is very crucial here
- $result = array(
- self::VALUE => null,
- self::IS_REF => false
- );
-
- if (isset($array[$index])) {
- if (is_array($array)) {
- $result[self::VALUE] =& $array[$index];
- $result[self::IS_REF] = true;
- } else {
- $result[self::VALUE] = $array[$index];
- // Objects are always passed around by reference
- $result[self::IS_REF] = is_object($array[$index]) ? true : false;
- }
- }
-
- return $result;
- }
-
- /**
- * Reads the a property from an object or array.
- *
- * @param object $object The object to read from.
- * @param string $property The property to read.
- *
- * @return mixed The value of the read property
- *
- * @throws NoSuchPropertyException If the property does not exist or is not
- * public.
- */
- private function &readProperty(&$object, $property)
- {
- // Use an array instead of an object since performance is
- // very crucial here
- $result = array(
- self::VALUE => null,
- self::IS_REF => false
- );
-
- if (!is_object($object)) {
- throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
- }
-
- $camelProp = $this->camelize($property);
- $reflClass = new \ReflectionClass($object);
- $getter = 'get'.$camelProp;
- $isser = 'is'.$camelProp;
- $hasser = 'has'.$camelProp;
- $classHasProperty = $reflClass->hasProperty($property);
-
- if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) {
- $result[self::VALUE] = $object->$getter();
- } elseif ($reflClass->hasMethod($isser) && $reflClass->getMethod($isser)->isPublic()) {
- $result[self::VALUE] = $object->$isser();
- } elseif ($reflClass->hasMethod($hasser) && $reflClass->getMethod($hasser)->isPublic()) {
- $result[self::VALUE] = $object->$hasser();
- } elseif ($reflClass->hasMethod('__get') && $reflClass->getMethod('__get')->isPublic()) {
- $result[self::VALUE] = $object->$property;
- } elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
- $result[self::VALUE] =& $object->$property;
- $result[self::IS_REF] = true;
- } elseif (!$classHasProperty && property_exists($object, $property)) {
- // Needed to support \stdClass instances. We need to explicitly
- // exclude $classHasProperty, otherwise if in the previous clause
- // a *protected* property was found on the class, property_exists()
- // returns true, consequently the following line will result in a
- // fatal error.
- $result[self::VALUE] =& $object->$property;
- $result[self::IS_REF] = true;
- } elseif ($this->magicCall && $reflClass->hasMethod('__call') && $reflClass->getMethod('__call')->isPublic()) {
- // we call the getter and hope the __call do the job
- $result[self::VALUE] = $object->$getter();
- } else {
- throw new NoSuchPropertyException(sprintf(
- 'Neither the property "%s" nor one of the methods "%s()", '.
- '"%s()", "%s()", "__get()" or "__call()" exist and have public access in '.
- 'class "%s".',
- $property,
- $getter,
- $isser,
- $hasser,
- $reflClass->name
- ));
- }
-
- // Objects are always passed around by reference
- if (is_object($result[self::VALUE])) {
- $result[self::IS_REF] = true;
- }
-
- return $result;
- }
-
- /**
- * Sets the value of the property at the given index in the path
- *
- * @param \ArrayAccess|array $array An array or \ArrayAccess object to write to
- * @param string|integer $index The index to write at
- * @param mixed $value The value to write
- *
- * @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array
- */
- private function writeIndex(&$array, $index, $value)
- {
- if (!$array instanceof \ArrayAccess && !is_array($array)) {
- throw new NoSuchPropertyException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array)));
- }
-
- $array[$index] = $value;
- }
-
- /**
- * Sets the value of the property at the given index in the path
- *
- * @param object|array $object The object or array to write to
- * @param string $property The property to write
- * @param string|null $singular The singular form of the property name or null
- * @param mixed $value The value to write
- *
- * @throws NoSuchPropertyException If the property does not exist or is not
- * public.
- */
- private function writeProperty(&$object, $property, $singular, $value)
- {
- $guessedAdders = '';
-
- if (!is_object($object)) {
- throw new NoSuchPropertyException(sprintf('Cannot write property "%s" to an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
- }
-
- $reflClass = new \ReflectionClass($object);
- $plural = $this->camelize($property);
-
- // Any of the two methods is required, but not yet known
- $singulars = null !== $singular ? array($singular) : (array) StringUtil::singularify($plural);
-
- if (is_array($value) || $value instanceof \Traversable) {
- $methods = $this->findAdderAndRemover($reflClass, $singulars);
-
- if (null !== $methods) {
- // At this point the add and remove methods have been found
- // Use iterator_to_array() instead of clone in order to prevent side effects
- // see https://github.com/symfony/symfony/issues/4670
- $itemsToAdd = is_object($value) ? iterator_to_array($value) : $value;
- $itemToRemove = array();
- $propertyValue = $this->readProperty($object, $property);
- $previousValue = $propertyValue[self::VALUE];
-
- if (is_array($previousValue) || $previousValue instanceof \Traversable) {
- foreach ($previousValue as $previousItem) {
- foreach ($value as $key => $item) {
- if ($item === $previousItem) {
- // Item found, don't add
- unset($itemsToAdd[$key]);
-
- // Next $previousItem
- continue 2;
- }
- }
-
- // Item not found, add to remove list
- $itemToRemove[] = $previousItem;
- }
- }
-
- foreach ($itemToRemove as $item) {
- call_user_func(array($object, $methods[1]), $item);
- }
-
- foreach ($itemsToAdd as $item) {
- call_user_func(array($object, $methods[0]), $item);
- }
-
- return;
- } else {
- // It is sufficient to include only the adders in the error
- // message. If the user implements the adder but not the remover,
- // an exception will be thrown in findAdderAndRemover() that
- // the remover has to be implemented as well.
- $guessedAdders = '"add'.implode('()", "add', $singulars).'()", ';
- }
- }
-
- $setter = 'set'.$this->camelize($property);
- $classHasProperty = $reflClass->hasProperty($property);
-
- if ($reflClass->hasMethod($setter) && $reflClass->getMethod($setter)->isPublic()) {
- $object->$setter($value);
- } elseif ($reflClass->hasMethod('__set') && $reflClass->getMethod('__set')->isPublic()) {
- $object->$property = $value;
- } elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
- $object->$property = $value;
- } elseif (!$classHasProperty && property_exists($object, $property)) {
- // Needed to support \stdClass instances. We need to explicitly
- // exclude $classHasProperty, otherwise if in the previous clause
- // a *protected* property was found on the class, property_exists()
- // returns true, consequently the following line will result in a
- // fatal error.
- $object->$property = $value;
- } elseif ($this->magicCall && $reflClass->hasMethod('__call') && $reflClass->getMethod('__call')->isPublic()) {
- // we call the getter and hope the __call do the job
- $object->$setter($value);
- } else {
- throw new NoSuchPropertyException(sprintf(
- 'Neither the property "%s" nor one of the methods %s"%s()", '.
- '"__set()" or "__call()" exist and have public access in class "%s".',
- $property,
- $guessedAdders,
- $setter,
- $reflClass->name
- ));
- }
- }
-
- /**
- * Camelizes a given string.
- *
- * @param string $string Some string
- *
- * @return string The camelized version of the string
- */
- private function camelize($string)
- {
- return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $string);
- }
-
- /**
- * Searches for add and remove methods.
- *
- * @param \ReflectionClass $reflClass The reflection class for the given object
- * @param array $singulars The singular form of the property name or null
- *
- * @return array|null An array containing the adder and remover when found, null otherwise
- *
- * @throws NoSuchPropertyException If the property does not exist
- */
- private function findAdderAndRemover(\ReflectionClass $reflClass, array $singulars)
- {
- foreach ($singulars as $singular) {
- $addMethod = 'add'.$singular;
- $removeMethod = 'remove'.$singular;
-
- $addMethodFound = $this->isAccessible($reflClass, $addMethod, 1);
- $removeMethodFound = $this->isAccessible($reflClass, $removeMethod, 1);
-
- if ($addMethodFound && $removeMethodFound) {
- return array($addMethod, $removeMethod);
- }
-
- if ($addMethodFound xor $removeMethodFound) {
- throw new NoSuchPropertyException(sprintf(
- 'Found the public method "%s()", but did not find a public "%s()" on class %s',
- $addMethodFound ? $addMethod : $removeMethod,
- $addMethodFound ? $removeMethod : $addMethod,
- $reflClass->name
- ));
- }
- }
-
- return null;
- }
-
- /**
- * Returns whether a method is public and has a specific number of required parameters.
- *
- * @param \ReflectionClass $class The class of the method
- * @param string $methodName The method name
- * @param integer $parameters The number of parameters
- *
- * @return Boolean Whether the method is public and has $parameters
- * required parameters
- */
- private function isAccessible(\ReflectionClass $class, $methodName, $parameters)
- {
- if ($class->hasMethod($methodName)) {
- $method = $class->getMethod($methodName);
-
- if ($method->isPublic() && $method->getNumberOfRequiredParameters() === $parameters) {
- return true;
- }
- }
-
- return false;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-/**
- * A configurable builder for PropertyAccessorInterface objects.
- *
- * @author Jérémie Augustin <jeremie.augustin@pixel-cookers.com>
- */
-class PropertyAccessorBuilder
-{
- /**
- * @var Boolean
- */
- private $magicCall = false;
-
- /**
- * Enables the use of "__call" by the ProperyAccessor.
- *
- * @return PropertyAccessorBuilder The builder object
- */
- public function enableMagicCall()
- {
- $this->magicCall = true;
-
- return $this;
- }
-
- /**
- * Disables the use of "__call" by the ProperyAccessor.
- *
- * @return PropertyAccessorBuilder The builder object
- */
- public function disableMagicCall()
- {
- $this->magicCall = false;
-
- return $this;
- }
-
- /**
- * @return Boolean true if the use of "__call" by the ProperyAccessor is enabled
- */
- public function isMagicCallEnabled()
- {
- return $this->magicCall;
- }
-
- /**
- * Builds and returns a new propertyAccessor object.
- *
- * @return PropertyAccessorInterface The built propertyAccessor
- */
- public function getPropertyAccessor()
- {
- return new PropertyAccessor($this->magicCall);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-/**
- * Writes and reads values to/from an object/array graph.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface PropertyAccessorInterface
-{
- /**
- * Sets the value at the end of the property path of the object
- *
- * Example:
- *
- * use Symfony\Component\PropertyAccess\PropertyAccess;
- *
- * $propertyAccessor = PropertyAccess::getPropertyAccessor();
- *
- * echo $propertyAccessor->setValue($object, 'child.name', 'Fabien');
- * // equals echo $object->getChild()->setName('Fabien');
- *
- * This method first tries to find a public setter for each property in the
- * path. The name of the setter must be the camel-cased property name
- * prefixed with "set".
- *
- * If the setter does not exist, this method tries to find a public
- * property. The value of the property is then changed.
- *
- * If neither is found, an exception is thrown.
- *
- * @param object|array $objectOrArray The object or array to modify
- * @param string|PropertyPathInterface $propertyPath The property path to modify
- * @param mixed $value The value to set at the end of the property path
- *
- * @throws Exception\NoSuchPropertyException If a property does not exist or is not public.
- * @throws Exception\UnexpectedTypeException If a value within the path is neither object
- * nor array
- */
- public function setValue(&$objectOrArray, $propertyPath, $value);
-
- /**
- * Returns the value at the end of the property path of the object
- *
- * Example:
- *
- * use Symfony\Component\PropertyAccess\PropertyAccess;
- *
- * $propertyAccessor = PropertyAccess::getPropertyAccessor();
- *
- * echo $propertyAccessor->getValue($object, 'child.name);
- * // equals echo $object->getChild()->getName();
- *
- * This method first tries to find a public getter for each property in the
- * path. The name of the getter must be the camel-cased property name
- * prefixed with "get", "is", or "has".
- *
- * If the getter does not exist, this method tries to find a public
- * property. The value of the property is then returned.
- *
- * If none of them are found, an exception is thrown.
- *
- * @param object|array $objectOrArray The object or array to traverse
- * @param string|PropertyPathInterface $propertyPath The property path to read
- *
- * @return mixed The value at the end of the property path
- *
- * @throws Exception\NoSuchPropertyException If a property does not exist or is not public.
- */
- public function getValue($objectOrArray, $propertyPath);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-use Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException;
-use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException;
-use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
-
-/**
- * Default implementation of {@link PropertyPathInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PropertyPath implements \IteratorAggregate, PropertyPathInterface
-{
- /**
- * Character used for separating between plural and singular of an element.
- * @var string
- */
- const SINGULAR_SEPARATOR = '|';
-
- /**
- * The elements of the property path
- * @var array
- */
- private $elements = array();
-
- /**
- * The singular forms of the elements in the property path.
- * @var array
- */
- private $singulars = array();
-
- /**
- * The number of elements in the property path
- * @var integer
- */
- private $length;
-
- /**
- * Contains a Boolean for each property in $elements denoting whether this
- * element is an index. It is a property otherwise.
- * @var array
- */
- private $isIndex = array();
-
- /**
- * String representation of the path
- * @var string
- */
- private $pathAsString;
-
- /**
- * Constructs a property path from a string.
- *
- * @param PropertyPath|string $propertyPath The property path as string or instance
- *
- * @throws UnexpectedTypeException If the given path is not a string
- * @throws InvalidPropertyPathException If the syntax of the property path is not valid
- */
- public function __construct($propertyPath)
- {
- // Can be used as copy constructor
- if ($propertyPath instanceof PropertyPath) {
- /* @var PropertyPath $propertyPath */
- $this->elements = $propertyPath->elements;
- $this->singulars = $propertyPath->singulars;
- $this->length = $propertyPath->length;
- $this->isIndex = $propertyPath->isIndex;
- $this->pathAsString = $propertyPath->pathAsString;
-
- return;
- }
- if (!is_string($propertyPath)) {
- throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPath');
- }
-
- if ('' === $propertyPath) {
- throw new InvalidPropertyPathException('The property path should not be empty.');
- }
-
- $this->pathAsString = $propertyPath;
- $position = 0;
- $remaining = $propertyPath;
-
- // first element is evaluated differently - no leading dot for properties
- $pattern = '/^(([^\.\[]+)|\[([^\]]+)\])(.*)/';
-
- while (preg_match($pattern, $remaining, $matches)) {
- if ('' !== $matches[2]) {
- $element = $matches[2];
- $this->isIndex[] = false;
- } else {
- $element = $matches[3];
- $this->isIndex[] = true;
- }
- // Disabled this behaviour as the syntax is not yet final
- //$pos = strpos($element, self::SINGULAR_SEPARATOR);
- $pos = false;
- $singular = null;
-
- if (false !== $pos) {
- $singular = substr($element, $pos + 1);
- $element = substr($element, 0, $pos);
- }
-
- $this->elements[] = $element;
- $this->singulars[] = $singular;
-
- $position += strlen($matches[1]);
- $remaining = $matches[4];
- $pattern = '/^(\.(\w+)|\[([^\]]+)\])(.*)/';
- }
-
- if ('' !== $remaining) {
- throw new InvalidPropertyPathException(sprintf(
- 'Could not parse property path "%s". Unexpected token "%s" at position %d',
- $propertyPath,
- $remaining{0},
- $position
- ));
- }
-
- $this->length = count($this->elements);
- }
-
- /**
- * {@inheritdoc}
- */
- public function __toString()
- {
- return $this->pathAsString;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLength()
- {
- return $this->length;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getParent()
- {
- if ($this->length <= 1) {
- return null;
- }
-
- $parent = clone $this;
-
- --$parent->length;
- $parent->pathAsString = substr($parent->pathAsString, 0, max(strrpos($parent->pathAsString, '.'), strrpos($parent->pathAsString, '[')));
- array_pop($parent->elements);
- array_pop($parent->singulars);
- array_pop($parent->isIndex);
-
- return $parent;
- }
-
- /**
- * Returns a new iterator for this path
- *
- * @return PropertyPathIteratorInterface
- */
- public function getIterator()
- {
- return new PropertyPathIterator($this);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getElements()
- {
- return $this->elements;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getElement($index)
- {
- if (!isset($this->elements[$index])) {
- throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
- }
-
- return $this->elements[$index];
- }
-
- /**
- * {@inheritdoc}
- */
- public function isProperty($index)
- {
- if (!isset($this->isIndex[$index])) {
- throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
- }
-
- return !$this->isIndex[$index];
- }
-
- /**
- * {@inheritdoc}
- */
- public function isIndex($index)
- {
- if (!isset($this->isIndex[$index])) {
- throw new OutOfBoundsException(sprintf('The index %s is not within the property path', $index));
- }
-
- return $this->isIndex[$index];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PropertyPathBuilder
-{
- /**
- * @var array
- */
- private $elements = array();
-
- /**
- * @var array
- */
- private $isIndex = array();
-
- /**
- * Creates a new property path builder.
- *
- * @param null|PropertyPathInterface|string $path The path to initially store
- * in the builder. Optional.
- */
- public function __construct($path = null)
- {
- if (null !== $path) {
- $this->append($path);
- }
- }
-
- /**
- * Appends a (sub-) path to the current path.
- *
- * @param PropertyPathInterface|string $path The path to append.
- * @param integer $offset The offset where the appended
- * piece starts in $path.
- * @param integer $length The length of the appended piece.
- * If 0, the full path is appended.
- */
- public function append($path, $offset = 0, $length = 0)
- {
- if (is_string($path)) {
- $path = new PropertyPath($path);
- }
-
- if (0 === $length) {
- $end = $path->getLength();
- } else {
- $end = $offset + $length;
- }
-
- for (; $offset < $end; ++$offset) {
- $this->elements[] = $path->getElement($offset);
- $this->isIndex[] = $path->isIndex($offset);
- }
- }
-
- /**
- * Appends an index element to the current path.
- *
- * @param string $name The name of the appended index
- */
- public function appendIndex($name)
- {
- $this->elements[] = $name;
- $this->isIndex[] = true;
- }
-
- /**
- * Appends a property element to the current path.
- *
- * @param string $name The name of the appended property
- */
- public function appendProperty($name)
- {
- $this->elements[] = $name;
- $this->isIndex[] = false;
- }
-
- /**
- * Removes elements from the current path.
- *
- * @param integer $offset The offset at which to remove
- * @param integer $length The length of the removed piece
- *
- * @throws OutOfBoundsException if offset is invalid
- */
- public function remove($offset, $length = 1)
- {
- if (!isset($this->elements[$offset])) {
- throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
- }
-
- $this->resize($offset, $length, 0);
- }
-
- /**
- * Replaces a sub-path by a different (sub-) path.
- *
- * @param integer $offset The offset at which to replace.
- * @param integer $length The length of the piece to replace.
- * @param PropertyPathInterface|string $path The path to insert.
- * @param integer $pathOffset The offset where the inserted piece
- * starts in $path.
- * @param integer $pathLength The length of the inserted piece.
- * If 0, the full path is inserted.
- *
- * @throws OutOfBoundsException If the offset is invalid
- */
- public function replace($offset, $length, $path, $pathOffset = 0, $pathLength = 0)
- {
- if (is_string($path)) {
- $path = new PropertyPath($path);
- }
-
- if ($offset < 0 && abs($offset) <= $this->getLength()) {
- $offset = $this->getLength() + $offset;
- } elseif (!isset($this->elements[$offset])) {
- throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path');
- }
-
- if (0 === $pathLength) {
- $pathLength = $path->getLength() - $pathOffset;
- }
-
- $this->resize($offset, $length, $pathLength);
-
- for ($i = 0; $i < $pathLength; ++$i) {
- $this->elements[$offset + $i] = $path->getElement($pathOffset + $i);
- $this->isIndex[$offset + $i] = $path->isIndex($pathOffset + $i);
- }
- }
-
- /**
- * Replaces a property element by an index element.
- *
- * @param integer $offset The offset at which to replace
- * @param string $name The new name of the element. Optional.
- *
- * @throws OutOfBoundsException If the offset is invalid
- */
- public function replaceByIndex($offset, $name = null)
- {
- if (!isset($this->elements[$offset])) {
- throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
- }
-
- if (null !== $name) {
- $this->elements[$offset] = $name;
- }
-
- $this->isIndex[$offset] = true;
- }
-
- /**
- * Replaces an index element by a property element.
- *
- * @param integer $offset The offset at which to replace
- * @param string $name The new name of the element. Optional.
- *
- * @throws OutOfBoundsException If the offset is invalid
- */
- public function replaceByProperty($offset, $name = null)
- {
- if (!isset($this->elements[$offset])) {
- throw new OutOfBoundsException(sprintf('The offset %s is not within the property path', $offset));
- }
-
- if (null !== $name) {
- $this->elements[$offset] = $name;
- }
-
- $this->isIndex[$offset] = false;
- }
-
- /**
- * Returns the length of the current path.
- *
- * @return integer The path length
- */
- public function getLength()
- {
- return count($this->elements);
- }
-
- /**
- * Returns the current property path.
- *
- * @return PropertyPathInterface The constructed property path
- */
- public function getPropertyPath()
- {
- $pathAsString = $this->__toString();
-
- return '' !== $pathAsString ? new PropertyPath($pathAsString) : null;
- }
-
- /**
- * Returns the current property path as string.
- *
- * @return string The property path as string
- */
- public function __toString()
- {
- $string = '';
-
- foreach ($this->elements as $offset => $element) {
- if ($this->isIndex[$offset]) {
- $element = '['.$element.']';
- } elseif ('' !== $string) {
- $string .= '.';
- }
-
- $string .= $element;
- }
-
- return $string;
- }
-
- /**
- * Resizes the path so that a chunk of length $cutLength is
- * removed at $offset and another chunk of length $insertionLength
- * can be inserted.
- *
- * @param integer $offset The offset where the removed chunk starts
- * @param integer $cutLength The length of the removed chunk
- * @param integer $insertionLength The length of the inserted chunk
- */
- private function resize($offset, $cutLength, $insertionLength)
- {
- // Nothing else to do in this case
- if ($insertionLength === $cutLength) {
- return;
- }
-
- $length = count($this->elements);
-
- if ($cutLength > $insertionLength) {
- // More elements should be removed than inserted
- $diff = $cutLength - $insertionLength;
- $newLength = $length - $diff;
-
- // Shift elements to the left (left-to-right until the new end)
- // Max allowed offset to be shifted is such that
- // $offset + $diff < $length (otherwise invalid index access)
- // i.e. $offset < $length - $diff = $newLength
- for ($i = $offset; $i < $newLength; ++$i) {
- $this->elements[$i] = $this->elements[$i + $diff];
- $this->isIndex[$i] = $this->isIndex[$i + $diff];
- }
-
- // All remaining elements should be removed
- for (; $i < $length; ++$i) {
- unset($this->elements[$i]);
- unset($this->isIndex[$i]);
- }
- } else {
- $diff = $insertionLength - $cutLength;
-
- $newLength = $length + $diff;
- $indexAfterInsertion = $offset + $insertionLength;
-
- // $diff <= $insertionLength
- // $indexAfterInsertion >= $insertionLength
- // => $diff <= $indexAfterInsertion
-
- // In each of the following loops, $i >= $diff must hold,
- // otherwise ($i - $diff) becomes negative.
-
- // Shift old elements to the right to make up space for the
- // inserted elements. This needs to be done left-to-right in
- // order to preserve an ascending array index order
- // Since $i = max($length, $indexAfterInsertion) and $indexAfterInsertion >= $diff,
- // $i >= $diff is guaranteed.
- for ($i = max($length, $indexAfterInsertion); $i < $newLength; ++$i) {
- $this->elements[$i] = $this->elements[$i - $diff];
- $this->isIndex[$i] = $this->isIndex[$i - $diff];
- }
-
- // Shift remaining elements to the right. Do this right-to-left
- // so we don't overwrite elements before copying them
- // The last written index is the immediate index after the inserted
- // string, because the indices before that will be overwritten
- // anyway.
- // Since $i >= $indexAfterInsertion and $indexAfterInsertion >= $diff,
- // $i >= $diff is guaranteed.
- for ($i = $length - 1; $i >= $indexAfterInsertion; --$i) {
- $this->elements[$i] = $this->elements[$i - $diff];
- $this->isIndex[$i] = $this->isIndex[$i - $diff];
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-/**
- * A sequence of property names or array indices.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface PropertyPathInterface extends \Traversable
-{
- /**
- * Returns the string representation of the property path
- *
- * @return string The path as string
- */
- public function __toString();
-
- /**
- * Returns the length of the property path, i.e. the number of elements.
- *
- * @return integer The path length
- */
- public function getLength();
-
- /**
- * Returns the parent property path.
- *
- * The parent property path is the one that contains the same items as
- * this one except for the last one.
- *
- * If this property path only contains one item, null is returned.
- *
- * @return PropertyPath The parent path or null
- */
- public function getParent();
-
- /**
- * Returns the elements of the property path as array
- *
- * @return array An array of property/index names
- */
- public function getElements();
-
- /**
- * Returns the element at the given index in the property path
- *
- * @param integer $index The index key
- *
- * @return string A property or index name
- *
- * @throws Exception\OutOfBoundsException If the offset is invalid
- */
- public function getElement($index);
-
- /**
- * Returns whether the element at the given index is a property
- *
- * @param integer $index The index in the property path
- *
- * @return Boolean Whether the element at this index is a property
- *
- * @throws Exception\OutOfBoundsException If the offset is invalid
- */
- public function isProperty($index);
-
- /**
- * Returns whether the element at the given index is an array index
- *
- * @param integer $index The index in the property path
- *
- * @return Boolean Whether the element at this index is an array index
- *
- * @throws Exception\OutOfBoundsException If the offset is invalid
- */
- public function isIndex($index);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-/**
- * Traverses a property path and provides additional methods to find out
- * information about the current element
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class PropertyPathIterator extends \ArrayIterator implements PropertyPathIteratorInterface
-{
- /**
- * The traversed property path
- * @var PropertyPathInterface
- */
- protected $path;
-
- /**
- * Constructor.
- *
- * @param PropertyPathInterface $path The property path to traverse
- */
- public function __construct(PropertyPathInterface $path)
- {
- parent::__construct($path->getElements());
-
- $this->path = $path;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isIndex()
- {
- return $this->path->isIndex($this->key());
- }
-
- /**
- * {@inheritdoc}
- */
- public function isProperty()
- {
- return $this->path->isProperty($this->key());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface PropertyPathIteratorInterface extends \Iterator, \SeekableIterator
-{
- /**
- * Returns whether the current element in the property path is an array
- * index.
- *
- * @return Boolean
- */
- public function isIndex();
-
- /**
- * Returns whether the current element in the property path is a property
- * name.
- *
- * @return Boolean
- */
- public function isProperty();
-}
+++ /dev/null
-PropertyAccess Component
-========================
-
-PropertyAccess reads/writes values from/to object/array graphs using a simple
-string notation.
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/PropertyAccess/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\PropertyAccess;
-
-/**
- * Creates singulars from plurals.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class StringUtil
-{
- /**
- * Map english plural to singular suffixes
- *
- * @var array
- *
- * @see http://english-zone.com/spelling/plurals.html
- * @see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English
- */
- private static $pluralMap = array(
- // First entry: plural suffix, reversed
- // Second entry: length of plural suffix
- // Third entry: Whether the suffix may succeed a vocal
- // Fourth entry: Whether the suffix may succeed a consonant
- // Fifth entry: singular suffix, normal
-
- // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
- array('a', 1, true, true, array('on', 'um')),
-
- // nebulae (nebula)
- array('ea', 2, true, true, 'a'),
-
- // mice (mouse), lice (louse)
- array('eci', 3, false, true, 'ouse'),
-
- // geese (goose)
- array('esee', 4, false, true, 'oose'),
-
- // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
- array('i', 1, true, true, 'us'),
-
- // men (man), women (woman)
- array('nem', 3, true, true, 'man'),
-
- // children (child)
- array('nerdlihc', 8, true, true, 'child'),
-
- // oxen (ox)
- array('nexo', 4, false, false, 'ox'),
-
- // indices (index), appendices (appendix), prices (price)
- array('seci', 4, false, true, array('ex', 'ix', 'ice')),
-
- // babies (baby)
- array('sei', 3, false, true, 'y'),
-
- // analyses (analysis), ellipses (ellipsis), funguses (fungus),
- // neuroses (neurosis), theses (thesis), emphases (emphasis),
- // oases (oasis), crises (crisis), houses (house), bases (base),
- // atlases (atlas), kisses (kiss)
- array('ses', 3, true, true, array('s', 'se', 'sis')),
-
- // objectives (objective), alternative (alternatives)
- array('sevit', 5, true, true, 'tive'),
-
- // lives (life), wives (wife)
- array('sevi', 4, false, true, 'ife'),
-
- // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
- array('sev', 3, true, true, 'f'),
-
- // axes (axis), axes (ax), axes (axe)
- array('sexa', 4, false, false, array('ax', 'axe', 'axis')),
-
- // indexes (index), matrixes (matrix)
- array('sex', 3, true, false, 'x'),
-
- // quizzes (quiz)
- array('sezz', 4, true, false, 'z'),
-
- // bureaus (bureau)
- array('suae', 4, false, true, 'eau'),
-
- // roses (rose), garages (garage), cassettes (cassette),
- // waltzes (waltz), heroes (hero), bushes (bush), arches (arch),
- // shoes (shoe)
- array('se', 2, true, true, array('', 'e')),
-
- // tags (tag)
- array('s', 1, true, true, ''),
-
- // chateaux (chateau)
- array('xuae', 4, false, true, 'eau'),
- );
-
- /**
- * This class should not be instantiated
- */
- private function __construct() {}
-
- /**
- * Returns the singular form of a word
- *
- * If the method can't determine the form with certainty, an array of the
- * possible singulars is returned.
- *
- * @param string $plural A word in plural form
- * @return string|array The singular form or an array of possible singular
- * forms
- */
- public static function singularify($plural)
- {
- $pluralRev = strrev($plural);
- $lowerPluralRev = strtolower($pluralRev);
- $pluralLength = strlen($lowerPluralRev);
-
- // The outer loop iterates over the entries of the plural table
- // The inner loop $j iterates over the characters of the plural suffix
- // in the plural table to compare them with the characters of the actual
- // given plural suffix
- foreach (self::$pluralMap as $map) {
- $suffix = $map[0];
- $suffixLength = $map[1];
- $j = 0;
-
- // Compare characters in the plural table and of the suffix of the
- // given plural one by one
- while ($suffix[$j] === $lowerPluralRev[$j]) {
- // Let $j point to the next character
- ++$j;
-
- // Successfully compared the last character
- // Add an entry with the singular suffix to the singular array
- if ($j === $suffixLength) {
- // Is there any character preceding the suffix in the plural string?
- if ($j < $pluralLength) {
- $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]);
-
- if (!$map[2] && $nextIsVocal) {
- // suffix may not succeed a vocal but next char is one
- break;
- }
-
- if (!$map[3] && !$nextIsVocal) {
- // suffix may not succeed a consonant but next char is one
- break;
- }
- }
-
- $newBase = substr($plural, 0, $pluralLength - $suffixLength);
- $newSuffix = $map[4];
-
- // Check whether the first character in the plural suffix
- // is uppercased. If yes, uppercase the first character in
- // the singular suffix too
- $firstUpper = ctype_upper($pluralRev[$j - 1]);
-
- if (is_array($newSuffix)) {
- $singulars = array();
-
- foreach ($newSuffix as $newSuffixEntry) {
- $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
- }
-
- return $singulars;
- }
-
- return $newBase.($firstUpper ? ucFirst($newSuffix) : $newSuffix);
- }
-
- // Suffix is longer than word
- if ($j === $pluralLength) {
- break;
- }
- }
- }
-
- // Convert teeth to tooth, feet to foot
- if (false !== ($pos = strpos($plural, 'ee'))) {
- return substr_replace($plural, 'oo', $pos, 2);
- }
-
- // Assume that plural and singular is identical
- return $plural;
- }
-}
+++ /dev/null
-{
- "name": "symfony/property-access",
- "type": "library",
- "description": "Symfony PropertyAccess Component",
- "keywords": ["property", "index", "access", "object", "array", "extraction", "injection", "reflection", "property path"],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3"
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\PropertyAccess\\": "" }
- },
- "target-dir": "Symfony/Component/PropertyAccess",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Annotation;
-
-/**
- * Annotation class for @Route().
- *
- * @Annotation
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Route
-{
- private $path;
- private $name;
- private $requirements;
- private $options;
- private $defaults;
- private $host;
- private $methods;
- private $schemes;
-
- /**
- * Constructor.
- *
- * @param array $data An array of key/value parameters.
- *
- * @throws \BadMethodCallException
- */
- public function __construct(array $data)
- {
- $this->requirements = array();
- $this->options = array();
- $this->defaults = array();
- $this->methods = array();
- $this->schemes = array();
-
- if (isset($data['value'])) {
- $data['path'] = $data['value'];
- unset($data['value']);
- }
-
- foreach ($data as $key => $value) {
- $method = 'set'.str_replace('_', '', $key);
- if (!method_exists($this, $method)) {
- throw new \BadMethodCallException(sprintf("Unknown property '%s' on annotation '%s'.", $key, get_class($this)));
- }
- $this->$method($value);
- }
- }
-
- /**
- * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
- */
- public function setPattern($pattern)
- {
- $this->path = $pattern;
- }
-
- /**
- * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
- */
- public function getPattern()
- {
- return $this->path;
- }
-
- public function setPath($path)
- {
- $this->path = $path;
- }
-
- public function getPath()
- {
- return $this->path;
- }
-
- public function setHost($pattern)
- {
- $this->host = $pattern;
- }
-
- public function getHost()
- {
- return $this->host;
- }
-
- public function setName($name)
- {
- $this->name = $name;
- }
-
- public function getName()
- {
- return $this->name;
- }
-
- public function setRequirements($requirements)
- {
- $this->requirements = $requirements;
- }
-
- public function getRequirements()
- {
- return $this->requirements;
- }
-
- public function setOptions($options)
- {
- $this->options = $options;
- }
-
- public function getOptions()
- {
- return $this->options;
- }
-
- public function setDefaults($defaults)
- {
- $this->defaults = $defaults;
- }
-
- public function getDefaults()
- {
- return $this->defaults;
- }
-
- public function setSchemes($schemes)
- {
- $this->schemes = is_array($schemes) ? $schemes : array($schemes);
- }
-
- public function getSchemes()
- {
- return $this->schemes;
- }
-
- public function setMethods($methods)
- {
- $this->methods = is_array($methods) ? $methods : array($methods);
- }
-
- public function getMethods()
- {
- return $this->methods;
- }
-}
+++ /dev/null
-CHANGELOG
-=========
-
-2.3.0
------
-
- * added RequestContext::getQueryString()
-
-2.2.0
------
-
- * [DEPRECATION] Several route settings have been renamed (the old ones will be removed in 3.0):
-
- * The `pattern` setting for a route has been deprecated in favor of `path`
- * The `_scheme` and `_method` requirements have been moved to the `schemes` and `methods` settings
-
- Before:
-
- ```
- article_edit:
- pattern: /article/{id}
- requirements: { '_method': 'POST|PUT', '_scheme': 'https', 'id': '\d+' }
-
- <route id="article_edit" pattern="/article/{id}">
- <requirement key="_method">POST|PUT</requirement>
- <requirement key="_scheme">https</requirement>
- <requirement key="id">\d+</requirement>
- </route>
-
- $route = new Route();
- $route->setPattern('/article/{id}');
- $route->setRequirement('_method', 'POST|PUT');
- $route->setRequirement('_scheme', 'https');
- ```
-
- After:
-
- ```
- article_edit:
- path: /article/{id}
- methods: [POST, PUT]
- schemes: https
- requirements: { 'id': '\d+' }
-
- <route id="article_edit" pattern="/article/{id}" methods="POST PUT" schemes="https">
- <requirement key="id">\d+</requirement>
- </route>
-
- $route = new Route();
- $route->setPath('/article/{id}');
- $route->setMethods(array('POST', 'PUT'));
- $route->setSchemes('https');
- ```
-
- * [BC BREAK] RouteCollection does not behave like a tree structure anymore but as
- a flat array of Routes. So when using PHP to build the RouteCollection, you must
- make sure to add routes to the sub-collection before adding it to the parent
- collection (this is not relevant when using YAML or XML for Route definitions).
-
- Before:
-
- ```
- $rootCollection = new RouteCollection();
- $subCollection = new RouteCollection();
- $rootCollection->addCollection($subCollection);
- $subCollection->add('foo', new Route('/foo'));
- ```
-
- After:
-
- ```
- $rootCollection = new RouteCollection();
- $subCollection = new RouteCollection();
- $subCollection->add('foo', new Route('/foo'));
- $rootCollection->addCollection($subCollection);
- ```
-
- Also one must call `addCollection` from the bottom to the top hierarchy.
- So the correct sequence is the following (and not the reverse):
-
- ```
- $childCollection->->addCollection($grandchildCollection);
- $rootCollection->addCollection($childCollection);
- ```
-
- * [DEPRECATION] The methods `RouteCollection::getParent()` and `RouteCollection::getRoot()`
- have been deprecated and will be removed in Symfony 2.3.
- * [BC BREAK] Misusing the `RouteCollection::addPrefix` method to add defaults, requirements
- or options without adding a prefix is not supported anymore. So if you called `addPrefix`
- with an empty prefix or `/` only (both have no relevance), like
- `addPrefix('', $defaultsArray, $requirementsArray, $optionsArray)`
- you need to use the new dedicated methods `addDefaults($defaultsArray)`,
- `addRequirements($requirementsArray)` or `addOptions($optionsArray)` instead.
- * [DEPRECATION] The `$options` parameter to `RouteCollection::addPrefix()` has been deprecated
- because adding options has nothing to do with adding a path prefix. If you want to add options
- to all child routes of a RouteCollection, you can use `addOptions()`.
- * [DEPRECATION] The method `RouteCollection::getPrefix()` has been deprecated
- because it suggested that all routes in the collection would have this prefix, which is
- not necessarily true. On top of that, since there is no tree structure anymore, this method
- is also useless. Don't worry about performance, prefix optimization for matching is still done
- in the dumper, which was also improved in 2.2.0 to find even more grouping possibilities.
- * [DEPRECATION] `RouteCollection::addCollection(RouteCollection $collection)` should now only be
- used with a single parameter. The other params `$prefix`, `$default`, `$requirements` and `$options`
- will still work, but have been deprecated. The `addPrefix` method should be used for this
- use-case instead.
- Before: `$parentCollection->addCollection($collection, '/prefix', array(...), array(...))`
- After:
- ```
- $collection->addPrefix('/prefix', array(...), array(...));
- $parentCollection->addCollection($collection);
- ```
- * added support for the method default argument values when defining a @Route
- * Adjacent placeholders without separator work now, e.g. `/{x}{y}{z}.{_format}`.
- * Characters that function as separator between placeholders are now whitelisted
- to fix routes with normal text around a variable, e.g. `/prefix{var}suffix`.
- * [BC BREAK] The default requirement of a variable has been changed slightly.
- Previously it disallowed the previous and the next char around a variable. Now
- it disallows the slash (`/`) and the next char. Using the previous char added
- no value and was problematic because the route `/index.{_format}` would be
- matched by `/index.ht/ml`.
- * The default requirement now uses possessive quantifiers when possible which
- improves matching performance by up to 20% because it prevents backtracking
- when it's not needed.
- * The ConfigurableRequirementsInterface can now also be used to disable the requirements
- check on URL generation completely by calling `setStrictRequirements(null)`. It
- improves performance in production environment as you should know that params always
- pass the requirements (otherwise it would break your link anyway).
- * There is no restriction on the route name anymore. So non-alphanumeric characters
- are now also allowed.
- * [BC BREAK] `RouteCompilerInterface::compile(Route $route)` was made static
- (only relevant if you implemented your own RouteCompiler).
- * Added possibility to generate relative paths and network paths in the UrlGenerator, e.g.
- "../parent-file" and "//example.com/dir/file". The third parameter in
- `UrlGeneratorInterface::generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)`
- now accepts more values and you should use the constants defined in `UrlGeneratorInterface` for
- claritiy. The old method calls with a Boolean parameter will continue to work because they
- equal the signature using the constants.
-
-2.1.0
------
-
- * added RequestMatcherInterface
- * added RequestContext::fromRequest()
- * the UrlMatcher does not throw a \LogicException anymore when the required
- scheme is not the current one
- * added TraceableUrlMatcher
- * added the possibility to define options, default values and requirements
- for placeholders in prefix, including imported routes
- * added RouterInterface::getRouteCollection
- * [BC BREAK] the UrlMatcher urldecodes the route parameters only once, they
- were decoded twice before. Note that the `urldecode()` calls have been
- changed for a single `rawurldecode()` in order to support `+` for input
- paths.
- * added RouteCollection::getRoot method to retrieve the root of a
- RouteCollection tree
- * [BC BREAK] made RouteCollection::setParent private which could not have
- been used anyway without creating inconsistencies
- * [BC BREAK] RouteCollection::remove also removes a route from parent
- collections (not only from its children)
- * added ConfigurableRequirementsInterface that allows to disable exceptions
- (and generate empty URLs instead) when generating a route with an invalid
- parameter value
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-/**
- * CompiledRoutes are returned by the RouteCompiler class.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class CompiledRoute
-{
- private $variables;
- private $tokens;
- private $staticPrefix;
- private $regex;
- private $pathVariables;
- private $hostVariables;
- private $hostRegex;
- private $hostTokens;
-
- /**
- * Constructor.
- *
- * @param string $staticPrefix The static prefix of the compiled route
- * @param string $regex The regular expression to use to match this route
- * @param array $tokens An array of tokens to use to generate URL for this route
- * @param array $pathVariables An array of path variables
- * @param string|null $hostRegex Host regex
- * @param array $hostTokens Host tokens
- * @param array $hostVariables An array of host variables
- * @param array $variables An array of variables (variables defined in the path and in the host patterns)
- */
- public function __construct($staticPrefix, $regex, array $tokens, array $pathVariables, $hostRegex = null, array $hostTokens = array(), array $hostVariables = array(), array $variables = array())
- {
- $this->staticPrefix = (string) $staticPrefix;
- $this->regex = $regex;
- $this->tokens = $tokens;
- $this->pathVariables = $pathVariables;
- $this->hostRegex = $hostRegex;
- $this->hostTokens = $hostTokens;
- $this->hostVariables = $hostVariables;
- $this->variables = $variables;
- }
-
- /**
- * Returns the static prefix.
- *
- * @return string The static prefix
- */
- public function getStaticPrefix()
- {
- return $this->staticPrefix;
- }
-
- /**
- * Returns the regex.
- *
- * @return string The regex
- */
- public function getRegex()
- {
- return $this->regex;
- }
-
- /**
- * Returns the host regex
- *
- * @return string|null The host regex or null
- */
- public function getHostRegex()
- {
- return $this->hostRegex;
- }
-
- /**
- * Returns the tokens.
- *
- * @return array The tokens
- */
- public function getTokens()
- {
- return $this->tokens;
- }
-
- /**
- * Returns the host tokens.
- *
- * @return array The tokens
- */
- public function getHostTokens()
- {
- return $this->hostTokens;
- }
-
- /**
- * Returns the variables.
- *
- * @return array The variables
- */
- public function getVariables()
- {
- return $this->variables;
- }
-
- /**
- * Returns the path variables.
- *
- * @return array The variables
- */
- public function getPathVariables()
- {
- return $this->pathVariables;
- }
-
- /**
- * Returns the host variables.
- *
- * @return array The variables
- */
- public function getHostVariables()
- {
- return $this->hostVariables;
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Exception;
-
-/**
- * ExceptionInterface
- *
- * @author Alexandre Salomé <alexandre.salome@gmail.com>
- *
- * @api
- */
-interface ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Exception;
-
-/**
- * Exception thrown when a parameter is not valid
- *
- * @author Alexandre Salomé <alexandre.salome@gmail.com>
- *
- * @api
- */
-class InvalidParameterException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Exception;
-
-/**
- * The resource was found but the request method is not allowed.
- *
- * This exception should trigger an HTTP 405 response in your application code.
- *
- * @author Kris Wallsmith <kris@symfony.com>
- *
- * @api
- */
-class MethodNotAllowedException extends \RuntimeException implements ExceptionInterface
-{
- /**
- * @var array
- */
- protected $allowedMethods = array();
-
- public function __construct(array $allowedMethods, $message = null, $code = 0, \Exception $previous = null)
- {
- $this->allowedMethods = array_map('strtoupper', $allowedMethods);
-
- parent::__construct($message, $code, $previous);
- }
-
- /**
- * Gets the allowed HTTP methods.
- *
- * @return array
- */
- public function getAllowedMethods()
- {
- return $this->allowedMethods;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Exception;
-
-/**
- * Exception thrown when a route cannot be generated because of missing
- * mandatory parameters.
- *
- * @author Alexandre Salomé <alexandre.salome@gmail.com>
- *
- * @api
- */
-class MissingMandatoryParametersException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Exception;
-
-/**
- * The resource was not found.
- *
- * This exception should trigger an HTTP 404 response in your application code.
- *
- * @author Kris Wallsmith <kris@symfony.com>
- *
- * @api
- */
-class ResourceNotFoundException extends \RuntimeException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Exception;
-
-/**
- * Exception thrown when a route does not exists
- *
- * @author Alexandre Salomé <alexandre.salome@gmail.com>
- *
- * @api
- */
-class RouteNotFoundException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Generator;
-
-/**
- * ConfigurableRequirementsInterface must be implemented by URL generators that
- * can be configured whether an exception should be generated when the parameters
- * do not match the requirements. It is also possible to disable the requirements
- * check for URL generation completely.
- *
- * The possible configurations and use-cases:
- * - setStrictRequirements(true): Throw an exception for mismatching requirements. This
- * is mostly useful in development environment.
- * - setStrictRequirements(false): Don't throw an exception but return null as URL for
- * mismatching requirements and log the problem. Useful when you cannot control all
- * params because they come from third party libs but don't want to have a 404 in
- * production environment. It should log the mismatch so one can review it.
- * - setStrictRequirements(null): Return the URL with the given parameters without
- * checking the requirements at all. When generating an URL you should either trust
- * your params or you validated them beforehand because otherwise it would break your
- * link anyway. So in production environment you should know that params always pass
- * the requirements. Thus this option allows to disable the check on URL generation for
- * performance reasons (saving a preg_match for each requirement every time a URL is
- * generated).
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- */
-interface ConfigurableRequirementsInterface
-{
- /**
- * Enables or disables the exception on incorrect parameters.
- * Passing null will deactivate the requirements check completely.
- *
- * @param Boolean|null $enabled
- */
- public function setStrictRequirements($enabled);
-
- /**
- * Returns whether to throw an exception on incorrect parameters.
- * Null means the requirements check is deactivated completely.
- *
- * @return Boolean|null
- */
- public function isStrictRequirements();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Generator\Dumper;
-
-use Symfony\Component\Routing\RouteCollection;
-
-/**
- * GeneratorDumper is the base class for all built-in generator dumpers.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-abstract class GeneratorDumper implements GeneratorDumperInterface
-{
- /**
- * @var RouteCollection
- */
- private $routes;
-
- /**
- * Constructor.
- *
- * @param RouteCollection $routes The RouteCollection to dump
- */
- public function __construct(RouteCollection $routes)
- {
- $this->routes = $routes;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRoutes()
- {
- return $this->routes;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Generator\Dumper;
-
-use Symfony\Component\Routing\RouteCollection;
-
-/**
- * GeneratorDumperInterface is the interface that all generator dumper classes must implement.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-interface GeneratorDumperInterface
-{
- /**
- * Dumps a set of routes to a string representation of executable code
- * that can then be used to generate a URL of such a route.
- *
- * @param array $options An array of options
- *
- * @return string Executable code
- */
- public function dump(array $options = array());
-
- /**
- * Gets the routes to dump.
- *
- * @return RouteCollection A RouteCollection instance
- */
- public function getRoutes();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Generator\Dumper;
-
-/**
- * PhpGeneratorDumper creates a PHP class able to generate URLs for a given set of routes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- *
- * @api
- */
-class PhpGeneratorDumper extends GeneratorDumper
-{
- /**
- * Dumps a set of routes to a PHP class.
- *
- * Available options:
- *
- * * class: The class name
- * * base_class: The base class name
- *
- * @param array $options An array of options
- *
- * @return string A PHP class representing the generator class
- *
- * @api
- */
- public function dump(array $options = array())
- {
- $options = array_merge(array(
- 'class' => 'ProjectUrlGenerator',
- 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
- ), $options);
-
- return <<<EOF
-<?php
-
-use Symfony\Component\Routing\RequestContext;
-use Symfony\Component\Routing\Exception\RouteNotFoundException;
-use Psr\Log\LoggerInterface;
-
-/**
- * {$options['class']}
- *
- * This class has been auto-generated
- * by the Symfony Routing Component.
- */
-class {$options['class']} extends {$options['base_class']}
-{
- static private \$declaredRoutes = {$this->generateDeclaredRoutes()};
-
- /**
- * Constructor.
- */
- public function __construct(RequestContext \$context, LoggerInterface \$logger = null)
- {
- \$this->context = \$context;
- \$this->logger = \$logger;
- }
-
-{$this->generateGenerateMethod()}
-}
-
-EOF;
- }
-
- /**
- * Generates PHP code representing an array of defined routes
- * together with the routes properties (e.g. requirements).
- *
- * @return string PHP code
- */
- private function generateDeclaredRoutes()
- {
- $routes = "array(\n";
- foreach ($this->getRoutes()->all() as $name => $route) {
- $compiledRoute = $route->compile();
-
- $properties = array();
- $properties[] = $compiledRoute->getVariables();
- $properties[] = $route->getDefaults();
- $properties[] = $route->getRequirements();
- $properties[] = $compiledRoute->getTokens();
- $properties[] = $compiledRoute->getHostTokens();
-
- $routes .= sprintf(" '%s' => %s,\n", $name, str_replace("\n", '', var_export($properties, true)));
- }
- $routes .= ' )';
-
- return $routes;
- }
-
- /**
- * Generates PHP code representing the `generate` method that implements the UrlGeneratorInterface.
- *
- * @return string PHP code
- */
- private function generateGenerateMethod()
- {
- return <<<EOF
- public function generate(\$name, \$parameters = array(), \$referenceType = self::ABSOLUTE_PATH)
- {
- if (!isset(self::\$declaredRoutes[\$name])) {
- throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', \$name));
- }
-
- list(\$variables, \$defaults, \$requirements, \$tokens, \$hostTokens) = self::\$declaredRoutes[\$name];
-
- return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostTokens);
- }
-EOF;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Generator;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\RequestContext;
-use Symfony\Component\Routing\Exception\InvalidParameterException;
-use Symfony\Component\Routing\Exception\RouteNotFoundException;
-use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
-use Psr\Log\LoggerInterface;
-
-/**
- * UrlGenerator can generate a URL or a path for any route in the RouteCollection
- * based on the passed parameters.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- *
- * @api
- */
-class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInterface
-{
- /**
- * @var RouteCollection
- */
- protected $routes;
-
- /**
- * @var RequestContext
- */
- protected $context;
-
- /**
- * @var Boolean|null
- */
- protected $strictRequirements = true;
-
- /**
- * @var LoggerInterface|null
- */
- protected $logger;
-
- /**
- * This array defines the characters (besides alphanumeric ones) that will not be percent-encoded in the path segment of the generated URL.
- *
- * PHP's rawurlencode() encodes all chars except "a-zA-Z0-9-._~" according to RFC 3986. But we want to allow some chars
- * to be used in their literal form (reasons below). Other chars inside the path must of course be encoded, e.g.
- * "?" and "#" (would be interpreted wrongly as query and fragment identifier),
- * "'" and """ (are used as delimiters in HTML).
- */
- protected $decodedChars = array(
- // the slash can be used to designate a hierarchical structure and we want allow using it with this meaning
- // some webservers don't allow the slash in encoded form in the path for security reasons anyway
- // see http://stackoverflow.com/questions/4069002/http-400-if-2f-part-of-get-url-in-jboss
- '%2F' => '/',
- // the following chars are general delimiters in the URI specification but have only special meaning in the authority component
- // so they can safely be used in the path in unencoded form
- '%40' => '@',
- '%3A' => ':',
- // these chars are only sub-delimiters that have no predefined meaning and can therefore be used literally
- // so URI producing applications can use these chars to delimit subcomponents in a path segment without being encoded for better readability
- '%3B' => ';',
- '%2C' => ',',
- '%3D' => '=',
- '%2B' => '+',
- '%21' => '!',
- '%2A' => '*',
- '%7C' => '|',
- );
-
- /**
- * Constructor.
- *
- * @param RouteCollection $routes A RouteCollection instance
- * @param RequestContext $context The context
- * @param LoggerInterface|null $logger A logger instance
- *
- * @api
- */
- public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null)
- {
- $this->routes = $routes;
- $this->context = $context;
- $this->logger = $logger;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setContext(RequestContext $context)
- {
- $this->context = $context;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getContext()
- {
- return $this->context;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setStrictRequirements($enabled)
- {
- $this->strictRequirements = null === $enabled ? null : (Boolean) $enabled;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isStrictRequirements()
- {
- return $this->strictRequirements;
- }
-
- /**
- * {@inheritDoc}
- */
- public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
- {
- if (null === $route = $this->routes->get($name)) {
- throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
- }
-
- // the Route has a cache of its own and is not recompiled as long as it does not get modified
- $compiledRoute = $route->compile();
-
- return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens());
- }
-
- /**
- * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
- * @throws InvalidParameterException When a parameter value for a placeholder is not correct because
- * it does not match the requirement
- */
- protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens)
- {
- $variables = array_flip($variables);
- $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
-
- // all params must be given
- if ($diff = array_diff_key($variables, $mergedParams)) {
- throw new MissingMandatoryParametersException(sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', array_keys($diff)), $name));
- }
-
- $url = '';
- $optional = true;
- foreach ($tokens as $token) {
- if ('variable' === $token[0]) {
- if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) {
- // check requirement
- if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
- $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
- if ($this->strictRequirements) {
- throw new InvalidParameterException($message);
- }
-
- if ($this->logger) {
- $this->logger->error($message);
- }
-
- return null;
- }
-
- $url = $token[1].$mergedParams[$token[3]].$url;
- $optional = false;
- }
- } else {
- // static text
- $url = $token[1].$url;
- $optional = false;
- }
- }
-
- if ('' === $url) {
- $url = '/';
- }
-
- // the contexts base url is already encoded (see Symfony\Component\HttpFoundation\Request)
- $url = strtr(rawurlencode($url), $this->decodedChars);
-
- // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
- // so we need to encode them as they are not used for this purpose here
- // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route
- $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
- if ('/..' === substr($url, -3)) {
- $url = substr($url, 0, -2).'%2E%2E';
- } elseif ('/.' === substr($url, -2)) {
- $url = substr($url, 0, -1).'%2E';
- }
-
- $schemeAuthority = '';
- if ($host = $this->context->getHost()) {
- $scheme = $this->context->getScheme();
- if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme !== $req) {
- $referenceType = self::ABSOLUTE_URL;
- $scheme = $req;
- }
-
- if ($hostTokens) {
- $routeHost = '';
- foreach ($hostTokens as $token) {
- if ('variable' === $token[0]) {
- if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
- $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
-
- if ($this->strictRequirements) {
- throw new InvalidParameterException($message);
- }
-
- if ($this->logger) {
- $this->logger->error($message);
- }
-
- return null;
- }
-
- $routeHost = $token[1].$mergedParams[$token[3]].$routeHost;
- } else {
- $routeHost = $token[1].$routeHost;
- }
- }
-
- if ($routeHost !== $host) {
- $host = $routeHost;
- if (self::ABSOLUTE_URL !== $referenceType) {
- $referenceType = self::NETWORK_PATH;
- }
- }
- }
-
- if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) {
- $port = '';
- if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
- $port = ':'.$this->context->getHttpPort();
- } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
- $port = ':'.$this->context->getHttpsPort();
- }
-
- $schemeAuthority = self::NETWORK_PATH === $referenceType ? '//' : "$scheme://";
- $schemeAuthority .= $host.$port;
- }
- }
-
- if (self::RELATIVE_PATH === $referenceType) {
- $url = self::getRelativePath($this->context->getPathInfo(), $url);
- } else {
- $url = $schemeAuthority.$this->context->getBaseUrl().$url;
- }
-
- // add a query string if needed
- $extra = array_diff_key($parameters, $variables, $defaults);
- if ($extra && $query = http_build_query($extra, '', '&')) {
- $url .= '?'.$query;
- }
-
- return $url;
- }
-
- /**
- * Returns the target path as relative reference from the base path.
- *
- * Only the URIs path component (no schema, host etc.) is relevant and must be given, starting with a slash.
- * Both paths must be absolute and not contain relative parts.
- * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
- * Furthermore, they can be used to reduce the link size in documents.
- *
- * Example target paths, given a base path of "/a/b/c/d":
- * - "/a/b/c/d" -> ""
- * - "/a/b/c/" -> "./"
- * - "/a/b/" -> "../"
- * - "/a/b/c/other" -> "other"
- * - "/a/x/y" -> "../../x/y"
- *
- * @param string $basePath The base path
- * @param string $targetPath The target path
- *
- * @return string The relative target path
- */
- public static function getRelativePath($basePath, $targetPath)
- {
- if ($basePath === $targetPath) {
- return '';
- }
-
- $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
- $targetDirs = explode('/', isset($targetPath[0]) && '/' === $targetPath[0] ? substr($targetPath, 1) : $targetPath);
- array_pop($sourceDirs);
- $targetFile = array_pop($targetDirs);
-
- foreach ($sourceDirs as $i => $dir) {
- if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
- unset($sourceDirs[$i], $targetDirs[$i]);
- } else {
- break;
- }
- }
-
- $targetDirs[] = $targetFile;
- $path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
-
- // A reference to the same base directory or an empty subdirectory must be prefixed with "./".
- // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
- // as the first segment of a relative-path reference, as it would be mistaken for a scheme name
- // (see http://tools.ietf.org/html/rfc3986#section-4.2).
- return '' === $path || '/' === $path[0]
- || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
- ? "./$path" : $path;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Generator;
-
-use Symfony\Component\Routing\Exception\InvalidParameterException;
-use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
-use Symfony\Component\Routing\Exception\RouteNotFoundException;
-use Symfony\Component\Routing\RequestContextAwareInterface;
-
-/**
- * UrlGeneratorInterface is the interface that all URL generator classes must implement.
- *
- * The constants in this interface define the different types of resource references that
- * are declared in RFC 3986: http://tools.ietf.org/html/rfc3986
- * We are using the term "URL" instead of "URI" as this is more common in web applications
- * and we do not need to distinguish them as the difference is mostly semantical and
- * less technical. Generating URIs, i.e. representation-independent resource identifiers,
- * is also possible.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- *
- * @api
- */
-interface UrlGeneratorInterface extends RequestContextAwareInterface
-{
- /**
- * Generates an absolute URL, e.g. "http://example.com/dir/file".
- */
- const ABSOLUTE_URL = true;
-
- /**
- * Generates an absolute path, e.g. "/dir/file".
- */
- const ABSOLUTE_PATH = false;
-
- /**
- * Generates a relative path based on the current request path, e.g. "../parent-file".
- * @see UrlGenerator::getRelativePath()
- */
- const RELATIVE_PATH = 'relative';
-
- /**
- * Generates a network path, e.g. "//example.com/dir/file".
- * Such reference reuses the current scheme but specifies the host.
- */
- const NETWORK_PATH = 'network';
-
- /**
- * Generates a URL or path for a specific route based on the given parameters.
- *
- * Parameters that reference placeholders in the route pattern will substitute them in the
- * path or host. Extra params are added as query string to the URL.
- *
- * When the passed reference type cannot be generated for the route because it requires a different
- * host or scheme than the current one, the method will return a more comprehensive reference
- * that includes the required params. For example, when you call this method with $referenceType = ABSOLUTE_PATH
- * but the route requires the https scheme whereas the current scheme is http, it will instead return an
- * ABSOLUTE_URL with the https scheme and the current host. This makes sure the generated URL matches
- * the route in any case.
- *
- * If there is no route with the given name, the generator must throw the RouteNotFoundException.
- *
- * @param string $name The name of the route
- * @param mixed $parameters An array of parameters
- * @param Boolean|string $referenceType The type of reference to be generated (one of the constants)
- *
- * @return string The generated URL
- *
- * @throws RouteNotFoundException If the named route doesn't exist
- * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
- * @throws InvalidParameterException When a parameter value for a placeholder is not correct because
- * it does not match the requirement
- *
- * @api
- */
- public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH);
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Loader;
-
-use Doctrine\Common\Annotations\Reader;
-use Symfony\Component\Config\Resource\FileResource;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Config\Loader\LoaderInterface;
-use Symfony\Component\Config\Loader\LoaderResolverInterface;
-
-/**
- * AnnotationClassLoader loads routing information from a PHP class and its methods.
- *
- * You need to define an implementation for the getRouteDefaults() method. Most of the
- * time, this method should define some PHP callable to be called for the route
- * (a controller in MVC speak).
- *
- * The @Route annotation can be set on the class (for global parameters),
- * and on each method.
- *
- * The @Route annotation main value is the route path. The annotation also
- * recognizes several parameters: requirements, options, defaults, schemes,
- * methods, host, and name. The name parameter is mandatory.
- * Here is an example of how you should be able to use it:
- *
- * /**
- * * @Route("/Blog")
- * * /
- * class Blog
- * {
- * /**
- * * @Route("/", name="blog_index")
- * * /
- * public function index()
- * {
- * }
- *
- * /**
- * * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"})
- * * /
- * public function show()
- * {
- * }
- * }
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-abstract class AnnotationClassLoader implements LoaderInterface
-{
- /**
- * @var Reader
- */
- protected $reader;
-
- /**
- * @var string
- */
- protected $routeAnnotationClass = 'Symfony\\Component\\Routing\\Annotation\\Route';
-
- /**
- * @var integer
- */
- protected $defaultRouteIndex = 0;
-
- /**
- * Constructor.
- *
- * @param Reader $reader
- */
- public function __construct(Reader $reader)
- {
- $this->reader = $reader;
- }
-
- /**
- * Sets the annotation class to read route properties from.
- *
- * @param string $class A fully-qualified class name
- */
- public function setRouteAnnotationClass($class)
- {
- $this->routeAnnotationClass = $class;
- }
-
- /**
- * Loads from annotations from a class.
- *
- * @param string $class A class name
- * @param string|null $type The resource type
- *
- * @return RouteCollection A RouteCollection instance
- *
- * @throws \InvalidArgumentException When route can't be parsed
- */
- public function load($class, $type = null)
- {
- if (!class_exists($class)) {
- throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
- }
-
- $globals = array(
- 'path' => '',
- 'requirements' => array(),
- 'options' => array(),
- 'defaults' => array(),
- 'schemes' => array(),
- 'methods' => array(),
- 'host' => '',
- );
-
- $class = new \ReflectionClass($class);
- if ($class->isAbstract()) {
- throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class));
- }
-
- if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) {
- // for BC reasons
- if (null !== $annot->getPath()) {
- $globals['path'] = $annot->getPath();
- } elseif (null !== $annot->getPattern()) {
- $globals['path'] = $annot->getPattern();
- }
-
- if (null !== $annot->getRequirements()) {
- $globals['requirements'] = $annot->getRequirements();
- }
-
- if (null !== $annot->getOptions()) {
- $globals['options'] = $annot->getOptions();
- }
-
- if (null !== $annot->getDefaults()) {
- $globals['defaults'] = $annot->getDefaults();
- }
-
- if (null !== $annot->getSchemes()) {
- $globals['schemes'] = $annot->getSchemes();
- }
-
- if (null !== $annot->getMethods()) {
- $globals['methods'] = $annot->getMethods();
- }
-
- if (null !== $annot->getHost()) {
- $globals['host'] = $annot->getHost();
- }
- }
-
- $collection = new RouteCollection();
- $collection->addResource(new FileResource($class->getFileName()));
-
- foreach ($class->getMethods() as $method) {
- $this->defaultRouteIndex = 0;
- foreach ($this->reader->getMethodAnnotations($method) as $annot) {
- if ($annot instanceof $this->routeAnnotationClass) {
- $this->addRoute($collection, $annot, $globals, $class, $method);
- }
- }
- }
-
- return $collection;
- }
-
- protected function addRoute(RouteCollection $collection, $annot, $globals, \ReflectionClass $class, \ReflectionMethod $method)
- {
- $name = $annot->getName();
- if (null === $name) {
- $name = $this->getDefaultRouteName($class, $method);
- }
-
- $defaults = array_replace($globals['defaults'], $annot->getDefaults());
- foreach ($method->getParameters() as $param) {
- if ($param->isOptional()) {
- $defaults[$param->getName()] = $param->getDefaultValue();
- }
- }
- $requirements = array_replace($globals['requirements'], $annot->getRequirements());
- $options = array_replace($globals['options'], $annot->getOptions());
- $schemes = array_replace($globals['schemes'], $annot->getSchemes());
- $methods = array_replace($globals['methods'], $annot->getMethods());
-
- $host = $annot->getHost();
- if (null === $host) {
- $host = $globals['host'];
- }
-
- $route = new Route($globals['path'].$annot->getPath(), $defaults, $requirements, $options, $host, $schemes, $methods);
-
- $this->configureRoute($route, $class, $method, $annot);
-
- $collection->add($name, $route);
- }
-
- /**
- * {@inheritdoc}
- */
- public function supports($resource, $type = null)
- {
- return is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setResolver(LoaderResolverInterface $resolver)
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function getResolver()
- {
- }
-
- /**
- * Gets the default route name for a class method.
- *
- * @param \ReflectionClass $class
- * @param \ReflectionMethod $method
- *
- * @return string
- */
- protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method)
- {
- $name = strtolower(str_replace('\\', '_', $class->name).'_'.$method->name);
- if ($this->defaultRouteIndex > 0) {
- $name .= '_'.$this->defaultRouteIndex;
- }
- $this->defaultRouteIndex++;
-
- return $name;
- }
-
- abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Loader;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Config\Resource\DirectoryResource;
-
-/**
- * AnnotationDirectoryLoader loads routing information from annotations set
- * on PHP classes and methods.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class AnnotationDirectoryLoader extends AnnotationFileLoader
-{
- /**
- * Loads from annotations from a directory.
- *
- * @param string $path A directory path
- * @param string|null $type The resource type
- *
- * @return RouteCollection A RouteCollection instance
- *
- * @throws \InvalidArgumentException When the directory does not exist or its routes cannot be parsed
- */
- public function load($path, $type = null)
- {
- $dir = $this->locator->locate($path);
-
- $collection = new RouteCollection();
- $collection->addResource(new DirectoryResource($dir, '/\.php$/'));
- $files = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::LEAVES_ONLY));
- usort($files, function (\SplFileInfo $a, \SplFileInfo $b) {
- return (string) $a > (string) $b ? 1 : -1;
- });
-
- foreach ($files as $file) {
- if (!$file->isFile() || '.php' !== substr($file->getFilename(), -4)) {
- continue;
- }
-
- if ($class = $this->findClass($file)) {
- $refl = new \ReflectionClass($class);
- if ($refl->isAbstract()) {
- continue;
- }
-
- $collection->addCollection($this->loader->load($class, $type));
- }
- }
-
- return $collection;
- }
-
- /**
- * {@inheritdoc}
- */
- public function supports($resource, $type = null)
- {
- try {
- $path = $this->locator->locate($resource);
- } catch (\Exception $e) {
- return false;
- }
-
- return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Loader;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Config\Resource\FileResource;
-use Symfony\Component\Config\Loader\FileLoader;
-use Symfony\Component\Config\FileLocatorInterface;
-
-/**
- * AnnotationFileLoader loads routing information from annotations set
- * on a PHP class and its methods.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class AnnotationFileLoader extends FileLoader
-{
- protected $loader;
-
- /**
- * Constructor.
- *
- * @param FileLocatorInterface $locator A FileLocator instance
- * @param AnnotationClassLoader $loader An AnnotationClassLoader instance
- * @param string|array $paths A path or an array of paths where to look for resources
- *
- * @throws \RuntimeException
- */
- public function __construct(FileLocatorInterface $locator, AnnotationClassLoader $loader, $paths = array())
- {
- if (!function_exists('token_get_all')) {
- throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.');
- }
-
- parent::__construct($locator, $paths);
-
- $this->loader = $loader;
- }
-
- /**
- * Loads from annotations from a file.
- *
- * @param string $file A PHP file path
- * @param string|null $type The resource type
- *
- * @return RouteCollection A RouteCollection instance
- *
- * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
- */
- public function load($file, $type = null)
- {
- $path = $this->locator->locate($file);
-
- $collection = new RouteCollection();
- if ($class = $this->findClass($path)) {
- $collection->addResource(new FileResource($path));
- $collection->addCollection($this->loader->load($class, $type));
- }
-
- return $collection;
- }
-
- /**
- * {@inheritdoc}
- */
- public function supports($resource, $type = null)
- {
- return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
- }
-
- /**
- * Returns the full class name for the first class in the file.
- *
- * @param string $file A PHP file path
- *
- * @return string|false Full class name if found, false otherwise
- */
- protected function findClass($file)
- {
- $class = false;
- $namespace = false;
- $tokens = token_get_all(file_get_contents($file));
- for ($i = 0, $count = count($tokens); $i < $count; $i++) {
- $token = $tokens[$i];
-
- if (!is_array($token)) {
- continue;
- }
-
- if (true === $class && T_STRING === $token[0]) {
- return $namespace.'\\'.$token[1];
- }
-
- if (true === $namespace && T_STRING === $token[0]) {
- $namespace = '';
- do {
- $namespace .= $token[1];
- $token = $tokens[++$i];
- } while ($i < $count && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING)));
- }
-
- if (T_CLASS === $token[0]) {
- $class = true;
- }
-
- if (T_NAMESPACE === $token[0]) {
- $namespace = true;
- }
- }
-
- return false;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Loader;
-
-use Symfony\Component\Config\Loader\Loader;
-use Symfony\Component\Routing\RouteCollection;
-
-/**
- * ClosureLoader loads routes from a PHP closure.
- *
- * The Closure must return a RouteCollection instance.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class ClosureLoader extends Loader
-{
- /**
- * Loads a Closure.
- *
- * @param \Closure $closure A Closure
- * @param string|null $type The resource type
- *
- * @return RouteCollection A RouteCollection instance
- *
- * @api
- */
- public function load($closure, $type = null)
- {
- return call_user_func($closure);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function supports($resource, $type = null)
- {
- return $resource instanceof \Closure && (!$type || 'closure' === $type);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Loader;
-
-use Symfony\Component\Config\Loader\FileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-use Symfony\Component\Routing\RouteCollection;
-
-/**
- * PhpFileLoader loads routes from a PHP file.
- *
- * The file must return a RouteCollection instance.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class PhpFileLoader extends FileLoader
-{
- /**
- * Loads a PHP file.
- *
- * @param string $file A PHP file path
- * @param string|null $type The resource type
- *
- * @return RouteCollection A RouteCollection instance
- *
- * @api
- */
- public function load($file, $type = null)
- {
- // the loader variable is exposed to the included file below
- $loader = $this;
-
- $path = $this->locator->locate($file);
- $this->setCurrentDir(dirname($path));
-
- $collection = include $path;
- $collection->addResource(new FileResource($path));
-
- return $collection;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function supports($resource, $type = null)
- {
- return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'php' === $type);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Loader;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Config\Resource\FileResource;
-use Symfony\Component\Config\Loader\FileLoader;
-use Symfony\Component\Config\Util\XmlUtils;
-
-/**
- * XmlFileLoader loads XML routing files.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- *
- * @api
- */
-class XmlFileLoader extends FileLoader
-{
- const NAMESPACE_URI = 'http://symfony.com/schema/routing';
- const SCHEME_PATH = '/schema/routing/routing-1.0.xsd';
-
- /**
- * Loads an XML file.
- *
- * @param string $file An XML file path
- * @param string|null $type The resource type
- *
- * @return RouteCollection A RouteCollection instance
- *
- * @throws \InvalidArgumentException When the file cannot be loaded or when the XML cannot be
- * parsed because it does not validate against the scheme.
- *
- * @api
- */
- public function load($file, $type = null)
- {
- $path = $this->locator->locate($file);
-
- $xml = $this->loadFile($path);
-
- $collection = new RouteCollection();
- $collection->addResource(new FileResource($path));
-
- // process routes and imports
- foreach ($xml->documentElement->childNodes as $node) {
- if (!$node instanceof \DOMElement) {
- continue;
- }
-
- $this->parseNode($collection, $node, $path, $file);
- }
-
- return $collection;
- }
-
- /**
- * Parses a node from a loaded XML file.
- *
- * @param RouteCollection $collection Collection to associate with the node
- * @param \DOMElement $node Element to parse
- * @param string $path Full path of the XML file being processed
- * @param string $file Loaded file name
- *
- * @throws \InvalidArgumentException When the XML is invalid
- */
- protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file)
- {
- if (self::NAMESPACE_URI !== $node->namespaceURI) {
- return;
- }
-
- switch ($node->localName) {
- case 'route':
- $this->parseRoute($collection, $node, $path);
- break;
- case 'import':
- $this->parseImport($collection, $node, $path, $file);
- break;
- default:
- throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path));
- }
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function supports($resource, $type = null)
- {
- return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'xml' === $type);
- }
-
- /**
- * Parses a route and adds it to the RouteCollection.
- *
- * @param RouteCollection $collection RouteCollection instance
- * @param \DOMElement $node Element to parse that represents a Route
- * @param string $path Full path of the XML file being processed
- *
- * @throws \InvalidArgumentException When the XML is invalid
- */
- protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path)
- {
- if ('' === ($id = $node->getAttribute('id')) || (!$node->hasAttribute('pattern') && !$node->hasAttribute('path'))) {
- throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" and a "path" attribute.', $path));
- }
-
- if ($node->hasAttribute('pattern')) {
- if ($node->hasAttribute('path')) {
- throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path));
- }
-
- $node->setAttribute('path', $node->getAttribute('pattern'));
- $node->removeAttribute('pattern');
- }
-
- $schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY);
- $methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);
-
- list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
-
- $route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods);
- $collection->add($id, $route);
- }
-
- /**
- * Parses an import and adds the routes in the resource to the RouteCollection.
- *
- * @param RouteCollection $collection RouteCollection instance
- * @param \DOMElement $node Element to parse that represents a Route
- * @param string $path Full path of the XML file being processed
- * @param string $file Loaded file name
- *
- * @throws \InvalidArgumentException When the XML is invalid
- */
- protected function parseImport(RouteCollection $collection, \DOMElement $node, $path, $file)
- {
- if ('' === $resource = $node->getAttribute('resource')) {
- throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute.', $path));
- }
-
- $type = $node->getAttribute('type');
- $prefix = $node->getAttribute('prefix');
- $host = $node->hasAttribute('host') ? $node->getAttribute('host') : null;
- $schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null;
- $methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null;
-
- list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
-
- $this->setCurrentDir(dirname($path));
-
- $subCollection = $this->import($resource, ('' !== $type ? $type : null), false, $file);
- /* @var $subCollection RouteCollection */
- $subCollection->addPrefix($prefix);
- if (null !== $host) {
- $subCollection->setHost($host);
- }
- if (null !== $schemes) {
- $subCollection->setSchemes($schemes);
- }
- if (null !== $methods) {
- $subCollection->setMethods($methods);
- }
- $subCollection->addDefaults($defaults);
- $subCollection->addRequirements($requirements);
- $subCollection->addOptions($options);
-
- $collection->addCollection($subCollection);
- }
-
- /**
- * Loads an XML file.
- *
- * @param string $file An XML file path
- *
- * @return \DOMDocument
- *
- * @throws \InvalidArgumentException When loading of XML file fails because of syntax errors
- * or when the XML structure is not as expected by the scheme -
- * see validate()
- */
- protected function loadFile($file)
- {
- return XmlUtils::loadFile($file, __DIR__.static::SCHEME_PATH);
- }
-
- /**
- * Parses the config elements (default, requirement, option).
- *
- * @param \DOMElement $node Element to parse that contains the configs
- * @param string $path Full path of the XML file being processed
- *
- * @return array An array with the defaults as first item, requirements as second and options as third.
- *
- * @throws \InvalidArgumentException When the XML is invalid
- */
- private function parseConfigs(\DOMElement $node, $path)
- {
- $defaults = array();
- $requirements = array();
- $options = array();
-
- foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, '*') as $n) {
- switch ($n->localName) {
- case 'default':
- if ($n->hasAttribute('xsi:nil') && 'true' == $n->getAttribute('xsi:nil')) {
- $defaults[$n->getAttribute('key')] = null;
- } else {
- $defaults[$n->getAttribute('key')] = trim($n->textContent);
- }
-
- break;
- case 'requirement':
- $requirements[$n->getAttribute('key')] = trim($n->textContent);
- break;
- case 'option':
- $options[$n->getAttribute('key')] = trim($n->textContent);
- break;
- default:
- throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement" or "option".', $n->localName, $path));
- }
- }
-
- return array($defaults, $requirements, $options);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Loader;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Config\Resource\FileResource;
-use Symfony\Component\Yaml\Parser as YamlParser;
-use Symfony\Component\Config\Loader\FileLoader;
-
-/**
- * YamlFileLoader loads Yaml routing files.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- *
- * @api
- */
-class YamlFileLoader extends FileLoader
-{
- private static $availableKeys = array(
- 'resource', 'type', 'prefix', 'pattern', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options',
- );
- private $yamlParser;
-
- /**
- * Loads a Yaml file.
- *
- * @param string $file A Yaml file path
- * @param string|null $type The resource type
- *
- * @return RouteCollection A RouteCollection instance
- *
- * @throws \InvalidArgumentException When a route can't be parsed because YAML is invalid
- *
- * @api
- */
- public function load($file, $type = null)
- {
- $path = $this->locator->locate($file);
-
- if (!stream_is_local($path)) {
- throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $path));
- }
-
- if (!file_exists($path)) {
- throw new \InvalidArgumentException(sprintf('File "%s" not found.', $path));
- }
-
- if (null === $this->yamlParser) {
- $this->yamlParser = new YamlParser();
- }
-
- $config = $this->yamlParser->parse(file_get_contents($path));
-
- $collection = new RouteCollection();
- $collection->addResource(new FileResource($path));
-
- // empty file
- if (null === $config) {
- return $collection;
- }
-
- // not an array
- if (!is_array($config)) {
- throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
- }
-
- foreach ($config as $name => $config) {
- if (isset($config['pattern'])) {
- if (isset($config['path'])) {
- throw new \InvalidArgumentException(sprintf('The file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path));
- }
-
- $config['path'] = $config['pattern'];
- unset($config['pattern']);
- }
-
- $this->validate($config, $name, $path);
-
- if (isset($config['resource'])) {
- $this->parseImport($collection, $config, $path, $file);
- } else {
- $this->parseRoute($collection, $name, $config, $path);
- }
- }
-
- return $collection;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function supports($resource, $type = null)
- {
- return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'yaml' === $type);
- }
-
- /**
- * Parses a route and adds it to the RouteCollection.
- *
- * @param RouteCollection $collection A RouteCollection instance
- * @param string $name Route name
- * @param array $config Route definition
- * @param string $path Full path of the YAML file being processed
- */
- protected function parseRoute(RouteCollection $collection, $name, array $config, $path)
- {
- $defaults = isset($config['defaults']) ? $config['defaults'] : array();
- $requirements = isset($config['requirements']) ? $config['requirements'] : array();
- $options = isset($config['options']) ? $config['options'] : array();
- $host = isset($config['host']) ? $config['host'] : '';
- $schemes = isset($config['schemes']) ? $config['schemes'] : array();
- $methods = isset($config['methods']) ? $config['methods'] : array();
-
- $route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods);
-
- $collection->add($name, $route);
- }
-
- /**
- * Parses an import and adds the routes in the resource to the RouteCollection.
- *
- * @param RouteCollection $collection A RouteCollection instance
- * @param array $config Route definition
- * @param string $path Full path of the YAML file being processed
- * @param string $file Loaded file name
- */
- protected function parseImport(RouteCollection $collection, array $config, $path, $file)
- {
- $type = isset($config['type']) ? $config['type'] : null;
- $prefix = isset($config['prefix']) ? $config['prefix'] : '';
- $defaults = isset($config['defaults']) ? $config['defaults'] : array();
- $requirements = isset($config['requirements']) ? $config['requirements'] : array();
- $options = isset($config['options']) ? $config['options'] : array();
- $host = isset($config['host']) ? $config['host'] : null;
- $schemes = isset($config['schemes']) ? $config['schemes'] : null;
- $methods = isset($config['methods']) ? $config['methods'] : null;
-
- $this->setCurrentDir(dirname($path));
-
- $subCollection = $this->import($config['resource'], $type, false, $file);
- /* @var $subCollection RouteCollection */
- $subCollection->addPrefix($prefix);
- if (null !== $host) {
- $subCollection->setHost($host);
- }
- if (null !== $schemes) {
- $subCollection->setSchemes($schemes);
- }
- if (null !== $methods) {
- $subCollection->setMethods($methods);
- }
- $subCollection->addDefaults($defaults);
- $subCollection->addRequirements($requirements);
- $subCollection->addOptions($options);
-
- $collection->addCollection($subCollection);
- }
-
- /**
- * Validates the route configuration.
- *
- * @param array $config A resource config
- * @param string $name The config key
- * @param string $path The loaded file path
- *
- * @throws \InvalidArgumentException If one of the provided config keys is not supported,
- * something is missing or the combination is nonsense
- */
- protected function validate($config, $name, $path)
- {
- if (!is_array($config)) {
- throw new \InvalidArgumentException(sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path));
- }
- if ($extraKeys = array_diff(array_keys($config), self::$availableKeys)) {
- throw new \InvalidArgumentException(sprintf(
- 'The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".',
- $path, $name, implode('", "', $extraKeys), implode('", "', self::$availableKeys)
- ));
- }
- if (isset($config['resource']) && isset($config['path'])) {
- throw new \InvalidArgumentException(sprintf(
- 'The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.',
- $path, $name
- ));
- }
- if (!isset($config['resource']) && isset($config['type'])) {
- throw new \InvalidArgumentException(sprintf(
- 'The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.',
- $name, $path
- ));
- }
- if (!isset($config['resource']) && !isset($config['path'])) {
- throw new \InvalidArgumentException(sprintf(
- 'You must define a "path" for the route "%s" in file "%s".',
- $name, $path
- ));
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<xsd:schema xmlns="http://symfony.com/schema/routing"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://symfony.com/schema/routing"
- elementFormDefault="qualified">
-
- <xsd:annotation>
- <xsd:documentation><![CDATA[
- Symfony XML Routing Schema, version 1.0
- Authors: Fabien Potencier, Tobias Schultze
-
- This scheme defines the elements and attributes that can be used to define
- routes. A route maps an HTTP request to a set of configuration variables.
- ]]></xsd:documentation>
- </xsd:annotation>
-
- <xsd:element name="routes" type="routes" />
-
- <xsd:complexType name="routes">
- <xsd:choice minOccurs="0" maxOccurs="unbounded">
- <xsd:element name="import" type="import" />
- <xsd:element name="route" type="route" />
- </xsd:choice>
- </xsd:complexType>
-
- <xsd:group name="configs">
- <xsd:choice>
- <xsd:element name="default" nillable="true" type="element" />
- <xsd:element name="requirement" type="element" />
- <xsd:element name="option" type="element" />
- </xsd:choice>
- </xsd:group>
-
- <xsd:complexType name="route">
- <xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
-
- <xsd:attribute name="id" type="xsd:string" use="required" />
- <xsd:attribute name="path" type="xsd:string" />
- <xsd:attribute name="pattern" type="xsd:string" />
- <xsd:attribute name="host" type="xsd:string" />
- <xsd:attribute name="schemes" type="xsd:string" />
- <xsd:attribute name="methods" type="xsd:string" />
- </xsd:complexType>
-
- <xsd:complexType name="import">
- <xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
-
- <xsd:attribute name="resource" type="xsd:string" use="required" />
- <xsd:attribute name="type" type="xsd:string" />
- <xsd:attribute name="prefix" type="xsd:string" />
- <xsd:attribute name="host" type="xsd:string" />
- <xsd:attribute name="schemes" type="xsd:string" />
- <xsd:attribute name="methods" type="xsd:string" />
- </xsd:complexType>
-
- <xsd:complexType name="element">
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute name="key" type="xsd:string" use="required" />
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
-</xsd:schema>
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher;
-
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-
-/**
- * ApacheUrlMatcher matches URL based on Apache mod_rewrite matching (see ApacheMatcherDumper).
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- */
-class ApacheUrlMatcher extends UrlMatcher
-{
- /**
- * Tries to match a URL based on Apache mod_rewrite matching.
- *
- * Returns false if no route matches the URL.
- *
- * @param string $pathinfo The pathinfo to be parsed
- *
- * @return array An array of parameters
- *
- * @throws MethodNotAllowedException If the current method is not allowed
- */
- public function match($pathinfo)
- {
- $parameters = array();
- $defaults = array();
- $allow = array();
- $route = null;
-
- foreach ($_SERVER as $key => $value) {
- $name = $key;
-
- // skip non-routing variables
- // this improves performance when $_SERVER contains many usual
- // variables like HTTP_*, DOCUMENT_ROOT, REQUEST_URI, ...
- if (false === strpos($name, '_ROUTING_')) {
- continue;
- }
-
- while (0 === strpos($name, 'REDIRECT_')) {
- $name = substr($name, 9);
- }
-
- // expect _ROUTING_<type>_<name>
- // or _ROUTING_<type>
-
- if (0 !== strpos($name, '_ROUTING_')) {
- continue;
- }
- if (false !== $pos = strpos($name, '_', 9)) {
- $type = substr($name, 9, $pos-9);
- $name = substr($name, $pos+1);
- } else {
- $type = substr($name, 9);
- }
-
- if ('param' === $type) {
- if ('' !== $value) {
- $parameters[$name] = $value;
- }
- } elseif ('default' === $type) {
- $defaults[$name] = $value;
- } elseif ('route' === $type) {
- $route = $value;
- } elseif ('allow' === $type) {
- $allow[] = $name;
- }
-
- unset($_SERVER[$key]);
- }
-
- if (null !== $route) {
- $parameters['_route'] = $route;
-
- return $this->mergeDefaults($parameters, $defaults);
- } elseif (0 < count($allow)) {
- throw new MethodNotAllowedException($allow);
- } else {
- return parent::match($pathinfo);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher\Dumper;
-
-use Symfony\Component\Routing\Route;
-
-/**
- * Dumps a set of Apache mod_rewrite rules.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Kris Wallsmith <kris@symfony.com>
- */
-class ApacheMatcherDumper extends MatcherDumper
-{
- /**
- * Dumps a set of Apache mod_rewrite rules.
- *
- * Available options:
- *
- * * script_name: The script name (app.php by default)
- * * base_uri: The base URI ("" by default)
- *
- * @param array $options An array of options
- *
- * @return string A string to be used as Apache rewrite rules
- *
- * @throws \LogicException When the route regex is invalid
- */
- public function dump(array $options = array())
- {
- $options = array_merge(array(
- 'script_name' => 'app.php',
- 'base_uri' => '',
- ), $options);
-
- $options['script_name'] = self::escape($options['script_name'], ' ', '\\');
-
- $rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]");
- $methodVars = array();
- $hostRegexUnique = 0;
- $prevHostRegex = '';
-
- foreach ($this->getRoutes()->all() as $name => $route) {
-
- $compiledRoute = $route->compile();
- $hostRegex = $compiledRoute->getHostRegex();
-
- if (null !== $hostRegex && $prevHostRegex !== $hostRegex) {
- $prevHostRegex = $hostRegex;
- $hostRegexUnique++;
-
- $rule = array();
-
- $regex = $this->regexToApacheRegex($hostRegex);
- $regex = self::escape($regex, ' ', '\\');
-
- $rule[] = sprintf('RewriteCond %%{HTTP:Host} %s', $regex);
-
- $variables = array();
- $variables[] = sprintf('E=__ROUTING_host_%s:1', $hostRegexUnique);
-
- foreach ($compiledRoute->getHostVariables() as $i => $variable) {
- $variables[] = sprintf('E=__ROUTING_host_%s_%s:%%%d', $hostRegexUnique, $variable, $i+1);
- }
-
- $variables = implode(',', $variables);
-
- $rule[] = sprintf('RewriteRule .? - [%s]', $variables);
-
- $rules[] = implode("\n", $rule);
- }
-
- $rules[] = $this->dumpRoute($name, $route, $options, $hostRegexUnique);
-
- if ($req = $route->getRequirement('_method')) {
- $methods = explode('|', strtoupper($req));
- $methodVars = array_merge($methodVars, $methods);
- }
- }
- if (0 < count($methodVars)) {
- $rule = array('# 405 Method Not Allowed');
- $methodVars = array_values(array_unique($methodVars));
- if (in_array('GET', $methodVars) && !in_array('HEAD', $methodVars)) {
- $methodVars[] = 'HEAD';
- }
- foreach ($methodVars as $i => $methodVar) {
- $rule[] = sprintf('RewriteCond %%{ENV:_ROUTING__allow_%s} =1%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : '');
- }
- $rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']);
-
- $rules[] = implode("\n", $rule);
- }
-
- return implode("\n\n", $rules)."\n";
- }
-
- /**
- * Dumps a single route
- *
- * @param string $name Route name
- * @param Route $route The route
- * @param array $options Options
- * @param bool $hostRegexUnique Unique identifier for the host regex
- *
- * @return string The compiled route
- */
- private function dumpRoute($name, $route, array $options, $hostRegexUnique)
- {
- $compiledRoute = $route->compile();
-
- // prepare the apache regex
- $regex = $this->regexToApacheRegex($compiledRoute->getRegex());
- $regex = '^'.self::escape(preg_quote($options['base_uri']).substr($regex, 1), ' ', '\\');
-
- $methods = $this->getRouteMethods($route);
-
- $hasTrailingSlash = (!$methods || in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex;
-
- $variables = array('E=_ROUTING_route:'.$name);
- foreach ($compiledRoute->getHostVariables() as $variable) {
- $variables[] = sprintf('E=_ROUTING_param_%s:%%{ENV:__ROUTING_host_%s_%s}', $variable, $hostRegexUnique, $variable);
- }
- foreach ($compiledRoute->getPathVariables() as $i => $variable) {
- $variables[] = 'E=_ROUTING_param_'.$variable.':%'.($i + 1);
- }
- foreach ($route->getDefaults() as $key => $value) {
- $variables[] = 'E=_ROUTING_default_'.$key.':'.strtr($value, array(
- ':' => '\\:',
- '=' => '\\=',
- '\\' => '\\\\',
- ' ' => '\\ ',
- ));
- }
- $variables = implode(',', $variables);
-
- $rule = array("# $name");
-
- // method mismatch
- if (0 < count($methods)) {
- $allow = array();
- foreach ($methods as $method) {
- $allow[] = 'E=_ROUTING_allow_'.$method.':1';
- }
-
- if ($hostRegex = $compiledRoute->getHostRegex()) {
- $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
- }
-
- $rule[] = "RewriteCond %{REQUEST_URI} $regex";
- $rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods));
- $rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow));
- }
-
- // redirect with trailing slash appended
- if ($hasTrailingSlash) {
-
- if ($hostRegex = $compiledRoute->getHostRegex()) {
- $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
- }
-
- $rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$';
- $rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]';
- }
-
- // the main rule
-
- if ($hostRegex = $compiledRoute->getHostRegex()) {
- $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
- }
-
- $rule[] = "RewriteCond %{REQUEST_URI} $regex";
- $rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]";
-
- return implode("\n", $rule);
- }
-
- /**
- * Returns methods allowed for a route
- *
- * @param Route $route The route
- *
- * @return array The methods
- */
- private function getRouteMethods(Route $route)
- {
- $methods = array();
- if ($req = $route->getRequirement('_method')) {
- $methods = explode('|', strtoupper($req));
- // GET and HEAD are equivalent
- if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
- $methods[] = 'HEAD';
- }
- }
-
- return $methods;
- }
-
- /**
- * Converts a regex to make it suitable for mod_rewrite
- *
- * @param string $regex The regex
- *
- * @return string The converted regex
- */
- private function regexToApacheRegex($regex)
- {
- $regexPatternEnd = strrpos($regex, $regex[0]);
-
- return preg_replace('/\?P<.+?>/', '', substr($regex, 1, $regexPatternEnd - 1));
- }
-
- /**
- * Escapes a string.
- *
- * @param string $string The string to be escaped
- * @param string $char The character to be escaped
- * @param string $with The character to be used for escaping
- *
- * @return string The escaped string
- */
- private static function escape($string, $char, $with)
- {
- $escaped = false;
- $output = '';
- foreach (str_split($string) as $symbol) {
- if ($escaped) {
- $output .= $symbol;
- $escaped = false;
- continue;
- }
- if ($symbol === $char) {
- $output .= $with.$char;
- continue;
- }
- if ($symbol === $with) {
- $escaped = true;
- }
- $output .= $symbol;
- }
-
- return $output;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher\Dumper;
-
-/**
- * Collection of routes.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- */
-class DumperCollection implements \IteratorAggregate
-{
- /**
- * @var DumperCollection|null
- */
- private $parent;
-
- /**
- * @var (DumperCollection|DumperRoute)[]
- */
- private $children = array();
-
- /**
- * @var array
- */
- private $attributes = array();
-
- /**
- * Returns the children routes and collections.
- *
- * @return (DumperCollection|DumperRoute)[] Array of DumperCollection|DumperRoute
- */
- public function all()
- {
- return $this->children;
- }
-
- /**
- * Adds a route or collection
- *
- * @param DumperRoute|DumperCollection The route or collection
- */
- public function add($child)
- {
- if ($child instanceof DumperCollection) {
- $child->setParent($this);
- }
- $this->children[] = $child;
- }
-
- /**
- * Sets children.
- *
- * @param array $children The children
- */
- public function setAll(array $children)
- {
- foreach ($children as $child) {
- if ($child instanceof DumperCollection) {
- $child->setParent($this);
- }
- }
- $this->children = $children;
- }
-
- /**
- * Returns an iterator over the children.
- *
- * @return \Iterator The iterator
- */
- public function getIterator()
- {
- return new \ArrayIterator($this->children);
- }
-
- /**
- * Returns the root of the collection.
- *
- * @return DumperCollection The root collection
- */
- public function getRoot()
- {
- return (null !== $this->parent) ? $this->parent->getRoot() : $this;
- }
-
- /**
- * Returns the parent collection.
- *
- * @return DumperCollection|null The parent collection or null if the collection has no parent
- */
- protected function getParent()
- {
- return $this->parent;
- }
-
- /**
- * Sets the parent collection.
- *
- * @param DumperCollection $parent The parent collection
- */
- protected function setParent(DumperCollection $parent)
- {
- $this->parent = $parent;
- }
-
- /**
- * Returns true if the attribute is defined.
- *
- * @param string $name The attribute name
- *
- * @return Boolean true if the attribute is defined, false otherwise
- */
- public function hasAttribute($name)
- {
- return array_key_exists($name, $this->attributes);
- }
-
- /**
- * Returns an attribute by name.
- *
- * @param string $name The attribute name
- * @param mixed $default Default value is the attribute doesn't exist
- *
- * @return mixed The attribute value
- */
- public function getAttribute($name, $default = null)
- {
- return $this->hasAttribute($name) ? $this->attributes[$name] : $default;
- }
-
- /**
- * Sets an attribute by name.
- *
- * @param string $name The attribute name
- * @param mixed $value The attribute value
- */
- public function setAttribute($name, $value)
- {
- $this->attributes[$name] = $value;
- }
-
- /**
- * Sets multiple attributes.
- *
- * @param array $attributes The attributes
- */
- public function setAttributes($attributes)
- {
- $this->attributes = $attributes;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher\Dumper;
-
-/**
- * Prefix tree of routes preserving routes order.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- */
-class DumperPrefixCollection extends DumperCollection
-{
- /**
- * @var string
- */
- private $prefix = '';
-
- /**
- * Returns the prefix.
- *
- * @return string The prefix
- */
- public function getPrefix()
- {
- return $this->prefix;
- }
-
- /**
- * Sets the prefix.
- *
- * @param string $prefix The prefix
- */
- public function setPrefix($prefix)
- {
- $this->prefix = $prefix;
- }
-
- /**
- * Adds a route in the tree.
- *
- * @param DumperRoute $route The route
- *
- * @return DumperPrefixCollection The node the route was added to
- *
- * @throws \LogicException
- */
- public function addPrefixRoute(DumperRoute $route)
- {
- $prefix = $route->getRoute()->compile()->getStaticPrefix();
-
- // Same prefix, add to current leave
- if ($this->prefix === $prefix) {
- $this->add($route);
-
- return $this;
- }
-
- // Prefix starts with route's prefix
- if ('' === $this->prefix || 0 === strpos($prefix, $this->prefix)) {
- $collection = new DumperPrefixCollection();
- $collection->setPrefix(substr($prefix, 0, strlen($this->prefix)+1));
- $this->add($collection);
-
- return $collection->addPrefixRoute($route);
- }
-
- // No match, fallback to parent (recursively)
-
- if (null === $parent = $this->getParent()) {
- throw new \LogicException("The collection root must not have a prefix");
- }
-
- return $parent->addPrefixRoute($route);
- }
-
- /**
- * Merges nodes whose prefix ends with a slash
- *
- * Children of a node whose prefix ends with a slash are moved to the parent node
- */
- public function mergeSlashNodes()
- {
- $children = array();
-
- foreach ($this as $child) {
- if ($child instanceof self) {
- $child->mergeSlashNodes();
- if ('/' === substr($child->prefix, -1)) {
- $children = array_merge($children, $child->all());
- } else {
- $children[] = $child;
- }
- } else {
- $children[] = $child;
- }
- }
-
- $this->setAll($children);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher\Dumper;
-
-use Symfony\Component\Routing\Route;
-
-/**
- * Container for a Route.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- */
-class DumperRoute
-{
- /**
- * @var string
- */
- private $name;
-
- /**
- * @var Route
- */
- private $route;
-
- /**
- * Constructor.
- *
- * @param string $name The route name
- * @param Route $route The route
- */
- public function __construct($name, Route $route)
- {
- $this->name = $name;
- $this->route = $route;
- }
-
- /**
- * Returns the route name.
- *
- * @return string The route name
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * Returns the route.
- *
- * @return Route The route
- */
- public function getRoute()
- {
- return $this->route;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher\Dumper;
-
-use Symfony\Component\Routing\RouteCollection;
-
-/**
- * MatcherDumper is the abstract class for all built-in matcher dumpers.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-abstract class MatcherDumper implements MatcherDumperInterface
-{
- /**
- * @var RouteCollection
- */
- private $routes;
-
- /**
- * Constructor.
- *
- * @param RouteCollection $routes The RouteCollection to dump
- */
- public function __construct(RouteCollection $routes)
- {
- $this->routes = $routes;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRoutes()
- {
- return $this->routes;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher\Dumper;
-
-/**
- * MatcherDumperInterface is the interface that all matcher dumper classes must implement.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface MatcherDumperInterface
-{
- /**
- * Dumps a set of routes to a string representation of executable code
- * that can then be used to match a request against these routes.
- *
- * @param array $options An array of options
- *
- * @return string Executable code
- */
- public function dump(array $options = array());
-
- /**
- * Gets the routes to dump.
- *
- * @return RouteCollection A RouteCollection instance
- */
- public function getRoutes();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher\Dumper;
-
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-
-/**
- * PhpMatcherDumper creates a PHP class able to match URLs for a given set of routes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- */
-class PhpMatcherDumper extends MatcherDumper
-{
- /**
- * Dumps a set of routes to a PHP class.
- *
- * Available options:
- *
- * * class: The class name
- * * base_class: The base class name
- *
- * @param array $options An array of options
- *
- * @return string A PHP class representing the matcher class
- */
- public function dump(array $options = array())
- {
- $options = array_replace(array(
- 'class' => 'ProjectUrlMatcher',
- 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
- ), $options);
-
- // trailing slash support is only enabled if we know how to redirect the user
- $interfaces = class_implements($options['base_class']);
- $supportsRedirections = isset($interfaces['Symfony\\Component\\Routing\\Matcher\\RedirectableUrlMatcherInterface']);
-
- return <<<EOF
-<?php
-
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\RequestContext;
-
-/**
- * {$options['class']}
- *
- * This class has been auto-generated
- * by the Symfony Routing Component.
- */
-class {$options['class']} extends {$options['base_class']}
-{
- /**
- * Constructor.
- */
- public function __construct(RequestContext \$context)
- {
- \$this->context = \$context;
- }
-
-{$this->generateMatchMethod($supportsRedirections)}
-}
-
-EOF;
- }
-
- /**
- * Generates the code for the match method implementing UrlMatcherInterface.
- *
- * @param Boolean $supportsRedirections Whether redirections are supported by the base class
- *
- * @return string Match method as PHP code
- */
- private function generateMatchMethod($supportsRedirections)
- {
- $code = rtrim($this->compileRoutes($this->getRoutes(), $supportsRedirections), "\n");
-
- return <<<EOF
- public function match(\$pathinfo)
- {
- \$allow = array();
- \$pathinfo = rawurldecode(\$pathinfo);
-
-$code
-
- throw 0 < count(\$allow) ? new MethodNotAllowedException(array_unique(\$allow)) : new ResourceNotFoundException();
- }
-EOF;
- }
-
- /**
- * Generates PHP code to match a RouteCollection with all its routes.
- *
- * @param RouteCollection $routes A RouteCollection instance
- * @param Boolean $supportsRedirections Whether redirections are supported by the base class
- *
- * @return string PHP code
- */
- private function compileRoutes(RouteCollection $routes, $supportsRedirections)
- {
- $fetchedHost = false;
-
- $groups = $this->groupRoutesByHostRegex($routes);
- $code = '';
-
- foreach ($groups as $collection) {
- if (null !== $regex = $collection->getAttribute('host_regex')) {
- if (!$fetchedHost) {
- $code .= " \$host = \$this->context->getHost();\n\n";
- $fetchedHost = true;
- }
-
- $code .= sprintf(" if (preg_match(%s, \$host, \$hostMatches)) {\n", var_export($regex, true));
- }
-
- $tree = $this->buildPrefixTree($collection);
- $groupCode = $this->compilePrefixRoutes($tree, $supportsRedirections);
-
- if (null !== $regex) {
- // apply extra indention at each line (except empty ones)
- $groupCode = preg_replace('/^.{2,}$/m', ' $0', $groupCode);
- $code .= $groupCode;
- $code .= " }\n\n";
- } else {
- $code .= $groupCode;
- }
- }
-
- return $code;
- }
-
- /**
- * Generates PHP code recursively to match a tree of routes
- *
- * @param DumperPrefixCollection $collection A DumperPrefixCollection instance
- * @param Boolean $supportsRedirections Whether redirections are supported by the base class
- * @param string $parentPrefix Prefix of the parent collection
- *
- * @return string PHP code
- */
- private function compilePrefixRoutes(DumperPrefixCollection $collection, $supportsRedirections, $parentPrefix = '')
- {
- $code = '';
- $prefix = $collection->getPrefix();
- $optimizable = 1 < strlen($prefix) && 1 < count($collection->all());
- $optimizedPrefix = $parentPrefix;
-
- if ($optimizable) {
- $optimizedPrefix = $prefix;
-
- $code .= sprintf(" if (0 === strpos(\$pathinfo, %s)) {\n", var_export($prefix, true));
- }
-
- foreach ($collection as $route) {
- if ($route instanceof DumperCollection) {
- $code .= $this->compilePrefixRoutes($route, $supportsRedirections, $optimizedPrefix);
- } else {
- $code .= $this->compileRoute($route->getRoute(), $route->getName(), $supportsRedirections, $optimizedPrefix)."\n";
- }
- }
-
- if ($optimizable) {
- $code .= " }\n\n";
- // apply extra indention at each line (except empty ones)
- $code = preg_replace('/^.{2,}$/m', ' $0', $code);
- }
-
- return $code;
- }
-
- /**
- * Compiles a single Route to PHP code used to match it against the path info.
- *
- * @param Route $route A Route instance
- * @param string $name The name of the Route
- * @param Boolean $supportsRedirections Whether redirections are supported by the base class
- * @param string|null $parentPrefix The prefix of the parent collection used to optimize the code
- *
- * @return string PHP code
- *
- * @throws \LogicException
- */
- private function compileRoute(Route $route, $name, $supportsRedirections, $parentPrefix = null)
- {
- $code = '';
- $compiledRoute = $route->compile();
- $conditions = array();
- $hasTrailingSlash = false;
- $matches = false;
- $hostMatches = false;
- $methods = array();
-
- if ($req = $route->getRequirement('_method')) {
- $methods = explode('|', strtoupper($req));
- // GET and HEAD are equivalent
- if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
- $methods[] = 'HEAD';
- }
- }
-
- $supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods));
-
- if (!count($compiledRoute->getPathVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
- if ($supportsTrailingSlash && substr($m['url'], -1) === '/') {
- $conditions[] = sprintf("rtrim(\$pathinfo, '/') === %s", var_export(rtrim(str_replace('\\', '', $m['url']), '/'), true));
- $hasTrailingSlash = true;
- } else {
- $conditions[] = sprintf("\$pathinfo === %s", var_export(str_replace('\\', '', $m['url']), true));
- }
- } else {
- if ($compiledRoute->getStaticPrefix() && $compiledRoute->getStaticPrefix() !== $parentPrefix) {
- $conditions[] = sprintf("0 === strpos(\$pathinfo, %s)", var_export($compiledRoute->getStaticPrefix(), true));
- }
-
- $regex = $compiledRoute->getRegex();
- if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) {
- $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
- $hasTrailingSlash = true;
- }
- $conditions[] = sprintf("preg_match(%s, \$pathinfo, \$matches)", var_export($regex, true));
-
- $matches = true;
- }
-
- if ($compiledRoute->getHostVariables()) {
- $hostMatches = true;
- }
-
- $conditions = implode(' && ', $conditions);
-
- $code .= <<<EOF
- // $name
- if ($conditions) {
-
-EOF;
-
- if ($methods) {
- $gotoname = 'not_'.preg_replace('/[^A-Za-z0-9_]/', '', $name);
-
- if (1 === count($methods)) {
- $code .= <<<EOF
- if (\$this->context->getMethod() != '$methods[0]') {
- \$allow[] = '$methods[0]';
- goto $gotoname;
- }
-
-
-EOF;
- } else {
- $methods = implode("', '", $methods);
- $code .= <<<EOF
- if (!in_array(\$this->context->getMethod(), array('$methods'))) {
- \$allow = array_merge(\$allow, array('$methods'));
- goto $gotoname;
- }
-
-
-EOF;
- }
- }
-
- if ($hasTrailingSlash) {
- $code .= <<<EOF
- if (substr(\$pathinfo, -1) !== '/') {
- return \$this->redirect(\$pathinfo.'/', '$name');
- }
-
-
-EOF;
- }
-
- if ($scheme = $route->getRequirement('_scheme')) {
- if (!$supportsRedirections) {
- throw new \LogicException('The "_scheme" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.');
- }
-
- $code .= <<<EOF
- if (\$this->context->getScheme() !== '$scheme') {
- return \$this->redirect(\$pathinfo, '$name', '$scheme');
- }
-
-
-EOF;
- }
-
- // optimize parameters array
- if ($matches || $hostMatches) {
- $vars = array();
- if ($hostMatches) {
- $vars[] = '$hostMatches';
- }
- if ($matches) {
- $vars[] = '$matches';
- }
- $vars[] = "array('_route' => '$name')";
-
- $code .= sprintf(" return \$this->mergeDefaults(array_replace(%s), %s);\n"
- , implode(', ', $vars), str_replace("\n", '', var_export($route->getDefaults(), true)));
-
- } elseif ($route->getDefaults()) {
- $code .= sprintf(" return %s;\n", str_replace("\n", '', var_export(array_replace($route->getDefaults(), array('_route' => $name)), true)));
- } else {
- $code .= sprintf(" return array('_route' => '%s');\n", $name);
- }
- $code .= " }\n";
-
- if ($methods) {
- $code .= " $gotoname:\n";
- }
-
- return $code;
- }
-
- /**
- * Groups consecutive routes having the same host regex.
- *
- * The result is a collection of collections of routes having the same host regex.
- *
- * @param RouteCollection $routes A flat RouteCollection
- *
- * @return DumperCollection A collection with routes grouped by host regex in sub-collections
- */
- private function groupRoutesByHostRegex(RouteCollection $routes)
- {
- $groups = new DumperCollection();
-
- $currentGroup = new DumperCollection();
- $currentGroup->setAttribute('host_regex', null);
- $groups->add($currentGroup);
-
- foreach ($routes as $name => $route) {
- $hostRegex = $route->compile()->getHostRegex();
- if ($currentGroup->getAttribute('host_regex') !== $hostRegex) {
- $currentGroup = new DumperCollection();
- $currentGroup->setAttribute('host_regex', $hostRegex);
- $groups->add($currentGroup);
- }
- $currentGroup->add(new DumperRoute($name, $route));
- }
-
- return $groups;
- }
-
- /**
- * Organizes the routes into a prefix tree.
- *
- * Routes order is preserved such that traversing the tree will traverse the
- * routes in the origin order.
- *
- * @param DumperCollection $collection A collection of routes
- *
- * @return DumperPrefixCollection
- */
- private function buildPrefixTree(DumperCollection $collection)
- {
- $tree = new DumperPrefixCollection();
- $current = $tree;
-
- foreach ($collection as $route) {
- $current = $current->addPrefixRoute($route);
- }
-
- $tree->mergeSlashNodes();
-
- return $tree;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher;
-
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\Route;
-
-/**
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-abstract class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
-{
- /**
- * {@inheritdoc}
- */
- public function match($pathinfo)
- {
- try {
- $parameters = parent::match($pathinfo);
- } catch (ResourceNotFoundException $e) {
- if ('/' === substr($pathinfo, -1) || !in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
- throw $e;
- }
-
- try {
- parent::match($pathinfo.'/');
-
- return $this->redirect($pathinfo.'/', null);
- } catch (ResourceNotFoundException $e2) {
- throw $e;
- }
- }
-
- return $parameters;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function handleRouteRequirements($pathinfo, $name, Route $route)
- {
- // check HTTP scheme requirement
- $scheme = $route->getRequirement('_scheme');
- if ($scheme && $this->context->getScheme() !== $scheme) {
- return array(self::ROUTE_MATCH, $this->redirect($pathinfo, $name, $scheme));
- }
-
- return array(self::REQUIREMENT_MATCH, null);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher;
-
-/**
- * RedirectableUrlMatcherInterface knows how to redirect the user.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-interface RedirectableUrlMatcherInterface
-{
- /**
- * Redirects the user to another URL.
- *
- * @param string $path The path info to redirect to.
- * @param string $route The route name that matched
- * @param string|null $scheme The URL scheme (null to keep the current one)
- *
- * @return array An array of parameters
- *
- * @api
- */
- public function redirect($path, $route, $scheme = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher;
-
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-
-/**
- * RequestMatcherInterface is the interface that all request matcher classes must implement.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface RequestMatcherInterface
-{
- /**
- * Tries to match a request with a set of routes.
- *
- * If the matcher can not find information, it must throw one of the exceptions documented
- * below.
- *
- * @param Request $request The request to match
- *
- * @return array An array of parameters
- *
- * @throws ResourceNotFoundException If no matching resource could be found
- * @throws MethodNotAllowedException If a matching resource was found but the request method is not allowed
- */
- public function matchRequest(Request $request);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher;
-
-use Symfony\Component\Routing\Exception\ExceptionInterface;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Matcher\UrlMatcher;
-
-/**
- * TraceableUrlMatcher helps debug path info matching by tracing the match.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TraceableUrlMatcher extends UrlMatcher
-{
- const ROUTE_DOES_NOT_MATCH = 0;
- const ROUTE_ALMOST_MATCHES = 1;
- const ROUTE_MATCHES = 2;
-
- protected $traces;
-
- public function getTraces($pathinfo)
- {
- $this->traces = array();
-
- try {
- $this->match($pathinfo);
- } catch (ExceptionInterface $e) {
- }
-
- return $this->traces;
- }
-
- protected function matchCollection($pathinfo, RouteCollection $routes)
- {
- foreach ($routes as $name => $route) {
- $compiledRoute = $route->compile();
-
- if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
- // does it match without any requirements?
- $r = new Route($route->getPath(), $route->getDefaults(), array(), $route->getOptions());
- $cr = $r->compile();
- if (!preg_match($cr->getRegex(), $pathinfo)) {
- $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
-
- continue;
- }
-
- foreach ($route->getRequirements() as $n => $regex) {
- $r = new Route($route->getPath(), $route->getDefaults(), array($n => $regex), $route->getOptions());
- $cr = $r->compile();
-
- if (in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) {
- $this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route);
-
- continue 2;
- }
- }
-
- continue;
- }
-
- // check host requirement
- $hostMatches = array();
- if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
- $this->addTrace(sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route);
-
- return true;
- }
-
- // check HTTP method requirement
- if ($req = $route->getRequirement('_method')) {
- // HEAD and GET are equivalent as per RFC
- if ('HEAD' === $method = $this->context->getMethod()) {
- $method = 'GET';
- }
-
- if (!in_array($method, $req = explode('|', strtoupper($req)))) {
- $this->allow = array_merge($this->allow, $req);
-
- $this->addTrace(sprintf('Method "%s" does not match the requirement ("%s")', $this->context->getMethod(), implode(', ', $req)), self::ROUTE_ALMOST_MATCHES, $name, $route);
-
- continue;
- }
- }
-
- // check HTTP scheme requirement
- if ($scheme = $route->getRequirement('_scheme')) {
- if ($this->context->getScheme() !== $scheme) {
- $this->addTrace(sprintf('Scheme "%s" does not match the requirement ("%s"); the user will be redirected', $this->context->getScheme(), $scheme), self::ROUTE_ALMOST_MATCHES, $name, $route);
-
- return true;
- }
- }
-
- $this->addTrace('Route matches!', self::ROUTE_MATCHES, $name, $route);
-
- return true;
- }
- }
-
- private function addTrace($log, $level = self::ROUTE_DOES_NOT_MATCH, $name = null, $route = null)
- {
- $this->traces[] = array(
- 'log' => $log,
- 'name' => $name,
- 'level' => $level,
- 'path' => null !== $route ? $route->getPath() : null,
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher;
-
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\RequestContext;
-use Symfony\Component\Routing\Route;
-
-/**
- * UrlMatcher matches URL based on a set of routes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class UrlMatcher implements UrlMatcherInterface
-{
- const REQUIREMENT_MATCH = 0;
- const REQUIREMENT_MISMATCH = 1;
- const ROUTE_MATCH = 2;
-
- /**
- * @var RequestContext
- */
- protected $context;
-
- /**
- * @var array
- */
- protected $allow = array();
-
- /**
- * @var RouteCollection
- */
- protected $routes;
-
- /**
- * Constructor.
- *
- * @param RouteCollection $routes A RouteCollection instance
- * @param RequestContext $context The context
- *
- * @api
- */
- public function __construct(RouteCollection $routes, RequestContext $context)
- {
- $this->routes = $routes;
- $this->context = $context;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setContext(RequestContext $context)
- {
- $this->context = $context;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getContext()
- {
- return $this->context;
- }
-
- /**
- * {@inheritdoc}
- */
- public function match($pathinfo)
- {
- $this->allow = array();
-
- if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) {
- return $ret;
- }
-
- throw 0 < count($this->allow)
- ? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow)))
- : new ResourceNotFoundException();
- }
-
- /**
- * Tries to match a URL with a set of routes.
- *
- * @param string $pathinfo The path info to be parsed
- * @param RouteCollection $routes The set of routes
- *
- * @return array An array of parameters
- *
- * @throws ResourceNotFoundException If the resource could not be found
- * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
- */
- protected function matchCollection($pathinfo, RouteCollection $routes)
- {
- foreach ($routes as $name => $route) {
- $compiledRoute = $route->compile();
-
- // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
- if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) {
- continue;
- }
-
- if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
- continue;
- }
-
- $hostMatches = array();
- if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
- continue;
- }
-
- // check HTTP method requirement
- if ($req = $route->getRequirement('_method')) {
- // HEAD and GET are equivalent as per RFC
- if ('HEAD' === $method = $this->context->getMethod()) {
- $method = 'GET';
- }
-
- if (!in_array($method, $req = explode('|', strtoupper($req)))) {
- $this->allow = array_merge($this->allow, $req);
-
- continue;
- }
- }
-
- $status = $this->handleRouteRequirements($pathinfo, $name, $route);
-
- if (self::ROUTE_MATCH === $status[0]) {
- return $status[1];
- }
-
- if (self::REQUIREMENT_MISMATCH === $status[0]) {
- continue;
- }
-
- return $this->getAttributes($route, $name, array_replace($matches, $hostMatches));
- }
- }
-
- /**
- * Returns an array of values to use as request attributes.
- *
- * As this method requires the Route object, it is not available
- * in matchers that do not have access to the matched Route instance
- * (like the PHP and Apache matcher dumpers).
- *
- * @param Route $route The route we are matching against
- * @param string $name The name of the route
- * @param array $attributes An array of attributes from the matcher
- *
- * @return array An array of parameters
- */
- protected function getAttributes(Route $route, $name, array $attributes)
- {
- $attributes['_route'] = $name;
-
- return $this->mergeDefaults($attributes, $route->getDefaults());
- }
-
- /**
- * Handles specific route requirements.
- *
- * @param string $pathinfo The path
- * @param string $name The route name
- * @param Route $route The route
- *
- * @return array The first element represents the status, the second contains additional information
- */
- protected function handleRouteRequirements($pathinfo, $name, Route $route)
- {
- // check HTTP scheme requirement
- $scheme = $route->getRequirement('_scheme');
- $status = $scheme && $scheme !== $this->context->getScheme() ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
-
- return array($status, null);
- }
-
- /**
- * Get merged default parameters.
- *
- * @param array $params The parameters
- * @param array $defaults The defaults
- *
- * @return array Merged default parameters
- */
- protected function mergeDefaults($params, $defaults)
- {
- foreach ($params as $key => $value) {
- if (!is_int($key)) {
- $defaults[$key] = $value;
- }
- }
-
- return $defaults;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Matcher;
-
-use Symfony\Component\Routing\RequestContextAwareInterface;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-
-/**
- * UrlMatcherInterface is the interface that all URL matcher classes must implement.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-interface UrlMatcherInterface extends RequestContextAwareInterface
-{
- /**
- * Tries to match a URL path with a set of routes.
- *
- * If the matcher can not find information, it must throw one of the exceptions documented
- * below.
- *
- * @param string $pathinfo The path info to be parsed (raw format, i.e. not urldecoded)
- *
- * @return array An array of parameters
- *
- * @throws ResourceNotFoundException If the resource could not be found
- * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
- *
- * @api
- */
- public function match($pathinfo);
-}
+++ /dev/null
-Routing Component
-=================
-
-Routing associates a request with the code that will convert it to a response.
-
-The example below demonstrates how you can set up a fully working routing
-system:
-
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\Routing\Matcher\UrlMatcher;
- use Symfony\Component\Routing\RequestContext;
- use Symfony\Component\Routing\RouteCollection;
- use Symfony\Component\Routing\Route;
-
- $routes = new RouteCollection();
- $routes->add('hello', new Route('/hello', array('controller' => 'foo')));
-
- $context = new RequestContext();
-
- // this is optional and can be done without a Request instance
- $context->fromRequest(Request::createFromGlobals());
-
- $matcher = new UrlMatcher($routes, $context);
-
- $parameters = $matcher->match('/hello');
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/Routing/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Holds information about the current request.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class RequestContext
-{
- private $baseUrl;
- private $pathInfo;
- private $method;
- private $host;
- private $scheme;
- private $httpPort;
- private $httpsPort;
- private $queryString;
-
- /**
- * @var array
- */
- private $parameters = array();
-
- /**
- * Constructor.
- *
- * @param string $baseUrl The base URL
- * @param string $method The HTTP method
- * @param string $host The HTTP host name
- * @param string $scheme The HTTP scheme
- * @param integer $httpPort The HTTP port
- * @param integer $httpsPort The HTTPS port
- * @param string $path The path
- * @param string $queryString The query string
- *
- * @api
- */
- public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443, $path = '/', $queryString = '')
- {
- $this->baseUrl = $baseUrl;
- $this->method = strtoupper($method);
- $this->host = $host;
- $this->scheme = strtolower($scheme);
- $this->httpPort = $httpPort;
- $this->httpsPort = $httpsPort;
- $this->pathInfo = $path;
- $this->queryString = $queryString;
- }
-
- public function fromRequest(Request $request)
- {
- $this->setBaseUrl($request->getBaseUrl());
- $this->setPathInfo($request->getPathInfo());
- $this->setMethod($request->getMethod());
- $this->setHost($request->getHost());
- $this->setScheme($request->getScheme());
- $this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort());
- $this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort);
- $this->setQueryString($request->server->get('QUERY_STRING'));
- }
-
- /**
- * Gets the base URL.
- *
- * @return string The base URL
- */
- public function getBaseUrl()
- {
- return $this->baseUrl;
- }
-
- /**
- * Sets the base URL.
- *
- * @param string $baseUrl The base URL
- *
- * @api
- */
- public function setBaseUrl($baseUrl)
- {
- $this->baseUrl = $baseUrl;
- }
-
- /**
- * Gets the path info.
- *
- * @return string The path info
- */
- public function getPathInfo()
- {
- return $this->pathInfo;
- }
-
- /**
- * Sets the path info.
- *
- * @param string $pathInfo The path info
- */
- public function setPathInfo($pathInfo)
- {
- $this->pathInfo = $pathInfo;
- }
-
- /**
- * Gets the HTTP method.
- *
- * The method is always an uppercased string.
- *
- * @return string The HTTP method
- */
- public function getMethod()
- {
- return $this->method;
- }
-
- /**
- * Sets the HTTP method.
- *
- * @param string $method The HTTP method
- *
- * @api
- */
- public function setMethod($method)
- {
- $this->method = strtoupper($method);
- }
-
- /**
- * Gets the HTTP host.
- *
- * @return string The HTTP host
- */
- public function getHost()
- {
- return $this->host;
- }
-
- /**
- * Sets the HTTP host.
- *
- * @param string $host The HTTP host
- *
- * @api
- */
- public function setHost($host)
- {
- $this->host = $host;
- }
-
- /**
- * Gets the HTTP scheme.
- *
- * @return string The HTTP scheme
- */
- public function getScheme()
- {
- return $this->scheme;
- }
-
- /**
- * Sets the HTTP scheme.
- *
- * @param string $scheme The HTTP scheme
- *
- * @api
- */
- public function setScheme($scheme)
- {
- $this->scheme = strtolower($scheme);
- }
-
- /**
- * Gets the HTTP port.
- *
- * @return string The HTTP port
- */
- public function getHttpPort()
- {
- return $this->httpPort;
- }
-
- /**
- * Sets the HTTP port.
- *
- * @param string $httpPort The HTTP port
- *
- * @api
- */
- public function setHttpPort($httpPort)
- {
- $this->httpPort = $httpPort;
- }
-
- /**
- * Gets the HTTPS port.
- *
- * @return string The HTTPS port
- */
- public function getHttpsPort()
- {
- return $this->httpsPort;
- }
-
- /**
- * Sets the HTTPS port.
- *
- * @param string $httpsPort The HTTPS port
- *
- * @api
- */
- public function setHttpsPort($httpsPort)
- {
- $this->httpsPort = $httpsPort;
- }
-
- /**
- * Gets the query string.
- *
- * @return string The query string
- */
- public function getQueryString()
- {
- return $this->queryString;
- }
-
- /**
- * Sets the query string.
- *
- * @param string $queryString The query string
- *
- * @api
- */
- public function setQueryString($queryString)
- {
- $this->queryString = $queryString;
- }
-
- /**
- * Returns the parameters.
- *
- * @return array The parameters
- */
- public function getParameters()
- {
- return $this->parameters;
- }
-
- /**
- * Sets the parameters.
- *
- * This method implements a fluent interface.
- *
- * @param array $parameters The parameters
- *
- * @return Route The current Route instance
- */
- public function setParameters(array $parameters)
- {
- $this->parameters = $parameters;
-
- return $this;
- }
-
- /**
- * Gets a parameter value.
- *
- * @param string $name A parameter name
- *
- * @return mixed The parameter value
- */
- public function getParameter($name)
- {
- return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
- }
-
- /**
- * Checks if a parameter value is set for the given parameter.
- *
- * @param string $name A parameter name
- *
- * @return Boolean true if the parameter value is set, false otherwise
- */
- public function hasParameter($name)
- {
- return array_key_exists($name, $this->parameters);
- }
-
- /**
- * Sets a parameter value.
- *
- * @param string $name A parameter name
- * @param mixed $parameter The parameter value
- *
- * @api
- */
- public function setParameter($name, $parameter)
- {
- $this->parameters[$name] = $parameter;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-/**
- * @api
- */
-interface RequestContextAwareInterface
-{
- /**
- * Sets the request context.
- *
- * @param RequestContext $context The context
- *
- * @api
- */
- public function setContext(RequestContext $context);
-
- /**
- * Gets the request context.
- *
- * @return RequestContext The context
- *
- * @api
- */
- public function getContext();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-/**
- * A Route describes a route and its parameters.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- *
- * @api
- */
-class Route implements \Serializable
-{
- /**
- * @var string
- */
- private $path = '/';
-
- /**
- * @var string
- */
- private $host = '';
-
- /**
- * @var array
- */
- private $schemes = array();
-
- /**
- * @var array
- */
- private $methods = array();
-
- /**
- * @var array
- */
- private $defaults = array();
-
- /**
- * @var array
- */
- private $requirements = array();
-
- /**
- * @var array
- */
- private $options = array();
-
- /**
- * @var null|RouteCompiler
- */
- private $compiled;
-
- /**
- * Constructor.
- *
- * Available options:
- *
- * * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
- *
- * @param string $path The path pattern to match
- * @param array $defaults An array of default parameter values
- * @param array $requirements An array of requirements for parameters (regexes)
- * @param array $options An array of options
- * @param string $host The host pattern to match
- * @param string|array $schemes A required URI scheme or an array of restricted schemes
- * @param string|array $methods A required HTTP method or an array of restricted methods
- *
- * @api
- */
- public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array())
- {
- $this->setPath($path);
- $this->setDefaults($defaults);
- $this->setRequirements($requirements);
- $this->setOptions($options);
- $this->setHost($host);
- // The conditions make sure that an initial empty $schemes/$methods does not override the corresponding requirement.
- // They can be removed when the BC layer is removed.
- if ($schemes) {
- $this->setSchemes($schemes);
- }
- if ($methods) {
- $this->setMethods($methods);
- }
- }
-
- public function serialize()
- {
- return serialize(array(
- 'path' => $this->path,
- 'host' => $this->host,
- 'defaults' => $this->defaults,
- 'requirements' => $this->requirements,
- 'options' => $this->options,
- 'schemes' => $this->schemes,
- 'methods' => $this->methods,
- ));
- }
-
- public function unserialize($data)
- {
- $data = unserialize($data);
- $this->path = $data['path'];
- $this->host = $data['host'];
- $this->defaults = $data['defaults'];
- $this->requirements = $data['requirements'];
- $this->options = $data['options'];
- $this->schemes = $data['schemes'];
- $this->methods = $data['methods'];
- }
-
- /**
- * Returns the pattern for the path.
- *
- * @return string The pattern
- *
- * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
- */
- public function getPattern()
- {
- return $this->path;
- }
-
- /**
- * Sets the pattern for the path.
- *
- * This method implements a fluent interface.
- *
- * @param string $pattern The path pattern
- *
- * @return Route The current Route instance
- *
- * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
- */
- public function setPattern($pattern)
- {
- return $this->setPath($pattern);
- }
-
- /**
- * Returns the pattern for the path.
- *
- * @return string The path pattern
- */
- public function getPath()
- {
- return $this->path;
- }
-
- /**
- * Sets the pattern for the path.
- *
- * This method implements a fluent interface.
- *
- * @param string $pattern The path pattern
- *
- * @return Route The current Route instance
- */
- public function setPath($pattern)
- {
- // A pattern must start with a slash and must not have multiple slashes at the beginning because the
- // generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
- $this->path = '/'.ltrim(trim($pattern), '/');
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Returns the pattern for the host.
- *
- * @return string The host pattern
- */
- public function getHost()
- {
- return $this->host;
- }
-
- /**
- * Sets the pattern for the host.
- *
- * This method implements a fluent interface.
- *
- * @param string $pattern The host pattern
- *
- * @return Route The current Route instance
- */
- public function setHost($pattern)
- {
- $this->host = (string) $pattern;
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Returns the lowercased schemes this route is restricted to.
- * So an empty array means that any scheme is allowed.
- *
- * @return array The schemes
- */
- public function getSchemes()
- {
- return $this->schemes;
- }
-
- /**
- * Sets the schemes (e.g. 'https') this route is restricted to.
- * So an empty array means that any scheme is allowed.
- *
- * This method implements a fluent interface.
- *
- * @param string|array $schemes The scheme or an array of schemes
- *
- * @return Route The current Route instance
- */
- public function setSchemes($schemes)
- {
- $this->schemes = array_map('strtolower', (array) $schemes);
-
- // this is to keep BC and will be removed in a future version
- if ($this->schemes) {
- $this->requirements['_scheme'] = implode('|', $this->schemes);
- } else {
- unset($this->requirements['_scheme']);
- }
-
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Returns the uppercased HTTP methods this route is restricted to.
- * So an empty array means that any method is allowed.
- *
- * @return array The schemes
- */
- public function getMethods()
- {
- return $this->methods;
- }
-
- /**
- * Sets the HTTP methods (e.g. 'POST') this route is restricted to.
- * So an empty array means that any method is allowed.
- *
- * This method implements a fluent interface.
- *
- * @param string|array $methods The method or an array of methods
- *
- * @return Route The current Route instance
- */
- public function setMethods($methods)
- {
- $this->methods = array_map('strtoupper', (array) $methods);
-
- // this is to keep BC and will be removed in a future version
- if ($this->methods) {
- $this->requirements['_method'] = implode('|', $this->methods);
- } else {
- unset($this->requirements['_method']);
- }
-
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Returns the options.
- *
- * @return array The options
- */
- public function getOptions()
- {
- return $this->options;
- }
-
- /**
- * Sets the options.
- *
- * This method implements a fluent interface.
- *
- * @param array $options The options
- *
- * @return Route The current Route instance
- */
- public function setOptions(array $options)
- {
- $this->options = array(
- 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
- );
-
- return $this->addOptions($options);
- }
-
- /**
- * Adds options.
- *
- * This method implements a fluent interface.
- *
- * @param array $options The options
- *
- * @return Route The current Route instance
- */
- public function addOptions(array $options)
- {
- foreach ($options as $name => $option) {
- $this->options[$name] = $option;
- }
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Sets an option value.
- *
- * This method implements a fluent interface.
- *
- * @param string $name An option name
- * @param mixed $value The option value
- *
- * @return Route The current Route instance
- *
- * @api
- */
- public function setOption($name, $value)
- {
- $this->options[$name] = $value;
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Get an option value.
- *
- * @param string $name An option name
- *
- * @return mixed The option value or null when not given
- */
- public function getOption($name)
- {
- return isset($this->options[$name]) ? $this->options[$name] : null;
- }
-
- /**
- * Checks if an option has been set
- *
- * @param string $name An option name
- *
- * @return Boolean true if the option is set, false otherwise
- */
- public function hasOption($name)
- {
- return array_key_exists($name, $this->options);
- }
-
- /**
- * Returns the defaults.
- *
- * @return array The defaults
- */
- public function getDefaults()
- {
- return $this->defaults;
- }
-
- /**
- * Sets the defaults.
- *
- * This method implements a fluent interface.
- *
- * @param array $defaults The defaults
- *
- * @return Route The current Route instance
- */
- public function setDefaults(array $defaults)
- {
- $this->defaults = array();
-
- return $this->addDefaults($defaults);
- }
-
- /**
- * Adds defaults.
- *
- * This method implements a fluent interface.
- *
- * @param array $defaults The defaults
- *
- * @return Route The current Route instance
- */
- public function addDefaults(array $defaults)
- {
- foreach ($defaults as $name => $default) {
- $this->defaults[$name] = $default;
- }
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Gets a default value.
- *
- * @param string $name A variable name
- *
- * @return mixed The default value or null when not given
- */
- public function getDefault($name)
- {
- return isset($this->defaults[$name]) ? $this->defaults[$name] : null;
- }
-
- /**
- * Checks if a default value is set for the given variable.
- *
- * @param string $name A variable name
- *
- * @return Boolean true if the default value is set, false otherwise
- */
- public function hasDefault($name)
- {
- return array_key_exists($name, $this->defaults);
- }
-
- /**
- * Sets a default value.
- *
- * @param string $name A variable name
- * @param mixed $default The default value
- *
- * @return Route The current Route instance
- *
- * @api
- */
- public function setDefault($name, $default)
- {
- $this->defaults[$name] = $default;
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Returns the requirements.
- *
- * @return array The requirements
- */
- public function getRequirements()
- {
- return $this->requirements;
- }
-
- /**
- * Sets the requirements.
- *
- * This method implements a fluent interface.
- *
- * @param array $requirements The requirements
- *
- * @return Route The current Route instance
- */
- public function setRequirements(array $requirements)
- {
- $this->requirements = array();
-
- return $this->addRequirements($requirements);
- }
-
- /**
- * Adds requirements.
- *
- * This method implements a fluent interface.
- *
- * @param array $requirements The requirements
- *
- * @return Route The current Route instance
- */
- public function addRequirements(array $requirements)
- {
- foreach ($requirements as $key => $regex) {
- $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
- }
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Returns the requirement for the given key.
- *
- * @param string $key The key
- *
- * @return string|null The regex or null when not given
- */
- public function getRequirement($key)
- {
- return isset($this->requirements[$key]) ? $this->requirements[$key] : null;
- }
-
- /**
- * Checks if a requirement is set for the given key.
- *
- * @param string $key A variable name
- *
- * @return Boolean true if a requirement is specified, false otherwise
- */
- public function hasRequirement($key)
- {
- return array_key_exists($key, $this->requirements);
- }
-
- /**
- * Sets a requirement for the given key.
- *
- * @param string $key The key
- * @param string $regex The regex
- *
- * @return Route The current Route instance
- *
- * @api
- */
- public function setRequirement($key, $regex)
- {
- $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
- $this->compiled = null;
-
- return $this;
- }
-
- /**
- * Compiles the route.
- *
- * @return CompiledRoute A CompiledRoute instance
- *
- * @throws \LogicException If the Route cannot be compiled because the
- * path or host pattern is invalid
- *
- * @see RouteCompiler which is responsible for the compilation process
- */
- public function compile()
- {
- if (null !== $this->compiled) {
- return $this->compiled;
- }
-
- $class = $this->getOption('compiler_class');
-
- return $this->compiled = $class::compile($this);
- }
-
- private function sanitizeRequirement($key, $regex)
- {
- if (!is_string($regex)) {
- throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string.', $key));
- }
-
- if ('' !== $regex && '^' === $regex[0]) {
- $regex = (string) substr($regex, 1); // returns false for a single character
- }
-
- if ('$' === substr($regex, -1)) {
- $regex = substr($regex, 0, -1);
- }
-
- if ('' === $regex) {
- throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
- }
-
- // this is to keep BC and will be removed in a future version
- if ('_scheme' === $key) {
- $this->setSchemes(explode('|', $regex));
- } elseif ('_method' === $key) {
- $this->setMethods(explode('|', $regex));
- }
-
- return $regex;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-use Symfony\Component\Config\Resource\ResourceInterface;
-
-/**
- * A RouteCollection represents a set of Route instances.
- *
- * When adding a route at the end of the collection, an existing route
- * with the same name is removed first. So there can only be one route
- * with a given name.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- *
- * @api
- */
-class RouteCollection implements \IteratorAggregate, \Countable
-{
- /**
- * @var Route[]
- */
- private $routes = array();
-
- /**
- * @var array
- */
- private $resources = array();
-
- public function __clone()
- {
- foreach ($this->routes as $name => $route) {
- $this->routes[$name] = clone $route;
- }
- }
-
- /**
- * Gets the current RouteCollection as an Iterator that includes all routes.
- *
- * It implements \IteratorAggregate.
- *
- * @see all()
- *
- * @return \ArrayIterator An \ArrayIterator object for iterating over routes
- */
- public function getIterator()
- {
- return new \ArrayIterator($this->routes);
- }
-
- /**
- * Gets the number of Routes in this collection.
- *
- * @return int The number of routes
- */
- public function count()
- {
- return count($this->routes);
- }
-
- /**
- * Adds a route.
- *
- * @param string $name The route name
- * @param Route $route A Route instance
- *
- * @api
- */
- public function add($name, Route $route)
- {
- unset($this->routes[$name]);
-
- $this->routes[$name] = $route;
- }
-
- /**
- * Returns all routes in this collection.
- *
- * @return Route[] An array of routes
- */
- public function all()
- {
- return $this->routes;
- }
-
- /**
- * Gets a route by name.
- *
- * @param string $name The route name
- *
- * @return Route|null A Route instance or null when not found
- */
- public function get($name)
- {
- return isset($this->routes[$name]) ? $this->routes[$name] : null;
- }
-
- /**
- * Removes a route or an array of routes by name from the collection
- *
- * @param string|array $name The route name or an array of route names
- */
- public function remove($name)
- {
- foreach ((array) $name as $n) {
- unset($this->routes[$n]);
- }
- }
-
- /**
- * Adds a route collection at the end of the current set by appending all
- * routes of the added collection.
- *
- * @param RouteCollection $collection A RouteCollection instance
- *
- * @api
- */
- public function addCollection(RouteCollection $collection)
- {
- // we need to remove all routes with the same names first because just replacing them
- // would not place the new route at the end of the merged array
- foreach ($collection->all() as $name => $route) {
- unset($this->routes[$name]);
- $this->routes[$name] = $route;
- }
-
- $this->resources = array_merge($this->resources, $collection->getResources());
- }
-
- /**
- * Adds a prefix to the path of all child routes.
- *
- * @param string $prefix An optional prefix to add before each pattern of the route collection
- * @param array $defaults An array of default values
- * @param array $requirements An array of requirements
- *
- * @api
- */
- public function addPrefix($prefix, array $defaults = array(), array $requirements = array())
- {
- $prefix = trim(trim($prefix), '/');
-
- if ('' === $prefix) {
- return;
- }
-
- foreach ($this->routes as $route) {
- $route->setPath('/'.$prefix.$route->getPath());
- $route->addDefaults($defaults);
- $route->addRequirements($requirements);
- }
- }
-
- /**
- * Sets the host pattern on all routes.
- *
- * @param string $pattern The pattern
- * @param array $defaults An array of default values
- * @param array $requirements An array of requirements
- */
- public function setHost($pattern, array $defaults = array(), array $requirements = array())
- {
- foreach ($this->routes as $route) {
- $route->setHost($pattern);
- $route->addDefaults($defaults);
- $route->addRequirements($requirements);
- }
- }
-
- /**
- * Adds defaults to all routes.
- *
- * An existing default value under the same name in a route will be overridden.
- *
- * @param array $defaults An array of default values
- */
- public function addDefaults(array $defaults)
- {
- if ($defaults) {
- foreach ($this->routes as $route) {
- $route->addDefaults($defaults);
- }
- }
- }
-
- /**
- * Adds requirements to all routes.
- *
- * An existing requirement under the same name in a route will be overridden.
- *
- * @param array $requirements An array of requirements
- */
- public function addRequirements(array $requirements)
- {
- if ($requirements) {
- foreach ($this->routes as $route) {
- $route->addRequirements($requirements);
- }
- }
- }
-
- /**
- * Adds options to all routes.
- *
- * An existing option value under the same name in a route will be overridden.
- *
- * @param array $options An array of options
- */
- public function addOptions(array $options)
- {
- if ($options) {
- foreach ($this->routes as $route) {
- $route->addOptions($options);
- }
- }
- }
-
- /**
- * Sets the schemes (e.g. 'https') all child routes are restricted to.
- *
- * @param string|array $schemes The scheme or an array of schemes
- */
- public function setSchemes($schemes)
- {
- foreach ($this->routes as $route) {
- $route->setSchemes($schemes);
- }
- }
-
- /**
- * Sets the HTTP methods (e.g. 'POST') all child routes are restricted to.
- *
- * @param string|array $methods The method or an array of methods
- */
- public function setMethods($methods)
- {
- foreach ($this->routes as $route) {
- $route->setMethods($methods);
- }
- }
-
- /**
- * Returns an array of resources loaded to build this collection.
- *
- * @return ResourceInterface[] An array of resources
- */
- public function getResources()
- {
- return array_unique($this->resources);
- }
-
- /**
- * Adds a resource for this collection.
- *
- * @param ResourceInterface $resource A resource instance
- */
- public function addResource(ResourceInterface $resource)
- {
- $this->resources[] = $resource;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-/**
- * RouteCompiler compiles Route instances to CompiledRoute instances.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Tobias Schultze <http://tobion.de>
- */
-class RouteCompiler implements RouteCompilerInterface
-{
- const REGEX_DELIMITER = '#';
-
- /**
- * This string defines the characters that are automatically considered separators in front of
- * optional placeholders (with default and no static text following). Such a single separator
- * can be left out together with the optional placeholder from matching and generating URLs.
- */
- const SEPARATORS = '/,;.:-_~+*=@|';
-
- /**
- * {@inheritDoc}
- *
- * @throws \LogicException If a variable is referenced more than once
- * @throws \DomainException If a variable name is numeric because PHP raises an error for such
- * subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)".
- */
- public static function compile(Route $route)
- {
- $staticPrefix = null;
- $hostVariables = array();
- $pathVariables = array();
- $variables = array();
- $tokens = array();
- $regex = null;
- $hostRegex = null;
- $hostTokens = array();
-
- if ('' !== $host = $route->getHost()) {
- $result = self::compilePattern($route, $host, true);
-
- $hostVariables = $result['variables'];
- $variables = array_merge($variables, $hostVariables);
-
- $hostTokens = $result['tokens'];
- $hostRegex = $result['regex'];
- }
-
- $path = $route->getPath();
-
- $result = self::compilePattern($route, $path, false);
-
- $staticPrefix = $result['staticPrefix'];
-
- $pathVariables = $result['variables'];
- $variables = array_merge($variables, $pathVariables);
-
- $tokens = $result['tokens'];
- $regex = $result['regex'];
-
- return new CompiledRoute(
- $staticPrefix,
- $regex,
- $tokens,
- $pathVariables,
- $hostRegex,
- $hostTokens,
- $hostVariables,
- array_unique($variables)
- );
- }
-
- private static function compilePattern(Route $route, $pattern, $isHost)
- {
- $tokens = array();
- $variables = array();
- $matches = array();
- $pos = 0;
- $defaultSeparator = $isHost ? '.' : '/';
-
- // Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable
- // in case of nested "{}", e.g. {foo{bar}}. This in ensured because \w does not match "{" or "}" itself.
- preg_match_all('#\{\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
- foreach ($matches as $match) {
- $varName = substr($match[0][0], 1, -1);
- // get all static text preceding the current variable
- $precedingText = substr($pattern, $pos, $match[0][1] - $pos);
- $pos = $match[0][1] + strlen($match[0][0]);
- $precedingChar = strlen($precedingText) > 0 ? substr($precedingText, -1) : '';
- $isSeparator = '' !== $precedingChar && false !== strpos(static::SEPARATORS, $precedingChar);
-
- if (is_numeric($varName)) {
- throw new \DomainException(sprintf('Variable name "%s" cannot be numeric in route pattern "%s". Please use a different name.', $varName, $pattern));
- }
- if (in_array($varName, $variables)) {
- throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName));
- }
-
- if ($isSeparator && strlen($precedingText) > 1) {
- $tokens[] = array('text', substr($precedingText, 0, -1));
- } elseif (!$isSeparator && strlen($precedingText) > 0) {
- $tokens[] = array('text', $precedingText);
- }
-
- $regexp = $route->getRequirement($varName);
- if (null === $regexp) {
- $followingPattern = (string) substr($pattern, $pos);
- // Find the next static character after the variable that functions as a separator. By default, this separator and '/'
- // are disallowed for the variable. This default requirement makes sure that optional variables can be matched at all
- // and that the generating-matching-combination of URLs unambiguous, i.e. the params used for generating the URL are
- // the same that will be matched. Example: new Route('/{page}.{_format}', array('_format' => 'html'))
- // If {page} would also match the separating dot, {_format} would never match as {page} will eagerly consume everything.
- // Also even if {_format} was not optional the requirement prevents that {page} matches something that was originally
- // part of {_format} when generating the URL, e.g. _format = 'mobile.html'.
- $nextSeparator = self::findNextSeparator($followingPattern);
- $regexp = sprintf(
- '[^%s%s]+',
- preg_quote($defaultSeparator, self::REGEX_DELIMITER),
- $defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator, self::REGEX_DELIMITER) : ''
- );
- if (('' !== $nextSeparator && !preg_match('#^\{\w+\}#', $followingPattern)) || '' === $followingPattern) {
- // When we have a separator, which is disallowed for the variable, we can optimize the regex with a possessive
- // quantifier. This prevents useless backtracking of PCRE and improves performance by 20% for matching those patterns.
- // Given the above example, there is no point in backtracking into {page} (that forbids the dot) when a dot must follow
- // after it. This optimization cannot be applied when the next char is no real separator or when the next variable is
- // directly adjacent, e.g. '/{x}{y}'.
- $regexp .= '+';
- }
- }
-
- $tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName);
- $variables[] = $varName;
- }
-
- if ($pos < strlen($pattern)) {
- $tokens[] = array('text', substr($pattern, $pos));
- }
-
- // find the first optional token
- $firstOptional = PHP_INT_MAX;
- if (!$isHost) {
- for ($i = count($tokens) - 1; $i >= 0; $i--) {
- $token = $tokens[$i];
- if ('variable' === $token[0] && $route->hasDefault($token[3])) {
- $firstOptional = $i;
- } else {
- break;
- }
- }
- }
-
- // compute the matching regexp
- $regexp = '';
- for ($i = 0, $nbToken = count($tokens); $i < $nbToken; $i++) {
- $regexp .= self::computeRegexp($tokens, $i, $firstOptional);
- }
-
- return array(
- 'staticPrefix' => 'text' === $tokens[0][0] ? $tokens[0][1] : '',
- 'regex' => self::REGEX_DELIMITER.'^'.$regexp.'$'.self::REGEX_DELIMITER.'s',
- 'tokens' => array_reverse($tokens),
- 'variables' => $variables,
- );
- }
-
- /**
- * Returns the next static character in the Route pattern that will serve as a separator.
- *
- * @param string $pattern The route pattern
- *
- * @return string The next static character that functions as separator (or empty string when none available)
- */
- private static function findNextSeparator($pattern)
- {
- if ('' == $pattern) {
- // return empty string if pattern is empty or false (false which can be returned by substr)
- return '';
- }
- // first remove all placeholders from the pattern so we can find the next real static character
- $pattern = preg_replace('#\{\w+\}#', '', $pattern);
-
- return isset($pattern[0]) && false !== strpos(static::SEPARATORS, $pattern[0]) ? $pattern[0] : '';
- }
-
- /**
- * Computes the regexp used to match a specific token. It can be static text or a subpattern.
- *
- * @param array $tokens The route tokens
- * @param integer $index The index of the current token
- * @param integer $firstOptional The index of the first optional token
- *
- * @return string The regexp pattern for a single token
- */
- private static function computeRegexp(array $tokens, $index, $firstOptional)
- {
- $token = $tokens[$index];
- if ('text' === $token[0]) {
- // Text tokens
- return preg_quote($token[1], self::REGEX_DELIMITER);
- } else {
- // Variable tokens
- if (0 === $index && 0 === $firstOptional) {
- // When the only token is an optional variable token, the separator is required
- return sprintf('%s(?P<%s>%s)?', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]);
- } else {
- $regexp = sprintf('%s(?P<%s>%s)', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]);
- if ($index >= $firstOptional) {
- // Enclose each optional token in a subpattern to make it optional.
- // "?:" means it is non-capturing, i.e. the portion of the subject string that
- // matched the optional subpattern is not passed back.
- $regexp = "(?:$regexp";
- $nbTokens = count($tokens);
- if ($nbTokens - 1 == $index) {
- // Close the optional subpatterns
- $regexp .= str_repeat(")?", $nbTokens - $firstOptional - (0 === $firstOptional ? 1 : 0));
- }
- }
-
- return $regexp;
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-/**
- * RouteCompilerInterface is the interface that all RouteCompiler classes must implement.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface RouteCompilerInterface
-{
- /**
- * Compiles the current route instance.
- *
- * @param Route $route A Route instance
- *
- * @return CompiledRoute A CompiledRoute instance
- *
- * @throws \LogicException If the Route cannot be compiled because the
- * path or host pattern is invalid
- */
- public static function compile(Route $route);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-use Symfony\Component\Config\Loader\LoaderInterface;
-use Symfony\Component\Config\ConfigCache;
-use Psr\Log\LoggerInterface;
-use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface;
-use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
-use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
-
-/**
- * The Router class is an example of the integration of all pieces of the
- * routing system for easier use.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Router implements RouterInterface
-{
- /**
- * @var UrlMatcherInterface|null
- */
- protected $matcher;
-
- /**
- * @var UrlGeneratorInterface|null
- */
- protected $generator;
-
- /**
- * @var RequestContext
- */
- protected $context;
-
- /**
- * @var LoaderInterface
- */
- protected $loader;
-
- /**
- * @var RouteCollection|null
- */
- protected $collection;
-
- /**
- * @var mixed
- */
- protected $resource;
-
- /**
- * @var array
- */
- protected $options = array();
-
- /**
- * @var LoggerInterface|null
- */
- protected $logger;
-
- /**
- * Constructor.
- *
- * @param LoaderInterface $loader A LoaderInterface instance
- * @param mixed $resource The main resource to load
- * @param array $options An array of options
- * @param RequestContext $context The context
- * @param LoggerInterface $logger A logger instance
- */
- public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, LoggerInterface $logger = null)
- {
- $this->loader = $loader;
- $this->resource = $resource;
- $this->logger = $logger;
- $this->context = null === $context ? new RequestContext() : $context;
- $this->setOptions($options);
- }
-
- /**
- * Sets options.
- *
- * Available options:
- *
- * * cache_dir: The cache directory (or null to disable caching)
- * * debug: Whether to enable debugging or not (false by default)
- * * resource_type: Type hint for the main resource (optional)
- *
- * @param array $options An array of options
- *
- * @throws \InvalidArgumentException When unsupported option is provided
- */
- public function setOptions(array $options)
- {
- $this->options = array(
- 'cache_dir' => null,
- 'debug' => false,
- 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
- 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
- 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper',
- 'generator_cache_class' => 'ProjectUrlGenerator',
- 'matcher_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
- 'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
- 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
- 'matcher_cache_class' => 'ProjectUrlMatcher',
- 'resource_type' => null,
- 'strict_requirements' => true,
- );
-
- // check option names and live merge, if errors are encountered Exception will be thrown
- $invalid = array();
- foreach ($options as $key => $value) {
- if (array_key_exists($key, $this->options)) {
- $this->options[$key] = $value;
- } else {
- $invalid[] = $key;
- }
- }
-
- if ($invalid) {
- throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid)));
- }
- }
-
- /**
- * Sets an option.
- *
- * @param string $key The key
- * @param mixed $value The value
- *
- * @throws \InvalidArgumentException
- */
- public function setOption($key, $value)
- {
- if (!array_key_exists($key, $this->options)) {
- throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
- }
-
- $this->options[$key] = $value;
- }
-
- /**
- * Gets an option value.
- *
- * @param string $key The key
- *
- * @return mixed The value
- *
- * @throws \InvalidArgumentException
- */
- public function getOption($key)
- {
- if (!array_key_exists($key, $this->options)) {
- throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
- }
-
- return $this->options[$key];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRouteCollection()
- {
- if (null === $this->collection) {
- $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
- }
-
- return $this->collection;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setContext(RequestContext $context)
- {
- $this->context = $context;
-
- if (null !== $this->matcher) {
- $this->getMatcher()->setContext($context);
- }
- if (null !== $this->generator) {
- $this->getGenerator()->setContext($context);
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function getContext()
- {
- return $this->context;
- }
-
- /**
- * {@inheritdoc}
- */
- public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
- {
- return $this->getGenerator()->generate($name, $parameters, $referenceType);
- }
-
- /**
- * {@inheritdoc}
- */
- public function match($pathinfo)
- {
- return $this->getMatcher()->match($pathinfo);
- }
-
- /**
- * Gets the UrlMatcher instance associated with this Router.
- *
- * @return UrlMatcherInterface A UrlMatcherInterface instance
- */
- public function getMatcher()
- {
- if (null !== $this->matcher) {
- return $this->matcher;
- }
-
- if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
- return $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context);
- }
-
- $class = $this->options['matcher_cache_class'];
- $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
- if (!$cache->isFresh($class)) {
- $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection());
-
- $options = array(
- 'class' => $class,
- 'base_class' => $this->options['matcher_base_class'],
- );
-
- $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
- }
-
- require_once $cache;
-
- return $this->matcher = new $class($this->context);
- }
-
- /**
- * Gets the UrlGenerator instance associated with this Router.
- *
- * @return UrlGeneratorInterface A UrlGeneratorInterface instance
- */
- public function getGenerator()
- {
- if (null !== $this->generator) {
- return $this->generator;
- }
-
- if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
- $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger);
- } else {
- $class = $this->options['generator_cache_class'];
- $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
- if (!$cache->isFresh($class)) {
- $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
-
- $options = array(
- 'class' => $class,
- 'base_class' => $this->options['generator_base_class'],
- );
-
- $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
- }
-
- require_once $cache;
-
- $this->generator = new $class($this->context, $this->logger);
- }
-
- if ($this->generator instanceof ConfigurableRequirementsInterface) {
- $this->generator->setStrictRequirements($this->options['strict_requirements']);
- }
-
- return $this->generator;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing;
-
-use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
-use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
-
-/**
- * RouterInterface is the interface that all Router classes must implement.
- *
- * This interface is the concatenation of UrlMatcherInterface and UrlGeneratorInterface.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface RouterInterface extends UrlMatcherInterface, UrlGeneratorInterface
-{
- /**
- * Gets the RouteCollection instance associated with this Router.
- *
- * @return RouteCollection A RouteCollection instance
- */
- public function getRouteCollection();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Annotation;
-
-use Symfony\Component\Routing\Annotation\Route;
-
-class RouteTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @expectedException \BadMethodCallException
- */
- public function testInvalidRouteParameter()
- {
- $route = new Route(array('foo' => 'bar'));
- }
-
- /**
- * @dataProvider getValidParameters
- */
- public function testRouteParameters($parameter, $value, $getter)
- {
- $route = new Route(array($parameter => $value));
- $this->assertEquals($route->$getter(), $value);
- }
-
- public function getValidParameters()
- {
- return array(
- array('value', '/Blog', 'getPattern'),
- array('value', '/Blog', 'getPath'),
- array('requirements', array('_method' => 'GET'), 'getRequirements'),
- array('options', array('compiler_class' => 'RouteCompiler'), 'getOptions'),
- array('name', 'blog_index', 'getName'),
- array('defaults', array('_controller' => 'MyBlogBundle:Blog:index'), 'getDefaults'),
- array('schemes', array('https'), 'getSchemes'),
- array('methods', array('GET', 'POST'), 'getMethods'),
- array('host', array('{locale}.example.com'), 'getHost')
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests;
-
-use Symfony\Component\Routing\CompiledRoute;
-
-class CompiledRouteTest extends \PHPUnit_Framework_TestCase
-{
- public function testAccessors()
- {
- $compiled = new CompiledRoute('prefix', 'regex', array('tokens'), array(), array(), array(), array(), array('variables'));
- $this->assertEquals('prefix', $compiled->getStaticPrefix(), '__construct() takes a static prefix as its second argument');
- $this->assertEquals('regex', $compiled->getRegex(), '__construct() takes a regexp as its third argument');
- $this->assertEquals(array('tokens'), $compiled->getTokens(), '__construct() takes an array of tokens as its fourth argument');
- $this->assertEquals(array('variables'), $compiled->getVariables(), '__construct() takes an array of variables as its ninth argument');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
-
-abstract class AbstractClass
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
-
-class BarClass
-{
- public function routeAction($arg1, $arg2 = 'defaultValue2', $arg3 = 'defaultValue3')
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
-
-class FooClass
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Fixtures;
-
-use Symfony\Component\Routing\Loader\XmlFileLoader;
-use Symfony\Component\Config\Util\XmlUtils;
-
-/**
- * XmlFileLoader with schema validation turned off
- */
-class CustomXmlFileLoader extends XmlFileLoader
-{
- protected function loadFile($file)
- {
- return XmlUtils::loadFile($file, function() { return true; });
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Fixtures;
-
-use Symfony\Component\Routing\Matcher\UrlMatcher;
-use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
-
-/**
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
-{
- public function redirect($path, $route, $scheme = null)
- {
- return array(
- '_controller' => 'Some controller reference...',
- 'path' => $path,
- 'scheme' => $scheme,
- );
- }
-}
+++ /dev/null
-# skip "real" requests
-RewriteCond %{REQUEST_FILENAME} -f
-RewriteRule .* - [QSA,L]
-
-# foo
-RewriteCond %{REQUEST_URI} ^/foo/(baz|symfony)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:foo,E=_ROUTING_param_bar:%1,E=_ROUTING_default_def:test]
-
-# foobar
-RewriteCond %{REQUEST_URI} ^/foo(?:/([^/]++))?$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:foobar,E=_ROUTING_param_bar:%1,E=_ROUTING_default_bar:toto]
-
-# bar
-RewriteCond %{REQUEST_URI} ^/bar/([^/]++)$
-RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
-RewriteRule .* - [S=1,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_HEAD:1]
-RewriteCond %{REQUEST_URI} ^/bar/([^/]++)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:bar,E=_ROUTING_param_foo:%1]
-
-# baragain
-RewriteCond %{REQUEST_URI} ^/baragain/([^/]++)$
-RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$ [NC]
-RewriteRule .* - [S=1,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_POST:1,E=_ROUTING_allow_HEAD:1]
-RewriteCond %{REQUEST_URI} ^/baragain/([^/]++)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baragain,E=_ROUTING_param_foo:%1]
-
-# baz
-RewriteCond %{REQUEST_URI} ^/test/baz$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz]
-
-# baz2
-RewriteCond %{REQUEST_URI} ^/test/baz\.html$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz2]
-
-# baz3
-RewriteCond %{REQUEST_URI} ^/test/baz3$
-RewriteRule .* $0/ [QSA,L,R=301]
-RewriteCond %{REQUEST_URI} ^/test/baz3/$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz3]
-
-# baz4
-RewriteCond %{REQUEST_URI} ^/test/([^/]++)$
-RewriteRule .* $0/ [QSA,L,R=301]
-RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz4,E=_ROUTING_param_foo:%1]
-
-# baz5
-RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
-RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
-RewriteRule .* - [S=2,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_HEAD:1]
-RewriteCond %{REQUEST_URI} ^/test/([^/]++)$
-RewriteRule .* $0/ [QSA,L,R=301]
-RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz5,E=_ROUTING_param_foo:%1]
-
-# baz5unsafe
-RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]++)/$
-RewriteCond %{REQUEST_METHOD} !^(POST)$ [NC]
-RewriteRule .* - [S=1,E=_ROUTING_allow_POST:1]
-RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]++)/$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz5unsafe,E=_ROUTING_param_foo:%1]
-
-# baz6
-RewriteCond %{REQUEST_URI} ^/test/baz$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz6,E=_ROUTING_default_foo:bar\ baz]
-
-# baz7
-RewriteCond %{REQUEST_URI} ^/te\ st/baz$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz7]
-
-# baz8
-RewriteCond %{REQUEST_URI} ^/te\\\ st/baz$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz8]
-
-# baz9
-RewriteCond %{REQUEST_URI} ^/test/(te\\\ st)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz9,E=_ROUTING_param_baz:%1]
-
-RewriteCond %{HTTP:Host} ^a\.example\.com$
-RewriteRule .? - [E=__ROUTING_host_1:1]
-
-# route1
-RewriteCond %{ENV:__ROUTING_host_1} =1
-RewriteCond %{REQUEST_URI} ^/route1$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route1]
-
-# route2
-RewriteCond %{ENV:__ROUTING_host_1} =1
-RewriteCond %{REQUEST_URI} ^/c2/route2$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route2]
-
-RewriteCond %{HTTP:Host} ^b\.example\.com$
-RewriteRule .? - [E=__ROUTING_host_2:1]
-
-# route3
-RewriteCond %{ENV:__ROUTING_host_2} =1
-RewriteCond %{REQUEST_URI} ^/c2/route3$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route3]
-
-RewriteCond %{HTTP:Host} ^a\.example\.com$
-RewriteRule .? - [E=__ROUTING_host_3:1]
-
-# route4
-RewriteCond %{ENV:__ROUTING_host_3} =1
-RewriteCond %{REQUEST_URI} ^/route4$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route4]
-
-RewriteCond %{HTTP:Host} ^c\.example\.com$
-RewriteRule .? - [E=__ROUTING_host_4:1]
-
-# route5
-RewriteCond %{ENV:__ROUTING_host_4} =1
-RewriteCond %{REQUEST_URI} ^/route5$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route5]
-
-# route6
-RewriteCond %{REQUEST_URI} ^/route6$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route6]
-
-RewriteCond %{HTTP:Host} ^([^\.]++)\.example\.com$
-RewriteRule .? - [E=__ROUTING_host_5:1,E=__ROUTING_host_5_var1:%1]
-
-# route11
-RewriteCond %{ENV:__ROUTING_host_5} =1
-RewriteCond %{REQUEST_URI} ^/route11$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route11,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1}]
-
-# route12
-RewriteCond %{ENV:__ROUTING_host_5} =1
-RewriteCond %{REQUEST_URI} ^/route12$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route12,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_default_var1:val]
-
-# route13
-RewriteCond %{ENV:__ROUTING_host_5} =1
-RewriteCond %{REQUEST_URI} ^/route13/([^/]++)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route13,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_param_name:%1]
-
-# route14
-RewriteCond %{ENV:__ROUTING_host_5} =1
-RewriteCond %{REQUEST_URI} ^/route14/([^/]++)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route14,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
-
-RewriteCond %{HTTP:Host} ^c\.example\.com$
-RewriteRule .? - [E=__ROUTING_host_6:1]
-
-# route15
-RewriteCond %{ENV:__ROUTING_host_6} =1
-RewriteCond %{REQUEST_URI} ^/route15/([^/]++)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route15,E=_ROUTING_param_name:%1]
-
-# route16
-RewriteCond %{REQUEST_URI} ^/route16/([^/]++)$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route16,E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
-
-# route17
-RewriteCond %{REQUEST_URI} ^/route17$
-RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route17]
-
-# 405 Method Not Allowed
-RewriteCond %{ENV:_ROUTING__allow_GET} =1 [OR]
-RewriteCond %{ENV:_ROUTING__allow_HEAD} =1 [OR]
-RewriteCond %{ENV:_ROUTING__allow_POST} =1
-RewriteRule .* app.php [QSA,L]
+++ /dev/null
-<?php
-
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\RequestContext;
-
-/**
- * ProjectUrlMatcher
- *
- * This class has been auto-generated
- * by the Symfony Routing Component.
- */
-class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
-{
- /**
- * Constructor.
- */
- public function __construct(RequestContext $context)
- {
- $this->context = $context;
- }
-
- public function match($pathinfo)
- {
- $allow = array();
- $pathinfo = rawurldecode($pathinfo);
-
- // foo
- if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo')), array ( 'def' => 'test',));
- }
-
- if (0 === strpos($pathinfo, '/bar')) {
- // bar
- if (preg_match('#^/bar/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
- $allow = array_merge($allow, array('GET', 'HEAD'));
- goto not_bar;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar')), array ());
- }
- not_bar:
-
- // barhead
- if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
- $allow = array_merge($allow, array('GET', 'HEAD'));
- goto not_barhead;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'barhead')), array ());
- }
- not_barhead:
-
- }
-
- if (0 === strpos($pathinfo, '/test')) {
- if (0 === strpos($pathinfo, '/test/baz')) {
- // baz
- if ($pathinfo === '/test/baz') {
- return array('_route' => 'baz');
- }
-
- // baz2
- if ($pathinfo === '/test/baz.html') {
- return array('_route' => 'baz2');
- }
-
- // baz3
- if ($pathinfo === '/test/baz3/') {
- return array('_route' => 'baz3');
- }
-
- }
-
- // baz4
- if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
- }
-
- // baz5
- if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
- if ($this->context->getMethod() != 'POST') {
- $allow[] = 'POST';
- goto not_baz5;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz5')), array ());
- }
- not_baz5:
-
- // baz.baz6
- if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
- if ($this->context->getMethod() != 'PUT') {
- $allow[] = 'PUT';
- goto not_bazbaz6;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz.baz6')), array ());
- }
- not_bazbaz6:
-
- }
-
- // foofoo
- if ($pathinfo === '/foofoo') {
- return array ( 'def' => 'test', '_route' => 'foofoo',);
- }
-
- // quoter
- if (preg_match('#^/(?P<quoter>[\']+)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'quoter')), array ());
- }
-
- // space
- if ($pathinfo === '/spa ce') {
- return array('_route' => 'space');
- }
-
- if (0 === strpos($pathinfo, '/a')) {
- if (0 === strpos($pathinfo, '/a/b\'b')) {
- // foo1
- if (preg_match('#^/a/b\'b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo1')), array ());
- }
-
- // bar1
- if (preg_match('#^/a/b\'b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar1')), array ());
- }
-
- }
-
- // overridden
- if (preg_match('#^/a/(?P<var>.*)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'overridden')), array ());
- }
-
- if (0 === strpos($pathinfo, '/a/b\'b')) {
- // foo2
- if (preg_match('#^/a/b\'b/(?P<foo1>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo2')), array ());
- }
-
- // bar2
- if (preg_match('#^/a/b\'b/(?P<bar1>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar2')), array ());
- }
-
- }
-
- }
-
- if (0 === strpos($pathinfo, '/multi')) {
- // helloWorld
- if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P<who>[^/]++))?$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'helloWorld')), array ( 'who' => 'World!',));
- }
-
- // overridden2
- if ($pathinfo === '/multi/new') {
- return array('_route' => 'overridden2');
- }
-
- // hey
- if ($pathinfo === '/multi/hey/') {
- return array('_route' => 'hey');
- }
-
- }
-
- // foo3
- if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo3')), array ());
- }
-
- // bar3
- if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar3')), array ());
- }
-
- if (0 === strpos($pathinfo, '/aba')) {
- // ababa
- if ($pathinfo === '/ababa') {
- return array('_route' => 'ababa');
- }
-
- // foo4
- if (preg_match('#^/aba/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo4')), array ());
- }
-
- }
-
- $host = $this->context->getHost();
-
- if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
- // route1
- if ($pathinfo === '/route1') {
- return array('_route' => 'route1');
- }
-
- // route2
- if ($pathinfo === '/c2/route2') {
- return array('_route' => 'route2');
- }
-
- }
-
- if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
- // route3
- if ($pathinfo === '/c2/route3') {
- return array('_route' => 'route3');
- }
-
- }
-
- if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
- // route4
- if ($pathinfo === '/route4') {
- return array('_route' => 'route4');
- }
-
- }
-
- if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
- // route5
- if ($pathinfo === '/route5') {
- return array('_route' => 'route5');
- }
-
- }
-
- // route6
- if ($pathinfo === '/route6') {
- return array('_route' => 'route6');
- }
-
- if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
- if (0 === strpos($pathinfo, '/route1')) {
- // route11
- if ($pathinfo === '/route11') {
- return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route11')), array ());
- }
-
- // route12
- if ($pathinfo === '/route12') {
- return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route12')), array ( 'var1' => 'val',));
- }
-
- // route13
- if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route13')), array ());
- }
-
- // route14
- if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route14')), array ( 'var1' => 'val',));
- }
-
- }
-
- }
-
- if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
- // route15
- if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());
- }
-
- }
-
- if (0 === strpos($pathinfo, '/route1')) {
- // route16
- if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'route16')), array ( 'var1' => 'val',));
- }
-
- // route17
- if ($pathinfo === '/route17') {
- return array('_route' => 'route17');
- }
-
- }
-
- if (0 === strpos($pathinfo, '/a')) {
- // a
- if ($pathinfo === '/a/a...') {
- return array('_route' => 'a');
- }
-
- if (0 === strpos($pathinfo, '/a/b')) {
- // b
- if (preg_match('#^/a/b/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'b')), array ());
- }
-
- // c
- if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'c')), array ());
- }
-
- }
-
- }
-
- throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
- }
-}
+++ /dev/null
-# skip "real" requests
-RewriteCond %{REQUEST_FILENAME} -f
-RewriteRule .* - [QSA,L]
-
-# foo
-RewriteCond %{REQUEST_URI} ^/foo$
-RewriteRule .* ap\ p_d\ ev.php [QSA,L,E=_ROUTING_route:foo]
+++ /dev/null
-<?php
-
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\RequestContext;
-
-/**
- * ProjectUrlMatcher
- *
- * This class has been auto-generated
- * by the Symfony Routing Component.
- */
-class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher
-{
- /**
- * Constructor.
- */
- public function __construct(RequestContext $context)
- {
- $this->context = $context;
- }
-
- public function match($pathinfo)
- {
- $allow = array();
- $pathinfo = rawurldecode($pathinfo);
-
- // foo
- if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo')), array ( 'def' => 'test',));
- }
-
- if (0 === strpos($pathinfo, '/bar')) {
- // bar
- if (preg_match('#^/bar/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
- $allow = array_merge($allow, array('GET', 'HEAD'));
- goto not_bar;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar')), array ());
- }
- not_bar:
-
- // barhead
- if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
- $allow = array_merge($allow, array('GET', 'HEAD'));
- goto not_barhead;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'barhead')), array ());
- }
- not_barhead:
-
- }
-
- if (0 === strpos($pathinfo, '/test')) {
- if (0 === strpos($pathinfo, '/test/baz')) {
- // baz
- if ($pathinfo === '/test/baz') {
- return array('_route' => 'baz');
- }
-
- // baz2
- if ($pathinfo === '/test/baz.html') {
- return array('_route' => 'baz2');
- }
-
- // baz3
- if (rtrim($pathinfo, '/') === '/test/baz3') {
- if (substr($pathinfo, -1) !== '/') {
- return $this->redirect($pathinfo.'/', 'baz3');
- }
-
- return array('_route' => 'baz3');
- }
-
- }
-
- // baz4
- if (preg_match('#^/test/(?P<foo>[^/]++)/?$#s', $pathinfo, $matches)) {
- if (substr($pathinfo, -1) !== '/') {
- return $this->redirect($pathinfo.'/', 'baz4');
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
- }
-
- // baz5
- if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
- if ($this->context->getMethod() != 'POST') {
- $allow[] = 'POST';
- goto not_baz5;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz5')), array ());
- }
- not_baz5:
-
- // baz.baz6
- if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
- if ($this->context->getMethod() != 'PUT') {
- $allow[] = 'PUT';
- goto not_bazbaz6;
- }
-
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz.baz6')), array ());
- }
- not_bazbaz6:
-
- }
-
- // foofoo
- if ($pathinfo === '/foofoo') {
- return array ( 'def' => 'test', '_route' => 'foofoo',);
- }
-
- // quoter
- if (preg_match('#^/(?P<quoter>[\']+)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'quoter')), array ());
- }
-
- // space
- if ($pathinfo === '/spa ce') {
- return array('_route' => 'space');
- }
-
- if (0 === strpos($pathinfo, '/a')) {
- if (0 === strpos($pathinfo, '/a/b\'b')) {
- // foo1
- if (preg_match('#^/a/b\'b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo1')), array ());
- }
-
- // bar1
- if (preg_match('#^/a/b\'b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar1')), array ());
- }
-
- }
-
- // overridden
- if (preg_match('#^/a/(?P<var>.*)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'overridden')), array ());
- }
-
- if (0 === strpos($pathinfo, '/a/b\'b')) {
- // foo2
- if (preg_match('#^/a/b\'b/(?P<foo1>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo2')), array ());
- }
-
- // bar2
- if (preg_match('#^/a/b\'b/(?P<bar1>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar2')), array ());
- }
-
- }
-
- }
-
- if (0 === strpos($pathinfo, '/multi')) {
- // helloWorld
- if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P<who>[^/]++))?$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'helloWorld')), array ( 'who' => 'World!',));
- }
-
- // overridden2
- if ($pathinfo === '/multi/new') {
- return array('_route' => 'overridden2');
- }
-
- // hey
- if (rtrim($pathinfo, '/') === '/multi/hey') {
- if (substr($pathinfo, -1) !== '/') {
- return $this->redirect($pathinfo.'/', 'hey');
- }
-
- return array('_route' => 'hey');
- }
-
- }
-
- // foo3
- if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo3')), array ());
- }
-
- // bar3
- if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar3')), array ());
- }
-
- if (0 === strpos($pathinfo, '/aba')) {
- // ababa
- if ($pathinfo === '/ababa') {
- return array('_route' => 'ababa');
- }
-
- // foo4
- if (preg_match('#^/aba/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo4')), array ());
- }
-
- }
-
- $host = $this->context->getHost();
-
- if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
- // route1
- if ($pathinfo === '/route1') {
- return array('_route' => 'route1');
- }
-
- // route2
- if ($pathinfo === '/c2/route2') {
- return array('_route' => 'route2');
- }
-
- }
-
- if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
- // route3
- if ($pathinfo === '/c2/route3') {
- return array('_route' => 'route3');
- }
-
- }
-
- if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
- // route4
- if ($pathinfo === '/route4') {
- return array('_route' => 'route4');
- }
-
- }
-
- if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
- // route5
- if ($pathinfo === '/route5') {
- return array('_route' => 'route5');
- }
-
- }
-
- // route6
- if ($pathinfo === '/route6') {
- return array('_route' => 'route6');
- }
-
- if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
- if (0 === strpos($pathinfo, '/route1')) {
- // route11
- if ($pathinfo === '/route11') {
- return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route11')), array ());
- }
-
- // route12
- if ($pathinfo === '/route12') {
- return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route12')), array ( 'var1' => 'val',));
- }
-
- // route13
- if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route13')), array ());
- }
-
- // route14
- if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route14')), array ( 'var1' => 'val',));
- }
-
- }
-
- }
-
- if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
- // route15
- if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());
- }
-
- }
-
- if (0 === strpos($pathinfo, '/route1')) {
- // route16
- if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'route16')), array ( 'var1' => 'val',));
- }
-
- // route17
- if ($pathinfo === '/route17') {
- return array('_route' => 'route17');
- }
-
- }
-
- if (0 === strpos($pathinfo, '/a')) {
- // a
- if ($pathinfo === '/a/a...') {
- return array('_route' => 'a');
- }
-
- if (0 === strpos($pathinfo, '/a/b')) {
- // b
- if (preg_match('#^/a/b/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'b')), array ());
- }
-
- // c
- if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'c')), array ());
- }
-
- }
-
- }
-
- // secure
- if ($pathinfo === '/secure') {
- if ($this->context->getScheme() !== 'https') {
- return $this->redirect($pathinfo, 'secure', 'https');
- }
-
- return array('_route' => 'secure');
- }
-
- // nonsecure
- if ($pathinfo === '/nonsecure') {
- if ($this->context->getScheme() !== 'http') {
- return $this->redirect($pathinfo, 'nonsecure', 'http');
- }
-
- return array('_route' => 'nonsecure');
- }
-
- throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
- }
-}
+++ /dev/null
-<?php
-
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\RequestContext;
-
-/**
- * ProjectUrlMatcher
- *
- * This class has been auto-generated
- * by the Symfony Routing Component.
- */
-class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
-{
- /**
- * Constructor.
- */
- public function __construct(RequestContext $context)
- {
- $this->context = $context;
- }
-
- public function match($pathinfo)
- {
- $allow = array();
- $pathinfo = rawurldecode($pathinfo);
-
- if (0 === strpos($pathinfo, '/rootprefix')) {
- // static
- if ($pathinfo === '/rootprefix/test') {
- return array('_route' => 'static');
- }
-
- // dynamic
- if (preg_match('#^/rootprefix/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
- return $this->mergeDefaults(array_replace($matches, array('_route' => 'dynamic')), array ());
- }
-
- }
-
- throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
- }
-}
+++ /dev/null
-blog_show:
- defaults: { _controller: MyBlogBundle:Blog:show }
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<routes xmlns="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <route path="/test"></route>
-</routes>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<routes xmlns="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <route id="myroute"></route>
-</routes>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<r:routes xmlns:r="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <r:route id="blog_show" path="/blog/{slug}" host="{_locale}.example.com">
- <r:default key="_controller">MyBundle:Blog:show</r:default>
- <requirement xmlns="http://symfony.com/schema/routing" key="slug">\w+</requirement>
- <r2:requirement xmlns:r2="http://symfony.com/schema/routing" key="_locale">en|fr|de</r2:requirement>
- <r:option key="compiler_class">RouteCompiler</r:option>
- </r:route>
-</r:routes>
+++ /dev/null
-blog_show:
- resource: validpattern.yml
- path: /test
+++ /dev/null
-blog_show:
- path: /blog/{slug}
- type: custom
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<routes xmlns="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <route id="blog_show" path="/blog/{slug}">
- <default key="_controller">MyBundle:Blog:show</default>
- <requirement key="_method">GET</requirement>
- <!-- </route> -->
-</routes>
+++ /dev/null
-route: string
+++ /dev/null
-someroute:
- resource: path/to/some.yml
- name_prefix: test_
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<routes xmlns="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <foo>bar</foo>
-</routes>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<routes xmlns="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <route id="blog_show" path="/blog/{slug}">
- <default key="_controller">MyBundle:Blog:show</default>
- <requirement key="_method">GET</requirement>
- <option key="compiler_class">RouteCompiler</option>
- <foo key="bar">baz</foo>
- </route>
-</routes>
+++ /dev/null
-"#$péß^a|":
- path: "true"
+++ /dev/null
-<?php
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Route;
-
-$collection = new RouteCollection();
-$collection->add('blog_show', new Route(
- '/blog/{slug}',
- array('_controller' => 'MyBlogBundle:Blog:show'),
- array('locale' => '\w+'),
- array('compiler_class' => 'RouteCompiler'),
- '{locale}.example.com',
- array('https'),
- array('GET','POST','put','OpTiOnS')
-));
-$collection->add('blog_show_legacy', new Route(
- '/blog/{slug}',
- array('_controller' => 'MyBlogBundle:Blog:show'),
- array('_method' => 'GET|POST|put|OpTiOnS', '_scheme' => 'https', 'locale' => '\w+',),
- array('compiler_class' => 'RouteCompiler'),
- '{locale}.example.com'
-));
-
-return $collection;
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<routes xmlns="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <route id="blog_show" path="/blog/{slug}" host="{locale}.example.com" methods="GET|POST put,OpTiOnS" schemes="hTTps">
- <default key="_controller">MyBundle:Blog:show</default>
- <requirement key="locale">\w+</requirement>
- <option key="compiler_class">RouteCompiler</option>
- </route>
-
- <route id="blog_show_legacy" pattern="/blog/{slug}" host="{locale}.example.com">
- <default key="_controller">MyBundle:Blog:show</default>
- <default key="slug" xsi:nil="true" />
- <requirement key="_method">GET|POST|put|OpTiOnS</requirement>
- <requirement key="_scheme">hTTps</requirement>
- <requirement key="locale">\w+</requirement>
- <option key="compiler_class">RouteCompiler</option>
- </route>
-</routes>
+++ /dev/null
-blog_show:
- path: /blog/{slug}
- defaults: { _controller: "MyBundle:Blog:show" }
- host: "{locale}.example.com"
- requirements: { 'locale': '\w+' }
- methods: ['GET','POST','put','OpTiOnS']
- schemes: ['https']
- options:
- compiler_class: RouteCompiler
-
-blog_show_legacy:
- pattern: /blog/{slug}
- defaults: { _controller: "MyBundle:Blog:show" }
- host: "{locale}.example.com"
- requirements: { '_method': 'GET|POST|put|OpTiOnS', _scheme: https, 'locale': '\w+' }
- options:
- compiler_class: RouteCompiler
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<routes xmlns="http://symfony.com/schema/routing"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
-
- <import resource="validpattern.xml" prefix="/{foo}" host="">
- <default key="foo">123</default>
- <requirement key="foo">\d+</requirement>
- <option key="foo">bar</option>
- </import>
-</routes>
+++ /dev/null
-_blog:
- resource: validpattern.yml
- prefix: /{foo}
- defaults: { 'foo': '123' }
- requirements: { 'foo': '\d+' }
- options: { 'foo': 'bar' }
- host: ""
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE foo>
-<foo></foo>
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Generator\Dumper;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper;
-use Symfony\Component\Routing\RequestContext;
-
-class PhpGeneratorDumperTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var RouteCollection
- */
- private $routeCollection;
-
- /**
- * @var PhpGeneratorDumper
- */
- private $generatorDumper;
-
- /**
- * @var string
- */
- private $testTmpFilepath;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->routeCollection = new RouteCollection();
- $this->generatorDumper = new PhpGeneratorDumper($this->routeCollection);
- $this->testTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.php';
- @unlink($this->testTmpFilepath);
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- @unlink($this->testTmpFilepath);
-
- $this->routeCollection = null;
- $this->generatorDumper = null;
- $this->testTmpFilepath = null;
- }
-
- public function testDumpWithRoutes()
- {
- $this->routeCollection->add('Test', new Route('/testing/{foo}'));
- $this->routeCollection->add('Test2', new Route('/testing2'));
-
- file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump());
- include ($this->testTmpFilepath);
-
- $projectUrlGenerator = new \ProjectUrlGenerator(new RequestContext('/app.php'));
-
- $absoluteUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), true);
- $absoluteUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), true);
- $relativeUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), false);
- $relativeUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), false);
-
- $this->assertEquals($absoluteUrlWithParameter, 'http://localhost/app.php/testing/bar');
- $this->assertEquals($absoluteUrlWithoutParameter, 'http://localhost/app.php/testing2');
- $this->assertEquals($relativeUrlWithParameter, '/app.php/testing/bar');
- $this->assertEquals($relativeUrlWithoutParameter, '/app.php/testing2');
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testDumpWithoutRoutes()
- {
- file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'WithoutRoutesUrlGenerator')));
- include ($this->testTmpFilepath);
-
- $projectUrlGenerator = new \WithoutRoutesUrlGenerator(new RequestContext('/app.php'));
-
- $projectUrlGenerator->generate('Test', array());
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
- */
- public function testGenerateNonExistingRoute()
- {
- $this->routeCollection->add('Test', new Route('/test'));
-
- file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'NonExistingRoutesUrlGenerator')));
- include ($this->testTmpFilepath);
-
- $projectUrlGenerator = new \NonExistingRoutesUrlGenerator(new RequestContext());
- $url = $projectUrlGenerator->generate('NonExisting', array());
- }
-
- public function testDumpForRouteWithDefaults()
- {
- $this->routeCollection->add('Test', new Route('/testing/{foo}', array('foo' => 'bar')));
-
- file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'DefaultRoutesUrlGenerator')));
- include ($this->testTmpFilepath);
-
- $projectUrlGenerator = new \DefaultRoutesUrlGenerator(new RequestContext());
- $url = $projectUrlGenerator->generate('Test', array());
-
- $this->assertEquals($url, '/testing');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Generator;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\Generator\UrlGenerator;
-use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
-use Symfony\Component\Routing\RequestContext;
-
-class UrlGeneratorTest extends \PHPUnit_Framework_TestCase
-{
- public function testAbsoluteUrlWithPort80()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes)->generate('test', array(), true);
-
- $this->assertEquals('http://localhost/app.php/testing', $url);
- }
-
- public function testAbsoluteSecureUrlWithPort443()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', array(), true);
-
- $this->assertEquals('https://localhost/app.php/testing', $url);
- }
-
- public function testAbsoluteUrlWithNonStandardPort()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes, array('httpPort' => 8080))->generate('test', array(), true);
-
- $this->assertEquals('http://localhost:8080/app.php/testing', $url);
- }
-
- public function testAbsoluteSecureUrlWithNonStandardPort()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes, array('httpsPort' => 8080, 'scheme' => 'https'))->generate('test', array(), true);
-
- $this->assertEquals('https://localhost:8080/app.php/testing', $url);
- }
-
- public function testRelativeUrlWithoutParameters()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes)->generate('test', array(), false);
-
- $this->assertEquals('/app.php/testing', $url);
- }
-
- public function testRelativeUrlWithParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
- $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), false);
-
- $this->assertEquals('/app.php/testing/bar', $url);
- }
-
- public function testRelativeUrlWithNullParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing.{format}', array('format' => null)));
- $url = $this->getGenerator($routes)->generate('test', array(), false);
-
- $this->assertEquals('/app.php/testing', $url);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testRelativeUrlWithNullParameterButNotOptional()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', array('foo' => null)));
- // This must raise an exception because the default requirement for "foo" is "[^/]+" which is not met with these params.
- // Generating path "/testing//bar" would be wrong as matching this route would fail.
- $this->getGenerator($routes)->generate('test', array(), false);
- }
-
- public function testRelativeUrlWithOptionalZeroParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{page}'));
- $url = $this->getGenerator($routes)->generate('test', array('page' => 0), false);
-
- $this->assertEquals('/app.php/testing/0', $url);
- }
-
- public function testNotPassedOptionalParameterInBetween()
- {
- $routes = $this->getRoutes('test', new Route('/{slug}/{page}', array('slug' => 'index', 'page' => 0)));
- $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', array('page' => 1)));
- $this->assertSame('/app.php/', $this->getGenerator($routes)->generate('test'));
- }
-
- public function testRelativeUrlWithExtraParameters()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), false);
-
- $this->assertEquals('/app.php/testing?foo=bar', $url);
- }
-
- public function testAbsoluteUrlWithExtraParameters()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
-
- $this->assertEquals('http://localhost/app.php/testing?foo=bar', $url);
- }
-
- public function testUrlWithNullExtraParameters()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $url = $this->getGenerator($routes)->generate('test', array('foo' => null), true);
-
- $this->assertEquals('http://localhost/app.php/testing', $url);
- }
-
- public function testUrlWithExtraParametersFromGlobals()
- {
- $routes = $this->getRoutes('test', new Route('/testing'));
- $generator = $this->getGenerator($routes);
- $context = new RequestContext('/app.php');
- $context->setParameter('bar', 'bar');
- $generator->setContext($context);
- $url = $generator->generate('test', array('foo' => 'bar'));
-
- $this->assertEquals('/app.php/testing?foo=bar', $url);
- }
-
- public function testUrlWithGlobalParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
- $generator = $this->getGenerator($routes);
- $context = new RequestContext('/app.php');
- $context->setParameter('foo', 'bar');
- $generator->setContext($context);
- $url = $generator->generate('test', array());
-
- $this->assertEquals('/app.php/testing/bar', $url);
- }
-
- public function testGlobalParameterHasHigherPriorityThanDefault()
- {
- $routes = $this->getRoutes('test', new Route('/{_locale}', array('_locale' => 'en')));
- $generator = $this->getGenerator($routes);
- $context = new RequestContext('/app.php');
- $context->setParameter('_locale', 'de');
- $generator->setContext($context);
- $url = $generator->generate('test', array());
-
- $this->assertSame('/app.php/de', $url);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
- */
- public function testGenerateWithoutRoutes()
- {
- $routes = $this->getRoutes('foo', new Route('/testing/{foo}'));
- $this->getGenerator($routes)->generate('test', array(), true);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
- */
- public function testGenerateForRouteWithoutMandatoryParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
- $this->getGenerator($routes)->generate('test', array(), true);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testGenerateForRouteWithInvalidOptionalParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
- $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testGenerateForRouteWithInvalidParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '1|2')));
- $this->getGenerator($routes)->generate('test', array('foo' => '0'), true);
- }
-
- public function testGenerateForRouteWithInvalidOptionalParameterNonStrict()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
- $generator = $this->getGenerator($routes);
- $generator->setStrictRequirements(false);
- $this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
- }
-
- public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger()
- {
- if (!interface_exists('Psr\Log\LoggerInterface')) {
- $this->markTestSkipped('The "psr/log" package is not available');
- }
-
- $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
- $logger = $this->getMock('Psr\Log\LoggerInterface');
- $logger->expects($this->once())
- ->method('error');
- $generator = $this->getGenerator($routes, array(), $logger);
- $generator->setStrictRequirements(false);
- $this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
- }
-
- public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
- $generator = $this->getGenerator($routes);
- $generator->setStrictRequirements(null);
- $this->assertSame('/app.php/testing/bar', $generator->generate('test', array('foo' => 'bar')));
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testGenerateForRouteWithInvalidMandatoryParameter()
- {
- $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => 'd+')));
- $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testRequiredParamAndEmptyPassed()
- {
- $routes = $this->getRoutes('test', new Route('/{slug}', array(), array('slug' => '.+')));
- $this->getGenerator($routes)->generate('test', array('slug' => ''));
- }
-
- public function testSchemeRequirementDoesNothingIfSameCurrentScheme()
- {
- $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'http')));
- $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test'));
-
- $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'https')));
- $this->assertEquals('/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
- }
-
- public function testSchemeRequirementForcesAbsoluteUrl()
- {
- $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'https')));
- $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
-
- $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'http')));
- $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
- }
-
- public function testPathWithTwoStartingSlashes()
- {
- $routes = $this->getRoutes('test', new Route('//path-and-not-domain'));
-
- // this must not generate '//path-and-not-domain' because that would be a network path
- $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, array('BaseUrl' => ''))->generate('test'));
- }
-
- public function testNoTrailingSlashForMultipleOptionalParameters()
- {
- $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', array('slug2' => null, 'slug3' => null)));
-
- $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', array('slug1' => 'foo')));
- }
-
- public function testWithAnIntegerAsADefaultValue()
- {
- $routes = $this->getRoutes('test', new Route('/{default}', array('default' => 0)));
-
- $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
- }
-
- public function testNullForOptionalParameterIsIgnored()
- {
- $routes = $this->getRoutes('test', new Route('/test/{default}', array('default' => 0)));
-
- $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => null)));
- }
-
- public function testQueryParamSameAsDefault()
- {
- $routes = $this->getRoutes('test', new Route('/test', array('default' => 'value')));
-
- $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
- $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'value')));
- $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
- }
-
- public function testGenerateWithSpecialRouteName()
- {
- $routes = $this->getRoutes('$péß^a|', new Route('/bar'));
-
- $this->assertSame('/app.php/bar', $this->getGenerator($routes)->generate('$péß^a|'));
- }
-
- public function testUrlEncoding()
- {
- // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986)
- // and other special ASCII chars. These chars are tested as static text path, variable path and query param.
- $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id';
- $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", array(), array('varpath' => '.+')));
- $this->assertSame('/app.php/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
- .'/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
- .'?query=%40%3A%5B%5D%2F%28%29%2A%27%22+%2B%2C%3B-._%7E%26%24%3C%3E%7C%7B%7D%25%5C%5E%60%21%3Ffoo%3Dbar%23id',
- $this->getGenerator($routes)->generate('test', array(
- 'varpath' => $chars,
- 'query' => $chars
- ))
- );
- }
-
- public function testEncodingOfRelativePathSegments()
- {
- $routes = $this->getRoutes('test', new Route('/dir/../dir/..'));
- $this->assertSame('/app.php/dir/%2E%2E/dir/%2E%2E', $this->getGenerator($routes)->generate('test'));
- $routes = $this->getRoutes('test', new Route('/dir/./dir/.'));
- $this->assertSame('/app.php/dir/%2E/dir/%2E', $this->getGenerator($routes)->generate('test'));
- $routes = $this->getRoutes('test', new Route('/a./.a/a../..a/...'));
- $this->assertSame('/app.php/a./.a/a../..a/...', $this->getGenerator($routes)->generate('test'));
- }
-
- public function testAdjacentVariables()
- {
- $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '\d+')));
- $generator = $this->getGenerator($routes);
- $this->assertSame('/app.php/foo123', $generator->generate('test', array('x' => 'foo', 'y' => '123')));
- $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', array('x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml')));
-
- // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything
- // and following optional variables like _format could never match.
- $this->setExpectedException('Symfony\Component\Routing\Exception\InvalidParameterException');
- $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml'));
- }
-
- public function testOptionalVariableWithNoRealSeparator()
- {
- $routes = $this->getRoutes('test', new Route('/get{what}', array('what' => 'All')));
- $generator = $this->getGenerator($routes);
-
- $this->assertSame('/app.php/get', $generator->generate('test'));
- $this->assertSame('/app.php/getSites', $generator->generate('test', array('what' => 'Sites')));
- }
-
- public function testRequiredVariableWithNoRealSeparator()
- {
- $routes = $this->getRoutes('test', new Route('/get{what}Suffix'));
- $generator = $this->getGenerator($routes);
-
- $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', array('what' => 'Sites')));
- }
-
- public function testDefaultRequirementOfVariable()
- {
- $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
- $generator = $this->getGenerator($routes);
-
- $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testDefaultRequirementOfVariableDisallowsSlash()
- {
- $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
- $this->getGenerator($routes)->generate('test', array('page' => 'index', '_format' => 'sl/ash'));
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testDefaultRequirementOfVariableDisallowsNextSeparator()
- {
- $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
- $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
- }
-
- public function testWithHostDifferentFromContext()
- {
- $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
-
- $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
- }
-
- public function testWithHostSameAsContext()
- {
- $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
-
- $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
- }
-
- public function testWithHostSameAsContextAndAbsolute()
- {
- $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
-
- $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' =>'Fabien', 'locale' => 'fr'), true));
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testUrlWithInvalidParameterInHost()
- {
- $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
- $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue()
- {
- $routes = $this->getRoutes('test', new Route('/', array('foo' => 'bar'), array('foo' => 'bar'), array(), '{foo}.example.com'));
- $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
- */
- public function testUrlWithInvalidParameterEqualsDefaultValueInHost()
- {
- $routes = $this->getRoutes('test', new Route('/', array('foo' => 'baz'), array('foo' => 'bar'), array(), '{foo}.example.com'));
- $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
- }
-
- public function testUrlWithInvalidParameterInHostInNonStrictMode()
- {
- $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
- $generator = $this->getGenerator($routes);
- $generator->setStrictRequirements(false);
- $this->assertNull($generator->generate('test', array('foo' => 'baz'), false));
- }
-
- public function testGenerateNetworkPath()
- {
- $routes = $this->getRoutes('test', new Route('/{name}', array(), array('_scheme' => 'http'), array(), '{locale}.example.com'));
-
- $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
- array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host'
- );
- $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test',
- array('name' =>'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context'
- );
- $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test',
- array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context'
- );
- $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
- array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested'
- );
- }
-
- public function testGenerateRelativePath()
- {
- $routes = new RouteCollection();
- $routes->add('article', new Route('/{author}/{article}/'));
- $routes->add('comments', new Route('/{author}/{article}/comments'));
- $routes->add('host', new Route('/{article}', array(), array(), array(), '{author}.example.com'));
- $routes->add('scheme', new Route('/{author}', array(), array('_scheme' => 'https')));
- $routes->add('unrelated', new Route('/about'));
-
- $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/'));
-
- $this->assertSame('comments', $generator->generate('comments',
- array('author' =>'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
- );
- $this->assertSame('comments?page=2', $generator->generate('comments',
- array('author' =>'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH)
- );
- $this->assertSame('../twig-is-great/', $generator->generate('article',
- array('author' =>'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
- );
- $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article',
- array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
- );
- $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host',
- array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
- );
- $this->assertSame('https://example.com/app.php/bernhard', $generator->generate('scheme',
- array('author' =>'bernhard'), UrlGeneratorInterface::RELATIVE_PATH)
- );
- $this->assertSame('../../about', $generator->generate('unrelated',
- array(), UrlGeneratorInterface::RELATIVE_PATH)
- );
- }
-
- /**
- * @dataProvider provideRelativePaths
- */
- public function testGetRelativePath($sourcePath, $targetPath, $expectedPath)
- {
- $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath));
- }
-
- public function provideRelativePaths()
- {
- return array(
- array(
- '/same/dir/',
- '/same/dir/',
- ''
- ),
- array(
- '/same/file',
- '/same/file',
- ''
- ),
- array(
- '/',
- '/file',
- 'file'
- ),
- array(
- '/',
- '/dir/file',
- 'dir/file'
- ),
- array(
- '/dir/file.html',
- '/dir/different-file.html',
- 'different-file.html'
- ),
- array(
- '/same/dir/extra-file',
- '/same/dir/',
- './'
- ),
- array(
- '/parent/dir/',
- '/parent/',
- '../'
- ),
- array(
- '/parent/dir/extra-file',
- '/parent/',
- '../'
- ),
- array(
- '/a/b/',
- '/x/y/z/',
- '../../x/y/z/'
- ),
- array(
- '/a/b/c/d/e',
- '/a/c/d',
- '../../../c/d'
- ),
- array(
- '/a/b/c//',
- '/a/b/c/',
- '../'
- ),
- array(
- '/a/b/c/',
- '/a/b/c//',
- './/'
- ),
- array(
- '/root/a/b/c/',
- '/root/x/b/c/',
- '../../../x/b/c/'
- ),
- array(
- '/a/b/c/d/',
- '/a',
- '../../../../a'
- ),
- array(
- '/special-chars/sp%20ce/1€/mäh/e=mc²',
- '/special-chars/sp%20ce/1€/<µ>/e=mc²',
- '../<µ>/e=mc²'
- ),
- array(
- 'not-rooted',
- 'dir/file',
- 'dir/file'
- ),
- array(
- '//dir/',
- '',
- '../../'
- ),
- array(
- '/dir/',
- '/dir/file:with-colon',
- './file:with-colon'
- ),
- array(
- '/dir/',
- '/dir/subdir/file:with-colon',
- 'subdir/file:with-colon'
- ),
- array(
- '/dir/',
- '/dir/:subdir/',
- './:subdir/'
- ),
- );
- }
-
- protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
- {
- $context = new RequestContext('/app.php');
- foreach ($parameters as $key => $value) {
- $method = 'set'.$key;
- $context->$method($value);
- }
- $generator = new UrlGenerator($routes, $context, $logger);
-
- return $generator;
- }
-
- protected function getRoutes($name, Route $route)
- {
- $routes = new RouteCollection();
- $routes->add($name, $route);
-
- return $routes;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-abstract class AbstractAnnotationLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Doctrine\\Common\\Version')) {
- $this->markTestSkipped('Doctrine is not available.');
- }
- }
-
- public function getReader()
- {
- return $this->getMockBuilder('Doctrine\Common\Annotations\Reader')
- ->disableOriginalConstructor()
- ->getMock()
- ;
- }
-
- public function getClassLoader($reader)
- {
- return $this->getMockBuilder('Symfony\Component\Routing\Loader\AnnotationClassLoader')
- ->setConstructorArgs(array($reader))
- ->getMockForAbstractClass()
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
-{
- protected $loader;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->reader = $this->getReader();
- $this->loader = $this->getClassLoader($this->reader);
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testLoadMissingClass()
- {
- $this->loader->load('MissingClass');
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testLoadAbstractClass()
- {
- $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\AbstractClass');
- }
-
- /**
- * @dataProvider provideTestSupportsChecksResource
- */
- public function testSupportsChecksResource($resource, $expectedSupports)
- {
- $this->assertSame($expectedSupports, $this->loader->supports($resource), '->supports() returns true if the resource is loadable');
- }
-
- public function provideTestSupportsChecksResource()
- {
- return array(
- array('class', true),
- array('\fully\qualified\class\name', true),
- array('namespaced\class\without\leading\slash', true),
- array('ÿClassWithLegalSpecialCharacters', true),
- array('5', false),
- array('foo.foo', false),
- array(null, false),
- );
- }
-
- public function testSupportsChecksTypeIfSpecified()
- {
- $this->assertTrue($this->loader->supports('class', 'annotation'), '->supports() checks the resource type if specified');
- $this->assertFalse($this->loader->supports('class', 'foo'), '->supports() checks the resource type if specified');
- }
-
- public function getLoadTests()
- {
- return array(
- array(
- 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
- array('name'=>'route1'),
- array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
- ),
- array(
- 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
- array('name'=>'route1', 'defaults' => array('arg2' => 'foo')),
- array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
- ),
- );
- }
-
- /**
- * @dataProvider getLoadTests
- */
- public function testLoad($className, $routeDatas = array(), $methodArgs = array())
- {
- $routeDatas = array_replace(array(
- 'name' => 'route',
- 'path' => '/',
- 'requirements' => array(),
- 'options' => array(),
- 'defaults' => array(),
- 'schemes' => array(),
- 'methods' => array(),
- ), $routeDatas);
-
- $this->reader
- ->expects($this->once())
- ->method('getMethodAnnotations')
- ->will($this->returnValue(array($this->getAnnotatedRoute($routeDatas))))
- ;
- $routeCollection = $this->loader->load($className);
- $route = $routeCollection->get($routeDatas['name']);
-
- $this->assertSame($routeDatas['path'], $route->getPath(), '->load preserves path annotation');
- $this->assertSame($routeDatas['requirements'],$route->getRequirements(), '->load preserves requirements annotation');
- $this->assertCount(0, array_intersect($route->getOptions(), $routeDatas['options']), '->load preserves options annotation');
- $this->assertSame(array_replace($routeDatas['defaults'], $methodArgs), $route->getDefaults(), '->load preserves defaults annotation');
- }
-
- private function getAnnotatedRoute($datas)
- {
- return new \Symfony\Component\Routing\Annotation\Route($datas);
- }
-
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
-use Symfony\Component\Config\FileLocator;
-
-class AnnotationDirectoryLoaderTest extends AbstractAnnotationLoaderTest
-{
- protected $loader;
- protected $reader;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->reader = $this->getReader();
- $this->loader = new AnnotationDirectoryLoader(new FileLocator(), $this->getClassLoader($this->reader));
- }
-
- public function testLoad()
- {
- $this->reader->expects($this->exactly(2))->method('getClassAnnotation');
-
- $this->reader
- ->expects($this->any())
- ->method('getMethodAnnotations')
- ->will($this->returnValue(array()))
- ;
-
- $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses');
- }
-
- public function testSupports()
- {
- $fixturesDir = __DIR__.'/../Fixtures';
-
- $this->assertTrue($this->loader->supports($fixturesDir), '->supports() returns true if the resource is loadable');
- $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
-
- $this->assertTrue($this->loader->supports($fixturesDir, 'annotation'), '->supports() checks the resource type if specified');
- $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports() checks the resource type if specified');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-use Symfony\Component\Routing\Loader\AnnotationFileLoader;
-use Symfony\Component\Config\FileLocator;
-
-class AnnotationFileLoaderTest extends AbstractAnnotationLoaderTest
-{
- protected $loader;
- protected $reader;
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->reader = $this->getReader();
- $this->loader = new AnnotationFileLoader(new FileLocator(), $this->getClassLoader($this->reader));
- }
-
- public function testLoad()
- {
- $this->reader->expects($this->once())->method('getClassAnnotation');
-
- $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php');
- }
-
- public function testSupports()
- {
- $fixture = __DIR__.'/../Fixtures/annotated.php';
-
- $this->assertTrue($this->loader->supports($fixture), '->supports() returns true if the resource is loadable');
- $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
-
- $this->assertTrue($this->loader->supports($fixture, 'annotation'), '->supports() checks the resource type if specified');
- $this->assertFalse($this->loader->supports($fixture, 'foo'), '->supports() checks the resource type if specified');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-use Symfony\Component\Routing\Loader\ClosureLoader;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-
-class ClosureLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\FileLocator')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testSupports()
- {
- $loader = new ClosureLoader();
-
- $closure = function () {};
-
- $this->assertTrue($loader->supports($closure), '->supports() returns true if the resource is loadable');
- $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
-
- $this->assertTrue($loader->supports($closure, 'closure'), '->supports() checks the resource type if specified');
- $this->assertFalse($loader->supports($closure, 'foo'), '->supports() checks the resource type if specified');
- }
-
- public function testLoad()
- {
- $loader = new ClosureLoader();
-
- $route = new Route('/');
- $routes = $loader->load(function () use ($route) {
- $routes = new RouteCollection();
-
- $routes->add('foo', $route);
-
- return $routes;
- });
-
- $this->assertEquals($route, $routes->get('foo'), '->load() loads a \Closure resource');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-use Symfony\Component\Config\FileLocator;
-use Symfony\Component\Routing\Loader\PhpFileLoader;
-
-class PhpFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\FileLocator')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testSupports()
- {
- $loader = new PhpFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
-
- $this->assertTrue($loader->supports('foo.php'), '->supports() returns true if the resource is loadable');
- $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
-
- $this->assertTrue($loader->supports('foo.php', 'php'), '->supports() checks the resource type if specified');
- $this->assertFalse($loader->supports('foo.php', 'foo'), '->supports() checks the resource type if specified');
- }
-
- public function testLoadWithRoute()
- {
- $loader = new PhpFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $routeCollection = $loader->load('validpattern.php');
- $routes = $routeCollection->all();
-
- $this->assertCount(2, $routes, 'Two routes are loaded');
- $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
-
- foreach ($routes as $route) {
- $this->assertSame('/blog/{slug}', $route->getPath());
- $this->assertSame('MyBlogBundle:Blog:show', $route->getDefault('_controller'));
- $this->assertSame('{locale}.example.com', $route->getHost());
- $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
- $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
- $this->assertEquals(array('https'), $route->getSchemes());
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-use Symfony\Component\Config\FileLocator;
-use Symfony\Component\Routing\Loader\XmlFileLoader;
-use Symfony\Component\Routing\Tests\Fixtures\CustomXmlFileLoader;
-
-class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\FileLocator')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testSupports()
- {
- $loader = new XmlFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
-
- $this->assertTrue($loader->supports('foo.xml'), '->supports() returns true if the resource is loadable');
- $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
-
- $this->assertTrue($loader->supports('foo.xml', 'xml'), '->supports() checks the resource type if specified');
- $this->assertFalse($loader->supports('foo.xml', 'foo'), '->supports() checks the resource type if specified');
- }
-
- public function testLoadWithRoute()
- {
- $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $routeCollection = $loader->load('validpattern.xml');
- $routes = $routeCollection->all();
-
- $this->assertCount(2, $routes, 'Two routes are loaded');
- $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
-
- foreach ($routes as $route) {
- $this->assertSame('/blog/{slug}', $route->getPath());
- $this->assertSame('{locale}.example.com', $route->getHost());
- $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
- $this->assertSame('\w+', $route->getRequirement('locale'));
- $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
- $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
- $this->assertEquals(array('https'), $route->getSchemes());
- }
- }
-
- public function testLoadWithNamespacePrefix()
- {
- $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $routeCollection = $loader->load('namespaceprefix.xml');
-
- $this->assertCount(1, $routeCollection->all(), 'One route is loaded');
-
- $route = $routeCollection->get('blog_show');
- $this->assertSame('/blog/{slug}', $route->getPath());
- $this->assertSame('{_locale}.example.com', $route->getHost());
- $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
- $this->assertSame('\w+', $route->getRequirement('slug'));
- $this->assertSame('en|fr|de', $route->getRequirement('_locale'));
- $this->assertSame(null, $route->getDefault('slug'));
- $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
- }
-
- public function testLoadWithImport()
- {
- $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $routeCollection = $loader->load('validresource.xml');
- $routes = $routeCollection->all();
-
- $this->assertCount(2, $routes, 'Two routes are loaded');
- $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
-
- foreach ($routes as $route) {
- $this->assertSame('/{foo}/blog/{slug}', $route->getPath());
- $this->assertSame('123', $route->getDefault('foo'));
- $this->assertSame('\d+', $route->getRequirement('foo'));
- $this->assertSame('bar', $route->getOption('foo'));
- $this->assertSame('', $route->getHost());
- }
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @dataProvider getPathsToInvalidFiles
- */
- public function testLoadThrowsExceptionWithInvalidFile($filePath)
- {
- $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $loader->load($filePath);
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @dataProvider getPathsToInvalidFiles
- */
- public function testLoadThrowsExceptionWithInvalidFileEvenWithoutSchemaValidation($filePath)
- {
- $loader = new CustomXmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $loader->load($filePath);
- }
-
- public function getPathsToInvalidFiles()
- {
- return array(array('nonvalidnode.xml'), array('nonvalidroute.xml'), array('nonvalid.xml'), array('missing_id.xml'), array('missing_path.xml'));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage Document types are not allowed.
- */
- public function testDocTypeIsNotAllowed()
- {
- $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $loader->load('withdoctype.xml');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Loader;
-
-use Symfony\Component\Config\FileLocator;
-use Symfony\Component\Routing\Loader\YamlFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\FileLocator')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- if (!class_exists('Symfony\Component\Yaml\Yaml')) {
- $this->markTestSkipped('The "Yaml" component is not available');
- }
- }
-
- public function testSupports()
- {
- $loader = new YamlFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
-
- $this->assertTrue($loader->supports('foo.yml'), '->supports() returns true if the resource is loadable');
- $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
-
- $this->assertTrue($loader->supports('foo.yml', 'yaml'), '->supports() checks the resource type if specified');
- $this->assertFalse($loader->supports('foo.yml', 'foo'), '->supports() checks the resource type if specified');
- }
-
- public function testLoadDoesNothingIfEmpty()
- {
- $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $collection = $loader->load('empty.yml');
-
- $this->assertEquals(array(), $collection->all());
- $this->assertEquals(array(new FileResource(realpath(__DIR__.'/../Fixtures/empty.yml'))), $collection->getResources());
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @dataProvider getPathsToInvalidFiles
- */
- public function testLoadThrowsExceptionWithInvalidFile($filePath)
- {
- $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $loader->load($filePath);
- }
-
- public function getPathsToInvalidFiles()
- {
- return array(array('nonvalid.yml'), array('nonvalid2.yml'), array('incomplete.yml'), array('nonvalidkeys.yml'), array('nonesense_resource_plus_path.yml'), array('nonesense_type_without_resource.yml'));
- }
-
- public function testLoadSpecialRouteName()
- {
- $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $routeCollection = $loader->load('special_route_name.yml');
- $route = $routeCollection->get('#$péß^a|');
-
- $this->assertInstanceOf('Symfony\Component\Routing\Route', $route);
- $this->assertSame('/true', $route->getPath());
- }
-
- public function testLoadWithRoute()
- {
- $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $routeCollection = $loader->load('validpattern.yml');
- $routes = $routeCollection->all();
-
- $this->assertCount(2, $routes, 'Two routes are loaded');
- $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
-
- foreach ($routes as $route) {
- $this->assertSame('/blog/{slug}', $route->getPath());
- $this->assertSame('{locale}.example.com', $route->getHost());
- $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
- $this->assertSame('\w+', $route->getRequirement('locale'));
- $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
- $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
- $this->assertEquals(array('https'), $route->getSchemes());
- }
- }
-
- public function testLoadWithResource()
- {
- $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
- $routeCollection = $loader->load('validresource.yml');
- $routes = $routeCollection->all();
-
- $this->assertCount(2, $routes, 'Two routes are loaded');
- $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
-
- foreach ($routes as $route) {
- $this->assertSame('/{foo}/blog/{slug}', $route->getPath());
- $this->assertSame('123', $route->getDefault('foo'));
- $this->assertSame('\d+', $route->getRequirement('foo'));
- $this->assertSame('bar', $route->getOption('foo'));
- $this->assertSame('', $route->getHost());
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Matcher;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\RequestContext;
-use Symfony\Component\Routing\Matcher\ApacheUrlMatcher;
-
-class ApacheUrlMatcherTest extends \PHPUnit_Framework_TestCase
-{
- protected $server;
-
- protected function setUp()
- {
- $this->server = $_SERVER;
- }
-
- protected function tearDown()
- {
- $_SERVER = $this->server;
- }
-
- /**
- * @dataProvider getMatchData
- */
- public function testMatch($name, $pathinfo, $server, $expect)
- {
- $collection = new RouteCollection();
- $context = new RequestContext();
- $matcher = new ApacheUrlMatcher($collection, $context);
-
- $_SERVER = $server;
-
- $result = $matcher->match($pathinfo, $server);
- $this->assertSame(var_export($expect, true), var_export($result, true));
- }
-
- public function getMatchData()
- {
- return array(
- array(
- 'Simple route',
- '/hello/world',
- array(
- '_ROUTING_route' => 'hello',
- '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
- '_ROUTING_param_name' => 'world',
- ),
- array(
- '_controller' => 'AcmeBundle:Default:index',
- 'name' => 'world',
- '_route' => 'hello',
- ),
- ),
- array(
- 'Route with params and defaults',
- '/hello/hugo',
- array(
- '_ROUTING_route' => 'hello',
- '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
- '_ROUTING_param_name' => 'hugo',
- '_ROUTING_default_name' => 'world',
- ),
- array(
- 'name' => 'hugo',
- '_controller' => 'AcmeBundle:Default:index',
- '_route' => 'hello',
- ),
- ),
- array(
- 'Route with defaults only',
- '/hello',
- array(
- '_ROUTING_route' => 'hello',
- '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
- '_ROUTING_default_name' => 'world',
- ),
- array(
- 'name' => 'world',
- '_controller' => 'AcmeBundle:Default:index',
- '_route' => 'hello',
- ),
- ),
- array(
- 'REDIRECT_ envs',
- '/hello/world',
- array(
- 'REDIRECT__ROUTING_route' => 'hello',
- 'REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
- 'REDIRECT__ROUTING_param_name' => 'world',
- ),
- array(
- '_controller' => 'AcmeBundle:Default:index',
- 'name' => 'world',
- '_route' => 'hello',
- ),
- ),
- array(
- 'REDIRECT_REDIRECT_ envs',
- '/hello/world',
- array(
- 'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
- 'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
- 'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
- ),
- array(
- '_controller' => 'AcmeBundle:Default:index',
- 'name' => 'world',
- '_route' => 'hello',
- ),
- ),
- array(
- 'REDIRECT_REDIRECT_ envs',
- '/hello/world',
- array(
- 'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
- 'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
- 'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
- ),
- array(
- '_controller' => 'AcmeBundle:Default:index',
- 'name' => 'world',
- '_route' => 'hello',
- ),
- ),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
-
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Matcher\Dumper\ApacheMatcherDumper;
-
-class ApacheMatcherDumperTest extends \PHPUnit_Framework_TestCase
-{
- protected static $fixturesPath;
-
- public static function setUpBeforeClass()
- {
- self::$fixturesPath = realpath(__DIR__.'/../../Fixtures/');
- }
-
- public function testDump()
- {
- $dumper = new ApacheMatcherDumper($this->getRouteCollection());
-
- $this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher1.apache', $dumper->dump(), '->dump() dumps basic routes to the correct apache format.');
- }
-
- /**
- * @dataProvider provideEscapeFixtures
- */
- public function testEscapePattern($src, $dest, $char, $with, $message)
- {
- $r = new \ReflectionMethod(new ApacheMatcherDumper($this->getRouteCollection()), 'escape');
- $r->setAccessible(true);
- $this->assertEquals($dest, $r->invoke(null, $src, $char, $with), $message);
- }
-
- public function provideEscapeFixtures()
- {
- return array(
- array('foo', 'foo', ' ', '-', 'Preserve string that should not be escaped'),
- array('fo-o', 'fo-o', ' ', '-', 'Preserve string that should not be escaped'),
- array('fo o', 'fo- o', ' ', '-', 'Escape special characters'),
- array('fo-- o', 'fo--- o', ' ', '-', 'Escape special characters'),
- array('fo- o', 'fo- o', ' ', '-', 'Do not escape already escaped string'),
- );
- }
-
- public function testEscapeScriptName()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo'));
- $dumper = new ApacheMatcherDumper($collection);
- $this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher2.apache', $dumper->dump(array('script_name' => 'ap p_d\ ev.php')));
- }
-
- private function getRouteCollection()
- {
- $collection = new RouteCollection();
-
- // defaults and requirements
- $collection->add('foo', new Route(
- '/foo/{bar}',
- array('def' => 'test'),
- array('bar' => 'baz|symfony')
- ));
- // defaults parameters in pattern
- $collection->add('foobar', new Route(
- '/foo/{bar}',
- array('bar' => 'toto')
- ));
- // method requirement
- $collection->add('bar', new Route(
- '/bar/{foo}',
- array(),
- array('_method' => 'GET|head')
- ));
- // method requirement (again)
- $collection->add('baragain', new Route(
- '/baragain/{foo}',
- array(),
- array('_method' => 'get|post')
- ));
- // simple
- $collection->add('baz', new Route(
- '/test/baz'
- ));
- // simple with extension
- $collection->add('baz2', new Route(
- '/test/baz.html'
- ));
- // trailing slash
- $collection->add('baz3', new Route(
- '/test/baz3/'
- ));
- // trailing slash with variable
- $collection->add('baz4', new Route(
- '/test/{foo}/'
- ));
- // trailing slash and safe method
- $collection->add('baz5', new Route(
- '/test/{foo}/',
- array(),
- array('_method' => 'get')
- ));
- // trailing slash and unsafe method
- $collection->add('baz5unsafe', new Route(
- '/testunsafe/{foo}/',
- array(),
- array('_method' => 'post')
- ));
- // complex
- $collection->add('baz6', new Route(
- '/test/baz',
- array('foo' => 'bar baz')
- ));
- // space in path
- $collection->add('baz7', new Route(
- '/te st/baz'
- ));
- // space preceded with \ in path
- $collection->add('baz8', new Route(
- '/te\\ st/baz'
- ));
- // space preceded with \ in requirement
- $collection->add('baz9', new Route(
- '/test/{baz}',
- array(),
- array(
- 'baz' => 'te\\\\ st',
- )
- ));
-
- $collection1 = new RouteCollection();
-
- $route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
- $collection1->add('route1', $route1);
-
- $collection2 = new RouteCollection();
-
- $route2 = new Route('/route2', array(), array(), array(), 'a.example.com');
- $collection2->add('route2', $route2);
-
- $route3 = new Route('/route3', array(), array(), array(), 'b.example.com');
- $collection2->add('route3', $route3);
-
- $collection2->addPrefix('/c2');
- $collection1->addCollection($collection2);
-
- $route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
- $collection1->add('route4', $route4);
-
- $route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
- $collection1->add('route5', $route5);
-
- $route6 = new Route('/route6', array(), array(), array(), null);
- $collection1->add('route6', $route6);
-
- $collection->addCollection($collection1);
-
- // host and variables
-
- $collection1 = new RouteCollection();
-
- $route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
- $collection1->add('route11', $route11);
-
- $route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
- $collection1->add('route12', $route12);
-
- $route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
- $collection1->add('route13', $route13);
-
- $route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
- $collection1->add('route14', $route14);
-
- $route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
- $collection1->add('route15', $route15);
-
- $route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
- $collection1->add('route16', $route16);
-
- $route17 = new Route('/route17', array(), array(), array(), null);
- $collection1->add('route17', $route17);
-
- $collection->addCollection($collection1);
-
- return $collection;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Test\Matcher\Dumper;
-
-use Symfony\Component\Routing\Matcher\Dumper\DumperCollection;
-
-class DumperCollectionTest extends \PHPUnit_Framework_TestCase
-{
- public function testGetRoot()
- {
- $a = new DumperCollection();
-
- $b = new DumperCollection();
- $a->add($b);
-
- $c = new DumperCollection();
- $b->add($c);
-
- $d = new DumperCollection();
- $c->add($d);
-
- $this->assertSame($a, $c->getRoot());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
-
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\Matcher\Dumper\DumperPrefixCollection;
-use Symfony\Component\Routing\Matcher\Dumper\DumperRoute;
-use Symfony\Component\Routing\Matcher\Dumper\DumperCollection;
-
-class DumperPrefixCollectionTest extends \PHPUnit_Framework_TestCase
-{
- public function testAddPrefixRoute()
- {
- $coll = new DumperPrefixCollection;
- $coll->setPrefix('');
-
- $route = new DumperRoute('bar', new Route('/foo/bar'));
- $coll = $coll->addPrefixRoute($route);
-
- $route = new DumperRoute('bar2', new Route('/foo/bar'));
- $coll = $coll->addPrefixRoute($route);
-
- $route = new DumperRoute('qux', new Route('/foo/qux'));
- $coll = $coll->addPrefixRoute($route);
-
- $route = new DumperRoute('bar3', new Route('/foo/bar'));
- $coll = $coll->addPrefixRoute($route);
-
- $route = new DumperRoute('bar4', new Route(''));
- $result = $coll->addPrefixRoute($route);
-
- $expect = <<<'EOF'
- |-coll /
- | |-coll /f
- | | |-coll /fo
- | | | |-coll /foo
- | | | | |-coll /foo/
- | | | | | |-coll /foo/b
- | | | | | | |-coll /foo/ba
- | | | | | | | |-coll /foo/bar
- | | | | | | | | |-route bar /foo/bar
- | | | | | | | | |-route bar2 /foo/bar
- | | | | | |-coll /foo/q
- | | | | | | |-coll /foo/qu
- | | | | | | | |-coll /foo/qux
- | | | | | | | | |-route qux /foo/qux
- | | | | | |-coll /foo/b
- | | | | | | |-coll /foo/ba
- | | | | | | | |-coll /foo/bar
- | | | | | | | | |-route bar3 /foo/bar
- | |-route bar4 /
-
-EOF;
-
- $this->assertSame($expect, $this->collectionToString($result->getRoot(), ' '));
- }
-
- public function testMergeSlashNodes()
- {
- $coll = new DumperPrefixCollection;
- $coll->setPrefix('');
-
- $route = new DumperRoute('bar', new Route('/foo/bar'));
- $coll = $coll->addPrefixRoute($route);
-
- $route = new DumperRoute('bar2', new Route('/foo/bar'));
- $coll = $coll->addPrefixRoute($route);
-
- $route = new DumperRoute('qux', new Route('/foo/qux'));
- $coll = $coll->addPrefixRoute($route);
-
- $route = new DumperRoute('bar3', new Route('/foo/bar'));
- $result = $coll->addPrefixRoute($route);
-
- $result->getRoot()->mergeSlashNodes();
-
- $expect = <<<'EOF'
- |-coll /f
- | |-coll /fo
- | | |-coll /foo
- | | | |-coll /foo/b
- | | | | |-coll /foo/ba
- | | | | | |-coll /foo/bar
- | | | | | | |-route bar /foo/bar
- | | | | | | |-route bar2 /foo/bar
- | | | |-coll /foo/q
- | | | | |-coll /foo/qu
- | | | | | |-coll /foo/qux
- | | | | | | |-route qux /foo/qux
- | | | |-coll /foo/b
- | | | | |-coll /foo/ba
- | | | | | |-coll /foo/bar
- | | | | | | |-route bar3 /foo/bar
-
-EOF;
-
- $this->assertSame($expect, $this->collectionToString($result->getRoot(), ' '));
- }
-
- private function collectionToString(DumperCollection $collection, $prefix)
- {
- $string = '';
- foreach ($collection as $route) {
- if ($route instanceof DumperCollection) {
- $string .= sprintf("%s|-coll %s\n", $prefix, $route->getPrefix());
- $string .= $this->collectionToString($route, $prefix.'| ');
- } else {
- $string .= sprintf("%s|-route %s %s\n", $prefix, $route->getName(), $route->getRoute()->getPath());
- }
- }
-
- return $string;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
-
-use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-
-class PhpMatcherDumperTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @expectedException \LogicException
- */
- public function testDumpWhenSchemeIsUsedWithoutAProperDumper()
- {
- $collection = new RouteCollection();
- $collection->add('secure', new Route(
- '/secure',
- array(),
- array('_scheme' => 'https')
- ));
- $dumper = new PhpMatcherDumper($collection);
- $dumper->dump();
- }
-
- /**
- * @dataProvider getRouteCollections
- */
- public function testDump(RouteCollection $collection, $fixture, $options = array())
- {
- $basePath = __DIR__.'/../../Fixtures/dumper/';
-
- $dumper = new PhpMatcherDumper($collection);
- $this->assertStringEqualsFile($basePath.$fixture, $dumper->dump($options), '->dump() correctly dumps routes as optimized PHP code.');
- }
-
- public function getRouteCollections()
- {
- /* test case 1 */
-
- $collection = new RouteCollection();
-
- $collection->add('overridden', new Route('/overridden'));
-
- // defaults and requirements
- $collection->add('foo', new Route(
- '/foo/{bar}',
- array('def' => 'test'),
- array('bar' => 'baz|symfony')
- ));
- // method requirement
- $collection->add('bar', new Route(
- '/bar/{foo}',
- array(),
- array('_method' => 'GET|head')
- ));
- // GET method requirement automatically adds HEAD as valid
- $collection->add('barhead', new Route(
- '/barhead/{foo}',
- array(),
- array('_method' => 'GET')
- ));
- // simple
- $collection->add('baz', new Route(
- '/test/baz'
- ));
- // simple with extension
- $collection->add('baz2', new Route(
- '/test/baz.html'
- ));
- // trailing slash
- $collection->add('baz3', new Route(
- '/test/baz3/'
- ));
- // trailing slash with variable
- $collection->add('baz4', new Route(
- '/test/{foo}/'
- ));
- // trailing slash and method
- $collection->add('baz5', new Route(
- '/test/{foo}/',
- array(),
- array('_method' => 'post')
- ));
- // complex name
- $collection->add('baz.baz6', new Route(
- '/test/{foo}/',
- array(),
- array('_method' => 'put')
- ));
- // defaults without variable
- $collection->add('foofoo', new Route(
- '/foofoo',
- array('def' => 'test')
- ));
- // pattern with quotes
- $collection->add('quoter', new Route(
- '/{quoter}',
- array(),
- array('quoter' => '[\']+')
- ));
- // space in pattern
- $collection->add('space', new Route(
- '/spa ce'
- ));
-
- // prefixes
- $collection1 = new RouteCollection();
- $collection1->add('overridden', new Route('/overridden1'));
- $collection1->add('foo1', new Route('/{foo}'));
- $collection1->add('bar1', new Route('/{bar}'));
- $collection1->addPrefix('/b\'b');
- $collection2 = new RouteCollection();
- $collection2->addCollection($collection1);
- $collection2->add('overridden', new Route('/{var}', array(), array('var' => '.*')));
- $collection1 = new RouteCollection();
- $collection1->add('foo2', new Route('/{foo1}'));
- $collection1->add('bar2', new Route('/{bar1}'));
- $collection1->addPrefix('/b\'b');
- $collection2->addCollection($collection1);
- $collection2->addPrefix('/a');
- $collection->addCollection($collection2);
-
- // overridden through addCollection() and multiple sub-collections with no own prefix
- $collection1 = new RouteCollection();
- $collection1->add('overridden2', new Route('/old'));
- $collection1->add('helloWorld', new Route('/hello/{who}', array('who' => 'World!')));
- $collection2 = new RouteCollection();
- $collection3 = new RouteCollection();
- $collection3->add('overridden2', new Route('/new'));
- $collection3->add('hey', new Route('/hey/'));
- $collection2->addCollection($collection3);
- $collection1->addCollection($collection2);
- $collection1->addPrefix('/multi');
- $collection->addCollection($collection1);
-
- // "dynamic" prefix
- $collection1 = new RouteCollection();
- $collection1->add('foo3', new Route('/{foo}'));
- $collection1->add('bar3', new Route('/{bar}'));
- $collection1->addPrefix('/b');
- $collection1->addPrefix('{_locale}');
- $collection->addCollection($collection1);
-
- // route between collections
- $collection->add('ababa', new Route('/ababa'));
-
- // collection with static prefix but only one route
- $collection1 = new RouteCollection();
- $collection1->add('foo4', new Route('/{foo}'));
- $collection1->addPrefix('/aba');
- $collection->addCollection($collection1);
-
- // prefix and host
-
- $collection1 = new RouteCollection();
-
- $route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
- $collection1->add('route1', $route1);
-
- $collection2 = new RouteCollection();
-
- $route2 = new Route('/c2/route2', array(), array(), array(), 'a.example.com');
- $collection1->add('route2', $route2);
-
- $route3 = new Route('/c2/route3', array(), array(), array(), 'b.example.com');
- $collection1->add('route3', $route3);
-
- $route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
- $collection1->add('route4', $route4);
-
- $route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
- $collection1->add('route5', $route5);
-
- $route6 = new Route('/route6', array(), array(), array(), null);
- $collection1->add('route6', $route6);
-
- $collection->addCollection($collection1);
-
- // host and variables
-
- $collection1 = new RouteCollection();
-
- $route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
- $collection1->add('route11', $route11);
-
- $route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
- $collection1->add('route12', $route12);
-
- $route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
- $collection1->add('route13', $route13);
-
- $route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
- $collection1->add('route14', $route14);
-
- $route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
- $collection1->add('route15', $route15);
-
- $route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
- $collection1->add('route16', $route16);
-
- $route17 = new Route('/route17', array(), array(), array(), null);
- $collection1->add('route17', $route17);
-
- $collection->addCollection($collection1);
-
- // multiple sub-collections with a single route and a prefix each
- $collection1 = new RouteCollection();
- $collection1->add('a', new Route('/a...'));
- $collection2 = new RouteCollection();
- $collection2->add('b', new Route('/{var}'));
- $collection3 = new RouteCollection();
- $collection3->add('c', new Route('/{var}'));
- $collection3->addPrefix('/c');
- $collection2->addCollection($collection3);
- $collection2->addPrefix('/b');
- $collection1->addCollection($collection2);
- $collection1->addPrefix('/a');
- $collection->addCollection($collection1);
-
- /* test case 2 */
-
- $redirectCollection = clone $collection;
-
- // force HTTPS redirection
- $redirectCollection->add('secure', new Route(
- '/secure',
- array(),
- array('_scheme' => 'https')
- ));
-
- // force HTTP redirection
- $redirectCollection->add('nonsecure', new Route(
- '/nonsecure',
- array(),
- array('_scheme' => 'http')
- ));
-
- /* test case 3 */
-
- $rootprefixCollection = new RouteCollection();
- $rootprefixCollection->add('static', new Route('/test'));
- $rootprefixCollection->add('dynamic', new Route('/{var}'));
- $rootprefixCollection->addPrefix('rootprefix');
-
- return array(
- array($collection, 'url_matcher1.php', array()),
- array($redirectCollection, 'url_matcher2.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
- array($rootprefixCollection, 'url_matcher3.php', array())
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Matcher;
-
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\RequestContext;
-
-class RedirectableUrlMatcherTest extends \PHPUnit_Framework_TestCase
-{
- public function testRedirectWhenNoSlash()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo/'));
-
- $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
- $matcher->expects($this->once())->method('redirect');
- $matcher->match('/foo');
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
- */
- public function testRedirectWhenNoSlashForNonSafeMethod()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo/'));
-
- $context = new RequestContext();
- $context->setMethod('POST');
- $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, $context));
- $matcher->match('/foo');
- }
-
- public function testSchemeRedirect()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo', array(), array('_scheme' => 'https')));
-
- $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
- $matcher
- ->expects($this->once())
- ->method('redirect')
- ->with('/foo', 'foo', 'https')
- ->will($this->returnValue(array('_route' => 'foo')))
- ;
- $matcher->match('/foo');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Matcher;
-
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\RequestContext;
-use Symfony\Component\Routing\Matcher\TraceableUrlMatcher;
-
-class TraceableUrlMatcherTest extends \PHPUnit_Framework_TestCase
-{
- public function test()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo', array(), array('_method' => 'POST')));
- $coll->add('bar', new Route('/bar/{id}', array(), array('id' => '\d+')));
- $coll->add('bar1', new Route('/bar/{name}', array(), array('id' => '\w+', '_method' => 'POST')));
- $coll->add('bar2', new Route('/foo', array(), array(), array(), 'baz'));
- $coll->add('bar3', new Route('/foo1', array(), array(), array(), 'baz'));
-
- $context = new RequestContext();
- $context->setHost('baz');
-
- $matcher = new TraceableUrlMatcher($coll, $context);
- $traces = $matcher->getTraces('/babar');
- $this->assertEquals(array(0, 0, 0, 0, 0), $this->getLevels($traces));
-
- $traces = $matcher->getTraces('/foo');
- $this->assertEquals(array(1, 0, 0, 2), $this->getLevels($traces));
-
- $traces = $matcher->getTraces('/bar/12');
- $this->assertEquals(array(0, 2), $this->getLevels($traces));
-
- $traces = $matcher->getTraces('/bar/dd');
- $this->assertEquals(array(0, 1, 1, 0, 0), $this->getLevels($traces));
-
- $traces = $matcher->getTraces('/foo1');
- $this->assertEquals(array(0, 0, 0, 0, 2), $this->getLevels($traces));
-
- $context->setMethod('POST');
- $traces = $matcher->getTraces('/foo');
- $this->assertEquals(array(2), $this->getLevels($traces));
-
- $traces = $matcher->getTraces('/bar/dd');
- $this->assertEquals(array(0, 1, 2), $this->getLevels($traces));
- }
-
- public function getLevels($traces)
- {
- $levels = array();
- foreach ($traces as $trace) {
- $levels[] = $trace['level'];
- }
-
- return $levels;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests\Matcher;
-
-use Symfony\Component\Routing\Exception\MethodNotAllowedException;
-use Symfony\Component\Routing\Exception\ResourceNotFoundException;
-use Symfony\Component\Routing\Matcher\UrlMatcher;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\RequestContext;
-
-class UrlMatcherTest extends \PHPUnit_Framework_TestCase
-{
- public function testNoMethodSoAllowed()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo'));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
- $matcher->match('/foo');
- }
-
- public function testMethodNotAllowed()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo', array(), array('_method' => 'post')));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
-
- try {
- $matcher->match('/foo');
- $this->fail();
- } catch (MethodNotAllowedException $e) {
- $this->assertEquals(array('POST'), $e->getAllowedMethods());
- }
- }
-
- public function testHeadAllowedWhenRequirementContainsGet()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo', array(), array('_method' => 'get')));
-
- $matcher = new UrlMatcher($coll, new RequestContext('', 'head'));
- $matcher->match('/foo');
- }
-
- public function testMethodNotAllowedAggregatesAllowedMethods()
- {
- $coll = new RouteCollection();
- $coll->add('foo1', new Route('/foo', array(), array('_method' => 'post')));
- $coll->add('foo2', new Route('/foo', array(), array('_method' => 'put|delete')));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
-
- try {
- $matcher->match('/foo');
- $this->fail();
- } catch (MethodNotAllowedException $e) {
- $this->assertEquals(array('POST', 'PUT', 'DELETE'), $e->getAllowedMethods());
- }
- }
-
- public function testMatch()
- {
- // test the patterns are matched and parameters are returned
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo/{bar}'));
- $matcher = new UrlMatcher($collection, new RequestContext());
- try {
- $matcher->match('/no-match');
- $this->fail();
- } catch (ResourceNotFoundException $e) {}
- $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz'), $matcher->match('/foo/baz'));
-
- // test that defaults are merged
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo/{bar}', array('def' => 'test')));
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz', 'def' => 'test'), $matcher->match('/foo/baz'));
-
- // test that route "method" is ignored if no method is given in the context
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo', array(), array('_method' => 'GET|head')));
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertInternalType('array', $matcher->match('/foo'));
-
- // route does not match with POST method context
- $matcher = new UrlMatcher($collection, new RequestContext('', 'post'));
- try {
- $matcher->match('/foo');
- $this->fail();
- } catch (MethodNotAllowedException $e) {}
-
- // route does match with GET or HEAD method context
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertInternalType('array', $matcher->match('/foo'));
- $matcher = new UrlMatcher($collection, new RequestContext('', 'head'));
- $this->assertInternalType('array', $matcher->match('/foo'));
-
- // route with an optional variable as the first segment
- $collection = new RouteCollection();
- $collection->add('bar', new Route('/{bar}/foo', array('bar' => 'bar'), array('bar' => 'foo|bar')));
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/bar/foo'));
- $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo/foo'));
-
- $collection = new RouteCollection();
- $collection->add('bar', new Route('/{bar}', array('bar' => 'bar'), array('bar' => 'foo|bar')));
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo'));
- $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/'));
-
- // route with only optional variables
- $collection = new RouteCollection();
- $collection->add('bar', new Route('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar'), array()));
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'), $matcher->match('/'));
- $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'), $matcher->match('/a'));
- $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'b'), $matcher->match('/a/b'));
- }
-
- public function testMatchWithPrefixes()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/{foo}'));
- $collection->addPrefix('/b');
- $collection->addPrefix('/a');
-
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => 'foo', 'foo' => 'foo'), $matcher->match('/a/b/foo'));
- }
-
- public function testMatchWithDynamicPrefix()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/{foo}'));
- $collection->addPrefix('/b');
- $collection->addPrefix('/{_locale}');
-
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'), $matcher->match('/fr/b/foo'));
- }
-
- public function testMatchSpecialRouteName()
- {
- $collection = new RouteCollection();
- $collection->add('$péß^a|', new Route('/bar'));
-
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar'));
- }
-
- public function testMatchNonAlpha()
- {
- $collection = new RouteCollection();
- $chars = '!"$%éà &\'()*+,./:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[]^_`abcdefghijklmnopqrstuvwxyz{|}~-';
- $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '['.preg_quote($chars).']+')));
-
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.rawurlencode($chars).'/bar'));
- $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.strtr($chars, array('%' => '%25')).'/bar'));
- }
-
- public function testMatchWithDotMetacharacterInRequirements()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '.+')));
-
- $matcher = new UrlMatcher($collection, new RequestContext());
- $this->assertEquals(array('_route' => 'foo', 'foo' => "\n"), $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched');
- }
-
- public function testMatchOverriddenRoute()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo'));
-
- $collection1 = new RouteCollection();
- $collection1->add('foo', new Route('/foo1'));
-
- $collection->addCollection($collection1);
-
- $matcher = new UrlMatcher($collection, new RequestContext());
-
- $this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo1'));
- $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
- $this->assertEquals(array(), $matcher->match('/foo'));
- }
-
- public function testMatchRegression()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo/{foo}'));
- $coll->add('bar', new Route('/foo/bar/{foo}'));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
- $this->assertEquals(array('foo' => 'bar', '_route' => 'bar'), $matcher->match('/foo/bar/bar'));
-
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/{bar}'));
- $matcher = new UrlMatcher($collection, new RequestContext());
- try {
- $matcher->match('/');
- $this->fail();
- } catch (ResourceNotFoundException $e) {
- }
- }
-
- public function testDefaultRequirementForOptionalVariables()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/{page}.{_format}', array('page' => 'index', '_format' => 'html')));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
- $this->assertEquals(array('page' => 'my-page', '_format' => 'xml', '_route' => 'test'), $matcher->match('/my-page.xml'));
- }
-
- public function testMatchingIsEager()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/{foo}-{bar}-', array(), array('foo' => '.+', 'bar' => '.+')));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
- $this->assertEquals(array('foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'), $matcher->match('/text1-text2-text3-text4-'));
- }
-
- public function testAdjacentVariables()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => 'y|Y')));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
- // 'w' eagerly matches as much as possible and the other variables match the remaining chars.
- // This also shows that the variables w-z must all exclude the separating char (the dot '.' in this case) by default requirement.
- // Otherwise they would also consume '.xml' and _format would never match as it's an optional variable.
- $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'Y', 'z' => 'Z','_format' => 'xml', '_route' => 'test'), $matcher->match('/wwwwwxYZ.xml'));
- // As 'y' has custom requirement and can only be of value 'y|Y', it will leave 'ZZZ' to variable z.
- // So with carefully chosen requirements adjacent variables, can be useful.
- $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'ZZZ','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxyZZZ'));
- // z and _format are optional.
- $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxy'));
-
- $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
- $matcher->match('/wxy.html');
- }
-
- public function testOptionalVariableWithNoRealSeparator()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/get{what}', array('what' => 'All')));
- $matcher = new UrlMatcher($coll, new RequestContext());
-
- $this->assertEquals(array('what' => 'All', '_route' => 'test'), $matcher->match('/get'));
- $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSites'));
-
- // Usually the character in front of an optional parameter can be left out, e.g. with pattern '/get/{what}' just '/get' would match.
- // But here the 't' in 'get' is not a separating character, so it makes no sense to match without it.
- $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
- $matcher->match('/ge');
- }
-
- public function testRequiredVariableWithNoRealSeparator()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/get{what}Suffix'));
- $matcher = new UrlMatcher($coll, new RequestContext());
-
- $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSitesSuffix'));
- }
-
- public function testDefaultRequirementOfVariable()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/{page}.{_format}'));
- $matcher = new UrlMatcher($coll, new RequestContext());
-
- $this->assertEquals(array('page' => 'index', '_format' => 'mobile.html', '_route' => 'test'), $matcher->match('/index.mobile.html'));
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
- */
- public function testDefaultRequirementOfVariableDisallowsSlash()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/{page}.{_format}'));
- $matcher = new UrlMatcher($coll, new RequestContext());
-
- $matcher->match('/index.sl/ash');
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
- */
- public function testDefaultRequirementOfVariableDisallowsNextSeparator()
- {
- $coll = new RouteCollection();
- $coll->add('test', new Route('/{page}.{_format}', array(), array('_format' => 'html|xml')));
- $matcher = new UrlMatcher($coll, new RequestContext());
-
- $matcher->match('/do.t.html');
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
- */
- public function testSchemeRequirement()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo', array(), array('_scheme' => 'https')));
- $matcher = new UrlMatcher($coll, new RequestContext());
- $matcher->match('/foo');
- }
-
- public function testDecodeOnce()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo/{foo}'));
-
- $matcher = new UrlMatcher($coll, new RequestContext());
- $this->assertEquals(array('foo' => 'bar%23', '_route' => 'foo'), $matcher->match('/foo/bar%2523'));
- }
-
- public function testCannotRelyOnPrefix()
- {
- $coll = new RouteCollection();
-
- $subColl = new RouteCollection();
- $subColl->add('bar', new Route('/bar'));
- $subColl->addPrefix('/prefix');
- // overwrite the pattern, so the prefix is not valid anymore for this route in the collection
- $subColl->get('bar')->setPattern('/new');
-
- $coll->addCollection($subColl);
-
- $matcher = new UrlMatcher($coll, new RequestContext());
- $this->assertEquals(array('_route' => 'bar'), $matcher->match('/new'));
- }
-
- public function testWithHost()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
-
- $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
- $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
- }
-
- public function testWithHostOnRouteCollection()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo/{foo}'));
- $coll->add('bar', new Route('/bar/{foo}', array(), array(), array(), '{locale}.example.net'));
- $coll->setHost('{locale}.example.com');
-
- $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
- $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
-
- $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
- $this->assertEquals(array('foo' => 'bar', '_route' => 'bar', 'locale' => 'en'), $matcher->match('/bar/bar'));
- }
-
- /**
- * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
- */
- public function testWithOutHostHostDoesNotMatch()
- {
- $coll = new RouteCollection();
- $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
-
- $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'example.com'));
- $matcher->match('/foo/bar');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Config\Resource\FileResource;
-
-class RouteCollectionTest extends \PHPUnit_Framework_TestCase
-{
- public function testRoute()
- {
- $collection = new RouteCollection();
- $route = new Route('/foo');
- $collection->add('foo', $route);
- $this->assertEquals(array('foo' => $route), $collection->all(), '->add() adds a route');
- $this->assertEquals($route, $collection->get('foo'), '->get() returns a route by name');
- $this->assertNull($collection->get('bar'), '->get() returns null if a route does not exist');
- }
-
- public function testOverriddenRoute()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo'));
- $collection->add('foo', new Route('/foo1'));
-
- $this->assertEquals('/foo1', $collection->get('foo')->getPath());
- }
-
- public function testDeepOverriddenRoute()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo'));
-
- $collection1 = new RouteCollection();
- $collection1->add('foo', new Route('/foo1'));
-
- $collection2 = new RouteCollection();
- $collection2->add('foo', new Route('/foo2'));
-
- $collection1->addCollection($collection2);
- $collection->addCollection($collection1);
-
- $this->assertEquals('/foo2', $collection1->get('foo')->getPath());
- $this->assertEquals('/foo2', $collection->get('foo')->getPath());
- }
-
- public function testIterator()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo'));
-
- $collection1 = new RouteCollection();
- $collection1->add('bar', $bar = new Route('/bar'));
- $collection1->add('foo', $foo = new Route('/foo-new'));
- $collection->addCollection($collection1);
- $collection->add('last', $last = new Route('/last'));
-
- $this->assertInstanceOf('\ArrayIterator', $collection->getIterator());
- $this->assertSame(array('bar' => $bar, 'foo' => $foo, 'last' => $last), $collection->getIterator()->getArrayCopy());
- }
-
- public function testCount()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo'));
-
- $collection1 = new RouteCollection();
- $collection1->add('bar', new Route('/bar'));
- $collection->addCollection($collection1);
-
- $this->assertCount(2, $collection);
- }
-
- public function testAddCollection()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/foo'));
-
- $collection1 = new RouteCollection();
- $collection1->add('bar', $bar = new Route('/bar'));
- $collection1->add('foo', $foo = new Route('/foo-new'));
-
- $collection2 = new RouteCollection();
- $collection2->add('grandchild', $grandchild = new Route('/grandchild'));
-
- $collection1->addCollection($collection2);
- $collection->addCollection($collection1);
- $collection->add('last', $last = new Route('/last'));
-
- $this->assertSame(array('bar' => $bar, 'foo' => $foo, 'grandchild' => $grandchild, 'last' => $last), $collection->all(),
- '->addCollection() imports routes of another collection, overrides if necessary and adds them at the end');
- }
-
- public function testAddCollectionWithResources()
- {
- if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- $collection = new RouteCollection();
- $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml'));
- $collection1 = new RouteCollection();
- $collection1->addResource($foo1 = new FileResource(__DIR__.'/Fixtures/foo1.xml'));
- $collection->addCollection($collection1);
- $this->assertEquals(array($foo, $foo1), $collection->getResources(), '->addCollection() merges resources');
- }
-
- public function testAddDefaultsAndRequirementsAndOptions()
- {
- $collection = new RouteCollection();
- $collection->add('foo', new Route('/{placeholder}'));
- $collection1 = new RouteCollection();
- $collection1->add('bar', new Route('/{placeholder}',
- array('_controller' => 'fixed', 'placeholder' => 'default'), array('placeholder' => '.+'), array('option' => 'value'))
- );
- $collection->addCollection($collection1);
-
- $collection->addDefaults(array('placeholder' => 'new-default'));
- $this->assertEquals(array('placeholder' => 'new-default'), $collection->get('foo')->getDefaults(), '->addDefaults() adds defaults to all routes');
- $this->assertEquals(array('_controller' => 'fixed', 'placeholder' => 'new-default'), $collection->get('bar')->getDefaults(),
- '->addDefaults() adds defaults to all routes and overwrites existing ones');
-
- $collection->addRequirements(array('placeholder' => '\d+'));
- $this->assertEquals(array('placeholder' => '\d+'), $collection->get('foo')->getRequirements(), '->addRequirements() adds requirements to all routes');
- $this->assertEquals(array('placeholder' => '\d+'), $collection->get('bar')->getRequirements(),
- '->addRequirements() adds requirements to all routes and overwrites existing ones');
-
- $collection->addOptions(array('option' => 'new-value'));
- $this->assertEquals(
- array('option' => 'new-value', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'),
- $collection->get('bar')->getOptions(), '->addOptions() adds options to all routes and overwrites existing ones'
- );
- }
-
- public function testAddPrefix()
- {
- $collection = new RouteCollection();
- $collection->add('foo', $foo = new Route('/foo'));
- $collection2 = new RouteCollection();
- $collection2->add('bar', $bar = new Route('/bar'));
- $collection->addCollection($collection2);
- $collection->addPrefix(' / ');
- $this->assertSame('/foo', $collection->get('foo')->getPattern(), '->addPrefix() trims the prefix and a single slash has no effect');
- $collection->addPrefix('/{admin}', array('admin' => 'admin'), array('admin' => '\d+'));
- $this->assertEquals('/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() adds a prefix to all routes');
- $this->assertEquals('/{admin}/bar', $collection->get('bar')->getPath(), '->addPrefix() adds a prefix to all routes');
- $this->assertEquals(array('admin' => 'admin'), $collection->get('foo')->getDefaults(), '->addPrefix() adds defaults to all routes');
- $this->assertEquals(array('admin' => 'admin'), $collection->get('bar')->getDefaults(), '->addPrefix() adds defaults to all routes');
- $this->assertEquals(array('admin' => '\d+'), $collection->get('foo')->getRequirements(), '->addPrefix() adds requirements to all routes');
- $this->assertEquals(array('admin' => '\d+'), $collection->get('bar')->getRequirements(), '->addPrefix() adds requirements to all routes');
- $collection->addPrefix('0');
- $this->assertEquals('/0/{admin}/foo', $collection->get('foo')->getPattern(), '->addPrefix() ensures a prefix must start with a slash and must not end with a slash');
- $collection->addPrefix('/ /');
- $this->assertSame('/ /0/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() can handle spaces if desired');
- $this->assertSame('/ /0/{admin}/bar', $collection->get('bar')->getPath(), 'the route pattern of an added collection is in synch with the added prefix');
- }
-
- public function testAddPrefixOverridesDefaultsAndRequirements()
- {
- $collection = new RouteCollection();
- $collection->add('foo', $foo = new Route('/foo'));
- $collection->add('bar', $bar = new Route('/bar', array(), array('_scheme' => 'http')));
- $collection->addPrefix('/admin', array(), array('_scheme' => 'https'));
-
- $this->assertEquals('https', $collection->get('foo')->getRequirement('_scheme'), '->addPrefix() overrides existing requirements');
- $this->assertEquals('https', $collection->get('bar')->getRequirement('_scheme'), '->addPrefix() overrides existing requirements');
- }
-
- public function testResource()
- {
- if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- $collection = new RouteCollection();
- $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml'));
- $collection->addResource($bar = new FileResource(__DIR__.'/Fixtures/bar.xml'));
- $collection->addResource(new FileResource(__DIR__.'/Fixtures/foo.xml'));
-
- $this->assertEquals(array($foo, $bar), $collection->getResources(),
- '->addResource() adds a resource and getResources() only returns unique ones by comparing the string representation');
- }
-
- public function testUniqueRouteWithGivenName()
- {
- $collection1 = new RouteCollection();
- $collection1->add('foo', new Route('/old'));
- $collection2 = new RouteCollection();
- $collection3 = new RouteCollection();
- $collection3->add('foo', $new = new Route('/new'));
-
- $collection2->addCollection($collection3);
- $collection1->addCollection($collection2);
-
- $this->assertSame($new, $collection1->get('foo'), '->get() returns new route that overrode previous one');
- // size of 1 because collection1 contains /new but not /old anymore
- $this->assertCount(1, $collection1->getIterator(), '->addCollection() removes previous routes when adding new routes with the same name');
- }
-
- public function testGet()
- {
- $collection1 = new RouteCollection();
- $collection1->add('a', $a = new Route('/a'));
- $collection2 = new RouteCollection();
- $collection2->add('b', $b = new Route('/b'));
- $collection1->addCollection($collection2);
- $collection1->add('$péß^a|', $c = new Route('/special'));
-
- $this->assertSame($b, $collection1->get('b'), '->get() returns correct route in child collection');
- $this->assertSame($c, $collection1->get('$péß^a|'), '->get() can handle special characters');
- $this->assertNull($collection2->get('a'), '->get() does not return the route defined in parent collection');
- $this->assertNull($collection1->get('non-existent'), '->get() returns null when route does not exist');
- $this->assertNull($collection1->get(0), '->get() does not disclose internal child RouteCollection');
- }
-
- public function testRemove()
- {
- $collection = new RouteCollection();
- $collection->add('foo', $foo = new Route('/foo'));
-
- $collection1 = new RouteCollection();
- $collection1->add('bar', $bar = new Route('/bar'));
- $collection->addCollection($collection1);
- $collection->add('last', $last = new Route('/last'));
-
- $collection->remove('foo');
- $this->assertSame(array('bar' => $bar, 'last' => $last), $collection->all(), '->remove() can remove a single route');
- $collection->remove(array('bar', 'last'));
- $this->assertSame(array(), $collection->all(), '->remove() accepts an array and can remove multiple routes at once');
- }
-
- public function testSetHost()
- {
- $collection = new RouteCollection();
- $routea = new Route('/a');
- $routeb = new Route('/b', array(), array(), array(), '{locale}.example.net');
- $collection->add('a', $routea);
- $collection->add('b', $routeb);
-
- $collection->setHost('{locale}.example.com');
-
- $this->assertEquals('{locale}.example.com', $routea->getHost());
- $this->assertEquals('{locale}.example.com', $routeb->getHost());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests;
-
-use Symfony\Component\Routing\Route;
-
-class RouteCompilerTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider provideCompileData
- */
- public function testCompile($name, $arguments, $prefix, $regex, $variables, $tokens)
- {
- $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
- $route = $r->newInstanceArgs($arguments);
-
- $compiled = $route->compile();
- $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
- $this->assertEquals($regex, $compiled->getRegex(), $name.' (regex)');
- $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
- $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
- }
-
- public function provideCompileData()
- {
- return array(
- array(
- 'Static route',
- array('/foo'),
- '/foo', '#^/foo$#s', array(), array(
- array('text', '/foo'),
- )),
-
- array(
- 'Route with a variable',
- array('/foo/{bar}'),
- '/foo', '#^/foo/(?P<bar>[^/]++)$#s', array('bar'), array(
- array('variable', '/', '[^/]++', 'bar'),
- array('text', '/foo'),
- )),
-
- array(
- 'Route with a variable that has a default value',
- array('/foo/{bar}', array('bar' => 'bar')),
- '/foo', '#^/foo(?:/(?P<bar>[^/]++))?$#s', array('bar'), array(
- array('variable', '/', '[^/]++', 'bar'),
- array('text', '/foo'),
- )),
-
- array(
- 'Route with several variables',
- array('/foo/{bar}/{foobar}'),
- '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
- array('variable', '/', '[^/]++', 'foobar'),
- array('variable', '/', '[^/]++', 'bar'),
- array('text', '/foo'),
- )),
-
- array(
- 'Route with several variables that have default values',
- array('/foo/{bar}/{foobar}', array('bar' => 'bar', 'foobar' => '')),
- '/foo', '#^/foo(?:/(?P<bar>[^/]++)(?:/(?P<foobar>[^/]++))?)?$#s', array('bar', 'foobar'), array(
- array('variable', '/', '[^/]++', 'foobar'),
- array('variable', '/', '[^/]++', 'bar'),
- array('text', '/foo'),
- )),
-
- array(
- 'Route with several variables but some of them have no default values',
- array('/foo/{bar}/{foobar}', array('bar' => 'bar')),
- '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
- array('variable', '/', '[^/]++', 'foobar'),
- array('variable', '/', '[^/]++', 'bar'),
- array('text', '/foo'),
- )),
-
- array(
- 'Route with an optional variable as the first segment',
- array('/{bar}', array('bar' => 'bar')),
- '', '#^/(?P<bar>[^/]++)?$#s', array('bar'), array(
- array('variable', '/', '[^/]++', 'bar'),
- )),
-
- array(
- 'Route with a requirement of 0',
- array('/{bar}', array('bar' => null), array('bar' => '0')),
- '', '#^/(?P<bar>0)?$#s', array('bar'), array(
- array('variable', '/', '0', 'bar'),
- )),
-
- array(
- 'Route with an optional variable as the first segment with requirements',
- array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')),
- '', '#^/(?P<bar>(foo|bar))?$#s', array('bar'), array(
- array('variable', '/', '(foo|bar)', 'bar'),
- )),
-
- array(
- 'Route with only optional variables',
- array('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar')),
- '', '#^/(?P<foo>[^/]++)?(?:/(?P<bar>[^/]++))?$#s', array('foo', 'bar'), array(
- array('variable', '/', '[^/]++', 'bar'),
- array('variable', '/', '[^/]++', 'foo'),
- )),
-
- array(
- 'Route with a variable in last position',
- array('/foo-{bar}'),
- '/foo', '#^/foo\-(?P<bar>[^/]++)$#s', array('bar'), array(
- array('variable', '-', '[^/]++', 'bar'),
- array('text', '/foo'),
- )),
-
- array(
- 'Route with nested placeholders',
- array('/{static{var}static}'),
- '/{static', '#^/\{static(?P<var>[^/]+)static\}$#s', array('var'), array(
- array('text', 'static}'),
- array('variable', '', '[^/]+', 'var'),
- array('text', '/{static'),
- )),
-
- array(
- 'Route without separator between variables',
- array('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '(y|Y)')),
- '', '#^/(?P<w>[^/\.]+)(?P<x>[^/\.]+)(?P<y>(y|Y))(?:(?P<z>[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#s', array('w', 'x', 'y', 'z', '_format'), array(
- array('variable', '.', '[^/]++', '_format'),
- array('variable', '', '[^/\.]++', 'z'),
- array('variable', '', '(y|Y)', 'y'),
- array('variable', '', '[^/\.]+', 'x'),
- array('variable', '/', '[^/\.]+', 'w'),
- )),
-
- array(
- 'Route with a format',
- array('/foo/{bar}.{_format}'),
- '/foo', '#^/foo/(?P<bar>[^/\.]++)\.(?P<_format>[^/]++)$#s', array('bar', '_format'), array(
- array('variable', '.', '[^/]++', '_format'),
- array('variable', '/', '[^/\.]++', 'bar'),
- array('text', '/foo'),
- )),
- );
- }
-
- /**
- * @expectedException \LogicException
- */
- public function testRouteWithSameVariableTwice()
- {
- $route = new Route('/{name}/{name}');
-
- $compiled = $route->compile();
- }
-
- /**
- * @dataProvider getNumericVariableNames
- * @expectedException \DomainException
- */
- public function testRouteWithNumericVariableName($name)
- {
- $route = new Route('/{'. $name.'}');
- $route->compile();
- }
-
- public function getNumericVariableNames()
- {
- return array(
- array('09'),
- array('123'),
- array('1e2')
- );
- }
-
- /**
- * @dataProvider provideCompileWithHostData
- */
- public function testCompileWithHost($name, $arguments, $prefix, $regex, $variables, $pathVariables, $tokens, $hostRegex, $hostVariables, $hostTokens)
- {
- $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
- $route = $r->newInstanceArgs($arguments);
-
- $compiled = $route->compile();
- $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
- $this->assertEquals($regex, str_replace(array("\n", ' '), '', $compiled->getRegex()), $name.' (regex)');
- $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
- $this->assertEquals($pathVariables, $compiled->getPathVariables(), $name.' (path variables)');
- $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
- $this->assertEquals($hostRegex, str_replace(array("\n", ' '), '', $compiled->getHostRegex()), $name.' (host regex)');
- $this->assertEquals($hostVariables, $compiled->getHostVariables(), $name.' (host variables)');
- $this->assertEquals($hostTokens, $compiled->getHostTokens(), $name.' (host tokens)');
- }
-
- public function provideCompileWithHostData()
- {
- return array(
- array(
- 'Route with host pattern',
- array('/hello', array(), array(), array(), 'www.example.com'),
- '/hello', '#^/hello$#s', array(), array(), array(
- array('text', '/hello'),
- ),
- '#^www\.example\.com$#s', array(), array(
- array('text', 'www.example.com'),
- ),
- ),
- array(
- 'Route with host pattern and some variables',
- array('/hello/{name}', array(), array(), array(), 'www.example.{tld}'),
- '/hello', '#^/hello/(?P<name>[^/]++)$#s', array('tld', 'name'), array('name'), array(
- array('variable', '/', '[^/]++', 'name'),
- array('text', '/hello'),
- ),
- '#^www\.example\.(?P<tld>[^\.]++)$#s', array('tld'), array(
- array('variable', '.', '[^\.]++', 'tld'),
- array('text', 'www.example'),
- ),
- ),
- array(
- 'Route with variable at beginning of host',
- array('/hello', array(), array(), array(), '{locale}.example.{tld}'),
- '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
- array('text', '/hello'),
- ),
- '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
- array('variable', '.', '[^\.]++', 'tld'),
- array('text', '.example'),
- array('variable', '', '[^\.]++', 'locale'),
- ),
- ),
- array(
- 'Route with host variables that has a default value',
- array('/hello', array('locale' => 'a', 'tld' => 'b'), array(), array(), '{locale}.example.{tld}'),
- '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
- array('text', '/hello'),
- ),
- '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
- array('variable', '.', '[^\.]++', 'tld'),
- array('text', '.example'),
- array('variable', '', '[^\.]++', 'locale'),
- ),
- ),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests;
-
-use Symfony\Component\Routing\Route;
-
-class RouteTest extends \PHPUnit_Framework_TestCase
-{
- public function testConstructor()
- {
- $route = new Route('/{foo}', array('foo' => 'bar'), array('foo' => '\d+'), array('foo' => 'bar'), '{locale}.example.com');
- $this->assertEquals('/{foo}', $route->getPath(), '__construct() takes a path as its first argument');
- $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '__construct() takes defaults as its second argument');
- $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '__construct() takes requirements as its third argument');
- $this->assertEquals('bar', $route->getOption('foo'), '__construct() takes options as its fourth argument');
- $this->assertEquals('{locale}.example.com', $route->getHost(), '__construct() takes a host pattern as its fifth argument');
-
- $route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put'));
- $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes schemes as its sixth argument and lowercases it');
- $this->assertEquals(array('POST', 'PUT'), $route->getMethods(), '__construct() takes methods as its seventh argument and uppercases it');
-
- $route = new Route('/', array(), array(), array(), '', 'Https', 'Post');
- $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes a single scheme as its sixth argument');
- $this->assertEquals(array('POST'), $route->getMethods(), '__construct() takes a single method as its seventh argument');
- }
-
- public function testPath()
- {
- $route = new Route('/{foo}');
- $route->setPath('/{bar}');
- $this->assertEquals('/{bar}', $route->getPath(), '->setPath() sets the path');
- $route->setPath('');
- $this->assertEquals('/', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
- $route->setPath('bar');
- $this->assertEquals('/bar', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
- $this->assertEquals($route, $route->setPath(''), '->setPath() implements a fluent interface');
- $route->setPath('//path');
- $this->assertEquals('/path', $route->getPath(), '->setPath() does not allow two slahes "//" at the beginning of the path as it would be confused with a network path when generating the path from the route');
- }
-
- public function testOptions()
- {
- $route = new Route('/{foo}');
- $route->setOptions(array('foo' => 'bar'));
- $this->assertEquals(array_merge(array(
- 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
- ), array('foo' => 'bar')), $route->getOptions(), '->setOptions() sets the options');
- $this->assertEquals($route, $route->setOptions(array()), '->setOptions() implements a fluent interface');
-
- $route->setOptions(array('foo' => 'foo'));
- $route->addOptions(array('bar' => 'bar'));
- $this->assertEquals($route, $route->addOptions(array()), '->addOptions() implements a fluent interface');
- $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $route->getOptions(), '->addDefaults() keep previous defaults');
- }
-
- public function testDefaults()
- {
- $route = new Route('/{foo}');
- $route->setDefaults(array('foo' => 'bar'));
- $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '->setDefaults() sets the defaults');
- $this->assertEquals($route, $route->setDefaults(array()), '->setDefaults() implements a fluent interface');
-
- $route->setDefault('foo', 'bar');
- $this->assertEquals('bar', $route->getDefault('foo'), '->setDefault() sets a default value');
-
- $route->setDefault('foo2', 'bar2');
- $this->assertEquals('bar2', $route->getDefault('foo2'), '->getDefault() return the default value');
- $this->assertNull($route->getDefault('not_defined'), '->getDefault() return null if default value is not setted');
-
- $route->setDefault('_controller', $closure = function () { return 'Hello'; });
- $this->assertEquals($closure, $route->getDefault('_controller'), '->setDefault() sets a default value');
-
- $route->setDefaults(array('foo' => 'foo'));
- $route->addDefaults(array('bar' => 'bar'));
- $this->assertEquals($route, $route->addDefaults(array()), '->addDefaults() implements a fluent interface');
- $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar'), $route->getDefaults(), '->addDefaults() keep previous defaults');
- }
-
- public function testRequirements()
- {
- $route = new Route('/{foo}');
- $route->setRequirements(array('foo' => '\d+'));
- $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '->setRequirements() sets the requirements');
- $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() returns a requirement');
- $this->assertNull($route->getRequirement('bar'), '->getRequirement() returns null if a requirement is not defined');
- $route->setRequirements(array('foo' => '^\d+$'));
- $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the path');
- $this->assertEquals($route, $route->setRequirements(array()), '->setRequirements() implements a fluent interface');
-
- $route->setRequirements(array('foo' => '\d+'));
- $route->addRequirements(array('bar' => '\d+'));
- $this->assertEquals($route, $route->addRequirements(array()), '->addRequirements() implements a fluent interface');
- $this->assertEquals(array('foo' => '\d+', 'bar' => '\d+'), $route->getRequirements(), '->addRequirement() keep previous requirements');
- }
-
- public function testRequirement()
- {
- $route = new Route('/{foo}');
- $route->setRequirement('foo', '^\d+$');
- $this->assertEquals('\d+', $route->getRequirement('foo'), '->setRequirement() removes ^ and $ from the path');
- }
-
- /**
- * @dataProvider getInvalidRequirements
- * @expectedException \InvalidArgumentException
- */
- public function testSetInvalidRequirement($req)
- {
- $route = new Route('/{foo}');
- $route->setRequirement('foo', $req);
- }
-
- public function getInvalidRequirements()
- {
- return array(
- array(''),
- array(array()),
- array('^$'),
- array('^'),
- array('$')
- );
- }
-
- public function testHost()
- {
- $route = new Route('/');
- $route->setHost('{locale}.example.net');
- $this->assertEquals('{locale}.example.net', $route->getHost(), '->setHost() sets the host pattern');
- }
-
- public function testScheme()
- {
- $route = new Route('/');
- $this->assertEquals(array(), $route->getSchemes(), 'schemes is initialized with array()');
- $route->setSchemes('hTTp');
- $this->assertEquals(array('http'), $route->getSchemes(), '->setSchemes() accepts a single scheme string and lowercases it');
- $route->setSchemes(array('HttpS', 'hTTp'));
- $this->assertEquals(array('https', 'http'), $route->getSchemes(), '->setSchemes() accepts an array of schemes and lowercases them');
- }
-
- public function testSchemeIsBC()
- {
- $route = new Route('/');
- $route->setRequirement('_scheme', 'http|https');
- $this->assertEquals('http|https', $route->getRequirement('_scheme'));
- $this->assertEquals(array('http', 'https'), $route->getSchemes());
- $route->setSchemes(array('hTTp'));
- $this->assertEquals('http', $route->getRequirement('_scheme'));
- $route->setSchemes(array());
- $this->assertNull($route->getRequirement('_scheme'));
- }
-
- public function testMethod()
- {
- $route = new Route('/');
- $this->assertEquals(array(), $route->getMethods(), 'methods is initialized with array()');
- $route->setMethods('gEt');
- $this->assertEquals(array('GET'), $route->getMethods(), '->setMethods() accepts a single method string and uppercases it');
- $route->setMethods(array('gEt', 'PosT'));
- $this->assertEquals(array('GET', 'POST'), $route->getMethods(), '->setMethods() accepts an array of methods and uppercases them');
- }
-
- public function testMethodIsBC()
- {
- $route = new Route('/');
- $route->setRequirement('_method', 'GET|POST');
- $this->assertEquals('GET|POST', $route->getRequirement('_method'));
- $this->assertEquals(array('GET', 'POST'), $route->getMethods());
- $route->setMethods(array('gEt'));
- $this->assertEquals('GET', $route->getRequirement('_method'));
- $route->setMethods(array());
- $this->assertNull($route->getRequirement('_method'));
- }
-
- public function testCompile()
- {
- $route = new Route('/{foo}');
- $this->assertInstanceOf('Symfony\Component\Routing\CompiledRoute', $compiled = $route->compile(), '->compile() returns a compiled route');
- $this->assertSame($compiled, $route->compile(), '->compile() only compiled the route once if unchanged');
- $route->setRequirement('foo', '.*');
- $this->assertNotSame($compiled, $route->compile(), '->compile() recompiles if the route was modified');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Routing\Tests;
-
-use Symfony\Component\Routing\Router;
-
-class RouterTest extends \PHPUnit_Framework_TestCase
-{
- private $router = null;
-
- private $loader = null;
-
- protected function setUp()
- {
- $this->loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
- $this->router = new Router($this->loader, 'routing.yml');
- }
-
- public function testSetOptionsWithSupportedOptions()
- {
- $this->router->setOptions(array(
- 'cache_dir' => './cache',
- 'debug' => true,
- 'resource_type' => 'ResourceType'
- ));
-
- $this->assertSame('./cache', $this->router->getOption('cache_dir'));
- $this->assertTrue($this->router->getOption('debug'));
- $this->assertSame('ResourceType', $this->router->getOption('resource_type'));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage The Router does not support the following options: "option_foo", "option_bar"
- */
- public function testSetOptionsWithUnsupportedOptions()
- {
- $this->router->setOptions(array(
- 'cache_dir' => './cache',
- 'option_foo' => true,
- 'option_bar' => 'baz',
- 'resource_type' => 'ResourceType'
- ));
- }
-
- public function testSetOptionWithSupportedOption()
- {
- $this->router->setOption('cache_dir', './cache');
-
- $this->assertSame('./cache', $this->router->getOption('cache_dir'));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage The Router does not support the "option_foo" option
- */
- public function testSetOptionWithUnsupportedOption()
- {
- $this->router->setOption('option_foo', true);
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage The Router does not support the "option_foo" option
- */
- public function testGetOptionWithUnsupportedOption()
- {
- $this->router->getOption('option_foo', true);
- }
-
- public function testThatRouteCollectionIsLoaded()
- {
- $this->router->setOption('resource_type', 'ResourceType');
-
- $routeCollection = $this->getMock('Symfony\Component\Routing\RouteCollection');
-
- $this->loader->expects($this->once())
- ->method('load')->with('routing.yml', 'ResourceType')
- ->will($this->returnValue($routeCollection));
-
- $this->assertSame($routeCollection, $this->router->getRouteCollection());
- }
-
- /**
- * @dataProvider provideMatcherOptionsPreventingCaching
- */
- public function testMatcherIsCreatedIfCacheIsNotConfigured($option)
- {
- $this->router->setOption($option, null);
-
- $this->loader->expects($this->once())
- ->method('load')->with('routing.yml', null)
- ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RouteCollection')));
-
- $this->assertInstanceOf('Symfony\\Component\\Routing\\Matcher\\UrlMatcher', $this->router->getMatcher());
-
- }
-
- public function provideMatcherOptionsPreventingCaching()
- {
- return array(
- array('cache_dir'),
- array('matcher_cache_class')
- );
- }
-
- /**
- * @dataProvider provideGeneratorOptionsPreventingCaching
- */
- public function testGeneratorIsCreatedIfCacheIsNotConfigured($option)
- {
- $this->router->setOption($option, null);
-
- $this->loader->expects($this->once())
- ->method('load')->with('routing.yml', null)
- ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RouteCollection')));
-
- $this->assertInstanceOf('Symfony\\Component\\Routing\\Generator\\UrlGenerator', $this->router->getGenerator());
-
- }
-
- public function provideGeneratorOptionsPreventingCaching()
- {
- return array(
- array('cache_dir'),
- array('generator_cache_class')
- );
- }
-}
+++ /dev/null
-{
- "name": "symfony/routing",
- "type": "library",
- "description": "Symfony Routing Component",
- "keywords": [],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "symfony/config": "~2.2",
- "symfony/yaml": "~2.0",
- "doctrine/common": "~2.2",
- "psr/log": "~1.0"
- },
- "suggest": {
- "symfony/config": "",
- "symfony/yaml": "",
- "doctrine/common": ""
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\Routing\\": "" }
- },
- "target-dir": "Symfony/Component/Routing",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony Routing Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./vendor</directory>
- <directory>./Tests</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-CHANGELOG
-=========
-
-2.3.0
------
-
- * added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)
- * added Translator::getFallbackLocales()
- * deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method
-
-2.2.0
------
-
- * QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.
- * [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now
- throws Symfony\Component\Translation\Exception\NotFoundResourceException when a resource cannot be found
- and Symfony\Component\Translation\Exception\InvalidResourceException when a resource is invalid.
- * changed the exception class thrown by some load() methods from \RuntimeException to \InvalidArgumentException
- (IcuDatFileLoader, IcuResFileLoader and QtFileLoader)
-
-2.1.0
------
-
- * added support for more than one fallback locale
- * added support for extracting translation messages from templates (Twig and PHP)
- * added dumpers for translation catalogs
- * added support for QT, gettext, and ResourceBundles
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Catalogue;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\MessageCatalogueInterface;
-
-/**
- * Base catalogues binary operation class.
- *
- * @author Jean-François Simon <contact@jfsimon.fr>
- */
-abstract class AbstractOperation implements OperationInterface
-{
- /**
- * @var MessageCatalogueInterface
- */
- protected $source;
-
- /**
- * @var MessageCatalogueInterface
- */
- protected $target;
-
- /**
- * @var MessageCatalogue
- */
- protected $result;
-
- /**
- * @var null|array
- */
- private $domains;
-
- /**
- * @var array
- */
- protected $messages;
-
- /**
- * @param MessageCatalogueInterface $source
- * @param MessageCatalogueInterface $target
- *
- * @throws \LogicException
- */
- public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
- {
- if ($source->getLocale() !== $target->getLocale()) {
- throw new \LogicException('Operated catalogues must belong to the same locale.');
- }
-
- $this->source = $source;
- $this->target = $target;
- $this->result = new MessageCatalogue($source->getLocale());
- $this->domains = null;
- $this->messages = array();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDomains()
- {
- if (null === $this->domains) {
- $this->domains = array_values(array_unique(array_merge($this->source->getDomains(), $this->target->getDomains())));
- }
-
- return $this->domains;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getMessages($domain)
- {
- if (!in_array($domain, $this->getDomains())) {
- throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
- }
-
- if (!isset($this->messages[$domain]['all'])) {
- $this->processDomain($domain);
- }
-
- return $this->messages[$domain]['all'];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getNewMessages($domain)
- {
- if (!in_array($domain, $this->getDomains())) {
- throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
- }
-
- if (!isset($this->messages[$domain]['new'])) {
- $this->processDomain($domain);
- }
-
- return $this->messages[$domain]['new'];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getObsoleteMessages($domain)
- {
- if (!in_array($domain, $this->getDomains())) {
- throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
- }
-
- if (!isset($this->messages[$domain]['obsolete'])) {
- $this->processDomain($domain);
- }
-
- return $this->messages[$domain]['obsolete'];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getResult()
- {
- foreach ($this->getDomains() as $domain) {
- if (!isset($this->messages[$domain])) {
- $this->processDomain($domain);
- }
- }
-
- return $this->result;
- }
-
- /**
- * @param string $domain
- */
- abstract protected function processDomain($domain);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Catalogue;
-
-/**
- * Diff operation between two catalogues.
- *
- * @author Jean-François Simon <contact@jfsimon.fr>
- */
-class DiffOperation extends AbstractOperation
-{
- /**
- * {@inheritdoc}
- */
- protected function processDomain($domain)
- {
- $this->messages[$domain] = array(
- 'all' => array(),
- 'new' => array(),
- 'obsolete' => array(),
- );
-
- foreach ($this->source->all($domain) as $id => $message) {
- if ($this->target->has($id, $domain)) {
- $this->messages[$domain]['all'][$id] = $message;
- $this->result->add(array($id => $message), $domain);
- } else {
- $this->messages[$domain]['obsolete'][$id] = $message;
- }
- }
-
- foreach ($this->target->all($domain) as $id => $message) {
- if (!$this->source->has($id, $domain)) {
- $this->messages[$domain]['all'][$id] = $message;
- $this->messages[$domain]['new'][$id] = $message;
- $this->result->add(array($id => $message), $domain);
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Catalogue;
-
-/**
- * Merge operation between two catalogues.
- *
- * @author Jean-François Simon <contact@jfsimon.fr>
- */
-class MergeOperation extends AbstractOperation
-{
- /**
- * {@inheritdoc}
- */
- protected function processDomain($domain)
- {
- $this->messages[$domain] = array(
- 'all' => array(),
- 'new' => array(),
- 'obsolete' => array(),
- );
-
- foreach ($this->source->all($domain) as $id => $message) {
- $this->messages[$domain]['all'][$id] = $message;
- $this->result->add(array($id => $message), $domain);
- }
-
- foreach ($this->target->all($domain) as $id => $message) {
- if (!$this->source->has($id, $domain)) {
- $this->messages[$domain]['all'][$id] = $message;
- $this->messages[$domain]['new'][$id] = $message;
- $this->result->add(array($id => $message), $domain);
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Catalogue;
-
-use Symfony\Component\Translation\MessageCatalogueInterface;
-
-/**
- * Represents an operation on catalogue(s).
- *
- * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
- */
-interface OperationInterface
-{
- /**
- * Returns domains affected by operation.
- *
- * @return array
- */
- public function getDomains();
-
- /**
- * Returns all valid messages after operation.
- *
- * @param string $domain
- *
- * @return array
- */
- public function getMessages($domain);
-
- /**
- * Returns new messages after operation.
- *
- * @param string $domain
- *
- * @return array
- */
- public function getNewMessages($domain);
-
- /**
- * Returns obsolete messages after operation.
- *
- * @param string $domain
- *
- * @return array
- */
- public function getObsoleteMessages($domain);
-
- /**
- * Returns resulting catalogue.
- *
- * @return MessageCatalogueInterface
- */
- public function getResult();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * CsvFileDumper generates a csv formatted string representation of a message catalogue.
- *
- * @author Stealth35
- */
-class CsvFileDumper extends FileDumper
-{
- private $delimiter = ';';
- private $enclosure = '"';
-
- /**
- * {@inheritDoc}
- */
- public function format(MessageCatalogue $messages, $domain = 'messages')
- {
- $handle = fopen('php://memory', 'rb+');
-
- foreach ($messages->all($domain) as $source => $target) {
- fputcsv($handle, array($source, $target), $this->delimiter, $this->enclosure);
- }
-
- rewind($handle);
- $output = stream_get_contents($handle);
- fclose($handle);
-
- return $output;
- }
-
- /**
- * Sets the delimiter and escape character for CSV.
- *
- * @param string $delimiter delimiter character
- * @param string $enclosure enclosure character
- */
- public function setCsvControl($delimiter = ';', $enclosure = '"')
- {
- $this->delimiter = $delimiter;
- $this->enclosure = $enclosure;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'csv';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * DumperInterface is the interface implemented by all translation dumpers.
- * There is no common option.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-interface DumperInterface
-{
- /**
- * Dumps the message catalogue.
- *
- * @param MessageCatalogue $messages The message catalogue
- * @param array $options Options that are used by the dumper
- */
- public function dump(MessageCatalogue $messages, $options = array());
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s).
- * Performs backup of already existing files.
- *
- * Options:
- * - path (mandatory): the directory where the files should be saved
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-abstract class FileDumper implements DumperInterface
-{
- /**
- * {@inheritDoc}
- */
- public function dump(MessageCatalogue $messages, $options = array())
- {
- if (!array_key_exists('path', $options)) {
- throw new \InvalidArgumentException('The file dumper need a path options.');
- }
-
- // save a file for each domain
- foreach ($messages->getDomains() as $domain) {
- $file = $domain.'.'.$messages->getLocale().'.'.$this->getExtension();
- // backup
- $fullpath = $options['path'].'/'.$file;
- if (file_exists($fullpath)) {
- copy($fullpath, $fullpath.'~');
- }
- // save file
- file_put_contents($fullpath, $this->format($messages, $domain));
- }
- }
-
- /**
- * Transforms a domain of a message catalogue to its string representation.
- *
- * @param MessageCatalogue $messages
- * @param string $domain
- *
- * @return string representation
- */
- abstract protected function format(MessageCatalogue $messages, $domain);
-
- /**
- * Gets the file extension of the dumper.
- *
- * @return string file extension
- */
- abstract protected function getExtension();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.
- *
- * @author Stealth35
- */
-class IcuResFileDumper implements DumperInterface
-{
- /**
- * {@inheritDoc}
- */
- public function dump(MessageCatalogue $messages, $options = array())
- {
- if (!array_key_exists('path', $options)) {
- throw new \InvalidArgumentException('The file dumper need a path options.');
- }
-
- // save a file for each domain
- foreach ($messages->getDomains() as $domain) {
- $file = $messages->getLocale().'.'.$this->getExtension();
- $path = $options['path'].'/'.$domain.'/';
-
- if (!file_exists($path)) {
- mkdir($path);
- }
-
- // backup
- if (file_exists($path.$file)) {
- copy($path.$file, $path.$file.'~');
- }
-
- // save file
- file_put_contents($path.$file, $this->format($messages, $domain));
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function format(MessageCatalogue $messages, $domain = 'messages')
- {
- $data = $indexes = $resources = '';
-
- foreach ($messages->all($domain) as $source => $target) {
- $indexes .= pack('v', strlen($data) + 28);
- $data .= $source."\0";
- }
-
- $data .= $this->writePadding($data);
-
- $keyTop = $this->getPosition($data);
-
- foreach ($messages->all($domain) as $source => $target) {
- $resources .= pack('V', $this->getPosition($data));
-
- $data .= pack('V', strlen($target))
- .mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8')
- .$this->writePadding($data)
- ;
- }
-
- $resOffset = $this->getPosition($data);
-
- $data .= pack('v', count($messages))
- .$indexes
- .$this->writePadding($data)
- .$resources
- ;
-
- $bundleTop = $this->getPosition($data);
-
- $root = pack('V7',
- $resOffset + (2 << 28), // Resource Offset + Resource Type
- 6, // Index length
- $keyTop, // Index keys top
- $bundleTop, // Index resources top
- $bundleTop, // Index bundle top
- count($messages), // Index max table length
- 0 // Index attributes
- );
-
- $header = pack('vC2v4C12@32',
- 32, // Header size
- 0xDA, 0x27, // Magic number 1 and 2
- 20, 0, 0, 2, // Rest of the header, ..., Size of a char
- 0x52, 0x65, 0x73, 0x42, // Data format identifier
- 1, 2, 0, 0, // Data version
- 1, 4, 0, 0 // Unicode version
- );
-
- $output = $header
- .$root
- .$data;
-
- return $output;
- }
-
- private function writePadding($data)
- {
- $padding = strlen($data) % 4;
-
- if ($padding) {
- return str_repeat("\xAA", 4 - $padding);
- }
- }
-
- private function getPosition($data)
- {
- $position = (strlen($data) + 28) / 4;
-
- return $position;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'res';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * IniFileDumper generates an ini formatted string representation of a message catalogue.
- *
- * @author Stealth35
- */
-class IniFileDumper extends FileDumper
-{
- /**
- * {@inheritDoc}
- */
- public function format(MessageCatalogue $messages, $domain = 'messages')
- {
- $output = '';
-
- foreach ($messages->all($domain) as $source => $target) {
- $escapeTarget = str_replace('"', '\"', $target);
- $output .= $source.'="'.$escapeTarget."\"\n";
- }
-
- return $output;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'ini';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Loader\MoFileLoader;
-
-/**
- * MoFileDumper generates a gettext formatted string representation of a message catalogue.
- *
- * @author Stealth35
- */
-class MoFileDumper extends FileDumper
-{
- /**
- * {@inheritDoc}
- */
- public function format(MessageCatalogue $messages, $domain = 'messages')
- {
- $output = $sources = $targets = $sourceOffsets = $targetOffsets = '';
- $offsets = array();
- $size = 0;
-
- foreach ($messages->all($domain) as $source => $target) {
- $offsets[] = array_map('strlen', array($sources, $source, $targets, $target));
- $sources .= "\0".$source;
- $targets .= "\0".$target;
- ++$size;
- }
-
- $header = array(
- 'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC,
- 'formatRevision' => 0,
- 'count' => $size,
- 'offsetId' => MoFileLoader::MO_HEADER_SIZE,
- 'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size),
- 'sizeHashes' => 0,
- 'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size),
- );
-
- $sourcesSize = strlen($sources);
- $sourcesStart = $header['offsetHashes'] + 1;
-
- foreach ($offsets as $offset) {
- $sourceOffsets .= $this->writeLong($offset[1])
- .$this->writeLong($offset[0] + $sourcesStart);
- $targetOffsets .= $this->writeLong($offset[3])
- .$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);
- }
-
- $output = implode(array_map(array($this, 'writeLong'), $header))
- .$sourceOffsets
- .$targetOffsets
- .$sources
- .$targets
- ;
-
- return $output;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'mo';
- }
-
- private function writeLong($str)
- {
- return pack('V*', $str);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * PhpFileDumper generates php files from a message catalogue.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-class PhpFileDumper extends FileDumper
-{
- /**
- * {@inheritDoc}
- */
- protected function format(MessageCatalogue $messages, $domain)
- {
- $output = "<?php\n\nreturn ".var_export($messages->all($domain), true).";\n";
-
- return $output;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'php';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * PoFileDumper generates a gettext formatted string representation of a message catalogue.
- *
- * @author Stealth35
- */
-class PoFileDumper extends FileDumper
-{
- /**
- * {@inheritDoc}
- */
- public function format(MessageCatalogue $messages, $domain = 'messages')
- {
- $output = '';
- $newLine = false;
- foreach ($messages->all($domain) as $source => $target) {
- if ($newLine) {
- $output .= "\n";
- } else {
- $newLine = true;
- }
- $output .= sprintf('msgid "%s"'."\n", $this->escape($source));
- $output .= sprintf('msgstr "%s"', $this->escape($target));
- }
-
- return $output;
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'po';
- }
-
- private function escape($str)
- {
- return addcslashes($str, "\0..\37\42\134");
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * QtFileDumper generates ts files from a message catalogue.
- *
- * @author Benjamin Eberlei <kontakt@beberlei.de>
- */
-class QtFileDumper extends FileDumper
-{
- /**
- * {@inheritDoc}
- */
- public function format(MessageCatalogue $messages, $domain)
- {
- $dom = new \DOMDocument('1.0', 'utf-8');
- $dom->formatOutput = true;
- $ts = $dom->appendChild($dom->createElement('TS'));
- $context = $ts->appendChild($dom->createElement('context'));
- $context->appendChild($dom->createElement('name', $domain));
-
- foreach ($messages->all($domain) as $source => $target) {
- $message = $context->appendChild($dom->createElement('message'));
- $message->appendChild($dom->createElement('source', $source));
- $message->appendChild($dom->createElement('translation', $target));
- }
-
- return $dom->saveXML();
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'ts';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * XliffFileDumper generates xliff files from a message catalogue.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-class XliffFileDumper extends FileDumper
-{
- /**
- * {@inheritDoc}
- */
- protected function format(MessageCatalogue $messages, $domain)
- {
- $dom = new \DOMDocument('1.0', 'utf-8');
- $dom->formatOutput = true;
-
- $xliff = $dom->appendChild($dom->createElement('xliff'));
- $xliff->setAttribute('version', '1.2');
- $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');
-
- $xliffFile = $xliff->appendChild($dom->createElement('file'));
- $xliffFile->setAttribute('source-language', $messages->getLocale());
- $xliffFile->setAttribute('datatype', 'plaintext');
- $xliffFile->setAttribute('original', 'file.ext');
-
- $xliffBody = $xliffFile->appendChild($dom->createElement('body'));
- foreach ($messages->all($domain) as $source => $target) {
- $translation = $dom->createElement('trans-unit');
-
- $translation->setAttribute('id', md5($source));
- $translation->setAttribute('resname', $source);
-
- $s = $translation->appendChild($dom->createElement('source'));
- $s->appendChild($dom->createTextNode($source));
-
- $t = $translation->appendChild($dom->createElement('target'));
- $t->appendChild($dom->createTextNode($target));
-
- $xliffBody->appendChild($translation);
- }
-
- return $dom->saveXML();
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'xlf';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Yaml\Yaml;
-
-/**
- * YamlFileDumper generates yaml files from a message catalogue.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-class YamlFileDumper extends FileDumper
-{
- /**
- * {@inheritDoc}
- */
- protected function format(MessageCatalogue $messages, $domain)
- {
- return Yaml::dump($messages->all($domain));
- }
-
- /**
- * {@inheritDoc}
- */
- protected function getExtension()
- {
- return 'yml';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Exception;
-
-/**
- * Exception interface for all exceptions thrown by the component.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-interface ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Exception;
-
-/**
- * Thrown when a resource cannot be loaded.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class InvalidResourceException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Exception;
-
-/**
- * Thrown when a resource does not exist.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class NotFoundResourceException extends \InvalidArgumentException implements ExceptionInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Extractor;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * ChainExtractor extracts translation messages from template files.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-class ChainExtractor implements ExtractorInterface
-{
- /**
- * The extractors.
- *
- * @var ExtractorInterface[]
- */
- private $extractors = array();
-
- /**
- * Adds a loader to the translation extractor.
- *
- * @param string $format The format of the loader
- * @param ExtractorInterface $extractor The loader
- */
- public function addExtractor($format, ExtractorInterface $extractor)
- {
- $this->extractors[$format] = $extractor;
- }
-
- /**
- * {@inheritDoc}
- */
- public function setPrefix($prefix)
- {
- foreach ($this->extractors as $extractor) {
- $extractor->setPrefix($prefix);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function extract($directory, MessageCatalogue $catalogue)
- {
- foreach ($this->extractors as $extractor) {
- $extractor->extract($directory, $catalogue);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Extractor;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * Extracts translation messages from a template directory to the catalogue.
- * New found messages are injected to the catalogue using the prefix.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-interface ExtractorInterface
-{
- /**
- * Extracts translation messages from a template directory to the catalogue.
- *
- * @param string $directory The path to look into
- * @param MessageCatalogue $catalogue The catalogue
- */
- public function extract($directory, MessageCatalogue $catalogue);
-
- /**
- * Sets the prefix that should be used for new found messages.
- *
- * @param string $prefix The prefix
- */
- public function setPrefix($prefix);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-/**
- * IdentityTranslator does not translate anything.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class IdentityTranslator implements TranslatorInterface
-{
- private $selector;
-
- /**
- * Constructor.
- *
- * @param MessageSelector $selector The message selector for pluralization
- *
- * @api
- */
- public function __construct(MessageSelector $selector)
- {
- $this->selector = $selector;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function setLocale($locale)
- {
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function getLocale()
- {
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function trans($id, array $parameters = array(), $domain = 'messages', $locale = null)
- {
- return strtr((string) $id, $parameters);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function transChoice($id, $number, array $parameters = array(), $domain = 'messages', $locale = null)
- {
- return strtr($this->selector->choose((string) $id, (int) $number, $locale), $parameters);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-/**
- * Tests if a given number belongs to a given math interval.
- *
- * An interval can represent a finite set of numbers:
- *
- * {1,2,3,4}
- *
- * An interval can represent numbers between two numbers:
- *
- * [1, +Inf]
- * ]-1,2[
- *
- * The left delimiter can be [ (inclusive) or ] (exclusive).
- * The right delimiter can be [ (exclusive) or ] (inclusive).
- * Beside numbers, you can use -Inf and +Inf for the infinite.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
- */
-class Interval
-{
- /**
- * Tests if the given number is in the math interval.
- *
- * @param integer $number A number
- * @param string $interval An interval
- *
- * @return Boolean
- *
- * @throws \InvalidArgumentException
- */
- public static function test($number, $interval)
- {
- $interval = trim($interval);
-
- if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
- throw new \InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
- }
-
- if ($matches[1]) {
- foreach (explode(',', $matches[2]) as $n) {
- if ($number == $n) {
- return true;
- }
- }
- } else {
- $leftNumber = self::convertNumber($matches['left']);
- $rightNumber = self::convertNumber($matches['right']);
-
- return
- ('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
- && (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
- ;
- }
-
- return false;
- }
-
- /**
- * Returns a Regexp that matches valid intervals.
- *
- * @return string A Regexp (without the delimiters)
- */
- public static function getIntervalRegexp()
- {
- return <<<EOF
- ({\s*
- (\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
- \s*})
-
- |
-
- (?P<left_delimiter>[\[\]])
- \s*
- (?P<left>-Inf|\-?\d+(\.\d+)?)
- \s*,\s*
- (?P<right>\+?Inf|\-?\d+(\.\d+)?)
- \s*
- (?P<right_delimiter>[\[\]])
-EOF;
- }
-
- private static function convertNumber($number)
- {
- if ('-Inf' === $number) {
- return log(0);
- } elseif ('+Inf' === $number || 'Inf' === $number) {
- return -log(0);
- }
-
- return (float) $number;
- }
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * ArrayLoader loads translations from a PHP array.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class ArrayLoader implements LoaderInterface
-{
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- $this->flatten($resource);
- $catalogue = new MessageCatalogue($locale);
- $catalogue->add($resource, $domain);
-
- return $catalogue;
- }
-
- /**
- * Flattens an nested array of translations
- *
- * The scheme used is:
- * 'key' => array('key2' => array('key3' => 'value'))
- * Becomes:
- * 'key.key2.key3' => 'value'
- *
- * This function takes an array by reference and will modify it
- *
- * @param array &$messages The array that will be flattened
- * @param array $subnode Current subnode being parsed, used internally for recursive calls
- * @param string $path Current path being parsed, used internally for recursive calls
- */
- private function flatten(array &$messages, array $subnode = null, $path = null)
- {
- if (null === $subnode) {
- $subnode =& $messages;
- }
- foreach ($subnode as $key => $value) {
- if (is_array($value)) {
- $nodePath = $path ? $path.'.'.$key : $key;
- $this->flatten($messages, $value, $nodePath);
- if (null === $path) {
- unset($messages[$key]);
- }
- } elseif (null !== $path) {
- $messages[$path.'.'.$key] = $value;
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * CsvFileLoader loads translations from CSV files.
- *
- * @author Saša Stamenković <umpirsky@gmail.com>
- *
- * @api
- */
-class CsvFileLoader extends ArrayLoader implements LoaderInterface
-{
- private $delimiter = ';';
- private $enclosure = '"';
- private $escape = '\\';
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $messages = array();
-
- try {
- $file = new \SplFileObject($resource, 'rb');
- } catch (\RuntimeException $e) {
- throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e);
- }
-
- $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
- $file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
-
- foreach ($file as $data) {
- if (substr($data[0], 0, 1) === '#') {
- continue;
- }
-
- if (!isset($data[1])) {
- continue;
- }
-
- if (count($data) == 2) {
- $messages[$data[0]] = $data[1];
- } else {
- continue;
- }
- }
-
- $catalogue = parent::load($messages, $locale, $domain);
- $catalogue->addResource(new FileResource($resource));
-
- return $catalogue;
- }
-
- /**
- * Sets the delimiter, enclosure, and escape character for CSV.
- *
- * @param string $delimiter delimiter character
- * @param string $enclosure enclosure character
- * @param string $escape escape character
- */
- public function setCsvControl($delimiter = ';', $enclosure = '"', $escape = '\\')
- {
- $this->delimiter = $delimiter;
- $this->enclosure = $enclosure;
- $this->escape = $escape;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * IcuResFileLoader loads translations from a resource bundle.
- *
- * @author stealth35
- */
-class IcuDatFileLoader extends IcuResFileLoader
-{
- /**
- * {@inheritdoc}
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource.'.dat')) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource.'.dat')) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $rb = new \ResourceBundle($locale, $resource);
-
- if (!$rb) {
- throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
- } elseif (intl_is_failure($rb->getErrorCode())) {
- throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
- }
-
- $messages = $this->flatten($rb);
- $catalogue = new MessageCatalogue($locale);
- $catalogue->add($messages, $domain);
- $catalogue->addResource(new FileResource($resource.'.dat'));
-
- return $catalogue;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\DirectoryResource;
-
-/**
- * IcuResFileLoader loads translations from a resource bundle.
- *
- * @author stealth35
- */
-class IcuResFileLoader implements LoaderInterface
-{
- /**
- * {@inheritdoc}
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!is_dir($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $rb = new \ResourceBundle($locale, $resource);
-
- if (!$rb) {
- throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
- } elseif (intl_is_failure($rb->getErrorCode())) {
- throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
- }
-
- $messages = $this->flatten($rb);
- $catalogue = new MessageCatalogue($locale);
- $catalogue->add($messages, $domain);
- $catalogue->addResource(new DirectoryResource($resource));
-
- return $catalogue;
- }
-
- /**
- * Flattens an ResourceBundle
- *
- * The scheme used is:
- * key { key2 { key3 { "value" } } }
- * Becomes:
- * 'key.key2.key3' => 'value'
- *
- * This function takes an array by reference and will modify it
- *
- * @param \ResourceBundle $rb the ResourceBundle that will be flattened
- * @param array $messages used internally for recursive calls
- * @param string $path current path being parsed, used internally for recursive calls
- *
- * @return array the flattened ResourceBundle
- */
- protected function flatten(\ResourceBundle $rb, array &$messages = array(), $path = null)
- {
- foreach ($rb as $key => $value) {
- $nodePath = $path ? $path.'.'.$key : $key;
- if ($value instanceof \ResourceBundle) {
- $this->flatten($value, $messages, $nodePath);
- } else {
- $messages[$nodePath] = $value;
- }
- }
-
- return $messages;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * IniFileLoader loads translations from an ini file.
- *
- * @author stealth35
- */
-class IniFileLoader extends ArrayLoader implements LoaderInterface
-{
- /**
- * {@inheritdoc}
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $messages = parse_ini_file($resource, true);
-
- $catalogue = parent::load($messages, $locale, $domain);
- $catalogue->addResource(new FileResource($resource));
-
- return $catalogue;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-
-/**
- * LoaderInterface is the interface implemented by all translation loaders.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-interface LoaderInterface
-{
- /**
- * Loads a locale.
- *
- * @param mixed $resource A resource
- * @param string $locale A locale
- * @param string $domain The domain
- *
- * @return MessageCatalogue A MessageCatalogue instance
- *
- * @api
- *
- * @throws NotFoundResourceException when the resource cannot be found
- * @throws InvalidResourceException when the resource cannot be loaded
- */
- public function load($resource, $locale, $domain = 'messages');
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
- */
-class MoFileLoader extends ArrayLoader implements LoaderInterface
-{
- /**
- * Magic used for validating the format of a MO file as well as
- * detecting if the machine used to create that file was little endian.
- *
- * @var float
- */
- const MO_LITTLE_ENDIAN_MAGIC = 0x950412de;
-
- /**
- * Magic used for validating the format of a MO file as well as
- * detecting if the machine used to create that file was big endian.
- *
- * @var float
- */
- const MO_BIG_ENDIAN_MAGIC = 0xde120495;
-
- /**
- * The size of the header of a MO file in bytes.
- *
- * @var integer Number of bytes.
- */
- const MO_HEADER_SIZE = 28;
-
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $messages = $this->parse($resource);
-
- // empty file
- if (null === $messages) {
- $messages = array();
- }
-
- // not an array
- if (!is_array($messages)) {
- throw new InvalidResourceException(sprintf('The file "%s" must contain a valid mo file.', $resource));
- }
-
- $catalogue = parent::load($messages, $locale, $domain);
- $catalogue->addResource(new FileResource($resource));
-
- return $catalogue;
- }
-
- /**
- * Parses machine object (MO) format, independent of the machine's endian it
- * was created on. Both 32bit and 64bit systems are supported.
- *
- * @param resource $resource
- *
- * @return array
- * @throws InvalidResourceException If stream content has an invalid format.
- */
- private function parse($resource)
- {
- $stream = fopen($resource, 'r');
-
- $stat = fstat($stream);
-
- if ($stat['size'] < self::MO_HEADER_SIZE) {
- throw new InvalidResourceException("MO stream content has an invalid format.");
- }
- $magic = unpack('V1', fread($stream, 4));
- $magic = hexdec(substr(dechex(current($magic)), -8));
-
- if ($magic == self::MO_LITTLE_ENDIAN_MAGIC) {
- $isBigEndian = false;
- } elseif ($magic == self::MO_BIG_ENDIAN_MAGIC) {
- $isBigEndian = true;
- } else {
- throw new InvalidResourceException("MO stream content has an invalid format.");
- }
-
- $formatRevision = $this->readLong($stream, $isBigEndian);
- $count = $this->readLong($stream, $isBigEndian);
- $offsetId = $this->readLong($stream, $isBigEndian);
- $offsetTranslated = $this->readLong($stream, $isBigEndian);
- $sizeHashes = $this->readLong($stream, $isBigEndian);
- $offsetHashes = $this->readLong($stream, $isBigEndian);
-
- $messages = array();
-
- for ($i = 0; $i < $count; $i++) {
- $singularId = $pluralId = null;
- $translated = null;
-
- fseek($stream, $offsetId + $i * 8);
-
- $length = $this->readLong($stream, $isBigEndian);
- $offset = $this->readLong($stream, $isBigEndian);
-
- if ($length < 1) {
- continue;
- }
-
- fseek($stream, $offset);
- $singularId = fread($stream, $length);
-
- if (strpos($singularId, "\000") !== false) {
- list($singularId, $pluralId) = explode("\000", $singularId);
- }
-
- fseek($stream, $offsetTranslated + $i * 8);
- $length = $this->readLong($stream, $isBigEndian);
- $offset = $this->readLong($stream, $isBigEndian);
-
- fseek($stream, $offset);
- $translated = fread($stream, $length);
-
- if (strpos($translated, "\000") !== false) {
- $translated = explode("\000", $translated);
- }
-
- $ids = array('singular' => $singularId, 'plural' => $pluralId);
- $item = compact('ids', 'translated');
-
- if (is_array($item['translated'])) {
- $messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
- if (isset($item['ids']['plural'])) {
- $plurals = array();
- foreach ($item['translated'] as $plural => $translated) {
- $plurals[] = sprintf('{%d} %s', $plural, $translated);
- }
- $messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
- }
- } elseif (!empty($item['ids']['singular'])) {
- $messages[$item['ids']['singular']] = stripcslashes($item['translated']);
- }
- }
-
- fclose($stream);
-
- return array_filter($messages);
- }
-
- /**
- * Reads an unsigned long from stream respecting endianess.
- *
- * @param resource $stream
- * @param boolean $isBigEndian
- * @return integer
- */
- private function readLong($stream, $isBigEndian)
- {
- $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
- $result = current($result);
-
- return (integer) substr($result, -8);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * PhpFileLoader loads translations from PHP files returning an array of translations.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class PhpFileLoader extends ArrayLoader implements LoaderInterface
-{
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $messages = require($resource);
-
- $catalogue = parent::load($messages, $locale, $domain);
- $catalogue->addResource(new FileResource($resource));
-
- return $catalogue;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
- * @copyright Copyright (c) 2012, Clemens Tolboom
- */
-class PoFileLoader extends ArrayLoader implements LoaderInterface
-{
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $messages = $this->parse($resource);
-
- // empty file
- if (null === $messages) {
- $messages = array();
- }
-
- // not an array
- if (!is_array($messages)) {
- throw new InvalidResourceException(sprintf('The file "%s" must contain a valid po file.', $resource));
- }
-
- $catalogue = parent::load($messages, $locale, $domain);
- $catalogue->addResource(new FileResource($resource));
-
- return $catalogue;
- }
-
- /**
- * Parses portable object (PO) format.
- *
- * From http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
- * we should be able to parse files having:
- *
- * white-space
- * # translator-comments
- * #. extracted-comments
- * #: reference...
- * #, flag...
- * #| msgid previous-untranslated-string
- * msgid untranslated-string
- * msgstr translated-string
- *
- * extra or different lines are:
- *
- * #| msgctxt previous-context
- * #| msgid previous-untranslated-string
- * msgctxt context
- *
- * #| msgid previous-untranslated-string-singular
- * #| msgid_plural previous-untranslated-string-plural
- * msgid untranslated-string-singular
- * msgid_plural untranslated-string-plural
- * msgstr[0] translated-string-case-0
- * ...
- * msgstr[N] translated-string-case-n
- *
- * The definition states:
- * - white-space and comments are optional.
- * - msgid "" that an empty singleline defines a header.
- *
- * This parser sacrifices some features of the reference implementation the
- * differences to that implementation are as follows.
- * - No support for comments spanning multiple lines.
- * - Translator and extracted comments are treated as being the same type.
- * - Message IDs are allowed to have other encodings as just US-ASCII.
- *
- * Items with an empty id are ignored.
- *
- * @param resource $resource
- *
- * @return array
- */
- private function parse($resource)
- {
- $stream = fopen($resource, 'r');
-
- $defaults = array(
- 'ids' => array(),
- 'translated' => null,
- );
-
- $messages = array();
- $item = $defaults;
-
- while ($line = fgets($stream)) {
- $line = trim($line);
-
- if ($line === '') {
- // Whitespace indicated current item is done
- $this->addMessage($messages, $item);
- $item = $defaults;
- } elseif (substr($line, 0, 7) === 'msgid "') {
- // We start a new msg so save previous
- // TODO: this fails when comments or contexts are added
- $this->addMessage($messages, $item);
- $item = $defaults;
- $item['ids']['singular'] = substr($line, 7, -1);
- } elseif (substr($line, 0, 8) === 'msgstr "') {
- $item['translated'] = substr($line, 8, -1);
- } elseif ($line[0] === '"') {
- $continues = isset($item['translated']) ? 'translated' : 'ids';
-
- if (is_array($item[$continues])) {
- end($item[$continues]);
- $item[$continues][key($item[$continues])] .= substr($line, 1, -1);
- } else {
- $item[$continues] .= substr($line, 1, -1);
- }
- } elseif (substr($line, 0, 14) === 'msgid_plural "') {
- $item['ids']['plural'] = substr($line, 14, -1);
- } elseif (substr($line, 0, 7) === 'msgstr[') {
- $size = strpos($line, ']');
- $item['translated'][(integer) substr($line, 7, 1)] = substr($line, $size + 3, -1);
- }
-
- }
- // save last item
- $this->addMessage($messages, $item);
- fclose($stream);
-
- return $messages;
- }
-
- /**
- * Save a translation item to the messeages.
- *
- * A .po file could contain by error missing plural indexes. We need to
- * fix these before saving them.
- *
- * @param array $messages
- * @param array $item
- */
- private function addMessage(array &$messages, array $item)
- {
- if (is_array($item['translated'])) {
- $messages[$item['ids']['singular']] = stripslashes($item['translated'][0]);
- if (isset($item['ids']['plural'])) {
- $plurals = $item['translated'];
- // PO are by definition indexed so sort by index.
- ksort($plurals);
- // Make sure every index is filled.
- end($plurals);
- $count = key($plurals);
- // Fill missing spots with '-'.
- $empties = array_fill(0, $count+1, '-');
- $plurals += $empties;
- ksort($plurals);
- $messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
- }
- } elseif (!empty($item['ids']['singular'])) {
- $messages[$item['ids']['singular']] = stripslashes($item['translated']);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * QtFileLoader loads translations from QT Translations XML files.
- *
- * @author Benjamin Eberlei <kontakt@beberlei.de>
- *
- * @api
- */
-class QtFileLoader implements LoaderInterface
-{
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- $dom = new \DOMDocument();
- $current = libxml_use_internal_errors(true);
- if (!@$dom->load($resource, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) {
- throw new InvalidResourceException(implode("\n", $this->getXmlErrors()));
- }
-
- $xpath = new \DOMXPath($dom);
- $nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]');
-
- $catalogue = new MessageCatalogue($locale);
- if ($nodes->length == 1) {
- $translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');
- foreach ($translations as $translation) {
- $catalogue->set(
- (string) $translation->getElementsByTagName('source')->item(0)->nodeValue,
- (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue,
- $domain
- );
- $translation = $translation->nextSibling;
- }
- $catalogue->addResource(new FileResource($resource));
- }
-
- libxml_use_internal_errors($current);
-
- return $catalogue;
- }
-
- /**
- * Returns the XML errors of the internal XML parser
- *
- * @return array An array of errors
- */
- private function getXmlErrors()
- {
- $errors = array();
- foreach (libxml_get_errors() as $error) {
- $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
- LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
- $error->code,
- trim($error->message),
- $error->file ? $error->file : 'n/a',
- $error->line,
- $error->column
- );
- }
-
- libxml_clear_errors();
- libxml_use_internal_errors(false);
-
- return $errors;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-
-/**
- * XliffFileLoader loads translations from XLIFF files.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class XliffFileLoader implements LoaderInterface
-{
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- list($xml, $encoding) = $this->parseFile($resource);
- $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
-
- $catalogue = new MessageCatalogue($locale);
- foreach ($xml->xpath('//xliff:trans-unit') as $translation) {
- $attributes = $translation->attributes();
-
- if (!(isset($attributes['resname']) || isset($translation->source)) || !isset($translation->target)) {
- continue;
- }
-
- $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
- $target = (string) $translation->target;
-
- // If the xlf file has another encoding specified, try to convert it because
- // simple_xml will always return utf-8 encoded values
- if ('UTF-8' !== $encoding && !empty($encoding)) {
- if (function_exists('mb_convert_encoding')) {
- $target = mb_convert_encoding($target, $encoding, 'UTF-8');
- } elseif (function_exists('iconv')) {
- $target = iconv('UTF-8', $encoding, $target);
- } else {
- throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
- }
- }
-
- $catalogue->set((string) $source, $target, $domain);
- }
- $catalogue->addResource(new FileResource($resource));
-
- return $catalogue;
- }
-
- /**
- * Validates and parses the given file into a SimpleXMLElement
- *
- * @param string $file
- *
- * @throws \RuntimeException
- *
- * @return \SimpleXMLElement
- *
- * @throws InvalidResourceException
- */
- private function parseFile($file)
- {
- $internalErrors = libxml_use_internal_errors(true);
- $disableEntities = libxml_disable_entity_loader(true);
- libxml_clear_errors();
-
- $dom = new \DOMDocument();
- $dom->validateOnParse = true;
- if (!@$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
- libxml_disable_entity_loader($disableEntities);
-
- throw new InvalidResourceException(implode("\n", $this->getXmlErrors($internalErrors)));
- }
-
- libxml_disable_entity_loader($disableEntities);
-
- foreach ($dom->childNodes as $child) {
- if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
- libxml_use_internal_errors($internalErrors);
-
- throw new InvalidResourceException('Document types are not allowed.');
- }
- }
-
- $location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
- $parts = explode('/', $location);
- if (0 === stripos($location, 'phar://')) {
- $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
- if ($tmpfile) {
- copy($location, $tmpfile);
- $parts = explode('/', str_replace('\\', '/', $tmpfile));
- }
- }
- $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
- $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
-
- $source = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
- $source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
-
- if (!@$dom->schemaValidateSource($source)) {
- throw new InvalidResourceException(implode("\n", $this->getXmlErrors($internalErrors)));
- }
-
- $dom->normalizeDocument();
-
- libxml_use_internal_errors($internalErrors);
-
- return array(simplexml_import_dom($dom), strtoupper($dom->encoding));
- }
-
- /**
- * Returns the XML errors of the internal XML parser
- *
- * @param Boolean $internalErrors
- *
- * @return array An array of errors
- */
- private function getXmlErrors($internalErrors)
- {
- $errors = array();
- foreach (libxml_get_errors() as $error) {
- $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
- LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
- $error->code,
- trim($error->message),
- $error->file ? $error->file : 'n/a',
- $error->line,
- $error->column
- );
- }
-
- libxml_clear_errors();
- libxml_use_internal_errors($internalErrors);
-
- return $errors;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Loader;
-
-use Symfony\Component\Translation\Exception\InvalidResourceException;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-use Symfony\Component\Config\Resource\FileResource;
-use Symfony\Component\Yaml\Parser as YamlParser;
-use Symfony\Component\Yaml\Exception\ParseException;
-
-/**
- * YamlFileLoader loads translations from Yaml files.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class YamlFileLoader extends ArrayLoader implements LoaderInterface
-{
- private $yamlParser;
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function load($resource, $locale, $domain = 'messages')
- {
- if (!stream_is_local($resource)) {
- throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
- }
-
- if (!file_exists($resource)) {
- throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
- }
-
- if (null === $this->yamlParser) {
- $this->yamlParser = new YamlParser();
- }
-
- try {
- $messages = $this->yamlParser->parse(file_get_contents($resource));
- } catch (ParseException $e) {
- throw new InvalidResourceException('Error parsing YAML.', 0, $e);
- }
-
- // empty file
- if (null === $messages) {
- $messages = array();
- }
-
- // not an array
- if (!is_array($messages)) {
- throw new InvalidResourceException(sprintf('The file "%s" must contain a YAML array.', $resource));
- }
-
- $catalogue = parent::load($messages, $locale, $domain);
- $catalogue->addResource(new FileResource($resource));
-
- return $catalogue;
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-
-May-19-2004:
-- Changed the <choice> for ElemType_header, moving minOccurs="0" maxOccurs="unbounded" from its elements
-to <choice> itself.
-- Added <choice> for ElemType_trans-unit to allow "any order" for <context-group>, <count-group>, <prop-group>, <note>, and
-<alt-trans>.
-
-Oct-2005
-- updated version info to 1.2
-- equiv-trans attribute to <trans-unit> element
-- merged-trans attribute for <group> element
-- Add the <seg-source> element as optional in the <trans-unit> and <alt-trans> content models, at the same level as <source>
-- Create a new value "seg" for the mtype attribute of the <mrk> element
-- Add mid as an optional attribute for the <alt-trans> element
-
-Nov-14-2005
-- Changed name attribute for <context-group> from required to optional
-- Added extension point at <xliff>
-
-Jan-9-2006
-- Added alttranstype type attribute to <alt-trans>, and values
-
-Jan-10-2006
-- Corrected error with overwritten purposeValueList
-- Corrected name="AttrType_Version", attribute should have been "name"
-
--->
-<xsd:schema xmlns:xlf="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:oasis:names:tc:xliff:document:1.2" xml:lang="en">
- <!-- Import for xml:lang and xml:space -->
- <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
- <!-- Attributes Lists -->
- <xsd:simpleType name="XTend">
- <xsd:restriction base="xsd:string">
- <xsd:pattern value="x-[^\s]+"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="context-typeValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'context-type'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="database">
- <xsd:annotation>
- <xsd:documentation>Indicates a database content.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="element">
- <xsd:annotation>
- <xsd:documentation>Indicates the content of an element within an XML document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="elementtitle">
- <xsd:annotation>
- <xsd:documentation>Indicates the name of an element within an XML document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="linenumber">
- <xsd:annotation>
- <xsd:documentation>Indicates the line number from the sourcefile (see context-type="sourcefile") where the <source> is found.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="numparams">
- <xsd:annotation>
- <xsd:documentation>Indicates a the number of parameters contained within the <source>.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="paramnotes">
- <xsd:annotation>
- <xsd:documentation>Indicates notes pertaining to the parameters in the <source>.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="record">
- <xsd:annotation>
- <xsd:documentation>Indicates the content of a record within a database.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="recordtitle">
- <xsd:annotation>
- <xsd:documentation>Indicates the name of a record within a database.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="sourcefile">
- <xsd:annotation>
- <xsd:documentation>Indicates the original source file in the case that multiple files are merged to form the original file from which the XLIFF file is created. This differs from the original <file> attribute in that this sourcefile is one of many that make up that file.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="count-typeValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'count-type'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="num-usages">
- <xsd:annotation>
- <xsd:documentation>Indicates the count units are items that are used X times in a certain context; example: this is a reusable text unit which is used 42 times in other texts.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="repetition">
- <xsd:annotation>
- <xsd:documentation>Indicates the count units are translation units existing already in the same document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="total">
- <xsd:annotation>
- <xsd:documentation>Indicates a total count.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="InlineDelimitersValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'ctype' when used other elements than <ph> or <x>.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="bold">
- <xsd:annotation>
- <xsd:documentation>Indicates a run of bolded text.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="italic">
- <xsd:annotation>
- <xsd:documentation>Indicates a run of text in italics.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="underlined">
- <xsd:annotation>
- <xsd:documentation>Indicates a run of underlined text.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="link">
- <xsd:annotation>
- <xsd:documentation>Indicates a run of hyper-text.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="InlinePlaceholdersValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'ctype' when used with <ph> or <x>.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="image">
- <xsd:annotation>
- <xsd:documentation>Indicates a inline image.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="pb">
- <xsd:annotation>
- <xsd:documentation>Indicates a page break.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="lb">
- <xsd:annotation>
- <xsd:documentation>Indicates a line break.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="mime-typeValueList">
- <xsd:restriction base="xsd:string">
- <xsd:pattern value="(text|multipart|message|application|image|audio|video|model)(/.+)*"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="datatypeValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'datatype'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="asp">
- <xsd:annotation>
- <xsd:documentation>Indicates Active Server Page data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="c">
- <xsd:annotation>
- <xsd:documentation>Indicates C source file data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="cdf">
- <xsd:annotation>
- <xsd:documentation>Indicates Channel Definition Format (CDF) data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="cfm">
- <xsd:annotation>
- <xsd:documentation>Indicates ColdFusion data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="cpp">
- <xsd:annotation>
- <xsd:documentation>Indicates C++ source file data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="csharp">
- <xsd:annotation>
- <xsd:documentation>Indicates C-Sharp data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="cstring">
- <xsd:annotation>
- <xsd:documentation>Indicates strings from C, ASM, and driver files data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="csv">
- <xsd:annotation>
- <xsd:documentation>Indicates comma-separated values data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="database">
- <xsd:annotation>
- <xsd:documentation>Indicates database data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="documentfooter">
- <xsd:annotation>
- <xsd:documentation>Indicates portions of document that follows data and contains metadata.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="documentheader">
- <xsd:annotation>
- <xsd:documentation>Indicates portions of document that precedes data and contains metadata.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="filedialog">
- <xsd:annotation>
- <xsd:documentation>Indicates data from standard UI file operations dialogs (e.g., Open, Save, Save As, Export, Import).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="form">
- <xsd:annotation>
- <xsd:documentation>Indicates standard user input screen data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="html">
- <xsd:annotation>
- <xsd:documentation>Indicates HyperText Markup Language (HTML) data - document instance.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="htmlbody">
- <xsd:annotation>
- <xsd:documentation>Indicates content within an HTML document’s <body> element.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="ini">
- <xsd:annotation>
- <xsd:documentation>Indicates Windows INI file data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="interleaf">
- <xsd:annotation>
- <xsd:documentation>Indicates Interleaf data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="javaclass">
- <xsd:annotation>
- <xsd:documentation>Indicates Java source file data (extension '.java').</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="javapropertyresourcebundle">
- <xsd:annotation>
- <xsd:documentation>Indicates Java property resource bundle data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="javalistresourcebundle">
- <xsd:annotation>
- <xsd:documentation>Indicates Java list resource bundle data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="javascript">
- <xsd:annotation>
- <xsd:documentation>Indicates JavaScript source file data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="jscript">
- <xsd:annotation>
- <xsd:documentation>Indicates JScript source file data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="layout">
- <xsd:annotation>
- <xsd:documentation>Indicates information relating to formatting.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="lisp">
- <xsd:annotation>
- <xsd:documentation>Indicates LISP source file data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="margin">
- <xsd:annotation>
- <xsd:documentation>Indicates information relating to margin formats.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="menufile">
- <xsd:annotation>
- <xsd:documentation>Indicates a file containing menu.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="messagefile">
- <xsd:annotation>
- <xsd:documentation>Indicates numerically identified string table.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="mif">
- <xsd:annotation>
- <xsd:documentation>Indicates Maker Interchange Format (MIF) data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="mimetype">
- <xsd:annotation>
- <xsd:documentation>Indicates that the datatype attribute value is a MIME Type value and is defined in the mime-type attribute.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="mo">
- <xsd:annotation>
- <xsd:documentation>Indicates GNU Machine Object data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="msglib">
- <xsd:annotation>
- <xsd:documentation>Indicates Message Librarian strings created by Novell's Message Librarian Tool.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="pagefooter">
- <xsd:annotation>
- <xsd:documentation>Indicates information to be displayed at the bottom of each page of a document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="pageheader">
- <xsd:annotation>
- <xsd:documentation>Indicates information to be displayed at the top of each page of a document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="parameters">
- <xsd:annotation>
- <xsd:documentation>Indicates a list of property values (e.g., settings within INI files or preferences dialog).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="pascal">
- <xsd:annotation>
- <xsd:documentation>Indicates Pascal source file data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="php">
- <xsd:annotation>
- <xsd:documentation>Indicates Hypertext Preprocessor data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="plaintext">
- <xsd:annotation>
- <xsd:documentation>Indicates plain text file (no formatting other than, possibly, wrapping).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="po">
- <xsd:annotation>
- <xsd:documentation>Indicates GNU Portable Object file.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="report">
- <xsd:annotation>
- <xsd:documentation>Indicates dynamically generated user defined document. e.g. Oracle Report, Crystal Report, etc.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="resources">
- <xsd:annotation>
- <xsd:documentation>Indicates Windows .NET binary resources.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="resx">
- <xsd:annotation>
- <xsd:documentation>Indicates Windows .NET Resources.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rtf">
- <xsd:annotation>
- <xsd:documentation>Indicates Rich Text Format (RTF) data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="sgml">
- <xsd:annotation>
- <xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - document instance.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="sgmldtd">
- <xsd:annotation>
- <xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - Document Type Definition (DTD).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="svg">
- <xsd:annotation>
- <xsd:documentation>Indicates Scalable Vector Graphic (SVG) data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="vbscript">
- <xsd:annotation>
- <xsd:documentation>Indicates VisualBasic Script source file.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="warning">
- <xsd:annotation>
- <xsd:documentation>Indicates warning message.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="winres">
- <xsd:annotation>
- <xsd:documentation>Indicates Windows (Win32) resources (i.e. resources extracted from an RC script, a message file, or a compiled file).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="xhtml">
- <xsd:annotation>
- <xsd:documentation>Indicates Extensible HyperText Markup Language (XHTML) data - document instance.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="xml">
- <xsd:annotation>
- <xsd:documentation>Indicates Extensible Markup Language (XML) data - document instance.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="xmldtd">
- <xsd:annotation>
- <xsd:documentation>Indicates Extensible Markup Language (XML) data - Document Type Definition (DTD).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="xsl">
- <xsd:annotation>
- <xsd:documentation>Indicates Extensible Stylesheet Language (XSL) data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="xul">
- <xsd:annotation>
- <xsd:documentation>Indicates XUL elements.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="mtypeValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'mtype'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="abbrev">
- <xsd:annotation>
- <xsd:documentation>Indicates the marked text is an abbreviation.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="abbreviated-form">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.8: A term resulting from the omission of any part of the full term while designating the same concept.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="abbreviation">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.8.1: An abbreviated form of a simple term resulting from the omission of some of its letters (e.g. 'adj.' for 'adjective').</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="acronym">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.8.4: An abbreviated form of a term made up of letters from the full form of a multiword term strung together into a sequence pronounced only syllabically (e.g. 'radar' for 'radio detecting and ranging').</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="appellation">
- <xsd:annotation>
- <xsd:documentation>ISO-12620: A proper-name term, such as the name of an agency or other proper entity.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="collocation">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.18.1: A recurrent word combination characterized by cohesion in that the components of the collocation must co-occur within an utterance or series of utterances, even though they do not necessarily have to maintain immediate proximity to one another.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="common-name">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.5: A synonym for an international scientific term that is used in general discourse in a given language.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="datetime">
- <xsd:annotation>
- <xsd:documentation>Indicates the marked text is a date and/or time.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="equation">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.15: An expression used to represent a concept based on a statement that two mathematical expressions are, for instance, equal as identified by the equal sign (=), or assigned to one another by a similar sign.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="expanded-form">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.7: The complete representation of a term for which there is an abbreviated form.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="formula">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.14: Figures, symbols or the like used to express a concept briefly, such as a mathematical or chemical formula.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="head-term">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.1: The concept designation that has been chosen to head a terminological record.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="initialism">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.8.3: An abbreviated form of a term consisting of some of the initial letters of the words making up a multiword term or the term elements making up a compound term when these letters are pronounced individually (e.g. 'BSE' for 'bovine spongiform encephalopathy').</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="international-scientific-term">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.4: A term that is part of an international scientific nomenclature as adopted by an appropriate scientific body.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="internationalism">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.6: A term that has the same or nearly identical orthographic or phonemic form in many languages.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="logical-expression">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.16: An expression used to represent a concept based on mathematical or logical relations, such as statements of inequality, set relationships, Boolean operations, and the like.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="materials-management-unit">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.17: A unit to track object.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="name">
- <xsd:annotation>
- <xsd:documentation>Indicates the marked text is a name.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="near-synonym">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.3: A term that represents the same or a very similar concept as another term in the same language, but for which interchangeability is limited to some contexts and inapplicable in others.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="part-number">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.17.2: A unique alphanumeric designation assigned to an object in a manufacturing system.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="phrase">
- <xsd:annotation>
- <xsd:documentation>Indicates the marked text is a phrase.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="phraseological-unit">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.18: Any group of two or more words that form a unit, the meaning of which frequently cannot be deduced based on the combined sense of the words making up the phrase.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="protected">
- <xsd:annotation>
- <xsd:documentation>Indicates the marked text should not be translated.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="romanized-form">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.12: A form of a term resulting from an operation whereby non-Latin writing systems are converted to the Latin alphabet.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="seg">
- <xsd:annotation>
- <xsd:documentation>Indicates that the marked text represents a segment.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="set-phrase">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.18.2: A fixed, lexicalized phrase.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="short-form">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.8.2: A variant of a multiword term that includes fewer words than the full form of the term (e.g. 'Group of Twenty-four' for 'Intergovernmental Group of Twenty-four on International Monetary Affairs').</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="sku">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.17.1: Stock keeping unit, an inventory item identified by a unique alphanumeric designation assigned to an object in an inventory control system.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="standard-text">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.19: A fixed chunk of recurring text.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="symbol">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.13: A designation of a concept by letters, numerals, pictograms or any combination thereof.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="synonym">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.2: Any term that represents the same or a very similar concept as the main entry term in a term entry.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="synonymous-phrase">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.18.3: Phraseological unit in a language that expresses the same semantic content as another phrase in that same language.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="term">
- <xsd:annotation>
- <xsd:documentation>Indicates the marked text is a term.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="transcribed-form">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.11: A form of a term resulting from an operation whereby the characters of one writing system are represented by characters from another writing system, taking into account the pronunciation of the characters converted.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="transliterated-form">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.10: A form of a term resulting from an operation whereby the characters of an alphabetic writing system are represented by characters from another alphabetic writing system.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="truncated-term">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.8.5: An abbreviated form of a term resulting from the omission of one or more term elements or syllables (e.g. 'flu' for 'influenza').</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="variant">
- <xsd:annotation>
- <xsd:documentation>ISO-12620 2.1.9: One of the alternate forms of a term.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="restypeValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'restype'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="auto3state">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC AUTO3STATE control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="autocheckbox">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC AUTOCHECKBOX control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="autoradiobutton">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC AUTORADIOBUTTON control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="bedit">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC BEDIT control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="bitmap">
- <xsd:annotation>
- <xsd:documentation>Indicates a bitmap, for example a BITMAP resource in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="button">
- <xsd:annotation>
- <xsd:documentation>Indicates a button object, for example a BUTTON control Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="caption">
- <xsd:annotation>
- <xsd:documentation>Indicates a caption, such as the caption of a dialog box.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="cell">
- <xsd:annotation>
- <xsd:documentation>Indicates the cell in a table, for example the content of the <td> element in HTML.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="checkbox">
- <xsd:annotation>
- <xsd:documentation>Indicates check box object, for example a CHECKBOX control in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="checkboxmenuitem">
- <xsd:annotation>
- <xsd:documentation>Indicates a menu item with an associated checkbox.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="checkedlistbox">
- <xsd:annotation>
- <xsd:documentation>Indicates a list box, but with a check-box for each item.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="colorchooser">
- <xsd:annotation>
- <xsd:documentation>Indicates a color selection dialog.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="combobox">
- <xsd:annotation>
- <xsd:documentation>Indicates a combination of edit box and listbox object, for example a COMBOBOX control in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="comboboxexitem">
- <xsd:annotation>
- <xsd:documentation>Indicates an initialization entry of an extended combobox DLGINIT resource block. (code 0x1234).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="comboboxitem">
- <xsd:annotation>
- <xsd:documentation>Indicates an initialization entry of a combobox DLGINIT resource block (code 0x0403).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="component">
- <xsd:annotation>
- <xsd:documentation>Indicates a UI base class element that cannot be represented by any other element.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="contextmenu">
- <xsd:annotation>
- <xsd:documentation>Indicates a context menu.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="ctext">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC CTEXT control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="cursor">
- <xsd:annotation>
- <xsd:documentation>Indicates a cursor, for example a CURSOR resource in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="datetimepicker">
- <xsd:annotation>
- <xsd:documentation>Indicates a date/time picker.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="defpushbutton">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC DEFPUSHBUTTON control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="dialog">
- <xsd:annotation>
- <xsd:documentation>Indicates a dialog box.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="dlginit">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC DLGINIT resource block.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="edit">
- <xsd:annotation>
- <xsd:documentation>Indicates an edit box object, for example an EDIT control in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="file">
- <xsd:annotation>
- <xsd:documentation>Indicates a filename.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="filechooser">
- <xsd:annotation>
- <xsd:documentation>Indicates a file dialog.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="fn">
- <xsd:annotation>
- <xsd:documentation>Indicates a footnote.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="font">
- <xsd:annotation>
- <xsd:documentation>Indicates a font name.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="footer">
- <xsd:annotation>
- <xsd:documentation>Indicates a footer.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="frame">
- <xsd:annotation>
- <xsd:documentation>Indicates a frame object.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="grid">
- <xsd:annotation>
- <xsd:documentation>Indicates a XUL grid element.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="groupbox">
- <xsd:annotation>
- <xsd:documentation>Indicates a groupbox object, for example a GROUPBOX control in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="header">
- <xsd:annotation>
- <xsd:documentation>Indicates a header item.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="heading">
- <xsd:annotation>
- <xsd:documentation>Indicates a heading, such has the content of <h1>, <h2>, etc. in HTML.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="hedit">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC HEDIT control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="hscrollbar">
- <xsd:annotation>
- <xsd:documentation>Indicates a horizontal scrollbar.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="icon">
- <xsd:annotation>
- <xsd:documentation>Indicates an icon, for example an ICON resource in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="iedit">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC IEDIT control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="keywords">
- <xsd:annotation>
- <xsd:documentation>Indicates keyword list, such as the content of the Keywords meta-data in HTML, or a K footnote in WinHelp RTF.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="label">
- <xsd:annotation>
- <xsd:documentation>Indicates a label object.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="linklabel">
- <xsd:annotation>
- <xsd:documentation>Indicates a label that is also a HTML link (not necessarily a URL).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="list">
- <xsd:annotation>
- <xsd:documentation>Indicates a list (a group of list-items, for example an <ol> or <ul> element in HTML).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="listbox">
- <xsd:annotation>
- <xsd:documentation>Indicates a listbox object, for example an LISTBOX control in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="listitem">
- <xsd:annotation>
- <xsd:documentation>Indicates an list item (an entry in a list).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="ltext">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC LTEXT control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="menu">
- <xsd:annotation>
- <xsd:documentation>Indicates a menu (a group of menu-items).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="menubar">
- <xsd:annotation>
- <xsd:documentation>Indicates a toolbar containing one or more tope level menus.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="menuitem">
- <xsd:annotation>
- <xsd:documentation>Indicates a menu item (an entry in a menu).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="menuseparator">
- <xsd:annotation>
- <xsd:documentation>Indicates a XUL menuseparator element.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="message">
- <xsd:annotation>
- <xsd:documentation>Indicates a message, for example an entry in a MESSAGETABLE resource in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="monthcalendar">
- <xsd:annotation>
- <xsd:documentation>Indicates a calendar control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="numericupdown">
- <xsd:annotation>
- <xsd:documentation>Indicates an edit box beside a spin control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="panel">
- <xsd:annotation>
- <xsd:documentation>Indicates a catch all for rectangular areas.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="popupmenu">
- <xsd:annotation>
- <xsd:documentation>Indicates a standalone menu not necessarily associated with a menubar.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="pushbox">
- <xsd:annotation>
- <xsd:documentation>Indicates a pushbox object, for example a PUSHBOX control in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="pushbutton">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC PUSHBUTTON control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="radio">
- <xsd:annotation>
- <xsd:documentation>Indicates a radio button object.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="radiobuttonmenuitem">
- <xsd:annotation>
- <xsd:documentation>Indicates a menuitem with associated radio button.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rcdata">
- <xsd:annotation>
- <xsd:documentation>Indicates raw data resources for an application.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="row">
- <xsd:annotation>
- <xsd:documentation>Indicates a row in a table.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rtext">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC RTEXT control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="scrollpane">
- <xsd:annotation>
- <xsd:documentation>Indicates a user navigable container used to show a portion of a document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="separator">
- <xsd:annotation>
- <xsd:documentation>Indicates a generic divider object (e.g. menu group separator).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="shortcut">
- <xsd:annotation>
- <xsd:documentation>Windows accelerators, shortcuts in resource or property files.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="spinner">
- <xsd:annotation>
- <xsd:documentation>Indicates a UI control to indicate process activity but not progress.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="splitter">
- <xsd:annotation>
- <xsd:documentation>Indicates a splitter bar.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="state3">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC STATE3 control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="statusbar">
- <xsd:annotation>
- <xsd:documentation>Indicates a window for providing feedback to the users, like 'read-only', etc.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="string">
- <xsd:annotation>
- <xsd:documentation>Indicates a string, for example an entry in a STRINGTABLE resource in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="tabcontrol">
- <xsd:annotation>
- <xsd:documentation>Indicates a layers of controls with a tab to select layers.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="table">
- <xsd:annotation>
- <xsd:documentation>Indicates a display and edits regular two-dimensional tables of cells.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="textbox">
- <xsd:annotation>
- <xsd:documentation>Indicates a XUL textbox element.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="togglebutton">
- <xsd:annotation>
- <xsd:documentation>Indicates a UI button that can be toggled to on or off state.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="toolbar">
- <xsd:annotation>
- <xsd:documentation>Indicates an array of controls, usually buttons.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="tooltip">
- <xsd:annotation>
- <xsd:documentation>Indicates a pop up tool tip text.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="trackbar">
- <xsd:annotation>
- <xsd:documentation>Indicates a bar with a pointer indicating a position within a certain range.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="tree">
- <xsd:annotation>
- <xsd:documentation>Indicates a control that displays a set of hierarchical data.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="uri">
- <xsd:annotation>
- <xsd:documentation>Indicates a URI (URN or URL).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="userbutton">
- <xsd:annotation>
- <xsd:documentation>Indicates a Windows RC USERBUTTON control.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="usercontrol">
- <xsd:annotation>
- <xsd:documentation>Indicates a user-defined control like CONTROL control in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="var">
- <xsd:annotation>
- <xsd:documentation>Indicates the text of a variable.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="versioninfo">
- <xsd:annotation>
- <xsd:documentation>Indicates version information about a resource like VERSIONINFO in Windows.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="vscrollbar">
- <xsd:annotation>
- <xsd:documentation>Indicates a vertical scrollbar.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="window">
- <xsd:annotation>
- <xsd:documentation>Indicates a graphical window.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="size-unitValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'size-unit'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="byte">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in 8-bit bytes.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="char">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in Unicode characters.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="col">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in columns. Used for HTML text area.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="cm">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in centimeters.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="dlgunit">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in dialog units, as defined in Windows resources.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="em">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in 'font-size' units (as defined in CSS).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="ex">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in 'x-height' units (as defined in CSS).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="glyph">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in glyphs. A glyph is considered to be one or more combined Unicode characters that represent a single displayable text character. Sometimes referred to as a 'grapheme cluster'</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="in">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in inches.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="mm">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in millimeters.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="percent">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in percentage.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="pixel">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in pixels.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="point">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in point.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="row">
- <xsd:annotation>
- <xsd:documentation>Indicates a size in rows. Used for HTML text area.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="stateValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'state'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="final">
- <xsd:annotation>
- <xsd:documentation>Indicates the terminating state.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="needs-adaptation">
- <xsd:annotation>
- <xsd:documentation>Indicates only non-textual information needs adaptation.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="needs-l10n">
- <xsd:annotation>
- <xsd:documentation>Indicates both text and non-textual information needs adaptation.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="needs-review-adaptation">
- <xsd:annotation>
- <xsd:documentation>Indicates only non-textual information needs review.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="needs-review-l10n">
- <xsd:annotation>
- <xsd:documentation>Indicates both text and non-textual information needs review.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="needs-review-translation">
- <xsd:annotation>
- <xsd:documentation>Indicates that only the text of the item needs to be reviewed.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="needs-translation">
- <xsd:annotation>
- <xsd:documentation>Indicates that the item needs to be translated.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="new">
- <xsd:annotation>
- <xsd:documentation>Indicates that the item is new. For example, translation units that were not in a previous version of the document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="signed-off">
- <xsd:annotation>
- <xsd:documentation>Indicates that changes are reviewed and approved.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="translated">
- <xsd:annotation>
- <xsd:documentation>Indicates that the item has been translated.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="state-qualifierValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'state-qualifier'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="exact-match">
- <xsd:annotation>
- <xsd:documentation>Indicates an exact match. An exact match occurs when a source text of a segment is exactly the same as the source text of a segment that was translated previously.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="fuzzy-match">
- <xsd:annotation>
- <xsd:documentation>Indicates a fuzzy match. A fuzzy match occurs when a source text of a segment is very similar to the source text of a segment that was translated previously (e.g. when the difference is casing, a few changed words, white-space discripancy, etc.).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="id-match">
- <xsd:annotation>
- <xsd:documentation>Indicates a match based on matching IDs (in addition to matching text).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="leveraged-glossary">
- <xsd:annotation>
- <xsd:documentation>Indicates a translation derived from a glossary.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="leveraged-inherited">
- <xsd:annotation>
- <xsd:documentation>Indicates a translation derived from existing translation.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="leveraged-mt">
- <xsd:annotation>
- <xsd:documentation>Indicates a translation derived from machine translation.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="leveraged-repository">
- <xsd:annotation>
- <xsd:documentation>Indicates a translation derived from a translation repository.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="leveraged-tm">
- <xsd:annotation>
- <xsd:documentation>Indicates a translation derived from a translation memory.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="mt-suggestion">
- <xsd:annotation>
- <xsd:documentation>Indicates the translation is suggested by machine translation.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rejected-grammar">
- <xsd:annotation>
- <xsd:documentation>Indicates that the item has been rejected because of incorrect grammar.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rejected-inaccurate">
- <xsd:annotation>
- <xsd:documentation>Indicates that the item has been rejected because it is incorrect.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rejected-length">
- <xsd:annotation>
- <xsd:documentation>Indicates that the item has been rejected because it is too long or too short.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rejected-spelling">
- <xsd:annotation>
- <xsd:documentation>Indicates that the item has been rejected because of incorrect spelling.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="tm-suggestion">
- <xsd:annotation>
- <xsd:documentation>Indicates the translation is suggested by translation memory.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="unitValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'unit'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="word">
- <xsd:annotation>
- <xsd:documentation>Refers to words.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="page">
- <xsd:annotation>
- <xsd:documentation>Refers to pages.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="trans-unit">
- <xsd:annotation>
- <xsd:documentation>Refers to <trans-unit> elements.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="bin-unit">
- <xsd:annotation>
- <xsd:documentation>Refers to <bin-unit> elements.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="glyph">
- <xsd:annotation>
- <xsd:documentation>Refers to glyphs.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="item">
- <xsd:annotation>
- <xsd:documentation>Refers to <trans-unit> and/or <bin-unit> elements.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="instance">
- <xsd:annotation>
- <xsd:documentation>Refers to the occurrences of instances defined by the count-type value.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="character">
- <xsd:annotation>
- <xsd:documentation>Refers to characters.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="line">
- <xsd:annotation>
- <xsd:documentation>Refers to lines.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="sentence">
- <xsd:annotation>
- <xsd:documentation>Refers to sentences.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="paragraph">
- <xsd:annotation>
- <xsd:documentation>Refers to paragraphs.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="segment">
- <xsd:annotation>
- <xsd:documentation>Refers to segments.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="placeable">
- <xsd:annotation>
- <xsd:documentation>Refers to placeables (inline elements).</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="priorityValueList">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'priority'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:positiveInteger">
- <xsd:enumeration value="1">
- <xsd:annotation>
- <xsd:documentation>Highest priority.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="2">
- <xsd:annotation>
- <xsd:documentation>High priority.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="3">
- <xsd:annotation>
- <xsd:documentation>High priority, but not as important as 2.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="4">
- <xsd:annotation>
- <xsd:documentation>High priority, but not as important as 3.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="5">
- <xsd:annotation>
- <xsd:documentation>Medium priority, but more important than 6.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="6">
- <xsd:annotation>
- <xsd:documentation>Medium priority, but less important than 5.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="7">
- <xsd:annotation>
- <xsd:documentation>Low priority, but more important than 8.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="8">
- <xsd:annotation>
- <xsd:documentation>Low priority, but more important than 9.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="9">
- <xsd:annotation>
- <xsd:documentation>Low priority.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="10">
- <xsd:annotation>
- <xsd:documentation>Lowest priority.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="reformatValueYesNo">
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="yes">
- <xsd:annotation>
- <xsd:documentation>This value indicates that all properties can be reformatted. This value must be used alone.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="no">
- <xsd:annotation>
- <xsd:documentation>This value indicates that no properties should be reformatted. This value must be used alone.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="reformatValueList">
- <xsd:list>
- <xsd:simpleType>
- <xsd:union memberTypes="xlf:XTend">
- <xsd:simpleType>
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="coord">
- <xsd:annotation>
- <xsd:documentation>This value indicates that all information in the coord attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="coord-x">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the x information in the coord attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="coord-y">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the y information in the coord attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="coord-cx">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the cx information in the coord attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="coord-cy">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the cy information in the coord attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="font">
- <xsd:annotation>
- <xsd:documentation>This value indicates that all the information in the font attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="font-name">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the name information in the font attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="font-size">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the size information in the font attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="font-weight">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the weight information in the font attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="css-style">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the information in the css-style attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="style">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the information in the style attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="ex-style">
- <xsd:annotation>
- <xsd:documentation>This value indicates that the information in the exstyle attribute can be modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:union>
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
- <xsd:simpleType name="purposeValueList">
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="information">
- <xsd:annotation>
- <xsd:documentation>Indicates that the context is informational in nature, specifying for example, how a term should be translated. Thus, should be displayed to anyone editing the XLIFF document.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="location">
- <xsd:annotation>
- <xsd:documentation>Indicates that the context-group is used to specify where the term was found in the translatable source. Thus, it is not displayed.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="match">
- <xsd:annotation>
- <xsd:documentation>Indicates that the context information should be used during translation memory lookups. Thus, it is not displayed.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="alttranstypeValueList">
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="proposal">
- <xsd:annotation>
- <xsd:documentation>Represents a translation proposal from a translation memory or other resource.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="previous-version">
- <xsd:annotation>
- <xsd:documentation>Represents a previous version of the target element.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="rejected">
- <xsd:annotation>
- <xsd:documentation>Represents a rejected version of the target element.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="reference">
- <xsd:annotation>
- <xsd:documentation>Represents a translation to be used for reference purposes only, for example from a related product or a different language.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- <xsd:enumeration value="accepted">
- <xsd:annotation>
- <xsd:documentation>Represents a proposed translation that was used for the translation of the trans-unit, possibly modified.</xsd:documentation>
- </xsd:annotation>
- </xsd:enumeration>
- </xsd:restriction>
- </xsd:simpleType>
- <!-- Other Types -->
- <xsd:complexType name="ElemType_ExternalReference">
- <xsd:choice>
- <xsd:element ref="xlf:internal-file"/>
- <xsd:element ref="xlf:external-file"/>
- </xsd:choice>
- </xsd:complexType>
- <xsd:simpleType name="AttrType_purpose">
- <xsd:list>
- <xsd:simpleType>
- <xsd:union memberTypes="xlf:purposeValueList xlf:XTend"/>
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_datatype">
- <xsd:union memberTypes="xlf:datatypeValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_restype">
- <xsd:union memberTypes="xlf:restypeValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_alttranstype">
- <xsd:union memberTypes="xlf:alttranstypeValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_context-type">
- <xsd:union memberTypes="xlf:context-typeValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_state">
- <xsd:union memberTypes="xlf:stateValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_state-qualifier">
- <xsd:union memberTypes="xlf:state-qualifierValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_count-type">
- <xsd:union memberTypes="xlf:restypeValueList xlf:count-typeValueList xlf:datatypeValueList xlf:stateValueList xlf:state-qualifierValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_InlineDelimiters">
- <xsd:union memberTypes="xlf:InlineDelimitersValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_InlinePlaceholders">
- <xsd:union memberTypes="xlf:InlinePlaceholdersValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_size-unit">
- <xsd:union memberTypes="xlf:size-unitValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_mtype">
- <xsd:union memberTypes="xlf:mtypeValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_unit">
- <xsd:union memberTypes="xlf:unitValueList xlf:XTend"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_priority">
- <xsd:union memberTypes="xlf:priorityValueList"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_reformat">
- <xsd:union memberTypes="xlf:reformatValueYesNo xlf:reformatValueList"/>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_YesNo">
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="yes"/>
- <xsd:enumeration value="no"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_Position">
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="open"/>
- <xsd:enumeration value="close"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_assoc">
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="preceding"/>
- <xsd:enumeration value="following"/>
- <xsd:enumeration value="both"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_annotates">
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="source"/>
- <xsd:enumeration value="target"/>
- <xsd:enumeration value="general"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_Coordinates">
- <xsd:annotation>
- <xsd:documentation>Values for the attribute 'coord'.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:string">
- <xsd:pattern value="(-?\d+|#);(-?\d+|#);(-?\d+|#);(-?\d+|#)"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:simpleType name="AttrType_Version">
- <xsd:annotation>
- <xsd:documentation>Version values: 1.0 and 1.1 are allowed for backward compatibility.</xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="1.2"/>
- <xsd:enumeration value="1.1"/>
- <xsd:enumeration value="1.0"/>
- </xsd:restriction>
- </xsd:simpleType>
- <!-- Groups -->
- <xsd:group name="ElemGroup_TextContent">
- <xsd:choice>
- <xsd:element ref="xlf:g"/>
- <xsd:element ref="xlf:bpt"/>
- <xsd:element ref="xlf:ept"/>
- <xsd:element ref="xlf:ph"/>
- <xsd:element ref="xlf:it"/>
- <xsd:element ref="xlf:mrk"/>
- <xsd:element ref="xlf:x"/>
- <xsd:element ref="xlf:bx"/>
- <xsd:element ref="xlf:ex"/>
- </xsd:choice>
- </xsd:group>
- <xsd:attributeGroup name="AttrGroup_TextContent">
- <xsd:attribute name="id" type="xsd:string" use="required"/>
- <xsd:attribute name="xid" type="xsd:string" use="optional"/>
- <xsd:attribute name="equiv-text" type="xsd:string" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:attributeGroup>
- <!-- XLIFF Structure -->
- <xsd:element name="xliff">
- <xsd:complexType>
- <xsd:sequence maxOccurs="unbounded">
- <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
- <xsd:element ref="xlf:file"/>
- </xsd:sequence>
- <xsd:attribute name="version" type="xlf:AttrType_Version" use="required"/>
- <xsd:attribute ref="xml:lang" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="file">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element minOccurs="0" ref="xlf:header"/>
- <xsd:element ref="xlf:body"/>
- </xsd:sequence>
- <xsd:attribute name="original" type="xsd:string" use="required"/>
- <xsd:attribute name="source-language" type="xsd:language" use="required"/>
- <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="required"/>
- <xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
- <xsd:attribute name="date" type="xsd:dateTime" use="optional"/>
- <xsd:attribute ref="xml:space" use="optional"/>
- <xsd:attribute name="category" type="xsd:string" use="optional"/>
- <xsd:attribute name="target-language" type="xsd:language" use="optional"/>
- <xsd:attribute name="product-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="product-version" type="xsd:string" use="optional"/>
- <xsd:attribute name="build-num" type="xsd:string" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- <xsd:unique name="U_group_id">
- <xsd:selector xpath=".//xlf:group"/>
- <xsd:field xpath="@id"/>
- </xsd:unique>
- <xsd:key name="K_unit_id">
- <xsd:selector xpath=".//xlf:trans-unit|.//xlf:bin-unit"/>
- <xsd:field xpath="@id"/>
- </xsd:key>
- <xsd:keyref name="KR_unit_id" refer="xlf:K_unit_id">
- <xsd:selector xpath=".//bpt|.//ept|.//it|.//ph|.//g|.//x|.//bx|.//ex|.//sub"/>
- <xsd:field xpath="@xid"/>
- </xsd:keyref>
- <xsd:key name="K_tool-id">
- <xsd:selector xpath="xlf:header/xlf:tool"/>
- <xsd:field xpath="@tool-id"/>
- </xsd:key>
- <xsd:keyref name="KR_file_tool-id" refer="xlf:K_tool-id">
- <xsd:selector xpath="."/>
- <xsd:field xpath="@tool-id"/>
- </xsd:keyref>
- <xsd:keyref name="KR_phase_tool-id" refer="xlf:K_tool-id">
- <xsd:selector xpath="xlf:header/xlf:phase-group/xlf:phase"/>
- <xsd:field xpath="@tool-id"/>
- </xsd:keyref>
- <xsd:keyref name="KR_alt-trans_tool-id" refer="xlf:K_tool-id">
- <xsd:selector xpath=".//xlf:trans-unit/xlf:alt-trans"/>
- <xsd:field xpath="@tool-id"/>
- </xsd:keyref>
- <xsd:key name="K_count-group_name">
- <xsd:selector xpath=".//xlf:count-group"/>
- <xsd:field xpath="@name"/>
- </xsd:key>
- <xsd:unique name="U_context-group_name">
- <xsd:selector xpath=".//xlf:context-group"/>
- <xsd:field xpath="@name"/>
- </xsd:unique>
- <xsd:key name="K_phase-name">
- <xsd:selector xpath="xlf:header/xlf:phase-group/xlf:phase"/>
- <xsd:field xpath="@phase-name"/>
- </xsd:key>
- <xsd:keyref name="KR_phase-name" refer="xlf:K_phase-name">
- <xsd:selector xpath=".//xlf:count|.//xlf:trans-unit|.//xlf:target|.//bin-unit|.//bin-target"/>
- <xsd:field xpath="@phase-name"/>
- </xsd:keyref>
- <xsd:unique name="U_uid">
- <xsd:selector xpath=".//xlf:external-file"/>
- <xsd:field xpath="@uid"/>
- </xsd:unique>
- </xsd:element>
- <xsd:element name="header">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element minOccurs="0" name="skl" type="xlf:ElemType_ExternalReference"/>
- <xsd:element minOccurs="0" ref="xlf:phase-group"/>
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element name="glossary" type="xlf:ElemType_ExternalReference"/>
- <xsd:element name="reference" type="xlf:ElemType_ExternalReference"/>
- <xsd:element ref="xlf:count-group"/>
- <xsd:element ref="xlf:note"/>
- <xsd:element ref="xlf:tool"/>
- </xsd:choice>
- <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="internal-file">
- <xsd:complexType>
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute name="form" type="xsd:string"/>
- <xsd:attribute name="crc" type="xsd:NMTOKEN"/>
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="external-file">
- <xsd:complexType>
- <xsd:attribute name="href" type="xsd:string" use="required"/>
- <xsd:attribute name="crc" type="xsd:NMTOKEN"/>
- <xsd:attribute name="uid" type="xsd:NMTOKEN"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="note">
- <xsd:complexType>
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute ref="xml:lang" use="optional"/>
- <xsd:attribute default="1" name="priority" type="xlf:AttrType_priority" use="optional"/>
- <xsd:attribute name="from" type="xsd:string" use="optional"/>
- <xsd:attribute default="general" name="annotates" type="xlf:AttrType_annotates" use="optional"/>
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="phase-group">
- <xsd:complexType>
- <xsd:sequence maxOccurs="unbounded">
- <xsd:element ref="xlf:phase"/>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="phase">
- <xsd:complexType>
- <xsd:sequence maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:note"/>
- </xsd:sequence>
- <xsd:attribute name="phase-name" type="xsd:string" use="required"/>
- <xsd:attribute name="process-name" type="xsd:string" use="required"/>
- <xsd:attribute name="company-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
- <xsd:attribute name="date" type="xsd:dateTime" use="optional"/>
- <xsd:attribute name="job-id" type="xsd:string" use="optional"/>
- <xsd:attribute name="contact-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="contact-email" type="xsd:string" use="optional"/>
- <xsd:attribute name="contact-phone" type="xsd:string" use="optional"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="count-group">
- <xsd:complexType>
- <xsd:sequence maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:count"/>
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="count">
- <xsd:complexType>
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute name="count-type" type="xlf:AttrType_count-type" use="optional"/>
- <xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
- <xsd:attribute default="word" name="unit" type="xlf:AttrType_unit" use="optional"/>
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="context-group">
- <xsd:complexType>
- <xsd:sequence maxOccurs="unbounded">
- <xsd:element ref="xlf:context"/>
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="optional"/>
- <xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="purpose" type="xlf:AttrType_purpose" use="optional"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="context">
- <xsd:complexType>
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute name="context-type" type="xlf:AttrType_context-type" use="required"/>
- <xsd:attribute default="no" name="match-mandatory" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="tool">
- <xsd:complexType mixed="true">
- <xsd:sequence>
- <xsd:any namespace="##any" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
- </xsd:sequence>
- <xsd:attribute name="tool-id" type="xsd:string" use="required"/>
- <xsd:attribute name="tool-name" type="xsd:string" use="required"/>
- <xsd:attribute name="tool-version" type="xsd:string" use="optional"/>
- <xsd:attribute name="tool-company" type="xsd:string" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="body">
- <xsd:complexType>
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:group"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:trans-unit"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:bin-unit"/>
- </xsd:choice>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="group">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:sequence>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:context-group"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:count-group"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:note"/>
- <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
- </xsd:sequence>
- <xsd:choice maxOccurs="unbounded">
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:group"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:trans-unit"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:bin-unit"/>
- </xsd:choice>
- </xsd:sequence>
- <xsd:attribute name="id" type="xsd:string" use="optional"/>
- <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
- <xsd:attribute default="default" ref="xml:space" use="optional"/>
- <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
- <xsd:attribute name="resname" type="xsd:string" use="optional"/>
- <xsd:attribute name="extradata" type="xsd:string" use="optional"/>
- <xsd:attribute name="extype" type="xsd:string" use="optional"/>
- <xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="menu" type="xsd:string" use="optional"/>
- <xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
- <xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
- <xsd:attribute name="font" type="xsd:string" use="optional"/>
- <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
- <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
- <xsd:attribute default="pixel" name="size-unit" type="xlf:AttrType_size-unit" use="optional"/>
- <xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="charclass" type="xsd:string" use="optional"/>
- <xsd:attribute default="no" name="merged-trans" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="trans-unit">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element ref="xlf:source"/>
- <xsd:element minOccurs="0" ref="xlf:seg-source"/>
- <xsd:element minOccurs="0" ref="xlf:target"/>
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:context-group"/>
- <xsd:element ref="xlf:count-group"/>
- <xsd:element ref="xlf:note"/>
- <xsd:element ref="xlf:alt-trans"/>
- </xsd:choice>
- <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
- </xsd:sequence>
- <xsd:attribute name="id" type="xsd:string" use="required"/>
- <xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
- <xsd:attribute default="default" ref="xml:space" use="optional"/>
- <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
- <xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
- <xsd:attribute name="resname" type="xsd:string" use="optional"/>
- <xsd:attribute name="extradata" type="xsd:string" use="optional"/>
- <xsd:attribute name="extype" type="xsd:string" use="optional"/>
- <xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="menu" type="xsd:string" use="optional"/>
- <xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
- <xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
- <xsd:attribute name="font" type="xsd:string" use="optional"/>
- <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
- <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute default="pixel" name="size-unit" type="xlf:AttrType_size-unit" use="optional"/>
- <xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="charclass" type="xsd:string" use="optional"/>
- <xsd:attribute default="yes" name="merged-trans" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- <xsd:unique name="U_tu_segsrc_mid">
- <xsd:selector xpath="./xlf:seg-source/xlf:mrk"/>
- <xsd:field xpath="@mid"/>
- </xsd:unique>
- <xsd:keyref name="KR_tu_segsrc_mid" refer="xlf:U_tu_segsrc_mid">
- <xsd:selector xpath="./xlf:target/xlf:mrk|./xlf:alt-trans"/>
- <xsd:field xpath="@mid"/>
- </xsd:keyref>
- </xsd:element>
- <xsd:element name="source">
- <xsd:complexType mixed="true">
- <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
- <xsd:attribute ref="xml:lang" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- <xsd:unique name="U_source_bpt_rid">
- <xsd:selector xpath=".//xlf:bpt"/>
- <xsd:field xpath="@rid"/>
- </xsd:unique>
- <xsd:keyref name="KR_source_ept_rid" refer="xlf:U_source_bpt_rid">
- <xsd:selector xpath=".//xlf:ept"/>
- <xsd:field xpath="@rid"/>
- </xsd:keyref>
- <xsd:unique name="U_source_bx_rid">
- <xsd:selector xpath=".//xlf:bx"/>
- <xsd:field xpath="@rid"/>
- </xsd:unique>
- <xsd:keyref name="KR_source_ex_rid" refer="xlf:U_source_bx_rid">
- <xsd:selector xpath=".//xlf:ex"/>
- <xsd:field xpath="@rid"/>
- </xsd:keyref>
- </xsd:element>
- <xsd:element name="seg-source">
- <xsd:complexType mixed="true">
- <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
- <xsd:attribute ref="xml:lang" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- <xsd:unique name="U_segsrc_bpt_rid">
- <xsd:selector xpath=".//xlf:bpt"/>
- <xsd:field xpath="@rid"/>
- </xsd:unique>
- <xsd:keyref name="KR_segsrc_ept_rid" refer="xlf:U_segsrc_bpt_rid">
- <xsd:selector xpath=".//xlf:ept"/>
- <xsd:field xpath="@rid"/>
- </xsd:keyref>
- <xsd:unique name="U_segsrc_bx_rid">
- <xsd:selector xpath=".//xlf:bx"/>
- <xsd:field xpath="@rid"/>
- </xsd:unique>
- <xsd:keyref name="KR_segsrc_ex_rid" refer="xlf:U_segsrc_bx_rid">
- <xsd:selector xpath=".//xlf:ex"/>
- <xsd:field xpath="@rid"/>
- </xsd:keyref>
- </xsd:element>
- <xsd:element name="target">
- <xsd:complexType mixed="true">
- <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
- <xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>
- <xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>
- <xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute ref="xml:lang" use="optional"/>
- <xsd:attribute name="resname" type="xsd:string" use="optional"/>
- <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
- <xsd:attribute name="font" type="xsd:string" use="optional"/>
- <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
- <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute default="yes" name="equiv-trans" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- <xsd:unique name="U_target_bpt_rid">
- <xsd:selector xpath=".//xlf:bpt"/>
- <xsd:field xpath="@rid"/>
- </xsd:unique>
- <xsd:keyref name="KR_target_ept_rid" refer="xlf:U_target_bpt_rid">
- <xsd:selector xpath=".//xlf:ept"/>
- <xsd:field xpath="@rid"/>
- </xsd:keyref>
- <xsd:unique name="U_target_bx_rid">
- <xsd:selector xpath=".//xlf:bx"/>
- <xsd:field xpath="@rid"/>
- </xsd:unique>
- <xsd:keyref name="KR_target_ex_rid" refer="xlf:U_target_bx_rid">
- <xsd:selector xpath=".//xlf:ex"/>
- <xsd:field xpath="@rid"/>
- </xsd:keyref>
- </xsd:element>
- <xsd:element name="alt-trans">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element minOccurs="0" ref="xlf:source"/>
- <xsd:element minOccurs="0" ref="xlf:seg-source"/>
- <xsd:element maxOccurs="1" ref="xlf:target"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:context-group"/>
- <xsd:element maxOccurs="unbounded" minOccurs="0" ref="xlf:note"/>
- <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
- </xsd:sequence>
- <xsd:attribute name="match-quality" type="xsd:string" use="optional"/>
- <xsd:attribute name="tool-id" type="xsd:string" use="optional"/>
- <xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute ref="xml:lang" use="optional"/>
- <xsd:attribute name="origin" type="xsd:string" use="optional"/>
- <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
- <xsd:attribute default="default" ref="xml:space" use="optional"/>
- <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
- <xsd:attribute name="resname" type="xsd:string" use="optional"/>
- <xsd:attribute name="extradata" type="xsd:string" use="optional"/>
- <xsd:attribute name="extype" type="xsd:string" use="optional"/>
- <xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="menu" type="xsd:string" use="optional"/>
- <xsd:attribute name="menu-option" type="xsd:string" use="optional"/>
- <xsd:attribute name="menu-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="mid" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>
- <xsd:attribute name="font" type="xsd:string" use="optional"/>
- <xsd:attribute name="css-style" type="xsd:string" use="optional"/>
- <xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute default="proposal" name="alttranstype" type="xlf:AttrType_alttranstype" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- <xsd:unique name="U_at_segsrc_mid">
- <xsd:selector xpath="./xlf:seg-source/xlf:mrk"/>
- <xsd:field xpath="@mid"/>
- </xsd:unique>
- <xsd:keyref name="KR_at_segsrc_mid" refer="xlf:U_at_segsrc_mid">
- <xsd:selector xpath="./xlf:target/xlf:mrk"/>
- <xsd:field xpath="@mid"/>
- </xsd:keyref>
- </xsd:element>
- <xsd:element name="bin-unit">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element ref="xlf:bin-source"/>
- <xsd:element minOccurs="0" ref="xlf:bin-target"/>
- <xsd:choice maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:context-group"/>
- <xsd:element ref="xlf:count-group"/>
- <xsd:element ref="xlf:note"/>
- <xsd:element ref="xlf:trans-unit"/>
- </xsd:choice>
- <xsd:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="strict"/>
- </xsd:sequence>
- <xsd:attribute name="id" type="xsd:string" use="required"/>
- <xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="required"/>
- <xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attribute default="yes" name="translate" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attribute default="yes" name="reformat" type="xlf:AttrType_reformat" use="optional"/>
- <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
- <xsd:attribute name="resname" type="xsd:string" use="optional"/>
- <xsd:attribute name="phase-name" type="xsd:string" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="bin-source">
- <xsd:complexType>
- <xsd:choice>
- <xsd:element ref="xlf:internal-file"/>
- <xsd:element ref="xlf:external-file"/>
- </xsd:choice>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="bin-target">
- <xsd:complexType>
- <xsd:choice>
- <xsd:element ref="xlf:internal-file"/>
- <xsd:element ref="xlf:external-file"/>
- </xsd:choice>
- <xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="optional"/>
- <xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>
- <xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>
- <xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>
- <xsd:attribute name="resname" type="xsd:string" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- </xsd:element>
- <!-- Element for inline codes -->
- <xsd:element name="g">
- <xsd:complexType mixed="true">
- <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
- <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
- <xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="x">
- <xsd:complexType>
- <xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>
- <xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="bx">
- <xsd:complexType>
- <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
- <xsd:attribute default="yes" name="clone" type="xlf:AttrType_YesNo" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="ex">
- <xsd:complexType>
- <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="ph">
- <xsd:complexType mixed="true">
- <xsd:sequence maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:sub"/>
- </xsd:sequence>
- <xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>
- <xsd:attribute name="crc" type="xsd:string" use="optional"/>
- <xsd:attribute name="assoc" type="xlf:AttrType_assoc" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="bpt">
- <xsd:complexType mixed="true">
- <xsd:sequence maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:sub"/>
- </xsd:sequence>
- <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
- <xsd:attribute name="crc" type="xsd:string" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="ept">
- <xsd:complexType mixed="true">
- <xsd:sequence maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:sub"/>
- </xsd:sequence>
- <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="crc" type="xsd:string" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="it">
- <xsd:complexType mixed="true">
- <xsd:sequence maxOccurs="unbounded" minOccurs="0">
- <xsd:element ref="xlf:sub"/>
- </xsd:sequence>
- <xsd:attribute name="pos" type="xlf:AttrType_Position" use="required"/>
- <xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
- <xsd:attribute name="crc" type="xsd:string" use="optional"/>
- <xsd:attributeGroup ref="xlf:AttrGroup_TextContent"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="sub">
- <xsd:complexType mixed="true">
- <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
- <xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>
- <xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>
- <xsd:attribute name="xid" type="xsd:string" use="optional"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="mrk">
- <xsd:complexType mixed="true">
- <xsd:group maxOccurs="unbounded" minOccurs="0" ref="xlf:ElemGroup_TextContent"/>
- <xsd:attribute name="mtype" type="xlf:AttrType_mtype" use="required"/>
- <xsd:attribute name="mid" type="xsd:NMTOKEN" use="optional"/>
- <xsd:attribute name="comment" type="xsd:string" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="strict"/>
- </xsd:complexType>
- </xsd:element>
-</xsd:schema>
+++ /dev/null
-<?xml version='1.0'?>
-<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
-<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
- xmlns:xs="http://www.w3.org/2001/XMLSchema"
- xmlns ="http://www.w3.org/1999/xhtml"
- xml:lang="en">
-
- <xs:annotation>
- <xs:documentation>
- <div>
- <h1>About the XML namespace</h1>
-
- <div class="bodytext">
- <p>
-
- This schema document describes the XML namespace, in a form
- suitable for import by other schema documents.
- </p>
- <p>
- See <a href="http://www.w3.org/XML/1998/namespace.html">
- http://www.w3.org/XML/1998/namespace.html</a> and
- <a href="http://www.w3.org/TR/REC-xml">
- http://www.w3.org/TR/REC-xml</a> for information
- about this namespace.
- </p>
-
- <p>
- Note that local names in this namespace are intended to be
- defined only by the World Wide Web Consortium or its subgroups.
- The names currently defined in this namespace are listed below.
- They should not be used with conflicting semantics by any Working
- Group, specification, or document instance.
- </p>
- <p>
- See further below in this document for more information about <a
- href="#usage">how to refer to this schema document from your own
- XSD schema documents</a> and about <a href="#nsversioning">the
- namespace-versioning policy governing this schema document</a>.
- </p>
- </div>
- </div>
-
- </xs:documentation>
- </xs:annotation>
-
- <xs:attribute name="lang">
- <xs:annotation>
- <xs:documentation>
- <div>
-
- <h3>lang (as an attribute name)</h3>
- <p>
-
- denotes an attribute whose value
- is a language code for the natural language of the content of
- any element; its value is inherited. This name is reserved
- by virtue of its definition in the XML specification.</p>
-
- </div>
- <div>
- <h4>Notes</h4>
- <p>
- Attempting to install the relevant ISO 2- and 3-letter
- codes as the enumerated possible values is probably never
- going to be a realistic possibility.
- </p>
- <p>
-
- See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
- http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
- and the IANA language subtag registry at
- <a href="http://www.iana.org/assignments/language-subtag-registry">
- http://www.iana.org/assignments/language-subtag-registry</a>
- for further information.
- </p>
- <p>
-
- The union allows for the 'un-declaration' of xml:lang with
- the empty string.
- </p>
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:union memberTypes="xs:language">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value=""/>
-
- </xs:restriction>
- </xs:simpleType>
- </xs:union>
- </xs:simpleType>
- </xs:attribute>
-
- <xs:attribute name="space">
- <xs:annotation>
- <xs:documentation>
-
- <div>
-
- <h3>space (as an attribute name)</h3>
- <p>
- denotes an attribute whose
- value is a keyword indicating what whitespace processing
- discipline is intended for the content of the element; its
- value is inherited. This name is reserved by virtue of its
- definition in the XML specification.</p>
-
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
-
- <xs:restriction base="xs:NCName">
- <xs:enumeration value="default"/>
- <xs:enumeration value="preserve"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
-
- <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
- <xs:documentation>
-
- <div>
-
- <h3>base (as an attribute name)</h3>
- <p>
- denotes an attribute whose value
- provides a URI to be used as the base for interpreting any
- relative URIs in the scope of the element on which it
- appears; its value is inherited. This name is reserved
- by virtue of its definition in the XML Base specification.</p>
-
- <p>
- See <a
- href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
- for information about this attribute.
- </p>
-
- </div>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="id" type="xs:ID">
- <xs:annotation>
- <xs:documentation>
- <div>
-
- <h3>id (as an attribute name)</h3>
- <p>
-
- denotes an attribute whose value
- should be interpreted as if declared to be of type ID.
- This name is reserved by virtue of its definition in the
- xml:id specification.</p>
-
- <p>
- See <a
- href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
- for information about this attribute.
- </p>
- </div>
- </xs:documentation>
- </xs:annotation>
-
- </xs:attribute>
-
- <xs:attributeGroup name="specialAttrs">
- <xs:attribute ref="xml:base"/>
- <xs:attribute ref="xml:lang"/>
- <xs:attribute ref="xml:space"/>
- <xs:attribute ref="xml:id"/>
- </xs:attributeGroup>
-
- <xs:annotation>
-
- <xs:documentation>
- <div>
-
- <h3>Father (in any context at all)</h3>
-
- <div class="bodytext">
- <p>
- denotes Jon Bosak, the chair of
- the original XML Working Group. This name is reserved by
- the following decision of the W3C XML Plenary and
- XML Coordination groups:
- </p>
- <blockquote>
- <p>
-
- In appreciation for his vision, leadership and
- dedication the W3C XML Plenary on this 10th day of
- February, 2000, reserves for Jon Bosak in perpetuity
- the XML name "xml:Father".
- </p>
- </blockquote>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-
- <xs:annotation>
- <xs:documentation>
-
- <div xml:id="usage" id="usage">
- <h2><a name="usage">About this schema document</a></h2>
-
- <div class="bodytext">
- <p>
- This schema defines attributes and an attribute group suitable
- for use by schemas wishing to allow <code>xml:base</code>,
- <code>xml:lang</code>, <code>xml:space</code> or
- <code>xml:id</code> attributes on elements they define.
- </p>
-
- <p>
- To enable this, such a schema must import this schema for
- the XML namespace, e.g. as follows:
- </p>
- <pre>
- <schema.. .>
- .. .
- <import namespace="http://www.w3.org/XML/1998/namespace"
- schemaLocation="http://www.w3.org/2001/xml.xsd"/>
- </pre>
- <p>
- or
- </p>
- <pre>
-
- <import namespace="http://www.w3.org/XML/1998/namespace"
- schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
- </pre>
- <p>
- Subsequently, qualified reference to any of the attributes or the
- group defined below will have the desired effect, e.g.
- </p>
- <pre>
- <type.. .>
- .. .
- <attributeGroup ref="xml:specialAttrs"/>
- </pre>
- <p>
- will define a type which will schema-validate an instance element
- with any of those attributes.
- </p>
-
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-
- <xs:annotation>
- <xs:documentation>
- <div id="nsversioning" xml:id="nsversioning">
- <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
-
- <div class="bodytext">
- <p>
- In keeping with the XML Schema WG's standard versioning
- policy, this schema document will persist at
- <a href="http://www.w3.org/2009/01/xml.xsd">
- http://www.w3.org/2009/01/xml.xsd</a>.
- </p>
- <p>
- At the date of issue it can also be found at
- <a href="http://www.w3.org/2001/xml.xsd">
- http://www.w3.org/2001/xml.xsd</a>.
- </p>
-
- <p>
- The schema document at that URI may however change in the future,
- in order to remain compatible with the latest version of XML
- Schema itself, or with the XML namespace itself. In other words,
- if the XML Schema or XML namespaces change, the version of this
- document at <a href="http://www.w3.org/2001/xml.xsd">
- http://www.w3.org/2001/xml.xsd
- </a>
- will change accordingly; the version at
- <a href="http://www.w3.org/2009/01/xml.xsd">
- http://www.w3.org/2009/01/xml.xsd
- </a>
- will not change.
- </p>
- <p>
-
- Previous dated (and unchanging) versions of this schema
- document are at:
- </p>
- <ul>
- <li><a href="http://www.w3.org/2009/01/xml.xsd">
- http://www.w3.org/2009/01/xml.xsd</a></li>
- <li><a href="http://www.w3.org/2007/08/xml.xsd">
- http://www.w3.org/2007/08/xml.xsd</a></li>
- <li><a href="http://www.w3.org/2004/10/xml.xsd">
-
- http://www.w3.org/2004/10/xml.xsd</a></li>
- <li><a href="http://www.w3.org/2001/03/xml.xsd">
- http://www.w3.org/2001/03/xml.xsd</a></li>
- </ul>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-
-</xs:schema>
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-use Symfony\Component\Config\Resource\ResourceInterface;
-
-/**
- * MessageCatalogue.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface
-{
- private $messages = array();
- private $metadata = array();
- private $resources = array();
- private $locale;
- private $fallbackCatalogue;
- private $parent;
-
- /**
- * Constructor.
- *
- * @param string $locale The locale
- * @param array $messages An array of messages classified by domain
- *
- * @api
- */
- public function __construct($locale, array $messages = array())
- {
- $this->locale = $locale;
- $this->messages = $messages;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function getLocale()
- {
- return $this->locale;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function getDomains()
- {
- return array_keys($this->messages);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function all($domain = null)
- {
- if (null === $domain) {
- return $this->messages;
- }
-
- return isset($this->messages[$domain]) ? $this->messages[$domain] : array();
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function set($id, $translation, $domain = 'messages')
- {
- $this->add(array($id => $translation), $domain);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function has($id, $domain = 'messages')
- {
- if (isset($this->messages[$domain][$id])) {
- return true;
- }
-
- if (null !== $this->fallbackCatalogue) {
- return $this->fallbackCatalogue->has($id, $domain);
- }
-
- return false;
- }
-
- /**
- * {@inheritdoc}
- */
- public function defines($id, $domain = 'messages')
- {
- return isset($this->messages[$domain][$id]);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function get($id, $domain = 'messages')
- {
- if (isset($this->messages[$domain][$id])) {
- return $this->messages[$domain][$id];
- }
-
- if (null !== $this->fallbackCatalogue) {
- return $this->fallbackCatalogue->get($id, $domain);
- }
-
- return $id;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function replace($messages, $domain = 'messages')
- {
- $this->messages[$domain] = array();
-
- $this->add($messages, $domain);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function add($messages, $domain = 'messages')
- {
- if (!isset($this->messages[$domain])) {
- $this->messages[$domain] = $messages;
- } else {
- $this->messages[$domain] = array_replace($this->messages[$domain], $messages);
- }
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function addCatalogue(MessageCatalogueInterface $catalogue)
- {
- if ($catalogue->getLocale() !== $this->locale) {
- throw new \LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s"', $catalogue->getLocale(), $this->locale));
- }
-
- foreach ($catalogue->all() as $domain => $messages) {
- $this->add($messages, $domain);
- }
-
- foreach ($catalogue->getResources() as $resource) {
- $this->addResource($resource);
- }
-
- if ($catalogue instanceof MetadataAwareInterface) {
- $metadata = $catalogue->getMetadata('', '');
- $this->addMetadata($metadata);
- }
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function addFallbackCatalogue(MessageCatalogueInterface $catalogue)
- {
- // detect circular references
- $c = $this;
- do {
- if ($c->getLocale() === $catalogue->getLocale()) {
- throw new \LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
- }
- } while ($c = $c->parent);
-
- $catalogue->parent = $this;
- $this->fallbackCatalogue = $catalogue;
-
- foreach ($catalogue->getResources() as $resource) {
- $this->addResource($resource);
- }
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function getFallbackCatalogue()
- {
- return $this->fallbackCatalogue;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function getResources()
- {
- return array_values($this->resources);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function addResource(ResourceInterface $resource)
- {
- $this->resources[$resource->__toString()] = $resource;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getMetadata($key = '', $domain = 'messages')
- {
- if ('' == $domain) {
- return $this->metadata;
- }
-
- if (isset($this->metadata[$domain])) {
- if ('' == $key) {
- return $this->metadata[$domain];
- }
-
- if (isset($this->metadata[$domain][$key])) {
- return $this->metadata[$domain][$key];
- }
- }
-
- return null;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setMetadata($key, $value, $domain = 'messages')
- {
- $this->metadata[$domain][$key] = $value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function deleteMetadata($key = '', $domain = 'messages')
- {
- if ('' == $domain) {
- $this->metadata = array();
- } elseif ('' == $key) {
- unset($this->metadata[$domain]);
- } else {
- unset($this->metadata[$domain][$key]);
- }
- }
-
- /**
- * Adds current values with the new values.
- *
- * @param array $values Values to add
- */
- private function addMetadata(array $values)
- {
- foreach ($values as $domain => $keys) {
- foreach ($keys as $key => $value) {
- $this->setMetadata($key, $value, $domain);
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-use Symfony\Component\Config\Resource\ResourceInterface;
-
-/**
- * MessageCatalogueInterface.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-interface MessageCatalogueInterface
-{
- /**
- * Gets the catalogue locale.
- *
- * @return string The locale
- *
- * @api
- */
- public function getLocale();
-
- /**
- * Gets the domains.
- *
- * @return array An array of domains
- *
- * @api
- */
- public function getDomains();
-
- /**
- * Gets the messages within a given domain.
- *
- * If $domain is null, it returns all messages.
- *
- * @param string $domain The domain name
- *
- * @return array An array of messages
- *
- * @api
- */
- public function all($domain = null);
-
- /**
- * Sets a message translation.
- *
- * @param string $id The message id
- * @param string $translation The messages translation
- * @param string $domain The domain name
- *
- * @api
- */
- public function set($id, $translation, $domain = 'messages');
-
- /**
- * Checks if a message has a translation.
- *
- * @param string $id The message id
- * @param string $domain The domain name
- *
- * @return Boolean true if the message has a translation, false otherwise
- *
- * @api
- */
- public function has($id, $domain = 'messages');
-
- /**
- * Checks if a message has a translation (it does not take into account the fallback mechanism).
- *
- * @param string $id The message id
- * @param string $domain The domain name
- *
- * @return Boolean true if the message has a translation, false otherwise
- *
- * @api
- */
- public function defines($id, $domain = 'messages');
-
- /**
- * Gets a message translation.
- *
- * @param string $id The message id
- * @param string $domain The domain name
- *
- * @return string The message translation
- *
- * @api
- */
- public function get($id, $domain = 'messages');
-
- /**
- * Sets translations for a given domain.
- *
- * @param array $messages An array of translations
- * @param string $domain The domain name
- *
- * @api
- */
- public function replace($messages, $domain = 'messages');
-
- /**
- * Adds translations for a given domain.
- *
- * @param array $messages An array of translations
- * @param string $domain The domain name
- *
- * @api
- */
- public function add($messages, $domain = 'messages');
-
- /**
- * Merges translations from the given Catalogue into the current one.
- *
- * The two catalogues must have the same locale.
- *
- * @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
- *
- * @api
- */
- public function addCatalogue(MessageCatalogueInterface $catalogue);
-
- /**
- * Merges translations from the given Catalogue into the current one
- * only when the translation does not exist.
- *
- * This is used to provide default translations when they do not exist for the current locale.
- *
- * @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
- *
- * @api
- */
- public function addFallbackCatalogue(MessageCatalogueInterface $catalogue);
-
- /**
- * Gets the fallback catalogue.
- *
- * @return MessageCatalogueInterface|null A MessageCatalogueInterface instance or null when no fallback has been set
- *
- * @api
- */
- public function getFallbackCatalogue();
-
- /**
- * Returns an array of resources loaded to build this collection.
- *
- * @return ResourceInterface[] An array of resources
- *
- * @api
- */
- public function getResources();
-
- /**
- * Adds a resource for this collection.
- *
- * @param ResourceInterface $resource A resource instance
- *
- * @api
- */
- public function addResource(ResourceInterface $resource);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-/**
- * MessageSelector.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class MessageSelector
-{
- /**
- * Given a message with different plural translations separated by a
- * pipe (|), this method returns the correct portion of the message based
- * on the given number, locale and the pluralization rules in the message
- * itself.
- *
- * The message supports two different types of pluralization rules:
- *
- * interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
- * indexed: There is one apple|There are %count% apples
- *
- * The indexed solution can also contain labels (e.g. one: There is one apple).
- * This is purely for making the translations more clear - it does not
- * affect the functionality.
- *
- * The two methods can also be mixed:
- * {0} There are no apples|one: There is one apple|more: There are %count% apples
- *
- * @param string $message The message being translated
- * @param integer $number The number of items represented for the message
- * @param string $locale The locale to use for choosing
- *
- * @return string
- *
- * @throws \InvalidArgumentException
- *
- * @api
- */
- public function choose($message, $number, $locale)
- {
- $parts = explode('|', $message);
- $explicitRules = array();
- $standardRules = array();
- foreach ($parts as $part) {
- $part = trim($part);
-
- if (preg_match('/^(?P<interval>'.Interval::getIntervalRegexp().')\s*(?P<message>.*?)$/x', $part, $matches)) {
- $explicitRules[$matches['interval']] = $matches['message'];
- } elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
- $standardRules[] = $matches[1];
- } else {
- $standardRules[] = $part;
- }
- }
-
- // try to match an explicit rule, then fallback to the standard ones
- foreach ($explicitRules as $interval => $m) {
- if (Interval::test($number, $interval)) {
- return $m;
- }
- }
-
- $position = PluralizationRules::get($number, $locale);
- if (!isset($standardRules[$position])) {
- throw new \InvalidArgumentException(sprintf('Unable to choose a translation for "%s" with locale "%s". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $message, $locale));
- }
-
- return $standardRules[$position];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-/**
- * MetadataAwareInterface.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface MetadataAwareInterface
-{
- /**
- * Gets metadata for the given domain and key.
- *
- * Passing an empty domain will return an array with all metadata indexed by
- * domain and then by key. Passing an empty key will return an array with all
- * metadata for the given domain.
- *
- * @param string $domain The domain name
- * @param string $key The key
- *
- * @return mixed The value that was set or an array with the domains/keys or null
- */
- public function getMetadata($key = '', $domain = 'messages');
-
- /**
- * Adds metadata to a message domain.
- *
- * @param string $key The key
- * @param mixed $value The value
- * @param string $domain The domain name
- */
- public function setMetadata($key, $value, $domain = 'messages');
-
- /**
- * Deletes metadata for the given key and domain.
- *
- * Passing an empty domain will delete all metadata. Passing an empty key will
- * delete all metadata for the given domain.
- *
- * @param string $domain The domain name
- * @param string $key The key
- */
- public function deleteMetadata($key = '', $domain = 'messages');
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-/**
- * Returns the plural rules for a given locale.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class PluralizationRules
-{
- // @codeCoverageIgnoreStart
- private static $rules = array();
-
- /**
- * Returns the plural position to use for the given locale and number.
- *
- * @param integer $number The number
- * @param string $locale The locale
- *
- * @return integer The plural position
- */
- public static function get($number, $locale)
- {
- if ("pt_BR" == $locale) {
- // temporary set a locale for brazilian
- $locale = "xbr";
- }
-
- if (strlen($locale) > 3) {
- $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
- }
-
- if (isset(self::$rules[$locale])) {
- $return = call_user_func(self::$rules[$locale], $number);
-
- if (!is_int($return) || $return < 0) {
- return 0;
- }
-
- return $return;
- }
-
- /*
- * The plural rules are derived from code of the Zend Framework (2010-09-25),
- * which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
- * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
- */
- switch ($locale) {
- case 'bo':
- case 'dz':
- case 'id':
- case 'ja':
- case 'jv':
- case 'ka':
- case 'km':
- case 'kn':
- case 'ko':
- case 'ms':
- case 'th':
- case 'tr':
- case 'vi':
- case 'zh':
- return 0;
- break;
-
- case 'af':
- case 'az':
- case 'bn':
- case 'bg':
- case 'ca':
- case 'da':
- case 'de':
- case 'el':
- case 'en':
- case 'eo':
- case 'es':
- case 'et':
- case 'eu':
- case 'fa':
- case 'fi':
- case 'fo':
- case 'fur':
- case 'fy':
- case 'gl':
- case 'gu':
- case 'ha':
- case 'he':
- case 'hu':
- case 'is':
- case 'it':
- case 'ku':
- case 'lb':
- case 'ml':
- case 'mn':
- case 'mr':
- case 'nah':
- case 'nb':
- case 'ne':
- case 'nl':
- case 'nn':
- case 'no':
- case 'om':
- case 'or':
- case 'pa':
- case 'pap':
- case 'ps':
- case 'pt':
- case 'so':
- case 'sq':
- case 'sv':
- case 'sw':
- case 'ta':
- case 'te':
- case 'tk':
- case 'ur':
- case 'zu':
- return ($number == 1) ? 0 : 1;
-
- case 'am':
- case 'bh':
- case 'fil':
- case 'fr':
- case 'gun':
- case 'hi':
- case 'ln':
- case 'mg':
- case 'nso':
- case 'xbr':
- case 'ti':
- case 'wa':
- return (($number == 0) || ($number == 1)) ? 0 : 1;
-
- case 'be':
- case 'bs':
- case 'hr':
- case 'ru':
- case 'sr':
- case 'uk':
- return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
-
- case 'cs':
- case 'sk':
- return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2);
-
- case 'ga':
- return ($number == 1) ? 0 : (($number == 2) ? 1 : 2);
-
- case 'lt':
- return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
-
- case 'sl':
- return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3));
-
- case 'mk':
- return ($number % 10 == 1) ? 0 : 1;
-
- case 'mt':
- return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3));
-
- case 'lv':
- return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2);
-
- case 'pl':
- return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2);
-
- case 'cy':
- return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3));
-
- case 'ro':
- return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
-
- case 'ar':
- return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number >= 3) && ($number <= 10)) ? 3 : ((($number >= 11) && ($number <= 99)) ? 4 : 5))));
-
- default:
- return 0;
- }
- }
-
- /**
- * Overrides the default plural rule for a given locale.
- *
- * @param string $rule A PHP callable
- * @param string $locale The locale
- *
- * @return null
- *
- * @throws \LogicException
- */
- public static function set($rule, $locale)
- {
- if ("pt_BR" == $locale) {
- // temporary set a locale for brazilian
- $locale = "xbr";
- }
-
- if (strlen($locale) > 3) {
- $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
- }
-
- if (!is_callable($rule)) {
- throw new \LogicException('The given rule can not be called');
- }
-
- self::$rules[$locale] = $rule;
- }
-
- // @codeCoverageIgnoreEnd
-}
+++ /dev/null
-Translation Component
-=====================
-
-Translation provides tools for loading translation files and generating
-translated strings from these including support for pluralization.
-
- use Symfony\Component\Translation\Translator;
- use Symfony\Component\Translation\MessageSelector;
- use Symfony\Component\Translation\Loader\ArrayLoader;
-
- $translator = new Translator('fr_FR', new MessageSelector());
- $translator->setFallbackLocales(array('fr'));
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array(
- 'Hello World!' => 'Bonjour',
- ), 'fr');
-
- echo $translator->trans('Hello World!')."\n";
-
-Resources
----------
-
-Silex integration:
-
-https://github.com/fabpot/Silex/blob/master/src/Silex/Provider/TranslationServiceProvider.php
-
-Documentation:
-
-http://symfony.com/doc/2.3/book/translation.html
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/Translation/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Test\Catalogue;
-
-use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\MessageCatalogueInterface;
-
-abstract class AbstractOperationTest extends TestCase
-{
- public function testGetEmptyDomains()
- {
- $this->assertEquals(
- array(),
- $this->createOperation(
- new MessageCatalogue('en'),
- new MessageCatalogue('en')
- )->getDomains()
- );
- }
-
- public function testGetMergedDomains()
- {
- $this->assertEquals(
- array('a', 'b', 'c'),
- $this->createOperation(
- new MessageCatalogue('en', array('a' => array(), 'b' => array())),
- new MessageCatalogue('en', array('b' => array(), 'c' => array()))
- )->getDomains()
- );
- }
-
- public function testGetMessagesFromUnknownDomain()
- {
- $this->setExpectedException('InvalidArgumentException');
- $this->createOperation(
- new MessageCatalogue('en'),
- new MessageCatalogue('en')
- )->getMessages('domain');
- }
-
- public function testGetEmptyMessages()
- {
- $this->assertEquals(
- array(),
- $this->createOperation(
- new MessageCatalogue('en', array('a' => array())),
- new MessageCatalogue('en')
- )->getMessages('a')
- );
- }
-
- public function testGetEmptyResult()
- {
- $this->assertEquals(
- new MessageCatalogue('en'),
- $this->createOperation(
- new MessageCatalogue('en'),
- new MessageCatalogue('en')
- )->getResult()
- );
- }
-
- abstract protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Test\Catalogue;
-
-use Symfony\Component\Translation\Catalogue\DiffOperation;
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\MessageCatalogueInterface;
-
-class DiffOperationTest extends AbstractOperationTest
-{
- public function testGetMessagesFromSingleDomain()
- {
- $operation = $this->createOperation(
- new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
- new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
- );
-
- $this->assertEquals(
- array('a' => 'old_a', 'c' => 'new_c'),
- $operation->getMessages('messages')
- );
-
- $this->assertEquals(
- array('c' => 'new_c'),
- $operation->getNewMessages('messages')
- );
-
- $this->assertEquals(
- array('b' => 'old_b'),
- $operation->getObsoleteMessages('messages')
- );
- }
-
- public function testGetResultFromSingleDomain()
- {
- $this->assertEquals(
- new MessageCatalogue('en', array(
- 'messages' => array('a' => 'old_a', 'c' => 'new_c')
- )),
- $this->createOperation(
- new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
- new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
- )->getResult()
- );
- }
-
- protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
- {
- return new DiffOperation($source, $target);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Test\Catalogue;
-
-use Symfony\Component\Translation\Catalogue\MergeOperation;
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\MessageCatalogueInterface;
-
-class MergeOperationTest extends AbstractOperationTest
-{
- public function testGetMessagesFromSingleDomain()
- {
- $operation = $this->createOperation(
- new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
- new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
- );
-
- $this->assertEquals(
- array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'),
- $operation->getMessages('messages')
- );
-
- $this->assertEquals(
- array('c' => 'new_c'),
- $operation->getNewMessages('messages')
- );
-
- $this->assertEquals(
- array(),
- $operation->getObsoleteMessages('messages')
- );
- }
-
- public function testGetResultFromSingleDomain()
- {
- $this->assertEquals(
- new MessageCatalogue('en', array(
- 'messages' => array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c')
- )),
- $this->createOperation(
- new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
- new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
- )->getResult()
- );
- }
-
- protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
- {
- return new MergeOperation($source, $target);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\CsvFileDumper;
-
-class CsvFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar', 'bar' => 'foo
-foo', 'foo;foo' => 'bar'));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new CsvFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
-
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/valid.csv'), file_get_contents($tempDir.'/messages.en.csv'));
-
- unlink($tempDir.'/messages.en.csv');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\IcuResFileDumper;
-
-class IcuResFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- if (!extension_loaded('mbstring')) {
- $this->markTestSkipped('This test requires mbstring to work.');
- }
-
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar'));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new IcuResFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
-
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resourcebundle/res/en.res'), file_get_contents($tempDir.'/messages/en.res'));
-
- unlink($tempDir.'/messages/en.res');
- rmdir($tempDir.'/messages');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\IniFileDumper;
-
-class IniFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar'));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new IniFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
-
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.ini'), file_get_contents($tempDir.'/messages.en.ini'));
-
- unlink($tempDir.'/messages.en.ini');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\MoFileDumper;
-
-class MoFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar'));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new MoFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.mo'), file_get_contents($tempDir.'/messages.en.mo'));
-
- unlink($tempDir.'/messages.en.mo');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\PhpFileDumper;
-
-class PhpFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar'));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new PhpFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
-
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.php'), file_get_contents($tempDir.'/messages.en.php'));
-
- unlink($tempDir.'/messages.en.php');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\PoFileDumper;
-
-class PoFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar'));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new PoFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.po'), file_get_contents($tempDir.'/messages.en.po'));
-
- unlink($tempDir.'/messages.en.po');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\QtFileDumper;
-
-class QtFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar'), 'resources');
-
- $tempDir = sys_get_temp_dir();
- $dumper = new QtFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
-
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.ts'), file_get_contents($tempDir.'/resources.en.ts'));
-
- unlink($tempDir.'/resources.en.ts');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\XliffFileDumper;
-
-class XliffFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar', 'key' => ''));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new XliffFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
-
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources-clean.xlf'), file_get_contents($tempDir.'/messages.en.xlf'));
-
- unlink($tempDir.'/messages.en.xlf');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Dumper;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\YamlFileDumper;
-
-class YamlFileDumperTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Yaml\Yaml')) {
- $this->markTestSkipped('The "Yaml" component is not available');
- }
- }
-
- public function testDump()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->add(array('foo' => 'bar'));
-
- $tempDir = sys_get_temp_dir();
- $dumper = new YamlFileDumper();
- $dumper->dump($catalogue, array('path' => $tempDir));
-
- $this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.yml'), file_get_contents($tempDir.'/messages.en.yml'));
-
- unlink($tempDir.'/messages.en.yml');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests;
-
-use Symfony\Component\Translation\IdentityTranslator;
-use Symfony\Component\Translation\MessageSelector;
-
-class IdentityTranslatorTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider getTransTests
- */
- public function testTrans($expected, $id, $parameters)
- {
- $translator = new IdentityTranslator(new MessageSelector());
-
- $this->assertEquals($expected, $translator->trans($id, $parameters));
- }
-
- /**
- * @dataProvider getTransChoiceTests
- */
- public function testTransChoice($expected, $id, $number, $parameters)
- {
- $translator = new IdentityTranslator(new MessageSelector());
-
- $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters));
- }
-
- // noop
- public function testGetSetLocale()
- {
- $translator = new IdentityTranslator(new MessageSelector());
- $translator->setLocale('en');
- $translator->getLocale();
- }
-
- public function getTransTests()
- {
- return array(
- array('Symfony2 is great!', 'Symfony2 is great!', array()),
- array('Symfony2 is awesome!', 'Symfony2 is %what%!', array('%what%' => 'awesome')),
- );
- }
-
- public function getTransChoiceTests()
- {
- return array(
- array('There is 10 apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10, array('%count%' => 10)),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests;
-
-use Symfony\Component\Translation\Interval;
-
-class IntervalTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider getTests
- */
- public function testTest($expected, $number, $interval)
- {
- $this->assertEquals($expected, Interval::test($number, $interval));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testTestException()
- {
- Interval::test(1, 'foobar');
- }
-
- public function getTests()
- {
- return array(
- array(true, 3, '{1,2, 3 ,4}'),
- array(false, 10, '{1,2, 3 ,4}'),
- array(false, 3, '[1,2]'),
- array(true, 1, '[1,2]'),
- array(true, 2, '[1,2]'),
- array(false, 1, ']1,2['),
- array(false, 2, ']1,2['),
- array(true, log(0), '[-Inf,2['),
- array(true, -log(0), '[-2,+Inf]'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\CsvFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class CsvFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new CsvFileLoader();
- $resource = __DIR__.'/../fixtures/resources.csv';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- public function testLoadDoesNothingIfEmpty()
- {
- $loader = new CsvFileLoader();
- $resource = __DIR__.'/../fixtures/empty.csv';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array(), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new CsvFileLoader();
- $resource = __DIR__.'/../fixtures/not-exists.csv';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadNonLocalResource()
- {
- $loader = new CsvFileLoader();
- $resource = 'http://example.com/resources.csv';
- $loader->load($resource, 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\IcuDatFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class IcuDatFileLoaderTest extends LocalizedTestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- if (!extension_loaded('intl')) {
- $this->markTestSkipped('This test requires intl extension to work.');
- }
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadInvalidResource()
- {
- $loader = new IcuDatFileLoader();
- $loader->load(__DIR__.'/../fixtures/resourcebundle/corrupted/resources', 'es', 'domain2');
- }
-
- public function testDatEnglishLoad()
- {
- // bundled resource is build using pkgdata command which at least in ICU 4.2 comes in extremely! buggy form
- // you must specify an temporary build directory which is not the same as current directory and
- // MUST reside on the same partition. pkgdata -p resources -T /srv -d.packagelist.txt
- $loader = new IcuDatFileLoader();
- $resource = __DIR__.'/../fixtures/resourcebundle/dat/resources';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('symfony' => 'Symfony 2 is great'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource.'.dat')), $catalogue->getResources());
- }
-
- public function testDatFrenchLoad()
- {
- $loader = new IcuDatFileLoader();
- $resource = __DIR__.'/../fixtures/resourcebundle/dat/resources';
- $catalogue = $loader->load($resource, 'fr', 'domain1');
-
- $this->assertEquals(array('symfony' => 'Symfony 2 est génial'), $catalogue->all('domain1'));
- $this->assertEquals('fr', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource.'.dat')), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new IcuDatFileLoader();
- $loader->load(__DIR__.'/../fixtures/non-existing.txt', 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\IcuResFileLoader;
-use Symfony\Component\Config\Resource\DirectoryResource;
-
-class IcuResFileLoaderTest extends LocalizedTestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- if (!extension_loaded('intl')) {
- $this->markTestSkipped('This test requires intl extension to work.');
- }
- }
-
- public function testLoad()
- {
- // resource is build using genrb command
- $loader = new IcuResFileLoader();
- $resource = __DIR__.'/../fixtures/resourcebundle/res';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new DirectoryResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new IcuResFileLoader();
- $loader->load(__DIR__.'/../fixtures/non-existing.txt', 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadInvalidResource()
- {
- $loader = new IcuResFileLoader();
- $loader->load(__DIR__.'/../fixtures/resourcebundle/corrupted', 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\IniFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class IniFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new IniFileLoader();
- $resource = __DIR__.'/../fixtures/resources.ini';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- public function testLoadDoesNothingIfEmpty()
- {
- $loader = new IniFileLoader();
- $resource = __DIR__.'/../fixtures/empty.ini';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array(), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new IniFileLoader();
- $resource = __DIR__.'/../fixtures/non-existing.ini';
- $loader->load($resource, 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-abstract class LocalizedTestCase extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!extension_loaded('intl')) {
- $this->markTestSkipped('The "intl" extension is not available');
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\MoFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class MoFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new MoFileLoader();
- $resource = __DIR__.'/../fixtures/resources.mo';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- public function testLoadPlurals()
- {
- $loader = new MoFileLoader();
- $resource = __DIR__.'/../fixtures/plurals.mo';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar', 'foos' => '{0} bar|{1} bars'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new MoFileLoader();
- $resource = __DIR__.'/../fixtures/non-existing.mo';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadInvalidResource()
- {
- $loader = new MoFileLoader();
- $resource = __DIR__.'/../fixtures/empty.mo';
- $loader->load($resource, 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\PhpFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class PhpFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new PhpFileLoader();
- $resource = __DIR__.'/../fixtures/resources.php';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new PhpFileLoader();
- $resource = __DIR__.'/../fixtures/non-existing.php';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadThrowsAnExceptionIfFileNotLocal()
- {
- $loader = new PhpFileLoader();
- $resource = 'http://example.com/resources.php';
- $loader->load($resource, 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\PoFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class PoFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new PoFileLoader();
- $resource = __DIR__.'/../fixtures/resources.po';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- public function testLoadPlurals()
- {
- $loader = new PoFileLoader();
- $resource = __DIR__.'/../fixtures/plurals.po';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar', 'foos' => 'bar|bars'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- public function testLoadDoesNothingIfEmpty()
- {
- $loader = new PoFileLoader();
- $resource = __DIR__.'/../fixtures/empty.po';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array(), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new PoFileLoader();
- $resource = __DIR__.'/../fixtures/non-existing.po';
- $loader->load($resource, 'en', 'domain1');
- }
-
- public function testLoadEmptyTranslation()
- {
- $loader = new PoFileLoader();
- $resource = __DIR__.'/../fixtures/empty-translation.po';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => ''), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\QtFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class QtFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new QtFileLoader();
- $resource = __DIR__.'/../fixtures/resources.ts';
- $catalogue = $loader->load($resource, 'en', 'resources');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('resources'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new QtFileLoader();
- $resource = __DIR__.'/../fixtures/non-existing.ts';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadNonLocalResource()
- {
- $loader = new QtFileLoader();
- $resource = 'http://domain1.com/resources.ts';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadInvalidResource()
- {
- $loader = new QtFileLoader();
- $resource = __DIR__.'/../fixtures/invalid-xml-resources.xlf';
- $loader->load($resource, 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\XliffFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new XliffFileLoader();
- $resource = __DIR__.'/../fixtures/resources.xlf';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- public function testLoadWithResname()
- {
- $loader = new XliffFileLoader();
- $catalogue = $loader->load(__DIR__.'/../fixtures/resname.xlf', 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo'), $catalogue->all('domain1'));
- }
-
- public function testIncompleteResource()
- {
- $loader = new XliffFileLoader();
- $catalogue = $loader->load(__DIR__.'/../fixtures/resources.xlf', 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar', 'key' => '', 'test' => 'with'), $catalogue->all('domain1'));
- $this->assertFalse($catalogue->has('extra', 'domain1'));
- }
-
- public function testEncoding()
- {
- if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
- $this->markTestSkipped('The iconv and mbstring extensions are not available.');
- }
-
- $loader = new XliffFileLoader();
- $catalogue = $loader->load(__DIR__.'/../fixtures/encoding.xlf', 'en', 'domain1');
-
- $this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1'));
- $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1'));
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadInvalidResource()
- {
- $loader = new XliffFileLoader();
- $loader->load(__DIR__.'/../fixtures/resources.php', 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadResourceDoesNotValidate()
- {
- $loader = new XliffFileLoader();
- $loader->load(__DIR__.'/../fixtures/non-valid.xlf', 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new XliffFileLoader();
- $resource = __DIR__.'/../fixtures/non-existing.xlf';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadThrowsAnExceptionIfFileNotLocal()
- {
- $loader = new XliffFileLoader();
- $resource = 'http://example.com/resources.xlf';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- * @expectedExceptionMessage Document types are not allowed.
- */
- public function testDocTypeIsNotAllowed()
- {
- $loader = new XliffFileLoader();
- $loader->load(__DIR__.'/../fixtures/withdoctype.xlf', 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests\Loader;
-
-use Symfony\Component\Translation\Loader\YamlFileLoader;
-use Symfony\Component\Config\Resource\FileResource;
-
-class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- if (!class_exists('Symfony\Component\Yaml\Yaml')) {
- $this->markTestSkipped('The "Yaml" component is not available');
- }
- }
-
- public function testLoad()
- {
- $loader = new YamlFileLoader();
- $resource = __DIR__.'/../fixtures/resources.yml';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- public function testLoadDoesNothingIfEmpty()
- {
- $loader = new YamlFileLoader();
- $resource = __DIR__.'/../fixtures/empty.yml';
- $catalogue = $loader->load($resource, 'en', 'domain1');
-
- $this->assertEquals(array(), $catalogue->all('domain1'));
- $this->assertEquals('en', $catalogue->getLocale());
- $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testLoadNonExistingResource()
- {
- $loader = new YamlFileLoader();
- $resource = __DIR__.'/../fixtures/non-existing.yml';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadThrowsAnExceptionIfFileNotLocal()
- {
- $loader = new YamlFileLoader();
- $resource = 'http://example.com/resources.yml';
- $loader->load($resource, 'en', 'domain1');
- }
-
- /**
- * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
- */
- public function testLoadThrowsAnExceptionIfNotAnArray()
- {
- $loader = new YamlFileLoader();
- $resource = __DIR__.'/../fixtures/non-valid.yml';
- $loader->load($resource, 'en', 'domain1');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests;
-
-use Symfony\Component\Translation\MessageCatalogue;
-
-class MessageCatalogueTest extends \PHPUnit_Framework_TestCase
-{
- public function testGetLocale()
- {
- $catalogue = new MessageCatalogue('en');
-
- $this->assertEquals('en', $catalogue->getLocale());
- }
-
- public function testGetDomains()
- {
- $catalogue = new MessageCatalogue('en', array('domain1' => array(), 'domain2' => array()));
-
- $this->assertEquals(array('domain1', 'domain2'), $catalogue->getDomains());
- }
-
- public function testAll()
- {
- $catalogue = new MessageCatalogue('en', $messages = array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
-
- $this->assertEquals(array('foo' => 'foo'), $catalogue->all('domain1'));
- $this->assertEquals(array(), $catalogue->all('domain88'));
- $this->assertEquals($messages, $catalogue->all());
- }
-
- public function testHas()
- {
- $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
-
- $this->assertTrue($catalogue->has('foo', 'domain1'));
- $this->assertFalse($catalogue->has('bar', 'domain1'));
- $this->assertFalse($catalogue->has('foo', 'domain88'));
- }
-
- public function testGetSet()
- {
- $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
- $catalogue->set('foo1', 'foo1', 'domain1');
-
- $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
- $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
- }
-
- public function testAdd()
- {
- $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
- $catalogue->add(array('foo1' => 'foo1'), 'domain1');
-
- $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
- $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
-
- $catalogue->add(array('foo' => 'bar'), 'domain1');
- $this->assertEquals('bar', $catalogue->get('foo', 'domain1'));
- $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
-
- $catalogue->add(array('foo' => 'bar'), 'domain88');
- $this->assertEquals('bar', $catalogue->get('foo', 'domain88'));
- }
-
- public function testReplace()
- {
- $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
- $catalogue->replace($messages = array('foo1' => 'foo1'), 'domain1');
-
- $this->assertEquals($messages, $catalogue->all('domain1'));
- }
-
- public function testAddCatalogue()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- $r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
- $r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
-
- $r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
- $r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
-
- $catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
- $catalogue->addResource($r);
-
- $catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo1' => 'foo1')));
- $catalogue1->addResource($r1);
-
- $catalogue->addCatalogue($catalogue1);
-
- $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
- $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
-
- $this->assertEquals(array($r, $r1), $catalogue->getResources());
- }
-
- public function testAddFallbackCatalogue()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- $r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
- $r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
-
- $r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
- $r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
-
- $catalogue = new MessageCatalogue('en_US', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
- $catalogue->addResource($r);
-
- $catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1')));
- $catalogue1->addResource($r1);
-
- $catalogue->addFallbackCatalogue($catalogue1);
-
- $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
- $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
-
- $this->assertEquals(array($r, $r1), $catalogue->getResources());
- }
-
- /**
- * @expectedException LogicException
- */
- public function testAddFallbackCatalogueWithCircularReference()
- {
- $main = new MessageCatalogue('en_US');
- $fallback = new MessageCatalogue('fr_FR');
-
- $fallback->addFallbackCatalogue($main);
- $main->addFallbackCatalogue($fallback);
- }
-
- /**
- * @expectedException LogicException
- */
- public function testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->addCatalogue(new MessageCatalogue('fr', array()));
- }
-
- public function testGetAddResource()
- {
- if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
- $this->markTestSkipped('The "Config" component is not available');
- }
-
- $catalogue = new MessageCatalogue('en');
- $r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
- $r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
- $catalogue->addResource($r);
- $catalogue->addResource($r);
- $r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
- $r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
- $catalogue->addResource($r1);
-
- $this->assertEquals(array($r, $r1), $catalogue->getResources());
- }
-
- public function testMetadataDelete()
- {
- $catalogue = new MessageCatalogue('en');
- $this->assertEquals(array(), $catalogue->getMetadata('', ''), 'Metadata is empty');
- $catalogue->deleteMetadata('key', 'messages');
- $catalogue->deleteMetadata('', 'messages');
- $catalogue->deleteMetadata();
- }
-
- public function testMetadataSetGetDelete()
- {
- $catalogue = new MessageCatalogue('en');
- $catalogue->setMetadata('key', 'value');
- $this->assertEquals('value', $catalogue->getMetadata('key', 'messages'), "Metadata 'key' = 'value'");
-
- $catalogue->setMetadata('key2', array());
- $this->assertEquals(array(), $catalogue->getMetadata('key2', 'messages'), 'Metadata key2 is array');
-
- $catalogue->deleteMetadata('key2', 'messages');
- $this->assertEquals(null, $catalogue->getMetadata('key2', 'messages'), 'Metadata key2 should is deleted.');
-
- $catalogue->deleteMetadata('key2', 'domain');
- $this->assertEquals(null, $catalogue->getMetadata('key2', 'domain'), 'Metadata key2 should is deleted.');
- }
-
- public function testMetadataMerge()
- {
- $cat1 = new MessageCatalogue('en');
- $cat1->setMetadata('a', 'b');
- $this->assertEquals(array('messages' => array('a' => 'b')), $cat1->getMetadata('', ''), 'Cat1 contains messages metadata.');
-
- $cat2 = new MessageCatalogue('en');
- $cat2->setMetadata('b', 'c', 'domain');
- $this->assertEquals(array('domain' => array('b' => 'c')), $cat2->getMetadata('', ''), 'Cat2 contains domain metadata.');
-
- $cat1->addCatalogue($cat2);
- $this->assertEquals(array('messages' => array('a' => 'b'), 'domain' => array('b' => 'c')), $cat1->getMetadata('', ''), 'Cat1 contains merged metadata.');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests;
-
-use Symfony\Component\Translation\MessageSelector;
-
-class MessageSelectorTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider getChooseTests
- */
- public function testChoose($expected, $id, $number)
- {
- $selector = new MessageSelector();
-
- $this->assertEquals($expected, $selector->choose($id, $number, 'en'));
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- public function testChooseWhenNoEnoughChoices()
- {
- $selector = new MessageSelector();
-
- $selector->choose('foo', 10, 'en');
- }
-
- public function getChooseTests()
- {
- return array(
- array('There is no apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
- array('There is no apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
- array('There is no apples', '{0}There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 0),
-
- array('There is one apple', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 1),
-
- array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10),
- array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf]There is %count% apples', 10),
- array('There is %count% apples', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', 10),
-
- array('There is %count% apples', 'There is one apple|There is %count% apples', 0),
- array('There is one apple', 'There is one apple|There is %count% apples', 1),
- array('There is %count% apples', 'There is one apple|There is %count% apples', 10),
-
- array('There is %count% apples', 'one: There is one apple|more: There is %count% apples', 0),
- array('There is one apple', 'one: There is one apple|more: There is %count% apples', 1),
- array('There is %count% apples', 'one: There is one apple|more: There is %count% apples', 10),
-
- array('There is no apples', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 0),
- array('There is one apple', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 1),
- array('There is %count% apples', '{0} There is no apples|one: There is one apple|more: There is %count% apples', 10),
-
- array('', '{0}|{1} There is one apple|]1,Inf] There is %count% apples', 0),
- array('', '{0} There is no apples|{1}|]1,Inf] There is %count% apples', 1),
-
- // Indexed only tests which are Gettext PoFile* compatible strings.
- array('There are %count% apples', 'There is one apple|There are %count% apples', 0),
- array('There is one apple', 'There is one apple|There are %count% apples', 1),
- array('There are %count% apples', 'There is one apple|There are %count% apples', 2),
-
- // Tests for float numbers
- array('There is almost one apple', '{0} There is no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7),
- array('There is one apple', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1),
- array('There is more than one apple', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7),
- array('There is no apples', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0),
- array('There is no apples', '{0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0),
- array('There is no apples', '{0.0} There is no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests;
-
-use Symfony\Component\Translation\PluralizationRules;
-
-/**
- * Test should cover all languages mentioned on http://translate.sourceforge.net/wiki/l10n/pluralforms
- * and Plural forms mentioned on http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms
- *
- * See also https://developer.mozilla.org/en/Localization_and_Plurals which mentions 15 rules having a maximum of 6 forms.
- * The mozilla code is also interesting to check for.
- *
- * As mentioned by chx http://drupal.org/node/1273968 we can cover all by testing number from 0 to 199
- *
- * The goal to cover all languages is to far fetched so this test case is smaller.
- *
- * @author Clemens Tolboom clemens@build2be.nl
- */
-class PluralizationRulesTest extends \PHPUnit_Framework_TestCase
-{
-
- /**
- * We test failed langcode here.
- *
- * TODO: The languages mentioned in the data provide need to get fixed somehow within PluralizationRules.
- *
- * @dataProvider failingLangcodes
- */
- public function testFailedLangcodes($nplural, $langCodes)
- {
- $matrix = $this->generateTestData($nplural, $langCodes);
- $this->validateMatrix($nplural, $matrix, false);
- }
-
- /**
- * @dataProvider successLangcodes
- */
- public function testLangcodes($nplural, $langCodes)
- {
- $matrix = $this->generateTestData($nplural, $langCodes);
- $this->validateMatrix($nplural, $matrix);
- }
-
- /**
- * This array should contain all currently known langcodes.
- *
- * As it is impossible to have this ever complete we should try as hard as possible to have it almost complete.
- *
- * @return type
- */
- public function successLangcodes()
- {
- return array(
- array('1' , array('ay','bo', 'cgg','dz','id', 'ja', 'jbo', 'ka','kk','km','ko','ky')),
- array('2' , array('nl', 'fr', 'en', 'de', 'de_GE')),
- array('3' , array('be','bs','cs','hr')),
- array('4' , array('cy','mt', 'sl')),
- array('5' , array()),
- array('6' , array('ar')),
- );
- }
-
- /**
- * This array should be at least empty within the near future.
- *
- * This both depends on a complete list trying to add above as understanding
- * the plural rules of the current failing languages.
- *
- * @return array with nplural together with langcodes
- */
- public function failingLangcodes()
- {
- return array(
- array('1' , array('fa')),
- array('2' , array('jbo')),
- array('3' , array('cbs')),
- array('4' , array('gd','kw')),
- array('5' , array('ga')),
- array('6' , array()),
- );
- }
-
- /**
- * We validate only on the plural coverage. Thus the real rules is not tested.
- *
- * @param string $nplural plural expected
- * @param array $matrix containing langcodes and their plural index values.
- * @param boolean $expectSuccess
- */
- protected function validateMatrix($nplural, $matrix, $expectSuccess = true)
- {
- foreach ($matrix as $langCode => $data) {
- $indexes = array_flip($data);
- if ($expectSuccess) {
- $this->assertEquals($nplural, count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
- } else {
- $this->assertNotEquals((int) $nplural, count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
- }
- }
- }
-
- protected function generateTestData($plural, $langCodes)
- {
- $matrix = array();
- foreach ($langCodes as $langCode) {
- for ($count=0; $count<200; $count++) {
- $plural = PluralizationRules::get($count, $langCode);
- $matrix[$langCode][$count] = $plural;
- }
- }
-
- return $matrix;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Tests;
-
-use Symfony\Component\Translation\Translator;
-use Symfony\Component\Translation\MessageSelector;
-use Symfony\Component\Translation\Loader\ArrayLoader;
-
-class TranslatorTest extends \PHPUnit_Framework_TestCase
-{
- public function testSetGetLocale()
- {
- $translator = new Translator('en', new MessageSelector());
-
- $this->assertEquals('en', $translator->getLocale());
-
- $translator->setLocale('fr');
- $this->assertEquals('fr', $translator->getLocale());
- }
-
- public function testSetFallbackLocales()
- {
- $translator = new Translator('en', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('foo' => 'foofoo'), 'en');
- $translator->addResource('array', array('bar' => 'foobar'), 'fr');
-
- // force catalogue loading
- $translator->trans('bar');
-
- $translator->setFallbackLocales(array('fr'));
- $this->assertEquals('foobar', $translator->trans('bar'));
- }
-
- public function testSetFallbackLocalesMultiple()
- {
- $translator = new Translator('en', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('foo' => 'foo (en)'), 'en');
- $translator->addResource('array', array('bar' => 'bar (fr)'), 'fr');
-
- // force catalogue loading
- $translator->trans('bar');
-
- $translator->setFallbackLocales(array('fr_FR', 'fr'));
- $this->assertEquals('bar (fr)', $translator->trans('bar'));
- }
-
- public function testTransWithFallbackLocale()
- {
- $translator = new Translator('fr_FR', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
- $translator->addResource('array', array('bar' => 'foobar'), 'en');
-
- $translator->setFallbackLocales(array('en'));
-
- $this->assertEquals('foobar', $translator->trans('bar'));
- }
-
- public function testAddResourceAfterTrans()
- {
- $translator = new Translator('fr', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
-
- $translator->setFallbackLocale(array('en'));
-
- $translator->addResource('array', array('foo' => 'foofoo'), 'en');
- $this->assertEquals('foofoo', $translator->trans('foo'));
-
- $translator->addResource('array', array('bar' => 'foobar'), 'en');
- $this->assertEquals('foobar', $translator->trans('bar'));
- }
-
- /**
- * @dataProvider getTransFileTests
- * @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
- */
- public function testTransWithoutFallbackLocaleFile($format, $loader)
- {
- $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
- $translator = new Translator('en', new MessageSelector());
- $translator->addLoader($format, new $loaderClass());
- $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en');
- $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en');
-
- // force catalogue loading
- $translator->trans('foo');
- }
-
- /**
- * @dataProvider getTransFileTests
- */
- public function testTransWithFallbackLocaleFile($format, $loader)
- {
- $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
- $translator = new Translator('en_GB', new MessageSelector());
- $translator->addLoader($format, new $loaderClass());
- $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en_GB');
- $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en', 'resources');
-
- $this->assertEquals('bar', $translator->trans('foo', array(), 'resources'));
- }
-
- public function testTransWithFallbackLocaleBis()
- {
- $translator = new Translator('en_US', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
- $translator->addResource('array', array('bar' => 'foobar'), 'en');
- $this->assertEquals('foobar', $translator->trans('bar'));
- }
-
- public function testTransWithFallbackLocaleTer()
- {
- $translator = new Translator('fr_FR', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('foo' => 'foo (en_US)'), 'en_US');
- $translator->addResource('array', array('bar' => 'bar (en)'), 'en');
-
- $translator->setFallbackLocales(array('en_US', 'en'));
-
- $this->assertEquals('foo (en_US)', $translator->trans('foo'));
- $this->assertEquals('bar (en)', $translator->trans('bar'));
- }
-
- public function testTransNonExistentWithFallback()
- {
- $translator = new Translator('fr', new MessageSelector());
- $translator->setFallbackLocales(array('en'));
- $translator->addLoader('array', new ArrayLoader());
- $this->assertEquals('non-existent', $translator->trans('non-existent'));
- }
-
- /**
- * @expectedException RuntimeException
- */
- public function testWhenAResourceHasNoRegisteredLoader()
- {
- $translator = new Translator('en', new MessageSelector());
- $translator->addResource('array', array('foo' => 'foofoo'), 'en');
-
- $translator->trans('foo');
- }
-
- /**
- * @dataProvider getTransTests
- */
- public function testTrans($expected, $id, $translation, $parameters, $locale, $domain)
- {
- $translator = new Translator('en', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
-
- $this->assertEquals($expected, $translator->trans($id, $parameters, $domain, $locale));
- }
-
- /**
- * @dataProvider getFlattenedTransTests
- */
- public function testFlattenedTrans($expected, $messages, $id)
- {
- $translator = new Translator('en', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', $messages, 'fr', '');
-
- $this->assertEquals($expected, $translator->trans($id, array(), '', 'fr'));
- }
-
- /**
- * @dataProvider getTransChoiceTests
- */
- public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain)
- {
- $translator = new Translator('en', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array((string) $id => $translation), $locale, $domain);
-
- $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters, $domain, $locale));
- }
-
- public function getTransFileTests()
- {
- return array(
- array('csv', 'CsvFileLoader'),
- array('ini', 'IniFileLoader'),
- array('mo', 'MoFileLoader'),
- array('po', 'PoFileLoader'),
- array('php', 'PhpFileLoader'),
- array('ts', 'QtFileLoader'),
- array('xlf', 'XliffFileLoader'),
- array('yml', 'YamlFileLoader'),
- );
- }
-
- public function getTransTests()
- {
- return array(
- array('Symfony2 est super !', 'Symfony2 is great!', 'Symfony2 est super !', array(), 'fr', ''),
- array('Symfony2 est awesome !', 'Symfony2 is %what%!', 'Symfony2 est %what% !', array('%what%' => 'awesome'), 'fr', ''),
- array('Symfony2 est super !', new String('Symfony2 is great!'), 'Symfony2 est super !', array(), 'fr', ''),
- );
- }
-
- public function getFlattenedTransTests()
- {
- $messages = array(
- 'symfony2' => array(
- 'is' => array(
- 'great' => 'Symfony2 est super!'
- )
- ),
- 'foo' => array(
- 'bar' => array(
- 'baz' => 'Foo Bar Baz'
- ),
- 'baz' => 'Foo Baz',
- ),
- );
-
- return array(
- array('Symfony2 est super!', $messages, 'symfony2.is.great'),
- array('Foo Bar Baz', $messages, 'foo.bar.baz'),
- array('Foo Baz', $messages, 'foo.baz'),
- );
- }
-
- public function getTransChoiceTests()
- {
- return array(
- array('Il y a 0 pomme', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
- array('Il y a 1 pomme', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
- array('Il y a 10 pommes', '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
-
- array('Il y a 0 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
- array('Il y a 1 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
- array('Il y a 10 pommes', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
-
- array('Il y a 0 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
- array('Il y a 1 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
- array('Il y a 10 pommes', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
-
- array('Il n\'y a aucune pomme', '{0} There is no apple|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
- array('Il y a 1 pomme', '{0} There is no apple|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
- array('Il y a 10 pommes', '{0} There is no apple|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
-
- array('Il y a 0 pomme', new String('{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples'), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
- );
- }
-
- public function testTransChoiceFallback()
- {
- $translator = new Translator('ru', new MessageSelector());
- $translator->setFallbackLocales(array('en'));
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en');
-
- $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
- }
-
- public function testTransChoiceFallbackBis()
- {
- $translator = new Translator('ru', new MessageSelector());
- $translator->setFallbackLocales(array('en_US', 'en'));
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en_US');
-
- $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testTransChoiceFallbackWithNoTranslation()
- {
- $translator = new Translator('ru', new MessageSelector());
- $translator->setFallbackLocales(array('en'));
- $translator->addLoader('array', new ArrayLoader());
-
- $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
- }
-}
-
-class String
-{
- protected $str;
-
- public function __construct($str)
- {
- $this->str = $str;
- }
-
- public function __toString()
- {
- return $this->str;
- }
-}
+++ /dev/null
-msgid "foo"
-msgstr ""
-
+++ /dev/null
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="1" resname="foo">
- <source>foo</source>
- <target>bär</target>
- </trans-unit>
- <trans-unit id="2" resname="bar">
- <source>bar</source>
- <target>föö</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="1">
- <source>foo</source>
- <target>bar
- </trans-unit>
- <trans-unit id="2">
- <source>extra</source>
- </trans-unit>
- <trans-unit id="3">
- <source>key</source>
- <target></target>
- </trans-unit>
- <trans-unit id="4">
- <source>test</source>
- <target>with</target>
- <note>note</note>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?xml version="1.0"?>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit>
- <source>foo</source>
- <target>bar</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-msgid "foo"
-msgid_plural "foos"
-msgstr[0] "bar"
-msgstr[1] "bars"
-
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="1" resname="foo">
- <source></source>
- <target>bar</target>
- </trans-unit>
- <trans-unit id="2" resname="bar">
- <source>bar source</source>
- <target>baz</target>
- </trans-unit>
- <trans-unit id="3">
- <source>baz</source>
- <target>foo</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-XXX
\ No newline at end of file
+++ /dev/null
-en{
- symfony{"Symfony 2 is great"}
-}
\ No newline at end of file
+++ /dev/null
-fr{
- symfony{"Symfony 2 est génial"}
-}
\ No newline at end of file
+++ /dev/null
-en.res
-fr.res
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="acbd18db4cc2f85cedef654fccc4a4d8" resname="foo">
- <source>foo</source>
- <target>bar</target>
- </trans-unit>
- <trans-unit id="3c6e0b8a9c15224a8228b9a98ca1531d" resname="key">
- <source>key</source>
- <target></target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-"foo"; "bar"
-#"bar"; "foo"
-"incorrect"; "number"; "columns"; "will"; "be"; "ignored"
-"incorrect"
\ No newline at end of file
+++ /dev/null
-<?php
-
-return array (
- 'foo' => 'bar',
-);
+++ /dev/null
-msgid "foo"
-msgstr "bar"
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<TS>
- <context>
- <name>resources</name>
- <message>
- <source>foo</source>
- <translation>bar</translation>
- </message>
- </context>
-</TS>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="1">
- <source>foo</source>
- <target>bar</target>
- </trans-unit>
- <trans-unit id="2">
- <source>extra</source>
- </trans-unit>
- <trans-unit id="3">
- <source>key</source>
- <target></target>
- </trans-unit>
- <trans-unit id="4">
- <source>test</source>
- <target>with</target>
- <note>note</note>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-foo;bar
-bar;"foo
-foo"
-"foo;foo";bar
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE foo>
-<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
- <file source-language="en" datatype="plaintext" original="file.ext">
- <body>
- <trans-unit id="1">
- <source>foo</source>
- <target>bar</target>
- </trans-unit>
- </body>
- </file>
-</xliff>
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-use Symfony\Component\Translation\Loader\LoaderInterface;
-use Symfony\Component\Translation\Exception\NotFoundResourceException;
-
-/**
- * Translator.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-class Translator implements TranslatorInterface
-{
- /**
- * @var MessageCatalogueInterface[]
- */
- protected $catalogues = array();
-
- /**
- * @var string
- */
- protected $locale;
-
- /**
- * @var array
- */
- private $fallbackLocales = array();
-
- /**
- * @var LoaderInterface[]
- */
- private $loaders = array();
-
- /**
- * @var array
- */
- private $resources = array();
-
- /**
- * @var MessageSelector
- */
- private $selector;
-
- /**
- * Constructor.
- *
- * @param string $locale The locale
- * @param MessageSelector|null $selector The message selector for pluralization
- *
- * @api
- */
- public function __construct($locale, MessageSelector $selector = null)
- {
- $this->locale = $locale;
- $this->selector = $selector ?: new MessageSelector();
- }
-
- /**
- * Adds a Loader.
- *
- * @param string $format The name of the loader (@see addResource())
- * @param LoaderInterface $loader A LoaderInterface instance
- *
- * @api
- */
- public function addLoader($format, LoaderInterface $loader)
- {
- $this->loaders[$format] = $loader;
- }
-
- /**
- * Adds a Resource.
- *
- * @param string $format The name of the loader (@see addLoader())
- * @param mixed $resource The resource name
- * @param string $locale The locale
- * @param string $domain The domain
- *
- * @api
- */
- public function addResource($format, $resource, $locale, $domain = null)
- {
- if (null === $domain) {
- $domain = 'messages';
- }
-
- $this->resources[$locale][] = array($format, $resource, $domain);
-
- if (in_array($locale, $this->fallbackLocales)) {
- $this->catalogues = array();
- } else {
- unset($this->catalogues[$locale]);
- }
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function setLocale($locale)
- {
- $this->locale = $locale;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function getLocale()
- {
- return $this->locale;
- }
-
- /**
- * Sets the fallback locale(s).
- *
- * @param string|array $locales The fallback locale(s)
- *
- * @deprecated since 2.3, to be removed in 3.0. Use setFallbackLocales() instead.
- *
- * @api
- */
- public function setFallbackLocale($locales)
- {
- $this->setFallbackLocales(is_array($locales) ? $locales : array($locales));
- }
-
- /**
- * Sets the fallback locales.
- *
- * @param array $locales The fallback locales
- *
- * @api
- */
- public function setFallbackLocales(array $locales)
- {
- // needed as the fallback locales are linked to the already loaded catalogues
- $this->catalogues = array();
-
- $this->fallbackLocales = $locales;
- }
-
- /**
- * Gets the fallback locales.
- *
- * @return array $locales The fallback locales
- *
- * @api
- */
- public function getFallbackLocales()
- {
- return $this->fallbackLocales;
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function trans($id, array $parameters = array(), $domain = null, $locale = null)
- {
- if (null === $locale) {
- $locale = $this->getLocale();
- }
-
- if (null === $domain) {
- $domain = 'messages';
- }
-
- if (!isset($this->catalogues[$locale])) {
- $this->loadCatalogue($locale);
- }
-
- return strtr($this->catalogues[$locale]->get((string) $id, $domain), $parameters);
- }
-
- /**
- * {@inheritdoc}
- *
- * @api
- */
- public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
- {
- if (null === $locale) {
- $locale = $this->getLocale();
- }
-
- if (null === $domain) {
- $domain = 'messages';
- }
-
- if (!isset($this->catalogues[$locale])) {
- $this->loadCatalogue($locale);
- }
-
- $id = (string) $id;
-
- $catalogue = $this->catalogues[$locale];
- while (!$catalogue->defines($id, $domain)) {
- if ($cat = $catalogue->getFallbackCatalogue()) {
- $catalogue = $cat;
- $locale = $catalogue->getLocale();
- } else {
- break;
- }
- }
-
- return strtr($this->selector->choose($catalogue->get($id, $domain), (int) $number, $locale), $parameters);
- }
-
- protected function loadCatalogue($locale)
- {
- try {
- $this->doLoadCatalogue($locale);
- } catch (NotFoundResourceException $e) {
- if (!$this->computeFallbackLocales($locale)) {
- throw $e;
- }
- }
- $this->loadFallbackCatalogues($locale);
- }
-
- private function doLoadCatalogue($locale)
- {
- $this->catalogues[$locale] = new MessageCatalogue($locale);
-
- if (isset($this->resources[$locale])) {
- foreach ($this->resources[$locale] as $resource) {
- if (!isset($this->loaders[$resource[0]])) {
- throw new \RuntimeException(sprintf('The "%s" translation loader is not registered.', $resource[0]));
- }
- $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
- }
- }
- }
-
- private function loadFallbackCatalogues($locale)
- {
- $current = $this->catalogues[$locale];
-
- foreach ($this->computeFallbackLocales($locale) as $fallback) {
- if (!isset($this->catalogues[$fallback])) {
- $this->doLoadCatalogue($fallback);
- }
-
- $current->addFallbackCatalogue($this->catalogues[$fallback]);
- $current = $this->catalogues[$fallback];
- }
- }
-
- protected function computeFallbackLocales($locale)
- {
- $locales = array();
- foreach ($this->fallbackLocales as $fallback) {
- if ($fallback === $locale) {
- continue;
- }
-
- $locales[] = $fallback;
- }
-
- if (strrchr($locale, '_') !== false) {
- array_unshift($locales, substr($locale, 0, -strlen(strrchr($locale, '_'))));
- }
-
- return array_unique($locales);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation;
-
-/**
- * TranslatorInterface.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-interface TranslatorInterface
-{
- /**
- * Translates the given message.
- *
- * @param string $id The message id (may also be an object that can be cast to string)
- * @param array $parameters An array of parameters for the message
- * @param string $domain The domain for the message
- * @param string $locale The locale
- *
- * @return string The translated string
- *
- * @api
- */
- public function trans($id, array $parameters = array(), $domain = null, $locale = null);
-
- /**
- * Translates the given choice message by choosing a translation according to a number.
- *
- * @param string $id The message id (may also be an object that can be cast to string)
- * @param integer $number The number to use to find the indice of the message
- * @param array $parameters An array of parameters for the message
- * @param string $domain The domain for the message
- * @param string $locale The locale
- *
- * @return string The translated string
- *
- * @api
- */
- public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null);
-
- /**
- * Sets the current locale.
- *
- * @param string $locale The locale
- *
- * @api
- */
- public function setLocale($locale);
-
- /**
- * Returns the current locale.
- *
- * @return string The locale
- *
- * @api
- */
- public function getLocale();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Translation\Writer;
-
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Component\Translation\Dumper\DumperInterface;
-
-/**
- * TranslationWriter writes translation messages.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
-class TranslationWriter
-{
- /**
- * Dumpers used for export.
- *
- * @var array
- */
- private $dumpers = array();
-
- /**
- * Adds a dumper to the writer.
- *
- * @param string $format The format of the dumper
- * @param DumperInterface $dumper The dumper
- */
- public function addDumper($format, DumperInterface $dumper)
- {
- $this->dumpers[$format] = $dumper;
- }
-
- /**
- * Obtains the list of supported formats.
- *
- * @return array
- */
- public function getFormats()
- {
- return array_keys($this->dumpers);
- }
-
- /**
- * Writes translation from the catalogue according to the selected format.
- *
- * @param MessageCatalogue $catalogue The message catalogue to dump
- * @param string $format The format to use to dump the messages
- * @param array $options Options that are passed to the dumper
- *
- * @throws \InvalidArgumentException
- */
- public function writeTranslations(MessageCatalogue $catalogue, $format, $options = array())
- {
- if (!isset($this->dumpers[$format])) {
- throw new \InvalidArgumentException(sprintf('There is no dumper associated with format "%s".', $format));
- }
-
- // get the right dumper
- $dumper = $this->dumpers[$format];
-
- // save
- $dumper->dump($catalogue, $options);
- }
-}
+++ /dev/null
-{
- "name": "symfony/translation",
- "type": "library",
- "description": "Symfony Translation Component",
- "keywords": [],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "symfony/config": "~2.0",
- "symfony/yaml": "~2.2"
- },
- "suggest": {
- "symfony/config": "",
- "symfony/yaml": ""
- },
- "autoload": {
- "psr-0": { "Symfony\\Component\\Translation\\": "" }
- },
- "target-dir": "Symfony/Component/Translation",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony Translation Component Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./vendor</directory>
- <directory>./Tests</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-vendor/
-composer.lock
-phpunit.xml
-
+++ /dev/null
-CHANGELOG
-=========
-
-2.3.0
------
-
- * added helpers form(), form_start() and form_end()
- * deprecated form_enctype() in favor of form_start()
-
-2.2.0
------
-
- * added a `controller` function to help generating controller references
- * added a `render_esi` and a `render_hinclude` function
- * [BC BREAK] restricted the `render` tag to only accept URIs or ControllerReference instances (the signature changed)
- * added a `render` function to render a request
- * The `app` global variable is now injected even when using the twig service directly.
- * Added an optional parameter to the `path` and `url` function which allows to generate
- relative paths (e.g. "../parent-file") and scheme-relative URLs (e.g. "//example.com/dir/file").
-
-2.1.0
------
-
- * added global variables access in a form theme
- * added TwigEngine
- * added TwigExtractor
- * added a csrf_token function
- * added a way to specify a default domain for a Twig template (via the
- 'trans_default_domain' tag)
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Extension;
-
-if (!defined('ENT_SUBSTITUTE')) {
- define('ENT_SUBSTITUTE', 8);
-}
-
-/**
- * Twig extension relate to PHP code and used by the profiler and the default exception templates.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class CodeExtension extends \Twig_Extension
-{
- private $fileLinkFormat;
- private $rootDir;
- private $charset;
-
- /**
- * Constructor.
- *
- * @param string $fileLinkFormat The format for links to source files
- * @param string $rootDir The project root directory
- * @param string $charset The charset
- */
- public function __construct($fileLinkFormat, $rootDir, $charset)
- {
- $this->fileLinkFormat = empty($fileLinkFormat) ? ini_get('xdebug.file_link_format') : $fileLinkFormat;
- $this->rootDir = str_replace('\\', '/', $rootDir).'/';
- $this->charset = $charset;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFilters()
- {
- return array(
- 'abbr_class' => new \Twig_Filter_Method($this, 'abbrClass', array('is_safe' => array('html'))),
- 'abbr_method' => new \Twig_Filter_Method($this, 'abbrMethod', array('is_safe' => array('html'))),
- 'format_args' => new \Twig_Filter_Method($this, 'formatArgs', array('is_safe' => array('html'))),
- 'format_args_as_text' => new \Twig_Filter_Method($this, 'formatArgsAsText'),
- 'file_excerpt' => new \Twig_Filter_Method($this, 'fileExcerpt', array('is_safe' => array('html'))),
- 'format_file' => new \Twig_Filter_Method($this, 'formatFile', array('is_safe' => array('html'))),
- 'format_file_from_text' => new \Twig_Filter_Method($this, 'formatFileFromText', array('is_safe' => array('html'))),
- 'file_link' => new \Twig_Filter_Method($this, 'getFileLink', array('is_safe' => array('html'))),
- );
- }
-
- public function abbrClass($class)
- {
- $parts = explode('\\', $class);
- $short = array_pop($parts);
-
- return sprintf("<abbr title=\"%s\">%s</abbr>", $class, $short);
- }
-
- public function abbrMethod($method)
- {
- if (false !== strpos($method, '::')) {
- list($class, $method) = explode('::', $method, 2);
- $result = sprintf("%s::%s()", $this->abbrClass($class), $method);
- } elseif ('Closure' === $method) {
- $result = sprintf("<abbr title=\"%s\">%s</abbr>", $method, $method);
- } else {
- $result = sprintf("<abbr title=\"%s\">%s</abbr>()", $method, $method);
- }
-
- return $result;
- }
-
- /**
- * Formats an array as a string.
- *
- * @param array $args The argument array
- *
- * @return string
- */
- public function formatArgs($args)
- {
- $result = array();
- foreach ($args as $key => $item) {
- if ('object' === $item[0]) {
- $parts = explode('\\', $item[1]);
- $short = array_pop($parts);
- $formattedValue = sprintf("<em>object</em>(<abbr title=\"%s\">%s</abbr>)", $item[1], $short);
- } elseif ('array' === $item[0]) {
- $formattedValue = sprintf("<em>array</em>(%s)", is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
- } elseif ('string' === $item[0]) {
- $formattedValue = sprintf("'%s'", htmlspecialchars($item[1], ENT_QUOTES, $this->charset));
- } elseif ('null' === $item[0]) {
- $formattedValue = '<em>null</em>';
- } elseif ('boolean' === $item[0]) {
- $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
- } elseif ('resource' === $item[0]) {
- $formattedValue = '<em>resource</em>';
- } else {
- $formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string) $item[1], ENT_QUOTES, $this->charset), true));
- }
-
- $result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
- }
-
- return implode(', ', $result);
- }
-
- /**
- * Formats an array as a string.
- *
- * @param array $args The argument array
- *
- * @return string
- */
- public function formatArgsAsText($args)
- {
- return strip_tags($this->formatArgs($args));
- }
-
- /**
- * Returns an excerpt of a code file around the given line number.
- *
- * @param string $file A file path
- * @param int $line The selected line number
- *
- * @return string An HTML string
- */
- public function fileExcerpt($file, $line)
- {
- if (is_readable($file)) {
- $code = highlight_file($file, true);
- // remove main code/span tags
- $code = preg_replace('#^<code.*?>\s*<span.*?>(.*)</span>\s*</code>#s', '\\1', $code);
- $content = preg_split('#<br />#', $code);
-
- $lines = array();
- for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; $i++) {
- $lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
- }
-
- return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
- }
- }
-
- /**
- * Formats a file path.
- *
- * @param string $file An absolute file path
- * @param integer $line The line number
- * @param string $text Use this text for the link rather than the file path
- *
- * @return string
- */
- public function formatFile($file, $line, $text = null)
- {
- if (null === $text) {
- $file = trim($file);
- $text = $file;
- if (0 === strpos($text, $this->rootDir)) {
- $text = str_replace($this->rootDir, '', str_replace('\\', '/', $text));
- $text = sprintf('<abbr title="%s">kernel.root_dir</abbr>/%s', $this->rootDir, $text);
- }
- }
-
- $text = "$text at line $line";
-
- if (false !== $link = $this->getFileLink($file, $line)) {
- return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', htmlspecialchars($link, ENT_QUOTES | ENT_SUBSTITUTE, $this->charset), $text);
- }
-
- return $text;
- }
-
- /**
- * Returns the link for a given file/line pair.
- *
- * @param string $file An absolute file path
- * @param integer $line The line number
- *
- * @return string A link of false
- */
- public function getFileLink($file, $line)
- {
- if ($this->fileLinkFormat && is_file($file)) {
- return strtr($this->fileLinkFormat, array('%f' => $file, '%l' => $line));
- }
-
- return false;
- }
-
- public function formatFileFromText($text)
- {
- $that = $this;
-
- return preg_replace_callback('/in ("|")?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) use ($that) {
- return 'in '.$that->formatFile($match[2], $match[3]);
- }, $text);
- }
-
- public function getName()
- {
- return 'code';
- }
-
- protected static function fixCodeMarkup($line)
- {
- // </span> ending tag from previous line
- $opening = strpos($line, '<span');
- $closing = strpos($line, '</span>');
- if (false !== $closing && (false === $opening || $closing < $opening)) {
- $line = substr_replace($line, '', $closing, 7);
- }
-
- // missing </span> tag at the end of line
- $opening = strpos($line, '<span');
- $closing = strpos($line, '</span>');
- if (false !== $opening && (false === $closing || $closing > $opening)) {
- $line .= '</span>';
- }
-
- return $line;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Extension;
-
-use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
-use Symfony\Bridge\Twig\Form\TwigRendererInterface;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-
-/**
- * FormExtension extends Twig with form capabilities.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class FormExtension extends \Twig_Extension
-{
- /**
- * This property is public so that it can be accessed directly from compiled
- * templates without having to call a getter, which slightly decreases performance.
- *
- * @var TwigRendererInterface
- */
- public $renderer;
-
- public function __construct(TwigRendererInterface $renderer)
- {
- $this->renderer = $renderer;
- }
-
- /**
- * {@inheritdoc}
- */
- public function initRuntime(\Twig_Environment $environment)
- {
- $this->renderer->setEnvironment($environment);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTokenParsers()
- {
- return array(
- // {% form_theme form "SomeBundle::widgets.twig" %}
- new FormThemeTokenParser(),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFunctions()
- {
- return array(
- 'form_enctype' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\FormEnctypeNode', array('is_safe' => array('html'))),
- 'form_widget' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
- 'form_errors' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
- 'form_label' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
- 'form_row' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
- 'form_rest' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
- 'form' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
- 'form_start' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
- 'form_end' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
- 'csrf_token' => new \Twig_Function_Method($this, 'renderer->renderCsrfToken'),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFilters()
- {
- return array(
- 'humanize' => new \Twig_Filter_Method($this, 'renderer->humanize'),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTests()
- {
- return array(
- 'selectedchoice' => new \Twig_Test_Method($this, 'isSelectedChoice'),
- );
- }
-
- /**
- * Returns whether a choice is selected for a given form value.
- *
- * Unfortunately Twig does not support an efficient way to execute the
- * "is_selected" closure passed to the template by ChoiceType. It is faster
- * to implement the logic here (around 65ms for a specific form).
- *
- * Directly implementing the logic here is also faster than doing so in
- * ChoiceView (around 30ms).
- *
- * The worst option tested so far is to implement the logic in ChoiceView
- * and access the ChoiceView method directly in the template. Doing so is
- * around 220ms slower than doing the method call here in the filter. Twig
- * seems to be much more efficient at executing filters than at executing
- * methods of an object.
- *
- * @param ChoiceView $choice The choice to check.
- * @param string|array $selectedValue The selected value to compare.
- *
- * @return Boolean Whether the choice is selected.
- *
- * @see ChoiceView::isSelected()
- */
- public function isSelectedChoice(ChoiceView $choice, $selectedValue)
- {
- if (is_array($selectedValue)) {
- return false !== array_search($choice->value, $selectedValue, true);
- }
-
- return $choice->value === $selectedValue;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'form';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Extension;
-
-use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
-use Symfony\Component\HttpKernel\Controller\ControllerReference;
-
-/**
- * Provides integration with the HttpKernel component.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class HttpKernelExtension extends \Twig_Extension
-{
- private $handler;
-
- /**
- * Constructor.
- *
- * @param FragmentHandler $handler A FragmentHandler instance
- */
- public function __construct(FragmentHandler $handler)
- {
- $this->handler = $handler;
- }
-
- public function getFunctions()
- {
- return array(
- 'render' => new \Twig_Function_Method($this, 'renderFragment', array('is_safe' => array('html'))),
- 'render_*' => new \Twig_Function_Method($this, 'renderFragmentStrategy', array('is_safe' => array('html'))),
- 'controller' => new \Twig_Function_Method($this, 'controller'),
- );
- }
-
- /**
- * Renders a fragment.
- *
- * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
- * @param array $options An array of options
- *
- * @return string The fragment content
- *
- * @see Symfony\Component\HttpKernel\Fragment\FragmentHandler::render()
- */
- public function renderFragment($uri, $options = array())
- {
- $strategy = isset($options['strategy']) ? $options['strategy'] : 'inline';
- unset($options['strategy']);
-
- return $this->handler->render($uri, $strategy, $options);
- }
-
- /**
- * Renders a fragment.
- *
- * @param string $strategy A strategy name
- * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance
- * @param array $options An array of options
- *
- * @return string The fragment content
- *
- * @see Symfony\Component\HttpKernel\Fragment\FragmentHandler::render()
- */
- public function renderFragmentStrategy($strategy, $uri, $options = array())
- {
- return $this->handler->render($uri, $strategy, $options);
- }
-
- public function controller($controller, $attributes = array(), $query = array())
- {
- return new ControllerReference($controller, $attributes, $query);
- }
-
- public function getName()
- {
- return 'http_kernel';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Extension;
-
-use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
-
-/**
- * Provides integration of the Routing component with Twig.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class RoutingExtension extends \Twig_Extension
-{
- private $generator;
-
- public function __construct(UrlGeneratorInterface $generator)
- {
- $this->generator = $generator;
- }
-
- /**
- * Returns a list of functions to add to the existing list.
- *
- * @return array An array of functions
- */
- public function getFunctions()
- {
- return array(
- 'url' => new \Twig_Function_Method($this, 'getUrl', array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
- 'path' => new \Twig_Function_Method($this, 'getPath', array('is_safe_callback' => array($this, 'isUrlGenerationSafe'))),
- );
- }
-
- public function getPath($name, $parameters = array(), $relative = false)
- {
- return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH);
- }
-
- public function getUrl($name, $parameters = array(), $schemeRelative = false)
- {
- return $this->generator->generate($name, $parameters, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL);
- }
-
- /**
- * Determines at compile time whether the generated URL will be safe and thus
- * saving the unneeded automatic escaping for performance reasons.
- *
- * The URL generation process percent encodes non-alphanumeric characters. So there is no risk
- * that malicious/invalid characters are part of the URL. The only character within an URL that
- * must be escaped in html is the ampersand ("&") which separates query params. So we cannot mark
- * the URL generation as always safe, but only when we are sure there won't be multiple query
- * params. This is the case when there are none or only one constant parameter given.
- * E.g. we know beforehand this will be safe:
- * - path('route')
- * - path('route', {'param': 'value'})
- * But the following may not:
- * - path('route', var)
- * - path('route', {'param': ['val1', 'val2'] }) // a sub-array
- * - path('route', {'param1': 'value1', 'param2': 'value2'})
- * If param1 and param2 reference placeholder in the route, it would still be safe. But we don't know.
- *
- * @param \Twig_Node $argsNode The arguments of the path/url function
- *
- * @return array An array with the contexts the URL is safe
- */
- public function isUrlGenerationSafe(\Twig_Node $argsNode)
- {
- // support named arguments
- $paramsNode = $argsNode->hasNode('parameters') ? $argsNode->getNode('parameters') : (
- $argsNode->hasNode(1) ? $argsNode->getNode(1) : null
- );
-
- if (null === $paramsNode || $paramsNode instanceof \Twig_Node_Expression_Array && count($paramsNode) <= 2 &&
- (!$paramsNode->hasNode(1) || $paramsNode->getNode(1) instanceof \Twig_Node_Expression_Constant)
- ) {
- return array('html');
- }
-
- return array();
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'routing';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Extension;
-
-use Symfony\Component\Security\Acl\Voter\FieldVote;
-use Symfony\Component\Security\Core\SecurityContextInterface;
-
-/**
- * SecurityExtension exposes security context features.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class SecurityExtension extends \Twig_Extension
-{
- private $context;
-
- public function __construct(SecurityContextInterface $context = null)
- {
- $this->context = $context;
- }
-
- public function isGranted($role, $object = null, $field = null)
- {
- if (null === $this->context) {
- return false;
- }
-
- if (null !== $field) {
- $object = new FieldVote($object, $field);
- }
-
- return $this->context->isGranted($role, $object);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFunctions()
- {
- return array(
- 'is_granted' => new \Twig_Function_Method($this, 'isGranted'),
- );
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'security';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Extension;
-
-use Symfony\Bridge\Twig\TokenParser\TransTokenParser;
-use Symfony\Bridge\Twig\TokenParser\TransChoiceTokenParser;
-use Symfony\Bridge\Twig\TokenParser\TransDefaultDomainTokenParser;
-use Symfony\Component\Translation\TranslatorInterface;
-use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
-use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor;
-
-/**
- * Provides integration of the Translation component with Twig.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TranslationExtension extends \Twig_Extension
-{
- private $translator;
- private $translationNodeVisitor;
-
- public function __construct(TranslatorInterface $translator, \Twig_NodeVisitorInterface $translationNodeVisitor = null)
- {
- if (!$translationNodeVisitor) {
- $translationNodeVisitor = new TranslationNodeVisitor();
- }
-
- $this->translator = $translator;
- $this->translationNodeVisitor = $translationNodeVisitor;
- }
-
- public function getTranslator()
- {
- return $this->translator;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFilters()
- {
- return array(
- 'trans' => new \Twig_Filter_Method($this, 'trans'),
- 'transchoice' => new \Twig_Filter_Method($this, 'transchoice'),
- );
- }
-
- /**
- * Returns the token parser instance to add to the existing list.
- *
- * @return array An array of Twig_TokenParser instances
- */
- public function getTokenParsers()
- {
- return array(
- // {% trans %}Symfony is great!{% endtrans %}
- new TransTokenParser(),
-
- // {% transchoice count %}
- // {0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples
- // {% endtranschoice %}
- new TransChoiceTokenParser(),
-
- // {% trans_default_domain "foobar" %}
- new TransDefaultDomainTokenParser(),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getNodeVisitors()
- {
- return array($this->translationNodeVisitor, new TranslationDefaultDomainNodeVisitor());
- }
-
- public function getTranslationNodeVisitor()
- {
- return $this->translationNodeVisitor;
- }
-
- public function trans($message, array $arguments = array(), $domain = null, $locale = null)
- {
- if (null === $domain) {
- $domain = 'messages';
- }
-
- return $this->translator->trans($message, $arguments, $domain, $locale);
- }
-
- public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null)
- {
- if (null === $domain) {
- $domain = 'messages';
- }
-
- return $this->translator->transChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale);
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'translator';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Extension;
-
-use Symfony\Component\Yaml\Dumper as YamlDumper;
-
-/**
- * Provides integration of the Yaml component with Twig.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class YamlExtension extends \Twig_Extension
-{
- /**
- * {@inheritdoc}
- */
- public function getFilters()
- {
- return array(
- 'yaml_encode' => new \Twig_Filter_Method($this, 'encode'),
- 'yaml_dump' => new \Twig_Filter_Method($this, 'dump'),
- );
- }
-
- public function encode($input, $inline = 0, $dumpObjects = false)
- {
- static $dumper;
-
- if (null === $dumper) {
- $dumper = new YamlDumper();
- }
-
- return $dumper->dump($input, $inline, false, $dumpObjects);
- }
-
- public function dump($value, $inline = 0, $dumpObjects = false)
- {
- if (is_resource($value)) {
- return '%Resource%';
- }
-
- if (is_array($value) || is_object($value)) {
- return '%'.gettype($value).'% '.$this->encode($value, $inline, $dumpObjects);
- }
-
- return $this->encode($value, $inline, $dumpObjects);
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'yaml';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Form;
-
-use Symfony\Component\Form\FormRenderer;
-use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class TwigRenderer extends FormRenderer implements TwigRendererInterface
-{
- /**
- * @var TwigRendererEngineInterface
- */
- private $engine;
-
- public function __construct(TwigRendererEngineInterface $engine, CsrfProviderInterface $csrfProvider = null)
- {
- parent::__construct($engine, $csrfProvider);
-
- $this->engine = $engine;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setEnvironment(\Twig_Environment $environment)
- {
- $this->engine->setEnvironment($environment);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Form;
-
-use Symfony\Component\Form\AbstractRendererEngine;
-use Symfony\Component\Form\FormView;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class TwigRendererEngine extends AbstractRendererEngine implements TwigRendererEngineInterface
-{
- /**
- * @var \Twig_Environment
- */
- private $environment;
-
- /**
- * @var \Twig_Template
- */
- private $template;
-
- /**
- * {@inheritdoc}
- */
- public function setEnvironment(\Twig_Environment $environment)
- {
- $this->environment = $environment;
- }
-
- /**
- * {@inheritdoc}
- */
- public function renderBlock(FormView $view, $resource, $blockName, array $variables = array())
- {
- $cacheKey = $view->vars[self::CACHE_KEY_VAR];
-
- $context = $this->environment->mergeGlobals($variables);
-
- ob_start();
-
- // By contract,This method can only be called after getting the resource
- // (which is passed to the method). Getting a resource for the first time
- // (with an empty cache) is guaranteed to invoke loadResourcesFromTheme(),
- // where the property $template is initialized.
-
- // We do not call renderBlock here to avoid too many nested level calls
- // (XDebug limits the level to 100 by default)
- $this->template->displayBlock($blockName, $context, $this->resources[$cacheKey]);
-
- return ob_get_clean();
- }
-
- /**
- * Loads the cache with the resource for a given block name.
- *
- * This implementation eagerly loads all blocks of the themes assigned to the given view
- * and all of its ancestors views. This is necessary, because Twig receives the
- * list of blocks later. At that point, all blocks must already be loaded, for the
- * case that the function "block()" is used in the Twig template.
- *
- * @see getResourceForBlock()
- *
- * @param string $cacheKey The cache key of the form view.
- * @param FormView $view The form view for finding the applying themes.
- * @param string $blockName The name of the block to load.
- *
- * @return Boolean True if the resource could be loaded, false otherwise.
- */
- protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName)
- {
- // The caller guarantees that $this->resources[$cacheKey][$block] is
- // not set, but it doesn't have to check whether $this->resources[$cacheKey]
- // is set. If $this->resources[$cacheKey] is set, all themes for this
- // $cacheKey are already loaded (due to the eager population, see doc comment).
- if (isset($this->resources[$cacheKey])) {
- // As said in the previous, the caller guarantees that
- // $this->resources[$cacheKey][$block] is not set. Since the themes are
- // already loaded, it can only be a non-existing block.
- $this->resources[$cacheKey][$blockName] = false;
-
- return false;
- }
-
- // Recursively try to find the block in the themes assigned to $view,
- // then of its parent view, then of the parent view of the parent and so on.
- // When the root view is reached in this recursion, also the default
- // themes are taken into account.
-
- // Check each theme whether it contains the searched block
- if (isset($this->themes[$cacheKey])) {
- for ($i = count($this->themes[$cacheKey]) - 1; $i >= 0; --$i) {
- $this->loadResourcesFromTheme($cacheKey, $this->themes[$cacheKey][$i]);
- // CONTINUE LOADING (see doc comment)
- }
- }
-
- // Check the default themes once we reach the root view without success
- if (!$view->parent) {
- for ($i = count($this->defaultThemes) - 1; $i >= 0; --$i) {
- $this->loadResourcesFromTheme($cacheKey, $this->defaultThemes[$i]);
- // CONTINUE LOADING (see doc comment)
- }
- }
-
- // Proceed with the themes of the parent view
- if ($view->parent) {
- $parentCacheKey = $view->parent->vars[self::CACHE_KEY_VAR];
-
- if (!isset($this->resources[$parentCacheKey])) {
- $this->loadResourceForBlockName($parentCacheKey, $view->parent, $blockName);
- }
-
- // EAGER CACHE POPULATION (see doc comment)
- foreach ($this->resources[$parentCacheKey] as $nestedBlockName => $resource) {
- if (!isset($this->resources[$cacheKey][$nestedBlockName])) {
- $this->resources[$cacheKey][$nestedBlockName] = $resource;
- }
- }
- }
-
- // Even though we loaded the themes, it can happen that none of them
- // contains the searched block
- if (!isset($this->resources[$cacheKey][$blockName])) {
- // Cache that we didn't find anything to speed up further accesses
- $this->resources[$cacheKey][$blockName] = false;
- }
-
- return false !== $this->resources[$cacheKey][$blockName];
- }
-
- /**
- * Loads the resources for all blocks in a theme.
- *
- * @param string $cacheKey The cache key for storing the resource.
- * @param mixed $theme The theme to load the block from. This parameter
- * is passed by reference, because it might be necessary
- * to initialize the theme first. Any changes made to
- * this variable will be kept and be available upon
- * further calls to this method using the same theme.
- */
- protected function loadResourcesFromTheme($cacheKey, &$theme)
- {
- if (!$theme instanceof \Twig_Template) {
- /* @var \Twig_Template $theme */
- $theme = $this->environment->loadTemplate($theme);
- }
-
- if (null === $this->template) {
- // Store the first \Twig_Template instance that we find so that
- // we can call displayBlock() later on. It doesn't matter *which*
- // template we use for that, since we pass the used blocks manually
- // anyway.
- $this->template = $theme;
- }
-
- // Use a separate variable for the inheritance traversal, because
- // theme is a reference and we don't want to change it.
- $currentTheme = $theme;
-
- // The do loop takes care of template inheritance.
- // Add blocks from all templates in the inheritance tree, but avoid
- // overriding blocks already set.
- do {
- foreach ($currentTheme->getBlocks() as $block => $blockData) {
- if (!isset($this->resources[$cacheKey][$block])) {
- // The resource given back is the key to the bucket that
- // contains this block.
- $this->resources[$cacheKey][$block] = $blockData;
- }
- }
- } while (false !== $currentTheme = $currentTheme->getParent(array()));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Form;
-
-use Symfony\Component\Form\FormRendererEngineInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface TwigRendererEngineInterface extends FormRendererEngineInterface
-{
- /**
- * Sets Twig's environment.
- *
- * @param \Twig_Environment $environment
- */
- public function setEnvironment(\Twig_Environment $environment);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Form;
-
-use Symfony\Component\Form\FormRendererInterface;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-interface TwigRendererInterface extends FormRendererInterface
-{
- /**
- * Sets Twig's environment.
- *
- * @param \Twig_Environment $environment
- */
- public function setEnvironment(\Twig_Environment $environment);
-}
+++ /dev/null
-Copyright (c) 2004-2013 Fabien Potencier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Node;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
- * the helper "form_start()" instead.
- */
-class FormEnctypeNode extends SearchAndRenderBlockNode
-{
- public function compile(\Twig_Compiler $compiler)
- {
- parent::compile($compiler);
-
- $compiler->raw(";\n");
-
- // Uncomment this as soon as the deprecation note should be shown
- // $compiler->write('trigger_error(\'The helper form_enctype(form) is deprecated since version 2.3 and will be removed in 3.0. Use form_start(form) instead.\', E_USER_DEPRECATED)');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Node;
-
-/**
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class FormThemeNode extends \Twig_Node
-{
- public function __construct(\Twig_NodeInterface $form, \Twig_NodeInterface $resources, $lineno, $tag = null)
- {
- parent::__construct(array('form' => $form, 'resources' => $resources), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param \Twig_Compiler $compiler A Twig_Compiler instance
- */
- public function compile(\Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('$this->env->getExtension(\'form\')->renderer->setTheme(')
- ->subcompile($this->getNode('form'))
- ->raw(', ')
- ->subcompile($this->getNode('resources'))
- ->raw(");\n");
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Node;
-
-/**
- * Compiles a call to {@link FormRendererInterface::renderBlock()}.
- *
- * The function name is used as block name. For example, if the function name
- * is "foo", the block "foo" will be rendered.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class RenderBlockNode extends \Twig_Node_Expression_Function
-{
- public function compile(\Twig_Compiler $compiler)
- {
- $compiler->addDebugInfo($this);
- $arguments = iterator_to_array($this->getNode('arguments'));
- $compiler->write('$this->env->getExtension(\'form\')->renderer->renderBlock(');
-
- if (isset($arguments[0])) {
- $compiler->subcompile($arguments[0]);
- $compiler->raw(', \'' . $this->getAttribute('name') . '\'');
-
- if (isset($arguments[1])) {
- $compiler->raw(', ');
- $compiler->subcompile($arguments[1]);
- }
- }
-
- $compiler->raw(')');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Node;
-
-/**
- * @author Bernhard Schussek <bschussek@gmail.com>
- */
-class SearchAndRenderBlockNode extends \Twig_Node_Expression_Function
-{
- public function compile(\Twig_Compiler $compiler)
- {
- $compiler->addDebugInfo($this);
- $compiler->raw('$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(');
-
- preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches);
-
- $label = null;
- $arguments = iterator_to_array($this->getNode('arguments'));
- $blockNameSuffix = $matches[1];
-
- if (isset($arguments[0])) {
- $compiler->subcompile($arguments[0]);
- $compiler->raw(', \''.$blockNameSuffix.'\'');
-
- if (isset($arguments[1])) {
- if ('label' === $blockNameSuffix) {
- // The "label" function expects the label in the second and
- // the variables in the third argument
- $label = $arguments[1];
- $variables = isset($arguments[2]) ? $arguments[2] : null;
- $lineno = $label->getLine();
-
- if ($label instanceof \Twig_Node_Expression_Constant) {
- // If the label argument is given as a constant, we can either
- // strip it away if it is empty, or integrate it into the array
- // of variables at compile time.
- $labelIsExpression = false;
-
- // Only insert the label into the array if it is not empty
- if (!twig_test_empty($label->getAttribute('value'))) {
- $originalVariables = $variables;
- $variables = new \Twig_Node_Expression_Array(array(), $lineno);
- $labelKey = new \Twig_Node_Expression_Constant('label', $lineno);
-
- if (null !== $originalVariables) {
- foreach ($originalVariables->getKeyValuePairs() as $pair) {
- // Don't copy the original label attribute over if it exists
- if ((string) $labelKey !== (string) $pair['key']) {
- $variables->addElement($pair['value'], $pair['key']);
- }
- }
- }
-
- // Insert the label argument into the array
- $variables->addElement($label, $labelKey);
- }
- } else {
- // The label argument is not a constant, but some kind of
- // expression. This expression needs to be evaluated at runtime.
- // Depending on the result (whether it is null or not), the
- // label in the arguments should take precedence over the label
- // in the attributes or not.
- $labelIsExpression = true;
- }
- } else {
- // All other functions than "label" expect the variables
- // in the second argument
- $label = null;
- $variables = $arguments[1];
- $labelIsExpression = false;
- }
-
- if (null !== $variables || $labelIsExpression) {
- $compiler->raw(', ');
-
- if (null !== $variables) {
- $compiler->subcompile($variables);
- }
-
- if ($labelIsExpression) {
- if (null !== $variables) {
- $compiler->raw(' + ');
- }
-
- // Check at runtime whether the label is empty.
- // If not, add it to the array at runtime.
- $compiler->raw('(twig_test_empty($_label_ = ');
- $compiler->subcompile($label);
- $compiler->raw(') ? array() : array("label" => $_label_))');
- }
- }
- }
- }
-
- $compiler->raw(")");
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Node;
-
-/**
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TransDefaultDomainNode extends \Twig_Node
-{
- public function __construct(\Twig_Node_Expression $expr, $lineno = 0, $tag = null)
- {
- parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param \Twig_Compiler $compiler A Twig_Compiler instance
- */
- public function compile(\Twig_Compiler $compiler)
- {
- // noop as this node is just a marker for TranslationDefaultDomainNodeVisitor
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Node;
-
-/**
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TransNode extends \Twig_Node
-{
- public function __construct(\Twig_NodeInterface $body, \Twig_NodeInterface $domain = null, \Twig_Node_Expression $count = null, \Twig_Node_Expression $vars = null, \Twig_Node_Expression $locale = null, $lineno = 0, $tag = null)
- {
- parent::__construct(array('count' => $count, 'body' => $body, 'domain' => $domain, 'vars' => $vars, 'locale' => $locale), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param \Twig_Compiler $compiler A Twig_Compiler instance
- */
- public function compile(\Twig_Compiler $compiler)
- {
- $compiler->addDebugInfo($this);
-
- $vars = $this->getNode('vars');
- $defaults = new \Twig_Node_Expression_Array(array(), -1);
- if ($vars instanceof \Twig_Node_Expression_Array) {
- $defaults = $this->getNode('vars');
- $vars = null;
- }
- list($msg, $defaults) = $this->compileString($this->getNode('body'), $defaults);
-
- $method = null === $this->getNode('count') ? 'trans' : 'transChoice';
-
- $compiler
- ->write('echo $this->env->getExtension(\'translator\')->getTranslator()->'.$method.'(')
- ->subcompile($msg)
- ;
-
- $compiler->raw(', ');
-
- if (null !== $this->getNode('count')) {
- $compiler
- ->subcompile($this->getNode('count'))
- ->raw(', ')
- ;
- }
-
- if (null !== $vars) {
- $compiler
- ->raw('array_merge(')
- ->subcompile($defaults)
- ->raw(', ')
- ->subcompile($this->getNode('vars'))
- ->raw(')')
- ;
- } else {
- $compiler->subcompile($defaults);
- }
-
- $compiler->raw(', ');
-
- if (null === $this->getNode('domain')) {
- $compiler->repr('messages');
- } else {
- $compiler->subcompile($this->getNode('domain'));
- }
-
- if (null !== $this->getNode('locale')) {
- $compiler
- ->raw(', ')
- ->subcompile($this->getNode('locale'))
- ;
- }
- $compiler->raw(");\n");
- }
-
- protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars)
- {
- if ($body instanceof \Twig_Node_Expression_Constant) {
- $msg = $body->getAttribute('value');
- } elseif ($body instanceof \Twig_Node_Text) {
- $msg = $body->getAttribute('data');
- } else {
- return array($body, $vars);
- }
-
- preg_match_all('/(?<!%)%([^%]+)%/', $msg, $matches);
-
- if (version_compare(\Twig_Environment::VERSION, '1.5', '>=')) {
- foreach ($matches[1] as $var) {
- $key = new \Twig_Node_Expression_Constant('%'.$var.'%', $body->getLine());
- if (!$vars->hasElement($key)) {
- $vars->addElement(new \Twig_Node_Expression_Name($var, $body->getLine()), $key);
- }
- }
- } else {
- $current = array();
- foreach ($vars as $name => $var) {
- $current[$name] = true;
- }
- foreach ($matches[1] as $var) {
- if (!isset($current['%'.$var.'%'])) {
- $vars->setNode('%'.$var.'%', new \Twig_Node_Expression_Name($var, $body->getLine()));
- }
- }
- }
-
- return array(new \Twig_Node_Expression_Constant(str_replace('%%', '%', trim($msg)), $body->getLine()), $vars);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\NodeVisitor;
-
-/**
- * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
- */
-class Scope
-{
- /**
- * @var Scope|null
- */
- private $parent;
-
- /**
- * @var Scope[]
- */
- private $children;
-
- /**
- * @var array
- */
- private $data;
-
- /**
- * @var boolean
- */
- private $left;
-
- /**
- * @param Scope $parent
- */
- public function __construct(Scope $parent = null)
- {
- $this->parent = $parent;
- $this->left = false;
- $this->data = array();
- }
-
- /**
- * Opens a new child scope.
- *
- * @return Scope
- */
- public function enter()
- {
- $child = new self($this);
- $this->children[] = $child;
-
- return $child;
- }
-
- /**
- * Closes current scope and returns parent one.
- *
- * @return Scope|null
- */
- public function leave()
- {
- $this->left = true;
-
- return $this->parent;
- }
-
- /**
- * Stores data into current scope.
- *
- * @param string $key
- * @param mixed $value
- *
- * @throws \LogicException
- *
- * @return Scope Current scope
- */
- public function set($key, $value)
- {
- if ($this->left) {
- throw new \LogicException('Left scope is not mutable.');
- }
-
- $this->data[$key] = $value;
-
- return $this;
- }
-
- /**
- * Tests if a data is visible from current scope.
- *
- * @param string $key
- *
- * @return boolean
- */
- public function has($key)
- {
- if (array_key_exists($key, $this->data)) {
- return true;
- }
-
- if (null === $this->parent) {
- return false;
- }
-
- return $this->parent->has($key);
- }
-
- /**
- * Returns data visible from current scope.
- *
- * @param string $key
- * @param mixed $default
- *
- * @return mixed
- */
- public function get($key, $default = null)
- {
- if (array_key_exists($key, $this->data)) {
- return $this->data[$key];
- }
-
- if (null === $this->parent) {
- return $default;
- }
-
- return $this->parent->get($key, $default);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\NodeVisitor;
-
-use Symfony\Bridge\Twig\Node\TransNode;
-use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
-
-/**
- * TranslationDefaultDomainNodeVisitor.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface
-{
- /**
- * @var Scope
- */
- private $scope;
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- $this->scope = new Scope();
- }
-
- /**
- * {@inheritdoc}
- */
- public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env)
- {
- if ($node instanceof \Twig_Node_Block || $node instanceof \Twig_Node_Module) {
- $this->scope = $this->scope->enter();
- }
-
- if ($node instanceof TransDefaultDomainNode) {
- if ($node->getNode('expr') instanceof \Twig_Node_Expression_Constant) {
- $this->scope->set('domain', $node->getNode('expr'));
-
- return $node;
- } else {
- $var = $env->getParser()->getVarName();
- $name = new \Twig_Node_Expression_AssignName($var, $node->getLine());
- $this->scope->set('domain', new \Twig_Node_Expression_Name($var, $node->getLine()));
-
- return new \Twig_Node_Set(false, new \Twig_Node(array($name)), new \Twig_Node(array($node->getNode('expr'))), $node->getLine());
- }
- }
-
- if (!$this->scope->has('domain')) {
- return $node;
- }
-
- if ($node instanceof \Twig_Node_Expression_Filter && in_array($node->getNode('filter')->getAttribute('value'), array('trans', 'transchoice'))) {
- $ind = 'trans' === $node->getNode('filter')->getAttribute('value') ? 1 : 2;
- $arguments = $node->getNode('arguments');
- if (!$arguments->hasNode($ind)) {
- if (!$arguments->hasNode($ind - 1)) {
- $arguments->setNode($ind - 1, new \Twig_Node_Expression_Array(array(), $node->getLine()));
- }
-
- $arguments->setNode($ind, $this->scope->get('domain'));
- }
- } elseif ($node instanceof TransNode) {
- if (null === $node->getNode('domain')) {
- $node->setNode('domain', $this->scope->get('domain'));
- }
- }
-
- return $node;
- }
-
- /**
- * {@inheritdoc}
- */
- public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env)
- {
- if ($node instanceof TransDefaultDomainNode) {
- return false;
- }
-
- if ($node instanceof \Twig_Node_Block || $node instanceof \Twig_Node_Module) {
- $this->scope = $this->scope->leave();
- }
-
- return $node;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPriority()
- {
- return -10;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\NodeVisitor;
-
-use Symfony\Bridge\Twig\Node\TransNode;
-
-/**
- * TranslationNodeVisitor extracts translation messages.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TranslationNodeVisitor implements \Twig_NodeVisitorInterface
-{
- const UNDEFINED_DOMAIN = '_undefined';
-
- private $enabled = false;
- private $messages = array();
-
- public function enable()
- {
- $this->enabled = true;
- $this->messages = array();
- }
-
- public function disable()
- {
- $this->enabled = false;
- $this->messages = array();
- }
-
- public function getMessages()
- {
- return $this->messages;
- }
-
- /**
- * {@inheritdoc}
- */
- public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env)
- {
- if (!$this->enabled) {
- return $node;
- }
-
- if (
- $node instanceof \Twig_Node_Expression_Filter &&
- 'trans' === $node->getNode('filter')->getAttribute('value') &&
- $node->getNode('node') instanceof \Twig_Node_Expression_Constant
- ) {
- // extract constant nodes with a trans filter
- $this->messages[] = array(
- $node->getNode('node')->getAttribute('value'),
- $this->getReadDomainFromArguments($node->getNode('arguments'), 1),
- );
- } elseif (
- $node instanceof \Twig_Node_Expression_Filter &&
- 'transchoice' === $node->getNode('filter')->getAttribute('value') &&
- $node->getNode('node') instanceof \Twig_Node_Expression_Constant
- ) {
- // extract constant nodes with a trans filter
- $this->messages[] = array(
- $node->getNode('node')->getAttribute('value'),
- $this->getReadDomainFromArguments($node->getNode('arguments'), 2),
- );
- } elseif ($node instanceof TransNode) {
- // extract trans nodes
- $this->messages[] = array(
- $node->getNode('body')->getAttribute('data'),
- $this->getReadDomainFromNode($node->getNode('domain')),
- );
- }
-
- return $node;
- }
-
- /**
- * {@inheritdoc}
- */
- public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env)
- {
- return $node;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPriority()
- {
- return 0;
- }
-
- /**
- * @param \Twig_Node $arguments
- * @param int $index
- *
- * @return string|null
- */
- private function getReadDomainFromArguments(\Twig_Node $arguments, $index)
- {
- if ($arguments->hasNode('domain')) {
- $argument = $arguments->getNode('domain');
- } elseif ($arguments->hasNode($index)) {
- $argument = $arguments->getNode($index);
- } else {
- return null;
- }
-
- return $this->getReadDomainFromNode($argument);
- }
-
- /**
- * @param \Twig_Node $node
- *
- * @return string|null
- */
- private function getReadDomainFromNode(\Twig_Node $node = null)
- {
- if (null === $node) {
- return null;
- }
-
- if ($node instanceof \Twig_Node_Expression_Constant) {
- return $node->getAttribute('value');
- }
-
- return self::UNDEFINED_DOMAIN;
- }
-}
+++ /dev/null
-Twig Bridge
-===========
-
-Provides integration for [Twig](http://twig.sensiolabs.org/) with various
-Symfony2 components.
-
-Resources
----------
-
-If you want to run the unit tests, install dev dependencies before
-running PHPUnit:
-
- $ cd path/to/Symfony/Bridge/Twig/
- $ composer.phar install --dev
- $ phpunit
+++ /dev/null
-{# Widgets #}
-
-{% block form_widget %}
-{% spaceless %}
- {% if compound %}
- {{ block('form_widget_compound') }}
- {% else %}
- {{ block('form_widget_simple') }}
- {% endif %}
-{% endspaceless %}
-{% endblock form_widget %}
-
-{% block form_widget_simple %}
-{% spaceless %}
- {% set type = type|default('text') %}
- <input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
-{% endspaceless %}
-{% endblock form_widget_simple %}
-
-{% block form_widget_compound %}
-{% spaceless %}
- <div {{ block('widget_container_attributes') }}>
- {% if form.parent is empty %}
- {{ form_errors(form) }}
- {% endif %}
- {{ block('form_rows') }}
- {{ form_rest(form) }}
- </div>
-{% endspaceless %}
-{% endblock form_widget_compound %}
-
-{% block collection_widget %}
-{% spaceless %}
- {% if prototype is defined %}
- {% set attr = attr|merge({'data-prototype': form_row(prototype) }) %}
- {% endif %}
- {{ block('form_widget') }}
-{% endspaceless %}
-{% endblock collection_widget %}
-
-{% block textarea_widget %}
-{% spaceless %}
- <textarea {{ block('widget_attributes') }}>{{ value }}</textarea>
-{% endspaceless %}
-{% endblock textarea_widget %}
-
-{% block choice_widget %}
-{% spaceless %}
- {% if expanded %}
- {{ block('choice_widget_expanded') }}
- {% else %}
- {{ block('choice_widget_collapsed') }}
- {% endif %}
-{% endspaceless %}
-{% endblock choice_widget %}
-
-{% block choice_widget_expanded %}
-{% spaceless %}
- <div {{ block('widget_container_attributes') }}>
- {% for child in form %}
- {{ form_widget(child) }}
- {{ form_label(child) }}
- {% endfor %}
- </div>
-{% endspaceless %}
-{% endblock choice_widget_expanded %}
-
-{% block choice_widget_collapsed %}
-{% spaceless %}
- <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
- {% if empty_value is not none %}
- <option {% if required %} disabled="disabled"{% if value is empty %} selected="selected"{% endif %}{% else %} value=""{% endif %}>{{ empty_value|trans({}, translation_domain) }}</option>
- {% endif %}
- {% if preferred_choices|length > 0 %}
- {% set options = preferred_choices %}
- {{ block('choice_widget_options') }}
- {% if choices|length > 0 and separator is not none %}
- <option disabled="disabled">{{ separator }}</option>
- {% endif %}
- {% endif %}
- {% set options = choices %}
- {{ block('choice_widget_options') }}
- </select>
-{% endspaceless %}
-{% endblock choice_widget_collapsed %}
-
-{% block choice_widget_options %}
-{% spaceless %}
- {% for group_label, choice in options %}
- {% if choice is iterable %}
- <optgroup label="{{ group_label|trans({}, translation_domain) }}">
- {% set options = choice %}
- {{ block('choice_widget_options') }}
- </optgroup>
- {% else %}
- <option value="{{ choice.value }}"{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice.label|trans({}, translation_domain) }}</option>
- {% endif %}
- {% endfor %}
-{% endspaceless %}
-{% endblock choice_widget_options %}
-
-{% block checkbox_widget %}
-{% spaceless %}
- <input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
-{% endspaceless %}
-{% endblock checkbox_widget %}
-
-{% block radio_widget %}
-{% spaceless %}
- <input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
-{% endspaceless %}
-{% endblock radio_widget %}
-
-{% block datetime_widget %}
-{% spaceless %}
- {% if widget == 'single_text' %}
- {{ block('form_widget_simple') }}
- {% else %}
- <div {{ block('widget_container_attributes') }}>
- {{ form_errors(form.date) }}
- {{ form_errors(form.time) }}
- {{ form_widget(form.date) }}
- {{ form_widget(form.time) }}
- </div>
- {% endif %}
-{% endspaceless %}
-{% endblock datetime_widget %}
-
-{% block date_widget %}
-{% spaceless %}
- {% if widget == 'single_text' %}
- {{ block('form_widget_simple') }}
- {% else %}
- <div {{ block('widget_container_attributes') }}>
- {{ date_pattern|replace({
- '{{ year }}': form_widget(form.year),
- '{{ month }}': form_widget(form.month),
- '{{ day }}': form_widget(form.day),
- })|raw }}
- </div>
- {% endif %}
-{% endspaceless %}
-{% endblock date_widget %}
-
-{% block time_widget %}
-{% spaceless %}
- {% if widget == 'single_text' %}
- {{ block('form_widget_simple') }}
- {% else %}
- {% set vars = widget == 'text' ? { 'attr': { 'size': 1 }} : {} %}
- <div {{ block('widget_container_attributes') }}>
- {{ form_widget(form.hour, vars) }}{% if with_minutes %}:{{ form_widget(form.minute, vars) }}{% endif %}{% if with_seconds %}:{{ form_widget(form.second, vars) }}{% endif %}
- </div>
- {% endif %}
-{% endspaceless %}
-{% endblock time_widget %}
-
-{% block number_widget %}
-{% spaceless %}
- {# type="number" doesn't work with floats #}
- {% set type = type|default('text') %}
- {{ block('form_widget_simple') }}
-{% endspaceless %}
-{% endblock number_widget %}
-
-{% block integer_widget %}
-{% spaceless %}
- {% set type = type|default('number') %}
- {{ block('form_widget_simple') }}
-{% endspaceless %}
-{% endblock integer_widget %}
-
-{% block money_widget %}
-{% spaceless %}
- {{ money_pattern|replace({ '{{ widget }}': block('form_widget_simple') })|raw }}
-{% endspaceless %}
-{% endblock money_widget %}
-
-{% block url_widget %}
-{% spaceless %}
- {% set type = type|default('url') %}
- {{ block('form_widget_simple') }}
-{% endspaceless %}
-{% endblock url_widget %}
-
-{% block search_widget %}
-{% spaceless %}
- {% set type = type|default('search') %}
- {{ block('form_widget_simple') }}
-{% endspaceless %}
-{% endblock search_widget %}
-
-{% block percent_widget %}
-{% spaceless %}
- {% set type = type|default('text') %}
- {{ block('form_widget_simple') }} %
-{% endspaceless %}
-{% endblock percent_widget %}
-
-{% block password_widget %}
-{% spaceless %}
- {% set type = type|default('password') %}
- {{ block('form_widget_simple') }}
-{% endspaceless %}
-{% endblock password_widget %}
-
-{% block hidden_widget %}
-{% spaceless %}
- {% set type = type|default('hidden') %}
- {{ block('form_widget_simple') }}
-{% endspaceless %}
-{% endblock hidden_widget %}
-
-{% block email_widget %}
-{% spaceless %}
- {% set type = type|default('email') %}
- {{ block('form_widget_simple') }}
-{% endspaceless %}
-{% endblock email_widget %}
-
-{% block button_widget %}
-{% spaceless %}
- {% if label is empty %}
- {% set label = name|humanize %}
- {% endif %}
- <button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ label|trans({}, translation_domain) }}</button>
-{% endspaceless %}
-{% endblock button_widget %}
-
-{% block submit_widget %}
-{% spaceless %}
- {% set type = type|default('submit') %}
- {{ block('button_widget') }}
-{% endspaceless %}
-{% endblock submit_widget %}
-
-{% block reset_widget %}
-{% spaceless %}
- {% set type = type|default('reset') %}
- {{ block('button_widget') }}
-{% endspaceless %}
-{% endblock reset_widget %}
-
-{# Labels #}
-
-{% block form_label %}
-{% spaceless %}
- {% if label is not sameas(false) %}
- {% if not compound %}
- {% set label_attr = label_attr|merge({'for': id}) %}
- {% endif %}
- {% if required %}
- {% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
- {% endif %}
- {% if label is empty %}
- {% set label = name|humanize %}
- {% endif %}
- <label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>
- {% endif %}
-{% endspaceless %}
-{% endblock form_label %}
-
-{% block button_label %}{% endblock %}
-
-{# Rows #}
-
-{% block repeated_row %}
-{% spaceless %}
- {#
- No need to render the errors here, as all errors are mapped
- to the first child (see RepeatedTypeValidatorExtension).
- #}
- {{ block('form_rows') }}
-{% endspaceless %}
-{% endblock repeated_row %}
-
-{% block form_row %}
-{% spaceless %}
- <div>
- {{ form_label(form) }}
- {{ form_errors(form) }}
- {{ form_widget(form) }}
- </div>
-{% endspaceless %}
-{% endblock form_row %}
-
-{% block button_row %}
-{% spaceless %}
- <div>
- {{ form_widget(form) }}
- </div>
-{% endspaceless %}
-{% endblock button_row %}
-
-{% block hidden_row %}
- {{ form_widget(form) }}
-{% endblock hidden_row %}
-
-{# Misc #}
-
-{% block form %}
-{% spaceless %}
- {{ form_start(form) }}
- {{ form_widget(form) }}
- {{ form_end(form) }}
-{% endspaceless %}
-{% endblock form %}
-
-{% block form_start %}
-{% spaceless %}
- {% set method = method|upper %}
- {% if method in ["GET", "POST"] %}
- {% set form_method = method %}
- {% else %}
- {% set form_method = "POST" %}
- {% endif %}
- <form method="{{ form_method|lower }}" action="{{ action }}"{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %}>
- {% if form_method != method %}
- <input type="hidden" name="_method" value="{{ method }}" />
- {% endif %}
-{% endspaceless %}
-{% endblock form_start %}
-
-{% block form_end %}
-{% spaceless %}
- {% if not render_rest is defined or render_rest %}
- {{ form_rest(form) }}
- {% endif %}
- </form>
-{% endspaceless %}
-{% endblock form_end %}
-
-{% block form_enctype %}
-{% spaceless %}
- {% if multipart %}enctype="multipart/form-data"{% endif %}
-{% endspaceless %}
-{% endblock form_enctype %}
-
-{% block form_errors %}
-{% spaceless %}
- {% if errors|length > 0 %}
- <ul>
- {% for error in errors %}
- <li>{{ error.message }}</li>
- {% endfor %}
- </ul>
- {% endif %}
-{% endspaceless %}
-{% endblock form_errors %}
-
-{% block form_rest %}
-{% spaceless %}
- {% for child in form %}
- {% if not child.rendered %}
- {{ form_row(child) }}
- {% endif %}
- {% endfor %}
-{% endspaceless %}
-{% endblock form_rest %}
-
-{# Support #}
-
-{% block form_rows %}
-{% spaceless %}
- {% for child in form %}
- {{ form_row(child) }}
- {% endfor %}
-{% endspaceless %}
-{% endblock form_rows %}
-
-{% block widget_attributes %}
-{% spaceless %}
- id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
- {% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %}
-{% endspaceless %}
-{% endblock widget_attributes %}
-
-{% block widget_container_attributes %}
-{% spaceless %}
- {% if id is not empty %}id="{{ id }}" {% endif %}
- {% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
-{% endspaceless %}
-{% endblock widget_container_attributes %}
-
-{% block button_attributes %}
-{% spaceless %}
- id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif %}
- {% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
-{% endspaceless %}
-{% endblock button_attributes %}
+++ /dev/null
-{% use "form_div_layout.html.twig" %}
-
-{% block form_row %}
-{% spaceless %}
- <tr>
- <td>
- {{ form_label(form) }}
- </td>
- <td>
- {{ form_errors(form) }}
- {{ form_widget(form) }}
- </td>
- </tr>
-{% endspaceless %}
-{% endblock form_row %}
-
-{% block button_row %}
-{% spaceless %}
- <tr>
- <td></td>
- <td>
- {{ form_widget(form) }}
- </td>
- </tr>
-{% endspaceless %}
-{% endblock button_row %}
-
-{% block hidden_row %}
-{% spaceless %}
- <tr style="display: none">
- <td colspan="2">
- {{ form_widget(form) }}
- </td>
- </tr>
-{% endspaceless %}
-{% endblock hidden_row %}
-
-{% block form_widget_compound %}
-{% spaceless %}
- <table {{ block('widget_container_attributes') }}>
- {% if form.parent is empty and errors|length > 0 %}
- <tr>
- <td colspan="2">
- {{ form_errors(form) }}
- </td>
- </tr>
- {% endif %}
- {{ block('form_rows') }}
- {{ form_rest(form) }}
- </table>
-{% endspaceless %}
-{% endblock form_widget_compound %}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension;
-
-use Symfony\Bridge\Twig\Extension\CodeExtension;
-
-class CodeExtensionTest extends \PHPUnit_Framework_TestCase
-{
- protected $helper;
-
- public function testFormatFile()
- {
- $expected = sprintf('<a href="txmt://open?url=file://%s&line=25" title="Click to open this file" class="file_link">%s at line 25</a>', __FILE__, __FILE__);
- $this->assertEquals($expected, $this->getExtension()->formatFile(__FILE__, 25));
- }
-
- /**
- * @dataProvider getClassNameProvider
- */
- public function testGettingClassAbbreviation($class, $abbr)
- {
- $this->assertEquals($this->getExtension()->abbrClass($class), $abbr);
- }
-
- /**
- * @dataProvider getMethodNameProvider
- */
- public function testGettingMethodAbbreviation($method, $abbr)
- {
- $this->assertEquals($this->getExtension()->abbrMethod($method), $abbr);
- }
-
- public function getClassNameProvider()
- {
- return array(
- array('F\Q\N\Foo', '<abbr title="F\Q\N\Foo">Foo</abbr>'),
- array('Bare', '<abbr title="Bare">Bare</abbr>'),
- );
- }
-
- public function getMethodNameProvider()
- {
- return array(
- array('F\Q\N\Foo::Method', '<abbr title="F\Q\N\Foo">Foo</abbr>::Method()'),
- array('Bare::Method', '<abbr title="Bare">Bare</abbr>::Method()'),
- array('Closure', '<abbr title="Closure">Closure</abbr>'),
- array('Method', '<abbr title="Method">Method</abbr>()')
- );
- }
-
- public function testGetName()
- {
- $this->assertEquals('code', $this->getExtension()->getName());
- }
-
- protected function getExtension()
- {
- return new CodeExtension('txmt://open?url=file://%f&line=%l', '/root', 'UTF-8');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures;
-
-// Preventing autoloader throwing E_FATAL when Twig is now available
-if (!class_exists('Twig_Environment')) {
- class StubFilesystemLoader
- {
- }
-} else {
- class StubFilesystemLoader extends \Twig_Loader_Filesystem
- {
- protected function findTemplate($name)
- {
- // strip away bundle name
- $parts = explode(':', $name);
-
- return parent::findTemplate(end($parts));
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures;
-
-use Symfony\Component\Translation\TranslatorInterface;
-
-class StubTranslator implements TranslatorInterface
-{
- public function trans($id, array $parameters = array(), $domain = null, $locale = null)
- {
- return '[trans]'.$id.'[/trans]';
- }
-
- public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
- {
- return '[trans]'.$id.'[/trans]';
- }
-
- public function setLocale($locale)
- {
- }
-
- public function getLocale()
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension;
-
-use Symfony\Bridge\Twig\Extension\FormExtension;
-use Symfony\Bridge\Twig\Form\TwigRenderer;
-use Symfony\Bridge\Twig\Form\TwigRendererEngine;
-use Symfony\Bridge\Twig\Extension\TranslationExtension;
-use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
-use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
-use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Extension\Core\View\ChoiceView;
-use Symfony\Component\Form\Tests\AbstractDivLayoutTest;
-
-class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
-{
- /**
- * @var FormExtension
- */
- protected $extension;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Locale\Locale')) {
- $this->markTestSkipped('The "Locale" component is not available');
- }
-
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- if (!class_exists('Symfony\Component\Form\Form')) {
- $this->markTestSkipped('The "Form" component is not available');
- }
-
- if (!class_exists('Twig_Environment')) {
- $this->markTestSkipped('Twig is not available.');
- }
-
- parent::setUp();
-
- $rendererEngine = new TwigRendererEngine(array(
- 'form_div_layout.html.twig',
- 'custom_widgets.html.twig',
- ));
- $renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'));
-
- $this->extension = new FormExtension($renderer);
-
- $loader = new StubFilesystemLoader(array(
- __DIR__.'/../../Resources/views/Form',
- __DIR__,
- ));
-
- $environment = new \Twig_Environment($loader, array('strict_variables' => true));
- $environment->addExtension(new TranslationExtension(new StubTranslator()));
- $environment->addGlobal('global', '');
- $environment->addExtension($this->extension);
-
- $this->extension->initRuntime($environment);
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->extension = null;
- }
-
- public function testThemeBlockInheritanceUsingUse()
- {
- $view = $this->factory
- ->createNamed('name', 'email')
- ->createView()
- ;
-
- $this->setTheme($view, array('theme_use.html.twig'));
-
- $this->assertMatchesXpath(
- $this->renderWidget($view),
- '/input[@type="email"][@rel="theme"]'
- );
- }
-
- public function testThemeBlockInheritanceUsingExtend()
- {
- $view = $this->factory
- ->createNamed('name', 'email')
- ->createView()
- ;
-
- $this->setTheme($view, array('theme_extends.html.twig'));
-
- $this->assertMatchesXpath(
- $this->renderWidget($view),
- '/input[@type="email"][@rel="theme"]'
- );
- }
-
- public function isSelectedChoiceProvider()
- {
- // The commented cases should not be necessary anymore, because the
- // choice lists should assure that both values passed here are always
- // strings
- return array(
-// array(true, 0, 0),
- array(true, '0', '0'),
- array(true, '1', '1'),
-// array(true, false, 0),
-// array(true, true, 1),
- array(true, '', ''),
-// array(true, null, ''),
- array(true, '1.23', '1.23'),
- array(true, 'foo', 'foo'),
- array(true, 'foo10', 'foo10'),
- array(true, 'foo', array(1, 'foo', 'foo10')),
-
- array(false, 10, array(1, 'foo', 'foo10')),
- array(false, 0, array(1, 'foo', 'foo10')),
- );
- }
-
- /**
- * @dataProvider isSelectedChoiceProvider
- */
- public function testIsChoiceSelected($expected, $choice, $value)
- {
- $choice = new ChoiceView($choice, $choice, $choice.' label');
-
- $this->assertSame($expected, $this->extension->isSelectedChoice($choice, $value));
- }
-
- protected function renderForm(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
- }
-
- protected function renderEnctype(FormView $view)
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
- }
-
- protected function renderLabel(FormView $view, $label = null, array $vars = array())
- {
- if ($label !== null) {
- $vars += array('label' => $label);
- }
-
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars);
- }
-
- protected function renderErrors(FormView $view)
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors');
- }
-
- protected function renderWidget(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars);
- }
-
- protected function renderRow(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars);
- }
-
- protected function renderRest(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
- }
-
- protected function renderStart(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
- }
-
- protected function renderEnd(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
- }
-
- protected function setTheme(FormView $view, array $themes)
- {
- $this->extension->renderer->setTheme($view, $themes);
- }
-
- public static function themeBlockInheritanceProvider()
- {
- return array(
- array(array('theme.html.twig'))
- );
- }
-
- public static function themeInheritanceProvider()
- {
- return array(
- array(array('parent_label.html.twig'), array('child_label.html.twig'))
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension;
-
-use Symfony\Component\Form\FormView;
-use Symfony\Bridge\Twig\Form\TwigRenderer;
-use Symfony\Bridge\Twig\Form\TwigRendererEngine;
-use Symfony\Bridge\Twig\Extension\FormExtension;
-use Symfony\Bridge\Twig\Extension\TranslationExtension;
-use Symfony\Component\Form\Tests\AbstractTableLayoutTest;
-use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
-use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
-
-class FormExtensionTableLayoutTest extends AbstractTableLayoutTest
-{
- /**
- * @var FormExtension
- */
- protected $extension;
-
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Locale\Locale')) {
- $this->markTestSkipped('The "Locale" component is not available');
- }
-
- if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
- $this->markTestSkipped('The "EventDispatcher" component is not available');
- }
-
- if (!class_exists('Symfony\Component\Form\Form')) {
- $this->markTestSkipped('The "Form" component is not available');
- }
-
- if (!class_exists('Twig_Environment')) {
- $this->markTestSkipped('Twig is not available.');
- }
-
- parent::setUp();
-
- $rendererEngine = new TwigRendererEngine(array(
- 'form_table_layout.html.twig',
- 'custom_widgets.html.twig',
- ));
- $renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'));
-
- $this->extension = new FormExtension($renderer);
-
- $loader = new StubFilesystemLoader(array(
- __DIR__.'/../../Resources/views/Form',
- __DIR__,
- ));
-
- $environment = new \Twig_Environment($loader, array('strict_variables' => true));
- $environment->addExtension(new TranslationExtension(new StubTranslator()));
- $environment->addGlobal('global', '');
- $environment->addExtension($this->extension);
-
- $this->extension->initRuntime($environment);
- }
-
- protected function tearDown()
- {
- parent::tearDown();
-
- $this->extension = null;
- }
-
- protected function renderForm(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
- }
-
- protected function renderEnctype(FormView $view)
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
- }
-
- protected function renderLabel(FormView $view, $label = null, array $vars = array())
- {
- if ($label !== null) {
- $vars += array('label' => $label);
- }
-
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars);
- }
-
- protected function renderErrors(FormView $view)
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors');
- }
-
- protected function renderWidget(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars);
- }
-
- protected function renderRow(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars);
- }
-
- protected function renderRest(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
- }
-
- protected function renderStart(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
- }
-
- protected function renderEnd(FormView $view, array $vars = array())
- {
- return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
- }
-
- protected function setTheme(FormView $view, array $themes)
- {
- $this->extension->renderer->setTheme($view, $themes);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension;
-
-use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
-use Symfony\Bridge\Twig\Tests\TestCase;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
-
-class HttpKernelExtensionTest extends TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- if (!class_exists('Symfony\Component\HttpKernel\HttpKernel')) {
- $this->markTestSkipped('The "HttpKernel" component is not available');
- }
-
- if (!class_exists('Twig_Environment')) {
- $this->markTestSkipped('Twig is not available.');
- }
- }
-
- /**
- * @expectedException \Twig_Error_Runtime
- */
- public function testFragmentWithError()
- {
- $kernel = $this->getFragmentHandler($this->throwException(new \Exception('foo')));
-
- $loader = new \Twig_Loader_Array(array('index' => '{{ fragment("foo") }}'));
- $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
- $twig->addExtension(new HttpKernelExtension($kernel));
-
- $this->renderTemplate($kernel);
- }
-
- protected function getFragmentHandler($return)
- {
- $strategy = $this->getMock('Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface');
- $strategy->expects($this->once())->method('getName')->will($this->returnValue('inline'));
- $strategy->expects($this->once())->method('render')->will($return);
-
- $renderer = new FragmentHandler(array($strategy));
- $renderer->setRequest(Request::create('/'));
-
- return $renderer;
- }
-
- protected function renderTemplate(FragmentHandler $renderer, $template = '{{ render("foo") }}')
- {
- $loader = new \Twig_Loader_Array(array('index' => $template));
- $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
- $twig->addExtension(new HttpKernelExtension($renderer));
-
- return $twig->render('index');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension;
-
-use Symfony\Bridge\Twig\Extension\RoutingExtension;
-use Symfony\Bridge\Twig\Tests\TestCase;
-
-class RoutingExtensionTest extends TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- if (!class_exists('Symfony\Component\Routing\Route')) {
- $this->markTestSkipped('The "Routing" component is not available');
- }
- }
-
- /**
- * @dataProvider getEscapingTemplates
- */
- public function testEscaping($template, $mustBeEscaped)
- {
- $twig = new \Twig_Environment(null, array('debug' => true, 'cache' => false, 'autoescape' => true, 'optimizations' => 0));
- $twig->addExtension(new RoutingExtension($this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface')));
-
- $nodes = $twig->parse($twig->tokenize($template));
-
- $this->assertSame($mustBeEscaped, $nodes->getNode('body')->getNode(0)->getNode('expr') instanceof \Twig_Node_Expression_Filter);
- }
-
- public function getEscapingTemplates()
- {
- return array(
- array('{{ path("foo") }}', false),
- array('{{ path("foo", {}) }}', false),
- array('{{ path("foo", { foo: "foo" }) }}', false),
- array('{{ path("foo", foo) }}', true),
- array('{{ path("foo", { foo: foo }) }}', true),
- array('{{ path("foo", { foo: ["foo", "bar"] }) }}', true),
- array('{{ path("foo", { foo: "foo", bar: "bar" }) }}', true),
-
- array('{{ path(name = "foo", parameters = {}) }}', false),
- array('{{ path(name = "foo", parameters = { foo: "foo" }) }}', false),
- array('{{ path(name = "foo", parameters = foo) }}', true),
- array('{{ path(name = "foo", parameters = { foo: ["foo", "bar"] }) }}', true),
- array('{{ path(name = "foo", parameters = { foo: foo }) }}', true),
- array('{{ path(name = "foo", parameters = { foo: "foo", bar: "bar" }) }}', true),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Extension;
-
-use Symfony\Bridge\Twig\Extension\TranslationExtension;
-use Symfony\Component\Translation\Translator;
-use Symfony\Component\Translation\MessageSelector;
-use Symfony\Component\Translation\Loader\ArrayLoader;
-use Symfony\Bridge\Twig\Tests\TestCase;
-
-class TranslationExtensionTest extends TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- if (!class_exists('Symfony\Component\Translation\Translator')) {
- $this->markTestSkipped('The "Translation" component is not available');
- }
-
- if (!class_exists('Twig_Environment')) {
- $this->markTestSkipped('Twig is not available.');
- }
- }
-
- public function testEscaping()
- {
- $output = $this->getTemplate('{% trans %}Percent: %value%%% (%msg%){% endtrans %}')->render(array('value' => 12, 'msg' => 'approx.'));
-
- $this->assertEquals('Percent: 12% (approx.)', $output);
- }
-
- /**
- * @dataProvider getTransTests
- */
- public function testTrans($template, $expected, array $variables = array())
- {
- if ($expected != $this->getTemplate($template)->render($variables)) {
- print $template."\n";
- $loader = new \Twig_Loader_Array(array('index' => $template));
- $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
- $twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector())));
-
- echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSource('index'), 'index')))."\n\n";
- $this->assertEquals($expected, $this->getTemplate($template)->render($variables));
- }
-
- $this->assertEquals($expected, $this->getTemplate($template)->render($variables));
- }
-
- public function getTransTests()
- {
- return array(
- // trans tag
- array('{% trans %}Hello{% endtrans %}', 'Hello'),
- array('{% trans %}%name%{% endtrans %}', 'Symfony2', array('name' => 'Symfony2')),
-
- array('{% trans from elsewhere %}Hello{% endtrans %}', 'Hello'),
-
- array('{% trans %}Hello %name%{% endtrans %}', 'Hello Symfony2', array('name' => 'Symfony2')),
- array('{% trans with { \'%name%\': \'Symfony2\' } %}Hello %name%{% endtrans %}', 'Hello Symfony2'),
- array('{% set vars = { \'%name%\': \'Symfony2\' } %}{% trans with vars %}Hello %name%{% endtrans %}', 'Hello Symfony2'),
-
- array('{% trans into "fr"%}Hello{% endtrans %}', 'Hello'),
-
- // transchoice
- array('{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
- 'There is no apples', array('count' => 0)),
- array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
- 'There is 5 apples', array('count' => 5)),
- array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
- 'There is 5 apples (Symfony2)', array('count' => 5, 'name' => 'Symfony2')),
- array('{% transchoice count with { \'%name%\': \'Symfony2\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
- 'There is 5 apples (Symfony2)', array('count' => 5)),
- array('{% transchoice count into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
- 'There is no apples', array('count' => 0)),
-
- // trans filter
- array('{{ "Hello"|trans }}', 'Hello'),
- array('{{ name|trans }}', 'Symfony2', array('name' => 'Symfony2')),
- array('{{ hello|trans({ \'%name%\': \'Symfony2\' }) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
- array('{% set vars = { \'%name%\': \'Symfony2\' } %}{{ hello|trans(vars) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
- array('{{ "Hello"|trans({}, "messages", "fr") }}', 'Hello'),
-
- // transchoice filter
- array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count) }}', 'There is 5 apples', array('count' => 5)),
- array('{{ text|transchoice(5, {\'%name%\': \'Symfony2\'}) }}', 'There is 5 apples (Symfony2)', array('text' => '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%)')),
- array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count, {}, "messages", "fr") }}', 'There is 5 apples', array('count' => 5)),
- );
- }
-
- public function testDefaultTranslationDomain()
- {
- $templates = array(
- 'index' => '
- {%- extends "base" %}
-
- {%- trans_default_domain "foo" %}
-
- {%- block content %}
- {%- trans %}foo{% endtrans %}
- {%- trans from "custom" %}foo{% endtrans %}
- {{- "foo"|trans }}
- {{- "foo"|trans({}, "custom") }}
- {{- "foo"|transchoice(1) }}
- {{- "foo"|transchoice(1, {}, "custom") }}
- {% endblock %}
- ',
-
- 'base' => '
- {%- block content "" %}
- ',
- );
-
- $translator = new Translator('en', new MessageSelector());
- $translator->addLoader('array', new ArrayLoader());
- $translator->addResource('array', array('foo' => 'foo (messages)'), 'en');
- $translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom');
- $translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo');
-
- $template = $this->getTemplate($templates, $translator);
-
- $this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array())));
- }
-
- protected function getTemplate($template, $translator = null)
- {
- if (null === $translator) {
- $translator = new Translator('en', new MessageSelector());
- }
-
- if (is_array($template)) {
- $loader = new \Twig_Loader_Array($template);
- } else {
- $loader = new \Twig_Loader_Array(array('index' => $template));
- }
- $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false));
- $twig->addExtension(new TranslationExtension($translator));
-
- return $twig->loadTemplate('index');
- }
-}
+++ /dev/null
-{% block form_label %}
- <label>{{ global }}child</label>
-{% endblock form_label %}
+++ /dev/null
-{% block _text_id_widget %}
-{% spaceless %}
- <div id="container">
- {{ form_widget(form) }}
- </div>
-{% endspaceless %}
-{% endblock _text_id_widget %}
-
-{% block _name_entry_label %}
-{% spaceless %}
- {% if label is empty %}
- {% set label = name|humanize %}
- {% endif %}
- <label>Custom label: {{ label|trans({}, translation_domain) }}</label>
-{% endspaceless %}
-{% endblock _name_entry_label %}
+++ /dev/null
-{% block form_label %}
- <label>parent</label>
-{% endblock form_label %}
+++ /dev/null
-{% block form_widget_simple %}
-{% spaceless %}
- {% set type = type|default('text') %}
- <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
-{% endspaceless %}
-{% endblock form_widget_simple %}
+++ /dev/null
-{% extends 'form_div_layout.html.twig' %}
-
-{% block form_widget_simple %}
-{% spaceless %}
- {% set type = type|default('text') %}
- <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
-{% endspaceless %}
-{% endblock form_widget_simple %}
+++ /dev/null
-{% use 'form_div_layout.html.twig' %}
-
-{% block form_widget_simple %}
-{% spaceless %}
- {% set type = type|default('text') %}
- <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
-{% endspaceless %}
-{% endblock form_widget_simple %}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Node;
-
-use Symfony\Bridge\Twig\Tests\TestCase;
-use Symfony\Bridge\Twig\Node\FormThemeNode;
-
-class FormThemeTest extends TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) {
- $this->markTestSkipped('Requires Twig version to be at least 1.5.0.');
- }
- }
-
- public function testConstructor()
- {
- $form = new \Twig_Node_Expression_Name('form', 0);
- $resources = new \Twig_Node(array(
- new \Twig_Node_Expression_Constant('tpl1', 0),
- new \Twig_Node_Expression_Constant('tpl2', 0)
- ));
-
- $node = new FormThemeNode($form, $resources, 0);
-
- $this->assertEquals($form, $node->getNode('form'));
- $this->assertEquals($resources, $node->getNode('resources'));
- }
-
- public function testCompile()
- {
- $form = new \Twig_Node_Expression_Name('form', 0);
- $resources = new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant(0, 0),
- new \Twig_Node_Expression_Constant('tpl1', 0),
- new \Twig_Node_Expression_Constant(1, 0),
- new \Twig_Node_Expression_Constant('tpl2', 0)
- ), 0);
-
- $node = new FormThemeNode($form, $resources, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->setTheme(%s, array(0 => "tpl1", 1 => "tpl2"));',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
-
- $resources = new \Twig_Node_Expression_Constant('tpl1', 0);
-
- $node = new FormThemeNode($form, $resources, 0);
-
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->setTheme(%s, "tpl1");',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- protected function getVariableGetter($name)
- {
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
- return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name);
- }
-
- return sprintf('$this->getContext($context, "%s")', $name);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Node;
-
-use Symfony\Bridge\Twig\Tests\TestCase;
-use Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode;
-
-class SearchAndRenderBlockNodeTest extends TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) {
- $this->markTestSkipped('Requires Twig version to be at least 1.5.0.');
- }
- }
-
- public function testCompileWidget()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'widget\')',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileWidgetWithVariables()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant('foo', 0),
- new \Twig_Node_Expression_Constant('bar', 0),
- ), 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'widget\', array("foo" => "bar"))',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithLabel()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Constant('my label', 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("label" => "my label"))',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithNullLabel()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Constant(null, 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- // "label" => null must not be included in the output!
- // Otherwise the default label is overwritten with null.
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithEmptyStringLabel()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Constant('', 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- // "label" => null must not be included in the output!
- // Otherwise the default label is overwritten with null.
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithDefaultLabel()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\')',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithAttributes()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Constant(null, 0),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant('foo', 0),
- new \Twig_Node_Expression_Constant('bar', 0),
- ), 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- // "label" => null must not be included in the output!
- // Otherwise the default label is overwritten with null.
- // https://github.com/symfony/symfony/issues/5029
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar"))',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithLabelAndAttributes()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Constant('value in argument', 0),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant('foo', 0),
- new \Twig_Node_Expression_Constant('bar', 0),
- new \Twig_Node_Expression_Constant('label', 0),
- new \Twig_Node_Expression_Constant('value in attributes', 0),
- ), 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in argument"))',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithLabelThatEvaluatesToNull()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Conditional(
- // if
- new \Twig_Node_Expression_Constant(true, 0),
- // then
- new \Twig_Node_Expression_Constant(null, 0),
- // else
- new \Twig_Node_Expression_Constant(null, 0),
- 0
- ),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- // "label" => null must not be included in the output!
- // Otherwise the default label is overwritten with null.
- // https://github.com/symfony/symfony/issues/5029
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes()
- {
- $arguments = new \Twig_Node(array(
- new \Twig_Node_Expression_Name('form', 0),
- new \Twig_Node_Expression_Conditional(
- // if
- new \Twig_Node_Expression_Constant(true, 0),
- // then
- new \Twig_Node_Expression_Constant(null, 0),
- // else
- new \Twig_Node_Expression_Constant(null, 0),
- 0
- ),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant('foo', 0),
- new \Twig_Node_Expression_Constant('bar', 0),
- new \Twig_Node_Expression_Constant('label', 0),
- new \Twig_Node_Expression_Constant('value in attributes', 0),
- ), 0),
- ));
-
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
-
- $compiler = new \Twig_Compiler(new \Twig_Environment());
-
- // "label" => null must not be included in the output!
- // Otherwise the default label is overwritten with null.
- // https://github.com/symfony/symfony/issues/5029
- $this->assertEquals(
- sprintf(
- '$this->env->getExtension(\'form\')->renderer->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in attributes") + (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))',
- $this->getVariableGetter('form')
- ),
- trim($compiler->compile($node)->getSource())
- );
- }
-
- protected function getVariableGetter($name)
- {
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
- return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name);
- }
-
- return sprintf('$this->getContext($context, "%s")', $name);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
-
-use Symfony\Bridge\Twig\NodeVisitor\Scope;
-use Symfony\Bridge\Twig\Tests\TestCase;
-
-class ScopeTest extends TestCase
-{
- public function testScopeInitiation()
- {
- $scope = new Scope();
- $scope->enter();
- $this->assertNull($scope->get('test'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
-
-use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor;
-use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
-use Symfony\Bridge\Twig\Tests\TestCase;
-
-class TranslationDefaultDomainNodeVisitorTest extends TestCase
-{
- private static $message = 'message';
- private static $domain = 'domain';
-
- /** @dataProvider getDefaultDomainAssignmentTestData */
- public function testDefaultDomainAssignment(\Twig_Node $node)
- {
- $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
- $visitor = new TranslationDefaultDomainNodeVisitor();
-
- // visit trans_default_domain tag
- $defaultDomain = TwigNodeProvider::getTransDefaultDomainTag(self::$domain);
- $visitor->enterNode($defaultDomain, $env);
- $visitor->leaveNode($defaultDomain, $env);
-
- // visit tested node
- $enteredNode = $visitor->enterNode($node, $env);
- $leavedNode = $visitor->leaveNode($node, $env);
- $this->assertSame($node, $enteredNode);
- $this->assertSame($node, $leavedNode);
-
- // extracting tested node messages
- $visitor = new TranslationNodeVisitor();
- $visitor->enable();
- $visitor->enterNode($node, $env);
- $visitor->leaveNode($node, $env);
-
- $this->assertEquals(array(array(self::$message, self::$domain)), $visitor->getMessages());
- }
-
- /** @dataProvider getDefaultDomainAssignmentTestData */
- public function testNewModuleWithoutDefaultDomainTag(\Twig_Node $node)
- {
- $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
- $visitor = new TranslationDefaultDomainNodeVisitor();
-
- // visit trans_default_domain tag
- $newModule = TwigNodeProvider::getModule('test');
- $visitor->enterNode($newModule, $env);
- $visitor->leaveNode($newModule, $env);
-
- // visit tested node
- $enteredNode = $visitor->enterNode($node, $env);
- $leavedNode = $visitor->leaveNode($node, $env);
- $this->assertSame($node, $enteredNode);
- $this->assertSame($node, $leavedNode);
-
- // extracting tested node messages
- $visitor = new TranslationNodeVisitor();
- $visitor->enable();
- $visitor->enterNode($node, $env);
- $visitor->leaveNode($node, $env);
-
- $this->assertEquals(array(array(self::$message, null)), $visitor->getMessages());
- }
-
- public function getDefaultDomainAssignmentTestData()
- {
- return array(
- array(TwigNodeProvider::getTransFilter(self::$message)),
- array(TwigNodeProvider::getTransChoiceFilter(self::$message)),
- array(TwigNodeProvider::getTransTag(self::$message)),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
-
-use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
-use Symfony\Bridge\Twig\Tests\TestCase;
-
-class TranslationNodeVisitorTest extends TestCase
-{
- /** @dataProvider getMessagesExtractionTestData */
- public function testMessagesExtraction(\Twig_Node $node, array $expectedMessages)
- {
- $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
- $visitor = new TranslationNodeVisitor();
- $visitor->enable();
- $visitor->enterNode($node, $env);
- $visitor->leaveNode($node, $env);
- $this->assertEquals($expectedMessages, $visitor->getMessages());
- }
-
- public function testMessageExtractionWithInvalidDomainNode()
- {
- $message = 'new key';
-
- $node = new \Twig_Node_Expression_Filter(
- new \Twig_Node_Expression_Constant($message, 0),
- new \Twig_Node_Expression_Constant('trans', 0),
- new \Twig_Node(array(
- new \Twig_Node_Expression_Array(array(), 0),
- new \Twig_Node_Expression_Name('variable', 0),
- )),
- 0
- );
-
- $this->testMessagesExtraction($node, array(array($message, TranslationNodeVisitor::UNDEFINED_DOMAIN)));
- }
-
- public function getMessagesExtractionTestData()
- {
- $message = 'new key';
- $domain = 'domain';
-
- return array(
- array(TwigNodeProvider::getTransFilter($message), array(array($message, null))),
- array(TwigNodeProvider::getTransChoiceFilter($message), array(array($message, null))),
- array(TwigNodeProvider::getTransTag($message), array(array($message, null))),
- array(TwigNodeProvider::getTransFilter($message, $domain), array(array($message, $domain))),
- array(TwigNodeProvider::getTransChoiceFilter($message, $domain), array(array($message, $domain))),
- array(TwigNodeProvider::getTransTag($message, $domain), array(array($message, $domain))),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
-
-use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
-use Symfony\Bridge\Twig\Node\TransNode;
-
-class TwigNodeProvider
-{
- public static function getModule($content)
- {
- return new \Twig_Node_Module(
- new \Twig_Node_Expression_Constant($content, 0),
- null,
- new \Twig_Node_Expression_Array(array(), 0),
- new \Twig_Node_Expression_Array(array(), 0),
- new \Twig_Node_Expression_Array(array(), 0),
- null,
- null
- );
- }
-
- public static function getTransFilter($message, $domain = null)
- {
- $arguments = $domain ? array(
- new \Twig_Node_Expression_Array(array(), 0),
- new \Twig_Node_Expression_Constant($domain, 0),
- ) : array();
-
- return new \Twig_Node_Expression_Filter(
- new \Twig_Node_Expression_Constant($message, 0),
- new \Twig_Node_Expression_Constant('trans', 0),
- new \Twig_Node($arguments),
- 0
- );
- }
-
- public static function getTransChoiceFilter($message, $domain = null)
- {
- $arguments = $domain ? array(
- new \Twig_Node_Expression_Constant(0, 0),
- new \Twig_Node_Expression_Array(array(), 0),
- new \Twig_Node_Expression_Constant($domain, 0),
- ) : array();
-
- return new \Twig_Node_Expression_Filter(
- new \Twig_Node_Expression_Constant($message, 0),
- new \Twig_Node_Expression_Constant('transchoice', 0),
- new \Twig_Node($arguments),
- 0
- );
- }
-
- public static function getTransTag($message, $domain = null)
- {
- return new TransNode(
- new \Twig_Node_Body(array(), array('data' => $message)),
- $domain ? new \Twig_Node_Expression_Constant($domain, 0) : null
- );
- }
-
- public static function getTransDefaultDomainTag($domain)
- {
- return new TransDefaultDomainNode(
- new \Twig_Node_Expression_Constant($domain, 0)
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests;
-
-abstract class TestCase extends \PHPUnit_Framework_TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Twig_Environment')) {
- $this->markTestSkipped('Twig is not available.');
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Node;
-
-use Symfony\Bridge\Twig\Tests\TestCase;
-use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
-use Symfony\Bridge\Twig\Node\FormThemeNode;
-
-class FormThemeTokenParserTest extends TestCase
-{
- protected function setUp()
- {
- parent::setUp();
-
- if (version_compare(\Twig_Environment::VERSION, '1.5.0', '<')) {
- $this->markTestSkipped('Requires Twig version to be at least 1.5.0.');
- }
- }
-
- /**
- * @dataProvider getTestsForFormTheme
- */
- public function testCompile($source, $expected)
- {
- $env = new \Twig_Environment(new \Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
- $env->addTokenParser(new FormThemeTokenParser());
- $stream = $env->tokenize($source);
- $parser = new \Twig_Parser($env);
-
- $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0));
- }
-
- public function getTestsForFormTheme()
- {
- return array(
- array(
- '{% form_theme form "tpl1" %}',
- new FormThemeNode(
- new \Twig_Node_Expression_Name('form', 1),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant(0, 1),
- new \Twig_Node_Expression_Constant('tpl1', 1),
- ), 1),
- 1,
- 'form_theme'
- )
- ),
- array(
- '{% form_theme form "tpl1" "tpl2" %}',
- new FormThemeNode(
- new \Twig_Node_Expression_Name('form', 1),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant(0, 1),
- new \Twig_Node_Expression_Constant('tpl1', 1),
- new \Twig_Node_Expression_Constant(1, 1),
- new \Twig_Node_Expression_Constant('tpl2', 1)
- ), 1),
- 1,
- 'form_theme'
- )
- ),
- array(
- '{% form_theme form with "tpl1" %}',
- new FormThemeNode(
- new \Twig_Node_Expression_Name('form', 1),
- new \Twig_Node_Expression_Constant('tpl1', 1),
- 1,
- 'form_theme'
- )
- ),
- array(
- '{% form_theme form with ["tpl1"] %}',
- new FormThemeNode(
- new \Twig_Node_Expression_Name('form', 1),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant(0, 1),
- new \Twig_Node_Expression_Constant('tpl1', 1),
- ), 1),
- 1,
- 'form_theme'
- )
- ),
- array(
- '{% form_theme form with ["tpl1", "tpl2"] %}',
- new FormThemeNode(
- new \Twig_Node_Expression_Name('form', 1),
- new \Twig_Node_Expression_Array(array(
- new \Twig_Node_Expression_Constant(0, 1),
- new \Twig_Node_Expression_Constant('tpl1', 1),
- new \Twig_Node_Expression_Constant(1, 1),
- new \Twig_Node_Expression_Constant('tpl2', 1)
- ), 1),
- 1,
- 'form_theme'
- )
- ),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Tests\Translation;
-
-use Symfony\Bridge\Twig\Extension\TranslationExtension;
-use Symfony\Bridge\Twig\Translation\TwigExtractor;
-use Symfony\Component\Translation\MessageCatalogue;
-use Symfony\Bridge\Twig\Tests\TestCase;
-
-class TwigExtractorTest extends TestCase
-{
- protected function setUp()
- {
- if (!class_exists('Symfony\Component\Translation\Translator')) {
- $this->markTestSkipped('The "Translation" component is not available');
- }
- }
-
- /**
- * @dataProvider getExtractData
- */
- public function testExtract($template, $messages)
- {
- $loader = new \Twig_Loader_Array(array());
- $twig = new \Twig_Environment($loader, array(
- 'strict_variables' => true,
- 'debug' => true,
- 'cache' => false,
- 'autoescape' => false,
- ));
- $twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface')));
-
- $extractor = new TwigExtractor($twig);
- $extractor->setPrefix('prefix');
- $catalogue = new MessageCatalogue('en');
-
- $m = new \ReflectionMethod($extractor, 'extractTemplate');
- $m->setAccessible(true);
- $m->invoke($extractor, $template, $catalogue);
-
- foreach ($messages as $key => $domain) {
- $this->assertTrue($catalogue->has($key, $domain));
- $this->assertEquals('prefix'.$key, $catalogue->get($key, $domain));
- }
- }
-
- public function getExtractData()
- {
- return array(
- array('{{ "new key" | trans() }}', array('new key' => 'messages')),
- array('{{ "new key" | trans() | upper }}', array('new key' => 'messages')),
- array('{{ "new key" | trans({}, "domain") }}', array('new key' => 'domain')),
- array('{{ "new key" | transchoice(1) }}', array('new key' => 'messages')),
- array('{{ "new key" | transchoice(1) | upper }}', array('new key' => 'messages')),
- array('{{ "new key" | transchoice(1, {}, "domain") }}', array('new key' => 'domain')),
- array('{% trans %}new key{% endtrans %}', array('new key' => 'messages')),
- array('{% trans %} new key {% endtrans %}', array('new key' => 'messages')),
- array('{% trans from "domain" %}new key{% endtrans %}', array('new key' => 'domain')),
- array('{% set foo = "new key" | trans %}', array('new key' => 'messages')),
- array('{{ 1 ? "new key" | trans : "another key" | trans }}', array('new key' => 'messages', 'another key' => 'messages')),
-
- // make sure 'trans_default_domain' tag is supported
- array('{% trans_default_domain "domain" %}{{ "new key"|trans }}', array('new key' => 'domain')),
- array('{% trans_default_domain "domain" %}{{ "new key"|transchoice }}', array('new key' => 'domain')),
- array('{% trans_default_domain "domain" %}{% trans %}new key{% endtrans %}', array('new key' => 'domain')),
-
- // make sure this works with twig's named arguments
- array('{{ "new key" | trans(domain="domain") }}', array('new key' => 'domain')),
- array('{{ "new key" | transchoice(domain="domain", count=1) }}', array('new key' => 'domain')),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\TokenParser;
-
-use Symfony\Bridge\Twig\Node\FormThemeNode;
-
-/**
- * Token Parser for the 'form_theme' tag.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class FormThemeTokenParser extends \Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param \Twig_Token $token A Twig_Token instance
- *
- * @return \Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(\Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
-
- $form = $this->parser->getExpressionParser()->parseExpression();
-
- if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'with')) {
- $this->parser->getStream()->next();
- $resources = $this->parser->getExpressionParser()->parseExpression();
- } else {
- $resources = new \Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
- do {
- $resources->addElement($this->parser->getExpressionParser()->parseExpression());
- } while (!$stream->test(\Twig_Token::BLOCK_END_TYPE));
- }
-
- $stream->expect(\Twig_Token::BLOCK_END_TYPE);
-
- return new FormThemeNode($form, $resources, $lineno, $this->getTag());
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'form_theme';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\TokenParser;
-
-use Symfony\Bridge\Twig\Node\TransNode;
-
-/**
- * Token Parser for the 'transchoice' tag.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TransChoiceTokenParser extends TransTokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param \Twig_Token $token A Twig_Token instance
- *
- * @return \Twig_NodeInterface A Twig_NodeInterface instance
- *
- * @throws \Twig_Error_Syntax
- */
- public function parse(\Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
-
- $vars = new \Twig_Node_Expression_Array(array(), $lineno);
-
- $count = $this->parser->getExpressionParser()->parseExpression();
-
- $domain = null;
- $locale = null;
-
- if ($stream->test('with')) {
- // {% transchoice count with vars %}
- $stream->next();
- $vars = $this->parser->getExpressionParser()->parseExpression();
- }
-
- if ($stream->test('from')) {
- // {% transchoice count from "messages" %}
- $stream->next();
- $domain = $this->parser->getExpressionParser()->parseExpression();
- }
-
- if ($stream->test('into')) {
- // {% transchoice count into "fr" %}
- $stream->next();
- $locale = $this->parser->getExpressionParser()->parseExpression();
- }
-
- $stream->expect(\Twig_Token::BLOCK_END_TYPE);
-
- $body = $this->parser->subparse(array($this, 'decideTransChoiceFork'), true);
-
- if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) {
- throw new \Twig_Error_Syntax('A message must be a simple text.');
- }
-
- $stream->expect(\Twig_Token::BLOCK_END_TYPE);
-
- return new TransNode($body, $domain, $count, $vars, $locale, $lineno, $this->getTag());
- }
-
- public function decideTransChoiceFork($token)
- {
- return $token->test(array('endtranschoice'));
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'transchoice';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\TokenParser;
-
-use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
-
-/**
- * Token Parser for the 'trans_default_domain' tag.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TransDefaultDomainTokenParser extends \Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param \Twig_Token $token A Twig_Token instance
- *
- * @return \Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(\Twig_Token $token)
- {
- $expr = $this->parser->getExpressionParser()->parseExpression();
-
- $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
-
- return new TransDefaultDomainNode($expr, $token->getLine(), $this->getTag());
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'trans_default_domain';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\TokenParser;
-
-use Symfony\Bridge\Twig\Node\TransNode;
-
-/**
- * Token Parser for the 'trans' tag.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TransTokenParser extends \Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param \Twig_Token $token A Twig_Token instance
- *
- * @return \Twig_NodeInterface A Twig_NodeInterface instance
- *
- * @throws \Twig_Error_Syntax
- */
- public function parse(\Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
-
- $vars = new \Twig_Node_Expression_Array(array(), $lineno);
- $domain = null;
- $locale = null;
- if (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
- if ($stream->test('with')) {
- // {% trans with vars %}
- $stream->next();
- $vars = $this->parser->getExpressionParser()->parseExpression();
- }
-
- if ($stream->test('from')) {
- // {% trans from "messages" %}
- $stream->next();
- $domain = $this->parser->getExpressionParser()->parseExpression();
- }
-
- if ($stream->test('into')) {
- // {% trans into "fr" %}
- $stream->next();
- $locale = $this->parser->getExpressionParser()->parseExpression();
- } elseif (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
- throw new \Twig_Error_Syntax('Unexpected token. Twig was looking for the "with" or "from" keyword.');
- }
- }
-
- // {% trans %}message{% endtrans %}
- $stream->expect(\Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideTransFork'), true);
-
- if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) {
- throw new \Twig_Error_Syntax('A message inside a trans tag must be a simple text');
- }
-
- $stream->expect(\Twig_Token::BLOCK_END_TYPE);
-
- return new TransNode($body, $domain, null, $vars, $locale, $lineno, $this->getTag());
- }
-
- public function decideTransFork($token)
- {
- return $token->test(array('endtrans'));
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'trans';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig\Translation;
-
-use Symfony\Component\Finder\Finder;
-use Symfony\Component\Translation\Extractor\ExtractorInterface;
-use Symfony\Component\Translation\MessageCatalogue;
-
-/**
- * TwigExtractor extracts translation messages from a twig template.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TwigExtractor implements ExtractorInterface
-{
- /**
- * Default domain for found messages.
- *
- * @var string
- */
- private $defaultDomain = 'messages';
-
- /**
- * Prefix for found message.
- *
- * @var string
- */
- private $prefix = '';
-
- /**
- * The twig environment.
- *
- * @var \Twig_Environment
- */
- private $twig;
-
- public function __construct(\Twig_Environment $twig)
- {
- $this->twig = $twig;
- }
-
- /**
- * {@inheritDoc}
- */
- public function extract($directory, MessageCatalogue $catalogue)
- {
- // load any existing translation files
- $finder = new Finder();
- $files = $finder->files()->name('*.twig')->in($directory);
- foreach ($files as $file) {
- $this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function setPrefix($prefix)
- {
- $this->prefix = $prefix;
- }
-
- protected function extractTemplate($template, MessageCatalogue $catalogue)
- {
- $visitor = $this->twig->getExtension('translator')->getTranslationNodeVisitor();
- $visitor->enable();
-
- $this->twig->parse($this->twig->tokenize($template));
-
- foreach ($visitor->getMessages() as $message) {
- $catalogue->set(trim($message[0]), $this->prefix.trim($message[0]), $message[1] ? $message[1] : $this->defaultDomain);
- }
-
- $visitor->disable();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bridge\Twig;
-
-use Symfony\Component\Templating\EngineInterface;
-use Symfony\Component\Templating\StreamingEngineInterface;
-use Symfony\Component\Templating\TemplateNameParserInterface;
-
-/**
- * This engine knows how to render Twig templates.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class TwigEngine implements EngineInterface, StreamingEngineInterface
-{
- protected $environment;
- protected $parser;
-
- /**
- * Constructor.
- *
- * @param \Twig_Environment $environment A \Twig_Environment instance
- * @param TemplateNameParserInterface $parser A TemplateNameParserInterface instance
- */
- public function __construct(\Twig_Environment $environment, TemplateNameParserInterface $parser)
- {
- $this->environment = $environment;
- $this->parser = $parser;
- }
-
- /**
- * Renders a template.
- *
- * @param mixed $name A template name
- * @param array $parameters An array of parameters to pass to the template
- *
- * @return string The evaluated template as a string
- *
- * @throws \InvalidArgumentException if the template does not exist
- * @throws \RuntimeException if the template cannot be rendered
- */
- public function render($name, array $parameters = array())
- {
- return $this->load($name)->render($parameters);
- }
-
- /**
- * Streams a template.
- *
- * @param mixed $name A template name or a TemplateReferenceInterface instance
- * @param array $parameters An array of parameters to pass to the template
- *
- * @throws \RuntimeException if the template cannot be rendered
- */
- public function stream($name, array $parameters = array())
- {
- $this->load($name)->display($parameters);
- }
-
- /**
- * Returns true if the template exists.
- *
- * @param mixed $name A template name
- *
- * @return Boolean true if the template exists, false otherwise
- */
- public function exists($name)
- {
- try {
- $this->load($name);
- } catch (\InvalidArgumentException $e) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Returns true if this class is able to render the given template.
- *
- * @param string $name A template name
- *
- * @return Boolean True if this class supports the given resource, false otherwise
- */
- public function supports($name)
- {
- if ($name instanceof \Twig_Template) {
- return true;
- }
-
- $template = $this->parser->parse($name);
-
- return 'twig' === $template->get('engine');
- }
-
- /**
- * Loads the given template.
- *
- * @param mixed $name A template name or an instance of Twig_Template
- *
- * @return \Twig_TemplateInterface A \Twig_TemplateInterface instance
- *
- * @throws \InvalidArgumentException if the template does not exist
- */
- protected function load($name)
- {
- if ($name instanceof \Twig_Template) {
- return $name;
- }
-
- try {
- return $this->environment->loadTemplate($name);
- } catch (\Twig_Error_Loader $e) {
- throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
- }
- }
-}
+++ /dev/null
-{
- "name": "symfony/twig-bridge",
- "type": "symfony-bridge",
- "description": "Symfony Twig Bridge",
- "keywords": [],
- "homepage": "http://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "http://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=5.3.3",
- "twig/twig": "~1.11"
- },
- "require-dev": {
- "symfony/form": "2.2.*",
- "symfony/http-kernel": "~2.2",
- "symfony/routing": "~2.2",
- "symfony/templating": "~2.1",
- "symfony/translation": "~2.2",
- "symfony/yaml": "~2.0",
- "symfony/security": "~2.0"
- },
- "suggest": {
- "symfony/form": "",
- "symfony/http-kernel": "",
- "symfony/routing": "",
- "symfony/templating": "",
- "symfony/translation": "",
- "symfony/yaml": "",
- "symfony/security": ""
- },
- "autoload": {
- "psr-0": { "Symfony\\Bridge\\Twig\\": "" }
- },
- "target-dir": "Symfony/Bridge/Twig",
- "minimum-stability": "dev",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Symfony Twig Bridge Test Suite">
- <directory>./Tests/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory>./</directory>
- <exclude>
- <directory>./Resources</directory>
- <directory>./Tests</directory>
- <directory>./vendor</directory>
- </exclude>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-Subproject commit f5b0c84f3699e494c84ee627d7d583e115d2c4a2
+++ /dev/null
-; top-most EditorConfig file
-root = true
-
-; Unix-style newlines
-[*]
-end_of_line = LF
-
-[*.php]
-indent_style = space
-indent_size = 4
-
-[*.test]
-indent_style = space
-indent_size = 4
-
-[*.rst]
-indent_style = space
-indent_size = 4
+++ /dev/null
-/ext/twig/autom4te.cache/
-
+++ /dev/null
-language: php
-
-php:
- - 5.2
- - 5.3
- - 5.4
- - 5.5
-
-env:
- - TWIG_EXT=no
- - TWIG_EXT=yes
-
-before_script:
- - if [ "$TWIG_EXT" == "yes" ]; then sh -c "cd ext/twig && phpize && ./configure --enable-twig && make && sudo make install"; fi
- - if [ "$TWIG_EXT" == "yes" ]; then echo "extension=twig.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi
+++ /dev/null
-Twig is written and maintained by the Twig Team:
-
-Lead Developer:
-
-- Fabien Potencier <fabien.potencier@symfony-project.org>
-
-Project Founder:
-
-- Armin Ronacher <armin.ronacher@active-4.com>
+++ /dev/null
-* 1.13.2 (2013-08-03)
-
- * fixed the error line number for an error occurs in and embedded template
- * fixed crashes of the C extension on some edge cases
-
-* 1.13.1 (2013-06-06)
-
- * added the possibility to ignore the filesystem constructor argument in Twig_Loader_Filesystem
- * fixed Twig_Loader_Chain::exists() for a loader which implements Twig_ExistsLoaderInterface
- * adjusted backtrace call to reduce memory usage when an error occurs
- * added support for object instances as the second argument of the constant test
- * fixed the include function when used in an assignment
-
-* 1.13.0 (2013-05-10)
-
- * fixed getting a numeric-like item on a variable ('09' for instance)
- * fixed getting a boolean or float key on an array, so it is consistent with PHP's array access:
- `{{ array[false] }}` behaves the same as `echo $array[false];` (equals `$array[0]`)
- * made the escape filter 20% faster for happy path (escaping string for html with UTF-8)
- * changed ☃ to § in tests
- * enforced usage of named arguments after positional ones
-
-* 1.12.3 (2013-04-08)
-
- * fixed a security issue in the filesystem loader where it was possible to include a template one
- level above the configured path
- * fixed fatal error that should be an exception when adding a filter/function/test too late
- * added a batch filter
- * added support for encoding an array as query string in the url_encode filter
-
-* 1.12.2 (2013-02-09)
-
- * fixed the timezone used by the date filter and function when the given date contains a timezone (like 2010-01-28T15:00:00+02:00)
- * fixed globals when getGlobals is called early on
- * added the first and last filter
-
-* 1.12.1 (2013-01-15)
-
- * added support for object instances as the second argument of the constant function
- * relaxed globals management to avoid a BC break
- * added support for {{ some_string[:2] }}
-
-* 1.12.0 (2013-01-08)
-
- * added verbatim as an alias for the raw tag to avoid confusion with the raw filter
- * fixed registration of tests and functions as anonymous functions
- * fixed globals management
-
-* 1.12.0-RC1 (2012-12-29)
-
- * added an include function (does the same as the include tag but in a more flexible way)
- * added the ability to use any PHP callable to define filters, functions, and tests
- * added a syntax error when using a loop variable that is not defined
- * added the ability to set default values for macro arguments
- * added support for named arguments for filters, tests, and functions
- * moved filters/functions/tests syntax errors to the parser
- * added support for extended ternary operator syntaxes
-
-* 1.11.1 (2012-11-11)
-
- * fixed debug info line numbering (was off by 2)
- * fixed escaping when calling a macro inside another one (regression introduced in 1.9.1)
- * optimized variable access on PHP 5.4
- * fixed a crash of the C extension when an exception was thrown from a macro called without being imported (using _self.XXX)
-
-* 1.11.0 (2012-11-07)
-
- * fixed macro compilation when a variable name is a PHP reserved keyword
- * changed the date filter behavior to always apply the default timezone, except if false is passed as the timezone
- * fixed bitwise operator precedences
- * added the template_from_string function
- * fixed default timezone usage for the date function
- * optimized the way Twig exceptions are managed (to make them faster)
- * added Twig_ExistsLoaderInterface (implementing this interface in your loader make the chain loader much faster)
-
-* 1.10.3 (2012-10-19)
-
- * fixed wrong template location in some error messages
- * reverted a BC break introduced in 1.10.2
- * added a split filter
-
-* 1.10.2 (2012-10-15)
-
- * fixed macro calls on PHP 5.4
-
-* 1.10.1 (2012-10-15)
-
- * made a speed optimization to macro calls when imported via the "import" tag
- * fixed C extension compilation on Windows
- * fixed a segfault in the C extension when using DateTime objects
-
-* 1.10.0 (2012-09-28)
-
- * extracted functional tests framework to make it reusable for third-party extensions
- * added namespaced templates support in Twig_Loader_Filesystem
- * added Twig_Loader_Filesystem::prependPath()
- * fixed an error when a token parser pass a closure as a test to the subparse() method
-
-* 1.9.2 (2012-08-25)
-
- * fixed the in operator for objects that contain circular references
- * fixed the C extension when accessing a public property of an object implementing the \ArrayAccess interface
-
-* 1.9.1 (2012-07-22)
-
- * optimized macro calls when auto-escaping is on
- * fixed wrong parent class for Twig_Function_Node
- * made Twig_Loader_Chain more explicit about problems
-
-* 1.9.0 (2012-07-13)
-
- * made the parsing independent of the template loaders
- * fixed exception trace when an error occurs when rendering a child template
- * added escaping strategies for CSS, URL, and HTML attributes
- * fixed nested embed tag calls
- * added the date_modify filter
-
-* 1.8.3 (2012-06-17)
-
- * fixed paths in the filesystem loader when passing a path that ends with a slash or a backslash
- * fixed escaping when a project defines a function named html or js
- * fixed chmod mode to apply the umask correctly
-
-* 1.8.2 (2012-05-30)
-
- * added the abs filter
- * fixed a regression when using a number in template attributes
- * fixed compiler when mbstring.func_overload is set to 2
- * fixed DateTimeZone support in date filter
-
-* 1.8.1 (2012-05-17)
-
- * fixed a regression when dealing with SimpleXMLElement instances in templates
- * fixed "is_safe" value for the "dump" function when "html_errors" is not defined in php.ini
- * switched to use mbstring whenever possible instead of iconv (you might need to update your encoding as mbstring and iconv encoding names sometimes differ)
-
-* 1.8.0 (2012-05-08)
-
- * enforced interface when adding tests, filters, functions, and node visitors from extensions
- * fixed a side-effect of the date filter where the timezone might be changed
- * simplified usage of the autoescape tag; the only (optional) argument is now the escaping strategy or false (with a BC layer)
- * added a way to dynamically change the auto-escaping strategy according to the template "filename"
- * changed the autoescape option to also accept a supported escaping strategy (for BC, true is equivalent to html)
- * added an embed tag
-
-* 1.7.0 (2012-04-24)
-
- * fixed a PHP warning when using CIFS
- * fixed template line number in some exceptions
- * added an iterable test
- * added an error when defining two blocks with the same name in a template
- * added the preserves_safety option for filters
- * fixed a PHP notice when trying to access a key on a non-object/array variable
- * enhanced error reporting when the template file is an instance of SplFileInfo
- * added Twig_Environment::mergeGlobals()
- * added compilation checks to avoid misuses of the sandbox tag
- * fixed filesystem loader freshness logic for high traffic websites
- * fixed random function when charset is null
-
-* 1.6.5 (2012-04-11)
-
- * fixed a regression when a template only extends another one without defining any blocks
-
-* 1.6.4 (2012-04-02)
-
- * fixed PHP notice in Twig_Error::guessTemplateLine() introduced in 1.6.3
- * fixed performance when compiling large files
- * optimized parent template creation when the template does not use dynamic inheritance
-
-* 1.6.3 (2012-03-22)
-
- * fixed usage of Z_ADDREF_P for PHP 5.2 in the C extension
- * fixed compilation of numeric values used in templates when using a locale where the decimal separator is not a dot
- * made the strategy used to guess the real template file name and line number in exception messages much faster and more accurate
-
-* 1.6.2 (2012-03-18)
-
- * fixed sandbox mode when used with inheritance
- * added preserveKeys support for the slice filter
- * fixed the date filter when a DateTime instance is passed with a specific timezone
- * added a trim filter
-
-* 1.6.1 (2012-02-29)
-
- * fixed Twig C extension
- * removed the creation of Twig_Markup instances when not needed
- * added a way to set the default global timezone for dates
- * fixed the slice filter on strings when the length is not specified
- * fixed the creation of the cache directory in case of a race condition
-
-* 1.6.0 (2012-02-04)
-
- * fixed raw blocks when used with the whitespace trim option
- * made a speed optimization to macro calls when imported via the "from" tag
- * fixed globals, parsers, visitors, filters, tests, and functions management in Twig_Environment when a new one or new extension is added
- * fixed the attribute function when passing arguments
- * added slice notation support for the [] operator (syntactic sugar for the slice operator)
- * added a slice filter
- * added string support for the reverse filter
- * fixed the empty test and the length filter for Twig_Markup instances
- * added a date function to ease date comparison
- * fixed unary operators precedence
- * added recursive parsing support in the parser
- * added string and integer handling for the random function
-
-* 1.5.1 (2012-01-05)
-
- * fixed a regression when parsing strings
-
-* 1.5.0 (2012-01-04)
-
- * added Traversable objects support for the join filter
-
-* 1.5.0-RC2 (2011-12-30)
-
- * added a way to set the default global date interval format
- * fixed the date filter for DateInterval instances (setTimezone() does not exist for them)
- * refactored Twig_Template::display() to ease its extension
- * added a number_format filter
-
-* 1.5.0-RC1 (2011-12-26)
-
- * removed the need to quote hash keys
- * allowed hash keys to be any expression
- * added a do tag
- * added a flush tag
- * added support for dynamically named filters and functions
- * added a dump function to help debugging templates
- * added a nl2br filter
- * added a random function
- * added a way to change the default format for the date filter
- * fixed the lexer when an operator ending with a letter ends a line
- * added string interpolation support
- * enhanced exceptions for unknown filters, functions, tests, and tags
-
-* 1.4.0 (2011-12-07)
-
- * fixed lexer when using big numbers (> PHP_INT_MAX)
- * added missing preserveKeys argument to the reverse filter
- * fixed macros containing filter tag calls
-
-* 1.4.0-RC2 (2011-11-27)
-
- * removed usage of Reflection in Twig_Template::getAttribute()
- * added a C extension that can optionally replace Twig_Template::getAttribute()
- * added negative timestamp support to the date filter
-
-* 1.4.0-RC1 (2011-11-20)
-
- * optimized variable access when using PHP 5.4
- * changed the precedence of the .. operator to be more consistent with languages that implements such a feature like Ruby
- * added an Exception to Twig_Loader_Array::isFresh() method when the template does not exist to be consistent with other loaders
- * added Twig_Function_Node to allow more complex functions to have their own Node class
- * added Twig_Filter_Node to allow more complex filters to have their own Node class
- * added Twig_Test_Node to allow more complex tests to have their own Node class
- * added a better error message when a template is empty but contain a BOM
- * fixed "in" operator for empty strings
- * fixed the "defined" test and the "default" filter (now works with more than one call (foo.bar.foo) and for both values of the strict_variables option)
- * changed the way extensions are loaded (addFilter/addFunction/addGlobal/addTest/addNodeVisitor/addTokenParser/addExtension can now be called in any order)
- * added Twig_Environment::display()
- * made the escape filter smarter when the encoding is not supported by PHP
- * added a convert_encoding filter
- * moved all node manipulations outside the compile() Node method
- * made several speed optimizations
-
-* 1.3.0 (2011-10-08)
-
-no changes
-
-* 1.3.0-RC1 (2011-10-04)
-
- * added an optimization for the parent() function
- * added cache reloading when auto_reload is true and an extension has been modified
- * added the possibility to force the escaping of a string already marked as safe (instance of Twig_Markup)
- * allowed empty templates to be used as traits
- * added traits support for the "parent" function
-
-* 1.2.0 (2011-09-13)
-
-no changes
-
-* 1.2.0-RC1 (2011-09-10)
-
- * enhanced the exception when a tag remains unclosed
- * added support for empty Countable objects for the "empty" test
- * fixed algorithm that determines if a template using inheritance is valid (no output between block definitions)
- * added better support for encoding problems when escaping a string (available as of PHP 5.4)
- * added a way to ignore a missing template when using the "include" tag ({% include "foo" ignore missing %})
- * added support for an array of templates to the "include" and "extends" tags ({% include ['foo', 'bar'] %})
- * added support for bitwise operators in expressions
- * added the "attribute" function to allow getting dynamic attributes on variables
- * added Twig_Loader_Chain
- * added Twig_Loader_Array::setTemplate()
- * added an optimization for the set tag when used to capture a large chunk of static text
- * changed name regex to match PHP one "[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*" (works for blocks, tags, functions, filters, and macros)
- * removed the possibility to use the "extends" tag from a block
- * added "if" modifier support to "for" loops
-
-* 1.1.2 (2011-07-30)
-
- * fixed json_encode filter on PHP 5.2
- * fixed regression introduced in 1.1.1 ({{ block(foo|lower) }})
- * fixed inheritance when using conditional parents
- * fixed compilation of templates when the body of a child template is not empty
- * fixed output when a macro throws an exception
- * fixed a parsing problem when a large chunk of text is enclosed in a comment tag
- * added PHPDoc for all Token parsers and Core extension functions
-
-* 1.1.1 (2011-07-17)
-
- * added a performance optimization in the Optimizer (also helps to lower the number of nested level calls)
- * made some performance improvement for some edge cases
-
-* 1.1.0 (2011-06-28)
-
- * fixed json_encode filter
-
-* 1.1.0-RC3 (2011-06-24)
-
- * fixed method case-sensitivity when using the sandbox mode
- * added timezone support for the date filter
- * fixed possible security problems with NUL bytes
-
-* 1.1.0-RC2 (2011-06-16)
-
- * added an exception when the template passed to "use" is not a string
- * made 'a.b is defined' not throw an exception if a is not defined (in strict mode)
- * added {% line \d+ %} directive
-
-* 1.1.0-RC1 (2011-05-28)
-
-Flush your cache after upgrading.
-
- * fixed date filter when using a timestamp
- * fixed the defined test for some cases
- * fixed a parsing problem when a large chunk of text is enclosed in a raw tag
- * added support for horizontal reuse of template blocks (see docs for more information)
- * added whitespace control modifier to all tags (see docs for more information)
- * added null as an alias for none (the null test is also an alias for the none test now)
- * made TRUE, FALSE, NONE equivalent to their lowercase counterparts
- * wrapped all compilation and runtime exceptions with Twig_Error_Runtime and added logic to guess the template name and line
- * moved display() method to Twig_Template (generated templates should now use doDisplay() instead)
-
-* 1.0.0 (2011-03-27)
-
- * fixed output when using mbstring
- * fixed duplicate call of methods when using the sandbox
- * made the charset configurable for the escape filter
-
-* 1.0.0-RC2 (2011-02-21)
-
- * changed the way {% set %} works when capturing (the content is now marked as safe)
- * added support for macro name in the endmacro tag
- * make Twig_Error compatible with PHP 5.3.0 >
- * fixed an infinite loop on some Windows configurations
- * fixed the "length" filter for numbers
- * fixed Template::getAttribute() as properties in PHP are case sensitive
- * removed coupling between Twig_Node and Twig_Template
- * fixed the ternary operator precedence rule
-
-* 1.0.0-RC1 (2011-01-09)
-
-Backward incompatibilities:
-
- * the "items" filter, which has been deprecated for quite a long time now, has been removed
- * the "range" filter has been converted to a function: 0|range(10) -> range(0, 10)
- * the "constant" filter has been converted to a function: {{ some_date|date('DATE_W3C'|constant) }} -> {{ some_date|date(constant('DATE_W3C')) }}
- * the "cycle" filter has been converted to a function: {{ ['odd', 'even']|cycle(i) }} -> {{ cycle(['odd', 'even'], i) }}
- * the "for" tag does not support "joined by" anymore
- * the "autoescape" first argument is now "true"/"false" (instead of "on"/"off")
- * the "parent" tag has been replaced by a "parent" function ({{ parent() }} instead of {% parent %})
- * the "display" tag has been replaced by a "block" function ({{ block('title') }} instead of {% display title %})
- * removed the grammar and simple token parser (moved to the Twig Extensions repository)
-
-Changes:
-
- * added "needs_context" option for filters and functions (the context is then passed as a first argument)
- * added global variables support
- * made macros return their value instead of echoing directly (fixes calling a macro in sandbox mode)
- * added the "from" tag to import macros as functions
- * added support for functions (a function is just syntactic sugar for a getAttribute() call)
- * made macros callable when sandbox mode is enabled
- * added an exception when a macro uses a reserved name
- * the "default" filter now uses the "empty" test instead of just checking for null
- * added the "empty" test
-
-* 0.9.10 (2010-12-16)
-
-Backward incompatibilities:
-
- * The Escaper extension is enabled by default, which means that all displayed
- variables are now automatically escaped. You can revert to the previous
- behavior by removing the extension via $env->removeExtension('escaper')
- or just set the 'autoescape' option to 'false'.
- * removed the "without loop" attribute for the "for" tag (not needed anymore
- as the Optimizer take care of that for most cases)
- * arrays and hashes have now a different syntax
- * arrays keep the same syntax with square brackets: [1, 2]
- * hashes now use curly braces (["a": "b"] should now be written as {"a": "b"})
- * support for "arrays with keys" and "hashes without keys" is not supported anymore ([1, "foo": "bar"] or {"foo": "bar", 1})
- * the i18n extension is now part of the Twig Extensions repository
-
-Changes:
-
- * added the merge filter
- * removed 'is_escaper' option for filters (a left over from the previous version) -- you must use 'is_safe' now instead
- * fixed usage of operators as method names (like is, in, and not)
- * changed the order of execution for node visitors
- * fixed default() filter behavior when used with strict_variables set to on
- * fixed filesystem loader compatibility with PHAR files
- * enhanced error messages when an unexpected token is parsed in an expression
- * fixed filename not being added to syntax error messages
- * added the autoescape option to enable/disable autoescaping
- * removed the newline after a comment (mimics PHP behavior)
- * added a syntax error exception when parent block is used on a template that does not extend another one
- * made the Escaper extension enabled by default
- * fixed sandbox extension when used with auto output escaping
- * fixed escaper when wrapping a Twig_Node_Print (the original class must be preserved)
- * added an Optimizer extension (enabled by default; optimizes "for" loops and "raw" filters)
- * added priority to node visitors
-
-* 0.9.9 (2010-11-28)
-
-Backward incompatibilities:
- * the self special variable has been renamed to _self
- * the odd and even filters are now tests:
- {{ foo|odd }} must now be written {{ foo is odd }}
- * the "safe" filter has been renamed to "raw"
- * in Node classes,
- sub-nodes are now accessed via getNode() (instead of property access)
- attributes via getAttribute() (instead of array access)
- * the urlencode filter had been renamed to url_encode
- * the include tag now merges the passed variables with the current context by default
- (the old behavior is still possible by adding the "only" keyword)
- * moved Exceptions to Twig_Error_* (Twig_SyntaxError/Twig_RuntimeError are now Twig_Error_Syntax/Twig_Error_Runtime)
- * removed support for {{ 1 < i < 3 }} (use {{ i > 1 and i < 3 }} instead)
- * the "in" filter has been removed ({{ a|in(b) }} should now be written {{ a in b }})
-
-Changes:
- * added file and line to Twig_Error_Runtime exceptions thrown from Twig_Template
- * changed trans tag to accept any variable for the plural count
- * fixed sandbox mode (__toString() method check was not enforced if called implicitly from complex statements)
- * added the ** (power) operator
- * changed the algorithm used for parsing expressions
- * added the spaceless tag
- * removed trim_blocks option
- * added support for is*() methods for attributes (foo.bar now looks for foo->getBar() or foo->isBar())
- * changed all exceptions to extend Twig_Error
- * fixed unary expressions ({{ not(1 or 0) }})
- * fixed child templates (with an extend tag) that uses one or more imports
- * added support for {{ 1 not in [2, 3] }} (more readable than the current {{ not (1 in [2, 3]) }})
- * escaping has been rewritten
- * the implementation of template inheritance has been rewritten
- (blocks can now be called individually and still work with inheritance)
- * fixed error handling for if tag when a syntax error occurs within a subparse process
- * added a way to implement custom logic for resolving token parsers given a tag name
- * fixed js escaper to be stricter (now uses a whilelist-based js escaper)
- * added the following filers: "constant", "trans", "replace", "json_encode"
- * added a "constant" test
- * fixed objects with __toString() not being autoescaped
- * fixed subscript expressions when calling __call() (methods now keep the case)
- * added "test" feature (accessible via the "is" operator)
- * removed the debug tag (should be done in an extension)
- * fixed trans tag when no vars are used in plural form
- * fixed race condition when writing template cache
- * added the special _charset variable to reference the current charset
- * added the special _context variable to reference the current context
- * renamed self to _self (to avoid conflict)
- * fixed Twig_Template::getAttribute() for protected properties
-
-* 0.9.8 (2010-06-28)
-
-Backward incompatibilities:
- * the trans tag plural count is now attached to the plural tag:
- old: `{% trans count %}...{% plural %}...{% endtrans %}`
- new: `{% trans %}...{% plural count %}...{% endtrans %}`
-
- * added a way to translate strings coming from a variable ({% trans var %})
- * fixed trans tag when used with the Escaper extension
- * fixed default cache umask
- * removed Twig_Template instances from the debug tag output
- * fixed objects with __isset() defined
- * fixed set tag when used with a capture
- * fixed type hinting for Twig_Environment::addFilter() method
-
-* 0.9.7 (2010-06-12)
-
-Backward incompatibilities:
- * changed 'as' to '=' for the set tag ({% set title as "Title" %} must now be {% set title = "Title" %})
- * removed the sandboxed attribute of the include tag (use the new sandbox tag instead)
- * refactored the Node system (if you have custom nodes, you will have to update them to use the new API)
-
- * added self as a special variable that refers to the current template (useful for importing macros from the current template)
- * added Twig_Template instance support to the include tag
- * added support for dynamic and conditional inheritance ({% extends some_var %} and {% extends standalone ? "minimum" : "base" %})
- * added a grammar sub-framework to ease the creation of custom tags
- * fixed the for tag for large arrays (some loop variables are now only available for arrays and objects that implement the Countable interface)
- * removed the Twig_Resource::resolveMissingFilter() method
- * fixed the filter tag which did not apply filtering to included files
- * added a bunch of unit tests
- * added a bunch of phpdoc
- * added a sandbox tag in the sandbox extension
- * changed the date filter to support any date format supported by DateTime
- * added strict_variable setting to throw an exception when an invalid variable is used in a template (disabled by default)
- * added the lexer, parser, and compiler as arguments to the Twig_Environment constructor
- * changed the cache option to only accepts an explicit path to a cache directory or false
- * added a way to add token parsers, filters, and visitors without creating an extension
- * added three interfaces: Twig_NodeInterface, Twig_TokenParserInterface, and Twig_FilterInterface
- * changed the generated code to match the new coding standards
- * fixed sandbox mode (__toString() method check was not enforced if called implicitly from a simple statement like {{ article }})
- * added an exception when a child template has a non-empty body (as it is always ignored when rendering)
-
-* 0.9.6 (2010-05-12)
-
- * fixed variables defined outside a loop and for which the value changes in a for loop
- * fixed the test suite for PHP 5.2 and older versions of PHPUnit
- * added support for __call() in expression resolution
- * fixed node visiting for macros (macros are now visited by visitors as any other node)
- * fixed nested block definitions with a parent call (rarely useful but nonetheless supported now)
- * added the cycle filter
- * fixed the Lexer when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII
- * added a long-syntax for the set tag ({% set foo %}...{% endset %})
- * unit tests are now powered by PHPUnit
- * added support for gettext via the `i18n` extension
- * fixed twig_capitalize_string_filter() and fixed twig_length_filter() when used with UTF-8 values
- * added a more useful exception if an if tag is not closed properly
- * added support for escaping strategy in the autoescape tag
- * fixed lexer when a template has a big chunk of text between/in a block
-
-* 0.9.5 (2010-01-20)
-
-As for any new release, don't forget to remove all cached templates after
-upgrading.
-
-If you have defined custom filters, you MUST upgrade them for this release. To
-upgrade, replace "array" with "new Twig_Filter_Function", and replace the
-environment constant by the "needs_environment" option:
-
- // before
- 'even' => array('twig_is_even_filter', false),
- 'escape' => array('twig_escape_filter', true),
-
- // after
- 'even' => new Twig_Filter_Function('twig_is_even_filter'),
- 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
-
-If you have created NodeTransformer classes, you will need to upgrade them to
-the new interface (please note that the interface is not yet considered
-stable).
-
- * fixed list nodes that did not extend the Twig_NodeListInterface
- * added the "without loop" option to the for tag (it disables the generation of the loop variable)
- * refactored node transformers to node visitors
- * fixed automatic-escaping for blocks
- * added a way to specify variables to pass to an included template
- * changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules)
- * improved the filter system to allow object methods to be used as filters
- * changed the Array and String loaders to actually make use of the cache mechanism
- * included the default filter function definitions in the extension class files directly (Core, Escaper)
- * added the // operator (like the floor() PHP function)
- * added the .. operator (as a syntactic sugar for the range filter when the step is 1)
- * added the in operator (as a syntactic sugar for the in filter)
- * added the following filters in the Core extension: in, range
- * added support for arrays (same behavior as in PHP, a mix between lists and dictionaries, arrays and hashes)
- * enhanced some error messages to provide better feedback in case of parsing errors
-
-* 0.9.4 (2009-12-02)
-
-If you have custom loaders, you MUST upgrade them for this release: The
-Twig_Loader base class has been removed, and the Twig_LoaderInterface has also
-been changed (see the source code for more information or the documentation).
-
- * added support for DateTime instances for the date filter
- * fixed loop.last when the array only has one item
- * made it possible to insert newlines in tag and variable blocks
- * fixed a bug when a literal '\n' were present in a template text
- * fixed bug when the filename of a template contains */
- * refactored loaders
-
-* 0.9.3 (2009-11-11)
-
-This release is NOT backward compatible with the previous releases.
-
- The loaders do not take the cache and autoReload arguments anymore. Instead,
- the Twig_Environment class has two new options: cache and auto_reload.
- Upgrading your code means changing this kind of code:
-
- $loader = new Twig_Loader_Filesystem('/path/to/templates', '/path/to/compilation_cache', true);
- $twig = new Twig_Environment($loader);
-
- to something like this:
-
- $loader = new Twig_Loader_Filesystem('/path/to/templates');
- $twig = new Twig_Environment($loader, array(
- 'cache' => '/path/to/compilation_cache',
- 'auto_reload' => true,
- ));
-
- * deprecated the "items" filter as it is not needed anymore
- * made cache and auto_reload options of Twig_Environment instead of arguments of Twig_Loader
- * optimized template loading speed
- * removed output when an error occurs in a template and render() is used
- * made major speed improvements for loops (up to 300% on even the smallest loops)
- * added properties as part of the sandbox mode
- * added public properties support (obj.item can now be the item property on the obj object)
- * extended set tag to support expression as value ({% set foo as 'foo' ~ 'bar' %} )
- * fixed bug when \ was used in HTML
-
-* 0.9.2 (2009-10-29)
-
- * made some speed optimizations
- * changed the cache extension to .php
- * added a js escaping strategy
- * added support for short block tag
- * changed the filter tag to allow chained filters
- * made lexer more flexible as you can now change the default delimiters
- * added set tag
- * changed default directory permission when cache dir does not exist (more secure)
- * added macro support
- * changed filters first optional argument to be a Twig_Environment instance instead of a Twig_Template instance
- * made Twig_Autoloader::autoload() a static method
- * avoid writing template file if an error occurs
- * added $ escaping when outputting raw strings
- * enhanced some error messages to ease debugging
- * fixed empty cache files when the template contains an error
-
-* 0.9.1 (2009-10-14)
-
- * fixed a bug in PHP 5.2.6
- * fixed numbers with one than one decimal
- * added support for method calls with arguments ({{ foo.bar('a', 43) }})
- * made small speed optimizations
- * made minor tweaks to allow better extensibility and flexibility
-
-* 0.9.0 (2009-10-12)
-
- * Initial release
+++ /dev/null
-Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details.
-
-Some rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
-
- * The names of the contributors may not be used to endorse or
- promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+++ /dev/null
-Twig, the flexible, fast, and secure template language for PHP
-==============================================================
-
-[![Build Status](https://secure.travis-ci.org/fabpot/Twig.png?branch=master)](http://travis-ci.org/fabpot/Twig)
-
-Twig is a template language for PHP, released under the new BSD license (code
-and documentation).
-
-Twig uses a syntax similar to the Django and Jinja template languages which
-inspired the Twig runtime environment.
-
-More Information
-----------------
-
-Read the [documentation][1] for more information.
-
-[1]: http://twig.sensiolabs.org/documentation
+++ /dev/null
-{
- "name": "twig/twig",
- "type": "library",
- "description": "Twig, the flexible, fast, and secure template language for PHP",
- "keywords": ["templating"],
- "homepage": "http://twig.sensiolabs.org",
- "license": "BSD-3-Clause",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Armin Ronacher",
- "email": "armin.ronacher@active-4.com"
- }
- ],
- "require": {
- "php": ">=5.2.4"
- },
- "autoload": {
- "psr-0" : {
- "Twig_" : "lib/"
- }
- },
- "extra": {
- "branch-alias": {
- "dev-master": "1.13-dev"
- }
- }
-}
+++ /dev/null
-Extending Twig
-==============
-
-.. caution::
-
- This section describes how to extend Twig as of **Twig 1.12**. If you are
- using an older version, read the :doc:`legacy<advanced_legacy>` chapter
- instead.
-
-Twig can be extended in many ways; you can add extra tags, filters, tests,
-operators, global variables, and functions. You can even extend the parser
-itself with node visitors.
-
-.. note::
-
- The first section of this chapter describes how to extend Twig easily. If
- you want to reuse your changes in different projects or if you want to
- share them with others, you should then create an extension as described
- in the following section.
-
-.. caution::
-
- When extending Twig without creating an extension, Twig won't be able to
- recompile your templates when the PHP code is updated. To see your changes
- in real-time, either disable template caching or package your code into an
- extension (see the next section of this chapter).
-
-Before extending Twig, you must understand the differences between all the
-different possible extension points and when to use them.
-
-First, remember that Twig has two main language constructs:
-
-* ``{{ }}``: used to print the result of an expression evaluation;
-
-* ``{% %}``: used to execute statements.
-
-To understand why Twig exposes so many extension points, let's see how to
-implement a *Lorem ipsum* generator (it needs to know the number of words to
-generate).
-
-You can use a ``lipsum`` *tag*:
-
-.. code-block:: jinja
-
- {% lipsum 40 %}
-
-That works, but using a tag for ``lipsum`` is not a good idea for at least
-three main reasons:
-
-* ``lipsum`` is not a language construct;
-* The tag outputs something;
-* The tag is not flexible as you cannot use it in an expression:
-
- .. code-block:: jinja
-
- {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
-
-In fact, you rarely need to create tags; and that's good news because tags are
-the most complex extension point of Twig.
-
-Now, let's use a ``lipsum`` *filter*:
-
-.. code-block:: jinja
-
- {{ 40|lipsum }}
-
-Again, it works, but it looks weird. A filter transforms the passed value to
-something else but here we use the value to indicate the number of words to
-generate (so, ``40`` is an argument of the filter, not the value we want to
-transform).
-
-Next, let's use a ``lipsum`` *function*:
-
-.. code-block:: jinja
-
- {{ lipsum(40) }}
-
-Here we go. For this specific example, the creation of a function is the
-extension point to use. And you can use it anywhere an expression is accepted:
-
-.. code-block:: jinja
-
- {{ 'some text' ~ lipsum(40) ~ 'some more text' }}
-
- {% set lipsum = lipsum(40) %}
-
-Last but not the least, you can also use a *global* object with a method able
-to generate lorem ipsum text:
-
-.. code-block:: jinja
-
- {{ text.lipsum(40) }}
-
-As a rule of thumb, use functions for frequently used features and global
-objects for everything else.
-
-Keep in mind the following when you want to extend Twig:
-
-========== ========================== ========== =========================
-What? Implementation difficulty? How often? When?
-========== ========================== ========== =========================
-*macro* trivial frequent Content generation
-*global* trivial frequent Helper object
-*function* trivial frequent Content generation
-*filter* trivial frequent Value transformation
-*tag* complex rare DSL language construct
-*test* trivial rare Boolean decision
-*operator* trivial rare Values transformation
-========== ========================== ========== =========================
-
-Globals
--------
-
-A global variable is like any other template variable, except that it's
-available in all templates and macros::
-
- $twig = new Twig_Environment($loader);
- $twig->addGlobal('text', new Text());
-
-You can then use the ``text`` variable anywhere in a template:
-
-.. code-block:: jinja
-
- {{ text.lipsum(40) }}
-
-Filters
--------
-
-Creating a filter is as simple as associating a name with a PHP callable::
-
- // an anonymous function
- $filter = new Twig_SimpleFilter('rot13', function ($string) {
- return str_rot13($string);
- });
-
- // or a simple PHP function
- $filter = new Twig_SimpleFilter('rot13', 'str_rot13');
-
- // or a class method
- $filter = new Twig_SimpleFilter('rot13', array('SomeClass', 'rot13Filter'));
-
-The first argument passed to the ``Twig_SimpleFilter`` constructor is the name
-of the filter you will use in templates and the second one is the PHP callable
-to associate with it.
-
-Then, add the filter to your Twig environment::
-
- $twig = new Twig_Environment($loader);
- $twig->addFilter($filter);
-
-And here is how to use it in a template:
-
-.. code-block:: jinja
-
- {{ 'Twig'|rot13 }}
-
- {# will output Gjvt #}
-
-When called by Twig, the PHP callable receives the left side of the filter
-(before the pipe ``|``) as the first argument and the extra arguments passed
-to the filter (within parentheses ``()``) as extra arguments.
-
-For instance, the following code:
-
-.. code-block:: jinja
-
- {{ 'TWIG'|lower }}
- {{ now|date('d/m/Y') }}
-
-is compiled to something like the following::
-
- <?php echo strtolower('TWIG') ?>
- <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
-
-The ``Twig_SimpleFilter`` class takes an array of options as its last
-argument::
-
- $filter = new Twig_SimpleFilter('rot13', 'str_rot13', $options);
-
-Environment aware Filters
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you want to access the current environment instance in your filter, set the
-``needs_environment`` option to ``true``; Twig will pass the current
-environment as the first argument to the filter call::
-
- $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $string) {
- // get the current charset for instance
- $charset = $env->getCharset();
-
- return str_rot13($string);
- }, array('needs_environment' => true));
-
-Context aware Filters
-~~~~~~~~~~~~~~~~~~~~~
-
-If you want to access the current context in your filter, set the
-``needs_context`` option to ``true``; Twig will pass the current context as
-the first argument to the filter call (or the second one if
-``needs_environment`` is also set to ``true``)::
-
- $filter = new Twig_SimpleFilter('rot13', function ($context, $string) {
- // ...
- }, array('needs_context' => true));
-
- $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $context, $string) {
- // ...
- }, array('needs_context' => true, 'needs_environment' => true));
-
-Automatic Escaping
-~~~~~~~~~~~~~~~~~~
-
-If automatic escaping is enabled, the output of the filter may be escaped
-before printing. If your filter acts as an escaper (or explicitly outputs html
-or JavaScript code), you will want the raw output to be printed. In such a
-case, set the ``is_safe`` option::
-
- $filter = new Twig_SimpleFilter('nl2br', 'nl2br', array('is_safe' => array('html')));
-
-Some filters may need to work on input that is already escaped or safe, for
-example when adding (safe) html tags to originally unsafe output. In such a
-case, set the ``pre_escape`` option to escape the input data before it is run
-through your filter::
-
- $filter = new Twig_SimpleFilter('somefilter', 'somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
-
-Dynamic Filters
-~~~~~~~~~~~~~~~
-
-A filter name containing the special ``*`` character is a dynamic filter as
-the ``*`` can be any string::
-
- $filter = new Twig_SimpleFilter('*_path', function ($name, $arguments) {
- // ...
- });
-
-The following filters will be matched by the above defined dynamic filter:
-
-* ``product_path``
-* ``category_path``
-
-A dynamic filter can define more than one dynamic parts::
-
- $filter = new Twig_SimpleFilter('*_path_*', function ($name, $suffix, $arguments) {
- // ...
- });
-
-The filter will receive all dynamic part values before the normal filter
-arguments, but after the environment and the context. For instance, a call to
-``'foo'|a_path_b()`` will result in the following arguments to be passed to
-the filter: ``('a', 'b', 'foo')``.
-
-Functions
----------
-
-Functions are defined in the exact same way as filters, but you need to create
-an instance of ``Twig_SimpleFunction``::
-
- $twig = new Twig_Environment($loader);
- $function = new Twig_SimpleFunction('function_name', function () {
- // ...
- });
- $twig->addFunction($function);
-
-Functions support the same features as filters, except for the ``pre_escape``
-and ``preserves_safety`` options.
-
-Tests
------
-
-Tests are defined in the exact same way as filters and functions, but you need
-to create an instance of ``Twig_SimpleTest``::
-
- $twig = new Twig_Environment($loader);
- $test = new Twig_SimpleTest('test_name', function () {
- // ...
- });
- $twig->addTest($test);
-
-Tests allow you to create custom application specific logic for evaluating
-boolean conditions. As a simple, example let's create a Twig test that checks if
-objects are 'red'::
-
- $twig = new Twig_Environment($loader)
- $test = new Twig_SimpleTest('red', function ($value) {
- if (isset($value->color) && $value->color == 'red') {
- return true;
- }
- if (isset($value->paint) && $value->paint == 'red') {
- return true;
- }
- return false;
- });
- $twig->addTest($test);
-
-Test functions should always return true/false.
-
-When creating tests you can use the ``node_class`` option to provide custom test
-compilation. This is useful if your test can be compiled into PHP primitives.
-This is used by many of the tests built into Twig::
-
- $twig = new Twig_Environment($loader)
- $test = new Twig_SimpleTest(
- 'odd',
- null,
- array('node_class' => 'Twig_Node_Expression_Test_Odd'));
- $twig->addTest($test);
-
- class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
- {
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(')
- ->subcompile($this->getNode('node'))
- ->raw(' % 2 == 1')
- ->raw(')')
- ;
- }
- }
-
-The above example, shows how you can create tests that use a node class. The
-node class has access to one sub-node called 'node'. This sub-node contains the
-value that is being tested. When the ``odd`` filter is used in code like:
-
-.. code-block:: jinja
-
- {% if my_value is odd %}
-
-The ``node`` sub-node will contain an expression of ``my_value``. Node based
-tests also have access to the ``arguments`` node. This node will contain the
-various other arguments that have been provided to your test.
-
-Tags
-----
-
-One of the most exciting feature of a template engine like Twig is the
-possibility to define new language constructs. This is also the most complex
-feature as you need to understand how Twig's internals work.
-
-Let's create a simple ``set`` tag that allows the definition of simple
-variables from within a template. The tag can be used like follows:
-
-.. code-block:: jinja
-
- {% set name = "value" %}
-
- {{ name }}
-
- {# should output value #}
-
-.. note::
-
- The ``set`` tag is part of the Core extension and as such is always
- available. The built-in version is slightly more powerful and supports
- multiple assignments by default (cf. the template designers chapter for
- more information).
-
-Three steps are needed to define a new tag:
-
-* Defining a Token Parser class (responsible for parsing the template code);
-
-* Defining a Node class (responsible for converting the parsed code to PHP);
-
-* Registering the tag.
-
-Registering a new tag
-~~~~~~~~~~~~~~~~~~~~~
-
-Adding a tag is as simple as calling the ``addTokenParser`` method on the
-``Twig_Environment`` instance::
-
- $twig = new Twig_Environment($loader);
- $twig->addTokenParser(new Project_Set_TokenParser());
-
-Defining a Token Parser
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Now, let's see the actual code of this class::
-
- class Project_Set_TokenParser extends Twig_TokenParser
- {
- public function parse(Twig_Token $token)
- {
- $parser = $this->parser;
- $stream = $parser->getStream();
-
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
- $stream->expect(Twig_Token::OPERATOR_TYPE, '=');
- $value = $parser->getExpressionParser()->parseExpression();
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Project_Set_Node($name, $value, $token->getLine(), $this->getTag());
- }
-
- public function getTag()
- {
- return 'set';
- }
- }
-
-The ``getTag()`` method must return the tag we want to parse, here ``set``.
-
-The ``parse()`` method is invoked whenever the parser encounters a ``set``
-tag. It should return a ``Twig_Node`` instance that represents the node (the
-``Project_Set_Node`` calls creating is explained in the next section).
-
-The parsing process is simplified thanks to a bunch of methods you can call
-from the token stream (``$this->parser->getStream()``):
-
-* ``getCurrent()``: Gets the current token in the stream.
-
-* ``next()``: Moves to the next token in the stream, *but returns the old one*.
-
-* ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
- the current token is of a particular type or value (or both). The value may be an
- array of several possible values.
-
-* ``expect($type[, $value[, $message]])``: If the current token isn't of the given
- type/value a syntax error is thrown. Otherwise, if the type and value are correct,
- the token is returned and the stream moves to the next token.
-
-* ``look()``: Looks a the next token without consuming it.
-
-Parsing expressions is done by calling the ``parseExpression()`` like we did for
-the ``set`` tag.
-
-.. tip::
-
- Reading the existing ``TokenParser`` classes is the best way to learn all
- the nitty-gritty details of the parsing process.
-
-Defining a Node
-~~~~~~~~~~~~~~~
-
-The ``Project_Set_Node`` class itself is rather simple::
-
- class Project_Set_Node extends Twig_Node
- {
- public function __construct($name, Twig_Node_Expression $value, $line, $tag = null)
- {
- parent::__construct(array('value' => $value), array('name' => $name), $line, $tag);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('$context[\''.$this->getAttribute('name').'\'] = ')
- ->subcompile($this->getNode('value'))
- ->raw(";\n")
- ;
- }
- }
-
-The compiler implements a fluid interface and provides methods that helps the
-developer generate beautiful and readable PHP code:
-
-* ``subcompile()``: Compiles a node.
-
-* ``raw()``: Writes the given string as is.
-
-* ``write()``: Writes the given string by adding indentation at the beginning
- of each line.
-
-* ``string()``: Writes a quoted string.
-
-* ``repr()``: Writes a PHP representation of a given value (see
- ``Twig_Node_For`` for a usage example).
-
-* ``addDebugInfo()``: Adds the line of the original template file related to
- the current node as a comment.
-
-* ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
- usage example).
-
-* ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
- usage example).
-
-.. _creating_extensions:
-
-Creating an Extension
----------------------
-
-The main motivation for writing an extension is to move often used code into a
-reusable class like adding support for internationalization. An extension can
-define tags, filters, tests, operators, global variables, functions, and node
-visitors.
-
-Creating an extension also makes for a better separation of code that is
-executed at compilation time and code needed at runtime. As such, it makes
-your code faster.
-
-Most of the time, it is useful to create a single extension for your project,
-to host all the specific tags and filters you want to add to Twig.
-
-.. tip::
-
- When packaging your code into an extension, Twig is smart enough to
- recompile your templates whenever you make a change to it (when
- ``auto_reload`` is enabled).
-
-.. note::
-
- Before writing your own extensions, have a look at the Twig official
- extension repository: http://github.com/fabpot/Twig-extensions.
-
-An extension is a class that implements the following interface::
-
- interface Twig_ExtensionInterface
- {
- /**
- * Initializes the runtime environment.
- *
- * This is where you can load some file that contains filter functions for instance.
- *
- * @param Twig_Environment $environment The current Twig_Environment instance
- */
- function initRuntime(Twig_Environment $environment);
-
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- function getTokenParsers();
-
- /**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- function getNodeVisitors();
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- function getFilters();
-
- /**
- * Returns a list of tests to add to the existing list.
- *
- * @return array An array of tests
- */
- function getTests();
-
- /**
- * Returns a list of functions to add to the existing list.
- *
- * @return array An array of functions
- */
- function getFunctions();
-
- /**
- * Returns a list of operators to add to the existing list.
- *
- * @return array An array of operators
- */
- function getOperators();
-
- /**
- * Returns a list of global variables to add to the existing list.
- *
- * @return array An array of global variables
- */
- function getGlobals();
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- function getName();
- }
-
-To keep your extension class clean and lean, it can inherit from the built-in
-``Twig_Extension`` class instead of implementing the whole interface. That
-way, you just need to implement the ``getName()`` method as the
-``Twig_Extension`` provides empty implementations for all other methods.
-
-The ``getName()`` method must return a unique identifier for your extension.
-
-Now, with this information in mind, let's create the most basic extension
-possible::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getName()
- {
- return 'project';
- }
- }
-
-.. note::
-
- Of course, this extension does nothing for now. We will customize it in
- the next sections.
-
-Twig does not care where you save your extension on the filesystem, as all
-extensions must be registered explicitly to be available in your templates.
-
-You can register an extension by using the ``addExtension()`` method on your
-main ``Environment`` object::
-
- $twig = new Twig_Environment($loader);
- $twig->addExtension(new Project_Twig_Extension());
-
-Of course, you need to first load the extension file by either using
-``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
-
-.. tip::
-
- The bundled extensions are great examples of how extensions work.
-
-Globals
-~~~~~~~
-
-Global variables can be registered in an extension via the ``getGlobals()``
-method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getGlobals()
- {
- return array(
- 'text' => new Text(),
- );
- }
-
- // ...
- }
-
-Functions
-~~~~~~~~~
-
-Functions can be registered in an extension via the ``getFunctions()``
-method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFunctions()
- {
- return array(
- new Twig_SimpleFunction('lipsum', 'generate_lipsum'),
- );
- }
-
- // ...
- }
-
-Filters
-~~~~~~~
-
-To add a filter to an extension, you need to override the ``getFilters()``
-method. This method must return an array of filters to add to the Twig
-environment::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFilters()
- {
- return array(
- new Twig_SimpleFilter('rot13', 'str_rot13'),
- );
- }
-
- // ...
- }
-
-Tags
-~~~~
-
-Adding a tag in an extension can be done by overriding the
-``getTokenParsers()`` method. This method must return an array of tags to add
-to the Twig environment::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getTokenParsers()
- {
- return array(new Project_Set_TokenParser());
- }
-
- // ...
- }
-
-In the above code, we have added a single new tag, defined by the
-``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
-responsible for parsing the tag and compiling it to PHP.
-
-Operators
-~~~~~~~~~
-
-The ``getOperators()`` methods allows to add new operators. Here is how to add
-``!``, ``||``, and ``&&`` operators::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getOperators()
- {
- return array(
- array(
- '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
- ),
- array(
- '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- ),
- );
- }
-
- // ...
- }
-
-Tests
-~~~~~
-
-The ``getTests()`` methods allows to add new test functions::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getTests()
- {
- return array(
- new Twig_SimpleTest('even', 'twig_test_even'),
- );
- }
-
- // ...
- }
-
-Overloading
------------
-
-To overload an already defined filter, test, operator, global variable, or
-function, define it again **as late as possible**::
-
- $twig = new Twig_Environment($loader);
- $twig->addFilter(new Twig_SimpleFilter('date', function ($timestamp, $format = 'F j, Y H:i') {
- // do something different from the built-in date filter
- }));
-
-Here, we have overloaded the built-in ``date`` filter with a custom one.
-
-That also works with an extension::
-
- class MyCoreExtension extends Twig_Extension
- {
- public function getFilters()
- {
- return array(
- new Twig_SimpleFilter('date', array($this, 'dateFilter')),
- );
- }
-
- public function dateFilter($timestamp, $format = 'F j, Y H:i')
- {
- // do something different from the built-in date filter
- }
-
- public function getName()
- {
- return 'project';
- }
- }
-
- $twig = new Twig_Environment($loader);
- $twig->addExtension(new MyCoreExtension());
-
-.. caution::
-
- Note that overloading the built-in Twig elements is not recommended as it
- might be confusing.
-
-Testing an Extension
---------------------
-
-Functional Tests
-~~~~~~~~~~~~~~~~
-
-You can create functional tests for extensions simply by creating the
-following file structure in your test directory::
-
- Fixtures/
- filters/
- foo.test
- bar.test
- functions/
- foo.test
- bar.test
- tags/
- foo.test
- bar.test
- IntegrationTest.php
-
-The ``IntegrationTest.php`` file should look like this::
-
- class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
- {
- public function getExtensions()
- {
- return array(
- new Project_Twig_Extension1(),
- new Project_Twig_Extension2(),
- );
- }
-
- public function getFixturesDir()
- {
- return dirname(__FILE__).'/Fixtures/';
- }
- }
-
-Fixtures examples can be found within the Twig repository
-`tests/Twig/Fixtures`_ directory.
-
-Node Tests
-~~~~~~~~~~
-
-Testing the node visitors can be complex, so extend your test cases from
-``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
-`tests/Twig/Node`_ directory.
-
-.. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
-.. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
-.. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures
-.. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node
+++ /dev/null
-Extending Twig
-==============
-
-.. caution::
-
- This section describes how to extends Twig for versions **older than
- 1.12**. If you are using a newer version, read the :doc:`newer<advanced>`
- chapter instead.
-
-Twig can be extended in many ways; you can add extra tags, filters, tests,
-operators, global variables, and functions. You can even extend the parser
-itself with node visitors.
-
-.. note::
-
- The first section of this chapter describes how to extend Twig easily. If
- you want to reuse your changes in different projects or if you want to
- share them with others, you should then create an extension as described
- in the following section.
-
-.. caution::
-
- When extending Twig by calling methods on the Twig environment instance,
- Twig won't be able to recompile your templates when the PHP code is
- updated. To see your changes in real-time, either disable template caching
- or package your code into an extension (see the next section of this
- chapter).
-
-Before extending Twig, you must understand the differences between all the
-different possible extension points and when to use them.
-
-First, remember that Twig has two main language constructs:
-
-* ``{{ }}``: used to print the result of an expression evaluation;
-
-* ``{% %}``: used to execute statements.
-
-To understand why Twig exposes so many extension points, let's see how to
-implement a *Lorem ipsum* generator (it needs to know the number of words to
-generate).
-
-You can use a ``lipsum`` *tag*:
-
-.. code-block:: jinja
-
- {% lipsum 40 %}
-
-That works, but using a tag for ``lipsum`` is not a good idea for at least
-three main reasons:
-
-* ``lipsum`` is not a language construct;
-* The tag outputs something;
-* The tag is not flexible as you cannot use it in an expression:
-
- .. code-block:: jinja
-
- {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
-
-In fact, you rarely need to create tags; and that's good news because tags are
-the most complex extension point of Twig.
-
-Now, let's use a ``lipsum`` *filter*:
-
-.. code-block:: jinja
-
- {{ 40|lipsum }}
-
-Again, it works, but it looks weird. A filter transforms the passed value to
-something else but here we use the value to indicate the number of words to
-generate (so, ``40`` is an argument of the filter, not the value we want to
-transform).
-
-Next, let's use a ``lipsum`` *function*:
-
-.. code-block:: jinja
-
- {{ lipsum(40) }}
-
-Here we go. For this specific example, the creation of a function is the
-extension point to use. And you can use it anywhere an expression is accepted:
-
-.. code-block:: jinja
-
- {{ 'some text' ~ ipsum(40) ~ 'some more text' }}
-
- {% set ipsum = ipsum(40) %}
-
-Last but not the least, you can also use a *global* object with a method able
-to generate lorem ipsum text:
-
-.. code-block:: jinja
-
- {{ text.lipsum(40) }}
-
-As a rule of thumb, use functions for frequently used features and global
-objects for everything else.
-
-Keep in mind the following when you want to extend Twig:
-
-========== ========================== ========== =========================
-What? Implementation difficulty? How often? When?
-========== ========================== ========== =========================
-*macro* trivial frequent Content generation
-*global* trivial frequent Helper object
-*function* trivial frequent Content generation
-*filter* trivial frequent Value transformation
-*tag* complex rare DSL language construct
-*test* trivial rare Boolean decision
-*operator* trivial rare Values transformation
-========== ========================== ========== =========================
-
-Globals
--------
-
-A global variable is like any other template variable, except that it's
-available in all templates and macros::
-
- $twig = new Twig_Environment($loader);
- $twig->addGlobal('text', new Text());
-
-You can then use the ``text`` variable anywhere in a template:
-
-.. code-block:: jinja
-
- {{ text.lipsum(40) }}
-
-Filters
--------
-
-A filter is a regular PHP function or an object method that takes the left
-side of the filter (before the pipe ``|``) as first argument and the extra
-arguments passed to the filter (within parentheses ``()``) as extra arguments.
-
-Defining a filter is as easy as associating the filter name with a PHP
-callable. For instance, let's say you have the following code in a template:
-
-.. code-block:: jinja
-
- {{ 'TWIG'|lower }}
-
-When compiling this template to PHP, Twig looks for the PHP callable
-associated with the ``lower`` filter. The ``lower`` filter is a built-in Twig
-filter, and it is simply mapped to the PHP ``strtolower()`` function. After
-compilation, the generated PHP code is roughly equivalent to:
-
-.. code-block:: html+php
-
- <?php echo strtolower('TWIG') ?>
-
-As you can see, the ``'TWIG'`` string is passed as a first argument to the PHP
-function.
-
-A filter can also take extra arguments like in the following example:
-
-.. code-block:: jinja
-
- {{ now|date('d/m/Y') }}
-
-In this case, the extra arguments are passed to the function after the main
-argument, and the compiled code is equivalent to:
-
-.. code-block:: html+php
-
- <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
-
-Let's see how to create a new filter.
-
-In this section, we will create a ``rot13`` filter, which should return the
-`rot13`_ transformation of a string. Here is an example of its usage and the
-expected output:
-
-.. code-block:: jinja
-
- {{ "Twig"|rot13 }}
-
- {# should displays Gjvt #}
-
-Adding a filter is as simple as calling the ``addFilter()`` method on the
-``Twig_Environment`` instance::
-
- $twig = new Twig_Environment($loader);
- $twig->addFilter('rot13', new Twig_Filter_Function('str_rot13'));
-
-The second argument of ``addFilter()`` is an instance of ``Twig_Filter``.
-Here, we use ``Twig_Filter_Function`` as the filter is a PHP function. The
-first argument passed to the ``Twig_Filter_Function`` constructor is the name
-of the PHP function to call, here ``str_rot13``, a native PHP function.
-
-Let's say I now want to be able to add a prefix before the converted string:
-
-.. code-block:: jinja
-
- {{ "Twig"|rot13('prefix_') }}
-
- {# should displays prefix_Gjvt #}
-
-As the PHP ``str_rot13()`` function does not support this requirement, let's
-create a new PHP function::
-
- function project_compute_rot13($string, $prefix = '')
- {
- return $prefix.str_rot13($string);
- }
-
-As you can see, the ``prefix`` argument of the filter is passed as an extra
-argument to the ``project_compute_rot13()`` function.
-
-Adding this filter is as easy as before::
-
- $twig->addFilter('rot13', new Twig_Filter_Function('project_compute_rot13'));
-
-For better encapsulation, a filter can also be defined as a static method of a
-class. The ``Twig_Filter_Function`` class can also be used to register such
-static methods as filters::
-
- $twig->addFilter('rot13', new Twig_Filter_Function('SomeClass::rot13Filter'));
-
-.. tip::
-
- In an extension, you can also define a filter as a static method of the
- extension class.
-
-Environment aware Filters
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``Twig_Filter`` classes take options as their last argument. For instance,
-if you want access to the current environment instance in your filter, set the
-``needs_environment`` option to ``true``::
-
- $filter = new Twig_Filter_Function('str_rot13', array('needs_environment' => true));
-
-Twig will then pass the current environment as the first argument to the
-filter call::
-
- function twig_compute_rot13(Twig_Environment $env, $string)
- {
- // get the current charset for instance
- $charset = $env->getCharset();
-
- return str_rot13($string);
- }
-
-Automatic Escaping
-~~~~~~~~~~~~~~~~~~
-
-If automatic escaping is enabled, the output of the filter may be escaped
-before printing. If your filter acts as an escaper (or explicitly outputs html
-or javascript code), you will want the raw output to be printed. In such a
-case, set the ``is_safe`` option::
-
- $filter = new Twig_Filter_Function('nl2br', array('is_safe' => array('html')));
-
-Some filters may need to work on input that is already escaped or safe, for
-example when adding (safe) html tags to originally unsafe output. In such a
-case, set the ``pre_escape`` option to escape the input data before it is run
-through your filter::
-
- $filter = new Twig_Filter_Function('somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
-
-Dynamic Filters
-~~~~~~~~~~~~~~~
-
-.. versionadded:: 1.5
- Dynamic filters support was added in Twig 1.5.
-
-A filter name containing the special ``*`` character is a dynamic filter as
-the ``*`` can be any string::
-
- $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
-
- function twig_path($name, $arguments)
- {
- // ...
- }
-
-The following filters will be matched by the above defined dynamic filter:
-
-* ``product_path``
-* ``category_path``
-
-A dynamic filter can define more than one dynamic parts::
-
- $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
-
- function twig_path($name, $suffix, $arguments)
- {
- // ...
- }
-
-The filter will receive all dynamic part values before the normal filters
-arguments. For instance, a call to ``'foo'|a_path_b()`` will result in the
-following PHP call: ``twig_path('a', 'b', 'foo')``.
-
-Functions
----------
-
-A function is a regular PHP function or an object method that can be called from
-templates.
-
-.. code-block:: jinja
-
- {{ constant("DATE_W3C") }}
-
-When compiling this template to PHP, Twig looks for the PHP callable
-associated with the ``constant`` function. The ``constant`` function is a built-in Twig
-function, and it is simply mapped to the PHP ``constant()`` function. After
-compilation, the generated PHP code is roughly equivalent to:
-
-.. code-block:: html+php
-
- <?php echo constant('DATE_W3C') ?>
-
-Adding a function is similar to adding a filter. This can be done by calling the
-``addFunction()`` method on the ``Twig_Environment`` instance::
-
- $twig = new Twig_Environment($loader);
- $twig->addFunction('functionName', new Twig_Function_Function('someFunction'));
-
-You can also expose extension methods as functions in your templates::
-
- // $this is an object that implements Twig_ExtensionInterface.
- $twig = new Twig_Environment($loader);
- $twig->addFunction('otherFunction', new Twig_Function_Method($this, 'someMethod'));
-
-Functions also support ``needs_environment`` and ``is_safe`` parameters.
-
-Dynamic Functions
-~~~~~~~~~~~~~~~~~
-
-.. versionadded:: 1.5
- Dynamic functions support was added in Twig 1.5.
-
-A function name containing the special ``*`` character is a dynamic function
-as the ``*`` can be any string::
-
- $twig->addFunction('*_path', new Twig_Function_Function('twig_path'));
-
- function twig_path($name, $arguments)
- {
- // ...
- }
-
-The following functions will be matched by the above defined dynamic function:
-
-* ``product_path``
-* ``category_path``
-
-A dynamic function can define more than one dynamic parts::
-
- $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
-
- function twig_path($name, $suffix, $arguments)
- {
- // ...
- }
-
-The function will receive all dynamic part values before the normal functions
-arguments. For instance, a call to ``a_path_b('foo')`` will result in the
-following PHP call: ``twig_path('a', 'b', 'foo')``.
-
-Tags
-----
-
-One of the most exciting feature of a template engine like Twig is the
-possibility to define new language constructs. This is also the most complex
-feature as you need to understand how Twig's internals work.
-
-Let's create a simple ``set`` tag that allows the definition of simple
-variables from within a template. The tag can be used like follows:
-
-.. code-block:: jinja
-
- {% set name = "value" %}
-
- {{ name }}
-
- {# should output value #}
-
-.. note::
-
- The ``set`` tag is part of the Core extension and as such is always
- available. The built-in version is slightly more powerful and supports
- multiple assignments by default (cf. the template designers chapter for
- more information).
-
-Three steps are needed to define a new tag:
-
-* Defining a Token Parser class (responsible for parsing the template code);
-
-* Defining a Node class (responsible for converting the parsed code to PHP);
-
-* Registering the tag.
-
-Registering a new tag
-~~~~~~~~~~~~~~~~~~~~~
-
-Adding a tag is as simple as calling the ``addTokenParser`` method on the
-``Twig_Environment`` instance::
-
- $twig = new Twig_Environment($loader);
- $twig->addTokenParser(new Project_Set_TokenParser());
-
-Defining a Token Parser
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Now, let's see the actual code of this class::
-
- class Project_Set_TokenParser extends Twig_TokenParser
- {
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
- $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue();
- $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, '=');
- $value = $this->parser->getExpressionParser()->parseExpression();
-
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Project_Set_Node($name, $value, $lineno, $this->getTag());
- }
-
- public function getTag()
- {
- return 'set';
- }
- }
-
-The ``getTag()`` method must return the tag we want to parse, here ``set``.
-
-The ``parse()`` method is invoked whenever the parser encounters a ``set``
-tag. It should return a ``Twig_Node`` instance that represents the node (the
-``Project_Set_Node`` calls creating is explained in the next section).
-
-The parsing process is simplified thanks to a bunch of methods you can call
-from the token stream (``$this->parser->getStream()``):
-
-* ``getCurrent()``: Gets the current token in the stream.
-
-* ``next()``: Moves to the next token in the stream, *but returns the old one*.
-
-* ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
- the current token is of a particular type or value (or both). The value may be an
- array of several possible values.
-
-* ``expect($type[, $value[, $message]])``: If the current token isn't of the given
- type/value a syntax error is thrown. Otherwise, if the type and value are correct,
- the token is returned and the stream moves to the next token.
-
-* ``look()``: Looks a the next token without consuming it.
-
-Parsing expressions is done by calling the ``parseExpression()`` like we did for
-the ``set`` tag.
-
-.. tip::
-
- Reading the existing ``TokenParser`` classes is the best way to learn all
- the nitty-gritty details of the parsing process.
-
-Defining a Node
-~~~~~~~~~~~~~~~
-
-The ``Project_Set_Node`` class itself is rather simple::
-
- class Project_Set_Node extends Twig_Node
- {
- public function __construct($name, Twig_Node_Expression $value, $lineno, $tag = null)
- {
- parent::__construct(array('value' => $value), array('name' => $name), $lineno, $tag);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('$context[\''.$this->getAttribute('name').'\'] = ')
- ->subcompile($this->getNode('value'))
- ->raw(";\n")
- ;
- }
- }
-
-The compiler implements a fluid interface and provides methods that helps the
-developer generate beautiful and readable PHP code:
-
-* ``subcompile()``: Compiles a node.
-
-* ``raw()``: Writes the given string as is.
-
-* ``write()``: Writes the given string by adding indentation at the beginning
- of each line.
-
-* ``string()``: Writes a quoted string.
-
-* ``repr()``: Writes a PHP representation of a given value (see
- ``Twig_Node_For`` for a usage example).
-
-* ``addDebugInfo()``: Adds the line of the original template file related to
- the current node as a comment.
-
-* ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
- usage example).
-
-* ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
- usage example).
-
-.. _creating_extensions:
-
-Creating an Extension
----------------------
-
-The main motivation for writing an extension is to move often used code into a
-reusable class like adding support for internationalization. An extension can
-define tags, filters, tests, operators, global variables, functions, and node
-visitors.
-
-Creating an extension also makes for a better separation of code that is
-executed at compilation time and code needed at runtime. As such, it makes
-your code faster.
-
-Most of the time, it is useful to create a single extension for your project,
-to host all the specific tags and filters you want to add to Twig.
-
-.. tip::
-
- When packaging your code into an extension, Twig is smart enough to
- recompile your templates whenever you make a change to it (when the
- ``auto_reload`` is enabled).
-
-.. note::
-
- Before writing your own extensions, have a look at the Twig official
- extension repository: http://github.com/fabpot/Twig-extensions.
-
-An extension is a class that implements the following interface::
-
- interface Twig_ExtensionInterface
- {
- /**
- * Initializes the runtime environment.
- *
- * This is where you can load some file that contains filter functions for instance.
- *
- * @param Twig_Environment $environment The current Twig_Environment instance
- */
- function initRuntime(Twig_Environment $environment);
-
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- function getTokenParsers();
-
- /**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- function getNodeVisitors();
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- function getFilters();
-
- /**
- * Returns a list of tests to add to the existing list.
- *
- * @return array An array of tests
- */
- function getTests();
-
- /**
- * Returns a list of functions to add to the existing list.
- *
- * @return array An array of functions
- */
- function getFunctions();
-
- /**
- * Returns a list of operators to add to the existing list.
- *
- * @return array An array of operators
- */
- function getOperators();
-
- /**
- * Returns a list of global variables to add to the existing list.
- *
- * @return array An array of global variables
- */
- function getGlobals();
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- function getName();
- }
-
-To keep your extension class clean and lean, it can inherit from the built-in
-``Twig_Extension`` class instead of implementing the whole interface. That
-way, you just need to implement the ``getName()`` method as the
-``Twig_Extension`` provides empty implementations for all other methods.
-
-The ``getName()`` method must return a unique identifier for your extension.
-
-Now, with this information in mind, let's create the most basic extension
-possible::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getName()
- {
- return 'project';
- }
- }
-
-.. note::
-
- Of course, this extension does nothing for now. We will customize it in
- the next sections.
-
-Twig does not care where you save your extension on the filesystem, as all
-extensions must be registered explicitly to be available in your templates.
-
-You can register an extension by using the ``addExtension()`` method on your
-main ``Environment`` object::
-
- $twig = new Twig_Environment($loader);
- $twig->addExtension(new Project_Twig_Extension());
-
-Of course, you need to first load the extension file by either using
-``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
-
-.. tip::
-
- The bundled extensions are great examples of how extensions work.
-
-Globals
-~~~~~~~
-
-Global variables can be registered in an extension via the ``getGlobals()``
-method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getGlobals()
- {
- return array(
- 'text' => new Text(),
- );
- }
-
- // ...
- }
-
-Functions
-~~~~~~~~~
-
-Functions can be registered in an extension via the ``getFunctions()``
-method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFunctions()
- {
- return array(
- 'lipsum' => new Twig_Function_Function('generate_lipsum'),
- );
- }
-
- // ...
- }
-
-Filters
-~~~~~~~
-
-To add a filter to an extension, you need to override the ``getFilters()``
-method. This method must return an array of filters to add to the Twig
-environment::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFilters()
- {
- return array(
- 'rot13' => new Twig_Filter_Function('str_rot13'),
- );
- }
-
- // ...
- }
-
-As you can see in the above code, the ``getFilters()`` method returns an array
-where keys are the name of the filters (``rot13``) and the values the
-definition of the filter (``new Twig_Filter_Function('str_rot13')``).
-
-As seen in the previous chapter, you can also define filters as static methods
-on the extension class::
-
-$twig->addFilter('rot13', new Twig_Filter_Function('Project_Twig_Extension::rot13Filter'));
-
-You can also use ``Twig_Filter_Method`` instead of ``Twig_Filter_Function``
-when defining a filter to use a method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFilters()
- {
- return array(
- 'rot13' => new Twig_Filter_Method($this, 'rot13Filter'),
- );
- }
-
- public function rot13Filter($string)
- {
- return str_rot13($string);
- }
-
- // ...
- }
-
-The first argument of the ``Twig_Filter_Method`` constructor is always
-``$this``, the current extension object. The second one is the name of the
-method to call.
-
-Using methods for filters is a great way to package your filter without
-polluting the global namespace. This also gives the developer more flexibility
-at the cost of a small overhead.
-
-Overriding default Filters
-..........................
-
-If some default core filters do not suit your needs, you can easily override
-them by creating your own extension. Just use the same names as the one you
-want to override::
-
- class MyCoreExtension extends Twig_Extension
- {
- public function getFilters()
- {
- return array(
- 'date' => new Twig_Filter_Method($this, 'dateFilter'),
- // ...
- );
- }
-
- public function dateFilter($timestamp, $format = 'F j, Y H:i')
- {
- return '...'.twig_date_format_filter($timestamp, $format);
- }
-
- public function getName()
- {
- return 'project';
- }
- }
-
-Here, we override the ``date`` filter with a custom one. Using this extension
-is as simple as registering the ``MyCoreExtension`` extension by calling the
-``addExtension()`` method on the environment instance::
-
- $twig = new Twig_Environment($loader);
- $twig->addExtension(new MyCoreExtension());
-
-Tags
-~~~~
-
-Adding a tag in an extension can be done by overriding the
-``getTokenParsers()`` method. This method must return an array of tags to add
-to the Twig environment::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getTokenParsers()
- {
- return array(new Project_Set_TokenParser());
- }
-
- // ...
- }
-
-In the above code, we have added a single new tag, defined by the
-``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
-responsible for parsing the tag and compiling it to PHP.
-
-Operators
-~~~~~~~~~
-
-The ``getOperators()`` methods allows to add new operators. Here is how to add
-``!``, ``||``, and ``&&`` operators::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getOperators()
- {
- return array(
- array(
- '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
- ),
- array(
- '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- ),
- );
- }
-
- // ...
- }
-
-Tests
-~~~~~
-
-The ``getTests()`` methods allows to add new test functions::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getTests()
- {
- return array(
- 'even' => new Twig_Test_Function('twig_test_even'),
- );
- }
-
- // ...
- }
-
-Testing an Extension
---------------------
-
-.. versionadded:: 1.10
- Support for functional tests was added in Twig 1.10.
-
-Functional Tests
-~~~~~~~~~~~~~~~~
-
-You can create functional tests for extensions simply by creating the
-following file structure in your test directory::
-
- Fixtures/
- filters/
- foo.test
- bar.test
- functions/
- foo.test
- bar.test
- tags/
- foo.test
- bar.test
- IntegrationTest.php
-
-The ``IntegrationTest.php`` file should look like this::
-
- class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
- {
- public function getExtensions()
- {
- return array(
- new Project_Twig_Extension1(),
- new Project_Twig_Extension2(),
- );
- }
-
- public function getFixturesDir()
- {
- return dirname(__FILE__).'/Fixtures/';
- }
- }
-
-Fixtures examples can be found within the Twig repository
-`tests/Twig/Fixtures`_ directory.
-
-Node Tests
-~~~~~~~~~~
-
-Testing the node visitors can be complex, so extend your test cases from
-``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
-`tests/Twig/Node`_ directory.
-
-.. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
-.. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
-.. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures
-.. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node
+++ /dev/null
-Twig for Developers
-===================
-
-This chapter describes the API to Twig and not the template language. It will
-be most useful as reference to those implementing the template interface to
-the application and not those who are creating Twig templates.
-
-Basics
-------
-
-Twig uses a central object called the **environment** (of class
-``Twig_Environment``). Instances of this class are used to store the
-configuration and extensions, and are used to load templates from the file
-system or other locations.
-
-Most applications will create one ``Twig_Environment`` object on application
-initialization and use that to load templates. In some cases it's however
-useful to have multiple environments side by side, if different configurations
-are in use.
-
-The simplest way to configure Twig to load templates for your application
-looks roughly like this::
-
- require_once '/path/to/lib/Twig/Autoloader.php';
- Twig_Autoloader::register();
-
- $loader = new Twig_Loader_Filesystem('/path/to/templates');
- $twig = new Twig_Environment($loader, array(
- 'cache' => '/path/to/compilation_cache',
- ));
-
-This will create a template environment with the default settings and a loader
-that looks up the templates in the ``/path/to/templates/`` folder. Different
-loaders are available and you can also write your own if you want to load
-templates from a database or other resources.
-
-.. note::
-
- Notice that the second argument of the environment is an array of options.
- The ``cache`` option is a compilation cache directory, where Twig caches
- the compiled templates to avoid the parsing phase for sub-sequent
- requests. It is very different from the cache you might want to add for
- the evaluated templates. For such a need, you can use any available PHP
- cache library.
-
-To load a template from this environment you just have to call the
-``loadTemplate()`` method which then returns a ``Twig_Template`` instance::
-
- $template = $twig->loadTemplate('index.html');
-
-To render the template with some variables, call the ``render()`` method::
-
- echo $template->render(array('the' => 'variables', 'go' => 'here'));
-
-.. note::
-
- The ``display()`` method is a shortcut to output the template directly.
-
-You can also load and render the template in one fell swoop::
-
- echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here'));
-
-.. _environment_options:
-
-Environment Options
--------------------
-
-When creating a new ``Twig_Environment`` instance, you can pass an array of
-options as the constructor second argument::
-
- $twig = new Twig_Environment($loader, array('debug' => true));
-
-The following options are available:
-
-* ``debug``: When set to ``true``, the generated templates have a
- ``__toString()`` method that you can use to display the generated nodes
- (default to ``false``).
-
-* ``charset``: The charset used by the templates (default to ``utf-8``).
-
-* ``base_template_class``: The base template class to use for generated
- templates (default to ``Twig_Template``).
-
-* ``cache``: An absolute path where to store the compiled templates, or
- ``false`` to disable caching (which is the default).
-
-* ``auto_reload``: When developing with Twig, it's useful to recompile the
- template whenever the source code changes. If you don't provide a value for
- the ``auto_reload`` option, it will be determined automatically based on the
- ``debug`` value.
-
-* ``strict_variables``: If set to ``false``, Twig will silently ignore invalid
- variables (variables and or attributes/methods that do not exist) and
- replace them with a ``null`` value. When set to ``true``, Twig throws an
- exception instead (default to ``false``).
-
-* ``autoescape``: If set to ``true``, auto-escaping will be enabled by default
- for all templates (default to ``true``). As of Twig 1.8, you can set the
- escaping strategy to use (``html``, ``js``, ``false`` to disable).
- As of Twig 1.9, you can set the escaping strategy to use (``css``, ``url``,
- ``html_attr``, or a PHP callback that takes the template "filename" and must
- return the escaping strategy to use -- the callback cannot be a function name
- to avoid collision with built-in escaping strategies).
-
-* ``optimizations``: A flag that indicates which optimizations to apply
- (default to ``-1`` -- all optimizations are enabled; set it to ``0`` to
- disable).
-
-Loaders
--------
-
-Loaders are responsible for loading templates from a resource such as the file
-system.
-
-Compilation Cache
-~~~~~~~~~~~~~~~~~
-
-All template loaders can cache the compiled templates on the filesystem for
-future reuse. It speeds up Twig a lot as templates are only compiled once; and
-the performance boost is even larger if you use a PHP accelerator such as APC.
-See the ``cache`` and ``auto_reload`` options of ``Twig_Environment`` above
-for more information.
-
-Built-in Loaders
-~~~~~~~~~~~~~~~~
-
-Here is a list of the built-in loaders Twig provides:
-
-``Twig_Loader_Filesystem``
-..........................
-
-.. versionadded:: 1.10
- The ``prependPath()`` and support for namespaces were added in Twig 1.10.
-
-``Twig_Loader_Filesystem`` loads templates from the file system. This loader
-can find templates in folders on the file system and is the preferred way to
-load them::
-
- $loader = new Twig_Loader_Filesystem($templateDir);
-
-It can also look for templates in an array of directories::
-
- $loader = new Twig_Loader_Filesystem(array($templateDir1, $templateDir2));
-
-With such a configuration, Twig will first look for templates in
-``$templateDir1`` and if they do not exist, it will fallback to look for them
-in the ``$templateDir2``.
-
-You can add or prepend paths via the ``addPath()`` and ``prependPath()``
-methods::
-
- $loader->addPath($templateDir3);
- $loader->prependPath($templateDir4);
-
-The filesystem loader also supports namespaced templates. This allows to group
-your templates under different namespaces which have their own template paths.
-
-When using the ``setPaths()``, ``addPath()``, and ``prependPath()`` methods,
-specify the namespace as the second argument (when not specified, these
-methods act on the "main" namespace)::
-
- $loader->addPath($templateDir, 'admin');
-
-Namespaced templates can be accessed via the special
-``@namespace_name/template_path`` notation::
-
- $twig->render('@admin/index.html', array());
-
-``Twig_Loader_String``
-......................
-
-``Twig_Loader_String`` loads templates from strings. It's a dummy loader as
-the template reference is the template source code::
-
- $loader = new Twig_Loader_String();
- $twig = new Twig_Environment($loader);
-
- echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
-
-This loader should only be used for unit testing as it has severe limitations:
-several tags, like ``extends`` or ``include`` do not make sense to use as the
-reference to the template is the template source code itself.
-
-``Twig_Loader_Array``
-.....................
-
-``Twig_Loader_Array`` loads a template from a PHP array. It's passed an array
-of strings bound to template names::
-
- $loader = new Twig_Loader_Array(array(
- 'index.html' => 'Hello {{ name }}!',
- ));
- $twig = new Twig_Environment($loader);
-
- echo $twig->render('index.html', array('name' => 'Fabien'));
-
-This loader is very useful for unit testing. It can also be used for small
-projects where storing all templates in a single PHP file might make sense.
-
-.. tip::
-
- When using the ``Array`` or ``String`` loaders with a cache mechanism, you
- should know that a new cache key is generated each time a template content
- "changes" (the cache key being the source code of the template). If you
- don't want to see your cache grows out of control, you need to take care
- of clearing the old cache file by yourself.
-
-``Twig_Loader_Chain``
-.....................
-
-``Twig_Loader_Chain`` delegates the loading of templates to other loaders::
-
- $loader1 = new Twig_Loader_Array(array(
- 'base.html' => '{% block content %}{% endblock %}',
- ));
- $loader2 = new Twig_Loader_Array(array(
- 'index.html' => '{% extends "base.twig" %}{% block content %}Hello {{ name }}{% endblock %}',
- 'base.html' => 'Will never be loaded',
- ));
-
- $loader = new Twig_Loader_Chain(array($loader1, $loader2));
-
- $twig = new Twig_Environment($loader);
-
-When looking for a template, Twig will try each loader in turn and it will
-return as soon as the template is found. When rendering the ``index.html``
-template from the above example, Twig will load it with ``$loader2`` but the
-``base.html`` template will be loaded from ``$loader1``.
-
-``Twig_Loader_Chain`` accepts any loader that implements
-``Twig_LoaderInterface``.
-
-.. note::
-
- You can also add loaders via the ``addLoader()`` method.
-
-Create your own Loader
-~~~~~~~~~~~~~~~~~~~~~~
-
-All loaders implement the ``Twig_LoaderInterface``::
-
- interface Twig_LoaderInterface
- {
- /**
- * Gets the source code of a template, given its name.
- *
- * @param string $name string The name of the template to load
- *
- * @return string The template source code
- */
- function getSource($name);
-
- /**
- * Gets the cache key to use for the cache for a given template name.
- *
- * @param string $name string The name of the template to load
- *
- * @return string The cache key
- */
- function getCacheKey($name);
-
- /**
- * Returns true if the template is still fresh.
- *
- * @param string $name The template name
- * @param timestamp $time The last modification time of the cached template
- */
- function isFresh($name, $time);
- }
-
-As an example, here is how the built-in ``Twig_Loader_String`` reads::
-
- class Twig_Loader_String implements Twig_LoaderInterface
- {
- public function getSource($name)
- {
- return $name;
- }
-
- public function getCacheKey($name)
- {
- return $name;
- }
-
- public function isFresh($name, $time)
- {
- return false;
- }
- }
-
-The ``isFresh()`` method must return ``true`` if the current cached template
-is still fresh, given the last modification time, or ``false`` otherwise.
-
-.. tip::
-
- As of Twig 1.11.0, you can also implement ``Twig_ExistsLoaderInterface``
- to make your loader faster when used with the chain loader.
-
-Using Extensions
-----------------
-
-Twig extensions are packages that add new features to Twig. Using an
-extension is as simple as using the ``addExtension()`` method::
-
- $twig->addExtension(new Twig_Extension_Sandbox());
-
-Twig comes bundled with the following extensions:
-
-* *Twig_Extension_Core*: Defines all the core features of Twig.
-
-* *Twig_Extension_Escaper*: Adds automatic output-escaping and the possibility
- to escape/unescape blocks of code.
-
-* *Twig_Extension_Sandbox*: Adds a sandbox mode to the default Twig
- environment, making it safe to evaluate untrusted code.
-
-* *Twig_Extension_Optimizer*: Optimizes the node tree before compilation.
-
-The core, escaper, and optimizer extensions do not need to be added to the
-Twig environment, as they are registered by default.
-
-Built-in Extensions
--------------------
-
-This section describes the features added by the built-in extensions.
-
-.. tip::
-
- Read the chapter about extending Twig to learn how to create your own
- extensions.
-
-Core Extension
-~~~~~~~~~~~~~~
-
-The ``core`` extension defines all the core features of Twig:
-
-* :doc:`Tags <tags/index>`;
-* :doc:`Filters <filters/index>`;
-* :doc:`Functions <functions/index>`;
-* :doc:`Tests <tests/index>`.
-
-Escaper Extension
-~~~~~~~~~~~~~~~~~
-
-The ``escaper`` extension adds automatic output escaping to Twig. It defines a
-tag, ``autoescape``, and a filter, ``raw``.
-
-When creating the escaper extension, you can switch on or off the global
-output escaping strategy::
-
- $escaper = new Twig_Extension_Escaper('html');
- $twig->addExtension($escaper);
-
-If set to ``html``, all variables in templates are escaped (using the ``html``
-escaping strategy), except those using the ``raw`` filter:
-
-.. code-block:: jinja
-
- {{ article.to_html|raw }}
-
-You can also change the escaping mode locally by using the ``autoescape`` tag
-(see the :doc:`autoescape<tags/autoescape>` doc for the syntax used before
-Twig 1.8):
-
-.. code-block:: jinja
-
- {% autoescape 'html' %}
- {{ var }}
- {{ var|raw }} {# var won't be escaped #}
- {{ var|escape }} {# var won't be double-escaped #}
- {% endautoescape %}
-
-.. warning::
-
- The ``autoescape`` tag has no effect on included files.
-
-The escaping rules are implemented as follows:
-
-* Literals (integers, booleans, arrays, ...) used in the template directly as
- variables or filter arguments are never automatically escaped:
-
- .. code-block:: jinja
-
- {{ "Twig<br />" }} {# won't be escaped #}
-
- {% set text = "Twig<br />" %}
- {{ text }} {# will be escaped #}
-
-* Expressions which the result is always a literal or a variable marked safe
- are never automatically escaped:
-
- .. code-block:: jinja
-
- {{ foo ? "Twig<br />" : "<br />Twig" }} {# won't be escaped #}
-
- {% set text = "Twig<br />" %}
- {{ foo ? text : "<br />Twig" }} {# will be escaped #}
-
- {% set text = "Twig<br />" %}
- {{ foo ? text|raw : "<br />Twig" }} {# won't be escaped #}
-
- {% set text = "Twig<br />" %}
- {{ foo ? text|escape : "<br />Twig" }} {# the result of the expression won't be escaped #}
-
-* Escaping is applied before printing, after any other filter is applied:
-
- .. code-block:: jinja
-
- {{ var|upper }} {# is equivalent to {{ var|upper|escape }} #}
-
-* The `raw` filter should only be used at the end of the filter chain:
-
- .. code-block:: jinja
-
- {{ var|raw|upper }} {# will be escaped #}
-
- {{ var|upper|raw }} {# won't be escaped #}
-
-* Automatic escaping is not applied if the last filter in the chain is marked
- safe for the current context (e.g. ``html`` or ``js``). ``escaper`` and
- ``escaper('html')`` are marked safe for html, ``escaper('js')`` is marked
- safe for javascript, ``raw`` is marked safe for everything.
-
- .. code-block:: jinja
-
- {% autoescape 'js' %}
- {{ var|escape('html') }} {# will be escaped for html and javascript #}
- {{ var }} {# will be escaped for javascript #}
- {{ var|escape('js') }} {# won't be double-escaped #}
- {% endautoescape %}
-
-.. note::
-
- Note that autoescaping has some limitations as escaping is applied on
- expressions after evaluation. For instance, when working with
- concatenation, ``{{ foo|raw ~ bar }}`` won't give the expected result as
- escaping is applied on the result of the concatenation, not on the
- individual variables (so, the ``raw`` filter won't have any effect here).
-
-Sandbox Extension
-~~~~~~~~~~~~~~~~~
-
-The ``sandbox`` extension can be used to evaluate untrusted code. Access to
-unsafe attributes and methods is prohibited. The sandbox security is managed
-by a policy instance. By default, Twig comes with one policy class:
-``Twig_Sandbox_SecurityPolicy``. This class allows you to white-list some
-tags, filters, properties, and methods::
-
- $tags = array('if');
- $filters = array('upper');
- $methods = array(
- 'Article' => array('getTitle', 'getBody'),
- );
- $properties = array(
- 'Article' => array('title', 'body'),
- );
- $functions = array('range');
- $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
-
-With the previous configuration, the security policy will only allow usage of
-the ``if`` tag, and the ``upper`` filter. Moreover, the templates will only be
-able to call the ``getTitle()`` and ``getBody()`` methods on ``Article``
-objects, and the ``title`` and ``body`` public properties. Everything else
-won't be allowed and will generate a ``Twig_Sandbox_SecurityError`` exception.
-
-The policy object is the first argument of the sandbox constructor::
-
- $sandbox = new Twig_Extension_Sandbox($policy);
- $twig->addExtension($sandbox);
-
-By default, the sandbox mode is disabled and should be enabled when including
-untrusted template code by using the ``sandbox`` tag:
-
-.. code-block:: jinja
-
- {% sandbox %}
- {% include 'user.html' %}
- {% endsandbox %}
-
-You can sandbox all templates by passing ``true`` as the second argument of
-the extension constructor::
-
- $sandbox = new Twig_Extension_Sandbox($policy, true);
-
-Optimizer Extension
-~~~~~~~~~~~~~~~~~~~
-
-The ``optimizer`` extension optimizes the node tree before compilation::
-
- $twig->addExtension(new Twig_Extension_Optimizer());
-
-By default, all optimizations are turned on. You can select the ones you want
-to enable by passing them to the constructor::
-
- $optimizer = new Twig_Extension_Optimizer(Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR);
-
- $twig->addExtension($optimizer);
-
-Twig supports the following optimizations:
-
-* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_ALL``, enables all optimizations
- (this is the default value).
-* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_NONE``, disables all optimizations.
- This reduces the compilation time, but it can increase the execution time
- and the consumed memory.
-* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR``, optimizes the ``for`` tag by
- removing the ``loop`` variable creation whenever possible.
-* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_RAW_FILTER``, removes the ``raw``
- filter whenever possible.
-* ``Twig_NodeVisitor_Optimizer::OPTIMIZE_VAR_ACCESS``, simplifies the creation
- and access of variables in the compiled templates whenever possible.
-
-Exceptions
-----------
-
-Twig can throw exceptions:
-
-* ``Twig_Error``: The base exception for all errors.
-
-* ``Twig_Error_Syntax``: Thrown to tell the user that there is a problem with
- the template syntax.
-
-* ``Twig_Error_Runtime``: Thrown when an error occurs at runtime (when a filter
- does not exist for instance).
-
-* ``Twig_Error_Loader``: Thrown when an error occurs during template loading.
-
-* ``Twig_Sandbox_SecurityError``: Thrown when an unallowed tag, filter, or
- method is called in a sandboxed template.
+++ /dev/null
-Coding Standards
-================
-
-When writing Twig templates, we recommend you to follow these official coding
-standards:
-
-* Put one (and only one) space after the start of a delimiter (``{{``, ``{%``,
- and ``{#``) and before the end of a delimiter (``}}``, ``%}``, and ``#}``):
-
- .. code-block:: jinja
-
- {{ foo }}
- {# comment #}
- {% if foo %}{% endif %}
-
- When using the whitespace control character, do not put any spaces between
- it and the delimiter:
-
- .. code-block:: jinja
-
- {{- foo -}}
- {#- comment -#}
- {%- if foo -%}{%- endif -%}
-
-* Put one (and only one) space before and after the following operators:
- comparison operators (``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``), math
- operators (``+``, ``-``, ``/``, ``*``, ``%``, ``//``, ``**``), logic
- operators (``not``, ``and``, ``or``), ``~``, ``is``, ``in``, and the ternary
- operator (``?:``):
-
- .. code-block:: jinja
-
- {{ 1 + 2 }}
- {{ foo ~ bar }}
- {{ true ? true : false }}
-
-* Put one (and only one) space after the ``:`` sign in hashes and ``,`` in
- arrays and hashes:
-
- .. code-block:: jinja
-
- {{ [1, 2, 3] }}
- {{ {'foo': 'bar'} }}
-
-* Do not put any spaces after an opening parenthesis and before a closing
- parenthesis in expressions:
-
- .. code-block:: jinja
-
- {{ 1 + (2 * 3) }}
-
-* Do not put any spaces before and after string delimiters:
-
- .. code-block:: jinja
-
- {{ 'foo' }}
- {{ "foo" }}
-
-* Do not put any spaces before and after the following operators: ``|``,
- ``.``, ``..``, ``[]``:
-
- .. code-block:: jinja
-
- {{ foo|upper|lower }}
- {{ user.name }}
- {{ user[name] }}
- {% for i in 1..12 %}{% endfor %}
-
-* Do not put any spaces before and after the parenthesis used for filter and
- function calls:
-
- .. code-block:: jinja
-
- {{ foo|default('foo') }}
- {{ range(1..10) }}
-
-* Do not put any spaces before and after the opening and the closing of arrays
- and hashes:
-
- .. code-block:: jinja
-
- {{ [1, 2, 3] }}
- {{ {'foo': 'bar'} }}
-
-* Use lower cased and underscored variable names:
-
- .. code-block:: jinja
-
- {% set foo = 'foo' %}
- {% set foo_bar = 'foo' %}
-
-* Indent your code inside tags (use the same indentation as the one used for
- the main language of the file):
-
- .. code-block:: jinja
-
- {% block foo %}
- {% if true %}
- true
- {% endif %}
- {% endblock %}
+++ /dev/null
-Deprecated Features
-===================
-
-This document lists all deprecated features in Twig. Deprecated features are
-kept for backward compatibility and removed in the next major release (a
-feature that was deprecated in Twig 1.x is removed in Twig 2.0).
-
-Token Parsers
--------------
-
-* As of Twig 1.x, the token parser broker sub-system is deprecated. The
- following class and interface will be removed in 2.0:
-
- * ``Twig_TokenParserBrokerInterface``
- * ``Twig_TokenParserBroker``
-
-Extensions
-----------
-
-* As of Twig 1.x, the ability to remove an extension is deprecated and the
- ``Twig_Environment::removeExtension()`` method will be removed in 2.0.
-
-PEAR
-----
-
-PEAR support will be discontinued in Twig 2.0, and no PEAR packages will be
-provided. Use Composer instead.
-
-Filters
--------
-
-* As of Twig 1.x, use ``Twig_SimpleFilter`` to add a filter. The following
- classes and interfaces will be removed in 2.0:
-
- * ``Twig_FilterInterface``
- * ``Twig_FilterCallableInterface``
- * ``Twig_Filter``
- * ``Twig_Filter_Function``
- * ``Twig_Filter_Method``
- * ``Twig_Filter_Node``
-
-* As of Twig 2.x, the ``Twig_SimpleFilter`` class is deprecated and will be
- removed in Twig 3.x (use ``Twig_Filter`` instead). In Twig 2.x,
- ``Twig_SimpleFilter`` is just an alias for ``Twig_Filter``.
-
-Functions
----------
-
-* As of Twig 1.x, use ``Twig_SimpleFunction`` to add a function. The following
- classes and interfaces will be removed in 2.0:
-
- * ``Twig_FunctionInterface``
- * ``Twig_FunctionCallableInterface``
- * ``Twig_Function``
- * ``Twig_Function_Function``
- * ``Twig_Function_Method``
- * ``Twig_Function_Node``
-
-* As of Twig 2.x, the ``Twig_SimpleFunction`` class is deprecated and will be
- removed in Twig 3.x (use ``Twig_Function`` instead). In Twig 2.x,
- ``Twig_SimpleFunction`` is just an alias for ``Twig_Function``.
-
-Tests
------
-
-* As of Twig 1.x, use ``Twig_SimpleTest`` to add a test. The following classes
- and interfaces will be removed in 2.0:
-
- * ``Twig_TestInterface``
- * ``Twig_TestCallableInterface``
- * ``Twig_Test``
- * ``Twig_Test_Function``
- * ``Twig_Test_Method``
- * ``Twig_Test_Node``
-
-* As of Twig 2.x, the ``Twig_SimpleTest`` class is deprecated and will be
- removed in Twig 3.x (use ``Twig_Test`` instead). In Twig 2.x,
- ``Twig_SimpleTest`` is just an alias for ``Twig_Test``.
-
-Interfaces
-----------
-
-* As of Twig 2.x, the following interfaces are deprecated and empty (they will
- be removed in Twig 3.0):
-
-* ``Twig_CompilerInterface`` (use ``Twig_Compiler`` instead)
-* ``Twig_LexerInterface`` (use ``Twig_Lexer`` instead)
-* ``Twig_NodeInterface`` (use ``Twig_Node`` instead)
-* ``Twig_ParserInterface`` (use ``Twig_Parser`` instead)
-* ``Twig_ExistsLoaderInterface`` (merged with ``Twig_LoaderInterface``)
-* ``Twig_TemplateInterface`` (use ``Twig_Template`` instead)
-
-Globals
--------
-
-* As of Twig 2.x, the ability to register a global variable after the runtime
- or the extensions have been initialized is not possible anymore (but
- changing the value of an already registered global is possible).
+++ /dev/null
-``abs``
-=======
-
-The ``abs`` filter returns the absolute value.
-
-.. code-block:: jinja
-
- {# number = -5 #}
-
- {{ number|abs }}
-
- {# outputs 5 #}
-
-.. note::
-
- Internally, Twig uses the PHP `abs`_ function.
-
-.. _`abs`: http://php.net/abs
+++ /dev/null
-``batch``
-=========
-
-.. versionadded:: 1.12.3
- The batch filter was added in Twig 1.12.3.
-
-The ``batch`` filter "batches" items by returning a list of lists with the
-given number of items. If you provide a second parameter, it is used to fill
-missing items:
-
-.. code-block:: jinja
-
- {% set items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] %}
-
- <table>
- {% for row in items|batch(3, 'No item') %}
- <tr>
- {% for column in row %}
- <td>{{ column }}</td>
- {% endfor %}
- </tr>
- {% endfor %}
- </table>
-
-The above example will be rendered as:
-
-.. code-block:: jinja
-
- <table>
- <tr>
- <td>a</td>
- <td>b</td>
- <td>c</td>
- </tr>
- <tr>
- <td>d</td>
- <td>e</td>
- <td>f</td>
- </tr>
- <tr>
- <td>g</td>
- <td>No item</td>
- <td>No item</td>
- </tr>
- </table>
+++ /dev/null
-``capitalize``
-==============
-
-The ``capitalize`` filter capitalizes a value. The first character will be
-uppercase, all others lowercase:
-
-.. code-block:: jinja
-
- {{ 'my first car'|capitalize }}
-
- {# outputs 'My first car' #}
+++ /dev/null
-``convert_encoding``
-====================
-
-.. versionadded:: 1.4
- The ``convert_encoding`` filter was added in Twig 1.4.
-
-The ``convert_encoding`` filter converts a string from one encoding to
-another. The first argument is the expected output charset and the second one
-is the input charset:
-
-.. code-block:: jinja
-
- {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
-
-.. note::
-
- This filter relies on the `iconv`_ or `mbstring`_ extension, so one of
- them must be installed. In case both are installed, `mbstring`_ is used by
- default (Twig before 1.8.1 uses `iconv`_ by default).
-
-Arguments
----------
-
- * ``from``: The input charset
- * ``to``: The output charset
-
-.. _`iconv`: http://php.net/iconv
-.. _`mbstring`: http://php.net/mbstring
+++ /dev/null
-``date``
-========
-
-.. versionadded:: 1.1
- The timezone support has been added in Twig 1.1.
-
-.. versionadded:: 1.5
- The default date format support has been added in Twig 1.5.
-
-.. versionadded:: 1.6.1
- The default timezone support has been added in Twig 1.6.1.
-
-.. versionadded:: 1.11.0
- The introduction of the false value for the timezone was introduced in Twig 1.11.0
-
-The ``date`` filter formats a date to a given format:
-
-.. code-block:: jinja
-
- {{ post.published_at|date("m/d/Y") }}
-
-The ``date`` filter accepts strings (it must be in a format supported by the
-`strtotime`_ function), `DateTime`_ instances, or `DateInterval`_ instances. For
-instance, to display the current date, filter the word "now":
-
-.. code-block:: jinja
-
- {{ "now"|date("m/d/Y") }}
-
-To escape words and characters in the date format use ``\\`` in front of each
-character:
-
-.. code-block:: jinja
-
- {{ post.published_at|date("F jS \\a\\t g:ia") }}
-
-If the value passed to the ``date`` filter is ``null``, it will return the
-current date by default. If an empty string is desired instead of the current
-date, use a ternary operator:
-
-.. code-block:: jinja
-
- {{ post.published_at is empty ? "" : post.published_at|date("m/d/Y") }}
-
-If no format is provided, Twig will use the default one: ``F j, Y H:i``. This
-default can be easily changed by calling the ``setDateFormat()`` method on the
-``core`` extension instance. The first argument is the default format for
-dates and the second one is the default format for date intervals:
-
-.. code-block:: php
-
- $twig = new Twig_Environment($loader);
- $twig->getExtension('core')->setDateFormat('d/m/Y', '%d days');
-
-Timezone
---------
-
-By default, the date is displayed by applying the default timezone (the one
-specified in php.ini or declared in Twig -- see below), but you can override
-it by explicitly specifying a timezone:
-
-.. code-block:: jinja
-
- {{ post.published_at|date("m/d/Y", "Europe/Paris") }}
-
-If the date is already a DateTime object, and if you want to keep its current
-timezone, pass ``false`` as the timezone value:
-
-.. code-block:: jinja
-
- {{ post.published_at|date("m/d/Y", false) }}
-
-The default timezone can also be set globally by calling ``setTimezone()``:
-
-.. code-block:: php
-
- $twig = new Twig_Environment($loader);
- $twig->getExtension('core')->setTimezone('Europe/Paris');
-
-Arguments
----------
-
- * ``format``: The date format
- * ``timezone``: The date timezone
-
-.. _`strtotime`: http://www.php.net/strtotime
-.. _`DateTime`: http://www.php.net/DateTime
-.. _`DateInterval`: http://www.php.net/DateInterval
+++ /dev/null
-``date_modify``
-===============
-
-.. versionadded:: 1.9.0
- The date_modify filter has been added in Twig 1.9.0.
-
-The ``date_modify`` filter modifies a date with a given modifier string:
-
-.. code-block:: jinja
-
- {{ post.published_at|date_modify("+1 day")|date("m/d/Y") }}
-
-The ``date_modify`` filter accepts strings (it must be in a format supported
-by the `strtotime`_ function) or `DateTime`_ instances. You can easily combine
-it with the :doc:`date<date>` filter for formatting.
-
-Arguments
----------
-
- * ``modifier``: The modifier
-
-.. _`strtotime`: http://www.php.net/strtotime
-.. _`DateTime`: http://www.php.net/DateTime
+++ /dev/null
-``default``
-===========
-
-The ``default`` filter returns the passed default value if the value is
-undefined or empty, otherwise the value of the variable:
-
-.. code-block:: jinja
-
- {{ var|default('var is not defined') }}
-
- {{ var.foo|default('foo item on var is not defined') }}
-
- {{ var['foo']|default('foo item on var is not defined') }}
-
- {{ ''|default('passed var is empty') }}
-
-When using the ``default`` filter on an expression that uses variables in some
-method calls, be sure to use the ``default`` filter whenever a variable can be
-undefined:
-
-.. code-block:: jinja
-
- {{ var.method(foo|default('foo'))|default('foo') }}
-
-.. note::
-
- Read the documentation for the :doc:`defined<../tests/defined>` and
- :doc:`empty<../tests/empty>` tests to learn more about their semantics.
-
-Arguments
----------
-
- * ``default``: The default value
+++ /dev/null
-``escape``
-==========
-
-.. versionadded:: 1.9.0
- The ``css``, ``url``, and ``html_attr`` strategies were added in Twig
- 1.9.0.
-
-The ``escape`` filter escapes a string for safe insertion into the final
-output. It supports different escaping strategies depending on the template
-context.
-
-By default, it uses the HTML escaping strategy:
-
-.. code-block:: jinja
-
- {{ user.username|escape }}
-
-For convenience, the ``e`` filter is defined as an alias:
-
-.. code-block:: jinja
-
- {{ user.username|e }}
-
-The ``escape`` filter can also be used in other contexts than HTML thanks to
-an optional argument which defines the escaping strategy to use:
-
-.. code-block:: jinja
-
- {{ user.username|e }}
- {# is equivalent to #}
- {{ user.username|e('html') }}
-
-And here is how to escape variables included in JavaScript code:
-
-.. code-block:: jinja
-
- {{ user.username|escape('js') }}
- {{ user.username|e('js') }}
-
-The ``escape`` filter supports the following escaping strategies:
-
-* ``html``: escapes a string for the **HTML body** context.
-
-* ``js``: escapes a string for the **JavaScript context**.
-
-* ``css``: escapes a string for the **CSS context**. CSS escaping can be
- applied to any string being inserted into CSS and escapes everything except
- alphanumerics.
-
-* ``url``: escapes a string for the **URI or parameter contexts**. This should
- not be used to escape an entire URI; only a subcomponent being inserted.
-
-* ``html_attr``: escapes a string for the **HTML attribute** context.
-
-.. note::
-
- Internally, ``escape`` uses the PHP native `htmlspecialchars`_ function
- for the HTML escaping strategy.
-
-.. caution::
-
- When using automatic escaping, Twig tries to not double-escape a variable
- when the automatic escaping strategy is the same as the one applied by the
- escape filter; but that does not work when using a variable as the
- escaping strategy:
-
- .. code-block:: jinja
-
- {% set strategy = 'html' %}
-
- {% autoescape 'html' %}
- {{ var|escape('html') }} {# won't be double-escaped #}
- {{ var|escape(strategy) }} {# will be double-escaped #}
- {% endautoescape %}
-
- When using a variable as the escaping strategy, you should disable
- automatic escaping:
-
- .. code-block:: jinja
-
- {% set strategy = 'html' %}
-
- {% autoescape 'html' %}
- {{ var|escape(strategy)|raw }} {# won't be double-escaped #}
- {% endautoescape %}
-
-Arguments
----------
-
- * ``strategy``: The escaping strategy
- * ``charset``: The string charset
-
-.. _`htmlspecialchars`: http://php.net/htmlspecialchars
+++ /dev/null
-``first``
-=========
-
-.. versionadded:: 1.12.2
- The first filter was added in Twig 1.12.2.
-
-The ``first`` filter returns the first "element" of a sequence, a mapping, or
-a string:
-
-.. code-block:: jinja
-
- {{ [1, 2, 3, 4]|first }}
- {# outputs 1 #}
-
- {{ { a: 1, b: 2, c: 3, d: 4 }|first }}
- {# outputs 1 #}
-
- {{ '1234'|first }}
- {# outputs 1 #}
-
-.. note::
-
- It also works with objects implementing the `Traversable`_ interface.
-
-.. _`Traversable`: http://php.net/manual/en/class.traversable.php
+++ /dev/null
-``format``
-==========
-
-The ``format`` filter formats a given string by replacing the placeholders
-(placeholders follows the `sprintf`_ notation):
-
-.. code-block:: jinja
-
- {{ "I like %s and %s."|format(foo, "bar") }}
-
- {# returns I like foo and bar
- if the foo parameter equals to the foo string. #}
-
-.. _`sprintf`: http://www.php.net/sprintf
-
-.. seealso:: :doc:`replace<replace>`
+++ /dev/null
-Filters
-=======
-
-.. toctree::
- :maxdepth: 1
-
- abs
- batch
- capitalize
- convert_encoding
- date
- date_modify
- default
- escape
- first
- format
- join
- json_encode
- keys
- last
- length
- lower
- nl2br
- number_format
- merge
- upper
- raw
- replace
- reverse
- slice
- sort
- split
- striptags
- title
- trim
- url_encode
+++ /dev/null
-``join``
-========
-
-The ``join`` filter returns a string which is the concatenation of the items
-of a sequence:
-
-.. code-block:: jinja
-
- {{ [1, 2, 3]|join }}
- {# returns 123 #}
-
-The separator between elements is an empty string per default, but you can
-define it with the optional first parameter:
-
-.. code-block:: jinja
-
- {{ [1, 2, 3]|join('|') }}
- {# returns 1|2|3 #}
-
-Arguments
----------
-
- * ``glue``: The separator
+++ /dev/null
-``json_encode``
-===============
-
-The ``json_encode`` filter returns the JSON representation of a string:
-
-.. code-block:: jinja
-
- {{ data|json_encode() }}
-
-.. note::
-
- Internally, Twig uses the PHP `json_encode`_ function.
-
-Arguments
----------
-
- * ``options``: A bitmask of `json_encode options`_ (``{{
- data|json_encode(constant(JSON_PRETTY_PRINT)) }}``)
-
-.. _`json_encode`: http://php.net/json_encode
-.. _`json_encode options`: http://www.php.net/manual/en/json.constants.php
+++ /dev/null
-``keys``
-========
-
-The ``keys`` filter returns the keys of an array. It is useful when you want to
-iterate over the keys of an array:
-
-.. code-block:: jinja
-
- {% for key in array|keys %}
- ...
- {% endfor %}
+++ /dev/null
-``last``
-========
-
-.. versionadded:: 1.12.2
- The last filter was added in Twig 1.12.2.
-
-The ``last`` filter returns the last "element" of a sequence, a mapping, or
-a string:
-
-.. code-block:: jinja
-
- {{ [1, 2, 3, 4]|last }}
- {# outputs 4 #}
-
- {{ { a: 1, b: 2, c: 3, d: 4 }|last }}
- {# outputs 4 #}
-
- {{ '1234'|last }}
- {# outputs 4 #}
-
-.. note::
-
- It also works with objects implementing the `Traversable`_ interface.
-
-.. _`Traversable`: http://php.net/manual/en/class.traversable.php
+++ /dev/null
-``length``
-==========
-
-The ``length`` filters returns the number of items of a sequence or mapping, or
-the length of a string:
-
-.. code-block:: jinja
-
- {% if users|length > 10 %}
- ...
- {% endif %}
-
+++ /dev/null
-``lower``
-=========
-
-The ``lower`` filter converts a value to lowercase:
-
-.. code-block:: jinja
-
- {{ 'WELCOME'|lower }}
-
- {# outputs 'welcome' #}
+++ /dev/null
-``merge``
-=========
-
-The ``merge`` filter merges an array with another array:
-
-.. code-block:: jinja
-
- {% set values = [1, 2] %}
-
- {% set values = values|merge(['apple', 'orange']) %}
-
- {# values now contains [1, 2, 'apple', 'orange'] #}
-
-New values are added at the end of the existing ones.
-
-The ``merge`` filter also works on hashes:
-
-.. code-block:: jinja
-
- {% set items = { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'unknown' } %}
-
- {% set items = items|merge({ 'peugeot': 'car', 'renault': 'car' }) %}
-
- {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car', 'renault': 'car' } #}
-
-For hashes, the merging process occurs on the keys: if the key does not
-already exist, it is added but if the key already exists, its value is
-overridden.
-
-.. tip::
-
- If you want to ensure that some values are defined in an array (by given
- default values), reverse the two elements in the call:
-
- .. code-block:: jinja
-
- {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
-
- {% set items = { 'apple': 'unknown' }|merge(items) %}
-
- {# items now contains { 'apple': 'fruit', 'orange': 'fruit' } #}
+++ /dev/null
-``nl2br``
-=========
-
-.. versionadded:: 1.5
- The nl2br filter was added in Twig 1.5.
-
-The ``nl2br`` filter inserts HTML line breaks before all newlines in a string:
-
-.. code-block:: jinja
-
- {{ "I like Twig.\nYou will like it too."|nl2br }}
- {# outputs
-
- I like Twig.<br />
- You will like it too.
-
- #}
-
-.. note::
-
- The ``nl2br`` filter pre-escapes the input before applying the
- transformation.
+++ /dev/null
-``number_format``
-=================
-
-.. versionadded:: 1.5
- The number_format filter was added in Twig 1.5
-
-The ``number_format`` filter formats numbers. It is a wrapper around PHP's
-`number_format`_ function:
-
-.. code-block:: jinja
-
- {{ 200.35|number_format }}
-
-You can control the number of decimal places, decimal point, and thousands
-separator using the additional arguments:
-
-.. code-block:: jinja
-
- {{ 9800.333|number_format(2, '.', ',') }}
-
-If no formatting options are provided then Twig will use the default formatting
-options of:
-
-- 0 decimal places.
-- ``.`` as the decimal point.
-- ``,`` as the thousands separator.
-
-These defaults can be easily changed through the core extension:
-
-.. code-block:: php
-
- $twig = new Twig_Environment($loader);
- $twig->getExtension('core')->setNumberFormat(3, '.', ',');
-
-The defaults set for ``number_format`` can be over-ridden upon each call using the
-additional parameters.
-
-Arguments
----------
-
- * ``decimal``: The number of decimal points to display
- * ``decimal_point``: The character(s) to use for the decimal point
- * ``decimal_sep``: The character(s) to use for the thousands separator
-
-.. _`number_format`: http://php.net/number_format
+++ /dev/null
-``raw``
-=======
-
-The ``raw`` filter marks the value as being "safe", which means that in an
-environment with automatic escaping enabled this variable will not be escaped
-if ``raw`` is the last filter applied to it:
-
-.. code-block:: jinja
-
- {% autoescape true %}
- {{ var|raw }} {# var won't be escaped #}
- {% endautoescape %}
+++ /dev/null
-``replace``
-===========
-
-The ``replace`` filter formats a given string by replacing the placeholders
-(placeholders are free-form):
-
-.. code-block:: jinja
-
- {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }}
-
- {# returns I like foo and bar
- if the foo parameter equals to the foo string. #}
-
-Arguments
----------
-
- * ``replace_pairs``: The placeholder values
-
-.. seealso:: :doc:`format<format>`
+++ /dev/null
-``reverse``
-===========
-
-.. versionadded:: 1.6
- Support for strings has been added in Twig 1.6.
-
-The ``reverse`` filter reverses a sequence, a mapping, or a string:
-
-.. code-block:: jinja
-
- {% for user in users|reverse %}
- ...
- {% endfor %}
-
- {{ '1234'|reverse }}
-
- {# outputs 4321 #}
-
-.. tip::
-
- For sequences and mappings, numeric keys are not preserved. To reverse
- them as well, pass ``true`` as an argument to the ``reverse`` filter:
-
- .. code-block:: jinja
-
- {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse %}
- {{ key }}: {{ value }}
- {%- endfor %}
-
- {# output: 0: c 1: b 2: a #}
-
- {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse(true) %}
- {{ key }}: {{ value }}
- {%- endfor %}
-
- {# output: 3: c 2: b 1: a #}
-
-.. note::
-
- It also works with objects implementing the `Traversable`_ interface.
-
-Arguments
----------
-
- * ``preserve_keys``: Preserve keys when reversing a mapping or a sequence.
-
-.. _`Traversable`: http://php.net/Traversable
+++ /dev/null
-``slice``
-===========
-
-.. versionadded:: 1.6
- The slice filter was added in Twig 1.6.
-
-The ``slice`` filter extracts a slice of a sequence, a mapping, or a string:
-
-.. code-block:: jinja
-
- {% for i in [1, 2, 3, 4, 5]|slice(1, 2) %}
- {# will iterate over 2 and 3 #}
- {% endfor %}
-
- {{ '12345'|slice(1, 2) }}
-
- {# outputs 23 #}
-
-You can use any valid expression for both the start and the length:
-
-.. code-block:: jinja
-
- {% for i in [1, 2, 3, 4, 5]|slice(start, length) %}
- {# ... #}
- {% endfor %}
-
-As syntactic sugar, you can also use the ``[]`` notation:
-
-.. code-block:: jinja
-
- {% for i in [1, 2, 3, 4, 5][start:length] %}
- {# ... #}
- {% endfor %}
-
- {{ '12345'[1:2] }}
-
- {# you can omit the first argument -- which is the same as 0 #}
- {{ '12345'[:2] }} {# will display "12" #}
-
- {# you can omit the last argument -- which will select everything till the end #}
- {{ '12345'[2:] }} {# will display "345" #}
-
-The ``slice`` filter works as the `array_slice`_ PHP function for arrays and
-`substr`_ for strings.
-
-If the start is non-negative, the sequence will start at that start in the
-variable. If start is negative, the sequence will start that far from the end
-of the variable.
-
-If length is given and is positive, then the sequence will have up to that
-many elements in it. If the variable is shorter than the length, then only the
-available variable elements will be present. If length is given and is
-negative then the sequence will stop that many elements from the end of the
-variable. If it is omitted, then the sequence will have everything from offset
-up until the end of the variable.
-
-.. note::
-
- It also works with objects implementing the `Traversable`_ interface.
-
-Arguments
----------
-
- * ``start``: The start of the slice
- * ``length``: The size of the slice
- * ``preserve_keys``: Whether to preserve key or not (when the input is an array)
-
-.. _`Traversable`: http://php.net/manual/en/class.traversable.php
-.. _`array_slice`: http://php.net/array_slice
-.. _`substr`: http://php.net/substr
+++ /dev/null
-``sort``
-========
-
-The ``sort`` filter sorts an array:
-
-.. code-block:: jinja
-
- {% for user in users|sort %}
- ...
- {% endfor %}
-
-.. note::
-
- Internally, Twig uses the PHP `asort`_ function to maintain index
- association.
-
-.. _`asort`: http://php.net/asort
+++ /dev/null
-``split``
-=========
-
-.. versionadded:: 1.10.3
- The split filter was added in Twig 1.10.3.
-
-The ``split`` filter splits a string by the given delimiter and returns a list
-of strings:
-
-.. code-block:: jinja
-
- {{ "one,two,three"|split(',') }}
- {# returns ['one', 'two', 'three'] #}
-
-You can also pass a ``limit`` argument:
-
- * If ``limit`` is positive, the returned array will contain a maximum of
- limit elements with the last element containing the rest of string;
-
- * If ``limit`` is negative, all components except the last -limit are
- returned;
-
- * If ``limit`` is zero, then this is treated as 1.
-
-.. code-block:: jinja
-
- {{ "one,two,three,four,five"|split(',', 3) }}
- {# returns ['one', 'two', 'three,four,five'] #}
-
-If the ``delimiter`` is an empty string, then value will be split by equal
-chunks. Length is set by the ``limit`` argument (one character by default).
-
-.. code-block:: jinja
-
- {{ "123"|split('') }}
- {# returns ['1', '2', '3'] #}
-
- {{ "aabbcc"|split('', 2) }}
- {# returns ['aa', 'bb', 'cc'] #}
-
-.. note::
-
- Internally, Twig uses the PHP `explode`_ or `str_split`_ (if delimiter is
- empty) functions for string splitting.
-
-Arguments
----------
-
- * ``delimiter``: The delimiter
- * ``limit``: The limit argument
-
-.. _`explode`: http://php.net/explode
-.. _`str_split`: http://php.net/str_split
+++ /dev/null
-``striptags``
-=============
-
-The ``striptags`` filter strips SGML/XML tags and replace adjacent whitespace
-by one space:
-
-.. code-block:: jinja
-
- {{ some_html|striptags }}
-
-.. note::
-
- Internally, Twig uses the PHP `strip_tags`_ function.
-
-.. _`strip_tags`: http://php.net/strip_tags
+++ /dev/null
-``title``
-=========
-
-The ``title`` filter returns a titlecased version of the value. Words will
-start with uppercase letters, all remaining characters are lowercase:
-
-.. code-block:: jinja
-
- {{ 'my first car'|title }}
-
- {# outputs 'My First Car' #}
+++ /dev/null
-``trim``
-========
-
-.. versionadded:: 1.6.2
- The trim filter was added in Twig 1.6.2.
-
-The ``trim`` filter strips whitespace (or other characters) from the beginning
-and end of a string:
-
-.. code-block:: jinja
-
- {{ ' I like Twig. '|trim }}
-
- {# outputs 'I like Twig.' #}
-
- {{ ' I like Twig.'|trim('.') }}
-
- {# outputs ' I like Twig' #}
-
-.. note::
-
- Internally, Twig uses the PHP `trim`_ function.
-
-Arguments
----------
-
- * ``character_mask``: The characters to strip
-
-.. _`trim`: http://php.net/trim
+++ /dev/null
-``upper``
-=========
-
-The ``upper`` filter converts a value to uppercase:
-
-.. code-block:: jinja
-
- {{ 'welcome'|upper }}
-
- {# outputs 'WELCOME' #}
+++ /dev/null
-``url_encode``
-==============
-
-.. versionadded:: 1.12.3
- Support for encoding an array as query string was added in Twig 1.12.3.
-
-The ``url_encode`` filter percent encodes a given string as URL segment
-or an array as query string:
-
-.. code-block:: jinja
-
- {{ "path-seg*ment"|url_encode }}
- {# outputs "path-seg%2Ament" #}
-
- {{ "string with spaces"|url_encode(true) }}
- {# outputs "string%20with%20spaces" #}
-
- {{ {'param': 'value', 'foo': 'bar'}|url_encode }}
- {# outputs "param=value&foo=bar" #}
-
-.. note::
-
- Internally, Twig uses the PHP `urlencode`_ (or `rawurlencode`_ if you pass
- ``true`` as the first parameter) or the `http_build_query`_ function.
-
-.. _`urlencode`: http://php.net/urlencode
-.. _`rawurlencode`: http://php.net/rawurlencode
-.. _`http_build_query`: http://php.net/http_build_query
+++ /dev/null
-``attribute``
-=============
-
-.. versionadded:: 1.2
- The ``attribute`` function was added in Twig 1.2.
-
-``attribute`` can be used to access a "dynamic" attribute of a variable:
-
-.. code-block:: jinja
-
- {{ attribute(object, method) }}
- {{ attribute(object, method, arguments) }}
- {{ attribute(array, item) }}
-
-.. note::
-
- The resolution algorithm is the same as the one used for the ``.``
- notation, except that the item can be any valid expression.
+++ /dev/null
-``block``
-=========
-
-When a template uses inheritance and if you want to print a block multiple
-times, use the ``block`` function:
-
-.. code-block:: jinja
-
- <title>{% block title %}{% endblock %}</title>
-
- <h1>{{ block('title') }}</h1>
-
- {% block body %}{% endblock %}
-
-.. seealso:: :doc:`extends<../tags/extends>`, :doc:`parent<../functions/parent>`
+++ /dev/null
-``constant``
-============
-
-.. versionadded: 1.12.1
- constant now accepts object instances as the second argument.
-
-``constant`` returns the constant value for a given string:
-
-.. code-block:: jinja
-
- {{ some_date|date(constant('DATE_W3C')) }}
- {{ constant('Namespace\\Classname::CONSTANT_NAME') }}
-
-As of 1.12.1 you can read constants from object instances as well:
-
-.. code-block:: jinja
-
- {{ constant('RSS', date) }}
+++ /dev/null
-``cycle``
-=========
-
-The ``cycle`` function cycles on an array of values:
-
-.. code-block:: jinja
-
- {% for i in 0..10 %}
- {{ cycle(['odd', 'even'], i) }}
- {% endfor %}
-
-The array can contain any number of values:
-
-.. code-block:: jinja
-
- {% set fruits = ['apple', 'orange', 'citrus'] %}
-
- {% for i in 0..10 %}
- {{ cycle(fruits, i) }}
- {% endfor %}
-
-Arguments
----------
-
- * ``position``: The cycle position
+++ /dev/null
-``date``
-========
-
-.. versionadded:: 1.6
- The date function has been added in Twig 1.6.
-
-.. versionadded:: 1.6.1
- The default timezone support has been added in Twig 1.6.1.
-
-Converts an argument to a date to allow date comparison:
-
-.. code-block:: jinja
-
- {% if date(user.created_at) < date('-2days') %}
- {# do something #}
- {% endif %}
-
-The argument must be in a format supported by the `date`_ function.
-
-You can pass a timezone as the second argument:
-
-.. code-block:: jinja
-
- {% if date(user.created_at) < date('-2days', 'Europe/Paris') %}
- {# do something #}
- {% endif %}
-
-If no argument is passed, the function returns the current date:
-
-.. code-block:: jinja
-
- {% if date(user.created_at) < date() %}
- {# always! #}
- {% endif %}
-
-.. note::
-
- You can set the default timezone globally by calling ``setTimezone()`` on
- the ``core`` extension instance:
-
- .. code-block:: php
-
- $twig = new Twig_Environment($loader);
- $twig->getExtension('core')->setTimezone('Europe/Paris');
-
-Arguments
----------
-
- * ``date``: The date
- * ``timezone``: The timezone
-
-.. _`date`: http://www.php.net/date
+++ /dev/null
-``dump``
-========
-
-.. versionadded:: 1.5
- The dump function was added in Twig 1.5.
-
-The ``dump`` function dumps information about a template variable. This is
-mostly useful to debug a template that does not behave as expected by
-introspecting its variables:
-
-.. code-block:: jinja
-
- {{ dump(user) }}
-
-.. note::
-
- The ``dump`` function is not available by default. You must add the
- ``Twig_Extension_Debug`` extension explicitly when creating your Twig
- environment::
-
- $twig = new Twig_Environment($loader, array(
- 'debug' => true,
- // ...
- ));
- $twig->addExtension(new Twig_Extension_Debug());
-
- Even when enabled, the ``dump`` function won't display anything if the
- ``debug`` option on the environment is not enabled (to avoid leaking debug
- information on a production server).
-
-In an HTML context, wrap the output with a ``pre`` tag to make it easier to
-read:
-
-.. code-block:: jinja
-
- <pre>
- {{ dump(user) }}
- </pre>
-
-.. tip::
-
- Using a ``pre`` tag is not needed when `XDebug`_ is enabled and
- ``html_errors`` is ``on``; as a bonus, the output is also nicer with
- XDebug enabled.
-
-You can debug several variables by passing them as additional arguments:
-
-.. code-block:: jinja
-
- {{ dump(user, categories) }}
-
-If you don't pass any value, all variables from the current context are
-dumped:
-
-.. code-block:: jinja
-
- {{ dump() }}
-
-.. note::
-
- Internally, Twig uses the PHP `var_dump`_ function.
-
-Arguments
----------
-
- * ``context``: The context to dump
-
-.. _`XDebug`: http://xdebug.org/docs/display
-.. _`var_dump`: http://php.net/var_dump
+++ /dev/null
-``include``
-===========
-
-.. versionadded:: 1.12
- The include function was added in Twig 1.12.
-
-The ``include`` function returns the rendered content of a template:
-
-.. code-block:: jinja
-
- {{ include('template.html') }}
- {{ include(some_var) }}
-
-Included templates have access to the variables of the active context.
-
-If you are using the filesystem loader, the templates are looked for in the
-paths defined by it.
-
-The context is passed by default to the template but you can also pass
-additional variables:
-
-.. code-block:: jinja
-
- {# template.html will have access to the variables from the current context and the additional ones provided #}
- {{ include('template.html', {foo: 'bar'}) }}
-
-You can disable access to the context by setting ``with_context`` to
-``false``:
-
-.. code-block:: jinja
-
- {# only the foo variable will be accessible #}
- {{ include('template.html', {foo: 'bar'}, with_context = false) }}
-
-.. code-block:: jinja
-
- {# no variables will be accessible #}
- {{ include('template.html', with_context = false) }}
-
-And if the expression evaluates to a ``Twig_Template`` object, Twig will use it
-directly::
-
- // {{ include(template) }}
-
- $template = $twig->loadTemplate('some_template.twig');
-
- $twig->loadTemplate('template.twig')->display(array('template' => $template));
-
-When you set the ``ignore_missing`` flag, Twig will return an empty string if
-the template does not exist:
-
-.. code-block:: jinja
-
- {{ include('sidebar.html', ignore_missing = true) }}
-
-You can also provide a list of templates that are checked for existence before
-inclusion. The first template that exists will be rendered:
-
-.. code-block:: jinja
-
- {{ include(['page_detailed.html', 'page.html']) }}
-
-If ``ignore_missing`` is set, it will fall back to rendering nothing if none
-of the templates exist, otherwise it will throw an exception.
-
-When including a template created by an end user, you should consider
-sandboxing it:
-
-.. code-block:: jinja
-
- {{ include('page.html', sandboxed = true) }}
-
-Arguments
----------
-
- * ``template``: The template to render
- * ``variables``: The variables to pass to the template
- * ``with_context``: Whether to pass the current context variables or not
- * ``ignore_missing``: Whether to ignore missing templates or not
- * ``sandboxed``: Whether to sandbox the template or not
+++ /dev/null
-Functions
-=========
-
-.. toctree::
- :maxdepth: 1
-
- attribute
- block
- constant
- cycle
- date
- dump
- include
- parent
- random
- range
- template_from_string
+++ /dev/null
-``parent``
-==========
-
-When a template uses inheritance, it's possible to render the contents of the
-parent block when overriding a block by using the ``parent`` function:
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% block sidebar %}
- <h3>Table Of Contents</h3>
- ...
- {{ parent() }}
- {% endblock %}
-
-The ``parent()`` call will return the content of the ``sidebar`` block as
-defined in the ``base.html`` template.
-
-.. seealso:: :doc:`extends<../tags/extends>`, :doc:`block<../functions/block>`, :doc:`block<../tags/block>`
+++ /dev/null
-``random``
-==========
-
-.. versionadded:: 1.5
- The random function was added in Twig 1.5.
-
-.. versionadded:: 1.6
- String and integer handling was added in Twig 1.6.
-
-The ``random`` function returns a random value depending on the supplied
-parameter type:
-
-* a random item from a sequence;
-* a random character from a string;
-* a random integer between 0 and the integer parameter (inclusive).
-
-.. code-block:: jinja
-
- {{ random(['apple', 'orange', 'citrus']) }} {# example output: orange #}
- {{ random('ABC') }} {# example output: C #}
- {{ random() }} {# example output: 15386094 (works as native PHP `mt_rand`_ function) #}
- {{ random(5) }} {# example output: 3 #}
-
-Arguments
----------
-
- * ``values``: The values
-
-.. _`mt_rand`: http://php.net/mt_rand
+++ /dev/null
-``range``
-=========
-
-Returns a list containing an arithmetic progression of integers:
-
-.. code-block:: jinja
-
- {% for i in range(0, 3) %}
- {{ i }},
- {% endfor %}
-
- {# returns 0, 1, 2, 3 #}
-
-When step is given (as the third parameter), it specifies the increment (or
-decrement):
-
-.. code-block:: jinja
-
- {% for i in range(0, 6, 2) %}
- {{ i }},
- {% endfor %}
-
- {# returns 0, 2, 4, 6 #}
-
-The Twig built-in ``..`` operator is just syntactic sugar for the ``range``
-function (with a step of 1):
-
-.. code-block:: jinja
-
- {% for i in 0..3 %}
- {{ i }},
- {% endfor %}
-
-.. tip::
-
- The ``range`` function works as the native PHP `range`_ function.
-
-Arguments
----------
-
- * ``low``: The first value of the sequence.
- * ``high``: The highest possible value of the sequence.
- * ``step``: The increment between elements of the sequence.
-
-.. _`range`: http://php.net/range
+++ /dev/null
-``template_from_string``
-========================
-
-.. versionadded:: 1.11
- The template_from_string function was added in Twig 1.11.
-
-The ``template_from_string`` function loads a template from a string:
-
-.. code-block:: jinja
-
- {{ include(template_from_string("Hello {{ name }}") }}
- {{ include(template_from_string(page.template)) }}
-
-.. note::
-
- The ``template_from_string`` function is not available by default. You
- must add the ``Twig_Extension_StringLoader`` extension explicitly when
- creating your Twig environment::
-
- $twig = new Twig_Environment(...);
- $twig->addExtension(new Twig_Extension_StringLoader());
-
-.. note::
-
- Even if you will probably always use the ``template_from_string`` function
- with the ``include`` function, you can use it with any tag or function that
- takes a template as an argument (like the ``embed`` or ``extends`` tags).
-
-Arguments
----------
-
- * ``template``: The template
+++ /dev/null
-Twig
-====
-
-.. toctree::
- :maxdepth: 2
-
- intro
- templates
- api
- advanced
- internals
- recipes
- coding_standards
- tags/index
- filters/index
- functions/index
- tests/index
- deprecated
+++ /dev/null
-Twig Internals
-==============
-
-Twig is very extensible and you can easily hack it. Keep in mind that you
-should probably try to create an extension before hacking the core, as most
-features and enhancements can be done with extensions. This chapter is also
-useful for people who want to understand how Twig works under the hood.
-
-How Twig works?
----------------
-
-The rendering of a Twig template can be summarized into four key steps:
-
-* **Load** the template: If the template is already compiled, load it and go
- to the *evaluation* step, otherwise:
-
- * First, the **lexer** tokenizes the template source code into small pieces
- for easier processing;
- * Then, the **parser** converts the token stream into a meaningful tree
- of nodes (the Abstract Syntax Tree);
- * Eventually, the *compiler* transforms the AST into PHP code;
-
-* **Evaluate** the template: It basically means calling the ``display()``
- method of the compiled template and passing it the context.
-
-The Lexer
----------
-
-The lexer tokenizes a template source code into a token stream (each token is
-an instance of ``Twig_Token``, and the stream is an instance of
-``Twig_TokenStream``). The default lexer recognizes 13 different token types:
-
-* ``Twig_Token::BLOCK_START_TYPE``, ``Twig_Token::BLOCK_END_TYPE``: Delimiters for blocks (``{% %}``)
-* ``Twig_Token::VAR_START_TYPE``, ``Twig_Token::VAR_END_TYPE``: Delimiters for variables (``{{ }}``)
-* ``Twig_Token::TEXT_TYPE``: A text outside an expression;
-* ``Twig_Token::NAME_TYPE``: A name in an expression;
-* ``Twig_Token::NUMBER_TYPE``: A number in an expression;
-* ``Twig_Token::STRING_TYPE``: A string in an expression;
-* ``Twig_Token::OPERATOR_TYPE``: An operator;
-* ``Twig_Token::PUNCTUATION_TYPE``: A punctuation sign;
-* ``Twig_Token::INTERPOLATION_START_TYPE``, ``Twig_Token::INTERPOLATION_END_TYPE`` (as of Twig 1.5): Delimiters for string interpolation;
-* ``Twig_Token::EOF_TYPE``: Ends of template.
-
-You can manually convert a source code into a token stream by calling the
-``tokenize()`` of an environment::
-
- $stream = $twig->tokenize($source, $identifier);
-
-As the stream has a ``__toString()`` method, you can have a textual
-representation of it by echoing the object::
-
- echo $stream."\n";
-
-Here is the output for the ``Hello {{ name }}`` template:
-
-.. code-block:: text
-
- TEXT_TYPE(Hello )
- VAR_START_TYPE()
- NAME_TYPE(name)
- VAR_END_TYPE()
- EOF_TYPE()
-
-.. note::
-
- You can change the default lexer use by Twig (``Twig_Lexer``) by calling
- the ``setLexer()`` method::
-
- $twig->setLexer($lexer);
-
-The Parser
-----------
-
-The parser converts the token stream into an AST (Abstract Syntax Tree), or a
-node tree (an instance of ``Twig_Node_Module``). The core extension defines
-the basic nodes like: ``for``, ``if``, ... and the expression nodes.
-
-You can manually convert a token stream into a node tree by calling the
-``parse()`` method of an environment::
-
- $nodes = $twig->parse($stream);
-
-Echoing the node object gives you a nice representation of the tree::
-
- echo $nodes."\n";
-
-Here is the output for the ``Hello {{ name }}`` template:
-
-.. code-block:: text
-
- Twig_Node_Module(
- Twig_Node_Text(Hello )
- Twig_Node_Print(
- Twig_Node_Expression_Name(name)
- )
- )
-
-.. note::
-
- The default parser (``Twig_TokenParser``) can be also changed by calling the
- ``setParser()`` method::
-
- $twig->setParser($parser);
-
-The Compiler
-------------
-
-The last step is done by the compiler. It takes a node tree as an input and
-generates PHP code usable for runtime execution of the template.
-
-You can call the compiler by hand with the ``compile()`` method of an
-environment::
-
- $php = $twig->compile($nodes);
-
-The ``compile()`` method returns the PHP source code representing the node.
-
-The generated template for a ``Hello {{ name }}`` template reads as follows
-(the actual output can differ depending on the version of Twig you are
-using)::
-
- /* Hello {{ name }} */
- class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template
- {
- protected function doDisplay(array $context, array $blocks = array())
- {
- // line 1
- echo "Hello ";
- echo twig_escape_filter($this->env, $this->getContext($context, "name"), "ndex", null, true);
- }
-
- // some more code
- }
-
-.. note::
-
- As for the lexer and the parser, the default compiler (``Twig_Compiler``) can
- be changed by calling the ``setCompiler()`` method::
-
- $twig->setCompiler($compiler);
+++ /dev/null
-Introduction
-============
-
-This is the documentation for Twig, the flexible, fast, and secure template
-engine for PHP.
-
-If you have any exposure to other text-based template languages, such as
-Smarty, Django, or Jinja, you should feel right at home with Twig. It's both
-designer and developer friendly by sticking to PHP's principles and adding
-functionality useful for templating environments.
-
-The key-features are...
-
-* *Fast*: Twig compiles templates down to plain optimized PHP code. The
- overhead compared to regular PHP code was reduced to the very minimum.
-
-* *Secure*: Twig has a sandbox mode to evaluate untrusted template code. This
- allows Twig to be used as a template language for applications where users
- may modify the template design.
-
-* *Flexible*: Twig is powered by a flexible lexer and parser. This allows the
- developer to define its own custom tags and filters, and create its own DSL.
-
-Prerequisites
--------------
-
-Twig needs at least **PHP 5.2.4** to run.
-
-Installation
-------------
-
-You have multiple ways to install Twig.
-
-Installing via Composer (recommended)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Install composer in your project:
-
-.. code-block:: bash
-
- curl -s http://getcomposer.org/installer | php
-
-2. Create a ``composer.json`` file in your project root:
-
-.. code-block:: javascript
-
- {
- "require": {
- "twig/twig": "1.*"
- }
- }
-
-3. Install via composer
-
-.. code-block:: bash
-
- php composer.phar install
-
-.. note::
- If you want to learn more about Composer, the ``composer.json`` file syntax
- and its usage, you can read the `online documentation`_.
-
-Installing from the tarball release
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Download the most recent tarball from the `download page`_
-2. Unpack the tarball
-3. Move the files somewhere in your project
-
-Installing the development version
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Install Git
-2. ``git clone git://github.com/fabpot/Twig.git``
-
-Installing the PEAR package
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Install PEAR
-2. ``pear channel-discover pear.twig-project.org``
-3. ``pear install twig/Twig`` (or ``pear install twig/Twig-beta``)
-
-
-Installing the C extension
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. versionadded:: 1.4
- The C extension was added in Twig 1.4.
-
-Twig comes with a C extension that enhances the performance of the Twig
-runtime engine. You can install it like any other PHP extension:
-
-.. code-block:: bash
-
- $ cd ext/twig
- $ phpize
- $ ./configure
- $ make
- $ make install
-
-Finally, enable the extension in your ``php.ini`` configuration file:
-
-.. code-block:: ini
-
- extension=twig.so
-
-And from now on, Twig will automatically compile your templates to take
-advantage of the C extension. Note that this extension does not replace the
-PHP code but only provides an optimized version of the
-``Twig_Template::getAttribute()`` method.
-
-.. tip::
-
- On Windows, you can also simply download and install a `pre-built DLL`_.
-
-Basic API Usage
----------------
-
-This section gives you a brief introduction to the PHP API for Twig.
-
-The first step to use Twig is to register its autoloader::
-
- require_once '/path/to/lib/Twig/Autoloader.php';
- Twig_Autoloader::register();
-
-Replace the ``/path/to/lib/`` path with the path you used for Twig
-installation.
-
-If you have installed Twig via Composer you can take advantage of Composer's
-autoload mechanism by replacing the previous snippet for::
-
- require_once '/path/to/vendor/autoload.php';
-
-.. note::
-
- Twig follows the PEAR convention names for its classes, which means you
- can easily integrate Twig classes loading in your own autoloader.
-
-.. code-block:: php
-
- $loader = new Twig_Loader_String();
- $twig = new Twig_Environment($loader);
-
- echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
-
-Twig uses a loader (``Twig_Loader_String``) to locate templates, and an
-environment (``Twig_Environment``) to store the configuration.
-
-The ``render()`` method loads the template passed as a first argument and
-renders it with the variables passed as a second argument.
-
-As templates are generally stored on the filesystem, Twig also comes with a
-filesystem loader::
-
- $loader = new Twig_Loader_Filesystem('/path/to/templates');
- $twig = new Twig_Environment($loader, array(
- 'cache' => '/path/to/compilation_cache',
- ));
-
- echo $twig->render('index.html', array('name' => 'Fabien'));
-
-.. _`download page`: https://github.com/fabpot/Twig/tags
-.. _`online documentation`: http://getcomposer.org/doc
-.. _`pre-built DLL`: https://github.com/stealth35/stealth35.github.com/downloads
+++ /dev/null
-Recipes
-=======
-
-Making a Layout conditional
----------------------------
-
-Working with Ajax means that the same content is sometimes displayed as is,
-and sometimes decorated with a layout. As Twig layout template names can be
-any valid expression, you can pass a variable that evaluates to ``true`` when
-the request is made via Ajax and choose the layout accordingly:
-
-.. code-block:: jinja
-
- {% extends request.ajax ? "base_ajax.html" : "base.html" %}
-
- {% block content %}
- This is the content to be displayed.
- {% endblock %}
-
-Making an Include dynamic
--------------------------
-
-When including a template, its name does not need to be a string. For
-instance, the name can depend on the value of a variable:
-
-.. code-block:: jinja
-
- {% include var ~ '_foo.html' %}
-
-If ``var`` evaluates to ``index``, the ``index_foo.html`` template will be
-rendered.
-
-As a matter of fact, the template name can be any valid expression, such as
-the following:
-
-.. code-block:: jinja
-
- {% include var|default('index') ~ '_foo.html' %}
-
-Overriding a Template that also extends itself
-----------------------------------------------
-
-A template can be customized in two different ways:
-
-* *Inheritance*: A template *extends* a parent template and overrides some
- blocks;
-
-* *Replacement*: If you use the filesystem loader, Twig loads the first
- template it finds in a list of configured directories; a template found in a
- directory *replaces* another one from a directory further in the list.
-
-But how do you combine both: *replace* a template that also extends itself
-(aka a template in a directory further in the list)?
-
-Let's say that your templates are loaded from both ``.../templates/mysite``
-and ``.../templates/default`` in this order. The ``page.twig`` template,
-stored in ``.../templates/default`` reads as follows:
-
-.. code-block:: jinja
-
- {# page.twig #}
- {% extends "layout.twig" %}
-
- {% block content %}
- {% endblock %}
-
-You can replace this template by putting a file with the same name in
-``.../templates/mysite``. And if you want to extend the original template, you
-might be tempted to write the following:
-
-.. code-block:: jinja
-
- {# page.twig in .../templates/mysite #}
- {% extends "page.twig" %} {# from .../templates/default #}
-
-Of course, this will not work as Twig will always load the template from
-``.../templates/mysite``.
-
-It turns out it is possible to get this to work, by adding a directory right
-at the end of your template directories, which is the parent of all of the
-other directories: ``.../templates`` in our case. This has the effect of
-making every template file within our system uniquely addressable. Most of the
-time you will use the "normal" paths, but in the special case of wanting to
-extend a template with an overriding version of itself we can reference its
-parent's full, unambiguous template path in the extends tag:
-
-.. code-block:: jinja
-
- {# page.twig in .../templates/mysite #}
- {% extends "default/page.twig" %} {# from .../templates #}
-
-.. note::
-
- This recipe was inspired by the following Django wiki page:
- http://code.djangoproject.com/wiki/ExtendingTemplates
-
-Customizing the Syntax
-----------------------
-
-Twig allows some syntax customization for the block delimiters. It's not
-recommended to use this feature as templates will be tied with your custom
-syntax. But for specific projects, it can make sense to change the defaults.
-
-To change the block delimiters, you need to create your own lexer object::
-
- $twig = new Twig_Environment();
-
- $lexer = new Twig_Lexer($twig, array(
- 'tag_comment' => array('{#', '#}'),
- 'tag_block' => array('{%', '%}'),
- 'tag_variable' => array('{{', '}}'),
- 'interpolation' => array('#{', '}'),
- ));
- $twig->setLexer($lexer);
-
-Here are some configuration example that simulates some other template engines
-syntax::
-
- // Ruby erb syntax
- $lexer = new Twig_Lexer($twig, array(
- 'tag_comment' => array('<%#', '%>'),
- 'tag_block' => array('<%', '%>'),
- 'tag_variable' => array('<%=', '%>'),
- ));
-
- // SGML Comment Syntax
- $lexer = new Twig_Lexer($twig, array(
- 'tag_comment' => array('<!--#', '-->'),
- 'tag_block' => array('<!--', '-->'),
- 'tag_variable' => array('${', '}'),
- ));
-
- // Smarty like
- $lexer = new Twig_Lexer($twig, array(
- 'tag_comment' => array('{*', '*}'),
- 'tag_block' => array('{', '}'),
- 'tag_variable' => array('{$', '}'),
- ));
-
-Using dynamic Object Properties
--------------------------------
-
-When Twig encounters a variable like ``article.title``, it tries to find a
-``title`` public property in the ``article`` object.
-
-It also works if the property does not exist but is rather defined dynamically
-thanks to the magic ``__get()`` method; you just need to also implement the
-``__isset()`` magic method like shown in the following snippet of code::
-
- class Article
- {
- public function __get($name)
- {
- if ('title' == $name) {
- return 'The title';
- }
-
- // throw some kind of error
- }
-
- public function __isset($name)
- {
- if ('title' == $name) {
- return true;
- }
-
- return false;
- }
- }
-
-Accessing the parent Context in Nested Loops
---------------------------------------------
-
-Sometimes, when using nested loops, you need to access the parent context. The
-parent context is always accessible via the ``loop.parent`` variable. For
-instance, if you have the following template data::
-
- $data = array(
- 'topics' => array(
- 'topic1' => array('Message 1 of topic 1', 'Message 2 of topic 1'),
- 'topic2' => array('Message 1 of topic 2', 'Message 2 of topic 2'),
- ),
- );
-
-And the following template to display all messages in all topics:
-
-.. code-block:: jinja
-
- {% for topic, messages in topics %}
- * {{ loop.index }}: {{ topic }}
- {% for message in messages %}
- - {{ loop.parent.loop.index }}.{{ loop.index }}: {{ message }}
- {% endfor %}
- {% endfor %}
-
-The output will be similar to:
-
-.. code-block:: text
-
- * 1: topic1
- - 1.1: The message 1 of topic 1
- - 1.2: The message 2 of topic 1
- * 2: topic2
- - 2.1: The message 1 of topic 2
- - 2.2: The message 2 of topic 2
-
-In the inner loop, the ``loop.parent`` variable is used to access the outer
-context. So, the index of the current ``topic`` defined in the outer for loop
-is accessible via the ``loop.parent.loop.index`` variable.
-
-Defining undefined Functions and Filters on the Fly
----------------------------------------------------
-
-When a function (or a filter) is not defined, Twig defaults to throw a
-``Twig_Error_Syntax`` exception. However, it can also call a `callback`_ (any
-valid PHP callable) which should return a function (or a filter).
-
-For filters, register callbacks with ``registerUndefinedFilterCallback()``.
-For functions, use ``registerUndefinedFunctionCallback()``::
-
- // auto-register all native PHP functions as Twig functions
- // don't try this at home as it's not secure at all!
- $twig->registerUndefinedFunctionCallback(function ($name) {
- if (function_exists($name)) {
- return new Twig_Function_Function($name);
- }
-
- return false;
- });
-
-If the callable is not able to return a valid function (or filter), it must
-return ``false``.
-
-If you register more than one callback, Twig will call them in turn until one
-does not return ``false``.
-
-.. tip::
-
- As the resolution of functions and filters is done during compilation,
- there is no overhead when registering these callbacks.
-
-Validating the Template Syntax
-------------------------------
-
-When template code is providing by a third-party (through a web interface for
-instance), it might be interesting to validate the template syntax before
-saving it. If the template code is stored in a `$template` variable, here is
-how you can do it::
-
- try {
- $twig->parse($twig->tokenize($template));
-
- // the $template is valid
- } catch (Twig_Error_Syntax $e) {
- // $template contains one or more syntax errors
- }
-
-If you iterate over a set of files, you can pass the filename to the
-``tokenize()`` method to get the filename in the exception message::
-
- foreach ($files as $file) {
- try {
- $twig->parse($twig->tokenize($template, $file));
-
- // the $template is valid
- } catch (Twig_Error_Syntax $e) {
- // $template contains one or more syntax errors
- }
- }
-
-.. note::
-
- This method won't catch any sandbox policy violations because the policy
- is enforced during template rendering (as Twig needs the context for some
- checks like allowed methods on objects).
-
-Refreshing modified Templates when APC is enabled and apc.stat = 0
-------------------------------------------------------------------
-
-When using APC with ``apc.stat`` set to ``0`` and Twig cache enabled, clearing
-the template cache won't update the APC cache. To get around this, one can
-extend ``Twig_Environment`` and force the update of the APC cache when Twig
-rewrites the cache::
-
- class Twig_Environment_APC extends Twig_Environment
- {
- protected function writeCacheFile($file, $content)
- {
- parent::writeCacheFile($file, $content);
-
- // Compile cached file into bytecode cache
- apc_compile_file($file);
- }
- }
-
-Reusing a stateful Node Visitor
--------------------------------
-
-When attaching a visitor to a ``Twig_Environment`` instance, Twig uses it to
-visit *all* templates it compiles. If you need to keep some state information
-around, you probably want to reset it when visiting a new template.
-
-This can be easily achieved with the following code::
-
- protected $someTemplateState = array();
-
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Module) {
- // reset the state as we are entering a new template
- $this->someTemplateState = array();
- }
-
- // ...
-
- return $node;
- }
-
-Using the Template name to set the default Escaping Strategy
-------------------------------------------------------------
-
-.. versionadded:: 1.8
- This recipe requires Twig 1.8 or later.
-
-The ``autoescape`` option determines the default escaping strategy to use when
-no escaping is applied on a variable. When Twig is used to mostly generate
-HTML files, you can set it to ``html`` and explicitly change it to ``js`` when
-you have some dynamic JavaScript files thanks to the ``autoescape`` tag:
-
-.. code-block:: jinja
-
- {% autoescape 'js' %}
- ... some JS ...
- {% endautoescape %}
-
-But if you have many HTML and JS files, and if your template names follow some
-conventions, you can instead determine the default escaping strategy to use
-based on the template name. Let's say that your template names always ends
-with ``.html`` for HTML files, ``.js`` for JavaScript ones, and ``.css`` for
-stylesheets, here is how you can configure Twig::
-
- class TwigEscapingGuesser
- {
- function guess($filename)
- {
- // get the format
- $format = substr($filename, strrpos($filename, '.') + 1);
-
- switch ($format) {
- case 'js':
- return 'js';
- case 'css':
- return 'css';
- case 'html':
- default:
- return 'html';
- }
- }
- }
-
- $loader = new Twig_Loader_Filesystem('/path/to/templates');
- $twig = new Twig_Environment($loader, array(
- 'autoescape' => array(new TwigEscapingGuesser(), 'guess'),
- ));
-
-This dynamic strategy does not incur any overhead at runtime as auto-escaping
-is done at compilation time.
-
-Using a Database to store Templates
------------------------------------
-
-If you are developing a CMS, templates are usually stored in a database. This
-recipe gives you a simple PDO template loader you can use as a starting point
-for your own.
-
-First, let's create a temporary in-memory SQLite3 database to work with::
-
- $dbh = new PDO('sqlite::memory:');
- $dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)');
- $base = '{% block content %}{% endblock %}';
- $index = '
- {% extends "base.twig" %}
- {% block content %}Hello {{ name }}{% endblock %}
- ';
- $now = time();
- $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('base.twig', '$base', $now)");
- $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('index.twig', '$index', $now)");
-
-We have created a simple ``templates`` table that hosts two templates:
-``base.twig`` and ``index.twig``.
-
-Now, let's define a loader able to use this database::
-
- class DatabaseTwigLoader implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
- {
- protected $dbh;
-
- public function __construct(PDO $dbh)
- {
- $this->dbh = $dbh;
- }
-
- public function getSource($name)
- {
- if (false === $source = $this->getValue('source', $name)) {
- throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name));
- }
-
- return $source;
- }
-
- // Twig_ExistsLoaderInterface as of Twig 1.11
- public function exists($name)
- {
- return $name === $this->getValue('name', $name);
- }
-
- public function getCacheKey($name)
- {
- return $name;
- }
-
- public function isFresh($name, $time)
- {
- if (false === $lastModified = $this->getValue('last_modified', $name)) {
- return false;
- }
-
- return $lastModified <= $time;
- }
-
- protected function getValue($column, $name)
- {
- $sth = $this->dbh->prepare('SELECT '.$column.' FROM templates WHERE name = :name');
- $sth->execute(array(':name' => (string) $name));
-
- return $sth->fetchColumn();
- }
- }
-
-Finally, here is an example on how you can use it::
-
- $loader = new DatabaseTwigLoader($dbh);
- $twig = new Twig_Environment($loader);
-
- echo $twig->render('index.twig', array('name' => 'Fabien'));
-
-Using different Template Sources
---------------------------------
-
-This recipe is the continuation of the previous one. Even if you store the
-contributed templates in a database, you might want to keep the original/base
-templates on the filesystem. When templates can be loaded from different
-sources, you need to use the ``Twig_Loader_Chain`` loader.
-
-As you can see in the previous recipe, we reference the template in the exact
-same way as we would have done it with a regular filesystem loader. This is
-the key to be able to mix and match templates coming from the database, the
-filesystem, or any other loader for that matter: the template name should be a
-logical name, and not the path from the filesystem::
-
- $loader1 = new DatabaseTwigLoader($dbh);
- $loader2 = new Twig_Loader_Array(array(
- 'base.twig' => '{% block content %}{% endblock %}',
- ));
- $loader = new Twig_Loader_Chain(array($loader1, $loader2));
-
- $twig = new Twig_Environment($loader);
-
- echo $twig->render('index.twig', array('name' => 'Fabien'));
-
-Now that the ``base.twig`` templates is defined in an array loader, you can
-remove it from the database, and everything else will still work as before.
-
-.. _callback: http://www.php.net/manual/en/function.is-callable.php
+++ /dev/null
-``autoescape``
-==============
-
-Whether automatic escaping is enabled or not, you can mark a section of a
-template to be escaped or not by using the ``autoescape`` tag:
-
-.. code-block:: jinja
-
- {# The following syntax works as of Twig 1.8 -- see the note below for previous versions #}
-
- {% autoescape %}
- Everything will be automatically escaped in this block
- using the HTML strategy
- {% endautoescape %}
-
- {% autoescape 'html' %}
- Everything will be automatically escaped in this block
- using the HTML strategy
- {% endautoescape %}
-
- {% autoescape 'js' %}
- Everything will be automatically escaped in this block
- using the js escaping strategy
- {% endautoescape %}
-
- {% autoescape false %}
- Everything will be outputted as is in this block
- {% endautoescape %}
-
-.. note::
-
- Before Twig 1.8, the syntax was different:
-
- .. code-block:: jinja
-
- {% autoescape true %}
- Everything will be automatically escaped in this block
- using the HTML strategy
- {% endautoescape %}
-
- {% autoescape false %}
- Everything will be outputted as is in this block
- {% endautoescape %}
-
- {% autoescape true js %}
- Everything will be automatically escaped in this block
- using the js escaping strategy
- {% endautoescape %}
-
-When automatic escaping is enabled everything is escaped by default except for
-values explicitly marked as safe. Those can be marked in the template by using
-the :doc:`raw<../filters/raw>` filter:
-
-.. code-block:: jinja
-
- {% autoescape %}
- {{ safe_value|raw }}
- {% endautoescape %}
-
-Functions returning template data (like :doc:`macros<macro>` and
-:doc:`parent<../functions/parent>`) always return safe markup.
-
-.. note::
-
- Twig is smart enough to not escape an already escaped value by the
- :doc:`escape<../filters/escape>` filter.
-
-.. note::
-
- The chapter :doc:`Twig for Developers<../api>` gives more information
- about when and how automatic escaping is applied.
+++ /dev/null
-``block``
-=========
-
-Blocks are used for inheritance and act as placeholders and replacements at
-the same time. They are documented in detail in the documentation for the
-:doc:`extends<../tags/extends>` tag.
-
-Block names should consist of alphanumeric characters, and underscores. Dashes
-are not permitted.
-
-.. seealso:: :doc:`block<../functions/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`, :doc:`extends<../tags/extends>`
+++ /dev/null
-``do``
-======
-
-.. versionadded:: 1.5
- The do tag was added in Twig 1.5.
-
-The ``do`` tag works exactly like the regular variable expression (``{{ ...
-}}``) just that it doesn't print anything:
-
-.. code-block:: jinja
-
- {% do 1 + 2 %}
+++ /dev/null
-``embed``
-=========
-
-.. versionadded:: 1.8
- The ``embed`` tag was added in Twig 1.8.
-
-The ``embed`` tag combines the behaviour of :doc:`include<include>` and
-:doc:`extends<extends>`.
-It allows you to include another template's contents, just like ``include``
-does. But it also allows you to override any block defined inside the
-included template, like when extending a template.
-
-Think of an embedded template as a "micro layout skeleton".
-
-.. code-block:: jinja
-
- {% embed "teasers_skeleton.twig" %}
- {# These blocks are defined in "teasers_skeleton.twig" #}
- {# and we override them right here: #}
- {% block left_teaser %}
- Some content for the left teaser box
- {% endblock %}
- {% block right_teaser %}
- Some content for the right teaser box
- {% endblock %}
- {% endembed %}
-
-The ``embed`` tag takes the idea of template inheritance to the level of
-content fragments. While template inheritance allows for "document skeletons",
-which are filled with life by child templates, the ``embed`` tag allows you to
-create "skeletons" for smaller units of content and re-use and fill them
-anywhere you like.
-
-Since the use case may not be obvious, let's look at a simplified example.
-Imagine a base template shared by multiple HTML pages, defining a single block
-named "content":
-
-.. code-block:: text
-
- ┌─── page layout ─────────────────────┐
- │ │
- │ ┌── block "content" ──┐ │
- │ │ │ │
- │ │ │ │
- │ │ (child template to │ │
- │ │ put content here) │ │
- │ │ │ │
- │ │ │ │
- │ └─────────────────────┘ │
- │ │
- └─────────────────────────────────────┘
-
-Some pages ("foo" and "bar") share the same content structure -
-two vertically stacked boxes:
-
-.. code-block:: text
-
- ┌─── page layout ─────────────────────┐
- │ │
- │ ┌── block "content" ──┐ │
- │ │ ┌─ block "top" ───┐ │ │
- │ │ │ │ │ │
- │ │ └─────────────────┘ │ │
- │ │ ┌─ block "bottom" ┐ │ │
- │ │ │ │ │ │
- │ │ └─────────────────┘ │ │
- │ └─────────────────────┘ │
- │ │
- └─────────────────────────────────────┘
-
-While other pages ("boom" and "baz") share a different content structure -
-two boxes side by side:
-
-.. code-block:: text
-
- ┌─── page layout ─────────────────────┐
- │ │
- │ ┌── block "content" ──┐ │
- │ │ │ │
- │ │ ┌ block ┐ ┌ block ┐ │ │
- │ │ │"left" │ │"right"│ │ │
- │ │ │ │ │ │ │ │
- │ │ │ │ │ │ │ │
- │ │ └───────┘ └───────┘ │ │
- │ └─────────────────────┘ │
- │ │
- └─────────────────────────────────────┘
-
-Without the ``embed`` tag, you have two ways to design your templates:
-
- * Create two "intermediate" base templates that extend the master layout
- template: one with vertically stacked boxes to be used by the "foo" and
- "bar" pages and another one with side-by-side boxes for the "boom" and
- "baz" pages.
-
- * Embed the markup for the top/bottom and left/right boxes into each page
- template directly.
-
-These two solutions do not scale well because they each have a major drawback:
-
- * The first solution may indeed work for this simplified example. But imagine
- we add a sidebar, which may again contain different, recurring structures
- of content. Now we would need to create intermediate base templates for
- all occurring combinations of content structure and sidebar structure...
- and so on.
-
- * The second solution involves duplication of common code with all its negative
- consequences: any change involves finding and editing all affected copies
- of the structure, correctness has to be verified for each copy, copies may
- go out of sync by careless modifications etc.
-
-In such a situation, the ``embed`` tag comes in handy. The common layout
-code can live in a single base template, and the two different content structures,
-let's call them "micro layouts" go into separate templates which are embedded
-as necessary:
-
-Page template ``foo.twig``:
-
-.. code-block:: jinja
-
- {% extends "layout_skeleton.twig" %}
-
- {% block content %}
- {% embed "vertical_boxes_skeleton.twig" %}
- {% block top %}
- Some content for the top box
- {% endblock %}
-
- {% block bottom %}
- Some content for the bottom box
- {% endblock %}
- {% endembed %}
- {% endblock %}
-
-And here is the code for ``vertical_boxes_skeleton.twig``:
-
-.. code-block:: html+jinja
-
- <div class="top_box">
- {% block top %}
- Top box default content
- {% endblock %}
- </div>
-
- <div class="bottom_box">
- {% block bottom %}
- Bottom box default content
- {% endblock %}
- </div>
-
-The goal of the ``vertical_boxes_skeleton.twig`` template being to factor
-out the HTML markup for the boxes.
-
-The ``embed`` tag takes the exact same arguments as the ``include`` tag:
-
-.. code-block:: jinja
-
- {% embed "base" with {'foo': 'bar'} %}
- ...
- {% endembed %}
-
- {% embed "base" with {'foo': 'bar'} only %}
- ...
- {% endembed %}
-
- {% embed "base" ignore missing %}
- ...
- {% endembed %}
-
-.. warning::
-
- As embedded templates do not have "names", auto-escaping strategies based
- on the template "filename" won't work as expected if you change the
- context (for instance, if you embed a CSS/JavaScript template into an HTML
- one). In that case, explicitly set the default auto-escaping strategy with
- the ``autoescape`` tag.
-
-.. seealso:: :doc:`include<../tags/include>`
+++ /dev/null
-``extends``
-===========
-
-The ``extends`` tag can be used to extend a template from another one.
-
-.. note::
-
- Like PHP, Twig does not support multiple inheritance. So you can only have
- one extends tag called per rendering. However, Twig supports horizontal
- :doc:`reuse<use>`.
-
-Let's define a base template, ``base.html``, which defines a simple HTML
-skeleton document:
-
-.. code-block:: html+jinja
-
- <!DOCTYPE html>
- <html>
- <head>
- {% block head %}
- <link rel="stylesheet" href="style.css" />
- <title>{% block title %}{% endblock %} - My Webpage</title>
- {% endblock %}
- </head>
- <body>
- <div id="content">{% block content %}{% endblock %}</div>
- <div id="footer">
- {% block footer %}
- © Copyright 2011 by <a href="http://domain.invalid/">you</a>.
- {% endblock %}
- </div>
- </body>
- </html>
-
-In this example, the :doc:`block<block>` tags define four blocks that child
-templates can fill in.
-
-All the ``block`` tag does is to tell the template engine that a child
-template may override those portions of the template.
-
-Child Template
---------------
-
-A child template might look like this:
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% block title %}Index{% endblock %}
- {% block head %}
- {{ parent() }}
- <style type="text/css">
- .important { color: #336699; }
- </style>
- {% endblock %}
- {% block content %}
- <h1>Index</h1>
- <p class="important">
- Welcome on my awesome homepage.
- </p>
- {% endblock %}
-
-The ``extends`` tag is the key here. It tells the template engine that this
-template "extends" another template. When the template system evaluates this
-template, first it locates the parent. The extends tag should be the first tag
-in the template.
-
-Note that since the child template doesn't define the ``footer`` block, the
-value from the parent template is used instead.
-
-You can't define multiple ``block`` tags with the same name in the same
-template. This limitation exists because a block tag works in "both"
-directions. That is, a block tag doesn't just provide a hole to fill - it also
-defines the content that fills the hole in the *parent*. If there were two
-similarly-named ``block`` tags in a template, that template's parent wouldn't
-know which one of the blocks' content to use.
-
-If you want to print a block multiple times you can however use the
-``block`` function:
-
-.. code-block:: jinja
-
- <title>{% block title %}{% endblock %}</title>
- <h1>{{ block('title') }}</h1>
- {% block body %}{% endblock %}
-
-Parent Blocks
--------------
-
-It's possible to render the contents of the parent block by using the
-:doc:`parent<../functions/parent>` function. This gives back the results of
-the parent block:
-
-.. code-block:: jinja
-
- {% block sidebar %}
- <h3>Table Of Contents</h3>
- ...
- {{ parent() }}
- {% endblock %}
-
-Named Block End-Tags
---------------------
-
-Twig allows you to put the name of the block after the end tag for better
-readability:
-
-.. code-block:: jinja
-
- {% block sidebar %}
- {% block inner_sidebar %}
- ...
- {% endblock inner_sidebar %}
- {% endblock sidebar %}
-
-Of course, the name after the ``endblock`` word must match the block name.
-
-Block Nesting and Scope
------------------------
-
-Blocks can be nested for more complex layouts. Per default, blocks have access
-to variables from outer scopes:
-
-.. code-block:: jinja
-
- {% for item in seq %}
- <li>{% block loop_item %}{{ item }}{% endblock %}</li>
- {% endfor %}
-
-Block Shortcuts
----------------
-
-For blocks with few content, it's possible to use a shortcut syntax. The
-following constructs do the same:
-
-.. code-block:: jinja
-
- {% block title %}
- {{ page_title|title }}
- {% endblock %}
-
-.. code-block:: jinja
-
- {% block title page_title|title %}
-
-Dynamic Inheritance
--------------------
-
-Twig supports dynamic inheritance by using a variable as the base template:
-
-.. code-block:: jinja
-
- {% extends some_var %}
-
-If the variable evaluates to a ``Twig_Template`` object, Twig will use it as
-the parent template::
-
- // {% extends layout %}
-
- $layout = $twig->loadTemplate('some_layout_template.twig');
-
- $twig->display('template.twig', array('layout' => $layout));
-
-.. versionadded:: 1.2
- The possibility to pass an array of templates has been added in Twig 1.2.
-
-You can also provide a list of templates that are checked for existence. The
-first template that exists will be used as a parent:
-
-.. code-block:: jinja
-
- {% extends ['layout.html', 'base_layout.html'] %}
-
-Conditional Inheritance
------------------------
-
-As the template name for the parent can be any valid Twig expression, it's
-possible to make the inheritance mechanism conditional:
-
-.. code-block:: jinja
-
- {% extends standalone ? "minimum.html" : "base.html" %}
-
-In this example, the template will extend the "minimum.html" layout template
-if the ``standalone`` variable evaluates to ``true``, and "base.html"
-otherwise.
-
-How blocks work?
-----------------
-
-A block provides a way to change how a certain part of a template is rendered
-but it does not interfere in any way with the logic around it.
-
-Let's take the following example to illustrate how a block work and more
-importantly, how it does not work:
-
-.. code-block:: jinja
-
- {# base.twig #}
-
- {% for post in posts %}
- {% block post %}
- <h1>{{ post.title }}</h1>
- <p>{{ post.body }}</p>
- {% endblock %}
- {% endfor %}
-
-If you render this template, the result would be exactly the same with or
-without the ``block`` tag. The ``block`` inside the ``for`` loop is just a way
-to make it overridable by a child template:
-
-.. code-block:: jinja
-
- {# child.twig #}
-
- {% extends "base.twig" %}
-
- {% block post %}
- <article>
- <header>{{ post.title }}</header>
- <section>{{ post.text }}</section>
- </article>
- {% endblock %}
-
-Now, when rendering the child template, the loop is going to use the block
-defined in the child template instead of the one defined in the base one; the
-executed template is then equivalent to the following one:
-
-.. code-block:: jinja
-
- {% for post in posts %}
- <article>
- <header>{{ post.title }}</header>
- <section>{{ post.text }}</section>
- </article>
- {% endfor %}
-
-Let's take another example: a block included within an ``if`` statement:
-
-.. code-block:: jinja
-
- {% if posts is empty %}
- {% block head %}
- {{ parent() }}
-
- <meta name="robots" content="noindex, follow">
- {% endblock head %}
- {% endif %}
-
-Contrary to what you might think, this template does not define a block
-conditionally; it just makes overridable by a child template the output of
-what will be rendered when the condition is ``true``.
-
-If you want the output to be displayed conditionally, use the following
-instead:
-
-.. code-block:: jinja
-
- {% block head %}
- {{ parent() }}
-
- {% if posts is empty %}
- <meta name="robots" content="noindex, follow">
- {% endif %}
- {% endblock head %}
-
-.. seealso:: :doc:`block<../functions/block>`, :doc:`block<../tags/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`
+++ /dev/null
-``filter``
-==========
-
-Filter sections allow you to apply regular Twig filters on a block of template
-data. Just wrap the code in the special ``filter`` section:
-
-.. code-block:: jinja
-
- {% filter upper %}
- This text becomes uppercase
- {% endfilter %}
-
-You can also chain filters:
-
-.. code-block:: jinja
-
- {% filter lower|escape %}
- <strong>SOME TEXT</strong>
- {% endfilter %}
-
- {# outputs "<strong>some text</strong>" #}
+++ /dev/null
-``flush``
-=========
-
-.. versionadded:: 1.5
- The flush tag was added in Twig 1.5.
-
-The ``flush`` tag tells Twig to flush the output buffer:
-
-.. code-block:: jinja
-
- {% flush %}
-
-.. note::
-
- Internally, Twig uses the PHP `flush`_ function.
-
-.. _`flush`: http://php.net/flush
+++ /dev/null
-``for``
-=======
-
-Loop over each item in a sequence. For example, to display a list of users
-provided in a variable called ``users``:
-
-.. code-block:: jinja
-
- <h1>Members</h1>
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
-
-.. note::
-
- A sequence can be either an array or an object implementing the
- ``Traversable`` interface.
-
-If you do need to iterate over a sequence of numbers, you can use the ``..``
-operator:
-
-.. code-block:: jinja
-
- {% for i in 0..10 %}
- * {{ i }}
- {% endfor %}
-
-The above snippet of code would print all numbers from 0 to 10.
-
-It can be also useful with letters:
-
-.. code-block:: jinja
-
- {% for letter in 'a'..'z' %}
- * {{ letter }}
- {% endfor %}
-
-The ``..`` operator can take any expression at both sides:
-
-.. code-block:: jinja
-
- {% for letter in 'a'|upper..'z'|upper %}
- * {{ letter }}
- {% endfor %}
-
-.. tip:
-
- If you need a step different from 1, you can use the ``range`` function
- instead.
-
-The `loop` variable
--------------------
-
-Inside of a ``for`` loop block you can access some special variables:
-
-===================== =============================================================
-Variable Description
-===================== =============================================================
-``loop.index`` The current iteration of the loop. (1 indexed)
-``loop.index0`` The current iteration of the loop. (0 indexed)
-``loop.revindex`` The number of iterations from the end of the loop (1 indexed)
-``loop.revindex0`` The number of iterations from the end of the loop (0 indexed)
-``loop.first`` True if first iteration
-``loop.last`` True if last iteration
-``loop.length`` The number of items in the sequence
-``loop.parent`` The parent context
-===================== =============================================================
-
-.. code-block:: jinja
-
- {% for user in users %}
- {{ loop.index }} - {{ user.username }}
- {% endfor %}
-
-.. note::
-
- The ``loop.length``, ``loop.revindex``, ``loop.revindex0``, and
- ``loop.last`` variables are only available for PHP arrays, or objects that
- implement the ``Countable`` interface. They are also not available when
- looping with a condition.
-
-.. versionadded:: 1.2
- The ``if`` modifier support has been added in Twig 1.2.
-
-Adding a condition
-------------------
-
-Unlike in PHP, it's not possible to ``break`` or ``continue`` in a loop. You
-can however filter the sequence during iteration which allows you to skip
-items. The following example skips all the users which are not active:
-
-.. code-block:: jinja
-
- <ul>
- {% for user in users if user.active %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
-
-The advantage is that the special loop variable will count correctly thus not
-counting the users not iterated over. Keep in mind that properties like
-``loop.last`` will not be defined when using loop conditions.
-
-.. note::
-
- Using the ``loop`` variable within the condition is not recommended as it
- will probably not be doing what you expect it to. For instance, adding a
- condition like ``loop.index > 4`` won't work as the index is only
- incremented when the condition is true (so the condition will never
- match).
-
-The `else` Clause
------------------
-
-If no iteration took place because the sequence was empty, you can render a
-replacement block by using ``else``:
-
-.. code-block:: jinja
-
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% else %}
- <li><em>no user found</em></li>
- {% endfor %}
- </ul>
-
-Iterating over Keys
--------------------
-
-By default, a loop iterates over the values of the sequence. You can iterate
-on keys by using the ``keys`` filter:
-
-.. code-block:: jinja
-
- <h1>Members</h1>
- <ul>
- {% for key in users|keys %}
- <li>{{ key }}</li>
- {% endfor %}
- </ul>
-
-Iterating over Keys and Values
-------------------------------
-
-You can also access both keys and values:
-
-.. code-block:: jinja
-
- <h1>Members</h1>
- <ul>
- {% for key, user in users %}
- <li>{{ key }}: {{ user.username|e }}</li>
- {% endfor %}
- </ul>
-
-Iterating over a Subset
------------------------
-
-You might want to iterate over a subset of values. This can be achieved using
-the :doc:`slice <../filters/slice>` filter:
-
-.. code-block:: jinja
-
- <h1>Top Ten Members</h1>
- <ul>
- {% for user in users|slice(0, 10) %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
+++ /dev/null
-``from``
-========
-
-The ``from`` tags import :doc:`macro<../tags/macro>` names into the current
-namespace. The tag is documented in detail in the documentation for the
-:doc:`import<../tags/import>` tag.
-
-.. seealso:: :doc:`macro<../tags/macro>`, :doc:`import<../tags/import>`
+++ /dev/null
-``if``
-======
-
-The ``if`` statement in Twig is comparable with the if statements of PHP.
-
-In the simplest form you can use it to test if an expression evaluates to
-``true``:
-
-.. code-block:: jinja
-
- {% if online == false %}
- <p>Our website is in maintenance mode. Please, come back later.</p>
- {% endif %}
-
-You can also test if an array is not empty:
-
-.. code-block:: jinja
-
- {% if users %}
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
- {% endif %}
-
-.. note::
-
- If you want to test if the variable is defined, use ``if users is
- defined`` instead.
-
-For multiple branches ``elseif`` and ``else`` can be used like in PHP. You can use
-more complex ``expressions`` there too:
-
-.. code-block:: jinja
-
- {% if kenny.sick %}
- Kenny is sick.
- {% elseif kenny.dead %}
- You killed Kenny! You bastard!!!
- {% else %}
- Kenny looks okay --- so far
- {% endif %}
+++ /dev/null
-``import``
-==========
-
-Twig supports putting often used code into :doc:`macros<../tags/macro>`. These
-macros can go into different templates and get imported from there.
-
-There are two ways to import templates. You can import the complete template
-into a variable or request specific macros from it.
-
-Imagine we have a helper module that renders forms (called ``forms.html``):
-
-.. code-block:: jinja
-
- {% macro input(name, value, type, size) %}
- <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
- {% endmacro %}
-
- {% macro textarea(name, value, rows) %}
- <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
- {% endmacro %}
-
-The easiest and most flexible is importing the whole module into a variable.
-That way you can access the attributes:
-
-.. code-block:: jinja
-
- {% import 'forms.html' as forms %}
-
- <dl>
- <dt>Username</dt>
- <dd>{{ forms.input('username') }}</dd>
- <dt>Password</dt>
- <dd>{{ forms.input('password', null, 'password') }}</dd>
- </dl>
- <p>{{ forms.textarea('comment') }}</p>
-
-Alternatively you can import names from the template into the current
-namespace:
-
-.. code-block:: jinja
-
- {% from 'forms.html' import input as input_field, textarea %}
-
- <dl>
- <dt>Username</dt>
- <dd>{{ input_field('username') }}</dd>
- <dt>Password</dt>
- <dd>{{ input_field('password', '', 'password') }}</dd>
- </dl>
- <p>{{ textarea('comment') }}</p>
-
-.. tip::
-
- To import macros from the current file, use the special ``_self`` variable
- for the source.
-
-.. seealso:: :doc:`macro<../tags/macro>`, :doc:`from<../tags/from>`
+++ /dev/null
-``include``
-===========
-
-The ``include`` statement includes a template and return the rendered content
-of that file into the current namespace:
-
-.. code-block:: jinja
-
- {% include 'header.html' %}
- Body
- {% include 'footer.html' %}
-
-Included templates have access to the variables of the active context.
-
-If you are using the filesystem loader, the templates are looked for in the
-paths defined by it.
-
-You can add additional variables by passing them after the ``with`` keyword:
-
-.. code-block:: jinja
-
- {# template.html will have access to the variables from the current context and the additional ones provided #}
- {% include 'template.html' with {'foo': 'bar'} %}
-
- {% set vars = {'foo': 'bar'} %}
- {% include 'template.html' with vars %}
-
-You can disable access to the context by appending the ``only`` keyword:
-
-.. code-block:: jinja
-
- {# only the foo variable will be accessible #}
- {% include 'template.html' with {'foo': 'bar'} only %}
-
-.. code-block:: jinja
-
- {# no variables will be accessible #}
- {% include 'template.html' only %}
-
-.. tip::
-
- When including a template created by an end user, you should consider
- sandboxing it. More information in the :doc:`Twig for Developers<../api>`
- chapter and in the :doc:`sandbox<../tags/sandbox>` tag documentation.
-
-The template name can be any valid Twig expression:
-
-.. code-block:: jinja
-
- {% include some_var %}
- {% include ajax ? 'ajax.html' : 'not_ajax.html' %}
-
-And if the expression evaluates to a ``Twig_Template`` object, Twig will use it
-directly::
-
- // {% include template %}
-
- $template = $twig->loadTemplate('some_template.twig');
-
- $twig->loadTemplate('template.twig')->display(array('template' => $template));
-
-.. versionadded:: 1.2
- The ``ignore missing`` feature has been added in Twig 1.2.
-
-You can mark an include with ``ignore missing`` in which case Twig will ignore
-the statement if the template to be included does not exist. It has to be
-placed just after the template name. Here some valid examples:
-
-.. code-block:: jinja
-
- {% include 'sidebar.html' ignore missing %}
- {% include 'sidebar.html' ignore missing with {'foo': 'bar'} %}
- {% include 'sidebar.html' ignore missing only %}
-
-.. versionadded:: 1.2
- The possibility to pass an array of templates has been added in Twig 1.2.
-
-You can also provide a list of templates that are checked for existence before
-inclusion. The first template that exists will be included:
-
-.. code-block:: jinja
-
- {% include ['page_detailed.html', 'page.html'] %}
-
-If ``ignore missing`` is given, it will fall back to rendering nothing if none
-of the templates exist, otherwise it will throw an exception.
+++ /dev/null
-Tags
-====
-
-.. toctree::
- :maxdepth: 1
-
- autoescape
- block
- filter
- do
- embed
- extends
- flush
- for
- from
- if
- import
- include
- macro
- sandbox
- set
- spaceless
- use
- verbatim
+++ /dev/null
-``macro``
-=========
-
-Macros are comparable with functions in regular programming languages. They
-are useful to put often used HTML idioms into reusable elements to not repeat
-yourself.
-
-Here is a small example of a macro that renders a form element:
-
-.. code-block:: jinja
-
- {% macro input(name, value, type, size) %}
- <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
- {% endmacro %}
-
-Macros differs from native PHP functions in a few ways:
-
-* Default argument values are defined by using the ``default`` filter in the
- macro body;
-
-* Arguments of a macro are always optional.
-
-But as with PHP functions, macros don't have access to the current template
-variables.
-
-.. tip::
-
- You can pass the whole context as an argument by using the special
- ``_context`` variable.
-
-Macros can be defined in any template, and need to be "imported" before being
-used (see the documentation for the :doc:`import<../tags/import>` tag for more
-information):
-
-.. code-block:: jinja
-
- {% import "forms.html" as forms %}
-
-The above ``import`` call imports the "forms.html" file (which can contain only
-macros, or a template and some macros), and import the functions as items of
-the ``forms`` variable.
-
-The macro can then be called at will:
-
-.. code-block:: jinja
-
- <p>{{ forms.input('username') }}</p>
- <p>{{ forms.input('password', null, 'password') }}</p>
-
-If macros are defined and used in the same template, you can use the
-special ``_self`` variable to import them:
-
-.. code-block:: jinja
-
- {% import _self as forms %}
-
- <p>{{ forms.input('username') }}</p>
-
-.. warning::
-
- When you define a macro in the template where you are going to use it, you
- might be tempted to call the macro directly via ``_self.input()`` instead
- of importing it; even if seems to work, this is just a side-effect of the
- current implementation and it won't work anymore in Twig 2.x.
-
-When you want to use a macro in another macro from the same file, you need to
-import it locally:
-
-.. code-block:: jinja
-
- {% macro input(name, value, type, size) %}
- <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
- {% endmacro %}
-
- {% macro wrapped_input(name, value, type, size) %}
- {% import _self as forms %}
-
- <div class="field">
- {{ forms.input(name, value, type, size) }}
- </div>
- {% endmacro %}
-
-.. seealso:: :doc:`from<../tags/from>`, :doc:`import<../tags/import>`
+++ /dev/null
-``sandbox``
-===========
-
-The ``sandbox`` tag can be used to enable the sandboxing mode for an included
-template, when sandboxing is not enabled globally for the Twig environment:
-
-.. code-block:: jinja
-
- {% sandbox %}
- {% include 'user.html' %}
- {% endsandbox %}
-
-.. warning::
-
- The ``sandbox`` tag is only available when the sandbox extension is
- enabled (see the :doc:`Twig for Developers<../api>` chapter).
-
-.. note::
-
- The ``sandbox`` tag can only be used to sandbox an include tag and it
- cannot be used to sandbox a section of a template. The following example
- won't work:
-
- .. code-block:: jinja
-
- {% sandbox %}
- {% for i in 1..2 %}
- {{ i }}
- {% endfor %}
- {% endsandbox %}
+++ /dev/null
-``set``
-=======
-
-Inside code blocks you can also assign values to variables. Assignments use
-the ``set`` tag and can have multiple targets.
-
-Here is how you can assign the ``bar`` value to the ``foo`` variable:
-
-.. code-block:: jinja
-
- {% set foo = 'bar' %}
-
-After the ``set`` call, the ``foo`` variable is available in the template like
-any other ones:
-
-.. code-block:: jinja
-
- {# displays bar #}
- {{ foo }}
-
-The assigned value can be any valid :ref:`Twig expressions
-<twig-expressions>`:
-
-.. code-block:: jinja
-
- {% set foo = [1, 2] %}
- {% set foo = {'foo': 'bar'} %}
- {% set foo = 'foo' ~ 'bar' %}
-
-Several variables can be assigned in one block:
-
-.. code-block:: jinja
-
- {% set foo, bar = 'foo', 'bar' %}
-
- {# is equivalent to #}
-
- {% set foo = 'foo' %}
- {% set bar = 'bar' %}
-
-The ``set`` tag can also be used to 'capture' chunks of text:
-
-.. code-block:: jinja
-
- {% set foo %}
- <div id="pagination">
- ...
- </div>
- {% endset %}
-
-.. caution::
-
- If you enable automatic output escaping, Twig will only consider the
- content to be safe when capturing chunks of text.
-
-.. note::
-
- Note that loops are scoped in Twig; therefore a variable declared inside a
- ``for`` loop is not accessible outside the loop itself:
-
- .. code-block:: jinja
-
- {% for item in list %}
- {% set foo = item %}
- {% endfor %}
-
- {# foo is NOT available #}
-
- If you want to access the variable, just declare it before the loop:
-
- .. code-block:: jinja
-
- {% set foo = "" %}
- {% for item in list %}
- {% set foo = item %}
- {% endfor %}
-
- {# foo is available #}
+++ /dev/null
-``spaceless``
-=============
-
-Use the ``spaceless`` tag to remove whitespace *between HTML tags*, not
-whitespace within HTML tags or whitespace in plain text:
-
-.. code-block:: jinja
-
- {% spaceless %}
- <div>
- <strong>foo</strong>
- </div>
- {% endspaceless %}
-
- {# output will be <div><strong>foo</strong></div> #}
-
-This tag is not meant to "optimize" the size of the generated HTML content but
-merely to avoid extra whitespace between HTML tags to avoid browser rendering
-quirks under some circumstances.
-
-.. tip::
-
- If you want to optimize the size of the generated HTML content, gzip
- compress the output instead.
-
-.. tip::
-
- If you want to create a tag that actually removes all extra whitespace in
- an HTML string, be warned that this is not as easy as it seems to be
- (think of ``textarea`` or ``pre`` tags for instance). Using a third-party
- library like Tidy is probably a better idea.
-
-.. tip::
-
- For more information on whitespace control, read the
- :doc:`dedicated<../templates>` section of the documentation and learn how
- you can also use the whitespace control modifier on your tags.
+++ /dev/null
-``use``
-=======
-
-.. versionadded:: 1.1
- Horizontal reuse was added in Twig 1.1.
-
-.. note::
-
- Horizontal reuse is an advanced Twig feature that is hardly ever needed in
- regular templates. It is mainly used by projects that need to make
- template blocks reusable without using inheritance.
-
-Template inheritance is one of the most powerful Twig's feature but it is
-limited to single inheritance; a template can only extend one other template.
-This limitation makes template inheritance simple to understand and easy to
-debug:
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% block title %}{% endblock %}
- {% block content %}{% endblock %}
-
-Horizontal reuse is a way to achieve the same goal as multiple inheritance,
-but without the associated complexity:
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% use "blocks.html" %}
-
- {% block title %}{% endblock %}
- {% block content %}{% endblock %}
-
-The ``use`` statement tells Twig to import the blocks defined in
-```blocks.html`` into the current template (it's like macros, but for blocks):
-
-.. code-block:: jinja
-
- # blocks.html
- {% block sidebar %}{% endblock %}
-
-In this example, the ``use`` statement imports the ``sidebar`` block into the
-main template. The code is mostly equivalent to the following one (the
-imported blocks are not outputted automatically):
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% block sidebar %}{% endblock %}
- {% block title %}{% endblock %}
- {% block content %}{% endblock %}
-
-.. note::
-
- The ``use`` tag only imports a template if it does not extend another
- template, if it does not define macros, and if the body is empty. But it
- can *use* other templates.
-
-.. note::
-
- Because ``use`` statements are resolved independently of the context
- passed to the template, the template reference cannot be an expression.
-
-The main template can also override any imported block. If the template
-already defines the ``sidebar`` block, then the one defined in ``blocks.html``
-is ignored. To avoid name conflicts, you can rename imported blocks:
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% use "blocks.html" with sidebar as base_sidebar %}
-
- {% block sidebar %}{% endblock %}
- {% block title %}{% endblock %}
- {% block content %}{% endblock %}
-
-.. versionadded:: 1.3
- The ``parent()`` support was added in Twig 1.3.
-
-The ``parent()`` function automatically determines the correct inheritance
-tree, so it can be used when overriding a block defined in an imported
-template:
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% use "blocks.html" %}
-
- {% block sidebar %}
- {{ parent() }}
- {% endblock %}
-
- {% block title %}{% endblock %}
- {% block content %}{% endblock %}
-
-In this example, ``parent()`` will correctly call the ``sidebar`` block from
-the ``blocks.html`` template.
-
-.. tip::
-
- In Twig 1.2, renaming allows you to simulate inheritance by calling the
- "parent" block:
-
- .. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% use "blocks.html" with sidebar as parent_sidebar %}
-
- {% block sidebar %}
- {{ block('parent_sidebar') }}
- {% endblock %}
-
-.. note::
-
- You can use as many ``use`` statements as you want in any given template.
- If two imported templates define the same block, the latest one wins.
+++ /dev/null
-``verbatim``
-============
-
-.. versionadded:: 1.12
- The ``verbatim`` tag was added in Twig 1.12 (it was named ``raw`` before).
-
-The ``verbatim`` tag marks sections as being raw text that should not be
-parsed. For example to put Twig syntax as example into a template you can use
-this snippet:
-
-.. code-block:: jinja
-
- {% verbatim %}
- <ul>
- {% for item in seq %}
- <li>{{ item }}</li>
- {% endfor %}
- </ul>
- {% endverbatim %}
-
-.. note::
-
- The ``verbatim`` tag works in the exact same way as the old ``raw`` tag,
- but was renamed to avoid confusion with the ``raw`` filter.
\ No newline at end of file
+++ /dev/null
-Twig for Template Designers
-===========================
-
-This document describes the syntax and semantics of the template engine and
-will be most useful as reference to those creating Twig templates.
-
-Synopsis
---------
-
-A template is simply a text file. It can generate any text-based format (HTML,
-XML, CSV, LaTeX, etc.). It doesn't have a specific extension, ``.html`` or
-``.xml`` are just fine.
-
-A template contains **variables** or **expressions**, which get replaced with
-values when the template is evaluated, and **tags**, which control the logic
-of the template.
-
-Below is a minimal template that illustrates a few basics. We will cover the
-details later on:
-
-.. code-block:: html+jinja
-
- <!DOCTYPE html>
- <html>
- <head>
- <title>My Webpage</title>
- </head>
- <body>
- <ul id="navigation">
- {% for item in navigation %}
- <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
- {% endfor %}
- </ul>
-
- <h1>My Webpage</h1>
- {{ a_variable }}
- </body>
- </html>
-
-There are two kinds of delimiters: ``{% ... %}`` and ``{{ ... }}``. The first
-one is used to execute statements such as for-loops, the latter prints the
-result of an expression to the template.
-
-IDEs Integration
-----------------
-
-Many IDEs support syntax highlighting and auto-completion for Twig:
-
-* *Textmate* via the `Twig bundle`_
-* *Vim* via the `Jinja syntax plugin`_
-* *Netbeans* via the `Twig syntax plugin`_ (until 7.1, native as of 7.2)
-* *PhpStorm* (native as of 2.1)
-* *Eclipse* via the `Twig plugin`_
-* *Sublime Text* via the `Twig bundle`_
-* *GtkSourceView* via the `Twig language definition`_ (used by gedit and other projects)
-* *Coda* and *SubEthaEdit* via the `Twig syntax mode`_
-* *Coda 2* via the `other Twig syntax mode`_
-* *Komodo* and *Komodo Edit* via the Twig highlight/syntax check mode
-* *Notepad++* via the `Notepad++ Twig Highlighter`_
-* *Emacs* via `web-mode.el`_
-
-Variables
----------
-
-The application passes variables to the templates you can mess around in the
-template. Variables may have attributes or elements on them you can access
-too. How a variable looks like heavily depends on the application providing
-those.
-
-You can use a dot (``.``) to access attributes of a variable (methods or
-properties of a PHP object, or items of a PHP array), or the so-called
-"subscript" syntax (``[]``):
-
-.. code-block:: jinja
-
- {{ foo.bar }}
- {{ foo['bar'] }}
-
-When the attribute contains special characters (like ``-`` that would be
-interpreted as the minus operator), use the ``attribute`` function instead to
-access the variable attribute:
-
-.. code-block:: jinja
-
- {# equivalent to the non-working foo.data-foo #}
- {{ attribute(foo, 'data-foo') }}
-
-.. note::
-
- It's important to know that the curly braces are *not* part of the
- variable but the print statement. If you access variables inside tags
- don't put the braces around.
-
-If a variable or attribute does not exist, you will get back a ``null`` value
-when the ``strict_variables`` option is set to ``false``, otherwise Twig will
-throw an error (see :ref:`environment options<environment_options>`).
-
-.. sidebar:: Implementation
-
- For convenience sake ``foo.bar`` does the following things on the PHP
- layer:
-
- * check if ``foo`` is an array and ``bar`` a valid element;
- * if not, and if ``foo`` is an object, check that ``bar`` is a valid property;
- * if not, and if ``foo`` is an object, check that ``bar`` is a valid method
- (even if ``bar`` is the constructor - use ``__construct()`` instead);
- * if not, and if ``foo`` is an object, check that ``getBar`` is a valid method;
- * if not, and if ``foo`` is an object, check that ``isBar`` is a valid method;
- * if not, return a ``null`` value.
-
- ``foo['bar']`` on the other hand only works with PHP arrays:
-
- * check if ``foo`` is an array and ``bar`` a valid element;
- * if not, return a ``null`` value.
-
-.. note::
-
- If you want to get a dynamic attribute on a variable, use the
- :doc:`attribute<functions/attribute>` function instead.
-
-Global Variables
-~~~~~~~~~~~~~~~~
-
-The following variables are always available in templates:
-
-* ``_self``: references the current template;
-* ``_context``: references the current context;
-* ``_charset``: references the current charset.
-
-Setting Variables
-~~~~~~~~~~~~~~~~~
-
-You can assign values to variables inside code blocks. Assignments use the
-:doc:`set<tags/set>` tag:
-
-.. code-block:: jinja
-
- {% set foo = 'foo' %}
- {% set foo = [1, 2] %}
- {% set foo = {'foo': 'bar'} %}
-
-Filters
--------
-
-Variables can be modified by **filters**. Filters are separated from the
-variable by a pipe symbol (``|``) and may have optional arguments in
-parentheses. Multiple filters can be chained. The output of one filter is
-applied to the next.
-
-The following example removes all HTML tags from the ``name`` and title-cases
-it:
-
-.. code-block:: jinja
-
- {{ name|striptags|title }}
-
-Filters that accept arguments have parentheses around the arguments. This
-example will join a list by commas:
-
-.. code-block:: jinja
-
- {{ list|join(', ') }}
-
-To apply a filter on a section of code, wrap it with the
-:doc:`filter<tags/filter>` tag:
-
-.. code-block:: jinja
-
- {% filter upper %}
- This text becomes uppercase
- {% endfilter %}
-
-Go to the :doc:`filters<filters/index>` page to learn more about the built-in
-filters.
-
-Functions
----------
-
-Functions can be called to generate content. Functions are called by their
-name followed by parentheses (``()``) and may have arguments.
-
-For instance, the ``range`` function returns a list containing an arithmetic
-progression of integers:
-
-.. code-block:: jinja
-
- {% for i in range(0, 3) %}
- {{ i }},
- {% endfor %}
-
-Go to the :doc:`functions<functions/index>` page to learn more about the
-built-in functions.
-
-Named Arguments
----------------
-
-.. versionadded:: 1.12
- Support for named arguments was added in Twig 1.12.
-
-Arguments for filters and functions can also be passed as *named arguments*:
-
-.. code-block:: jinja
-
- {% for i in range(low=1, high=10, step=2) %}
- {{ i }},
- {% endfor %}
-
-Using named arguments makes your templates more explicit about the meaning of
-the values you pass as arguments:
-
-.. code-block:: jinja
-
- {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
-
- {# versus #}
-
- {{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}
-
-Named arguments also allow you to skip some arguments for which you don't want
-to change the default value:
-
-.. code-block:: jinja
-
- {# the first argument is the date format, which defaults to the global date format if null is passed #}
- {{ "now"|date(null, "Europe/Paris") }}
-
- {# or skip the format value by using a named argument for the timezone #}
- {{ "now"|date(timezone="Europe/Paris") }}
-
-You can also use both positional and named arguments in one call, in which
-case positional arguments must always come before named arguments:
-
-.. code-block:: jinja
-
- {{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }}
-
-.. tip::
-
- Each function and filter documentation page has a section where the names
- of all arguments are listed when supported.
-
-Control Structure
------------------
-
-A control structure refers to all those things that control the flow of a
-program - conditionals (i.e. ``if``/``elseif``/``else``), ``for``-loops, as
-well as things like blocks. Control structures appear inside ``{% ... %}``
-blocks.
-
-For example, to display a list of users provided in a variable called
-``users``, use the :doc:`for<tags/for>` tag:
-
-.. code-block:: jinja
-
- <h1>Members</h1>
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
-
-The :doc:`if<tags/if>` tag can be used to test an expression:
-
-.. code-block:: jinja
-
- {% if users|length > 0 %}
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
- {% endif %}
-
-Go to the :doc:`tags<tags/index>` page to learn more about the built-in tags.
-
-Comments
---------
-
-To comment-out part of a line in a template, use the comment syntax ``{# ...
-#}``. This is useful for debugging or to add information for other template
-designers or yourself:
-
-.. code-block:: jinja
-
- {# note: disabled template because we no longer use this
- {% for user in users %}
- ...
- {% endfor %}
- #}
-
-Including other Templates
--------------------------
-
-The :doc:`include<tags/include>` tag is useful to include a template and
-return the rendered content of that template into the current one:
-
-.. code-block:: jinja
-
- {% include 'sidebar.html' %}
-
-Per default included templates are passed the current context.
-
-The context that is passed to the included template includes variables defined
-in the template:
-
-.. code-block:: jinja
-
- {% for box in boxes %}
- {% include "render_box.html" %}
- {% endfor %}
-
-The included template ``render_box.html`` is able to access ``box``.
-
-The filename of the template depends on the template loader. For instance, the
-``Twig_Loader_Filesystem`` allows you to access other templates by giving the
-filename. You can access templates in subdirectories with a slash:
-
-.. code-block:: jinja
-
- {% include "sections/articles/sidebar.html" %}
-
-This behavior depends on the application embedding Twig.
-
-Template Inheritance
---------------------
-
-The most powerful part of Twig is template inheritance. Template inheritance
-allows you to build a base "skeleton" template that contains all the common
-elements of your site and defines **blocks** that child templates can
-override.
-
-Sounds complicated but is very basic. It's easier to understand it by
-starting with an example.
-
-Let's define a base template, ``base.html``, which defines a simple HTML
-skeleton document that you might use for a simple two-column page:
-
-.. code-block:: html+jinja
-
- <!DOCTYPE html>
- <html>
- <head>
- {% block head %}
- <link rel="stylesheet" href="style.css" />
- <title>{% block title %}{% endblock %} - My Webpage</title>
- {% endblock %}
- </head>
- <body>
- <div id="content">{% block content %}{% endblock %}</div>
- <div id="footer">
- {% block footer %}
- © Copyright 2011 by <a href="http://domain.invalid/">you</a>.
- {% endblock %}
- </div>
- </body>
- </html>
-
-In this example, the :doc:`block<tags/block>` tags define four blocks that
-child templates can fill in. All the ``block`` tag does is to tell the
-template engine that a child template may override those portions of the
-template.
-
-A child template might look like this:
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
-
- {% block title %}Index{% endblock %}
- {% block head %}
- {{ parent() }}
- <style type="text/css">
- .important { color: #336699; }
- </style>
- {% endblock %}
- {% block content %}
- <h1>Index</h1>
- <p class="important">
- Welcome to my awesome homepage.
- </p>
- {% endblock %}
-
-The :doc:`extends<tags/extends>` tag is the key here. It tells the template
-engine that this template "extends" another template. When the template system
-evaluates this template, first it locates the parent. The extends tag should
-be the first tag in the template.
-
-Note that since the child template doesn't define the ``footer`` block, the
-value from the parent template is used instead.
-
-It's possible to render the contents of the parent block by using the
-:doc:`parent<functions/parent>` function. This gives back the results of the
-parent block:
-
-.. code-block:: jinja
-
- {% block sidebar %}
- <h3>Table Of Contents</h3>
- ...
- {{ parent() }}
- {% endblock %}
-
-.. tip::
-
- The documentation page for the :doc:`extends<tags/extends>` tag describes
- more advanced features like block nesting, scope, dynamic inheritance, and
- conditional inheritance.
-
-.. note::
-
- Twig also supports multiple inheritance with the so called horizontal reuse
- with the help of the :doc:`use<tags/use>` tag. This is an advanced feature
- hardly ever needed in regular templates.
-
-HTML Escaping
--------------
-
-When generating HTML from templates, there's always a risk that a variable
-will include characters that affect the resulting HTML. There are two
-approaches: manually escaping each variable or automatically escaping
-everything by default.
-
-Twig supports both, automatic escaping is enabled by default.
-
-.. note::
-
- Automatic escaping is only supported if the *escaper* extension has been
- enabled (which is the default).
-
-Working with Manual Escaping
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If manual escaping is enabled, it is **your** responsibility to escape
-variables if needed. What to escape? Any variable you don't trust.
-
-Escaping works by piping the variable through the
-:doc:`escape<filters/escape>` or ``e`` filter:
-
-.. code-block:: jinja
-
- {{ user.username|e }}
-
-By default, the ``escape`` filter uses the ``html`` strategy, but depending on
-the escaping context, you might want to explicitly use any other available
-strategies:
-
-.. code-block:: jinja
-
- {{ user.username|e('js') }}
- {{ user.username|e('css') }}
- {{ user.username|e('url') }}
- {{ user.username|e('html_attr') }}
-
-Working with Automatic Escaping
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Whether automatic escaping is enabled or not, you can mark a section of a
-template to be escaped or not by using the :doc:`autoescape<tags/autoescape>`
-tag:
-
-.. code-block:: jinja
-
- {% autoescape %}
- Everything will be automatically escaped in this block (using the HTML strategy)
- {% endautoescape %}
-
-By default, auto-escaping uses the ``html`` escaping strategy. If you output
-variables in other contexts, you need to explicitly escape them with the
-appropriate escaping strategy:
-
-.. code-block:: jinja
-
- {% autoescape 'js' %}
- Everything will be automatically escaped in this block (using the JS strategy)
- {% endautoescape %}
-
-Escaping
---------
-
-It is sometimes desirable or even necessary to have Twig ignore parts it would
-otherwise handle as variables or blocks. For example if the default syntax is
-used and you want to use ``{{`` as raw string in the template and not start a
-variable you have to use a trick.
-
-The easiest way is to output the variable delimiter (``{{``) by using a variable
-expression:
-
-.. code-block:: jinja
-
- {{ '{{' }}
-
-For bigger sections it makes sense to mark a block
-:doc:`verbatim<tags/verbatim>`.
-
-Macros
-------
-
-.. versionadded:: 1.12
- Support for default argument values was added in Twig 1.12.
-
-Macros are comparable with functions in regular programming languages. They
-are useful to reuse often used HTML fragments to not repeat yourself.
-
-A macro is defined via the :doc:`macro<tags/macro>` tag. Here is a small example
-(subsequently called ``forms.html``) of a macro that renders a form element:
-
-.. code-block:: jinja
-
- {% macro input(name, value, type, size) %}
- <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
- {% endmacro %}
-
-Macros can be defined in any template, and need to be "imported" via the
-:doc:`import<tags/import>` tag before being used:
-
-.. code-block:: jinja
-
- {% import "forms.html" as forms %}
-
- <p>{{ forms.input('username') }}</p>
-
-Alternatively, you can import individual macro names from a template into the
-current namespace via the :doc:`from<tags/from>` tag and optionally alias them:
-
-.. code-block:: jinja
-
- {% from 'forms.html' import input as input_field %}
-
- <dl>
- <dt>Username</dt>
- <dd>{{ input_field('username') }}</dd>
- <dt>Password</dt>
- <dd>{{ input_field('password', '', 'password') }}</dd>
- </dl>
-
-A default value can also be defined for macro arguments when not provided in a
-macro call:
-
-.. code-block:: jinja
-
- {% macro input(name, value = "", type = "text", size = 20) %}
- <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
- {% endmacro %}
-
-.. _twig-expressions:
-
-Expressions
------------
-
-Twig allows expressions everywhere. These work very similar to regular PHP and
-even if you're not working with PHP you should feel comfortable with it.
-
-.. note::
-
- The operator precedence is as follows, with the lowest-precedence
- operators listed first: ``b-and``, ``b-xor``, ``b-or``, ``or``, ``and``,
- ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``..``, ``+``,
- ``-``, ``~``, ``*``, ``/``, ``//``, ``%``, ``is``, ``**``, ``|``, ``[]``,
- and ``.``:
-
- .. code-block:: jinja
-
- {% set greeting = 'Hello' %}
- {% set name = 'Fabien' %}
-
- {{ greeting ~ name|lower }} {# Hello fabien #}
-
- {# use parenthesis to change precedence #}
- {{ (greeting ~ name)|lower }} {# hello fabien #}
-
-Literals
-~~~~~~~~
-
-.. versionadded:: 1.5
- Support for hash keys as names and expressions was added in Twig 1.5.
-
-The simplest form of expressions are literals. Literals are representations
-for PHP types such as strings, numbers, and arrays. The following literals
-exist:
-
-* ``"Hello World"``: Everything between two double or single quotes is a
- string. They are useful whenever you need a string in the template (for
- example as arguments to function calls, filters or just to extend or include
- a template). A string can contain a delimiter if it is preceded by a
- backslash (``\``) -- like in ``'It\'s good'``.
-
-* ``42`` / ``42.23``: Integers and floating point numbers are created by just
- writing the number down. If a dot is present the number is a float,
- otherwise an integer.
-
-* ``["foo", "bar"]``: Arrays are defined by a sequence of expressions
- separated by a comma (``,``) and wrapped with squared brackets (``[]``).
-
-* ``{"foo": "bar"}``: Hashes are defined by a list of keys and values
- separated by a comma (``,``) and wrapped with curly braces (``{}``):
-
- .. code-block:: jinja
-
- {# keys as string #}
- { 'foo': 'foo', 'bar': 'bar' }
-
- {# keys as names (equivalent to the previous hash) -- as of Twig 1.5 #}
- { foo: 'foo', bar: 'bar' }
-
- {# keys as integer #}
- { 2: 'foo', 4: 'bar' }
-
- {# keys as expressions (the expression must be enclosed into parentheses) -- as of Twig 1.5 #}
- { (1 + 1): 'foo', (a ~ 'b'): 'bar' }
-
-* ``true`` / ``false``: ``true`` represents the true value, ``false``
- represents the false value.
-
-* ``null``: ``null`` represents no specific value. This is the value returned
- when a variable does not exist. ``none`` is an alias for ``null``.
-
-Arrays and hashes can be nested:
-
-.. code-block:: jinja
-
- {% set foo = [1, {"foo": "bar"}] %}
-
-.. tip::
-
- Using double-quoted or single-quoted strings has no impact on performance
- but string interpolation is only supported in double-quoted strings.
-
-Math
-~~~~
-
-Twig allows you to calculate with values. This is rarely useful in templates
-but exists for completeness' sake. The following operators are supported:
-
-* ``+``: Adds two objects together (the operands are casted to numbers). ``{{
- 1 + 1 }}`` is ``2``.
-
-* ``-``: Subtracts the second number from the first one. ``{{ 3 - 2 }}`` is
- ``1``.
-
-* ``/``: Divides two numbers. The returned value will be a floating point
- number. ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``.
-
-* ``%``: Calculates the remainder of an integer division. ``{{ 11 % 7 }}`` is
- ``4``.
-
-* ``//``: Divides two numbers and returns the truncated integer result. ``{{
- 20 // 7 }}`` is ``2``.
-
-* ``*``: Multiplies the left operand with the right one. ``{{ 2 * 2 }}`` would
- return ``4``.
-
-* ``**``: Raises the left operand to the power of the right operand. ``{{ 2 **
- 3 }}`` would return ``8``.
-
-Logic
-~~~~~
-
-You can combine multiple expressions with the following operators:
-
-* ``and``: Returns true if the left and the right operands are both true.
-
-* ``or``: Returns true if the left or the right operand is true.
-
-* ``not``: Negates a statement.
-
-* ``(expr)``: Groups an expression.
-
-.. note::
-
- Twig also support bitwise operators (``b-and``, ``b-xor``, and ``b-or``).
-
-Comparisons
-~~~~~~~~~~~
-
-The following comparison operators are supported in any expression: ``==``,
-``!=``, ``<``, ``>``, ``>=``, and ``<=``.
-
-Containment Operator
-~~~~~~~~~~~~~~~~~~~~
-
-The ``in`` operator performs containment test.
-
-It returns ``true`` if the left operand is contained in the right:
-
-.. code-block:: jinja
-
- {# returns true #}
-
- {{ 1 in [1, 2, 3] }}
-
- {{ 'cd' in 'abcde' }}
-
-.. tip::
-
- You can use this filter to perform a containment test on strings, arrays,
- or objects implementing the ``Traversable`` interface.
-
-To perform a negative test, use the ``not in`` operator:
-
-.. code-block:: jinja
-
- {% if 1 not in [1, 2, 3] %}
-
- {# is equivalent to #}
- {% if not (1 in [1, 2, 3]) %}
-
-Test Operator
-~~~~~~~~~~~~~
-
-The ``is`` operator performs tests. Tests can be used to test a variable against
-a common expression. The right operand is name of the test:
-
-.. code-block:: jinja
-
- {# find out if a variable is odd #}
-
- {{ name is odd }}
-
-Tests can accept arguments too:
-
-.. code-block:: jinja
-
- {% if loop.index is divisibleby(3) %}
-
-Tests can be negated by using the ``is not`` operator:
-
-.. code-block:: jinja
-
- {% if loop.index is not divisibleby(3) %}
-
- {# is equivalent to #}
- {% if not (loop.index is divisibleby(3)) %}
-
-Go to the :doc:`tests<tests/index>` page to learn more about the built-in
-tests.
-
-Other Operators
-~~~~~~~~~~~~~~~
-
-.. versionadded:: 1.12.0
- Support for the extended ternary operator was added in Twig 1.12.0.
-
-The following operators are very useful but don't fit into any of the other
-categories:
-
-* ``..``: Creates a sequence based on the operand before and after the
- operator (this is just syntactic sugar for the :doc:`range<functions/range>`
- function).
-
-* ``|``: Applies a filter.
-
-* ``~``: Converts all operands into strings and concatenates them. ``{{ "Hello
- " ~ name ~ "!" }}`` would return (assuming ``name`` is ``'John'``) ``Hello
- John!``.
-
-* ``.``, ``[]``: Gets an attribute of an object.
-
-* ``?:``: The ternary operator:
-
- .. code-block:: jinja
-
- {{ foo ? 'yes' : 'no' }}
-
- {# as of Twig 1.12.0 #}
- {{ foo ?: 'no' }} == {{ foo ? foo : 'no' }}
- {{ foo ? 'yes' }} == {{ foo ? 'yes' : '' }}
-
-String Interpolation
-~~~~~~~~~~~~~~~~~~~~
-
-.. versionadded:: 1.5
- String interpolation was added in Twig 1.5.
-
-String interpolation (`#{expression}`) allows any valid expression to appear
-within a *double-quoted string*. The result of evaluating that expression is
-inserted into the string:
-
-.. code-block:: jinja
-
- {{ "foo #{bar} baz" }}
- {{ "foo #{1 + 2} baz" }}
-
-Whitespace Control
-------------------
-
-.. versionadded:: 1.1
- Tag level whitespace control was added in Twig 1.1.
-
-The first newline after a template tag is removed automatically (like in PHP.)
-Whitespace is not further modified by the template engine, so each whitespace
-(spaces, tabs, newlines etc.) is returned unchanged.
-
-Use the ``spaceless`` tag to remove whitespace *between HTML tags*:
-
-.. code-block:: jinja
-
- {% spaceless %}
- <div>
- <strong>foo bar</strong>
- </div>
- {% endspaceless %}
-
- {# output will be <div><strong>foo bar</strong></div> #}
-
-In addition to the spaceless tag you can also control whitespace on a per tag
-level. By using the whitespace control modifier on your tags, you can trim
-leading and or trailing whitespace:
-
-.. code-block:: jinja
-
- {% set value = 'no spaces' %}
- {#- No leading/trailing whitespace -#}
- {%- if true -%}
- {{- value -}}
- {%- endif -%}
-
- {# output 'no spaces' #}
-
-The above sample shows the default whitespace control modifier, and how you can
-use it to remove whitespace around tags. Trimming space will consume all whitespace
-for that side of the tag. It is possible to use whitespace trimming on one side
-of a tag:
-
-.. code-block:: jinja
-
- {% set value = 'no spaces' %}
- <li> {{- value }} </li>
-
- {# outputs '<li>no spaces </li>' #}
-
-Extensions
-----------
-
-Twig can be easily extended.
-
-If you are looking for new tags, filters, or functions, have a look at the Twig official
-`extension repository`_.
-
-If you want to create your own, read the :ref:`Creating an
-Extension<creating_extensions>` chapter.
-
-.. _`Twig bundle`: https://github.com/Anomareh/PHP-Twig.tmbundle
-.. _`Jinja syntax plugin`: http://jinja.pocoo.org/2/documentation/integration
-.. _`Twig syntax plugin`: http://plugins.netbeans.org/plugin/37069/php-twig
-.. _`Twig plugin`: https://github.com/pulse00/Twig-Eclipse-Plugin
-.. _`Twig language definition`: https://github.com/gabrielcorpse/gedit-twig-template-language
-.. _`extension repository`: http://github.com/fabpot/Twig-extensions
-.. _`Twig syntax mode`: https://github.com/bobthecow/Twig-HTML.mode
-.. _`other Twig syntax mode`: https://github.com/muxx/Twig-HTML.mode
-.. _`Notepad++ Twig Highlighter`: https://github.com/Banane9/notepadplusplus-twig
-.. _`web-mode.el`: http://web-mode.org/
+++ /dev/null
-``constant``
-============
-
-.. versionadded: 1.13.1
- constant now accepts object instances as the second argument.
-
-``constant`` checks if a variable has the exact same value as a constant. You
-can use either global constants or class constants:
-
-.. code-block:: jinja
-
- {% if post.status is constant('Post::PUBLISHED') %}
- the status attribute is exactly the same as Post::PUBLISHED
- {% endif %}
-
-You can test constants from object instances as well:
-
-.. code-block:: jinja
-
- {% if post.status is constant('PUBLISHED', post) %}
- the status attribute is exactly the same as Post::PUBLISHED
- {% endif %}
+++ /dev/null
-``defined``
-===========
-
-``defined`` checks if a variable is defined in the current context. This is very
-useful if you use the ``strict_variables`` option:
-
-.. code-block:: jinja
-
- {# defined works with variable names #}
- {% if foo is defined %}
- ...
- {% endif %}
-
- {# and attributes on variables names #}
- {% if foo.bar is defined %}
- ...
- {% endif %}
-
- {% if foo['bar'] is defined %}
- ...
- {% endif %}
-
-When using the ``defined`` test on an expression that uses variables in some
-method calls, be sure that they are all defined first:
-
-.. code-block:: jinja
-
- {% if var is defined and foo.method(var) is defined %}
- ...
- {% endif %}
+++ /dev/null
-``divisibleby``
-===============
-
-``divisibleby`` checks if a variable is divisible by a number:
-
-.. code-block:: jinja
-
- {% if loop.index is divisibleby(3) %}
- ...
- {% endif %}
+++ /dev/null
-``empty``
-=========
-
-``empty`` checks if a variable is empty:
-
-.. code-block:: jinja
-
- {# evaluates to true if the foo variable is null, false, an empty array, or the empty string #}
- {% if foo is empty %}
- ...
- {% endif %}
+++ /dev/null
-``even``
-========
-
-``even`` returns ``true`` if the given number is even:
-
-.. code-block:: jinja
-
- {{ var is even }}
-
-.. seealso:: :doc:`odd<../tests/odd>`
+++ /dev/null
-Tests
-=====
-
-.. toctree::
- :maxdepth: 1
-
- constant
- defined
- divisibleby
- empty
- even
- iterable
- null
- odd
- sameas
+++ /dev/null
-``iterable``
-============
-
-.. versionadded:: 1.7
- The iterable test was added in Twig 1.7.
-
-``iterable`` checks if a variable is an array or a traversable object:
-
-.. code-block:: jinja
-
- {# evaluates to true if the foo variable is iterable #}
- {% if users is iterable %}
- {% for user in users %}
- Hello {{ user }}!
- {% endfor %}
- {% else %}
- {# users is probably a string #}
- Hello {{ users }}!
- {% endif %}
+++ /dev/null
-``null``
-========
-
-``null`` returns ``true`` if the variable is ``null``:
-
-.. code-block:: jinja
-
- {{ var is null }}
-
-.. note::
-
- ``none`` is an alias for ``null``.
+++ /dev/null
-``odd``
-=======
-
-``odd`` returns ``true`` if the given number is odd:
-
-.. code-block:: jinja
-
- {{ var is odd }}
-
-.. seealso:: :doc:`even<../tests/even>`
+++ /dev/null
-``sameas``
-==========
-
-``sameas`` checks if a variable points to the same memory address than another
-variable:
-
-.. code-block:: jinja
-
- {% if foo.attribute is sameas(false) %}
- the foo attribute really is the ``false`` PHP value
- {% endif %}
+++ /dev/null
-*.sw*
-.deps
-Makefile
-Makefile.fragments
-Makefile.global
-Makefile.objects
-acinclude.m4
-aclocal.m4
-build/
-config.cache
-config.guess
-config.h
-config.h.in
-config.log
-config.nice
-config.status
-config.sub
-configure
-configure.in
-install-sh
-libtool
-ltmain.sh
-missing
-mkinstalldirs
-run-tests.php
-twig.loT
-.libs/
-modules/
-twig.la
-twig.lo
+++ /dev/null
-Copyright (c) 2011, Derick Rethans <derick@derickrethans.nl>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+++ /dev/null
-dnl config.m4 for extension twig
-
-PHP_ARG_ENABLE(twig, whether to enable twig support,
-[ --enable-twig Enable twig support])
-
-if test "$PHP_TWIG" != "no"; then
- PHP_NEW_EXTENSION(twig, twig.c, $ext_shared)
-fi
+++ /dev/null
-// vim:ft=javascript
-
-ARG_ENABLE("twig", "Twig support", "no");
-
-if (PHP_TWIG != "no") {
- AC_DEFINE('HAVE_TWIG', 1);
- EXTENSION('twig', 'twig.c');
-}
+++ /dev/null
-/*
- +----------------------------------------------------------------------+
- | Twig Extension |
- +----------------------------------------------------------------------+
- | Copyright (c) 2011 Derick Rethans |
- +----------------------------------------------------------------------+
- | Redistribution and use in source and binary forms, with or without |
- | modification, are permitted provided that the conditions mentioned |
- | in the accompanying LICENSE file are met (BSD, revised). |
- +----------------------------------------------------------------------+
- | Author: Derick Rethans <derick@derickrethans.nl> |
- +----------------------------------------------------------------------+
- */
-
-#ifndef PHP_TWIG_H
-#define PHP_TWIG_H
-
-#define PHP_TWIG_VERSION "1.13.2"
-
-#include "php.h"
-
-extern zend_module_entry twig_module_entry;
-#define phpext_twig_ptr &twig_module_entry
-
-#ifdef ZTS
-#include "TSRM.h"
-#endif
-
-PHP_FUNCTION(twig_template_get_attributes);
-
-#endif
+++ /dev/null
-/*
- +----------------------------------------------------------------------+
- | Twig Extension |
- +----------------------------------------------------------------------+
- | Copyright (c) 2011 Derick Rethans |
- +----------------------------------------------------------------------+
- | Redistribution and use in source and binary forms, with or without |
- | modification, are permitted provided that the conditions mentioned |
- | in the accompanying LICENSE file are met (BSD, revised). |
- +----------------------------------------------------------------------+
- | Author: Derick Rethans <derick@derickrethans.nl> |
- +----------------------------------------------------------------------+
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_twig.h"
-#include "ext/standard/php_string.h"
-#include "ext/standard/php_smart_str.h"
-
-#include "Zend/zend_object_handlers.h"
-#include "Zend/zend_interfaces.h"
-#include "Zend/zend_exceptions.h"
-
-#ifndef Z_ADDREF_P
-#define Z_ADDREF_P(pz) (pz)->refcount++
-#endif
-
-#define FREE_DTOR(z) \
- zval_dtor(z); \
- efree(z);
-
-#if PHP_VERSION_ID >= 50300
- #define APPLY_TSRMLS_DC TSRMLS_DC
- #define APPLY_TSRMLS_CC TSRMLS_CC
- #define APPLY_TSRMLS_FETCH()
-#else
- #define APPLY_TSRMLS_DC
- #define APPLY_TSRMLS_CC
- #define APPLY_TSRMLS_FETCH() TSRMLS_FETCH()
-#endif
-
-ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 6)
- ZEND_ARG_INFO(0, template)
- ZEND_ARG_INFO(0, object)
- ZEND_ARG_INFO(0, item)
- ZEND_ARG_INFO(0, arguments)
- ZEND_ARG_INFO(0, type)
- ZEND_ARG_INFO(0, isDefinedTest)
-ZEND_END_ARG_INFO()
-
-zend_function_entry twig_functions[] = {
- PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args)
- {NULL, NULL, NULL}
-};
-
-
-zend_module_entry twig_module_entry = {
- STANDARD_MODULE_HEADER,
- "twig",
- twig_functions,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- PHP_TWIG_VERSION,
- STANDARD_MODULE_PROPERTIES
-};
-
-
-#ifdef COMPILE_DL_TWIG
-ZEND_GET_MODULE(twig)
-#endif
-
-int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
-{
- zval temp;
- int result;
-
- if (Z_TYPE_P(array) != IS_ARRAY) {
- return 0;
- }
-
- switch (Z_TYPE_P(key)) {
- case IS_NULL:
- return zend_hash_exists(Z_ARRVAL_P(array), "", 1);
-
- case IS_BOOL:
- case IS_DOUBLE:
- convert_to_long(key);
- case IS_LONG:
- return zend_hash_index_exists(Z_ARRVAL_P(array), Z_LVAL_P(key));
-
- default:
- convert_to_string(key);
- return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1);
- }
-}
-
-int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
-{
- if (Z_TYPE_P(object) != IS_OBJECT) {
- return 0;
- }
- return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC);
-}
-
-int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
-{
- zend_class_entry **pce;
- if (Z_TYPE_P(object) != IS_OBJECT) {
- return 0;
- }
- if (zend_lookup_class(interface, strlen(interface), &pce TSRMLS_CC) == FAILURE) {
- return 0;
- }
- return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC);
-}
-
-zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
-{
- zend_class_entry *ce = Z_OBJCE_P(object);
- zval *retval;
-
- if (Z_TYPE_P(object) == IS_OBJECT) {
- SEPARATE_ARG_IF_REF(offset);
- zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
-
- zval_ptr_dtor(&offset);
-
- if (!retval) {
- if (!EG(exception)) {
- zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
- }
- return NULL;
- }
-
- return retval;
- }
- return NULL;
-}
-
-int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
-{
- zend_class_entry *ce = Z_OBJCE_P(object);
- zval *retval;
-
- if (Z_TYPE_P(object) == IS_OBJECT) {
- SEPARATE_ARG_IF_REF(offset);
- zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
-
- zval_ptr_dtor(&offset);
-
- if (!retval) {
- if (!EG(exception)) {
- zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
- }
- return 0;
- }
-
- return (retval && Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval));
- }
- return 0;
-}
-
-char *TWIG_STRTOLOWER(const char *str, int str_len)
-{
- char *item_dup;
-
- item_dup = estrndup(str, str_len);
- php_strtolower(item_dup, str_len);
- return item_dup;
-}
-
-zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
-{
- zend_fcall_info fci;
- zval ***args = NULL;
- int arg_count = 0;
- HashTable *table;
- HashPosition pos;
- int i = 0;
- zval *retval_ptr;
- zval *zfunction;
-
- if (arguments) {
- table = HASH_OF(arguments);
- args = safe_emalloc(sizeof(zval **), table->nNumOfElements, 0);
-
- zend_hash_internal_pointer_reset_ex(table, &pos);
-
- while (zend_hash_get_current_data_ex(table, (void **)&args[i], &pos) == SUCCESS) {
- i++;
- zend_hash_move_forward_ex(table, &pos);
- }
- arg_count = table->nNumOfElements;
- }
-
- MAKE_STD_ZVAL(zfunction);
- ZVAL_STRING(zfunction, function, 1);
- fci.size = sizeof(fci);
- fci.function_table = EG(function_table);
- fci.function_name = zfunction;
- fci.symbol_table = NULL;
-#if PHP_VERSION_ID >= 50300
- fci.object_ptr = object;
-#else
- fci.object_pp = &object;
-#endif
- fci.retval_ptr_ptr = &retval_ptr;
- fci.param_count = arg_count;
- fci.params = args;
- fci.no_separation = 0;
-
- if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
- ALLOC_INIT_ZVAL(retval_ptr);
- ZVAL_BOOL(retval_ptr, 0);
- }
-
- if (args) {
- efree(fci.params);
- }
- FREE_DTOR(zfunction);
- return retval_ptr;
-}
-
-int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
-{
- zval *ret;
- int res;
-
- ret = TWIG_CALL_USER_FUNC_ARRAY(object, functionName, NULL TSRMLS_CC);
- res = Z_LVAL_P(ret);
- zval_ptr_dtor(&ret);
- return res;
-}
-
-zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
-{
- zval **tmp_zval;
- zend_class_entry *ce;
-
- if (class == NULL || Z_TYPE_P(class) != IS_OBJECT) {
- return NULL;
- }
-
- ce = zend_get_class_entry(class TSRMLS_CC);
-#if PHP_VERSION_ID >= 50400
- tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0, NULL TSRMLS_CC);
-#else
- tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0 TSRMLS_CC);
-#endif
- return *tmp_zval;
-}
-
-zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
-{
- zval **tmp_zval;
- char *tmp_name;
-
- if (class == NULL || Z_TYPE_P(class) != IS_ARRAY) {
- if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
- // array access object
- return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC);
- }
- return NULL;
- }
-
- switch(Z_TYPE_P(prop_name)) {
- case IS_NULL:
- zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval);
- return *tmp_zval;
-
- case IS_BOOL:
- case IS_DOUBLE:
- convert_to_long(prop_name);
- case IS_LONG:
- zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name), (void **) &tmp_zval);
- return *tmp_zval;
-
- case IS_STRING:
- zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name) + 1, (void**) &tmp_zval);
- return *tmp_zval;
- }
-
- return NULL;
-}
-
-zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
-{
- zval **tmp_zval;
-
- if (class == NULL/* || Z_TYPE_P(class) != IS_ARRAY*/) {
- return NULL;
- }
-
- if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
- // array access object
- zval *tmp_name_zval;
- zval *tmp_ret_zval;
-
- ALLOC_INIT_ZVAL(tmp_name_zval);
- ZVAL_STRING(tmp_name_zval, prop_name, 1);
- tmp_ret_zval = TWIG_GET_ARRAYOBJECT_ELEMENT(class, tmp_name_zval TSRMLS_CC);
- FREE_DTOR(tmp_name_zval);
- return tmp_ret_zval;
- }
-
- if (zend_symtable_find(HASH_OF(class), prop_name, prop_name_length+1, (void**)&tmp_zval) == SUCCESS) {
- return *tmp_zval;
- }
- return NULL;
-}
-
-zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
-{
- zval *tmp = NULL;
-
- if (Z_OBJ_HT_P(object)->read_property) {
-#if PHP_VERSION_ID >= 50400
- tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS, NULL TSRMLS_CC);
-#else
- tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS TSRMLS_CC);
-#endif
- if (tmp != EG(uninitialized_zval_ptr)) {
- return tmp;
- } else {
- return NULL;
- }
- }
- return tmp;
-}
-
-int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
-{
- if (Z_OBJ_HT_P(object)->has_property) {
-#if PHP_VERSION_ID >= 50400
- return Z_OBJ_HT_P(object)->has_property(object, propname, 0, NULL TSRMLS_CC);
-#else
- return Z_OBJ_HT_P(object)->has_property(object, propname, 0 TSRMLS_CC);
-#endif
- }
- return 0;
-}
-
-int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
-{
- if (Z_OBJ_HT_P(object)->get_properties) {
- return zend_hash_quick_exists(
- Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), // the properties hash
- prop, // property name
- prop_len + 1, // property length
- zend_get_hash_value(prop, prop_len + 1) // hash value
- );
- }
- return 0;
-}
-
-zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
-{
- zval *tmp_name_zval, *tmp;
-
- ALLOC_INIT_ZVAL(tmp_name_zval);
- ZVAL_STRING(tmp_name_zval, propname, 1);
- tmp = TWIG_PROPERTY(object, tmp_name_zval TSRMLS_CC);
- FREE_DTOR(tmp_name_zval);
- return tmp;
-}
-
-int TWIG_CALL_B_0(zval *object, char *method)
-{
- return 0;
-}
-
-zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
-{
- zend_fcall_info fci;
- zval **args[1];
- zval *argument;
- zval *zfunction;
- zval *retval_ptr;
-
- MAKE_STD_ZVAL(argument);
- ZVAL_STRING(argument, arg0, 1);
- args[0] = &argument;
-
- MAKE_STD_ZVAL(zfunction);
- ZVAL_STRING(zfunction, method, 1);
- fci.size = sizeof(fci);
- fci.function_table = EG(function_table);
- fci.function_name = zfunction;
- fci.symbol_table = NULL;
-#if PHP_VERSION_ID >= 50300
- fci.object_ptr = object;
-#else
- fci.object_pp = &object;
-#endif
- fci.retval_ptr_ptr = &retval_ptr;
- fci.param_count = 1;
- fci.params = args;
- fci.no_separation = 0;
-
- if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
- FREE_DTOR(zfunction);
- zval_ptr_dtor(&argument);
- return 0;
- }
- FREE_DTOR(zfunction);
- zval_ptr_dtor(&argument);
- return retval_ptr;
-}
-
-int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
-{
- zval *retval_ptr;
- int success;
-
- retval_ptr = TWIG_CALL_S(object, method, arg0 TSRMLS_CC);
- success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
-
- if (retval_ptr) {
- zval_ptr_dtor(&retval_ptr);
- }
-
- return success;
-}
-
-int TWIG_CALL_Z(zval *object, char *method, zval *arg1 TSRMLS_DC)
-{
- zend_fcall_info fci;
- zval **args[1];
- zval *zfunction;
- zval *retval_ptr;
- int success;
-
- args[0] = &arg1;
-
- MAKE_STD_ZVAL(zfunction);
- ZVAL_STRING(zfunction, method, 1);
- fci.size = sizeof(fci);
- fci.function_table = EG(function_table);
- fci.function_name = zfunction;
- fci.symbol_table = NULL;
-#if PHP_VERSION_ID >= 50300
- fci.object_ptr = object;
-#else
- fci.object_pp = &object;
-#endif
- fci.retval_ptr_ptr = &retval_ptr;
- fci.param_count = 1;
- fci.params = args;
- fci.no_separation = 0;
-
- if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
- FREE_DTOR(zfunction);
- if (retval_ptr) {
- zval_ptr_dtor(&retval_ptr);
- }
- return 0;
- }
-
- FREE_DTOR(zfunction);
-
- success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
- if (retval_ptr) {
- zval_ptr_dtor(&retval_ptr);
- }
-
- return success;
-}
-
-int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
-{
- zend_fcall_info fci;
- zval **args[2];
- zval *zfunction;
- zval *retval_ptr;
- int success;
-
- args[0] = &arg1;
- args[1] = &arg2;
-
- MAKE_STD_ZVAL(zfunction);
- ZVAL_STRING(zfunction, method, 1);
- fci.size = sizeof(fci);
- fci.function_table = EG(function_table);
- fci.function_name = zfunction;
- fci.symbol_table = NULL;
-#if PHP_VERSION_ID >= 50300
- fci.object_ptr = object;
-#else
- fci.object_pp = &object;
-#endif
- fci.retval_ptr_ptr = &retval_ptr;
- fci.param_count = 2;
- fci.params = args;
- fci.no_separation = 0;
-
- if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
- FREE_DTOR(zfunction);
- return 0;
- }
-
- FREE_DTOR(zfunction);
-
- success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
- if (retval_ptr) {
- zval_ptr_dtor(&retval_ptr);
- }
-
- return success;
-}
-
-#ifndef Z_SET_REFCOUNT_P
-# define Z_SET_REFCOUNT_P(pz, rc) pz->refcount = rc
-# define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
-#endif
-
-void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
-{
- zend_class_entry **pce;
-
- if (zend_lookup_class(class, strlen(class), &pce TSRMLS_CC) == FAILURE) {
- return;
- }
-
- Z_TYPE_P(object) = IS_OBJECT;
- object_init_ex(object, *pce);
- Z_SET_REFCOUNT_P(object, 1);
- Z_UNSET_ISREF_P(object);
-
- TWIG_CALL_ZZ(object, "__construct", arg0, arg1 TSRMLS_CC);
-}
-
-static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
-{
- smart_str *buf;
- char *joiner;
- APPLY_TSRMLS_FETCH();
-
- buf = va_arg(args, smart_str*);
- joiner = va_arg(args, char*);
-
- if (buf->len != 0) {
- smart_str_appends(buf, joiner);
- }
-
- if (hash_key->nKeyLength == 0) {
- smart_str_append_long(buf, (long) hash_key->h);
- } else {
- char *key, *tmp_str;
- int key_len, tmp_len;
- key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC);
- tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL);
-
- smart_str_appendl(buf, tmp_str, tmp_len);
- efree(key);
- efree(tmp_str);
- }
-
- return 0;
-}
-
-char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
-{
- smart_str collector = { 0, 0, 0 };
-
- smart_str_appendl(&collector, "", 0);
- zend_hash_apply_with_arguments(HASH_OF(array) APPLY_TSRMLS_CC, twig_add_array_key_to_string, 2, &collector, joiner);
- smart_str_0(&collector);
-
- return collector.c;
-}
-
-static void TWIG_THROW_EXCEPTION(char *exception_name TSRMLS_DC, char *message, ...)
-{
- char *buffer;
- va_list args;
- zend_class_entry **pce;
-
- if (zend_lookup_class(exception_name, strlen(exception_name), &pce TSRMLS_CC) == FAILURE) {
- return;
- }
-
- va_start(args, message);
- vspprintf(&buffer, 0, message, args);
- va_end(args);
-
- zend_throw_exception_ex(*pce, 0 TSRMLS_CC, buffer);
- efree(buffer);
-}
-
-static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...)
-{
- char *buffer;
- va_list args;
- zend_class_entry **pce;
- zval *ex;
- zval *constructor;
- zval *zmessage;
- zval *lineno;
- zval *filename_func;
- zval *filename;
- zval *constructor_args[3];
- zval *constructor_retval;
-
- if (zend_lookup_class("Twig_Error_Runtime", strlen("Twig_Error_Runtime"), &pce TSRMLS_CC) == FAILURE) {
- return;
- }
-
- va_start(args, message);
- vspprintf(&buffer, 0, message, args);
- va_end(args);
-
- MAKE_STD_ZVAL(ex);
- object_init_ex(ex, *pce);
-
- // Call Twig_Error constructor
- MAKE_STD_ZVAL(constructor);
- MAKE_STD_ZVAL(zmessage);
- MAKE_STD_ZVAL(lineno);
- MAKE_STD_ZVAL(filename);
- MAKE_STD_ZVAL(filename_func);
- MAKE_STD_ZVAL(constructor_retval);
-
- ZVAL_STRINGL(constructor, "__construct", sizeof("__construct")-1, 1);
- ZVAL_STRING(zmessage, buffer, 1);
- ZVAL_LONG(lineno, -1);
-
- // Get template filename
- ZVAL_STRINGL(filename_func, "getTemplateName", sizeof("getTemplateName")-1, 1);
- call_user_function(EG(function_table), &template, filename_func, filename, 0, 0 TSRMLS_CC);
-
- constructor_args[0] = zmessage;
- constructor_args[1] = lineno;
- constructor_args[2] = filename;
- call_user_function(EG(function_table), &ex, constructor, constructor_retval, 3, constructor_args TSRMLS_CC);
-
- zval_ptr_dtor(&constructor_retval);
- zval_ptr_dtor(&zmessage);
- zval_ptr_dtor(&lineno);
- zval_ptr_dtor(&filename);
- FREE_DTOR(constructor);
- FREE_DTOR(filename_func);
- efree(buffer);
-
- zend_throw_exception_object(ex TSRMLS_CC);
-}
-
-static char *TWIG_GET_CLASS_NAME(zval *object TSRMLS_DC)
-{
- char *class_name;
- zend_uint class_name_len;
-
- if (Z_TYPE_P(object) != IS_OBJECT) {
- return "";
- }
-#if PHP_API_VERSION >= 20100412
- zend_get_object_classname(object, (const char **) &class_name, &class_name_len TSRMLS_CC);
-#else
- zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
-#endif
- return class_name;
-}
-
-static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
-{
- zval *retval;
- char *item;
- size_t item_len;
- zend_function *mptr = (zend_function *) pDest;
- APPLY_TSRMLS_FETCH();
-
- if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)) {
- return 0;
- }
-
- retval = va_arg(args, zval*);
-
- item_len = strlen(mptr->common.function_name);
- item = estrndup(mptr->common.function_name, item_len);
- php_strtolower(item, item_len);
-
- add_assoc_stringl_ex(retval, item, item_len+1, item, item_len, 0);
-
- return 0;
-}
-
-static int twig_add_property_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
-{
- zend_class_entry *ce;
- zval *retval;
- char *class_name, *prop_name;
- zend_property_info *pptr = (zend_property_info *) pDest;
- APPLY_TSRMLS_FETCH();
-
- if (!(pptr->flags & ZEND_ACC_PUBLIC)) {
- return 0;
- }
-
- ce = *va_arg(args, zend_class_entry**);
- retval = va_arg(args, zval*);
-
-#if PHP_API_VERSION >= 20100412
- zend_unmangle_property_name(pptr->name, pptr->name_length, (const char **) &class_name, (const char **) &prop_name);
-#else
- zend_unmangle_property_name(pptr->name, pptr->name_length, &class_name, &prop_name);
-#endif
-
- add_assoc_string(retval, prop_name, prop_name, 1);
-
- return 0;
-}
-
-static void twig_add_class_to_cache(zval *cache, zval *object, char *class_name TSRMLS_DC)
-{
- zval *class_info, *class_methods, *class_properties;
- zend_class_entry *class_ce;
-
- class_ce = zend_get_class_entry(object TSRMLS_CC);
-
- ALLOC_INIT_ZVAL(class_info);
- ALLOC_INIT_ZVAL(class_methods);
- ALLOC_INIT_ZVAL(class_properties);
- array_init(class_info);
- array_init(class_methods);
- array_init(class_properties);
- // add all methods to self::cache[$class]['methods']
- zend_hash_apply_with_arguments(&class_ce->function_table APPLY_TSRMLS_CC, twig_add_method_to_class, 1, class_methods);
- zend_hash_apply_with_arguments(&class_ce->properties_info APPLY_TSRMLS_CC, twig_add_property_to_class, 2, &class_ce, class_properties);
-
- add_assoc_zval(class_info, "methods", class_methods);
- add_assoc_zval(class_info, "properties", class_properties);
- add_assoc_zval(cache, class_name, class_info);
-}
-
-/* {{{ proto mixed twig_template_get_attributes(TwigTemplate template, mixed object, mixed item, array arguments, string type, boolean isDefinedTest, boolean ignoreStrictCheck)
- A C implementation of TwigTemplate::getAttribute() */
-PHP_FUNCTION(twig_template_get_attributes)
-{
- zval *template;
- zval *object;
- char *item;
- int item_len;
- zval *zitem, ztmpitem;
- zval *arguments = NULL;
- zval *ret = NULL;
- char *type = NULL;
- int type_len = 0;
- zend_bool isDefinedTest = 0;
- zend_bool ignoreStrictCheck = 0;
- int free_ret = 0;
- zval *tmp_self_cache;
-
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &zitem, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) {
- return;
- }
-
- // convert the item to a string
- ztmpitem = *zitem;
- zval_copy_ctor(&ztmpitem);
- convert_to_string(&ztmpitem);
- item_len = Z_STRLEN(ztmpitem);
- item = estrndup(Z_STRVAL(ztmpitem), item_len);
- zval_dtor(&ztmpitem);
-
- if (!type) {
- type = "any";
- }
-
-/*
- // array
- if (Twig_TemplateInterface::METHOD_CALL !== $type) {
- $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
-
- if ((is_array($object) && array_key_exists($arrayItem, $object))
- || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
- ) {
- if ($isDefinedTest) {
- return true;
- }
-
- return $object[$arrayItem];
- }
-*/
-
-
- if (strcmp("method", type) != 0) {
- if ((TWIG_ARRAY_KEY_EXISTS(object, zitem))
- || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, zitem TSRMLS_CC))
- ) {
-
- if (isDefinedTest) {
- RETURN_TRUE;
- }
-
- ret = TWIG_GET_ARRAY_ELEMENT_ZVAL(object, zitem TSRMLS_CC);
-
- if (!ret) {
- ret = &EG(uninitialized_zval);
- }
- RETVAL_ZVAL(ret, 1, 0);
- if (free_ret) {
- zval_ptr_dtor(&ret);
- }
- return;
- }
-/*
- if (Twig_TemplateInterface::ARRAY_CALL === $type) {
- if ($isDefinedTest) {
- return false;
- }
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
- return null;
- }
-*/
- if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
- if (isDefinedTest) {
- RETURN_FALSE;
- }
- if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
- return;
- }
-/*
- if (is_object($object)) {
- throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
- } elseif (is_array($object)) {
- throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
- } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
- throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
- } else {
- throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
- }
- }
- }
-*/
- if (Z_TYPE_P(object) == IS_OBJECT) {
- TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" in object (with ArrayAccess) of type \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
- } else if (Z_TYPE_P(object) == IS_ARRAY) {
- TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
- } else {
- char *type_name = zend_zval_type_name(object);
- Z_ADDREF_P(object);
- convert_to_string(object);
- TWIG_RUNTIME_ERROR(template TSRMLS_CC,
- (strcmp("array", type) == 0)
- ? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")"
- : "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")",
- item, type_name, Z_STRVAL_P(object));
- zval_ptr_dtor(&object);
- }
- return;
- }
- }
-
-/*
- if (!is_object($object)) {
- if ($isDefinedTest) {
- return false;
- }
-*/
-
- if (Z_TYPE_P(object) != IS_OBJECT) {
- if (isDefinedTest) {
- RETURN_FALSE;
- }
-/*
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
- return null;
- }
- throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
- }
-*/
- if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
- return;
- }
-
- char *type_name = zend_zval_type_name(object);
- Z_ADDREF_P(object);
- convert_to_string_ex(&object);
-
- TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
-
- zval_ptr_dtor(&object);
-
- return;
- }
-/*
- $class = get_class($object);
-*/
- char *class_name = NULL;
- zval *tmp_class;
-
- class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
- tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC);
- tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
-
- if (!tmp_class) {
- twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC);
- tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
- }
- efree(class_name);
-
-/*
- // object property
- if (Twig_TemplateInterface::METHOD_CALL !== $type) {
- if (isset($object->$item) || array_key_exists((string) $item, $object)) {
- if ($isDefinedTest) {
- return true;
- }
-
- if ($this->env->hasExtension('sandbox')) {
- $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
- }
-
- return $object->$item;
- }
- }
-*/
- if (strcmp("method", type) != 0) {
- zval *tmp_properties, *tmp_item;
-
- tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC);
- tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC);
-
- if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
- if (isDefinedTest) {
- RETURN_TRUE;
- }
- if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
- TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
- }
- if (EG(exception)) {
- return;
- }
-
- ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
- RETURN_ZVAL(ret, 1, 0);
- }
- }
-/*
- // object method
- if (!isset(self::$cache[$class]['methods'])) {
- self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
- }
-
- $lcItem = strtolower($item);
- if (isset(self::$cache[$class]['methods'][$lcItem])) {
- $method = (string) $item;
- } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
- $method = 'get'.$item;
- } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
- $method = 'is'.$item;
- } elseif (isset(self::$cache[$class]['methods']['__call'])) {
- $method = (string) $item;
-*/
- {
- char *lcItem = TWIG_STRTOLOWER(item, item_len);
- int lcItem_length;
- char *method = NULL;
- char *tmp_method_name_get;
- char *tmp_method_name_is;
- zval *tmp_methods;
-
- lcItem_length = strlen(lcItem);
- tmp_method_name_get = emalloc(4 + lcItem_length);
- tmp_method_name_is = emalloc(3 + lcItem_length);
-
- sprintf(tmp_method_name_get, "get%s", lcItem);
- sprintf(tmp_method_name_is, "is%s", lcItem);
-
- tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC);
-
- if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) {
- method = item;
- } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_get, lcItem_length + 3 TSRMLS_CC)) {
- method = tmp_method_name_get;
- } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_is, lcItem_length + 2 TSRMLS_CC)) {
- method = tmp_method_name_is;
- } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) {
- method = item;
-/*
- } else {
- if ($isDefinedTest) {
- return false;
- }
-
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
- return null;
- }
-
- throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
- }
-
- if ($isDefinedTest) {
- return true;
- }
-*/
- } else {
- efree(tmp_method_name_get);
- efree(tmp_method_name_is);
- efree(lcItem);
-
- if (isDefinedTest) {
- RETURN_FALSE;
- }
- if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
- return;
- }
- TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Method \"%s\" for object \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
- return;
- }
-
- if (isDefinedTest) {
- efree(tmp_method_name_get);
- efree(tmp_method_name_is);
- efree(lcItem);
- RETURN_TRUE;
- }
-/*
- if ($this->env->hasExtension('sandbox')) {
- $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
- }
-*/
- if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
- TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zitem TSRMLS_CC);
- }
- if (EG(exception)) {
- efree(tmp_method_name_get);
- efree(tmp_method_name_is);
- efree(lcItem);
- return;
- }
-/*
- $ret = call_user_func_array(array($object, $method), $arguments);
-*/
- ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
- free_ret = 1;
- efree(tmp_method_name_get);
- efree(tmp_method_name_is);
- efree(lcItem);
- }
-/*
- // useful when calling a template method from a template
- // this is not supported but unfortunately heavily used in the Symfony profiler
- if ($object instanceof Twig_TemplateInterface) {
- return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
- }
-
- return $ret;
-*/
- // ret can be null, if e.g. the called method throws an exception
- if (ret) {
- if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
- if (Z_STRLEN_P(ret) != 0) {
- zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC);
- TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC);
- zval_ptr_dtor(&charset);
- if (ret) {
- zval_ptr_dtor(&ret);
- }
- return;
- }
- }
-
- RETVAL_ZVAL(ret, 1, 0);
- if (free_ret) {
- zval_ptr_dtor(&ret);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Autoloads Twig classes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Autoloader
-{
- /**
- * Registers Twig_Autoloader as an SPL autoloader.
- *
- * @param Boolean $prepend Whether to prepend the autoloader or not.
- */
- public static function register($prepend = false)
- {
- if (version_compare(phpversion(), '5.3.0', '>=')) {
- spl_autoload_register(array(new self, 'autoload'), true, $prepend);
- } else {
- spl_autoload_register(array(new self, 'autoload'));
- }
- }
-
- /**
- * Handles autoloading of classes.
- *
- * @param string $class A class name.
- */
- public static function autoload($class)
- {
- if (0 !== strpos($class, 'Twig')) {
- return;
- }
-
- if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
- require $file;
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Compiles a node to PHP code.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Compiler implements Twig_CompilerInterface
-{
- protected $lastLine;
- protected $source;
- protected $indentation;
- protected $env;
- protected $debugInfo;
- protected $sourceOffset;
- protected $sourceLine;
- protected $filename;
-
- /**
- * Constructor.
- *
- * @param Twig_Environment $env The twig environment instance
- */
- public function __construct(Twig_Environment $env)
- {
- $this->env = $env;
- $this->debugInfo = array();
- }
-
- public function getFilename()
- {
- return $this->filename;
- }
-
- /**
- * Returns the environment instance related to this compiler.
- *
- * @return Twig_Environment The environment instance
- */
- public function getEnvironment()
- {
- return $this->env;
- }
-
- /**
- * Gets the current PHP code after compilation.
- *
- * @return string The PHP code
- */
- public function getSource()
- {
- return $this->source;
- }
-
- /**
- * Compiles a node.
- *
- * @param Twig_NodeInterface $node The node to compile
- * @param integer $indentation The current indentation
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function compile(Twig_NodeInterface $node, $indentation = 0)
- {
- $this->lastLine = null;
- $this->source = '';
- $this->sourceOffset = 0;
- // source code starts at 1 (as we then increment it when we encounter new lines)
- $this->sourceLine = 1;
- $this->indentation = $indentation;
-
- if ($node instanceof Twig_Node_Module) {
- $this->filename = $node->getAttribute('filename');
- }
-
- $node->compile($this);
-
- return $this;
- }
-
- public function subcompile(Twig_NodeInterface $node, $raw = true)
- {
- if (false === $raw) {
- $this->addIndentation();
- }
-
- $node->compile($this);
-
- return $this;
- }
-
- /**
- * Adds a raw string to the compiled code.
- *
- * @param string $string The string
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function raw($string)
- {
- $this->source .= $string;
-
- return $this;
- }
-
- /**
- * Writes a string to the compiled code by adding indentation.
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function write()
- {
- $strings = func_get_args();
- foreach ($strings as $string) {
- $this->addIndentation();
- $this->source .= $string;
- }
-
- return $this;
- }
-
- /**
- * Appends an indentation to the current PHP code after compilation.
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function addIndentation()
- {
- $this->source .= str_repeat(' ', $this->indentation * 4);
-
- return $this;
- }
-
- /**
- * Adds a quoted string to the compiled code.
- *
- * @param string $value The string
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function string($value)
- {
- $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
-
- return $this;
- }
-
- /**
- * Returns a PHP representation of a given value.
- *
- * @param mixed $value The value to convert
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function repr($value)
- {
- if (is_int($value) || is_float($value)) {
- if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
- setlocale(LC_NUMERIC, 'C');
- }
-
- $this->raw($value);
-
- if (false !== $locale) {
- setlocale(LC_NUMERIC, $locale);
- }
- } elseif (null === $value) {
- $this->raw('null');
- } elseif (is_bool($value)) {
- $this->raw($value ? 'true' : 'false');
- } elseif (is_array($value)) {
- $this->raw('array(');
- $i = 0;
- foreach ($value as $key => $value) {
- if ($i++) {
- $this->raw(', ');
- }
- $this->repr($key);
- $this->raw(' => ');
- $this->repr($value);
- }
- $this->raw(')');
- } else {
- $this->string($value);
- }
-
- return $this;
- }
-
- /**
- * Adds debugging information.
- *
- * @param Twig_NodeInterface $node The related twig node
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function addDebugInfo(Twig_NodeInterface $node)
- {
- if ($node->getLine() != $this->lastLine) {
- $this->write("// line {$node->getLine()}\n");
-
- // when mbstring.func_overload is set to 2
- // mb_substr_count() replaces substr_count()
- // but they have different signatures!
- if (((int) ini_get('mbstring.func_overload')) & 2) {
- // this is much slower than the "right" version
- $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
- } else {
- $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
- }
- $this->sourceOffset = strlen($this->source);
- $this->debugInfo[$this->sourceLine] = $node->getLine();
-
- $this->lastLine = $node->getLine();
- }
-
- return $this;
- }
-
- public function getDebugInfo()
- {
- return $this->debugInfo;
- }
-
- /**
- * Indents the generated code.
- *
- * @param integer $step The number of indentation to add
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function indent($step = 1)
- {
- $this->indentation += $step;
-
- return $this;
- }
-
- /**
- * Outdents the generated code.
- *
- * @param integer $step The number of indentation to remove
- *
- * @return Twig_Compiler The current compiler instance
- */
- public function outdent($step = 1)
- {
- // can't outdent by more steps than the current indentation level
- if ($this->indentation < $step) {
- throw new LogicException('Unable to call outdent() as the indentation would become negative');
- }
-
- $this->indentation -= $step;
-
- return $this;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by compiler classes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_CompilerInterface
-{
- /**
- * Compiles a node.
- *
- * @param Twig_NodeInterface $node The node to compile
- *
- * @return Twig_CompilerInterface The current compiler instance
- */
- public function compile(Twig_NodeInterface $node);
-
- /**
- * Gets the current PHP code after compilation.
- *
- * @return string The PHP code
- */
- public function getSource();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Stores the Twig configuration.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Environment
-{
- const VERSION = '1.13.2';
-
- protected $charset;
- protected $loader;
- protected $debug;
- protected $autoReload;
- protected $cache;
- protected $lexer;
- protected $parser;
- protected $compiler;
- protected $baseTemplateClass;
- protected $extensions;
- protected $parsers;
- protected $visitors;
- protected $filters;
- protected $tests;
- protected $functions;
- protected $globals;
- protected $runtimeInitialized;
- protected $extensionInitialized;
- protected $loadedTemplates;
- protected $strictVariables;
- protected $unaryOperators;
- protected $binaryOperators;
- protected $templateClassPrefix = '__TwigTemplate_';
- protected $functionCallbacks;
- protected $filterCallbacks;
- protected $staging;
-
- /**
- * Constructor.
- *
- * Available options:
- *
- * * debug: When set to true, it automatically set "auto_reload" to true as
- * well (default to false).
- *
- * * charset: The charset used by the templates (default to UTF-8).
- *
- * * base_template_class: The base template class to use for generated
- * templates (default to Twig_Template).
- *
- * * cache: An absolute path where to store the compiled templates, or
- * false to disable compilation cache (default).
- *
- * * auto_reload: Whether to reload the template is the original source changed.
- * If you don't provide the auto_reload option, it will be
- * determined automatically base on the debug value.
- *
- * * strict_variables: Whether to ignore invalid variables in templates
- * (default to false).
- *
- * * autoescape: Whether to enable auto-escaping (default to html):
- * * false: disable auto-escaping
- * * true: equivalent to html
- * * html, js: set the autoescaping to one of the supported strategies
- * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
- *
- * * optimizations: A flag that indicates which optimizations to apply
- * (default to -1 which means that all optimizations are enabled;
- * set it to 0 to disable).
- *
- * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
- * @param array $options An array of options
- */
- public function __construct(Twig_LoaderInterface $loader = null, $options = array())
- {
- if (null !== $loader) {
- $this->setLoader($loader);
- }
-
- $options = array_merge(array(
- 'debug' => false,
- 'charset' => 'UTF-8',
- 'base_template_class' => 'Twig_Template',
- 'strict_variables' => false,
- 'autoescape' => 'html',
- 'cache' => false,
- 'auto_reload' => null,
- 'optimizations' => -1,
- ), $options);
-
- $this->debug = (bool) $options['debug'];
- $this->charset = strtoupper($options['charset']);
- $this->baseTemplateClass = $options['base_template_class'];
- $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
- $this->strictVariables = (bool) $options['strict_variables'];
- $this->runtimeInitialized = false;
- $this->setCache($options['cache']);
- $this->functionCallbacks = array();
- $this->filterCallbacks = array();
-
- $this->addExtension(new Twig_Extension_Core());
- $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
- $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
- $this->extensionInitialized = false;
- $this->staging = new Twig_Extension_Staging();
- }
-
- /**
- * Gets the base template class for compiled templates.
- *
- * @return string The base template class name
- */
- public function getBaseTemplateClass()
- {
- return $this->baseTemplateClass;
- }
-
- /**
- * Sets the base template class for compiled templates.
- *
- * @param string $class The base template class name
- */
- public function setBaseTemplateClass($class)
- {
- $this->baseTemplateClass = $class;
- }
-
- /**
- * Enables debugging mode.
- */
- public function enableDebug()
- {
- $this->debug = true;
- }
-
- /**
- * Disables debugging mode.
- */
- public function disableDebug()
- {
- $this->debug = false;
- }
-
- /**
- * Checks if debug mode is enabled.
- *
- * @return Boolean true if debug mode is enabled, false otherwise
- */
- public function isDebug()
- {
- return $this->debug;
- }
-
- /**
- * Enables the auto_reload option.
- */
- public function enableAutoReload()
- {
- $this->autoReload = true;
- }
-
- /**
- * Disables the auto_reload option.
- */
- public function disableAutoReload()
- {
- $this->autoReload = false;
- }
-
- /**
- * Checks if the auto_reload option is enabled.
- *
- * @return Boolean true if auto_reload is enabled, false otherwise
- */
- public function isAutoReload()
- {
- return $this->autoReload;
- }
-
- /**
- * Enables the strict_variables option.
- */
- public function enableStrictVariables()
- {
- $this->strictVariables = true;
- }
-
- /**
- * Disables the strict_variables option.
- */
- public function disableStrictVariables()
- {
- $this->strictVariables = false;
- }
-
- /**
- * Checks if the strict_variables option is enabled.
- *
- * @return Boolean true if strict_variables is enabled, false otherwise
- */
- public function isStrictVariables()
- {
- return $this->strictVariables;
- }
-
- /**
- * Gets the cache directory or false if cache is disabled.
- *
- * @return string|false
- */
- public function getCache()
- {
- return $this->cache;
- }
-
- /**
- * Sets the cache directory or false if cache is disabled.
- *
- * @param string|false $cache The absolute path to the compiled templates,
- * or false to disable cache
- */
- public function setCache($cache)
- {
- $this->cache = $cache ? $cache : false;
- }
-
- /**
- * Gets the cache filename for a given template.
- *
- * @param string $name The template name
- *
- * @return string The cache file name
- */
- public function getCacheFilename($name)
- {
- if (false === $this->cache) {
- return false;
- }
-
- $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
-
- return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
- }
-
- /**
- * Gets the template class associated with the given string.
- *
- * @param string $name The name for which to calculate the template class name
- * @param integer $index The index if it is an embedded template
- *
- * @return string The template class name
- */
- public function getTemplateClass($name, $index = null)
- {
- return $this->templateClassPrefix.md5($this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
- }
-
- /**
- * Gets the template class prefix.
- *
- * @return string The template class prefix
- */
- public function getTemplateClassPrefix()
- {
- return $this->templateClassPrefix;
- }
-
- /**
- * Renders a template.
- *
- * @param string $name The template name
- * @param array $context An array of parameters to pass to the template
- *
- * @return string The rendered template
- */
- public function render($name, array $context = array())
- {
- return $this->loadTemplate($name)->render($context);
- }
-
- /**
- * Displays a template.
- *
- * @param string $name The template name
- * @param array $context An array of parameters to pass to the template
- */
- public function display($name, array $context = array())
- {
- $this->loadTemplate($name)->display($context);
- }
-
- /**
- * Loads a template by name.
- *
- * @param string $name The template name
- * @param integer $index The index if it is an embedded template
- *
- * @return Twig_TemplateInterface A template instance representing the given template name
- */
- public function loadTemplate($name, $index = null)
- {
- $cls = $this->getTemplateClass($name, $index);
-
- if (isset($this->loadedTemplates[$cls])) {
- return $this->loadedTemplates[$cls];
- }
-
- if (!class_exists($cls, false)) {
- if (false === $cache = $this->getCacheFilename($name)) {
- eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
- } else {
- if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
- $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
- }
-
- require_once $cache;
- }
- }
-
- if (!$this->runtimeInitialized) {
- $this->initRuntime();
- }
-
- return $this->loadedTemplates[$cls] = new $cls($this);
- }
-
- /**
- * Returns true if the template is still fresh.
- *
- * Besides checking the loader for freshness information,
- * this method also checks if the enabled extensions have
- * not changed.
- *
- * @param string $name The template name
- * @param timestamp $time The last modification time of the cached template
- *
- * @return Boolean true if the template is fresh, false otherwise
- */
- public function isTemplateFresh($name, $time)
- {
- foreach ($this->extensions as $extension) {
- $r = new ReflectionObject($extension);
- if (filemtime($r->getFileName()) > $time) {
- return false;
- }
- }
-
- return $this->getLoader()->isFresh($name, $time);
- }
-
- public function resolveTemplate($names)
- {
- if (!is_array($names)) {
- $names = array($names);
- }
-
- foreach ($names as $name) {
- if ($name instanceof Twig_Template) {
- return $name;
- }
-
- try {
- return $this->loadTemplate($name);
- } catch (Twig_Error_Loader $e) {
- }
- }
-
- if (1 === count($names)) {
- throw $e;
- }
-
- throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
- }
-
- /**
- * Clears the internal template cache.
- */
- public function clearTemplateCache()
- {
- $this->loadedTemplates = array();
- }
-
- /**
- * Clears the template cache files on the filesystem.
- */
- public function clearCacheFiles()
- {
- if (false === $this->cache) {
- return;
- }
-
- foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
- if ($file->isFile()) {
- @unlink($file->getPathname());
- }
- }
- }
-
- /**
- * Gets the Lexer instance.
- *
- * @return Twig_LexerInterface A Twig_LexerInterface instance
- */
- public function getLexer()
- {
- if (null === $this->lexer) {
- $this->lexer = new Twig_Lexer($this);
- }
-
- return $this->lexer;
- }
-
- /**
- * Sets the Lexer instance.
- *
- * @param Twig_LexerInterface A Twig_LexerInterface instance
- */
- public function setLexer(Twig_LexerInterface $lexer)
- {
- $this->lexer = $lexer;
- }
-
- /**
- * Tokenizes a source code.
- *
- * @param string $source The template source code
- * @param string $name The template name
- *
- * @return Twig_TokenStream A Twig_TokenStream instance
- */
- public function tokenize($source, $name = null)
- {
- return $this->getLexer()->tokenize($source, $name);
- }
-
- /**
- * Gets the Parser instance.
- *
- * @return Twig_ParserInterface A Twig_ParserInterface instance
- */
- public function getParser()
- {
- if (null === $this->parser) {
- $this->parser = new Twig_Parser($this);
- }
-
- return $this->parser;
- }
-
- /**
- * Sets the Parser instance.
- *
- * @param Twig_ParserInterface A Twig_ParserInterface instance
- */
- public function setParser(Twig_ParserInterface $parser)
- {
- $this->parser = $parser;
- }
-
- /**
- * Parses a token stream.
- *
- * @param Twig_TokenStream $tokens A Twig_TokenStream instance
- *
- * @return Twig_Node_Module A Node tree
- */
- public function parse(Twig_TokenStream $tokens)
- {
- return $this->getParser()->parse($tokens);
- }
-
- /**
- * Gets the Compiler instance.
- *
- * @return Twig_CompilerInterface A Twig_CompilerInterface instance
- */
- public function getCompiler()
- {
- if (null === $this->compiler) {
- $this->compiler = new Twig_Compiler($this);
- }
-
- return $this->compiler;
- }
-
- /**
- * Sets the Compiler instance.
- *
- * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
- */
- public function setCompiler(Twig_CompilerInterface $compiler)
- {
- $this->compiler = $compiler;
- }
-
- /**
- * Compiles a Node.
- *
- * @param Twig_NodeInterface $node A Twig_NodeInterface instance
- *
- * @return string The compiled PHP source code
- */
- public function compile(Twig_NodeInterface $node)
- {
- return $this->getCompiler()->compile($node)->getSource();
- }
-
- /**
- * Compiles a template source code.
- *
- * @param string $source The template source code
- * @param string $name The template name
- *
- * @return string The compiled PHP source code
- */
- public function compileSource($source, $name = null)
- {
- try {
- return $this->compile($this->parse($this->tokenize($source, $name)));
- } catch (Twig_Error $e) {
- $e->setTemplateFile($name);
- throw $e;
- } catch (Exception $e) {
- throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
- }
- }
-
- /**
- * Sets the Loader instance.
- *
- * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
- */
- public function setLoader(Twig_LoaderInterface $loader)
- {
- $this->loader = $loader;
- }
-
- /**
- * Gets the Loader instance.
- *
- * @return Twig_LoaderInterface A Twig_LoaderInterface instance
- */
- public function getLoader()
- {
- if (null === $this->loader) {
- throw new LogicException('You must set a loader first.');
- }
-
- return $this->loader;
- }
-
- /**
- * Sets the default template charset.
- *
- * @param string $charset The default charset
- */
- public function setCharset($charset)
- {
- $this->charset = strtoupper($charset);
- }
-
- /**
- * Gets the default template charset.
- *
- * @return string The default charset
- */
- public function getCharset()
- {
- return $this->charset;
- }
-
- /**
- * Initializes the runtime environment.
- */
- public function initRuntime()
- {
- $this->runtimeInitialized = true;
-
- foreach ($this->getExtensions() as $extension) {
- $extension->initRuntime($this);
- }
- }
-
- /**
- * Returns true if the given extension is registered.
- *
- * @param string $name The extension name
- *
- * @return Boolean Whether the extension is registered or not
- */
- public function hasExtension($name)
- {
- return isset($this->extensions[$name]);
- }
-
- /**
- * Gets an extension by name.
- *
- * @param string $name The extension name
- *
- * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
- */
- public function getExtension($name)
- {
- if (!isset($this->extensions[$name])) {
- throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
- }
-
- return $this->extensions[$name];
- }
-
- /**
- * Registers an extension.
- *
- * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
- */
- public function addExtension(Twig_ExtensionInterface $extension)
- {
- if ($this->extensionInitialized) {
- throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
- }
-
- $this->extensions[$extension->getName()] = $extension;
- }
-
- /**
- * Removes an extension by name.
- *
- * This method is deprecated and you should not use it.
- *
- * @param string $name The extension name
- *
- * @deprecated since 1.12 (to be removed in 2.0)
- */
- public function removeExtension($name)
- {
- if ($this->extensionInitialized) {
- throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
- }
-
- unset($this->extensions[$name]);
- }
-
- /**
- * Registers an array of extensions.
- *
- * @param array $extensions An array of extensions
- */
- public function setExtensions(array $extensions)
- {
- foreach ($extensions as $extension) {
- $this->addExtension($extension);
- }
- }
-
- /**
- * Returns all registered extensions.
- *
- * @return array An array of extensions
- */
- public function getExtensions()
- {
- return $this->extensions;
- }
-
- /**
- * Registers a Token Parser.
- *
- * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
- */
- public function addTokenParser(Twig_TokenParserInterface $parser)
- {
- if ($this->extensionInitialized) {
- throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
- }
-
- $this->staging->addTokenParser($parser);
- }
-
- /**
- * Gets the registered Token Parsers.
- *
- * @return Twig_TokenParserBrokerInterface A broker containing token parsers
- */
- public function getTokenParsers()
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- return $this->parsers;
- }
-
- /**
- * Gets registered tags.
- *
- * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
- *
- * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
- */
- public function getTags()
- {
- $tags = array();
- foreach ($this->getTokenParsers()->getParsers() as $parser) {
- if ($parser instanceof Twig_TokenParserInterface) {
- $tags[$parser->getTag()] = $parser;
- }
- }
-
- return $tags;
- }
-
- /**
- * Registers a Node Visitor.
- *
- * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
- */
- public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
- {
- if ($this->extensionInitialized) {
- throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
- }
-
- $this->staging->addNodeVisitor($visitor);
- }
-
- /**
- * Gets the registered Node Visitors.
- *
- * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
- */
- public function getNodeVisitors()
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- return $this->visitors;
- }
-
- /**
- * Registers a Filter.
- *
- * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
- * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
- */
- public function addFilter($name, $filter = null)
- {
- if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
- throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
- }
-
- if ($name instanceof Twig_SimpleFilter) {
- $filter = $name;
- $name = $filter->getName();
- }
-
- if ($this->extensionInitialized) {
- throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
- }
-
- $this->staging->addFilter($name, $filter);
- }
-
- /**
- * Get a filter by name.
- *
- * Subclasses may override this method and load filters differently;
- * so no list of filters is available.
- *
- * @param string $name The filter name
- *
- * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
- */
- public function getFilter($name)
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- if (isset($this->filters[$name])) {
- return $this->filters[$name];
- }
-
- foreach ($this->filters as $pattern => $filter) {
- $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
-
- if ($count) {
- if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
- array_shift($matches);
- $filter->setArguments($matches);
-
- return $filter;
- }
- }
- }
-
- foreach ($this->filterCallbacks as $callback) {
- if (false !== $filter = call_user_func($callback, $name)) {
- return $filter;
- }
- }
-
- return false;
- }
-
- public function registerUndefinedFilterCallback($callable)
- {
- $this->filterCallbacks[] = $callable;
- }
-
- /**
- * Gets the registered Filters.
- *
- * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
- *
- * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
- *
- * @see registerUndefinedFilterCallback
- */
- public function getFilters()
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- return $this->filters;
- }
-
- /**
- * Registers a Test.
- *
- * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
- * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
- */
- public function addTest($name, $test = null)
- {
- if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
- throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
- }
-
- if ($name instanceof Twig_SimpleTest) {
- $test = $name;
- $name = $test->getName();
- }
-
- if ($this->extensionInitialized) {
- throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
- }
-
- $this->staging->addTest($name, $test);
- }
-
- /**
- * Gets the registered Tests.
- *
- * @return Twig_TestInterface[] An array of Twig_TestInterface instances
- */
- public function getTests()
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- return $this->tests;
- }
-
- /**
- * Gets a test by name.
- *
- * @param string $name The test name
- *
- * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
- */
- public function getTest($name)
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- if (isset($this->tests[$name])) {
- return $this->tests[$name];
- }
-
- return false;
- }
-
- /**
- * Registers a Function.
- *
- * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
- * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
- */
- public function addFunction($name, $function = null)
- {
- if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
- throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
- }
-
- if ($name instanceof Twig_SimpleFunction) {
- $function = $name;
- $name = $function->getName();
- }
-
- if ($this->extensionInitialized) {
- throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
- }
-
- $this->staging->addFunction($name, $function);
- }
-
- /**
- * Get a function by name.
- *
- * Subclasses may override this method and load functions differently;
- * so no list of functions is available.
- *
- * @param string $name function name
- *
- * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
- */
- public function getFunction($name)
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- if (isset($this->functions[$name])) {
- return $this->functions[$name];
- }
-
- foreach ($this->functions as $pattern => $function) {
- $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
-
- if ($count) {
- if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
- array_shift($matches);
- $function->setArguments($matches);
-
- return $function;
- }
- }
- }
-
- foreach ($this->functionCallbacks as $callback) {
- if (false !== $function = call_user_func($callback, $name)) {
- return $function;
- }
- }
-
- return false;
- }
-
- public function registerUndefinedFunctionCallback($callable)
- {
- $this->functionCallbacks[] = $callable;
- }
-
- /**
- * Gets registered functions.
- *
- * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
- *
- * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
- *
- * @see registerUndefinedFunctionCallback
- */
- public function getFunctions()
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- return $this->functions;
- }
-
- /**
- * Registers a Global.
- *
- * New globals can be added before compiling or rendering a template;
- * but after, you can only update existing globals.
- *
- * @param string $name The global name
- * @param mixed $value The global value
- */
- public function addGlobal($name, $value)
- {
- if ($this->extensionInitialized || $this->runtimeInitialized) {
- if (null === $this->globals) {
- $this->globals = $this->initGlobals();
- }
-
- /* This condition must be uncommented in Twig 2.0
- if (!array_key_exists($name, $this->globals)) {
- throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
- }
- */
- }
-
- if ($this->extensionInitialized || $this->runtimeInitialized) {
- // update the value
- $this->globals[$name] = $value;
- } else {
- $this->staging->addGlobal($name, $value);
- }
- }
-
- /**
- * Gets the registered Globals.
- *
- * @return array An array of globals
- */
- public function getGlobals()
- {
- if (!$this->runtimeInitialized && !$this->extensionInitialized) {
- return $this->initGlobals();
- }
-
- if (null === $this->globals) {
- $this->globals = $this->initGlobals();
- }
-
- return $this->globals;
- }
-
- /**
- * Merges a context with the defined globals.
- *
- * @param array $context An array representing the context
- *
- * @return array The context merged with the globals
- */
- public function mergeGlobals(array $context)
- {
- // we don't use array_merge as the context being generally
- // bigger than globals, this code is faster.
- foreach ($this->getGlobals() as $key => $value) {
- if (!array_key_exists($key, $context)) {
- $context[$key] = $value;
- }
- }
-
- return $context;
- }
-
- /**
- * Gets the registered unary Operators.
- *
- * @return array An array of unary operators
- */
- public function getUnaryOperators()
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- return $this->unaryOperators;
- }
-
- /**
- * Gets the registered binary Operators.
- *
- * @return array An array of binary operators
- */
- public function getBinaryOperators()
- {
- if (!$this->extensionInitialized) {
- $this->initExtensions();
- }
-
- return $this->binaryOperators;
- }
-
- public function computeAlternatives($name, $items)
- {
- $alternatives = array();
- foreach ($items as $item) {
- $lev = levenshtein($name, $item);
- if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
- $alternatives[$item] = $lev;
- }
- }
- asort($alternatives);
-
- return array_keys($alternatives);
- }
-
- protected function initGlobals()
- {
- $globals = array();
- foreach ($this->extensions as $extension) {
- $extGlob = $extension->getGlobals();
- if (!is_array($extGlob)) {
- throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
- }
-
- $globals[] = $extGlob;
- }
-
- $globals[] = $this->staging->getGlobals();
-
- return call_user_func_array('array_merge', $globals);
- }
-
- protected function initExtensions()
- {
- if ($this->extensionInitialized) {
- return;
- }
-
- $this->extensionInitialized = true;
- $this->parsers = new Twig_TokenParserBroker();
- $this->filters = array();
- $this->functions = array();
- $this->tests = array();
- $this->visitors = array();
- $this->unaryOperators = array();
- $this->binaryOperators = array();
-
- foreach ($this->extensions as $extension) {
- $this->initExtension($extension);
- }
- $this->initExtension($this->staging);
- }
-
- protected function initExtension(Twig_ExtensionInterface $extension)
- {
- // filters
- foreach ($extension->getFilters() as $name => $filter) {
- if ($name instanceof Twig_SimpleFilter) {
- $filter = $name;
- $name = $filter->getName();
- } elseif ($filter instanceof Twig_SimpleFilter) {
- $name = $filter->getName();
- }
-
- $this->filters[$name] = $filter;
- }
-
- // functions
- foreach ($extension->getFunctions() as $name => $function) {
- if ($name instanceof Twig_SimpleFunction) {
- $function = $name;
- $name = $function->getName();
- } elseif ($function instanceof Twig_SimpleFunction) {
- $name = $function->getName();
- }
-
- $this->functions[$name] = $function;
- }
-
- // tests
- foreach ($extension->getTests() as $name => $test) {
- if ($name instanceof Twig_SimpleTest) {
- $test = $name;
- $name = $test->getName();
- } elseif ($test instanceof Twig_SimpleTest) {
- $name = $test->getName();
- }
-
- $this->tests[$name] = $test;
- }
-
- // token parsers
- foreach ($extension->getTokenParsers() as $parser) {
- if ($parser instanceof Twig_TokenParserInterface) {
- $this->parsers->addTokenParser($parser);
- } elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
- $this->parsers->addTokenParserBroker($parser);
- } else {
- throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
- }
- }
-
- // node visitors
- foreach ($extension->getNodeVisitors() as $visitor) {
- $this->visitors[] = $visitor;
- }
-
- // operators
- if ($operators = $extension->getOperators()) {
- if (2 !== count($operators)) {
- throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
- }
-
- $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
- $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
- }
- }
-
- protected function writeCacheFile($file, $content)
- {
- $dir = dirname($file);
- if (!is_dir($dir)) {
- if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
- throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
- }
- } elseif (!is_writable($dir)) {
- throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
- }
-
- $tmpFile = tempnam(dirname($file), basename($file));
- if (false !== @file_put_contents($tmpFile, $content)) {
- // rename does not work on Win32 before 5.2.6
- if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
- @chmod($file, 0666 & ~umask());
-
- return;
- }
- }
-
- throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Twig base exception.
- *
- * This exception class and its children must only be used when
- * an error occurs during the loading of a template, when a syntax error
- * is detected in a template, or when rendering a template. Other
- * errors must use regular PHP exception classes (like when the template
- * cache directory is not writable for instance).
- *
- * To help debugging template issues, this class tracks the original template
- * name and line where the error occurred.
- *
- * Whenever possible, you must set these information (original template name
- * and line number) yourself by passing them to the constructor. If some or all
- * these information are not available from where you throw the exception, then
- * this class will guess them automatically (when the line number is set to -1
- * and/or the filename is set to null). As this is a costly operation, this
- * can be disabled by passing false for both the filename and the line number
- * when creating a new instance of this class.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Error extends Exception
-{
- protected $lineno;
- protected $filename;
- protected $rawMessage;
- protected $previous;
-
- /**
- * Constructor.
- *
- * Set both the line number and the filename to false to
- * disable automatic guessing of the original template name
- * and line number.
- *
- * Set the line number to -1 to enable its automatic guessing.
- * Set the filename to null to enable its automatic guessing.
- *
- * By default, automatic guessing is enabled.
- *
- * @param string $message The error message
- * @param integer $lineno The template line where the error occurred
- * @param string $filename The template file name where the error occurred
- * @param Exception $previous The previous exception
- */
- public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
- {
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- $this->previous = $previous;
- parent::__construct('');
- } else {
- parent::__construct('', 0, $previous);
- }
-
- $this->lineno = $lineno;
- $this->filename = $filename;
-
- if (-1 === $this->lineno || null === $this->filename) {
- $this->guessTemplateInfo();
- }
-
- $this->rawMessage = $message;
-
- $this->updateRepr();
- }
-
- /**
- * Gets the raw message.
- *
- * @return string The raw message
- */
- public function getRawMessage()
- {
- return $this->rawMessage;
- }
-
- /**
- * Gets the filename where the error occurred.
- *
- * @return string The filename
- */
- public function getTemplateFile()
- {
- return $this->filename;
- }
-
- /**
- * Sets the filename where the error occurred.
- *
- * @param string $filename The filename
- */
- public function setTemplateFile($filename)
- {
- $this->filename = $filename;
-
- $this->updateRepr();
- }
-
- /**
- * Gets the template line where the error occurred.
- *
- * @return integer The template line
- */
- public function getTemplateLine()
- {
- return $this->lineno;
- }
-
- /**
- * Sets the template line where the error occurred.
- *
- * @param integer $lineno The template line
- */
- public function setTemplateLine($lineno)
- {
- $this->lineno = $lineno;
-
- $this->updateRepr();
- }
-
- public function guess()
- {
- $this->guessTemplateInfo();
- $this->updateRepr();
- }
-
- /**
- * For PHP < 5.3.0, provides access to the getPrevious() method.
- *
- * @param string $method The method name
- * @param array $arguments The parameters to be passed to the method
- *
- * @return Exception The previous exception or null
- *
- * @throws BadMethodCallException
- */
- public function __call($method, $arguments)
- {
- if ('getprevious' == strtolower($method)) {
- return $this->previous;
- }
-
- throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
- }
-
- protected function updateRepr()
- {
- $this->message = $this->rawMessage;
-
- $dot = false;
- if ('.' === substr($this->message, -1)) {
- $this->message = substr($this->message, 0, -1);
- $dot = true;
- }
-
- if ($this->filename) {
- if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
- $filename = sprintf('"%s"', $this->filename);
- } else {
- $filename = json_encode($this->filename);
- }
- $this->message .= sprintf(' in %s', $filename);
- }
-
- if ($this->lineno && $this->lineno >= 0) {
- $this->message .= sprintf(' at line %d', $this->lineno);
- }
-
- if ($dot) {
- $this->message .= '.';
- }
- }
-
- protected function guessTemplateInfo()
- {
- $template = null;
- $templateClass = null;
-
- if (version_compare(phpversion(), '5.3.6', '>=')) {
- $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
- } else {
- $backtrace = debug_backtrace();
- }
-
- foreach ($backtrace as $trace) {
- if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
- $currentClass = get_class($trace['object']);
- $isEmbedContainer = 0 === strpos($templateClass, $currentClass);
- if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
- $template = $trace['object'];
- $templateClass = get_class($trace['object']);
- }
- }
- }
-
- // update template filename
- if (null !== $template && null === $this->filename) {
- $this->filename = $template->getTemplateName();
- }
-
- if (null === $template || $this->lineno > -1) {
- return;
- }
-
- $r = new ReflectionObject($template);
- $file = $r->getFileName();
-
- $exceptions = array($e = $this);
- while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
- $exceptions[] = $e;
- }
-
- while ($e = array_pop($exceptions)) {
- $traces = $e->getTrace();
- while ($trace = array_shift($traces)) {
- if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
- continue;
- }
-
- foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
- if ($codeLine <= $trace['line']) {
- // update template line
- $this->lineno = $templateLine;
-
- return;
- }
- }
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Exception thrown when an error occurs during template loading.
- *
- * Automatic template information guessing is always turned off as
- * if a template cannot be loaded, there is nothing to guess.
- * However, when a template is loaded from another one, then, we need
- * to find the current context and this is automatically done by
- * Twig_Template::displayWithErrorHandling().
- *
- * This strategy makes Twig_Environment::resolveTemplate() much faster.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Error_Loader extends Twig_Error
-{
- public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
- {
- parent::__construct($message, false, false, $previous);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Exception thrown when an error occurs at runtime.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Error_Runtime extends Twig_Error
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Exception thrown when a syntax error occurs during lexing or parsing of a template.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Error_Syntax extends Twig_Error
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Adds an exists() method for loaders.
- *
- * @author Florin Patan <florinpatan@gmail.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_ExistsLoaderInterface
-{
- /**
- * Check if we have the source code of a template, given its name.
- *
- * @param string $name The name of the template to check if we can load
- *
- * @return boolean If the template source code is handled by this loader or not
- */
- public function exists($name);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Parses expressions.
- *
- * This parser implements a "Precedence climbing" algorithm.
- *
- * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
- * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_ExpressionParser
-{
- const OPERATOR_LEFT = 1;
- const OPERATOR_RIGHT = 2;
-
- protected $parser;
- protected $unaryOperators;
- protected $binaryOperators;
-
- public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
- {
- $this->parser = $parser;
- $this->unaryOperators = $unaryOperators;
- $this->binaryOperators = $binaryOperators;
- }
-
- public function parseExpression($precedence = 0)
- {
- $expr = $this->getPrimary();
- $token = $this->parser->getCurrentToken();
- while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
- $op = $this->binaryOperators[$token->getValue()];
- $this->parser->getStream()->next();
-
- if (isset($op['callable'])) {
- $expr = call_user_func($op['callable'], $this->parser, $expr);
- } else {
- $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
- $class = $op['class'];
- $expr = new $class($expr, $expr1, $token->getLine());
- }
-
- $token = $this->parser->getCurrentToken();
- }
-
- if (0 === $precedence) {
- return $this->parseConditionalExpression($expr);
- }
-
- return $expr;
- }
-
- protected function getPrimary()
- {
- $token = $this->parser->getCurrentToken();
-
- if ($this->isUnary($token)) {
- $operator = $this->unaryOperators[$token->getValue()];
- $this->parser->getStream()->next();
- $expr = $this->parseExpression($operator['precedence']);
- $class = $operator['class'];
-
- return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
- } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
- $this->parser->getStream()->next();
- $expr = $this->parseExpression();
- $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
-
- return $this->parsePostfixExpression($expr);
- }
-
- return $this->parsePrimaryExpression();
- }
-
- protected function parseConditionalExpression($expr)
- {
- while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) {
- $this->parser->getStream()->next();
- if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
- $expr2 = $this->parseExpression();
- if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
- $this->parser->getStream()->next();
- $expr3 = $this->parseExpression();
- } else {
- $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
- }
- } else {
- $this->parser->getStream()->next();
- $expr2 = $expr;
- $expr3 = $this->parseExpression();
- }
-
- $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
- }
-
- return $expr;
- }
-
- protected function isUnary(Twig_Token $token)
- {
- return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
- }
-
- protected function isBinary(Twig_Token $token)
- {
- return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
- }
-
- public function parsePrimaryExpression()
- {
- $token = $this->parser->getCurrentToken();
- switch ($token->getType()) {
- case Twig_Token::NAME_TYPE:
- $this->parser->getStream()->next();
- switch ($token->getValue()) {
- case 'true':
- case 'TRUE':
- $node = new Twig_Node_Expression_Constant(true, $token->getLine());
- break;
-
- case 'false':
- case 'FALSE':
- $node = new Twig_Node_Expression_Constant(false, $token->getLine());
- break;
-
- case 'none':
- case 'NONE':
- case 'null':
- case 'NULL':
- $node = new Twig_Node_Expression_Constant(null, $token->getLine());
- break;
-
- default:
- if ('(' === $this->parser->getCurrentToken()->getValue()) {
- $node = $this->getFunctionNode($token->getValue(), $token->getLine());
- } else {
- $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
- }
- }
- break;
-
- case Twig_Token::NUMBER_TYPE:
- $this->parser->getStream()->next();
- $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
- break;
-
- case Twig_Token::STRING_TYPE:
- case Twig_Token::INTERPOLATION_START_TYPE:
- $node = $this->parseStringExpression();
- break;
-
- default:
- if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
- $node = $this->parseArrayExpression();
- } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
- $node = $this->parseHashExpression();
- } else {
- throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
- }
- }
-
- return $this->parsePostfixExpression($node);
- }
-
- public function parseStringExpression()
- {
- $stream = $this->parser->getStream();
-
- $nodes = array();
- // a string cannot be followed by another string in a single expression
- $nextCanBeString = true;
- while (true) {
- if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) {
- $token = $stream->next();
- $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
- $nextCanBeString = false;
- } elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) {
- $stream->next();
- $nodes[] = $this->parseExpression();
- $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
- $nextCanBeString = true;
- } else {
- break;
- }
- }
-
- $expr = array_shift($nodes);
- foreach ($nodes as $node) {
- $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
- }
-
- return $expr;
- }
-
- public function parseArrayExpression()
- {
- $stream = $this->parser->getStream();
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
-
- $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
- $first = true;
- while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
- if (!$first) {
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
-
- // trailing ,?
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
- break;
- }
- }
- $first = false;
-
- $node->addElement($this->parseExpression());
- }
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
-
- return $node;
- }
-
- public function parseHashExpression()
- {
- $stream = $this->parser->getStream();
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
-
- $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
- $first = true;
- while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
- if (!$first) {
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
-
- // trailing ,?
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
- break;
- }
- }
- $first = false;
-
- // a hash key can be:
- //
- // * a number -- 12
- // * a string -- 'a'
- // * a name, which is equivalent to a string -- a
- // * an expression, which must be enclosed in parentheses -- (1 + 2)
- if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) {
- $token = $stream->next();
- $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
- } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
- $key = $this->parseExpression();
- } else {
- $current = $stream->getCurrent();
-
- throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
- }
-
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
- $value = $this->parseExpression();
-
- $node->addElement($value, $key);
- }
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
-
- return $node;
- }
-
- public function parsePostfixExpression($node)
- {
- while (true) {
- $token = $this->parser->getCurrentToken();
- if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
- if ('.' == $token->getValue() || '[' == $token->getValue()) {
- $node = $this->parseSubscriptExpression($node);
- } elseif ('|' == $token->getValue()) {
- $node = $this->parseFilterExpression($node);
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- return $node;
- }
-
- public function getFunctionNode($name, $line)
- {
- switch ($name) {
- case 'parent':
- $args = $this->parseArguments();
- if (!count($this->parser->getBlockStack())) {
- throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
- }
-
- if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
- throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
- }
-
- return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
- case 'block':
- return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
- case 'attribute':
- $args = $this->parseArguments();
- if (count($args) < 2) {
- throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
- }
-
- return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
- default:
- if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
- $arguments = new Twig_Node_Expression_Array(array(), $line);
- foreach ($this->parseArguments() as $n) {
- $arguments->addElement($n);
- }
-
- $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
- $node->setAttribute('safe', true);
-
- return $node;
- }
-
- $args = $this->parseArguments(true);
- $class = $this->getFunctionNodeClass($name, $line);
-
- return new $class($name, $args, $line);
- }
- }
-
- public function parseSubscriptExpression($node)
- {
- $stream = $this->parser->getStream();
- $token = $stream->next();
- $lineno = $token->getLine();
- $arguments = new Twig_Node_Expression_Array(array(), $lineno);
- $type = Twig_TemplateInterface::ANY_CALL;
- if ($token->getValue() == '.') {
- $token = $stream->next();
- if (
- $token->getType() == Twig_Token::NAME_TYPE
- ||
- $token->getType() == Twig_Token::NUMBER_TYPE
- ||
- ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
- ) {
- $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
-
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
- $type = Twig_TemplateInterface::METHOD_CALL;
- foreach ($this->parseArguments() as $n) {
- $arguments->addElement($n);
- }
- }
- } else {
- throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
- }
-
- if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
- if (!$arg instanceof Twig_Node_Expression_Constant) {
- throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
- }
-
- $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
- $node->setAttribute('safe', true);
-
- return $node;
- }
- } else {
- $type = Twig_TemplateInterface::ARRAY_CALL;
-
- // slice?
- $slice = false;
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
- $slice = true;
- $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
- } else {
- $arg = $this->parseExpression();
- }
-
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
- $slice = true;
- $stream->next();
- }
-
- if ($slice) {
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
- $length = new Twig_Node_Expression_Constant(null, $token->getLine());
- } else {
- $length = $this->parseExpression();
- }
-
- $class = $this->getFilterNodeClass('slice', $token->getLine());
- $arguments = new Twig_Node(array($arg, $length));
- $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
-
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
-
- return $filter;
- }
-
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
- }
-
- return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
- }
-
- public function parseFilterExpression($node)
- {
- $this->parser->getStream()->next();
-
- return $this->parseFilterExpressionRaw($node);
- }
-
- public function parseFilterExpressionRaw($node, $tag = null)
- {
- while (true) {
- $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
-
- $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
- if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
- $arguments = new Twig_Node();
- } else {
- $arguments = $this->parseArguments(true);
- }
-
- $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
-
- $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
-
- if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
- break;
- }
-
- $this->parser->getStream()->next();
- }
-
- return $node;
- }
-
- /**
- * Parses arguments.
- *
- * @param Boolean $namedArguments Whether to allow named arguments or not
- * @param Boolean $definition Whether we are parsing arguments for a function definition
- */
- public function parseArguments($namedArguments = false, $definition = false)
- {
- $args = array();
- $stream = $this->parser->getStream();
-
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
- while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
- if (!empty($args)) {
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
- }
-
- if ($definition) {
- $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
- $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
- } else {
- $value = $this->parseExpression();
- }
-
- $name = null;
- if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
- $token = $stream->next();
- if (!$value instanceof Twig_Node_Expression_Name) {
- throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
- }
- $name = $value->getAttribute('name');
-
- if ($definition) {
- $value = $this->parsePrimaryExpression();
-
- if (!$this->checkConstantExpression($value)) {
- throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
- }
- } else {
- $value = $this->parseExpression();
- }
- }
-
- if ($definition) {
- if (null === $name) {
- $name = $value->getAttribute('name');
- $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
- }
- $args[$name] = $value;
- } else {
- if (null === $name) {
- $args[] = $value;
- } else {
- $args[$name] = $value;
- }
- }
- }
- $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
-
- return new Twig_Node($args);
- }
-
- public function parseAssignmentExpression()
- {
- $targets = array();
- while (true) {
- $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
- if (in_array($token->getValue(), array('true', 'false', 'none'))) {
- throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
- }
- $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
-
- if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
- break;
- }
- $this->parser->getStream()->next();
- }
-
- return new Twig_Node($targets);
- }
-
- public function parseMultitargetExpression()
- {
- $targets = array();
- while (true) {
- $targets[] = $this->parseExpression();
- if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
- break;
- }
- $this->parser->getStream()->next();
- }
-
- return new Twig_Node($targets);
- }
-
- protected function getFunctionNodeClass($name, $line)
- {
- $env = $this->parser->getEnvironment();
-
- if (false === $function = $env->getFunction($name)) {
- $message = sprintf('The function "%s" does not exist', $name);
- if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
- }
-
- throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
- }
-
- if ($function instanceof Twig_SimpleFunction) {
- return $function->getNodeClass();
- }
-
- return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
- }
-
- protected function getFilterNodeClass($name, $line)
- {
- $env = $this->parser->getEnvironment();
-
- if (false === $filter = $env->getFilter($name)) {
- $message = sprintf('The filter "%s" does not exist', $name);
- if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
- }
-
- throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
- }
-
- if ($filter instanceof Twig_SimpleFilter) {
- return $filter->getNodeClass();
- }
-
- return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
- }
-
- // checks that the node only contains "constant" elements
- protected function checkConstantExpression(Twig_NodeInterface $node)
- {
- if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
- return false;
- }
-
- foreach ($node as $n) {
- if (!$this->checkConstantExpression($n)) {
- return false;
- }
- }
-
- return true;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-abstract class Twig_Extension implements Twig_ExtensionInterface
-{
- /**
- * Initializes the runtime environment.
- *
- * This is where you can load some file that contains filter functions for instance.
- *
- * @param Twig_Environment $environment The current Twig_Environment instance
- */
- public function initRuntime(Twig_Environment $environment)
- {
- }
-
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- public function getTokenParsers()
- {
- return array();
- }
-
- /**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- public function getNodeVisitors()
- {
- return array();
- }
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- public function getFilters()
- {
- return array();
- }
-
- /**
- * Returns a list of tests to add to the existing list.
- *
- * @return array An array of tests
- */
- public function getTests()
- {
- return array();
- }
-
- /**
- * Returns a list of functions to add to the existing list.
- *
- * @return array An array of functions
- */
- public function getFunctions()
- {
- return array();
- }
-
- /**
- * Returns a list of operators to add to the existing list.
- *
- * @return array An array of operators
- */
- public function getOperators()
- {
- return array();
- }
-
- /**
- * Returns a list of global variables to add to the existing list.
- *
- * @return array An array of global variables
- */
- public function getGlobals()
- {
- return array();
- }
-}
+++ /dev/null
-<?php
-
-if (!defined('ENT_SUBSTITUTE')) {
- define('ENT_SUBSTITUTE', 8);
-}
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Extension_Core extends Twig_Extension
-{
- protected $dateFormats = array('F j, Y H:i', '%d days');
- protected $numberFormat = array(0, '.', ',');
- protected $timezone = null;
-
- /**
- * Sets the default format to be used by the date filter.
- *
- * @param string $format The default date format string
- * @param string $dateIntervalFormat The default date interval format string
- */
- public function setDateFormat($format = null, $dateIntervalFormat = null)
- {
- if (null !== $format) {
- $this->dateFormats[0] = $format;
- }
-
- if (null !== $dateIntervalFormat) {
- $this->dateFormats[1] = $dateIntervalFormat;
- }
- }
-
- /**
- * Gets the default format to be used by the date filter.
- *
- * @return array The default date format string and the default date interval format string
- */
- public function getDateFormat()
- {
- return $this->dateFormats;
- }
-
- /**
- * Sets the default timezone to be used by the date filter.
- *
- * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object
- */
- public function setTimezone($timezone)
- {
- $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);
- }
-
- /**
- * Gets the default timezone to be used by the date filter.
- *
- * @return DateTimeZone The default timezone currently in use
- */
- public function getTimezone()
- {
- if (null === $this->timezone) {
- $this->timezone = new DateTimeZone(date_default_timezone_get());
- }
-
- return $this->timezone;
- }
-
- /**
- * Sets the default format to be used by the number_format filter.
- *
- * @param integer $decimal The number of decimal places to use.
- * @param string $decimalPoint The character(s) to use for the decimal point.
- * @param string $thousandSep The character(s) to use for the thousands separator.
- */
- public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
- {
- $this->numberFormat = array($decimal, $decimalPoint, $thousandSep);
- }
-
- /**
- * Get the default format used by the number_format filter.
- *
- * @return array The arguments for number_format()
- */
- public function getNumberFormat()
- {
- return $this->numberFormat;
- }
-
- /**
- * Returns the token parser instance to add to the existing list.
- *
- * @return array An array of Twig_TokenParser instances
- */
- public function getTokenParsers()
- {
- return array(
- new Twig_TokenParser_For(),
- new Twig_TokenParser_If(),
- new Twig_TokenParser_Extends(),
- new Twig_TokenParser_Include(),
- new Twig_TokenParser_Block(),
- new Twig_TokenParser_Use(),
- new Twig_TokenParser_Filter(),
- new Twig_TokenParser_Macro(),
- new Twig_TokenParser_Import(),
- new Twig_TokenParser_From(),
- new Twig_TokenParser_Set(),
- new Twig_TokenParser_Spaceless(),
- new Twig_TokenParser_Flush(),
- new Twig_TokenParser_Do(),
- new Twig_TokenParser_Embed(),
- );
- }
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- public function getFilters()
- {
- $filters = array(
- // formatting filters
- new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
- new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
- new Twig_SimpleFilter('format', 'sprintf'),
- new Twig_SimpleFilter('replace', 'strtr'),
- new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
- new Twig_SimpleFilter('abs', 'abs'),
-
- // encoding
- new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'),
- new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'),
- new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'),
-
- // string filters
- new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)),
- new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)),
- new Twig_SimpleFilter('upper', 'strtoupper'),
- new Twig_SimpleFilter('lower', 'strtolower'),
- new Twig_SimpleFilter('striptags', 'strip_tags'),
- new Twig_SimpleFilter('trim', 'trim'),
- new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
-
- // array helpers
- new Twig_SimpleFilter('join', 'twig_join_filter'),
- new Twig_SimpleFilter('split', 'twig_split_filter'),
- new Twig_SimpleFilter('sort', 'twig_sort_filter'),
- new Twig_SimpleFilter('merge', 'twig_array_merge'),
- new Twig_SimpleFilter('batch', 'twig_array_batch'),
-
- // string/array filters
- new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)),
- new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)),
- new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)),
- new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)),
- new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)),
-
- // iteration and runtime
- new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')),
- new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'),
-
- // escaping
- new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
- new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
- );
-
- if (function_exists('mb_get_info')) {
- $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true));
- $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true));
- }
-
- return $filters;
- }
-
- /**
- * Returns a list of global functions to add to the existing list.
- *
- * @return array An array of global functions
- */
- public function getFunctions()
- {
- return array(
- new Twig_SimpleFunction('range', 'range'),
- new Twig_SimpleFunction('constant', 'twig_constant'),
- new Twig_SimpleFunction('cycle', 'twig_cycle'),
- new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)),
- new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)),
- new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))),
- );
- }
-
- /**
- * Returns a list of tests to add to the existing list.
- *
- * @return array An array of tests
- */
- public function getTests()
- {
- return array(
- new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')),
- new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')),
- new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')),
- new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
- new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
- new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
- new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
- new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')),
- new Twig_SimpleTest('empty', 'twig_test_empty'),
- new Twig_SimpleTest('iterable', 'twig_test_iterable'),
- );
- }
-
- /**
- * Returns a list of operators to add to the existing list.
- *
- * @return array An array of operators
- */
- public function getOperators()
- {
- return array(
- array(
- 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
- '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'),
- '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'),
- ),
- array(
- 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
- ),
- );
- }
-
- public function parseNotTestExpression(Twig_Parser $parser, $node)
- {
- return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
- }
-
- public function parseTestExpression(Twig_Parser $parser, $node)
- {
- $stream = $parser->getStream();
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
- $arguments = null;
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
- $arguments = $parser->getExpressionParser()->parseArguments(true);
- }
-
- $class = $this->getTestNodeClass($parser, $name, $node->getLine());
-
- return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
- }
-
- protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
- {
- $env = $parser->getEnvironment();
- $testMap = $env->getTests();
- if (!isset($testMap[$name])) {
- $message = sprintf('The test "%s" does not exist', $name);
- if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) {
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
- }
-
- throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
- }
-
- if ($testMap[$name] instanceof Twig_SimpleTest) {
- return $testMap[$name]->getNodeClass();
- }
-
- return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test';
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'core';
- }
-}
-
-/**
- * Cycles over a value.
- *
- * @param ArrayAccess|array $values An array or an ArrayAccess instance
- * @param integer $position The cycle position
- *
- * @return string The next value in the cycle
- */
-function twig_cycle($values, $position)
-{
- if (!is_array($values) && !$values instanceof ArrayAccess) {
- return $values;
- }
-
- return $values[$position % count($values)];
-}
-
-/**
- * Returns a random value depending on the supplied parameter type:
- * - a random item from a Traversable or array
- * - a random character from a string
- * - a random integer between 0 and the integer parameter
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param Traversable|array|integer|string $values The values to pick a random item from
- *
- * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
- *
- * @return mixed A random value from the given sequence
- */
-function twig_random(Twig_Environment $env, $values = null)
-{
- if (null === $values) {
- return mt_rand();
- }
-
- if (is_int($values) || is_float($values)) {
- return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values);
- }
-
- if ($values instanceof Traversable) {
- $values = iterator_to_array($values);
- } elseif (is_string($values)) {
- if ('' === $values) {
- return '';
- }
- if (null !== $charset = $env->getCharset()) {
- if ('UTF-8' != $charset) {
- $values = twig_convert_encoding($values, 'UTF-8', $charset);
- }
-
- // unicode version of str_split()
- // split at all positions, but not after the start and not before the end
- $values = preg_split('/(?<!^)(?!$)/u', $values);
-
- if ('UTF-8' != $charset) {
- foreach ($values as $i => $value) {
- $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
- }
- }
- } else {
- return $values[mt_rand(0, strlen($values) - 1)];
- }
- }
-
- if (!is_array($values)) {
- return $values;
- }
-
- if (0 === count($values)) {
- throw new Twig_Error_Runtime('The random function cannot pick from an empty array.');
- }
-
- return $values[array_rand($values, 1)];
-}
-
-/**
- * Converts a date to the given format.
- *
- * <pre>
- * {{ post.published_at|date("m/d/Y") }}
- * </pre>
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param DateTime|DateInterval|string $date A date
- * @param string $format A format
- * @param DateTimeZone|string $timezone A timezone
- *
- * @return string The formatted date
- */
-function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null)
-{
- if (null === $format) {
- $formats = $env->getExtension('core')->getDateFormat();
- $format = $date instanceof DateInterval ? $formats[1] : $formats[0];
- }
-
- if ($date instanceof DateInterval) {
- return $date->format($format);
- }
-
- return twig_date_converter($env, $date, $timezone)->format($format);
-}
-
-/**
- * Returns a new date object modified
- *
- * <pre>
- * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
- * </pre>
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param DateTime|string $date A date
- * @param string $modifier A modifier string
- *
- * @return DateTime A new date object
- */
-function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
-{
- $date = twig_date_converter($env, $date, false);
- $date->modify($modifier);
-
- return $date;
-}
-
-/**
- * Converts an input to a DateTime instance.
- *
- * <pre>
- * {% if date(user.created_at) < date('+2days') %}
- * {# do something #}
- * {% endif %}
- * </pre>
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param DateTime|string $date A date
- * @param DateTimeZone|string $timezone A timezone
- *
- * @return DateTime A DateTime instance
- */
-function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
-{
- // determine the timezone
- if (!$timezone) {
- $defaultTimezone = $env->getExtension('core')->getTimezone();
- } elseif (!$timezone instanceof DateTimeZone) {
- $defaultTimezone = new DateTimeZone($timezone);
- } else {
- $defaultTimezone = $timezone;
- }
-
- if ($date instanceof DateTime) {
- $date = clone $date;
- if (false !== $timezone) {
- $date->setTimezone($defaultTimezone);
- }
-
- return $date;
- }
-
- $asString = (string) $date;
- if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
- $date = '@'.$date;
- }
-
- $date = new DateTime($date, $defaultTimezone);
- if (false !== $timezone) {
- $date->setTimezone($defaultTimezone);
- }
-
- return $date;
-}
-
-/**
- * Number format filter.
- *
- * All of the formatting options can be left null, in that case the defaults will
- * be used. Supplying any of the parameters will override the defaults set in the
- * environment object.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param mixed $number A float/int/string of the number to format
- * @param integer $decimal The number of decimal points to display.
- * @param string $decimalPoint The character(s) to use for the decimal point.
- * @param string $thousandSep The character(s) to use for the thousands separator.
- *
- * @return string The formatted number
- */
-function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
-{
- $defaults = $env->getExtension('core')->getNumberFormat();
- if (null === $decimal) {
- $decimal = $defaults[0];
- }
-
- if (null === $decimalPoint) {
- $decimalPoint = $defaults[1];
- }
-
- if (null === $thousandSep) {
- $thousandSep = $defaults[2];
- }
-
- return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
-}
-
-/**
- * URL encodes a string as a path segment or an array as a query string.
- *
- * @param string|array $url A URL or an array of query parameters
- * @param bool $raw true to use rawurlencode() instead of urlencode
- *
- * @return string The URL encoded value
- */
-function twig_urlencode_filter($url, $raw = false)
-{
- if (is_array($url)) {
- return http_build_query($url, '', '&');
- }
-
- if ($raw) {
- return rawurlencode($url);
- }
-
- return urlencode($url);
-}
-
-if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- /**
- * JSON encodes a variable.
- *
- * @param mixed $value The value to encode.
- * @param integer $options Not used on PHP 5.2.x
- *
- * @return mixed The JSON encoded value
- */
- function twig_jsonencode_filter($value, $options = 0)
- {
- if ($value instanceof Twig_Markup) {
- $value = (string) $value;
- } elseif (is_array($value)) {
- array_walk_recursive($value, '_twig_markup2string');
- }
-
- return json_encode($value);
- }
-} else {
- /**
- * JSON encodes a variable.
- *
- * @param mixed $value The value to encode.
- * @param integer $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
- *
- * @return mixed The JSON encoded value
- */
- function twig_jsonencode_filter($value, $options = 0)
- {
- if ($value instanceof Twig_Markup) {
- $value = (string) $value;
- } elseif (is_array($value)) {
- array_walk_recursive($value, '_twig_markup2string');
- }
-
- return json_encode($value, $options);
- }
-}
-
-function _twig_markup2string(&$value)
-{
- if ($value instanceof Twig_Markup) {
- $value = (string) $value;
- }
-}
-
-/**
- * Merges an array with another one.
- *
- * <pre>
- * {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
- *
- * {% set items = items|merge({ 'peugeot': 'car' }) %}
- *
- * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
- * </pre>
- *
- * @param array $arr1 An array
- * @param array $arr2 An array
- *
- * @return array The merged array
- */
-function twig_array_merge($arr1, $arr2)
-{
- if (!is_array($arr1) || !is_array($arr2)) {
- throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
- }
-
- return array_merge($arr1, $arr2);
-}
-
-/**
- * Slices a variable.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param mixed $item A variable
- * @param integer $start Start of the slice
- * @param integer $length Size of the slice
- * @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array)
- *
- * @return mixed The sliced variable
- */
-function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
-{
- if ($item instanceof Traversable) {
- $item = iterator_to_array($item, false);
- }
-
- if (is_array($item)) {
- return array_slice($item, $start, $length, $preserveKeys);
- }
-
- $item = (string) $item;
-
- if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
- return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
- }
-
- return null === $length ? substr($item, $start) : substr($item, $start, $length);
-}
-
-/**
- * Returns the first element of the item.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param mixed $item A variable
- *
- * @return mixed The first element of the item
- */
-function twig_first(Twig_Environment $env, $item)
-{
- $elements = twig_slice($env, $item, 0, 1, false);
-
- return is_string($elements) ? $elements[0] : current($elements);
-}
-
-/**
- * Returns the last element of the item.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param mixed $item A variable
- *
- * @return mixed The last element of the item
- */
-function twig_last(Twig_Environment $env, $item)
-{
- $elements = twig_slice($env, $item, -1, 1, false);
-
- return is_string($elements) ? $elements[0] : current($elements);
-}
-
-/**
- * Joins the values to a string.
- *
- * The separator between elements is an empty string per default, you can define it with the optional parameter.
- *
- * <pre>
- * {{ [1, 2, 3]|join('|') }}
- * {# returns 1|2|3 #}
- *
- * {{ [1, 2, 3]|join }}
- * {# returns 123 #}
- * </pre>
- *
- * @param array $value An array
- * @param string $glue The separator
- *
- * @return string The concatenated string
- */
-function twig_join_filter($value, $glue = '')
-{
- if ($value instanceof Traversable) {
- $value = iterator_to_array($value, false);
- }
-
- return implode($glue, (array) $value);
-}
-
-/**
- * Splits the string into an array.
- *
- * <pre>
- * {{ "one,two,three"|split(',') }}
- * {# returns [one, two, three] #}
- *
- * {{ "one,two,three,four,five"|split(',', 3) }}
- * {# returns [one, two, "three,four,five"] #}
- *
- * {{ "123"|split('') }}
- * {# returns [1, 2, 3] #}
- *
- * {{ "aabbcc"|split('', 2) }}
- * {# returns [aa, bb, cc] #}
- * </pre>
- *
- * @param string $value A string
- * @param string $delimiter The delimiter
- * @param integer $limit The limit
- *
- * @return array The split string as an array
- */
-function twig_split_filter($value, $delimiter, $limit = null)
-{
- if (empty($delimiter)) {
- return str_split($value, null === $limit ? 1 : $limit);
- }
-
- return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
-}
-
-// The '_default' filter is used internally to avoid using the ternary operator
-// which costs a lot for big contexts (before PHP 5.4). So, on average,
-// a function call is cheaper.
-function _twig_default_filter($value, $default = '')
-{
- if (twig_test_empty($value)) {
- return $default;
- }
-
- return $value;
-}
-
-/**
- * Returns the keys for the given array.
- *
- * It is useful when you want to iterate over the keys of an array:
- *
- * <pre>
- * {% for key in array|keys %}
- * {# ... #}
- * {% endfor %}
- * </pre>
- *
- * @param array $array An array
- *
- * @return array The keys
- */
-function twig_get_array_keys_filter($array)
-{
- if (is_object($array) && $array instanceof Traversable) {
- return array_keys(iterator_to_array($array));
- }
-
- if (!is_array($array)) {
- return array();
- }
-
- return array_keys($array);
-}
-
-/**
- * Reverses a variable.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param array|Traversable|string $item An array, a Traversable instance, or a string
- * @param Boolean $preserveKeys Whether to preserve key or not
- *
- * @return mixed The reversed input
- */
-function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
-{
- if (is_object($item) && $item instanceof Traversable) {
- return array_reverse(iterator_to_array($item), $preserveKeys);
- }
-
- if (is_array($item)) {
- return array_reverse($item, $preserveKeys);
- }
-
- if (null !== $charset = $env->getCharset()) {
- $string = (string) $item;
-
- if ('UTF-8' != $charset) {
- $item = twig_convert_encoding($string, 'UTF-8', $charset);
- }
-
- preg_match_all('/./us', $item, $matches);
-
- $string = implode('', array_reverse($matches[0]));
-
- if ('UTF-8' != $charset) {
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
- }
-
- return $string;
- }
-
- return strrev((string) $item);
-}
-
-/**
- * Sorts an array.
- *
- * @param array $array An array
- */
-function twig_sort_filter($array)
-{
- asort($array);
-
- return $array;
-}
-
-/* used internally */
-function twig_in_filter($value, $compare)
-{
- if (is_array($compare)) {
- return in_array($value, $compare, is_object($value));
- } elseif (is_string($compare)) {
- if (!strlen($value)) {
- return empty($compare);
- }
-
- return false !== strpos($compare, (string) $value);
- } elseif ($compare instanceof Traversable) {
- return in_array($value, iterator_to_array($compare, false), is_object($value));
- }
-
- return false;
-}
-
-/**
- * Escapes a string.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $string The value to be escaped
- * @param string $strategy The escaping strategy
- * @param string $charset The charset
- * @param Boolean $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
- */
-function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
-{
- if ($autoescape && $string instanceof Twig_Markup) {
- return $string;
- }
-
- if (!is_string($string)) {
- if (is_object($string) && method_exists($string, '__toString')) {
- $string = (string) $string;
- } else {
- return $string;
- }
- }
-
- if (null === $charset) {
- $charset = $env->getCharset();
- }
-
- switch ($strategy) {
- case 'html':
- // see http://php.net/htmlspecialchars
-
- // Using a static variable to avoid initializing the array
- // each time the function is called. Moving the declaration on the
- // top of the function slow downs other escaping strategies.
- static $htmlspecialcharsCharsets = array(
- 'ISO-8859-1' => true, 'ISO8859-1' => true,
- 'ISO-8859-15' => true, 'ISO8859-15' => true,
- 'utf-8' => true, 'UTF-8' => true,
- 'CP866' => true, 'IBM866' => true, '866' => true,
- 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
- '1251' => true,
- 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
- 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
- 'BIG5' => true, '950' => true,
- 'GB2312' => true, '936' => true,
- 'BIG5-HKSCS' => true,
- 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
- 'EUC-JP' => true, 'EUCJP' => true,
- 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
- );
-
- if (isset($htmlspecialcharsCharsets[$charset])) {
- return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
- }
-
- if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
- // cache the lowercase variant for future iterations
- $htmlspecialcharsCharsets[$charset] = true;
-
- return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
- }
-
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
- $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
-
- return twig_convert_encoding($string, $charset, 'UTF-8');
-
- case 'js':
- // escape all non-alphanumeric characters
- // into their \xHH or \uHHHH representations
- if ('UTF-8' != $charset) {
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
- }
-
- if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
- throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
- }
-
- $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string);
-
- if ('UTF-8' != $charset) {
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
- }
-
- return $string;
-
- case 'css':
- if ('UTF-8' != $charset) {
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
- }
-
- if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
- throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
- }
-
- $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string);
-
- if ('UTF-8' != $charset) {
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
- }
-
- return $string;
-
- case 'html_attr':
- if ('UTF-8' != $charset) {
- $string = twig_convert_encoding($string, 'UTF-8', $charset);
- }
-
- if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
- throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
- }
-
- $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string);
-
- if ('UTF-8' != $charset) {
- $string = twig_convert_encoding($string, $charset, 'UTF-8');
- }
-
- return $string;
-
- case 'url':
- // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
- // at that point however PHP 5.2.* support can be removed
- if (PHP_VERSION < '5.3.0') {
- return str_replace('%7E', '~', rawurlencode($string));
- }
-
- return rawurlencode($string);
-
- default:
- throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: html, js, url, css, and html_attr).', $strategy));
- }
-}
-
-/* used internally */
-function twig_escape_filter_is_safe(Twig_Node $filterArgs)
-{
- foreach ($filterArgs as $arg) {
- if ($arg instanceof Twig_Node_Expression_Constant) {
- return array($arg->getAttribute('value'));
- }
-
- return array();
- }
-
- return array('html');
-}
-
-if (function_exists('mb_convert_encoding')) {
- function twig_convert_encoding($string, $to, $from)
- {
- return mb_convert_encoding($string, $to, $from);
- }
-} elseif (function_exists('iconv')) {
- function twig_convert_encoding($string, $to, $from)
- {
- return iconv($from, $to, $string);
- }
-} else {
- function twig_convert_encoding($string, $to, $from)
- {
- throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
- }
-}
-
-function _twig_escape_js_callback($matches)
-{
- $char = $matches[0];
-
- // \xHH
- if (!isset($char[1])) {
- return '\\x'.strtoupper(substr('00'.bin2hex($char), -2));
- }
-
- // \uHHHH
- $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
-
- return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
-}
-
-function _twig_escape_css_callback($matches)
-{
- $char = $matches[0];
-
- // \xHH
- if (!isset($char[1])) {
- $hex = ltrim(strtoupper(bin2hex($char)), '0');
- if (0 === strlen($hex)) {
- $hex = '0';
- }
-
- return '\\'.$hex.' ';
- }
-
- // \uHHHH
- $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
-
- return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
-}
-
-/**
- * This function is adapted from code coming from Zend Framework.
- *
- * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
-function _twig_escape_html_attr_callback($matches)
-{
- /*
- * While HTML supports far more named entities, the lowest common denominator
- * has become HTML5's XML Serialisation which is restricted to the those named
- * entities that XML supports. Using HTML entities would result in this error:
- * XML Parsing Error: undefined entity
- */
- static $entityMap = array(
- 34 => 'quot', /* quotation mark */
- 38 => 'amp', /* ampersand */
- 60 => 'lt', /* less-than sign */
- 62 => 'gt', /* greater-than sign */
- );
-
- $chr = $matches[0];
- $ord = ord($chr);
-
- /**
- * The following replaces characters undefined in HTML with the
- * hex entity for the Unicode replacement character.
- */
- if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) {
- return '�';
- }
-
- /**
- * Check if the current character to escape has a name entity we should
- * replace it with while grabbing the hex value of the character.
- */
- if (strlen($chr) == 1) {
- $hex = strtoupper(substr('00'.bin2hex($chr), -2));
- } else {
- $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8');
- $hex = strtoupper(substr('0000'.bin2hex($chr), -4));
- }
-
- $int = hexdec($hex);
- if (array_key_exists($int, $entityMap)) {
- return sprintf('&%s;', $entityMap[$int]);
- }
-
- /**
- * Per OWASP recommendations, we'll use hex entities for any other
- * characters where a named entity does not exist.
- */
-
- return sprintf('&#x%s;', $hex);
-}
-
-// add multibyte extensions if possible
-if (function_exists('mb_get_info')) {
- /**
- * Returns the length of a variable.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param mixed $thing A variable
- *
- * @return integer The length of the value
- */
- function twig_length_filter(Twig_Environment $env, $thing)
- {
- return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
- }
-
- /**
- * Converts a string to uppercase.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $string A string
- *
- * @return string The uppercased string
- */
- function twig_upper_filter(Twig_Environment $env, $string)
- {
- if (null !== ($charset = $env->getCharset())) {
- return mb_strtoupper($string, $charset);
- }
-
- return strtoupper($string);
- }
-
- /**
- * Converts a string to lowercase.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $string A string
- *
- * @return string The lowercased string
- */
- function twig_lower_filter(Twig_Environment $env, $string)
- {
- if (null !== ($charset = $env->getCharset())) {
- return mb_strtolower($string, $charset);
- }
-
- return strtolower($string);
- }
-
- /**
- * Returns a titlecased string.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $string A string
- *
- * @return string The titlecased string
- */
- function twig_title_string_filter(Twig_Environment $env, $string)
- {
- if (null !== ($charset = $env->getCharset())) {
- return mb_convert_case($string, MB_CASE_TITLE, $charset);
- }
-
- return ucwords(strtolower($string));
- }
-
- /**
- * Returns a capitalized string.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $string A string
- *
- * @return string The capitalized string
- */
- function twig_capitalize_string_filter(Twig_Environment $env, $string)
- {
- if (null !== ($charset = $env->getCharset())) {
- return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
- mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
- }
-
- return ucfirst(strtolower($string));
- }
-}
-// and byte fallback
-else {
- /**
- * Returns the length of a variable.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param mixed $thing A variable
- *
- * @return integer The length of the value
- */
- function twig_length_filter(Twig_Environment $env, $thing)
- {
- return is_scalar($thing) ? strlen($thing) : count($thing);
- }
-
- /**
- * Returns a titlecased string.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $string A string
- *
- * @return string The titlecased string
- */
- function twig_title_string_filter(Twig_Environment $env, $string)
- {
- return ucwords(strtolower($string));
- }
-
- /**
- * Returns a capitalized string.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $string A string
- *
- * @return string The capitalized string
- */
- function twig_capitalize_string_filter(Twig_Environment $env, $string)
- {
- return ucfirst(strtolower($string));
- }
-}
-
-/* used internally */
-function twig_ensure_traversable($seq)
-{
- if ($seq instanceof Traversable || is_array($seq)) {
- return $seq;
- }
-
- return array();
-}
-
-/**
- * Checks if a variable is empty.
- *
- * <pre>
- * {# evaluates to true if the foo variable is null, false, or the empty string #}
- * {% if foo is empty %}
- * {# ... #}
- * {% endif %}
- * </pre>
- *
- * @param mixed $value A variable
- *
- * @return Boolean true if the value is empty, false otherwise
- */
-function twig_test_empty($value)
-{
- if ($value instanceof Countable) {
- return 0 == count($value);
- }
-
- return '' === $value || false === $value || null === $value || array() === $value;
-}
-
-/**
- * Checks if a variable is traversable.
- *
- * <pre>
- * {# evaluates to true if the foo variable is an array or a traversable object #}
- * {% if foo is traversable %}
- * {# ... #}
- * {% endif %}
- * </pre>
- *
- * @param mixed $value A variable
- *
- * @return Boolean true if the value is traversable
- */
-function twig_test_iterable($value)
-{
- return $value instanceof Traversable || is_array($value);
-}
-
-/**
- * Renders a template.
- *
- * @param string $template The template to render
- * @param array $variables The variables to pass to the template
- * @param Boolean $with_context Whether to pass the current context variables or not
- * @param Boolean $ignore_missing Whether to ignore missing templates or not
- * @param Boolean $sandboxed Whether to sandbox the template or not
- *
- * @return string The rendered template
- */
-function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
-{
- if ($withContext) {
- $variables = array_merge($context, $variables);
- }
-
- if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) {
- $sandbox = $env->getExtension('sandbox');
- if (!$alreadySandboxed = $sandbox->isSandboxed()) {
- $sandbox->enableSandbox();
- }
- }
-
- try {
- return $env->resolveTemplate($template)->render($variables);
- } catch (Twig_Error_Loader $e) {
- if (!$ignoreMissing) {
- throw $e;
- }
- }
-
- if ($isSandboxed && !$alreadySandboxed) {
- $sandbox->disableSandbox();
- }
-}
-
-/**
- * Provides the ability to get constants from instances as well as class/global constants.
- *
- * @param string $constant The name of the constant
- * @param null|object $object The object to get the constant from
- *
- * @return string
- */
-function twig_constant($constant, $object = null)
-{
- if (null !== $object) {
- $constant = get_class($object).'::'.$constant;
- }
-
- return constant($constant);
-}
-
-/**
- * Batches item.
- *
- * @param array $items An array of items
- * @param integer $size The size of the batch
- * @param string $fill A string to fill missing items
- *
- * @return array
- */
-function twig_array_batch($items, $size, $fill = null)
-{
- if ($items instanceof Traversable) {
- $items = iterator_to_array($items, false);
- }
-
- $size = ceil($size);
-
- $result = array_chunk($items, $size, true);
-
- if (null !== $fill) {
- $last = count($result) - 1;
- $result[$last] = array_merge(
- $result[$last],
- array_fill(0, $size - count($result[$last]), $fill)
- );
- }
-
- return $result;
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Extension_Debug extends Twig_Extension
-{
- /**
- * Returns a list of global functions to add to the existing list.
- *
- * @return array An array of global functions
- */
- public function getFunctions()
- {
- // dump is safe if var_dump is overridden by xdebug
- $isDumpOutputHtmlSafe = extension_loaded('xdebug')
- // false means that it was not set (and the default is on) or it explicitly enabled
- && (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
- // false means that it was not set (and the default is on) or it explicitly enabled
- // xdebug.overload_var_dump produces HTML only when html_errors is also enabled
- && (false === ini_get('html_errors') || ini_get('html_errors'))
- || 'cli' === php_sapi_name()
- ;
-
- return array(
- new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
- );
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'debug';
- }
-}
-
-function twig_var_dump(Twig_Environment $env, $context)
-{
- if (!$env->isDebug()) {
- return;
- }
-
- ob_start();
-
- $count = func_num_args();
- if (2 === $count) {
- $vars = array();
- foreach ($context as $key => $value) {
- if (!$value instanceof Twig_Template) {
- $vars[$key] = $value;
- }
- }
-
- var_dump($vars);
- } else {
- for ($i = 2; $i < $count; $i++) {
- var_dump(func_get_arg($i));
- }
- }
-
- return ob_get_clean();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Extension_Escaper extends Twig_Extension
-{
- protected $defaultStrategy;
-
- public function __construct($defaultStrategy = 'html')
- {
- $this->setDefaultStrategy($defaultStrategy);
- }
-
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- public function getTokenParsers()
- {
- return array(new Twig_TokenParser_AutoEscape());
- }
-
- /**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- public function getNodeVisitors()
- {
- return array(new Twig_NodeVisitor_Escaper());
- }
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- public function getFilters()
- {
- return array(
- new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
- );
- }
-
- /**
- * Sets the default strategy to use when not defined by the user.
- *
- * The strategy can be a valid PHP callback that takes the template
- * "filename" as an argument and returns the strategy to use.
- *
- * @param mixed $defaultStrategy An escaping strategy
- */
- public function setDefaultStrategy($defaultStrategy)
- {
- // for BC
- if (true === $defaultStrategy) {
- $defaultStrategy = 'html';
- }
-
- $this->defaultStrategy = $defaultStrategy;
- }
-
- /**
- * Gets the default strategy to use when not defined by the user.
- *
- * @param string $filename The template "filename"
- *
- * @return string The default strategy to use for the template
- */
- public function getDefaultStrategy($filename)
- {
- // disable string callables to avoid calling a function named html or js,
- // or any other upcoming escaping strategy
- if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
- return call_user_func($this->defaultStrategy, $filename);
- }
-
- return $this->defaultStrategy;
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'escaper';
- }
-}
-
-/**
- * Marks a variable as being safe.
- *
- * @param string $string A PHP variable
- */
-function twig_raw_filter($string)
-{
- return $string;
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Extension_Optimizer extends Twig_Extension
-{
- protected $optimizers;
-
- public function __construct($optimizers = -1)
- {
- $this->optimizers = $optimizers;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getNodeVisitors()
- {
- return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'optimizer';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Extension_Sandbox extends Twig_Extension
-{
- protected $sandboxedGlobally;
- protected $sandboxed;
- protected $policy;
-
- public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
- {
- $this->policy = $policy;
- $this->sandboxedGlobally = $sandboxed;
- }
-
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- public function getTokenParsers()
- {
- return array(new Twig_TokenParser_Sandbox());
- }
-
- /**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- public function getNodeVisitors()
- {
- return array(new Twig_NodeVisitor_Sandbox());
- }
-
- public function enableSandbox()
- {
- $this->sandboxed = true;
- }
-
- public function disableSandbox()
- {
- $this->sandboxed = false;
- }
-
- public function isSandboxed()
- {
- return $this->sandboxedGlobally || $this->sandboxed;
- }
-
- public function isSandboxedGlobally()
- {
- return $this->sandboxedGlobally;
- }
-
- public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
- {
- $this->policy = $policy;
- }
-
- public function getSecurityPolicy()
- {
- return $this->policy;
- }
-
- public function checkSecurity($tags, $filters, $functions)
- {
- if ($this->isSandboxed()) {
- $this->policy->checkSecurity($tags, $filters, $functions);
- }
- }
-
- public function checkMethodAllowed($obj, $method)
- {
- if ($this->isSandboxed()) {
- $this->policy->checkMethodAllowed($obj, $method);
- }
- }
-
- public function checkPropertyAllowed($obj, $method)
- {
- if ($this->isSandboxed()) {
- $this->policy->checkPropertyAllowed($obj, $method);
- }
- }
-
- public function ensureToStringAllowed($obj)
- {
- if (is_object($obj)) {
- $this->policy->checkMethodAllowed($obj, '__toString');
- }
-
- return $obj;
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'sandbox';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Internal class.
- *
- * This class is used by Twig_Environment as a staging area and must not be used directly.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Extension_Staging extends Twig_Extension
-{
- protected $functions = array();
- protected $filters = array();
- protected $visitors = array();
- protected $tokenParsers = array();
- protected $globals = array();
- protected $tests = array();
-
- public function addFunction($name, $function)
- {
- $this->functions[$name] = $function;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFunctions()
- {
- return $this->functions;
- }
-
- public function addFilter($name, $filter)
- {
- $this->filters[$name] = $filter;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFilters()
- {
- return $this->filters;
- }
-
- public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
- {
- $this->visitors[] = $visitor;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getNodeVisitors()
- {
- return $this->visitors;
- }
-
- public function addTokenParser(Twig_TokenParserInterface $parser)
- {
- $this->tokenParsers[] = $parser;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTokenParsers()
- {
- return $this->tokenParsers;
- }
-
- public function addGlobal($name, $value)
- {
- $this->globals[$name] = $value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getGlobals()
- {
- return $this->globals;
- }
-
- public function addTest($name, $test)
- {
- $this->tests[$name] = $test;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTests()
- {
- return $this->tests;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'staging';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Extension_StringLoader extends Twig_Extension
-{
- /**
- * {@inheritdoc}
- */
- public function getFunctions()
- {
- return array(
- new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'string_loader';
- }
-}
-
-/**
- * Loads a template from a string.
- *
- * <pre>
- * {{ include(template_from_string("Hello {{ name }}")) }}
- * </pre>
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param string $template A template as a string
- *
- * @return Twig_Template A Twig_Template instance
- */
-function twig_template_from_string(Twig_Environment $env, $template)
-{
- static $loader;
-
- if (null === $loader) {
- $loader = new Twig_Loader_String();
- }
-
- $current = $env->getLoader();
- $env->setLoader($loader);
- try {
- $template = $env->loadTemplate($template);
- } catch (Exception $e) {
- $env->setLoader($current);
-
- throw $e;
- }
- $env->setLoader($current);
-
- return $template;
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by extension classes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface Twig_ExtensionInterface
-{
- /**
- * Initializes the runtime environment.
- *
- * This is where you can load some file that contains filter functions for instance.
- *
- * @param Twig_Environment $environment The current Twig_Environment instance
- */
- public function initRuntime(Twig_Environment $environment);
-
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- public function getTokenParsers();
-
- /**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- public function getNodeVisitors();
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- public function getFilters();
-
- /**
- * Returns a list of tests to add to the existing list.
- *
- * @return array An array of tests
- */
- public function getTests();
-
- /**
- * Returns a list of functions to add to the existing list.
- *
- * @return array An array of functions
- */
- public function getFunctions();
-
- /**
- * Returns a list of operators to add to the existing list.
- *
- * @return array An array of operators
- */
- public function getOperators();
-
- /**
- * Returns a list of global variables to add to the existing list.
- *
- * @return array An array of global variables
- */
- public function getGlobals();
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template filter.
- *
- * Use Twig_SimpleFilter instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
-{
- protected $options;
- protected $arguments = array();
-
- public function __construct(array $options = array())
- {
- $this->options = array_merge(array(
- 'needs_environment' => false,
- 'needs_context' => false,
- 'pre_escape' => null,
- 'preserves_safety' => null,
- 'callable' => null,
- ), $options);
- }
-
- public function setArguments($arguments)
- {
- $this->arguments = $arguments;
- }
-
- public function getArguments()
- {
- return $this->arguments;
- }
-
- public function needsEnvironment()
- {
- return $this->options['needs_environment'];
- }
-
- public function needsContext()
- {
- return $this->options['needs_context'];
- }
-
- public function getSafe(Twig_Node $filterArgs)
- {
- if (isset($this->options['is_safe'])) {
- return $this->options['is_safe'];
- }
-
- if (isset($this->options['is_safe_callback'])) {
- return call_user_func($this->options['is_safe_callback'], $filterArgs);
- }
- }
-
- public function getPreservesSafety()
- {
- return $this->options['preserves_safety'];
- }
-
- public function getPreEscape()
- {
- return $this->options['pre_escape'];
- }
-
- public function getCallable()
- {
- return $this->options['callable'];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a function template filter.
- *
- * Use Twig_SimpleFilter instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Filter_Function extends Twig_Filter
-{
- protected $function;
-
- public function __construct($function, array $options = array())
- {
- $options['callable'] = $function;
-
- parent::__construct($options);
-
- $this->function = $function;
- }
-
- public function compile()
- {
- return $this->function;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a method template filter.
- *
- * Use Twig_SimpleFilter instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Filter_Method extends Twig_Filter
-{
- protected $extension;
- protected $method;
-
- public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
- {
- $options['callable'] = array($extension, $method);
-
- parent::__construct($options);
-
- $this->extension = $extension;
- $this->method = $method;
- }
-
- public function compile()
- {
- return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template filter as a node.
- *
- * Use Twig_SimpleFilter instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Filter_Node extends Twig_Filter
-{
- protected $class;
-
- public function __construct($class, array $options = array())
- {
- parent::__construct($options);
-
- $this->class = $class;
- }
-
- public function getClass()
- {
- return $this->class;
- }
-
- public function compile()
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a callable template filter.
- *
- * Use Twig_SimpleFilter instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_FilterCallableInterface
-{
- public function getCallable();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template filter.
- *
- * Use Twig_SimpleFilter instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_FilterInterface
-{
- /**
- * Compiles a filter.
- *
- * @return string The PHP code for the filter
- */
- public function compile();
-
- public function needsEnvironment();
-
- public function needsContext();
-
- public function getSafe(Twig_Node $filterArgs);
-
- public function getPreservesSafety();
-
- public function getPreEscape();
-
- public function setArguments($arguments);
-
- public function getArguments();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template function.
- *
- * Use Twig_SimpleFunction instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
-{
- protected $options;
- protected $arguments = array();
-
- public function __construct(array $options = array())
- {
- $this->options = array_merge(array(
- 'needs_environment' => false,
- 'needs_context' => false,
- 'callable' => null,
- ), $options);
- }
-
- public function setArguments($arguments)
- {
- $this->arguments = $arguments;
- }
-
- public function getArguments()
- {
- return $this->arguments;
- }
-
- public function needsEnvironment()
- {
- return $this->options['needs_environment'];
- }
-
- public function needsContext()
- {
- return $this->options['needs_context'];
- }
-
- public function getSafe(Twig_Node $functionArgs)
- {
- if (isset($this->options['is_safe'])) {
- return $this->options['is_safe'];
- }
-
- if (isset($this->options['is_safe_callback'])) {
- return call_user_func($this->options['is_safe_callback'], $functionArgs);
- }
-
- return array();
- }
-
- public function getCallable()
- {
- return $this->options['callable'];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2010 Arnaud Le Blanc
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a function template function.
- *
- * Use Twig_SimpleFunction instead.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Function_Function extends Twig_Function
-{
- protected $function;
-
- public function __construct($function, array $options = array())
- {
- $options['callable'] = $function;
-
- parent::__construct($options);
-
- $this->function = $function;
- }
-
- public function compile()
- {
- return $this->function;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2010 Arnaud Le Blanc
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a method template function.
- *
- * Use Twig_SimpleFunction instead.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Function_Method extends Twig_Function
-{
- protected $extension;
- protected $method;
-
- public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
- {
- $options['callable'] = array($extension, $method);
-
- parent::__construct($options);
-
- $this->extension = $extension;
- $this->method = $method;
- }
-
- public function compile()
- {
- return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template function as a node.
- *
- * Use Twig_SimpleFunction instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Function_Node extends Twig_Function
-{
- protected $class;
-
- public function __construct($class, array $options = array())
- {
- parent::__construct($options);
-
- $this->class = $class;
- }
-
- public function getClass()
- {
- return $this->class;
- }
-
- public function compile()
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a callable template function.
- *
- * Use Twig_SimpleFunction instead.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_FunctionCallableInterface
-{
- public function getCallable();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- * (c) 2010 Arnaud Le Blanc
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template function.
- *
- * Use Twig_SimpleFunction instead.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_FunctionInterface
-{
- /**
- * Compiles a function.
- *
- * @return string The PHP code for the function
- */
- public function compile();
-
- public function needsEnvironment();
-
- public function needsContext();
-
- public function getSafe(Twig_Node $filterArgs);
-
- public function setArguments($arguments);
-
- public function getArguments();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Lexes a template string.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Lexer implements Twig_LexerInterface
-{
- protected $tokens;
- protected $code;
- protected $cursor;
- protected $lineno;
- protected $end;
- protected $state;
- protected $states;
- protected $brackets;
- protected $env;
- protected $filename;
- protected $options;
- protected $regexes;
- protected $position;
- protected $positions;
- protected $currentVarBlockLine;
-
- const STATE_DATA = 0;
- const STATE_BLOCK = 1;
- const STATE_VAR = 2;
- const STATE_STRING = 3;
- const STATE_INTERPOLATION = 4;
-
- const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
- const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
- const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
- const REGEX_DQ_STRING_DELIM = '/"/A';
- const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
- const PUNCTUATION = '()[]{}?:.,|';
-
- public function __construct(Twig_Environment $env, array $options = array())
- {
- $this->env = $env;
-
- $this->options = array_merge(array(
- 'tag_comment' => array('{#', '#}'),
- 'tag_block' => array('{%', '%}'),
- 'tag_variable' => array('{{', '}}'),
- 'whitespace_trim' => '-',
- 'interpolation' => array('#{', '}'),
- ), $options);
-
- $this->regexes = array(
- 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
- 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
- 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
- 'operator' => $this->getOperatorRegex(),
- 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
- 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
- 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
- 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
- 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
- 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
- );
- }
-
- /**
- * Tokenizes a source code.
- *
- * @param string $code The source code
- * @param string $filename A unique identifier for the source code
- *
- * @return Twig_TokenStream A token stream instance
- */
- public function tokenize($code, $filename = null)
- {
- if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
- $mbEncoding = mb_internal_encoding();
- mb_internal_encoding('ASCII');
- }
-
- $this->code = str_replace(array("\r\n", "\r"), "\n", $code);
- $this->filename = $filename;
- $this->cursor = 0;
- $this->lineno = 1;
- $this->end = strlen($this->code);
- $this->tokens = array();
- $this->state = self::STATE_DATA;
- $this->states = array();
- $this->brackets = array();
- $this->position = -1;
-
- // find all token starts in one go
- preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
- $this->positions = $matches;
-
- while ($this->cursor < $this->end) {
- // dispatch to the lexing functions depending
- // on the current state
- switch ($this->state) {
- case self::STATE_DATA:
- $this->lexData();
- break;
-
- case self::STATE_BLOCK:
- $this->lexBlock();
- break;
-
- case self::STATE_VAR:
- $this->lexVar();
- break;
-
- case self::STATE_STRING:
- $this->lexString();
- break;
-
- case self::STATE_INTERPOLATION:
- $this->lexInterpolation();
- break;
- }
- }
-
- $this->pushToken(Twig_Token::EOF_TYPE);
-
- if (!empty($this->brackets)) {
- list($expect, $lineno) = array_pop($this->brackets);
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
- }
-
- if (isset($mbEncoding)) {
- mb_internal_encoding($mbEncoding);
- }
-
- return new Twig_TokenStream($this->tokens, $this->filename);
- }
-
- protected function lexData()
- {
- // if no matches are left we return the rest of the template as simple text token
- if ($this->position == count($this->positions[0]) - 1) {
- $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
- $this->cursor = $this->end;
-
- return;
- }
-
- // Find the first token after the current cursor
- $position = $this->positions[0][++$this->position];
- while ($position[1] < $this->cursor) {
- if ($this->position == count($this->positions[0]) - 1) {
- return;
- }
- $position = $this->positions[0][++$this->position];
- }
-
- // push the template text first
- $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
- if (isset($this->positions[2][$this->position][0])) {
- $text = rtrim($text);
- }
- $this->pushToken(Twig_Token::TEXT_TYPE, $text);
- $this->moveCursor($textContent.$position[0]);
-
- switch ($this->positions[1][$this->position][0]) {
- case $this->options['tag_comment'][0]:
- $this->lexComment();
- break;
-
- case $this->options['tag_block'][0]:
- // raw data?
- if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
- $this->moveCursor($match[0]);
- $this->lexRawData($match[1]);
- // {% line \d+ %}
- } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
- $this->moveCursor($match[0]);
- $this->lineno = (int) $match[1];
- } else {
- $this->pushToken(Twig_Token::BLOCK_START_TYPE);
- $this->pushState(self::STATE_BLOCK);
- $this->currentVarBlockLine = $this->lineno;
- }
- break;
-
- case $this->options['tag_variable'][0]:
- $this->pushToken(Twig_Token::VAR_START_TYPE);
- $this->pushState(self::STATE_VAR);
- $this->currentVarBlockLine = $this->lineno;
- break;
- }
- }
-
- protected function lexBlock()
- {
- if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
- $this->pushToken(Twig_Token::BLOCK_END_TYPE);
- $this->moveCursor($match[0]);
- $this->popState();
- } else {
- $this->lexExpression();
- }
- }
-
- protected function lexVar()
- {
- if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
- $this->pushToken(Twig_Token::VAR_END_TYPE);
- $this->moveCursor($match[0]);
- $this->popState();
- } else {
- $this->lexExpression();
- }
- }
-
- protected function lexExpression()
- {
- // whitespace
- if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
- $this->moveCursor($match[0]);
-
- if ($this->cursor >= $this->end) {
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
- }
- }
-
- // operators
- if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
- $this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]);
- $this->moveCursor($match[0]);
- }
- // names
- elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
- $this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
- $this->moveCursor($match[0]);
- }
- // numbers
- elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
- $number = (float) $match[0]; // floats
- if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
- $number = (int) $match[0]; // integers lower than the maximum
- }
- $this->pushToken(Twig_Token::NUMBER_TYPE, $number);
- $this->moveCursor($match[0]);
- }
- // punctuation
- elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
- // opening bracket
- if (false !== strpos('([{', $this->code[$this->cursor])) {
- $this->brackets[] = array($this->code[$this->cursor], $this->lineno);
- }
- // closing bracket
- elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
- if (empty($this->brackets)) {
- throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
- }
-
- list($expect, $lineno) = array_pop($this->brackets);
- if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
- }
- }
-
- $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
- ++$this->cursor;
- }
- // strings
- elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
- $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
- $this->moveCursor($match[0]);
- }
- // opening double quoted string
- elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
- $this->brackets[] = array('"', $this->lineno);
- $this->pushState(self::STATE_STRING);
- $this->moveCursor($match[0]);
- }
- // unlexable
- else {
- throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
- }
- }
-
- protected function lexRawData($tag)
- {
- if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
- throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
- }
-
- $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
- $this->moveCursor($text.$match[0][0]);
-
- if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
- $text = rtrim($text);
- }
-
- $this->pushToken(Twig_Token::TEXT_TYPE, $text);
- }
-
- protected function lexComment()
- {
- if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
- throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
- }
-
- $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
- }
-
- protected function lexString()
- {
- if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
- $this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
- $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
- $this->moveCursor($match[0]);
- $this->pushState(self::STATE_INTERPOLATION);
-
- } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
- $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
- $this->moveCursor($match[0]);
-
- } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
-
- list($expect, $lineno) = array_pop($this->brackets);
- if ($this->code[$this->cursor] != '"') {
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
- }
-
- $this->popState();
- ++$this->cursor;
- }
- }
-
- protected function lexInterpolation()
- {
- $bracket = end($this->brackets);
- if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
- array_pop($this->brackets);
- $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
- $this->moveCursor($match[0]);
- $this->popState();
- } else {
- $this->lexExpression();
- }
- }
-
- protected function pushToken($type, $value = '')
- {
- // do not push empty text tokens
- if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
- return;
- }
-
- $this->tokens[] = new Twig_Token($type, $value, $this->lineno);
- }
-
- protected function moveCursor($text)
- {
- $this->cursor += strlen($text);
- $this->lineno += substr_count($text, "\n");
- }
-
- protected function getOperatorRegex()
- {
- $operators = array_merge(
- array('='),
- array_keys($this->env->getUnaryOperators()),
- array_keys($this->env->getBinaryOperators())
- );
-
- $operators = array_combine($operators, array_map('strlen', $operators));
- arsort($operators);
-
- $regex = array();
- foreach ($operators as $operator => $length) {
- // an operator that ends with a character must be followed by
- // a whitespace or a parenthesis
- if (ctype_alpha($operator[$length - 1])) {
- $regex[] = preg_quote($operator, '/').'(?=[\s()])';
- } else {
- $regex[] = preg_quote($operator, '/');
- }
- }
-
- return '/'.implode('|', $regex).'/A';
- }
-
- protected function pushState($state)
- {
- $this->states[] = $this->state;
- $this->state = $state;
- }
-
- protected function popState()
- {
- if (0 === count($this->states)) {
- throw new Exception('Cannot pop state without a previous state');
- }
-
- $this->state = array_pop($this->states);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by lexer classes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_LexerInterface
-{
- /**
- * Tokenizes a source code.
- *
- * @param string $code The source code
- * @param string $filename A unique identifier for the source code
- *
- * @return Twig_TokenStream A token stream instance
- */
- public function tokenize($code, $filename = null);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Loads a template from an array.
- *
- * When using this loader with a cache mechanism, you should know that a new cache
- * key is generated each time a template content "changes" (the cache key being the
- * source code of the template). If you don't want to see your cache grows out of
- * control, you need to take care of clearing the old cache file by yourself.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
-{
- protected $templates;
-
- /**
- * Constructor.
- *
- * @param array $templates An array of templates (keys are the names, and values are the source code)
- *
- * @see Twig_Loader
- */
- public function __construct(array $templates)
- {
- $this->templates = array();
- foreach ($templates as $name => $template) {
- $this->templates[$name] = $template;
- }
- }
-
- /**
- * Adds or overrides a template.
- *
- * @param string $name The template name
- * @param string $template The template source
- */
- public function setTemplate($name, $template)
- {
- $this->templates[(string) $name] = $template;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSource($name)
- {
- $name = (string) $name;
- if (!isset($this->templates[$name])) {
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
- }
-
- return $this->templates[$name];
- }
-
- /**
- * {@inheritdoc}
- */
- public function exists($name)
- {
- return isset($this->templates[(string) $name]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCacheKey($name)
- {
- $name = (string) $name;
- if (!isset($this->templates[$name])) {
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
- }
-
- return $this->templates[$name];
- }
-
- /**
- * {@inheritdoc}
- */
- public function isFresh($name, $time)
- {
- $name = (string) $name;
- if (!isset($this->templates[$name])) {
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
- }
-
- return true;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Loads templates from other loaders.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
-{
- private $hasSourceCache = array();
- protected $loaders;
-
- /**
- * Constructor.
- *
- * @param Twig_LoaderInterface[] $loaders An array of loader instances
- */
- public function __construct(array $loaders = array())
- {
- $this->loaders = array();
- foreach ($loaders as $loader) {
- $this->addLoader($loader);
- }
- }
-
- /**
- * Adds a loader instance.
- *
- * @param Twig_LoaderInterface $loader A Loader instance
- */
- public function addLoader(Twig_LoaderInterface $loader)
- {
- $this->loaders[] = $loader;
- $this->hasSourceCache = array();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSource($name)
- {
- $exceptions = array();
- foreach ($this->loaders as $loader) {
- if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
- continue;
- }
-
- try {
- return $loader->getSource($name);
- } catch (Twig_Error_Loader $e) {
- $exceptions[] = $e->getMessage();
- }
- }
-
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
- }
-
- /**
- * {@inheritdoc}
- */
- public function exists($name)
- {
- $name = (string) $name;
-
- if (isset($this->hasSourceCache[$name])) {
- return $this->hasSourceCache[$name];
- }
-
- foreach ($this->loaders as $loader) {
- if ($loader instanceof Twig_ExistsLoaderInterface) {
- if ($loader->exists($name)) {
- return $this->hasSourceCache[$name] = true;
- }
-
- continue;
- }
-
- try {
- $loader->getSource($name);
-
- return $this->hasSourceCache[$name] = true;
- } catch (Twig_Error_Loader $e) {
- }
- }
-
- return $this->hasSourceCache[$name] = false;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCacheKey($name)
- {
- $exceptions = array();
- foreach ($this->loaders as $loader) {
- if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
- continue;
- }
-
- try {
- return $loader->getCacheKey($name);
- } catch (Twig_Error_Loader $e) {
- $exceptions[] = get_class($loader).': '.$e->getMessage();
- }
- }
-
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
- }
-
- /**
- * {@inheritdoc}
- */
- public function isFresh($name, $time)
- {
- $exceptions = array();
- foreach ($this->loaders as $loader) {
- if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
- continue;
- }
-
- try {
- return $loader->isFresh($name, $time);
- } catch (Twig_Error_Loader $e) {
- $exceptions[] = get_class($loader).': '.$e->getMessage();
- }
- }
-
- throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Loads template from the filesystem.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
-{
- /** Identifier of the main namespace. */
- const MAIN_NAMESPACE = '__main__';
-
- protected $paths;
- protected $cache;
-
- /**
- * Constructor.
- *
- * @param string|array $paths A path or an array of paths where to look for templates
- */
- public function __construct($paths = array())
- {
- if ($paths) {
- $this->setPaths($paths);
- }
- }
-
- /**
- * Returns the paths to the templates.
- *
- * @param string $namespace A path namespace
- *
- * @return array The array of paths where to look for templates
- */
- public function getPaths($namespace = self::MAIN_NAMESPACE)
- {
- return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
- }
-
- /**
- * Returns the path namespaces.
- *
- * The main namespace is always defined.
- *
- * @return array The array of defined namespaces
- */
- public function getNamespaces()
- {
- return array_keys($this->paths);
- }
-
- /**
- * Sets the paths where templates are stored.
- *
- * @param string|array $paths A path or an array of paths where to look for templates
- * @param string $namespace A path namespace
- */
- public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
- {
- if (!is_array($paths)) {
- $paths = array($paths);
- }
-
- $this->paths[$namespace] = array();
- foreach ($paths as $path) {
- $this->addPath($path, $namespace);
- }
- }
-
- /**
- * Adds a path where templates are stored.
- *
- * @param string $path A path where to look for templates
- * @param string $namespace A path name
- *
- * @throws Twig_Error_Loader
- */
- public function addPath($path, $namespace = self::MAIN_NAMESPACE)
- {
- // invalidate the cache
- $this->cache = array();
-
- if (!is_dir($path)) {
- throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
- }
-
- $this->paths[$namespace][] = rtrim($path, '/\\');
- }
-
- /**
- * Prepends a path where templates are stored.
- *
- * @param string $path A path where to look for templates
- * @param string $namespace A path name
- *
- * @throws Twig_Error_Loader
- */
- public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
- {
- // invalidate the cache
- $this->cache = array();
-
- if (!is_dir($path)) {
- throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
- }
-
- $path = rtrim($path, '/\\');
-
- if (!isset($this->paths[$namespace])) {
- $this->paths[$namespace][] = $path;
- } else {
- array_unshift($this->paths[$namespace], $path);
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSource($name)
- {
- return file_get_contents($this->findTemplate($name));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCacheKey($name)
- {
- return $this->findTemplate($name);
- }
-
- /**
- * {@inheritdoc}
- */
- public function exists($name)
- {
- $name = (string) $name;
- if (isset($this->cache[$name])) {
- return true;
- }
-
- try {
- $this->findTemplate($name);
-
- return true;
- } catch (Twig_Error_Loader $exception) {
- return false;
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function isFresh($name, $time)
- {
- return filemtime($this->findTemplate($name)) <= $time;
- }
-
- protected function findTemplate($name)
- {
- $name = (string) $name;
-
- // normalize name
- $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
-
- if (isset($this->cache[$name])) {
- return $this->cache[$name];
- }
-
- $this->validateName($name);
-
- $namespace = self::MAIN_NAMESPACE;
- if (isset($name[0]) && '@' == $name[0]) {
- if (false === $pos = strpos($name, '/')) {
- throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
- }
-
- $namespace = substr($name, 1, $pos - 1);
-
- $name = substr($name, $pos + 1);
- }
-
- if (!isset($this->paths[$namespace])) {
- throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
- }
-
- foreach ($this->paths[$namespace] as $path) {
- if (is_file($path.'/'.$name)) {
- return $this->cache[$name] = $path.'/'.$name;
- }
- }
-
- throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
- }
-
- protected function validateName($name)
- {
- if (false !== strpos($name, "\0")) {
- throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
- }
-
- $name = ltrim($name, '/');
- $parts = explode('/', $name);
- $level = 0;
- foreach ($parts as $part) {
- if ('..' === $part) {
- --$level;
- } elseif ('.' !== $part) {
- ++$level;
- }
-
- if ($level < 0) {
- throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Loads a template from a string.
- *
- * This loader should only be used for unit testing as it has many limitations
- * (for instance, the include or extends tag does not make any sense for a string
- * loader).
- *
- * When using this loader with a cache mechanism, you should know that a new cache
- * key is generated each time a template content "changes" (the cache key being the
- * source code of the template). If you don't want to see your cache grows out of
- * control, you need to take care of clearing the old cache file by yourself.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
-{
- /**
- * {@inheritdoc}
- */
- public function getSource($name)
- {
- return $name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function exists($name)
- {
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCacheKey($name)
- {
- return $name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isFresh($name, $time)
- {
- return true;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface all loaders must implement.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface Twig_LoaderInterface
-{
- /**
- * Gets the source code of a template, given its name.
- *
- * @param string $name The name of the template to load
- *
- * @return string The template source code
- *
- * @throws Twig_Error_Loader When $name is not found
- */
- public function getSource($name);
-
- /**
- * Gets the cache key to use for the cache for a given template name.
- *
- * @param string $name The name of the template to load
- *
- * @return string The cache key
- *
- * @throws Twig_Error_Loader When $name is not found
- */
- public function getCacheKey($name);
-
- /**
- * Returns true if the template is still fresh.
- *
- * @param string $name The template name
- * @param timestamp $time The last modification time of the cached template
- *
- * @return Boolean true if the template is fresh, false otherwise
- *
- * @throws Twig_Error_Loader When $name is not found
- */
- public function isFresh($name, $time);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Marks a content as safe.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Markup implements Countable
-{
- protected $content;
- protected $charset;
-
- public function __construct($content, $charset)
- {
- $this->content = (string) $content;
- $this->charset = $charset;
- }
-
- public function __toString()
- {
- return $this->content;
- }
-
- public function count()
- {
- return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a node in the AST.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node implements Twig_NodeInterface
-{
- protected $nodes;
- protected $attributes;
- protected $lineno;
- protected $tag;
-
- /**
- * Constructor.
- *
- * The nodes are automatically made available as properties ($this->node).
- * The attributes are automatically made available as array items ($this['name']).
- *
- * @param array $nodes An array of named nodes
- * @param array $attributes An array of attributes (should not be nodes)
- * @param integer $lineno The line number
- * @param string $tag The tag name associated with the Node
- */
- public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
- {
- $this->nodes = $nodes;
- $this->attributes = $attributes;
- $this->lineno = $lineno;
- $this->tag = $tag;
- }
-
- public function __toString()
- {
- $attributes = array();
- foreach ($this->attributes as $name => $value) {
- $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
- }
-
- $repr = array(get_class($this).'('.implode(', ', $attributes));
-
- if (count($this->nodes)) {
- foreach ($this->nodes as $name => $node) {
- $len = strlen($name) + 4;
- $noderepr = array();
- foreach (explode("\n", (string) $node) as $line) {
- $noderepr[] = str_repeat(' ', $len).$line;
- }
-
- $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
- }
-
- $repr[] = ')';
- } else {
- $repr[0] .= ')';
- }
-
- return implode("\n", $repr);
- }
-
- public function toXml($asDom = false)
- {
- $dom = new DOMDocument('1.0', 'UTF-8');
- $dom->formatOutput = true;
- $dom->appendChild($xml = $dom->createElement('twig'));
-
- $xml->appendChild($node = $dom->createElement('node'));
- $node->setAttribute('class', get_class($this));
-
- foreach ($this->attributes as $name => $value) {
- $node->appendChild($attribute = $dom->createElement('attribute'));
- $attribute->setAttribute('name', $name);
- $attribute->appendChild($dom->createTextNode($value));
- }
-
- foreach ($this->nodes as $name => $n) {
- if (null === $n) {
- continue;
- }
-
- $child = $n->toXml(true)->getElementsByTagName('node')->item(0);
- $child = $dom->importNode($child, true);
- $child->setAttribute('name', $name);
-
- $node->appendChild($child);
- }
-
- return $asDom ? $dom : $dom->saveXml();
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- foreach ($this->nodes as $node) {
- $node->compile($compiler);
- }
- }
-
- public function getLine()
- {
- return $this->lineno;
- }
-
- public function getNodeTag()
- {
- return $this->tag;
- }
-
- /**
- * Returns true if the attribute is defined.
- *
- * @param string The attribute name
- *
- * @return Boolean true if the attribute is defined, false otherwise
- */
- public function hasAttribute($name)
- {
- return array_key_exists($name, $this->attributes);
- }
-
- /**
- * Gets an attribute.
- *
- * @param string The attribute name
- *
- * @return mixed The attribute value
- */
- public function getAttribute($name)
- {
- if (!array_key_exists($name, $this->attributes)) {
- throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
- }
-
- return $this->attributes[$name];
- }
-
- /**
- * Sets an attribute.
- *
- * @param string The attribute name
- * @param mixed The attribute value
- */
- public function setAttribute($name, $value)
- {
- $this->attributes[$name] = $value;
- }
-
- /**
- * Removes an attribute.
- *
- * @param string The attribute name
- */
- public function removeAttribute($name)
- {
- unset($this->attributes[$name]);
- }
-
- /**
- * Returns true if the node with the given identifier exists.
- *
- * @param string The node name
- *
- * @return Boolean true if the node with the given name exists, false otherwise
- */
- public function hasNode($name)
- {
- return array_key_exists($name, $this->nodes);
- }
-
- /**
- * Gets a node by name.
- *
- * @param string The node name
- *
- * @return Twig_Node A Twig_Node instance
- */
- public function getNode($name)
- {
- if (!array_key_exists($name, $this->nodes)) {
- throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
- }
-
- return $this->nodes[$name];
- }
-
- /**
- * Sets a node.
- *
- * @param string The node name
- * @param Twig_Node A Twig_Node instance
- */
- public function setNode($name, $node = null)
- {
- $this->nodes[$name] = $node;
- }
-
- /**
- * Removes a node by name.
- *
- * @param string The node name
- */
- public function removeNode($name)
- {
- unset($this->nodes[$name]);
- }
-
- public function count()
- {
- return count($this->nodes);
- }
-
- public function getIterator()
- {
- return new ArrayIterator($this->nodes);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents an autoescape node.
- *
- * The value is the escaping strategy (can be html, js, ...)
- *
- * The true value is equivalent to html.
- *
- * If autoescaping is disabled, then the value is false.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_AutoEscape extends Twig_Node
-{
- public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
- {
- parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->subcompile($this->getNode('body'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a block node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Block extends Twig_Node
-{
- public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
- {
- parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
- ->indent()
- ;
-
- $compiler
- ->subcompile($this->getNode('body'))
- ->outdent()
- ->write("}\n\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a block call node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
-{
- public function __construct($name, $lineno, $tag = null)
- {
- parent::__construct(array(), array('name' => $name), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a body node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Body extends Twig_Node
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a do node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Do extends Twig_Node
-{
- public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
- {
- parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('')
- ->subcompile($this->getNode('expr'))
- ->raw(";\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents an embed node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Embed extends Twig_Node_Include
-{
- // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
- public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
- {
- parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
-
- $this->setAttribute('filename', $filename);
- $this->setAttribute('index', $index);
- }
-
- protected function addGetTemplate(Twig_Compiler $compiler)
- {
- $compiler
- ->write("\$this->env->loadTemplate(")
- ->string($this->getAttribute('filename'))
- ->raw(', ')
- ->string($this->getAttribute('index'))
- ->raw(")")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Abstract class for all nodes that represents an expression.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-abstract class Twig_Node_Expression extends Twig_Node
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Array extends Twig_Node_Expression
-{
- protected $index;
-
- public function __construct(array $elements, $lineno)
- {
- parent::__construct($elements, array(), $lineno);
-
- $this->index = -1;
- foreach ($this->getKeyValuePairs() as $pair) {
- if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
- $this->index = $pair['key']->getAttribute('value');
- }
- }
- }
-
- public function getKeyValuePairs()
- {
- $pairs = array();
-
- foreach (array_chunk($this->nodes, 2) as $pair) {
- $pairs[] = array(
- 'key' => $pair[0],
- 'value' => $pair[1],
- );
- }
-
- return $pairs;
- }
-
- public function hasElement(Twig_Node_Expression $key)
- {
- foreach ($this->getKeyValuePairs() as $pair) {
- // we compare the string representation of the keys
- // to avoid comparing the line numbers which are not relevant here.
- if ((string) $key == (string) $pair['key']) {
- return true;
- }
- }
-
- return false;
- }
-
- public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
- {
- if (null === $key) {
- $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
- }
-
- array_push($this->nodes, $key, $value);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->raw('array(');
- $first = true;
- foreach ($this->getKeyValuePairs() as $pair) {
- if (!$first) {
- $compiler->raw(', ');
- }
- $first = false;
-
- $compiler
- ->subcompile($pair['key'])
- ->raw(' => ')
- ->subcompile($pair['value'])
- ;
- }
- $compiler->raw(')');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
-{
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('$context[')
- ->string($this->getAttribute('name'))
- ->raw(']')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
-{
- public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
- {
- parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(')
- ->subcompile($this->getNode('left'))
- ->raw(' ')
- ;
- $this->operator($compiler);
- $compiler
- ->raw(' ')
- ->subcompile($this->getNode('right'))
- ->raw(')')
- ;
- }
-
- abstract public function operator(Twig_Compiler $compiler);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('+');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('&&');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('&');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('|');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('^');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('.');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('/');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('==');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
-{
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->raw('intval(floor(');
- parent::compile($compiler);
- $compiler->raw('))');
- }
-
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('/');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('>');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('>=');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
-{
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('twig_in_filter(')
- ->subcompile($this->getNode('left'))
- ->raw(', ')
- ->subcompile($this->getNode('right'))
- ->raw(')')
- ;
- }
-
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('in');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('<');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('<=');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('%');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('*');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('!=');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
-{
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('!twig_in_filter(')
- ->subcompile($this->getNode('left'))
- ->raw(', ')
- ->subcompile($this->getNode('right'))
- ->raw(')')
- ;
- }
-
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('not in');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('||');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
-{
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('pow(')
- ->subcompile($this->getNode('left'))
- ->raw(', ')
- ->subcompile($this->getNode('right'))
- ->raw(')')
- ;
- }
-
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('**');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
-{
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('range(')
- ->subcompile($this->getNode('left'))
- ->raw(', ')
- ->subcompile($this->getNode('right'))
- ->raw(')')
- ;
- }
-
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('..');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
-{
- public function operator(Twig_Compiler $compiler)
- {
- return $compiler->raw('-');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a block call node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
-{
- public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null)
- {
- parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- if ($this->getAttribute('as_string')) {
- $compiler->raw('(string) ');
- }
-
- if ($this->getAttribute('output')) {
- $compiler
- ->addDebugInfo($this)
- ->write("\$this->displayBlock(")
- ->subcompile($this->getNode('name'))
- ->raw(", \$context, \$blocks);\n")
- ;
- } else {
- $compiler
- ->raw("\$this->renderBlock(")
- ->subcompile($this->getNode('name'))
- ->raw(", \$context, \$blocks)")
- ;
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
-{
- protected function compileCallable(Twig_Compiler $compiler)
- {
- $callable = $this->getAttribute('callable');
-
- $closingParenthesis = false;
- if ($callable) {
- if (is_string($callable)) {
- $compiler->raw($callable);
- } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
- $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
- } else {
- $type = ucfirst($this->getAttribute('type'));
- $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
- $closingParenthesis = true;
- }
- } else {
- $compiler->raw($this->getAttribute('thing')->compile());
- }
-
- $this->compileArguments($compiler);
-
- if ($closingParenthesis) {
- $compiler->raw(')');
- }
- }
-
- protected function compileArguments(Twig_Compiler $compiler)
- {
- $compiler->raw('(');
-
- $first = true;
-
- if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
- $compiler->raw('$this->env');
- $first = false;
- }
-
- if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
- if (!$first) {
- $compiler->raw(', ');
- }
- $compiler->raw('$context');
- $first = false;
- }
-
- if ($this->hasAttribute('arguments')) {
- foreach ($this->getAttribute('arguments') as $argument) {
- if (!$first) {
- $compiler->raw(', ');
- }
- $compiler->string($argument);
- $first = false;
- }
- }
-
- if ($this->hasNode('node')) {
- if (!$first) {
- $compiler->raw(', ');
- }
- $compiler->subcompile($this->getNode('node'));
- $first = false;
- }
-
- if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
- $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
-
- $arguments = $this->getArguments($callable, $this->getNode('arguments'));
-
- foreach ($arguments as $node) {
- if (!$first) {
- $compiler->raw(', ');
- }
- $compiler->subcompile($node);
- $first = false;
- }
- }
-
- $compiler->raw(')');
- }
-
- protected function getArguments($callable, $arguments)
- {
- $parameters = array();
- $named = false;
- foreach ($arguments as $name => $node) {
- if (!is_int($name)) {
- $named = true;
- $name = $this->normalizeName($name);
- } elseif ($named) {
- throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
- }
-
- $parameters[$name] = $node;
- }
-
- if (!$named) {
- return $parameters;
- }
-
- if (!$callable) {
- throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
- }
-
- // manage named arguments
- if (is_array($callable)) {
- $r = new ReflectionMethod($callable[0], $callable[1]);
- } elseif (is_object($callable) && !$callable instanceof Closure) {
- $r = new ReflectionObject($callable);
- $r = $r->getMethod('__invoke');
- } else {
- $r = new ReflectionFunction($callable);
- }
-
- $definition = $r->getParameters();
- if ($this->hasNode('node')) {
- array_shift($definition);
- }
- if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
- array_shift($definition);
- }
- if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
- array_shift($definition);
- }
- if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
- foreach ($this->getAttribute('arguments') as $argument) {
- array_shift($definition);
- }
- }
-
- $arguments = array();
- $pos = 0;
- foreach ($definition as $param) {
- $name = $this->normalizeName($param->name);
-
- if (array_key_exists($name, $parameters)) {
- if (array_key_exists($pos, $parameters)) {
- throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
- }
-
- $arguments[] = $parameters[$name];
- unset($parameters[$name]);
- } elseif (array_key_exists($pos, $parameters)) {
- $arguments[] = $parameters[$pos];
- unset($parameters[$pos]);
- ++$pos;
- } elseif ($param->isDefaultValueAvailable()) {
- $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
- } elseif ($param->isOptional()) {
- break;
- } else {
- throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
- }
- }
-
- if (!empty($parameters)) {
- throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '' , implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
- }
-
- return $arguments;
- }
-
- protected function normalizeName($name)
- {
- return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Conditional extends Twig_Node_Expression
-{
- public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
- {
- parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('((')
- ->subcompile($this->getNode('expr1'))
- ->raw(') ? (')
- ->subcompile($this->getNode('expr2'))
- ->raw(') : (')
- ->subcompile($this->getNode('expr3'))
- ->raw('))')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Constant extends Twig_Node_Expression
-{
- public function __construct($value, $lineno)
- {
- parent::__construct(array(), array('value' => $value), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->repr($this->getAttribute('value'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents an extension call node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
-{
- public function __construct($name, $lineno, $tag = null)
- {
- parent::__construct(array(), array('name' => $name), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
-{
- public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
- {
- parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $name = $this->getNode('filter')->getAttribute('value');
- $filter = $compiler->getEnvironment()->getFilter($name);
-
- $this->setAttribute('name', $name);
- $this->setAttribute('type', 'filter');
- $this->setAttribute('thing', $filter);
- $this->setAttribute('needs_environment', $filter->needsEnvironment());
- $this->setAttribute('needs_context', $filter->needsContext());
- $this->setAttribute('arguments', $filter->getArguments());
- if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
- $this->setAttribute('callable', $filter->getCallable());
- }
-
- $this->compileCallable($compiler);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Returns the value or the default value when it is undefined or empty.
- *
- * <pre>
- * {{ var.foo|default('foo item on var is not defined') }}
- * </pre>
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
-{
- public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
- {
- $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
-
- if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
- $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
- $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
-
- $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
- } else {
- $node = $default;
- }
-
- parent::__construct($node, $filterName, $arguments, $lineno, $tag);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->subcompile($this->getNode('node'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
-{
- public function __construct($name, Twig_NodeInterface $arguments, $lineno)
- {
- parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $name = $this->getAttribute('name');
- $function = $compiler->getEnvironment()->getFunction($name);
-
- $this->setAttribute('name', $name);
- $this->setAttribute('type', 'function');
- $this->setAttribute('thing', $function);
- $this->setAttribute('needs_environment', $function->needsEnvironment());
- $this->setAttribute('needs_context', $function->needsContext());
- $this->setAttribute('arguments', $function->getArguments());
- if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
- $this->setAttribute('callable', $function->getCallable());
- }
-
- $this->compileCallable($compiler);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
-{
- public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
- {
- parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
- $compiler->raw('twig_template_get_attributes($this, ');
- } else {
- $compiler->raw('$this->getAttribute(');
- }
-
- if ($this->getAttribute('ignore_strict_check')) {
- $this->getNode('node')->setAttribute('ignore_strict_check', true);
- }
-
- $compiler->subcompile($this->getNode('node'));
-
- $compiler->raw(', ')->subcompile($this->getNode('attribute'));
-
- if (count($this->getNode('arguments')) || Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
- $compiler->raw(', ')->subcompile($this->getNode('arguments'));
-
- if (Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
- $compiler->raw(', ')->repr($this->getAttribute('type'));
- }
-
- if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
- $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
- }
-
- if ($this->getAttribute('ignore_strict_check')) {
- $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
- }
- }
-
- $compiler->raw(')');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
-{
- public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
- {
- parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
-
- if ($node instanceof Twig_Node_Expression_Name) {
- $node->setAttribute('always_defined', true);
- }
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->subcompile($this->getNode('node'))
- ->raw('->')
- ->raw($this->getAttribute('method'))
- ->raw('(')
- ;
- $first = true;
- foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
- if (!$first) {
- $compiler->raw(', ');
- }
- $first = false;
-
- $compiler->subcompile($pair['value']);
- }
- $compiler->raw(')');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Name extends Twig_Node_Expression
-{
- protected $specialVars = array(
- '_self' => '$this',
- '_context' => '$context',
- '_charset' => '$this->env->getCharset()',
- );
-
- public function __construct($name, $lineno)
- {
- parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $name = $this->getAttribute('name');
-
- if ($this->getAttribute('is_defined_test')) {
- if ($this->isSpecial()) {
- $compiler->repr(true);
- } else {
- $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
- }
- } elseif ($this->isSpecial()) {
- $compiler->raw($this->specialVars[$name]);
- } elseif ($this->getAttribute('always_defined')) {
- $compiler
- ->raw('$context[')
- ->string($name)
- ->raw(']')
- ;
- } else {
- // remove the non-PHP 5.4 version when PHP 5.3 support is dropped
- // as the non-optimized version is just a workaround for slow ternary operator
- // when the context has a lot of variables
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
- // PHP 5.4 ternary operator performance was optimized
- $compiler
- ->raw('(isset($context[')
- ->string($name)
- ->raw(']) ? $context[')
- ->string($name)
- ->raw('] : ')
- ;
-
- if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
- $compiler->raw('null)');
- } else {
- $compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
- }
- } else {
- $compiler
- ->raw('$this->getContext($context, ')
- ->string($name)
- ;
-
- if ($this->getAttribute('ignore_strict_check')) {
- $compiler->raw(', true');
- }
-
- $compiler
- ->raw(')')
- ;
- }
- }
- }
-
- public function isSpecial()
- {
- return isset($this->specialVars[$this->getAttribute('name')]);
- }
-
- public function isSimple()
- {
- return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a parent node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Parent extends Twig_Node_Expression
-{
- public function __construct($name, $lineno, $tag = null)
- {
- parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- if ($this->getAttribute('output')) {
- $compiler
- ->addDebugInfo($this)
- ->write("\$this->displayParentBlock(")
- ->string($this->getAttribute('name'))
- ->raw(", \$context, \$blocks);\n")
- ;
- } else {
- $compiler
- ->raw("\$this->renderParentBlock(")
- ->string($this->getAttribute('name'))
- ->raw(", \$context, \$blocks)")
- ;
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_TempName extends Twig_Node_Expression
-{
- public function __construct($name, $lineno)
- {
- parent::__construct(array(), array('name' => $name), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('$_')
- ->raw($this->getAttribute('name'))
- ->raw('_')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
-{
- public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
- {
- parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $name = $this->getAttribute('name');
- $test = $compiler->getEnvironment()->getTest($name);
-
- $this->setAttribute('name', $name);
- $this->setAttribute('type', 'test');
- $this->setAttribute('thing', $test);
- if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
- $this->setAttribute('callable', $test->getCallable());
- }
-
- $this->compileCallable($compiler);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Checks if a variable is the exact same value as a constant.
- *
- * <pre>
- * {% if post.status is constant('Post::PUBLISHED') %}
- * the status attribute is exactly the same as Post::PUBLISHED
- * {% endif %}
- * </pre>
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
-{
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(')
- ->subcompile($this->getNode('node'))
- ->raw(' === constant(')
- ;
-
- if ($this->getNode('arguments')->hasNode(1)) {
- $compiler
- ->raw('get_class(')
- ->subcompile($this->getNode('arguments')->getNode(1))
- ->raw(')."::".')
- ;
- }
-
- $compiler
- ->subcompile($this->getNode('arguments')->getNode(0))
- ->raw('))')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Checks if a variable is defined in the current context.
- *
- * <pre>
- * {# defined works with variable names and variable attributes #}
- * {% if foo is defined %}
- * {# ... #}
- * {% endif %}
- * </pre>
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
-{
- public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
- {
- parent::__construct($node, $name, $arguments, $lineno);
-
- if ($node instanceof Twig_Node_Expression_Name) {
- $node->setAttribute('is_defined_test', true);
- } elseif ($node instanceof Twig_Node_Expression_GetAttr) {
- $node->setAttribute('is_defined_test', true);
-
- $this->changeIgnoreStrictCheck($node);
- } else {
- throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
- }
- }
-
- protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
- {
- $node->setAttribute('ignore_strict_check', true);
-
- if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
- $this->changeIgnoreStrictCheck($node->getNode('node'));
- }
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->subcompile($this->getNode('node'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Checks if a variable is divisible by a number.
- *
- * <pre>
- * {% if loop.index is divisibleby(3) %}
- * </pre>
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
-{
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(0 == ')
- ->subcompile($this->getNode('node'))
- ->raw(' % ')
- ->subcompile($this->getNode('arguments')->getNode(0))
- ->raw(')')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Checks if a number is even.
- *
- * <pre>
- * {{ var is even }}
- * </pre>
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
-{
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(')
- ->subcompile($this->getNode('node'))
- ->raw(' % 2 == 0')
- ->raw(')')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Checks that a variable is null.
- *
- * <pre>
- * {{ var is none }}
- * </pre>
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
-{
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(null === ')
- ->subcompile($this->getNode('node'))
- ->raw(')')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Checks if a number is odd.
- *
- * <pre>
- * {{ var is odd }}
- * </pre>
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
-{
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(')
- ->subcompile($this->getNode('node'))
- ->raw(' % 2 == 1')
- ->raw(')')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Checks if a variable is the same as another one (=== in PHP).
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
-{
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->raw('(')
- ->subcompile($this->getNode('node'))
- ->raw(' === ')
- ->subcompile($this->getNode('arguments')->getNode(0))
- ->raw(')')
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
-{
- public function __construct(Twig_NodeInterface $node, $lineno)
- {
- parent::__construct(array('node' => $node), array(), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->raw('(');
- $this->operator($compiler);
- $compiler
- ->subcompile($this->getNode('node'))
- ->raw(')')
- ;
- }
-
- abstract public function operator(Twig_Compiler $compiler);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary
-{
- public function operator(Twig_Compiler $compiler)
- {
- $compiler->raw('-');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary
-{
- public function operator(Twig_Compiler $compiler)
- {
- $compiler->raw('!');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary
-{
- public function operator(Twig_Compiler $compiler)
- {
- $compiler->raw('+');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a flush node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Flush extends Twig_Node
-{
- public function __construct($lineno, $tag)
- {
- parent::__construct(array(), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write("flush();\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a for node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_For extends Twig_Node
-{
- protected $loop;
-
- public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
- {
- $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
-
- if (null !== $ifexpr) {
- $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
- }
-
- parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- // the (array) cast bypasses a PHP 5.2.6 bug
- ->write("\$context['_parent'] = (array) \$context;\n")
- ->write("\$context['_seq'] = twig_ensure_traversable(")
- ->subcompile($this->getNode('seq'))
- ->raw(");\n")
- ;
-
- if (null !== $this->getNode('else')) {
- $compiler->write("\$context['_iterated'] = false;\n");
- }
-
- if ($this->getAttribute('with_loop')) {
- $compiler
- ->write("\$context['loop'] = array(\n")
- ->write(" 'parent' => \$context['_parent'],\n")
- ->write(" 'index0' => 0,\n")
- ->write(" 'index' => 1,\n")
- ->write(" 'first' => true,\n")
- ->write(");\n")
- ;
-
- if (!$this->getAttribute('ifexpr')) {
- $compiler
- ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
- ->indent()
- ->write("\$length = count(\$context['_seq']);\n")
- ->write("\$context['loop']['revindex0'] = \$length - 1;\n")
- ->write("\$context['loop']['revindex'] = \$length;\n")
- ->write("\$context['loop']['length'] = \$length;\n")
- ->write("\$context['loop']['last'] = 1 === \$length;\n")
- ->outdent()
- ->write("}\n")
- ;
- }
- }
-
- $this->loop->setAttribute('else', null !== $this->getNode('else'));
- $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
- $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
-
- $compiler
- ->write("foreach (\$context['_seq'] as ")
- ->subcompile($this->getNode('key_target'))
- ->raw(" => ")
- ->subcompile($this->getNode('value_target'))
- ->raw(") {\n")
- ->indent()
- ->subcompile($this->getNode('body'))
- ->outdent()
- ->write("}\n")
- ;
-
- if (null !== $this->getNode('else')) {
- $compiler
- ->write("if (!\$context['_iterated']) {\n")
- ->indent()
- ->subcompile($this->getNode('else'))
- ->outdent()
- ->write("}\n")
- ;
- }
-
- $compiler->write("\$_parent = \$context['_parent'];\n");
-
- // remove some "private" loop variables (needed for nested loops)
- $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
-
- // keep the values set in the inner context for variables defined in the outer context
- $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Internal node used by the for node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_ForLoop extends Twig_Node
-{
- public function __construct($lineno, $tag = null)
- {
- parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- if ($this->getAttribute('else')) {
- $compiler->write("\$context['_iterated'] = true;\n");
- }
-
- if ($this->getAttribute('with_loop')) {
- $compiler
- ->write("++\$context['loop']['index0'];\n")
- ->write("++\$context['loop']['index'];\n")
- ->write("\$context['loop']['first'] = false;\n")
- ;
-
- if (!$this->getAttribute('ifexpr')) {
- $compiler
- ->write("if (isset(\$context['loop']['length'])) {\n")
- ->indent()
- ->write("--\$context['loop']['revindex0'];\n")
- ->write("--\$context['loop']['revindex'];\n")
- ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
- ->outdent()
- ->write("}\n")
- ;
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents an if node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_If extends Twig_Node
-{
- public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
- {
- parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->addDebugInfo($this);
- for ($i = 0; $i < count($this->getNode('tests')); $i += 2) {
- if ($i > 0) {
- $compiler
- ->outdent()
- ->write("} elseif (")
- ;
- } else {
- $compiler
- ->write('if (')
- ;
- }
-
- $compiler
- ->subcompile($this->getNode('tests')->getNode($i))
- ->raw(") {\n")
- ->indent()
- ->subcompile($this->getNode('tests')->getNode($i + 1))
- ;
- }
-
- if ($this->hasNode('else') && null !== $this->getNode('else')) {
- $compiler
- ->outdent()
- ->write("} else {\n")
- ->indent()
- ->subcompile($this->getNode('else'))
- ;
- }
-
- $compiler
- ->outdent()
- ->write("}\n");
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents an import node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Import extends Twig_Node
-{
- public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null)
- {
- parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('')
- ->subcompile($this->getNode('var'))
- ->raw(' = ')
- ;
-
- if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) {
- $compiler->raw("\$this");
- } else {
- $compiler
- ->raw('$this->env->loadTemplate(')
- ->subcompile($this->getNode('expr'))
- ->raw(")")
- ;
- }
-
- $compiler->raw(";\n");
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents an include node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
-{
- public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
- {
- parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only, 'ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->addDebugInfo($this);
-
- if ($this->getAttribute('ignore_missing')) {
- $compiler
- ->write("try {\n")
- ->indent()
- ;
- }
-
- $this->addGetTemplate($compiler);
-
- $compiler->raw('->display(');
-
- $this->addTemplateArguments($compiler);
-
- $compiler->raw(");\n");
-
- if ($this->getAttribute('ignore_missing')) {
- $compiler
- ->outdent()
- ->write("} catch (Twig_Error_Loader \$e) {\n")
- ->indent()
- ->write("// ignore missing template\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
- }
-
- protected function addGetTemplate(Twig_Compiler $compiler)
- {
- if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
- $compiler
- ->write("\$this->env->loadTemplate(")
- ->subcompile($this->getNode('expr'))
- ->raw(")")
- ;
- } else {
- $compiler
- ->write("\$template = \$this->env->resolveTemplate(")
- ->subcompile($this->getNode('expr'))
- ->raw(");\n")
- ->write('$template')
- ;
- }
- }
-
- protected function addTemplateArguments(Twig_Compiler $compiler)
- {
- if (false === $this->getAttribute('only')) {
- if (null === $this->getNode('variables')) {
- $compiler->raw('$context');
- } else {
- $compiler
- ->raw('array_merge($context, ')
- ->subcompile($this->getNode('variables'))
- ->raw(')')
- ;
- }
- } else {
- if (null === $this->getNode('variables')) {
- $compiler->raw('array()');
- } else {
- $compiler->subcompile($this->getNode('variables'));
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a macro node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Macro extends Twig_Node
-{
- public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
- {
- parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write(sprintf("public function get%s(", $this->getAttribute('name')))
- ;
-
- $count = count($this->getNode('arguments'));
- $pos = 0;
- foreach ($this->getNode('arguments') as $name => $default) {
- $compiler
- ->raw('$_'.$name.' = ')
- ->subcompile($default)
- ;
-
- if (++$pos < $count) {
- $compiler->raw(', ');
- }
- }
-
- $compiler
- ->raw(")\n")
- ->write("{\n")
- ->indent()
- ;
-
- if (!count($this->getNode('arguments'))) {
- $compiler->write("\$context = \$this->env->getGlobals();\n\n");
- } else {
- $compiler
- ->write("\$context = \$this->env->mergeGlobals(array(\n")
- ->indent()
- ;
-
- foreach ($this->getNode('arguments') as $name => $default) {
- $compiler
- ->write('')
- ->string($name)
- ->raw(' => $_'.$name)
- ->raw(",\n")
- ;
- }
-
- $compiler
- ->outdent()
- ->write("));\n\n")
- ;
- }
-
- $compiler
- ->write("\$blocks = array();\n\n")
- ->write("ob_start();\n")
- ->write("try {\n")
- ->indent()
- ->subcompile($this->getNode('body'))
- ->outdent()
- ->write("} catch (Exception \$e) {\n")
- ->indent()
- ->write("ob_end_clean();\n\n")
- ->write("throw \$e;\n")
- ->outdent()
- ->write("}\n\n")
- ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a module node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Module extends Twig_Node
-{
- public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
- {
- // embedded templates are set as attributes so that they are only visited once by the visitors
- parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
- }
-
- public function setIndex($index)
- {
- $this->setAttribute('index', $index);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $this->compileTemplate($compiler);
-
- foreach ($this->getAttribute('embedded_templates') as $template) {
- $compiler->subcompile($template);
- }
- }
-
- protected function compileTemplate(Twig_Compiler $compiler)
- {
- if (!$this->getAttribute('index')) {
- $compiler->write('<?php');
- }
-
- $this->compileClassHeader($compiler);
-
- if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
- $this->compileConstructor($compiler);
- }
-
- $this->compileGetParent($compiler);
-
- $this->compileDisplayHeader($compiler);
-
- $this->compileDisplayBody($compiler);
-
- $this->compileDisplayFooter($compiler);
-
- $compiler->subcompile($this->getNode('blocks'));
-
- $this->compileMacros($compiler);
-
- $this->compileGetTemplateName($compiler);
-
- $this->compileIsTraitable($compiler);
-
- $this->compileDebugInfo($compiler);
-
- $this->compileClassFooter($compiler);
- }
-
- protected function compileGetParent(Twig_Compiler $compiler)
- {
- if (null === $this->getNode('parent')) {
- return;
- }
-
- $compiler
- ->write("protected function doGetParent(array \$context)\n", "{\n")
- ->indent()
- ->write("return ")
- ;
-
- if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
- $compiler->subcompile($this->getNode('parent'));
- } else {
- $compiler
- ->raw("\$this->env->resolveTemplate(")
- ->subcompile($this->getNode('parent'))
- ->raw(")")
- ;
- }
-
- $compiler
- ->raw(";\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- protected function compileDisplayBody(Twig_Compiler $compiler)
- {
- $compiler->subcompile($this->getNode('body'));
-
- if (null !== $this->getNode('parent')) {
- if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
- $compiler->write("\$this->parent");
- } else {
- $compiler->write("\$this->getParent(\$context)");
- }
- $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
- }
- }
-
- protected function compileClassHeader(Twig_Compiler $compiler)
- {
- $compiler
- ->write("\n\n")
- // if the filename contains */, add a blank to avoid a PHP parse error
- ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
- ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
- ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
- ->write("{\n")
- ->indent()
- ;
- }
-
- protected function compileConstructor(Twig_Compiler $compiler)
- {
- $compiler
- ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
- ->indent()
- ->write("parent::__construct(\$env);\n\n")
- ;
-
- // parent
- if (null === $this->getNode('parent')) {
- $compiler->write("\$this->parent = false;\n\n");
- } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
- $compiler
- ->write("\$this->parent = \$this->env->loadTemplate(")
- ->subcompile($this->getNode('parent'))
- ->raw(");\n\n")
- ;
- }
-
- $countTraits = count($this->getNode('traits'));
- if ($countTraits) {
- // traits
- foreach ($this->getNode('traits') as $i => $trait) {
- $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
-
- $compiler
- ->addDebugInfo($trait->getNode('template'))
- ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
- ->indent()
- ->write("throw new Twig_Error_Runtime('Template \"'.")
- ->subcompile($trait->getNode('template'))
- ->raw(".'\" cannot be used as a trait.');\n")
- ->outdent()
- ->write("}\n")
- ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
- ;
-
- foreach ($trait->getNode('targets') as $key => $value) {
- $compiler
- ->write(sprintf("\$_trait_%s_blocks[", $i))
- ->subcompile($value)
- ->raw(sprintf("] = \$_trait_%s_blocks[", $i))
- ->string($key)
- ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
- ->string($key)
- ->raw("]);\n\n")
- ;
- }
- }
-
- if ($countTraits > 1) {
- $compiler
- ->write("\$this->traits = array_merge(\n")
- ->indent()
- ;
-
- for ($i = 0; $i < $countTraits; $i++) {
- $compiler
- ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
- ;
- }
-
- $compiler
- ->outdent()
- ->write(");\n\n")
- ;
- } else {
- $compiler
- ->write("\$this->traits = \$_trait_0_blocks;\n\n")
- ;
- }
-
- $compiler
- ->write("\$this->blocks = array_merge(\n")
- ->indent()
- ->write("\$this->traits,\n")
- ->write("array(\n")
- ;
- } else {
- $compiler
- ->write("\$this->blocks = array(\n")
- ;
- }
-
- // blocks
- $compiler
- ->indent()
- ;
-
- foreach ($this->getNode('blocks') as $name => $node) {
- $compiler
- ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
- ;
- }
-
- if ($countTraits) {
- $compiler
- ->outdent()
- ->write(")\n")
- ;
- }
-
- $compiler
- ->outdent()
- ->write(");\n")
- ->outdent()
- ->write("}\n\n");
- ;
- }
-
- protected function compileDisplayHeader(Twig_Compiler $compiler)
- {
- $compiler
- ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
- ->indent()
- ;
- }
-
- protected function compileDisplayFooter(Twig_Compiler $compiler)
- {
- $compiler
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- protected function compileClassFooter(Twig_Compiler $compiler)
- {
- $compiler
- ->outdent()
- ->write("}\n")
- ;
- }
-
- protected function compileMacros(Twig_Compiler $compiler)
- {
- $compiler->subcompile($this->getNode('macros'));
- }
-
- protected function compileGetTemplateName(Twig_Compiler $compiler)
- {
- $compiler
- ->write("public function getTemplateName()\n", "{\n")
- ->indent()
- ->write('return ')
- ->repr($this->getAttribute('filename'))
- ->raw(";\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- protected function compileIsTraitable(Twig_Compiler $compiler)
- {
- // A template can be used as a trait if:
- // * it has no parent
- // * it has no macros
- // * it has no body
- //
- // Put another way, a template can be used as a trait if it
- // only contains blocks and use statements.
- $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
- if ($traitable) {
- if ($this->getNode('body') instanceof Twig_Node_Body) {
- $nodes = $this->getNode('body')->getNode(0);
- } else {
- $nodes = $this->getNode('body');
- }
-
- if (!count($nodes)) {
- $nodes = new Twig_Node(array($nodes));
- }
-
- foreach ($nodes as $node) {
- if (!count($node)) {
- continue;
- }
-
- if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
- continue;
- }
-
- if ($node instanceof Twig_Node_BlockReference) {
- continue;
- }
-
- $traitable = false;
- break;
- }
- }
-
- if ($traitable) {
- return;
- }
-
- $compiler
- ->write("public function isTraitable()\n", "{\n")
- ->indent()
- ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- protected function compileDebugInfo(Twig_Compiler $compiler)
- {
- $compiler
- ->write("public function getDebugInfo()\n", "{\n")
- ->indent()
- ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
- ->outdent()
- ->write("}\n")
- ;
- }
-
- protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
- {
- if ($node instanceof Twig_Node_Expression_Constant) {
- $compiler
- ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
- ->subcompile($node)
- ->raw(");\n")
- ;
- } else {
- $compiler
- ->write(sprintf("%s = ", $var))
- ->subcompile($node)
- ->raw(";\n")
- ->write(sprintf("if (!%s", $var))
- ->raw(" instanceof Twig_Template) {\n")
- ->indent()
- ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
- ->outdent()
- ->write("}\n")
- ;
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a node that outputs an expression.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
-{
- public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
- {
- parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('echo ')
- ->subcompile($this->getNode('expr'))
- ->raw(";\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a sandbox node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Sandbox extends Twig_Node
-{
- public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
- {
- parent::__construct(array('body' => $body), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
- ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
- ->indent()
- ->write("\$sandbox->enableSandbox();\n")
- ->outdent()
- ->write("}\n")
- ->subcompile($this->getNode('body'))
- ->write("if (!\$alreadySandboxed) {\n")
- ->indent()
- ->write("\$sandbox->disableSandbox();\n")
- ->outdent()
- ->write("}\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a module node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_SandboxedModule extends Twig_Node_Module
-{
- protected $usedFilters;
- protected $usedTags;
- protected $usedFunctions;
-
- public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
- {
- parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag());
-
- $this->setAttribute('index', $node->getAttribute('index'));
-
- $this->usedFilters = $usedFilters;
- $this->usedTags = $usedTags;
- $this->usedFunctions = $usedFunctions;
- }
-
- protected function compileDisplayBody(Twig_Compiler $compiler)
- {
- $compiler->write("\$this->checkSecurity();\n");
-
- parent::compileDisplayBody($compiler);
- }
-
- protected function compileDisplayFooter(Twig_Compiler $compiler)
- {
- parent::compileDisplayFooter($compiler);
-
- $compiler
- ->write("protected function checkSecurity()\n", "{\n")
- ->indent()
- ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
- ->indent()
- ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
- ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
- ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
- ->outdent()
- ->write(");\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Twig_Node_SandboxedPrint adds a check for the __toString() method
- * when the variable is an object and the sandbox is activated.
- *
- * When there is a simple Print statement, like {{ article }},
- * and if the sandbox is enabled, we need to check that the __toString()
- * method is allowed if 'article' is an object.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_SandboxedPrint extends Twig_Node_Print
-{
- public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
- {
- parent::__construct($expr, $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(')
- ->subcompile($this->getNode('expr'))
- ->raw(");\n")
- ;
- }
-
- /**
- * Removes node filters.
- *
- * This is mostly needed when another visitor adds filters (like the escaper one).
- *
- * @param Twig_Node $node A Node
- */
- protected function removeNodeFilter($node)
- {
- if ($node instanceof Twig_Node_Expression_Filter) {
- return $this->removeNodeFilter($node->getNode('node'));
- }
-
- return $node;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a set node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Set extends Twig_Node
-{
- public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
- {
- parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag);
-
- /*
- * Optimizes the node when capture is used for a large block of text.
- *
- * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
- */
- if ($this->getAttribute('capture')) {
- $this->setAttribute('safe', true);
-
- $values = $this->getNode('values');
- if ($values instanceof Twig_Node_Text) {
- $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine()));
- $this->setAttribute('capture', false);
- }
- }
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->addDebugInfo($this);
-
- if (count($this->getNode('names')) > 1) {
- $compiler->write('list(');
- foreach ($this->getNode('names') as $idx => $node) {
- if ($idx) {
- $compiler->raw(', ');
- }
-
- $compiler->subcompile($node);
- }
- $compiler->raw(')');
- } else {
- if ($this->getAttribute('capture')) {
- $compiler
- ->write("ob_start();\n")
- ->subcompile($this->getNode('values'))
- ;
- }
-
- $compiler->subcompile($this->getNode('names'), false);
-
- if ($this->getAttribute('capture')) {
- $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())");
- }
- }
-
- if (!$this->getAttribute('capture')) {
- $compiler->raw(' = ');
-
- if (count($this->getNode('names')) > 1) {
- $compiler->write('array(');
- foreach ($this->getNode('values') as $idx => $value) {
- if ($idx) {
- $compiler->raw(', ');
- }
-
- $compiler->subcompile($value);
- }
- $compiler->raw(')');
- } else {
- if ($this->getAttribute('safe')) {
- $compiler
- ->raw("('' === \$tmp = ")
- ->subcompile($this->getNode('values'))
- ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())")
- ;
- } else {
- $compiler->subcompile($this->getNode('values'));
- }
- }
- }
-
- $compiler->raw(";\n");
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Node_SetTemp extends Twig_Node
-{
- public function __construct($name, $lineno)
- {
- parent::__construct(array(), array('name' => $name), $lineno);
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $name = $this->getAttribute('name');
- $compiler
- ->addDebugInfo($this)
- ->write('if (isset($context[')
- ->string($name)
- ->raw('])) { $_')
- ->raw($name)
- ->raw('_ = $context[')
- ->repr($name)
- ->raw(']; } else { $_')
- ->raw($name)
- ->raw("_ = null; }\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a spaceless node.
- *
- * It removes spaces between HTML tags.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Spaceless extends Twig_Node
-{
- public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless')
- {
- parent::__construct(array('body' => $body), array(), $lineno, $tag);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write("ob_start();\n")
- ->subcompile($this->getNode('body'))
- ->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a text node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
-{
- public function __construct($data, $lineno)
- {
- parent::__construct(array(), array('data' => $data), $lineno);
- }
-
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler)
- {
- $compiler
- ->addDebugInfo($this)
- ->write('echo ')
- ->string($this->getAttribute('data'))
- ->raw(";\n")
- ;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a node in the AST.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_NodeInterface extends Countable, IteratorAggregate
-{
- /**
- * Compiles the node to PHP.
- *
- * @param Twig_Compiler A Twig_Compiler instance
- */
- public function compile(Twig_Compiler $compiler);
-
- public function getLine();
-
- public function getNodeTag();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a displayable node in the AST.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface Twig_NodeOutputInterface
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Twig_NodeTraverser is a node traverser.
- *
- * It visits all nodes and their children and call the given visitor for each.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_NodeTraverser
-{
- protected $env;
- protected $visitors;
-
- /**
- * Constructor.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- * @param array $visitors An array of Twig_NodeVisitorInterface instances
- */
- public function __construct(Twig_Environment $env, array $visitors = array())
- {
- $this->env = $env;
- $this->visitors = array();
- foreach ($visitors as $visitor) {
- $this->addVisitor($visitor);
- }
- }
-
- /**
- * Adds a visitor.
- *
- * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
- */
- public function addVisitor(Twig_NodeVisitorInterface $visitor)
- {
- if (!isset($this->visitors[$visitor->getPriority()])) {
- $this->visitors[$visitor->getPriority()] = array();
- }
-
- $this->visitors[$visitor->getPriority()][] = $visitor;
- }
-
- /**
- * Traverses a node and calls the registered visitors.
- *
- * @param Twig_NodeInterface $node A Twig_NodeInterface instance
- */
- public function traverse(Twig_NodeInterface $node)
- {
- ksort($this->visitors);
- foreach ($this->visitors as $visitors) {
- foreach ($visitors as $visitor) {
- $node = $this->traverseForVisitor($visitor, $node);
- }
- }
-
- return $node;
- }
-
- protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null)
- {
- if (null === $node) {
- return null;
- }
-
- $node = $visitor->enterNode($node, $this->env);
-
- foreach ($node as $k => $n) {
- if (false !== $n = $this->traverseForVisitor($visitor, $n)) {
- $node->setNode($k, $n);
- } else {
- $node->removeNode($k);
- }
- }
-
- return $visitor->leaveNode($node, $this->env);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Twig_NodeVisitor_Escaper implements output escaping.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
-{
- protected $statusStack = array();
- protected $blocks = array();
- protected $safeAnalysis;
- protected $traverser;
- protected $defaultStrategy = false;
- protected $safeVars = array();
-
- public function __construct()
- {
- $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
- }
-
- /**
- * Called before child nodes are visited.
- *
- * @param Twig_NodeInterface $node The node to visit
- * @param Twig_Environment $env The Twig environment instance
- *
- * @return Twig_NodeInterface The modified node
- */
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Module) {
- if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
- $this->defaultStrategy = $defaultStrategy;
- }
- $this->safeVars = array();
- } elseif ($node instanceof Twig_Node_AutoEscape) {
- $this->statusStack[] = $node->getAttribute('value');
- } elseif ($node instanceof Twig_Node_Block) {
- $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
- } elseif ($node instanceof Twig_Node_Import) {
- $this->safeVars[] = $node->getNode('var')->getAttribute('name');
- }
-
- return $node;
- }
-
- /**
- * Called after child nodes are visited.
- *
- * @param Twig_NodeInterface $node The node to visit
- * @param Twig_Environment $env The Twig environment instance
- *
- * @return Twig_NodeInterface The modified node
- */
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Module) {
- $this->defaultStrategy = false;
- $this->safeVars = array();
- } elseif ($node instanceof Twig_Node_Expression_Filter) {
- return $this->preEscapeFilterNode($node, $env);
- } elseif ($node instanceof Twig_Node_Print) {
- return $this->escapePrintNode($node, $env, $this->needEscaping($env));
- }
-
- if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
- array_pop($this->statusStack);
- } elseif ($node instanceof Twig_Node_BlockReference) {
- $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
- }
-
- return $node;
- }
-
- protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
- {
- if (false === $type) {
- return $node;
- }
-
- $expression = $node->getNode('expr');
-
- if ($this->isSafeFor($type, $expression, $env)) {
- return $node;
- }
-
- $class = get_class($node);
-
- return new $class(
- $this->getEscaperFilter($type, $expression),
- $node->getLine()
- );
- }
-
- protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
- {
- $name = $filter->getNode('filter')->getAttribute('value');
-
- $type = $env->getFilter($name)->getPreEscape();
- if (null === $type) {
- return $filter;
- }
-
- $node = $filter->getNode('node');
- if ($this->isSafeFor($type, $node, $env)) {
- return $filter;
- }
-
- $filter->setNode('node', $this->getEscaperFilter($type, $node));
-
- return $filter;
- }
-
- protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
- {
- $safe = $this->safeAnalysis->getSafe($expression);
-
- if (null === $safe) {
- if (null === $this->traverser) {
- $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
- }
-
- $this->safeAnalysis->setSafeVars($this->safeVars);
-
- $this->traverser->traverse($expression);
- $safe = $this->safeAnalysis->getSafe($expression);
- }
-
- return in_array($type, $safe) || in_array('all', $safe);
- }
-
- protected function needEscaping(Twig_Environment $env)
- {
- if (count($this->statusStack)) {
- return $this->statusStack[count($this->statusStack) - 1];
- }
-
- return $this->defaultStrategy ? $this->defaultStrategy : false;
- }
-
- protected function getEscaperFilter($type, Twig_NodeInterface $node)
- {
- $line = $node->getLine();
- $name = new Twig_Node_Expression_Constant('escape', $line);
- $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
-
- return new Twig_Node_Expression_Filter($node, $name, $args, $line);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPriority()
- {
- return 0;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Twig_NodeVisitor_Optimizer tries to optimizes the AST.
- *
- * This visitor is always the last registered one.
- *
- * You can configure which optimizations you want to activate via the
- * optimizer mode.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
-{
- const OPTIMIZE_ALL = -1;
- const OPTIMIZE_NONE = 0;
- const OPTIMIZE_FOR = 2;
- const OPTIMIZE_RAW_FILTER = 4;
- const OPTIMIZE_VAR_ACCESS = 8;
-
- protected $loops = array();
- protected $optimizers;
- protected $prependedNodes = array();
- protected $inABody = false;
-
- /**
- * Constructor.
- *
- * @param integer $optimizers The optimizer mode
- */
- public function __construct($optimizers = -1)
- {
- if (!is_int($optimizers) || $optimizers > 2) {
- throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
- }
-
- $this->optimizers = $optimizers;
- }
-
- /**
- * {@inheritdoc}
- */
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
- $this->enterOptimizeFor($node, $env);
- }
-
- if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
- if ($this->inABody) {
- if (!$node instanceof Twig_Node_Expression) {
- if (get_class($node) !== 'Twig_Node') {
- array_unshift($this->prependedNodes, array());
- }
- } else {
- $node = $this->optimizeVariables($node, $env);
- }
- } elseif ($node instanceof Twig_Node_Body) {
- $this->inABody = true;
- }
- }
-
- return $node;
- }
-
- /**
- * {@inheritdoc}
- */
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- $expression = $node instanceof Twig_Node_Expression;
-
- if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
- $this->leaveOptimizeFor($node, $env);
- }
-
- if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
- $node = $this->optimizeRawFilter($node, $env);
- }
-
- $node = $this->optimizePrintNode($node, $env);
-
- if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
- if ($node instanceof Twig_Node_Body) {
- $this->inABody = false;
- } elseif ($this->inABody) {
- if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
- $nodes = array();
- foreach (array_unique($prependedNodes) as $name) {
- $nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
- }
-
- $nodes[] = $node;
- $node = new Twig_Node($nodes);
- }
- }
- }
-
- return $node;
- }
-
- protected function optimizeVariables($node, $env)
- {
- if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
- $this->prependedNodes[0][] = $node->getAttribute('name');
-
- return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
- }
-
- return $node;
- }
-
- /**
- * Optimizes print nodes.
- *
- * It replaces:
- *
- * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
- *
- * @param Twig_NodeInterface $node A Node
- * @param Twig_Environment $env The current Twig environment
- */
- protected function optimizePrintNode($node, $env)
- {
- if (!$node instanceof Twig_Node_Print) {
- return $node;
- }
-
- if (
- $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
- $node->getNode('expr') instanceof Twig_Node_Expression_Parent
- ) {
- $node->getNode('expr')->setAttribute('output', true);
-
- return $node->getNode('expr');
- }
-
- return $node;
- }
-
- /**
- * Removes "raw" filters.
- *
- * @param Twig_NodeInterface $node A Node
- * @param Twig_Environment $env The current Twig environment
- */
- protected function optimizeRawFilter($node, $env)
- {
- if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
- return $node->getNode('node');
- }
-
- return $node;
- }
-
- /**
- * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
- *
- * @param Twig_NodeInterface $node A Node
- * @param Twig_Environment $env The current Twig environment
- */
- protected function enterOptimizeFor($node, $env)
- {
- if ($node instanceof Twig_Node_For) {
- // disable the loop variable by default
- $node->setAttribute('with_loop', false);
- array_unshift($this->loops, $node);
- } elseif (!$this->loops) {
- // we are outside a loop
- return;
- }
-
- // when do we need to add the loop variable back?
-
- // the loop variable is referenced for the current loop
- elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
- $this->addLoopToCurrent();
- }
-
- // block reference
- elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
- $this->addLoopToCurrent();
- }
-
- // include without the only attribute
- elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
- $this->addLoopToAll();
- }
-
- // the loop variable is referenced via an attribute
- elseif ($node instanceof Twig_Node_Expression_GetAttr
- && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
- || 'parent' === $node->getNode('attribute')->getAttribute('value')
- )
- && (true === $this->loops[0]->getAttribute('with_loop')
- || ($node->getNode('node') instanceof Twig_Node_Expression_Name
- && 'loop' === $node->getNode('node')->getAttribute('name')
- )
- )
- ) {
- $this->addLoopToAll();
- }
- }
-
- /**
- * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
- *
- * @param Twig_NodeInterface $node A Node
- * @param Twig_Environment $env The current Twig environment
- */
- protected function leaveOptimizeFor($node, $env)
- {
- if ($node instanceof Twig_Node_For) {
- array_shift($this->loops);
- }
- }
-
- protected function addLoopToCurrent()
- {
- $this->loops[0]->setAttribute('with_loop', true);
- }
-
- protected function addLoopToAll()
- {
- foreach ($this->loops as $loop) {
- $loop->setAttribute('with_loop', true);
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPriority()
- {
- return 255;
- }
-}
+++ /dev/null
-<?php
-
-class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
-{
- protected $data = array();
- protected $safeVars = array();
-
- public function setSafeVars($safeVars)
- {
- $this->safeVars = $safeVars;
- }
-
- public function getSafe(Twig_NodeInterface $node)
- {
- $hash = spl_object_hash($node);
- if (isset($this->data[$hash])) {
- foreach ($this->data[$hash] as $bucket) {
- if ($bucket['key'] === $node) {
- return $bucket['value'];
- }
- }
- }
- }
-
- protected function setSafe(Twig_NodeInterface $node, array $safe)
- {
- $hash = spl_object_hash($node);
- if (isset($this->data[$hash])) {
- foreach ($this->data[$hash] as &$bucket) {
- if ($bucket['key'] === $node) {
- $bucket['value'] = $safe;
-
- return;
- }
- }
- }
- $this->data[$hash][] = array(
- 'key' => $node,
- 'value' => $safe,
- );
- }
-
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- return $node;
- }
-
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Expression_Constant) {
- // constants are marked safe for all
- $this->setSafe($node, array('all'));
- } elseif ($node instanceof Twig_Node_Expression_BlockReference) {
- // blocks are safe by definition
- $this->setSafe($node, array('all'));
- } elseif ($node instanceof Twig_Node_Expression_Parent) {
- // parent block is safe by definition
- $this->setSafe($node, array('all'));
- } elseif ($node instanceof Twig_Node_Expression_Conditional) {
- // intersect safeness of both operands
- $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
- $this->setSafe($node, $safe);
- } elseif ($node instanceof Twig_Node_Expression_Filter) {
- // filter expression is safe when the filter is safe
- $name = $node->getNode('filter')->getAttribute('value');
- $args = $node->getNode('arguments');
- if (false !== $filter = $env->getFilter($name)) {
- $safe = $filter->getSafe($args);
- if (null === $safe) {
- $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
- }
- $this->setSafe($node, $safe);
- } else {
- $this->setSafe($node, array());
- }
- } elseif ($node instanceof Twig_Node_Expression_Function) {
- // function expression is safe when the function is safe
- $name = $node->getAttribute('name');
- $args = $node->getNode('arguments');
- $function = $env->getFunction($name);
- if (false !== $function) {
- $this->setSafe($node, $function->getSafe($args));
- } else {
- $this->setSafe($node, array());
- }
- } elseif ($node instanceof Twig_Node_Expression_MethodCall) {
- if ($node->getAttribute('safe')) {
- $this->setSafe($node, array('all'));
- } else {
- $this->setSafe($node, array());
- }
- } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
- $name = $node->getNode('node')->getAttribute('name');
- // attributes on template instances are safe
- if ('_self' == $name || in_array($name, $this->safeVars)) {
- $this->setSafe($node, array('all'));
- } else {
- $this->setSafe($node, array());
- }
- } else {
- $this->setSafe($node, array());
- }
-
- return $node;
- }
-
- protected function intersectSafe(array $a = null, array $b = null)
- {
- if (null === $a || null === $b) {
- return array();
- }
-
- if (in_array('all', $a)) {
- return $b;
- }
-
- if (in_array('all', $b)) {
- return $a;
- }
-
- return array_intersect($a, $b);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPriority()
- {
- return 0;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Twig_NodeVisitor_Sandbox implements sandboxing.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
-{
- protected $inAModule = false;
- protected $tags;
- protected $filters;
- protected $functions;
-
- /**
- * Called before child nodes are visited.
- *
- * @param Twig_NodeInterface $node The node to visit
- * @param Twig_Environment $env The Twig environment instance
- *
- * @return Twig_NodeInterface The modified node
- */
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Module) {
- $this->inAModule = true;
- $this->tags = array();
- $this->filters = array();
- $this->functions = array();
-
- return $node;
- } elseif ($this->inAModule) {
- // look for tags
- if ($node->getNodeTag()) {
- $this->tags[] = $node->getNodeTag();
- }
-
- // look for filters
- if ($node instanceof Twig_Node_Expression_Filter) {
- $this->filters[] = $node->getNode('filter')->getAttribute('value');
- }
-
- // look for functions
- if ($node instanceof Twig_Node_Expression_Function) {
- $this->functions[] = $node->getAttribute('name');
- }
-
- // wrap print to check __toString() calls
- if ($node instanceof Twig_Node_Print) {
- return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
- }
- }
-
- return $node;
- }
-
- /**
- * Called after child nodes are visited.
- *
- * @param Twig_NodeInterface $node The node to visit
- * @param Twig_Environment $env The Twig environment instance
- *
- * @return Twig_NodeInterface The modified node
- */
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Module) {
- $this->inAModule = false;
-
- return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
- }
-
- return $node;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPriority()
- {
- return 0;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface Twig_NodeVisitorInterface
-{
- /**
- * Called before child nodes are visited.
- *
- * @param Twig_NodeInterface $node The node to visit
- * @param Twig_Environment $env The Twig environment instance
- *
- * @return Twig_NodeInterface The modified node
- */
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env);
-
- /**
- * Called after child nodes are visited.
- *
- * @param Twig_NodeInterface $node The node to visit
- * @param Twig_Environment $env The Twig environment instance
- *
- * @return Twig_NodeInterface|false The modified node or false if the node must be removed
- */
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env);
-
- /**
- * Returns the priority for this visitor.
- *
- * Priority should be between -10 and 10 (0 is the default).
- *
- * @return integer The priority level
- */
- public function getPriority();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Default parser implementation.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Parser implements Twig_ParserInterface
-{
- protected $stack = array();
- protected $stream;
- protected $parent;
- protected $handlers;
- protected $visitors;
- protected $expressionParser;
- protected $blocks;
- protected $blockStack;
- protected $macros;
- protected $env;
- protected $reservedMacroNames;
- protected $importedSymbols;
- protected $traits;
- protected $embeddedTemplates = array();
-
- /**
- * Constructor.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- */
- public function __construct(Twig_Environment $env)
- {
- $this->env = $env;
- }
-
- public function getEnvironment()
- {
- return $this->env;
- }
-
- public function getVarName()
- {
- return sprintf('__internal_%s', hash('sha1', uniqid(mt_rand(), true), false));
- }
-
- public function getFilename()
- {
- return $this->stream->getFilename();
- }
-
- /**
- * Converts a token stream to a node tree.
- *
- * @param Twig_TokenStream $stream A token stream instance
- *
- * @return Twig_Node_Module A node tree
- */
- public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
- {
- // push all variables into the stack to keep the current state of the parser
- $vars = get_object_vars($this);
- unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']);
- $this->stack[] = $vars;
-
- // tag handlers
- if (null === $this->handlers) {
- $this->handlers = $this->env->getTokenParsers();
- $this->handlers->setParser($this);
- }
-
- // node visitors
- if (null === $this->visitors) {
- $this->visitors = $this->env->getNodeVisitors();
- }
-
- if (null === $this->expressionParser) {
- $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
- }
-
- $this->stream = $stream;
- $this->parent = null;
- $this->blocks = array();
- $this->macros = array();
- $this->traits = array();
- $this->blockStack = array();
- $this->importedSymbols = array(array());
- $this->embeddedTemplates = array();
-
- try {
- $body = $this->subparse($test, $dropNeedle);
-
- if (null !== $this->parent) {
- if (null === $body = $this->filterBodyNodes($body)) {
- $body = new Twig_Node();
- }
- }
- } catch (Twig_Error_Syntax $e) {
- if (!$e->getTemplateFile()) {
- $e->setTemplateFile($this->getFilename());
- }
-
- if (!$e->getTemplateLine()) {
- $e->setTemplateLine($this->stream->getCurrent()->getLine());
- }
-
- throw $e;
- }
-
- $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
-
- $traverser = new Twig_NodeTraverser($this->env, $this->visitors);
-
- $node = $traverser->traverse($node);
-
- // restore previous stack so previous parse() call can resume working
- foreach (array_pop($this->stack) as $key => $val) {
- $this->$key = $val;
- }
-
- return $node;
- }
-
- public function subparse($test, $dropNeedle = false)
- {
- $lineno = $this->getCurrentToken()->getLine();
- $rv = array();
- while (!$this->stream->isEOF()) {
- switch ($this->getCurrentToken()->getType()) {
- case Twig_Token::TEXT_TYPE:
- $token = $this->stream->next();
- $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
- break;
-
- case Twig_Token::VAR_START_TYPE:
- $token = $this->stream->next();
- $expr = $this->expressionParser->parseExpression();
- $this->stream->expect(Twig_Token::VAR_END_TYPE);
- $rv[] = new Twig_Node_Print($expr, $token->getLine());
- break;
-
- case Twig_Token::BLOCK_START_TYPE:
- $this->stream->next();
- $token = $this->getCurrentToken();
-
- if ($token->getType() !== Twig_Token::NAME_TYPE) {
- throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename());
- }
-
- if (null !== $test && call_user_func($test, $token)) {
- if ($dropNeedle) {
- $this->stream->next();
- }
-
- if (1 === count($rv)) {
- return $rv[0];
- }
-
- return new Twig_Node($rv, array(), $lineno);
- }
-
- $subparser = $this->handlers->getTokenParser($token->getValue());
- if (null === $subparser) {
- if (null !== $test) {
- $error = sprintf('Unexpected tag name "%s"', $token->getValue());
- if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
- $error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno);
- }
-
- throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename());
- }
-
- $message = sprintf('Unknown tag name "%s"', $token->getValue());
- if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
- $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
- }
-
- throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
- }
-
- $this->stream->next();
-
- $node = $subparser->parse($token);
- if (null !== $node) {
- $rv[] = $node;
- }
- break;
-
- default:
- throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
- }
- }
-
- if (1 === count($rv)) {
- return $rv[0];
- }
-
- return new Twig_Node($rv, array(), $lineno);
- }
-
- public function addHandler($name, $class)
- {
- $this->handlers[$name] = $class;
- }
-
- public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
- {
- $this->visitors[] = $visitor;
- }
-
- public function getBlockStack()
- {
- return $this->blockStack;
- }
-
- public function peekBlockStack()
- {
- return $this->blockStack[count($this->blockStack) - 1];
- }
-
- public function popBlockStack()
- {
- array_pop($this->blockStack);
- }
-
- public function pushBlockStack($name)
- {
- $this->blockStack[] = $name;
- }
-
- public function hasBlock($name)
- {
- return isset($this->blocks[$name]);
- }
-
- public function getBlock($name)
- {
- return $this->blocks[$name];
- }
-
- public function setBlock($name, $value)
- {
- $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
- }
-
- public function hasMacro($name)
- {
- return isset($this->macros[$name]);
- }
-
- public function setMacro($name, Twig_Node_Macro $node)
- {
- if (null === $this->reservedMacroNames) {
- $this->reservedMacroNames = array();
- $r = new ReflectionClass($this->env->getBaseTemplateClass());
- foreach ($r->getMethods() as $method) {
- $this->reservedMacroNames[] = $method->getName();
- }
- }
-
- if (in_array($name, $this->reservedMacroNames)) {
- throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
- }
-
- $this->macros[$name] = $node;
- }
-
- public function addTrait($trait)
- {
- $this->traits[] = $trait;
- }
-
- public function hasTraits()
- {
- return count($this->traits) > 0;
- }
-
- public function embedTemplate(Twig_Node_Module $template)
- {
- $template->setIndex(mt_rand());
-
- $this->embeddedTemplates[] = $template;
- }
-
- public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
- {
- $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
- }
-
- public function getImportedSymbol($type, $alias)
- {
- foreach ($this->importedSymbols as $functions) {
- if (isset($functions[$type][$alias])) {
- return $functions[$type][$alias];
- }
- }
- }
-
- public function isMainScope()
- {
- return 1 === count($this->importedSymbols);
- }
-
- public function pushLocalScope()
- {
- array_unshift($this->importedSymbols, array());
- }
-
- public function popLocalScope()
- {
- array_shift($this->importedSymbols);
- }
-
- /**
- * Gets the expression parser.
- *
- * @return Twig_ExpressionParser The expression parser
- */
- public function getExpressionParser()
- {
- return $this->expressionParser;
- }
-
- public function getParent()
- {
- return $this->parent;
- }
-
- public function setParent($parent)
- {
- $this->parent = $parent;
- }
-
- /**
- * Gets the token stream.
- *
- * @return Twig_TokenStream The token stream
- */
- public function getStream()
- {
- return $this->stream;
- }
-
- /**
- * Gets the current token.
- *
- * @return Twig_Token The current token
- */
- public function getCurrentToken()
- {
- return $this->stream->getCurrent();
- }
-
- protected function filterBodyNodes(Twig_NodeInterface $node)
- {
- // check that the body does not contain non-empty output nodes
- if (
- ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
- ||
- (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
- ) {
- if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
- throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
- }
-
- throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
- }
-
- // bypass "set" nodes as they "capture" the output
- if ($node instanceof Twig_Node_Set) {
- return $node;
- }
-
- if ($node instanceof Twig_NodeOutputInterface) {
- return;
- }
-
- foreach ($node as $k => $n) {
- if (null !== $n && null === $n = $this->filterBodyNodes($n)) {
- $node->removeNode($k);
- }
- }
-
- return $node;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by parser classes.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_ParserInterface
-{
- /**
- * Converts a token stream to a node tree.
- *
- * @param Twig_TokenStream $stream A token stream instance
- *
- * @return Twig_Node_Module A node tree
- */
- public function parse(Twig_TokenStream $stream);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Exception thrown when a security error occurs at runtime.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Sandbox_SecurityError extends Twig_Error
-{
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a security policy which need to be enforced when sandbox mode is enabled.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
-{
- protected $allowedTags;
- protected $allowedFilters;
- protected $allowedMethods;
- protected $allowedProperties;
- protected $allowedFunctions;
-
- public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
- {
- $this->allowedTags = $allowedTags;
- $this->allowedFilters = $allowedFilters;
- $this->setAllowedMethods($allowedMethods);
- $this->allowedProperties = $allowedProperties;
- $this->allowedFunctions = $allowedFunctions;
- }
-
- public function setAllowedTags(array $tags)
- {
- $this->allowedTags = $tags;
- }
-
- public function setAllowedFilters(array $filters)
- {
- $this->allowedFilters = $filters;
- }
-
- public function setAllowedMethods(array $methods)
- {
- $this->allowedMethods = array();
- foreach ($methods as $class => $m) {
- $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m));
- }
- }
-
- public function setAllowedProperties(array $properties)
- {
- $this->allowedProperties = $properties;
- }
-
- public function setAllowedFunctions(array $functions)
- {
- $this->allowedFunctions = $functions;
- }
-
- public function checkSecurity($tags, $filters, $functions)
- {
- foreach ($tags as $tag) {
- if (!in_array($tag, $this->allowedTags)) {
- throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag));
- }
- }
-
- foreach ($filters as $filter) {
- if (!in_array($filter, $this->allowedFilters)) {
- throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
- }
- }
-
- foreach ($functions as $function) {
- if (!in_array($function, $this->allowedFunctions)) {
- throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
- }
- }
- }
-
- public function checkMethodAllowed($obj, $method)
- {
- if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) {
- return true;
- }
-
- $allowed = false;
- $method = strtolower($method);
- foreach ($this->allowedMethods as $class => $methods) {
- if ($obj instanceof $class) {
- $allowed = in_array($method, $methods);
-
- break;
- }
- }
-
- if (!$allowed) {
- throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
- }
- }
-
- public function checkPropertyAllowed($obj, $property)
- {
- $allowed = false;
- foreach ($this->allowedProperties as $class => $properties) {
- if ($obj instanceof $class) {
- $allowed = in_array($property, is_array($properties) ? $properties : array($properties));
-
- break;
- }
- }
-
- if (!$allowed) {
- throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj)));
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interfaces that all security policy classes must implements.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface Twig_Sandbox_SecurityPolicyInterface
-{
- public function checkSecurity($tags, $filters, $functions);
-
- public function checkMethodAllowed($obj, $method);
-
- public function checkPropertyAllowed($obj, $method);
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009-2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template filter.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_SimpleFilter
-{
- protected $name;
- protected $callable;
- protected $options;
- protected $arguments = array();
-
- public function __construct($name, $callable, array $options = array())
- {
- $this->name = $name;
- $this->callable = $callable;
- $this->options = array_merge(array(
- 'needs_environment' => false,
- 'needs_context' => false,
- 'is_safe' => null,
- 'is_safe_callback' => null,
- 'pre_escape' => null,
- 'preserves_safety' => null,
- 'node_class' => 'Twig_Node_Expression_Filter',
- ), $options);
- }
-
- public function getName()
- {
- return $this->name;
- }
-
- public function getCallable()
- {
- return $this->callable;
- }
-
- public function getNodeClass()
- {
- return $this->options['node_class'];
- }
-
- public function setArguments($arguments)
- {
- $this->arguments = $arguments;
- }
-
- public function getArguments()
- {
- return $this->arguments;
- }
-
- public function needsEnvironment()
- {
- return $this->options['needs_environment'];
- }
-
- public function needsContext()
- {
- return $this->options['needs_context'];
- }
-
- public function getSafe(Twig_Node $filterArgs)
- {
- if (null !== $this->options['is_safe']) {
- return $this->options['is_safe'];
- }
-
- if (null !== $this->options['is_safe_callback']) {
- return call_user_func($this->options['is_safe_callback'], $filterArgs);
- }
- }
-
- public function getPreservesSafety()
- {
- return $this->options['preserves_safety'];
- }
-
- public function getPreEscape()
- {
- return $this->options['pre_escape'];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010-2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template function.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_SimpleFunction
-{
- protected $name;
- protected $callable;
- protected $options;
- protected $arguments = array();
-
- public function __construct($name, $callable, array $options = array())
- {
- $this->name = $name;
- $this->callable = $callable;
- $this->options = array_merge(array(
- 'needs_environment' => false,
- 'needs_context' => false,
- 'is_safe' => null,
- 'is_safe_callback' => null,
- 'node_class' => 'Twig_Node_Expression_Function',
- ), $options);
- }
-
- public function getName()
- {
- return $this->name;
- }
-
- public function getCallable()
- {
- return $this->callable;
- }
-
- public function getNodeClass()
- {
- return $this->options['node_class'];
- }
-
- public function setArguments($arguments)
- {
- $this->arguments = $arguments;
- }
-
- public function getArguments()
- {
- return $this->arguments;
- }
-
- public function needsEnvironment()
- {
- return $this->options['needs_environment'];
- }
-
- public function needsContext()
- {
- return $this->options['needs_context'];
- }
-
- public function getSafe(Twig_Node $functionArgs)
- {
- if (null !== $this->options['is_safe']) {
- return $this->options['is_safe'];
- }
-
- if (null !== $this->options['is_safe_callback']) {
- return call_user_func($this->options['is_safe_callback'], $functionArgs);
- }
-
- return array();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010-2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template test.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_SimpleTest
-{
- protected $name;
- protected $callable;
- protected $options;
-
- public function __construct($name, $callable, array $options = array())
- {
- $this->name = $name;
- $this->callable = $callable;
- $this->options = array_merge(array(
- 'node_class' => 'Twig_Node_Expression_Test',
- ), $options);
- }
-
- public function getName()
- {
- return $this->name;
- }
-
- public function getCallable()
- {
- return $this->callable;
- }
-
- public function getNodeClass()
- {
- return $this->options['node_class'];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Default base class for compiled templates.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-abstract class Twig_Template implements Twig_TemplateInterface
-{
- protected static $cache = array();
-
- protected $parent;
- protected $parents;
- protected $env;
- protected $blocks;
- protected $traits;
-
- /**
- * Constructor.
- *
- * @param Twig_Environment $env A Twig_Environment instance
- */
- public function __construct(Twig_Environment $env)
- {
- $this->env = $env;
- $this->blocks = array();
- $this->traits = array();
- }
-
- /**
- * Returns the template name.
- *
- * @return string The template name
- */
- abstract public function getTemplateName();
-
- /**
- * {@inheritdoc}
- */
- public function getEnvironment()
- {
- return $this->env;
- }
-
- /**
- * Returns the parent template.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * @return Twig_TemplateInterface|false The parent template or false if there is no parent
- */
- public function getParent(array $context)
- {
- if (null !== $this->parent) {
- return $this->parent;
- }
-
- $parent = $this->doGetParent($context);
- if (false === $parent) {
- return false;
- } elseif ($parent instanceof Twig_Template) {
- $name = $parent->getTemplateName();
- $this->parents[$name] = $parent;
- $parent = $name;
- } elseif (!isset($this->parents[$parent])) {
- $this->parents[$parent] = $this->env->loadTemplate($parent);
- }
-
- return $this->parents[$parent];
- }
-
- protected function doGetParent(array $context)
- {
- return false;
- }
-
- public function isTraitable()
- {
- return true;
- }
-
- /**
- * Displays a parent block.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * @param string $name The block name to display from the parent
- * @param array $context The context
- * @param array $blocks The current set of blocks
- */
- public function displayParentBlock($name, array $context, array $blocks = array())
- {
- $name = (string) $name;
-
- if (isset($this->traits[$name])) {
- $this->traits[$name][0]->displayBlock($name, $context, $blocks);
- } elseif (false !== $parent = $this->getParent($context)) {
- $parent->displayBlock($name, $context, $blocks);
- } else {
- throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
- }
- }
-
- /**
- * Displays a block.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * @param string $name The block name to display
- * @param array $context The context
- * @param array $blocks The current set of blocks
- */
- public function displayBlock($name, array $context, array $blocks = array())
- {
- $name = (string) $name;
-
- if (isset($blocks[$name])) {
- $b = $blocks;
- unset($b[$name]);
- call_user_func($blocks[$name], $context, $b);
- } elseif (isset($this->blocks[$name])) {
- call_user_func($this->blocks[$name], $context, $blocks);
- } elseif (false !== $parent = $this->getParent($context)) {
- $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks));
- }
- }
-
- /**
- * Renders a parent block.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * @param string $name The block name to render from the parent
- * @param array $context The context
- * @param array $blocks The current set of blocks
- *
- * @return string The rendered block
- */
- public function renderParentBlock($name, array $context, array $blocks = array())
- {
- ob_start();
- $this->displayParentBlock($name, $context, $blocks);
-
- return ob_get_clean();
- }
-
- /**
- * Renders a block.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * @param string $name The block name to render
- * @param array $context The context
- * @param array $blocks The current set of blocks
- *
- * @return string The rendered block
- */
- public function renderBlock($name, array $context, array $blocks = array())
- {
- ob_start();
- $this->displayBlock($name, $context, $blocks);
-
- return ob_get_clean();
- }
-
- /**
- * Returns whether a block exists or not.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * This method does only return blocks defined in the current template
- * or defined in "used" traits.
- *
- * It does not return blocks from parent templates as the parent
- * template name can be dynamic, which is only known based on the
- * current context.
- *
- * @param string $name The block name
- *
- * @return Boolean true if the block exists, false otherwise
- */
- public function hasBlock($name)
- {
- return isset($this->blocks[(string) $name]);
- }
-
- /**
- * Returns all block names.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * @return array An array of block names
- *
- * @see hasBlock
- */
- public function getBlockNames()
- {
- return array_keys($this->blocks);
- }
-
- /**
- * Returns all blocks.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * @return array An array of blocks
- *
- * @see hasBlock
- */
- public function getBlocks()
- {
- return $this->blocks;
- }
-
- /**
- * {@inheritdoc}
- */
- public function display(array $context, array $blocks = array())
- {
- $this->displayWithErrorHandling($this->env->mergeGlobals($context), $blocks);
- }
-
- /**
- * {@inheritdoc}
- */
- public function render(array $context)
- {
- $level = ob_get_level();
- ob_start();
- try {
- $this->display($context);
- } catch (Exception $e) {
- while (ob_get_level() > $level) {
- ob_end_clean();
- }
-
- throw $e;
- }
-
- return ob_get_clean();
- }
-
- protected function displayWithErrorHandling(array $context, array $blocks = array())
- {
- try {
- $this->doDisplay($context, $blocks);
- } catch (Twig_Error $e) {
- if (!$e->getTemplateFile()) {
- $e->setTemplateFile($this->getTemplateName());
- }
-
- // this is mostly useful for Twig_Error_Loader exceptions
- // see Twig_Error_Loader
- if (false === $e->getTemplateLine()) {
- $e->setTemplateLine(-1);
- $e->guess();
- }
-
- throw $e;
- } catch (Exception $e) {
- throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, null, $e);
- }
- }
-
- /**
- * Auto-generated method to display the template with the given context.
- *
- * @param array $context An array of parameters to pass to the template
- * @param array $blocks An array of blocks to pass to the template
- */
- abstract protected function doDisplay(array $context, array $blocks = array());
-
- /**
- * Returns a variable from the context.
- *
- * This method is for internal use only and should never be called
- * directly.
- *
- * This method should not be overridden in a sub-class as this is an
- * implementation detail that has been introduced to optimize variable
- * access for versions of PHP before 5.4. This is not a way to override
- * the way to get a variable value.
- *
- * @param array $context The context
- * @param string $item The variable to return from the context
- * @param Boolean $ignoreStrictCheck Whether to ignore the strict variable check or not
- *
- * @return The content of the context variable
- *
- * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
- */
- final protected function getContext($context, $item, $ignoreStrictCheck = false)
- {
- if (!array_key_exists($item, $context)) {
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
- return null;
- }
-
- throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
- }
-
- return $context[$item];
- }
-
- /**
- * Returns the attribute value for a given array/object.
- *
- * @param mixed $object The object or array from where to get the item
- * @param mixed $item The item to get from the array or object
- * @param array $arguments An array of arguments to pass if the item is an object method
- * @param string $type The type of attribute (@see Twig_TemplateInterface)
- * @param Boolean $isDefinedTest Whether this is only a defined check
- * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not
- *
- * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
- *
- * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
- */
- protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
- {
- // array
- if (Twig_TemplateInterface::METHOD_CALL !== $type) {
- $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
-
- if ((is_array($object) && array_key_exists($arrayItem, $object))
- || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
- ) {
- if ($isDefinedTest) {
- return true;
- }
-
- return $object[$arrayItem];
- }
-
- if (Twig_TemplateInterface::ARRAY_CALL === $type || !is_object($object)) {
- if ($isDefinedTest) {
- return false;
- }
-
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
- return null;
- }
-
- if (is_object($object)) {
- throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
- } elseif (is_array($object)) {
- throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
- } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
- throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
- } else {
- throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
- }
- }
- }
-
- if (!is_object($object)) {
- if ($isDefinedTest) {
- return false;
- }
-
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
- return null;
- }
-
- throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
- }
-
- $class = get_class($object);
-
- // object property
- if (Twig_TemplateInterface::METHOD_CALL !== $type) {
- if (isset($object->$item) || array_key_exists((string) $item, $object)) {
- if ($isDefinedTest) {
- return true;
- }
-
- if ($this->env->hasExtension('sandbox')) {
- $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
- }
-
- return $object->$item;
- }
- }
-
- // object method
- if (!isset(self::$cache[$class]['methods'])) {
- self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
- }
-
- $lcItem = strtolower($item);
- if (isset(self::$cache[$class]['methods'][$lcItem])) {
- $method = (string) $item;
- } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
- $method = 'get'.$item;
- } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
- $method = 'is'.$item;
- } elseif (isset(self::$cache[$class]['methods']['__call'])) {
- $method = (string) $item;
- } else {
- if ($isDefinedTest) {
- return false;
- }
-
- if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
- return null;
- }
-
- throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
- }
-
- if ($isDefinedTest) {
- return true;
- }
-
- if ($this->env->hasExtension('sandbox')) {
- $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
- }
-
- $ret = call_user_func_array(array($object, $method), $arguments);
-
- // useful when calling a template method from a template
- // this is not supported but unfortunately heavily used in the Symfony profiler
- if ($object instanceof Twig_TemplateInterface) {
- return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
- }
-
- return $ret;
- }
-
- /**
- * This method is only useful when testing Twig. Do not use it.
- */
- public static function clearCache()
- {
- self::$cache = array();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by all compiled templates.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_TemplateInterface
-{
- const ANY_CALL = 'any';
- const ARRAY_CALL = 'array';
- const METHOD_CALL = 'method';
-
- /**
- * Renders the template with the given context and returns it as string.
- *
- * @param array $context An array of parameters to pass to the template
- *
- * @return string The rendered template
- */
- public function render(array $context);
-
- /**
- * Displays the template with the given context.
- *
- * @param array $context An array of parameters to pass to the template
- * @param array $blocks An array of blocks to pass to the template
- */
- public function display(array $context, array $blocks = array());
-
- /**
- * Returns the bound environment for this template.
- *
- * @return Twig_Environment The current environment
- */
- public function getEnvironment();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template test.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface
-{
- protected $options;
- protected $arguments = array();
-
- public function __construct(array $options = array())
- {
- $this->options = array_merge(array(
- 'callable' => null,
- ), $options);
- }
-
- public function getCallable()
- {
- return $this->options['callable'];
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a function template test.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Test_Function extends Twig_Test
-{
- protected $function;
-
- public function __construct($function, array $options = array())
- {
- $options['callable'] = $function;
-
- parent::__construct($options);
-
- $this->function = $function;
- }
-
- public function compile()
- {
- return $this->function;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Integration test helper
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Karma Dordrak <drak@zikula.org>
- */
-abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase
-{
- abstract protected function getExtensions();
- abstract protected function getFixturesDir();
-
- /**
- * @dataProvider getTests
- */
- public function testIntegration($file, $message, $condition, $templates, $exception, $outputs)
- {
- $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs);
- }
-
- public function getTests()
- {
- $fixturesDir = realpath($this->getFixturesDir());
- $tests = array();
-
- foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
- if (!preg_match('/\.test$/', $file)) {
- continue;
- }
-
- $test = file_get_contents($file->getRealpath());
-
- if (preg_match('/
- --TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) {
- $message = $match[1];
- $condition = $match[2];
- $templates = $this->parseTemplates($match[3]);
- $exception = $match[5];
- $outputs = array(array(null, $match[4], null, ''));
- } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) {
- $message = $match[1];
- $condition = $match[2];
- $templates = $this->parseTemplates($match[3]);
- $exception = false;
- preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER);
- } else {
- throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file)));
- }
-
- $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs);
- }
-
- return $tests;
- }
-
- protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs)
- {
- if ($condition) {
- eval('$ret = '.$condition.';');
- if (!$ret) {
- $this->markTestSkipped($condition);
- }
- }
-
- $loader = new Twig_Loader_Array($templates);
-
- foreach ($outputs as $match) {
- $config = array_merge(array(
- 'cache' => false,
- 'strict_variables' => true,
- ), $match[2] ? eval($match[2].';') : array());
- $twig = new Twig_Environment($loader, $config);
- $twig->addGlobal('global', 'global');
- foreach ($this->getExtensions() as $extension) {
- $twig->addExtension($extension);
- }
-
- try {
- $template = $twig->loadTemplate('index.twig');
- } catch (Exception $e) {
- if (false !== $exception) {
- $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage())));
-
- return;
- }
-
- if ($e instanceof Twig_Error_Syntax) {
- $e->setTemplateFile($file);
-
- throw $e;
- }
-
- throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
- }
-
- try {
- $output = trim($template->render(eval($match[1].';')), "\n ");
- } catch (Exception $e) {
- if (false !== $exception) {
- $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage())));
-
- return;
- }
-
- if ($e instanceof Twig_Error_Syntax) {
- $e->setTemplateFile($file);
- } else {
- $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
- }
-
- $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage()));
- }
-
- if (false !== $exception) {
- list($class, ) = explode(':', $exception);
- $this->assertThat(NULL, new PHPUnit_Framework_Constraint_Exception($class));
- }
-
- $expected = trim($match[3], "\n ");
-
- if ($expected != $output) {
- echo 'Compiled template that failed:';
-
- foreach (array_keys($templates) as $name) {
- echo "Template: $name\n";
- $source = $loader->getSource($name);
- echo $twig->compile($twig->parse($twig->tokenize($source, $name)));
- }
- }
- $this->assertEquals($expected, $output, $message.' (in '.$file.')');
- }
- }
-
- protected static function parseTemplates($test)
- {
- $templates = array();
- preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2];
- }
-
- return $templates;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a method template test.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Test_Method extends Twig_Test
-{
- protected $extension;
- protected $method;
-
- public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
- {
- $options['callable'] = array($extension, $method);
-
- parent::__construct($options);
-
- $this->extension = $extension;
- $this->method = $method;
- }
-
- public function compile()
- {
- return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template test as a Node.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_Test_Node extends Twig_Test
-{
- protected $class;
-
- public function __construct($class, array $options = array())
- {
- parent::__construct($options);
-
- $this->class = $class;
- }
-
- public function getClass()
- {
- return $this->class;
- }
-
- public function compile()
- {
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-abstract class Twig_Test_NodeTestCase extends PHPUnit_Framework_TestCase
-{
- abstract public function getTests();
-
- /**
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- $this->assertNodeCompilation($source, $node, $environment);
- }
-
- public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null)
- {
- $compiler = $this->getCompiler($environment);
- $compiler->compile($node);
-
- $this->assertEquals($source, trim($compiler->getSource()));
- }
-
- protected function getCompiler(Twig_Environment $environment = null)
- {
- return new Twig_Compiler(null === $environment ? $this->getEnvironment() : $environment);
- }
-
- protected function getEnvironment()
- {
- return new Twig_Environment();
- }
-
- protected function getVariableGetter($name)
- {
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
- return sprintf('(isset($context["%s"]) ? $context["%s"] : null)', $name, $name);
- }
-
- return sprintf('$this->getContext($context, "%s")', $name);
- }
-
- protected function getAttributeGetter()
- {
- if (function_exists('twig_template_get_attributes')) {
- return 'twig_template_get_attributes($this, ';
- }
-
- return '$this->getAttribute(';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a callable template test.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_TestCallableInterface
-{
- public function getCallable();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a template test.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_TestInterface
-{
- /**
- * Compiles a test.
- *
- * @return string The PHP code for the test
- */
- public function compile();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a Token.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_Token
-{
- protected $value;
- protected $type;
- protected $lineno;
-
- const EOF_TYPE = -1;
- const TEXT_TYPE = 0;
- const BLOCK_START_TYPE = 1;
- const VAR_START_TYPE = 2;
- const BLOCK_END_TYPE = 3;
- const VAR_END_TYPE = 4;
- const NAME_TYPE = 5;
- const NUMBER_TYPE = 6;
- const STRING_TYPE = 7;
- const OPERATOR_TYPE = 8;
- const PUNCTUATION_TYPE = 9;
- const INTERPOLATION_START_TYPE = 10;
- const INTERPOLATION_END_TYPE = 11;
-
- /**
- * Constructor.
- *
- * @param integer $type The type of the token
- * @param string $value The token value
- * @param integer $lineno The line position in the source
- */
- public function __construct($type, $value, $lineno)
- {
- $this->type = $type;
- $this->value = $value;
- $this->lineno = $lineno;
- }
-
- /**
- * Returns a string representation of the token.
- *
- * @return string A string representation of the token
- */
- public function __toString()
- {
- return sprintf('%s(%s)', self::typeToString($this->type, true, $this->lineno), $this->value);
- }
-
- /**
- * Tests the current token for a type and/or a value.
- *
- * Parameters may be:
- * * just type
- * * type and value (or array of possible values)
- * * just value (or array of possible values) (NAME_TYPE is used as type)
- *
- * @param array|integer $type The type to test
- * @param array|string|null $values The token value
- *
- * @return Boolean
- */
- public function test($type, $values = null)
- {
- if (null === $values && !is_int($type)) {
- $values = $type;
- $type = self::NAME_TYPE;
- }
-
- return ($this->type === $type) && (
- null === $values ||
- (is_array($values) && in_array($this->value, $values)) ||
- $this->value == $values
- );
- }
-
- /**
- * Gets the line.
- *
- * @return integer The source line
- */
- public function getLine()
- {
- return $this->lineno;
- }
-
- /**
- * Gets the token type.
- *
- * @return integer The token type
- */
- public function getType()
- {
- return $this->type;
- }
-
- /**
- * Gets the token value.
- *
- * @return string The token value
- */
- public function getValue()
- {
- return $this->value;
- }
-
- /**
- * Returns the constant representation (internal) of a given type.
- *
- * @param integer $type The type as an integer
- * @param Boolean $short Whether to return a short representation or not
- * @param integer $line The code line
- *
- * @return string The string representation
- */
- public static function typeToString($type, $short = false, $line = -1)
- {
- switch ($type) {
- case self::EOF_TYPE:
- $name = 'EOF_TYPE';
- break;
- case self::TEXT_TYPE:
- $name = 'TEXT_TYPE';
- break;
- case self::BLOCK_START_TYPE:
- $name = 'BLOCK_START_TYPE';
- break;
- case self::VAR_START_TYPE:
- $name = 'VAR_START_TYPE';
- break;
- case self::BLOCK_END_TYPE:
- $name = 'BLOCK_END_TYPE';
- break;
- case self::VAR_END_TYPE:
- $name = 'VAR_END_TYPE';
- break;
- case self::NAME_TYPE:
- $name = 'NAME_TYPE';
- break;
- case self::NUMBER_TYPE:
- $name = 'NUMBER_TYPE';
- break;
- case self::STRING_TYPE:
- $name = 'STRING_TYPE';
- break;
- case self::OPERATOR_TYPE:
- $name = 'OPERATOR_TYPE';
- break;
- case self::PUNCTUATION_TYPE:
- $name = 'PUNCTUATION_TYPE';
- break;
- case self::INTERPOLATION_START_TYPE:
- $name = 'INTERPOLATION_START_TYPE';
- break;
- case self::INTERPOLATION_END_TYPE:
- $name = 'INTERPOLATION_END_TYPE';
- break;
- default:
- throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
- }
-
- return $short ? $name : 'Twig_Token::'.$name;
- }
-
- /**
- * Returns the english representation of a given type.
- *
- * @param integer $type The type as an integer
- * @param integer $line The code line
- *
- * @return string The string representation
- */
- public static function typeToEnglish($type, $line = -1)
- {
- switch ($type) {
- case self::EOF_TYPE:
- return 'end of template';
- case self::TEXT_TYPE:
- return 'text';
- case self::BLOCK_START_TYPE:
- return 'begin of statement block';
- case self::VAR_START_TYPE:
- return 'begin of print statement';
- case self::BLOCK_END_TYPE:
- return 'end of statement block';
- case self::VAR_END_TYPE:
- return 'end of print statement';
- case self::NAME_TYPE:
- return 'name';
- case self::NUMBER_TYPE:
- return 'number';
- case self::STRING_TYPE:
- return 'string';
- case self::OPERATOR_TYPE:
- return 'operator';
- case self::PUNCTUATION_TYPE:
- return 'punctuation';
- case self::INTERPOLATION_START_TYPE:
- return 'begin of string interpolation';
- case self::INTERPOLATION_END_TYPE:
- return 'end of string interpolation';
- default:
- throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Base class for all token parsers.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-abstract class Twig_TokenParser implements Twig_TokenParserInterface
-{
- /**
- * @var Twig_Parser
- */
- protected $parser;
-
- /**
- * Sets the parser associated with this token parser
- *
- * @param $parser A Twig_Parser instance
- */
- public function setParser(Twig_Parser $parser)
- {
- $this->parser = $parser;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Marks a section of a template to be escaped or not.
- *
- * <pre>
- * {% autoescape true %}
- * Everything will be automatically escaped in this block
- * {% endautoescape %}
- *
- * {% autoescape false %}
- * Everything will be outputed as is in this block
- * {% endautoescape %}
- *
- * {% autoescape true js %}
- * Everything will be automatically escaped in this block
- * using the js escaping strategy
- * {% endautoescape %}
- * </pre>
- */
-class Twig_TokenParser_AutoEscape extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
-
- if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
- $value = 'html';
- } else {
- $expr = $this->parser->getExpressionParser()->parseExpression();
- if (!$expr instanceof Twig_Node_Expression_Constant) {
- throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename());
- }
- $value = $expr->getAttribute('value');
-
- $compat = true === $value || false === $value;
-
- if (true === $value) {
- $value = 'html';
- }
-
- if ($compat && $stream->test(Twig_Token::NAME_TYPE)) {
- if (false === $value) {
- throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename());
- }
-
- $value = $stream->next()->getValue();
- }
- }
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
- }
-
- public function decideBlockEnd(Twig_Token $token)
- {
- return $token->test('endautoescape');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'autoescape';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Marks a section of a template as being reusable.
- *
- * <pre>
- * {% block head %}
- * <link rel="stylesheet" href="style.css" />
- * <title>{% block title %}{% endblock %} - My Webpage</title>
- * {% endblock %}
- * </pre>
- */
-class Twig_TokenParser_Block extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
- if ($this->parser->hasBlock($name)) {
- throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename());
- }
- $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
- $this->parser->pushLocalScope();
- $this->parser->pushBlockStack($name);
-
- if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
- $stream->next();
-
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- if ($stream->test(Twig_Token::NAME_TYPE)) {
- $value = $stream->next()->getValue();
-
- if ($value != $name) {
- throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
- }
- }
- } else {
- $body = new Twig_Node(array(
- new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
- ));
- }
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- $block->setNode('body', $body);
- $this->parser->popBlockStack();
- $this->parser->popLocalScope();
-
- return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
- }
-
- public function decideBlockEnd(Twig_Token $token)
- {
- return $token->test('endblock');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'block';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Evaluates an expression, discarding the returned value.
- */
-class Twig_TokenParser_Do extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $expr = $this->parser->getExpressionParser()->parseExpression();
-
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node_Do($expr, $token->getLine(), $this->getTag());
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'do';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2012 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Embeds a template.
- */
-class Twig_TokenParser_Embed extends Twig_TokenParser_Include
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $stream = $this->parser->getStream();
-
- $parent = $this->parser->getExpressionParser()->parseExpression();
-
- list($variables, $only, $ignoreMissing) = $this->parseArguments();
-
- // inject a fake parent to make the parent() function work
- $stream->injectTokens(array(
- new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
- new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
- new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
- new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
- ));
-
- $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);
-
- // override the parent with the correct one
- $module->setNode('parent', $parent);
-
- $this->parser->embedTemplate($module);
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
- }
-
- public function decideBlockEnd(Twig_Token $token)
- {
- return $token->test('endembed');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'embed';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Extends a template by another one.
- *
- * <pre>
- * {% extends "base.html" %}
- * </pre>
- */
-class Twig_TokenParser_Extends extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- if (!$this->parser->isMainScope()) {
- throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename());
- }
-
- if (null !== $this->parser->getParent()) {
- throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename());
- }
- $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
-
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'extends';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Filters a section of a template by applying filters.
- *
- * <pre>
- * {% filter upper %}
- * This text becomes uppercase
- * {% endfilter %}
- * </pre>
- */
-class Twig_TokenParser_Filter extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $name = $this->parser->getVarName();
- $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag());
-
- $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- $block = new Twig_Node_Block($name, $body, $token->getLine());
- $this->parser->setBlock($name, $block);
-
- return new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
- }
-
- public function decideBlockEnd(Twig_Token $token)
- {
- return $token->test('endfilter');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'filter';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Flushes the output to the client.
- *
- * @see flush()
- */
-class Twig_TokenParser_Flush extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node_Flush($token->getLine(), $this->getTag());
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'flush';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Loops over each item of a sequence.
- *
- * <pre>
- * <ul>
- * {% for user in users %}
- * <li>{{ user.username|e }}</li>
- * {% endfor %}
- * </ul>
- * </pre>
- */
-class Twig_TokenParser_For extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
- $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
- $stream->expect(Twig_Token::OPERATOR_TYPE, 'in');
- $seq = $this->parser->getExpressionParser()->parseExpression();
-
- $ifexpr = null;
- if ($stream->test(Twig_Token::NAME_TYPE, 'if')) {
- $stream->next();
- $ifexpr = $this->parser->getExpressionParser()->parseExpression();
- }
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideForFork'));
- if ($stream->next()->getValue() == 'else') {
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $else = $this->parser->subparse(array($this, 'decideForEnd'), true);
- } else {
- $else = null;
- }
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- if (count($targets) > 1) {
- $keyTarget = $targets->getNode(0);
- $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
- $valueTarget = $targets->getNode(1);
- $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
- } else {
- $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
- $valueTarget = $targets->getNode(0);
- $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
- }
-
- if ($ifexpr) {
- $this->checkLoopUsageCondition($stream, $ifexpr);
- $this->checkLoopUsageBody($stream, $body);
- }
-
- return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
- }
-
- public function decideForFork(Twig_Token $token)
- {
- return $token->test(array('else', 'endfor'));
- }
-
- public function decideForEnd(Twig_Token $token)
- {
- return $token->test('endfor');
- }
-
- // the loop variable cannot be used in the condition
- protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
- {
- if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
- throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename());
- }
-
- foreach ($node as $n) {
- if (!$n) {
- continue;
- }
-
- $this->checkLoopUsageCondition($stream, $n);
- }
- }
-
- // check usage of non-defined loop-items
- // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include)
- protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node)
- {
- if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
- $attribute = $node->getNode('attribute');
- if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
- throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename());
- }
- }
-
- // should check for parent.loop.XXX usage
- if ($node instanceof Twig_Node_For) {
- return;
- }
-
- foreach ($node as $n) {
- if (!$n) {
- continue;
- }
-
- $this->checkLoopUsageBody($stream, $n);
- }
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'for';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Imports macros.
- *
- * <pre>
- * {% from 'forms.html' import forms %}
- * </pre>
- */
-class Twig_TokenParser_From extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $macro = $this->parser->getExpressionParser()->parseExpression();
- $stream = $this->parser->getStream();
- $stream->expect('import');
-
- $targets = array();
- do {
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
-
- $alias = $name;
- if ($stream->test('as')) {
- $stream->next();
-
- $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
- }
-
- $targets[$name] = $alias;
-
- if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
- break;
- }
-
- $stream->next();
- } while (true);
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
-
- foreach ($targets as $name => $alias) {
- $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
- }
-
- return $node;
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'from';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Tests a condition.
- *
- * <pre>
- * {% if users %}
- * <ul>
- * {% for user in users %}
- * <li>{{ user.username|e }}</li>
- * {% endfor %}
- * </ul>
- * {% endif %}
- * </pre>
- */
-class Twig_TokenParser_If extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
- $expr = $this->parser->getExpressionParser()->parseExpression();
- $stream = $this->parser->getStream();
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideIfFork'));
- $tests = array($expr, $body);
- $else = null;
-
- $end = false;
- while (!$end) {
- switch ($stream->next()->getValue()) {
- case 'else':
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $else = $this->parser->subparse(array($this, 'decideIfEnd'));
- break;
-
- case 'elseif':
- $expr = $this->parser->getExpressionParser()->parseExpression();
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideIfFork'));
- $tests[] = $expr;
- $tests[] = $body;
- break;
-
- case 'endif':
- $end = true;
- break;
-
- default:
- throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename());
- }
- }
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
- }
-
- public function decideIfFork(Twig_Token $token)
- {
- return $token->test(array('elseif', 'else', 'endif'));
- }
-
- public function decideIfEnd(Twig_Token $token)
- {
- return $token->test(array('endif'));
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'if';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Imports macros.
- *
- * <pre>
- * {% import 'forms.html' as forms %}
- * </pre>
- */
-class Twig_TokenParser_Import extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $macro = $this->parser->getExpressionParser()->parseExpression();
- $this->parser->getStream()->expect('as');
- $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- $this->parser->addImportedSymbol('template', $var->getAttribute('name'));
-
- return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'import';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Includes a template.
- *
- * <pre>
- * {% include 'header.html' %}
- * Body
- * {% include 'footer.html' %}
- * </pre>
- */
-class Twig_TokenParser_Include extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $expr = $this->parser->getExpressionParser()->parseExpression();
-
- list($variables, $only, $ignoreMissing) = $this->parseArguments();
-
- return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
- }
-
- protected function parseArguments()
- {
- $stream = $this->parser->getStream();
-
- $ignoreMissing = false;
- if ($stream->test(Twig_Token::NAME_TYPE, 'ignore')) {
- $stream->next();
- $stream->expect(Twig_Token::NAME_TYPE, 'missing');
-
- $ignoreMissing = true;
- }
-
- $variables = null;
- if ($stream->test(Twig_Token::NAME_TYPE, 'with')) {
- $stream->next();
-
- $variables = $this->parser->getExpressionParser()->parseExpression();
- }
-
- $only = false;
- if ($stream->test(Twig_Token::NAME_TYPE, 'only')) {
- $stream->next();
-
- $only = true;
- }
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- return array($variables, $only, $ignoreMissing);
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'include';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Defines a macro.
- *
- * <pre>
- * {% macro input(name, value, type, size) %}
- * <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
- * {% endmacro %}
- * </pre>
- */
-class Twig_TokenParser_Macro extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
-
- $arguments = $this->parser->getExpressionParser()->parseArguments(true, true);
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $this->parser->pushLocalScope();
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- if ($stream->test(Twig_Token::NAME_TYPE)) {
- $value = $stream->next()->getValue();
-
- if ($value != $name) {
- throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
- }
- }
- $this->parser->popLocalScope();
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag()));
- }
-
- public function decideBlockEnd(Twig_Token $token)
- {
- return $token->test('endmacro');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'macro';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Marks a section of a template as untrusted code that must be evaluated in the sandbox mode.
- *
- * <pre>
- * {% sandbox %}
- * {% include 'user.html' %}
- * {% endsandbox %}
- * </pre>
- *
- * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
- */
-class Twig_TokenParser_Sandbox extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- // in a sandbox tag, only include tags are allowed
- if (!$body instanceof Twig_Node_Include) {
- foreach ($body as $node) {
- if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
- continue;
- }
-
- if (!$node instanceof Twig_Node_Include) {
- throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename());
- }
- }
- }
-
- return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
- }
-
- public function decideBlockEnd(Twig_Token $token)
- {
- return $token->test('endsandbox');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'sandbox';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Defines a variable.
- *
- * <pre>
- * {% set foo = 'foo' %}
- *
- * {% set foo = [1, 2] %}
- *
- * {% set foo = {'foo': 'bar'} %}
- *
- * {% set foo = 'foo' ~ 'bar' %}
- *
- * {% set foo, bar = 'foo', 'bar' %}
- *
- * {% set foo %}Some content{% endset %}
- * </pre>
- */
-class Twig_TokenParser_Set extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
- $stream = $this->parser->getStream();
- $names = $this->parser->getExpressionParser()->parseAssignmentExpression();
-
- $capture = false;
- if ($stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
- $stream->next();
- $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- if (count($names) !== count($values)) {
- throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignments.", $stream->getCurrent()->getLine(), $stream->getFilename());
- }
- } else {
- $capture = true;
-
- if (count($names) > 1) {
- throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename());
- }
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- }
-
- return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
- }
-
- public function decideBlockEnd(Twig_Token $token)
- {
- return $token->test('endset');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'set';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Remove whitespaces between HTML tags.
- *
- * <pre>
- * {% spaceless %}
- * <div>
- * <strong>foo</strong>
- * </div>
- * {% endspaceless %}
- *
- * {# output will be <div><strong>foo</strong></div> #}
- * </pre>
- */
-class Twig_TokenParser_Spaceless extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $lineno = $token->getLine();
-
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true);
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node_Spaceless($body, $lineno, $this->getTag());
- }
-
- public function decideSpacelessEnd(Twig_Token $token)
- {
- return $token->test('endspaceless');
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'spaceless';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Imports blocks defined in another template into the current template.
- *
- * <pre>
- * {% extends "base.html" %}
- *
- * {% use "blocks.html" %}
- *
- * {% block title %}{% endblock %}
- * {% block content %}{% endblock %}
- * </pre>
- *
- * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details.
- */
-class Twig_TokenParser_Use extends Twig_TokenParser
-{
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token)
- {
- $template = $this->parser->getExpressionParser()->parseExpression();
- $stream = $this->parser->getStream();
-
- if (!$template instanceof Twig_Node_Expression_Constant) {
- throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename());
- }
-
- $targets = array();
- if ($stream->test('with')) {
- $stream->next();
-
- do {
- $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
-
- $alias = $name;
- if ($stream->test('as')) {
- $stream->next();
-
- $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
- }
-
- $targets[$name] = new Twig_Node_Expression_Constant($alias, -1);
-
- if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
- break;
- }
-
- $stream->next();
- } while (true);
- }
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets))));
- }
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag()
- {
- return 'use';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- * (c) 2010 Arnaud Le Blanc
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Default implementation of a token parser broker.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface
-{
- protected $parser;
- protected $parsers = array();
- protected $brokers = array();
-
- /**
- * Constructor.
- *
- * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances
- * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances
- */
- public function __construct($parsers = array(), $brokers = array())
- {
- foreach ($parsers as $parser) {
- if (!$parser instanceof Twig_TokenParserInterface) {
- throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');
- }
- $this->parsers[$parser->getTag()] = $parser;
- }
- foreach ($brokers as $broker) {
- if (!$broker instanceof Twig_TokenParserBrokerInterface) {
- throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');
- }
- $this->brokers[] = $broker;
- }
- }
-
- /**
- * Adds a TokenParser.
- *
- * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
- */
- public function addTokenParser(Twig_TokenParserInterface $parser)
- {
- $this->parsers[$parser->getTag()] = $parser;
- }
-
- /**
- * Removes a TokenParser.
- *
- * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
- */
- public function removeTokenParser(Twig_TokenParserInterface $parser)
- {
- $name = $parser->getTag();
- if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) {
- unset($this->parsers[$name]);
- }
- }
-
- /**
- * Adds a TokenParserBroker.
- *
- * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
- */
- public function addTokenParserBroker(Twig_TokenParserBroker $broker)
- {
- $this->brokers[] = $broker;
- }
-
- /**
- * Removes a TokenParserBroker.
- *
- * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
- */
- public function removeTokenParserBroker(Twig_TokenParserBroker $broker)
- {
- if (false !== $pos = array_search($broker, $this->brokers)) {
- unset($this->brokers[$pos]);
- }
- }
-
- /**
- * Gets a suitable TokenParser for a tag.
- *
- * First looks in parsers, then in brokers.
- *
- * @param string $tag A tag name
- *
- * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
- */
- public function getTokenParser($tag)
- {
- if (isset($this->parsers[$tag])) {
- return $this->parsers[$tag];
- }
- $broker = end($this->brokers);
- while (false !== $broker) {
- $parser = $broker->getTokenParser($tag);
- if (null !== $parser) {
- return $parser;
- }
- $broker = prev($this->brokers);
- }
- }
-
- public function getParsers()
- {
- return $this->parsers;
- }
-
- public function getParser()
- {
- return $this->parser;
- }
-
- public function setParser(Twig_ParserInterface $parser)
- {
- $this->parser = $parser;
- foreach ($this->parsers as $tokenParser) {
- $tokenParser->setParser($parser);
- }
- foreach ($this->brokers as $broker) {
- $broker->setParser($parser);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- * (c) 2010 Arnaud Le Blanc
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by token parser brokers.
- *
- * Token parser brokers allows to implement custom logic in the process of resolving a token parser for a given tag name.
- *
- * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
- * @deprecated since 1.12 (to be removed in 2.0)
- */
-interface Twig_TokenParserBrokerInterface
-{
- /**
- * Gets a TokenParser suitable for a tag.
- *
- * @param string $tag A tag name
- *
- * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
- */
- public function getTokenParser($tag);
-
- /**
- * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of.
- *
- * @param Twig_ParserInterface $parser A Twig_ParserInterface interface
- */
- public function setParser(Twig_ParserInterface $parser);
-
- /**
- * Gets the Twig_ParserInterface.
- *
- * @return null|Twig_ParserInterface A Twig_ParserInterface instance or null
- */
- public function getParser();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by token parsers.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-interface Twig_TokenParserInterface
-{
- /**
- * Sets the parser associated with this token parser
- *
- * @param $parser A Twig_Parser instance
- */
- public function setParser(Twig_Parser $parser);
-
- /**
- * Parses a token and returns a node.
- *
- * @param Twig_Token $token A Twig_Token instance
- *
- * @return Twig_NodeInterface A Twig_NodeInterface instance
- */
- public function parse(Twig_Token $token);
-
- /**
- * Gets the tag name associated with this token parser.
- *
- * @return string The tag name
- */
- public function getTag();
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a token stream.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-class Twig_TokenStream
-{
- protected $tokens;
- protected $current;
- protected $filename;
-
- /**
- * Constructor.
- *
- * @param array $tokens An array of tokens
- * @param string $filename The name of the filename which tokens are associated with
- */
- public function __construct(array $tokens, $filename = null)
- {
- $this->tokens = $tokens;
- $this->current = 0;
- $this->filename = $filename;
- }
-
- /**
- * Returns a string representation of the token stream.
- *
- * @return string
- */
- public function __toString()
- {
- return implode("\n", $this->tokens);
- }
-
- public function injectTokens(array $tokens)
- {
- $this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current));
- }
-
- /**
- * Sets the pointer to the next token and returns the old one.
- *
- * @return Twig_Token
- */
- public function next()
- {
- if (!isset($this->tokens[++$this->current])) {
- throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename);
- }
-
- return $this->tokens[$this->current - 1];
- }
-
- /**
- * Tests a token and returns it or throws a syntax error.
- *
- * @return Twig_Token
- */
- public function expect($type, $value = null, $message = null)
- {
- $token = $this->tokens[$this->current];
- if (!$token->test($type, $value)) {
- $line = $token->getLine();
- throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)',
- $message ? $message.'. ' : '',
- Twig_Token::typeToEnglish($token->getType(), $line), $token->getValue(),
- Twig_Token::typeToEnglish($type, $line), $value ? sprintf(' with value "%s"', $value) : ''),
- $line,
- $this->filename
- );
- }
- $this->next();
-
- return $token;
- }
-
- /**
- * Looks at the next token.
- *
- * @param integer $number
- *
- * @return Twig_Token
- */
- public function look($number = 1)
- {
- if (!isset($this->tokens[$this->current + $number])) {
- throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename);
- }
-
- return $this->tokens[$this->current + $number];
- }
-
- /**
- * Tests the current token
- *
- * @return bool
- */
- public function test($primary, $secondary = null)
- {
- return $this->tokens[$this->current]->test($primary, $secondary);
- }
-
- /**
- * Checks if end of stream was reached
- *
- * @return bool
- */
- public function isEOF()
- {
- return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE;
- }
-
- /**
- * Gets the current token
- *
- * @return Twig_Token
- */
- public function getCurrent()
- {
- return $this->tokens[$this->current];
- }
-
- /**
- * Gets the filename associated with this stream
- *
- * @return string
- */
- public function getFilename()
- {
- return $this->filename;
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="test/bootstrap.php"
->
- <testsuites>
- <testsuite name="Twig Test Suite">
- <directory>./test/Twig/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory suffix=".php">./lib/Twig/</directory>
- </whitelist>
- </filter>
-</phpunit>
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_AutoloaderTest extends PHPUnit_Framework_TestCase
-{
- public function testAutoload()
- {
- $this->assertFalse(class_exists('FooBarFoo'), '->autoload() does not try to load classes that does not begin with Twig');
-
- $autoloader = new Twig_Autoloader();
- $this->assertNull($autoloader->autoload('Foo'), '->autoload() returns false if it is not able to load a class');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_CompilerTest extends PHPUnit_Framework_TestCase
-{
- public function testReprNumericValueWithLocale()
- {
- $compiler = new Twig_Compiler(new Twig_Environment());
-
- $locale = setlocale(LC_NUMERIC, 0);
- if (false === $locale) {
- $this->markTestSkipped('Your platform does not support locales.');
- }
-
- $required_locales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252');
- if (false === setlocale(LC_ALL, $required_locales)) {
- $this->markTestSkipped('Could not set any of required locales: ' . implode(", ", $required_locales));
- }
-
- $this->assertEquals('1.2', $compiler->repr(1.2)->getSource());
- $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0)));
-
- setlocale(LC_ALL, $locale);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
-{
- /**
- * @expectedException LogicException
- * @expectedExceptionMessage You must set a loader first.
- */
- public function testRenderNoLoader()
- {
- $env = new Twig_Environment();
- $env->render('test');
- }
-
- public function testAutoescapeOption()
- {
- $loader = new Twig_Loader_Array(array(
- 'html' => '{{ foo }} {{ foo }}',
- 'js' => '{{ bar }} {{ bar }}',
- ));
-
- $twig = new Twig_Environment($loader, array(
- 'debug' => true,
- 'cache' => false,
- 'autoescape' => array($this, 'escapingStrategyCallback'),
- ));
-
- $this->assertEquals('foo<br/ > foo<br/ >', $twig->render('html', array('foo' => 'foo<br/ >')));
- $this->assertEquals('foo\x3Cbr\x2F\x20\x3E foo\x3Cbr\x2F\x20\x3E', $twig->render('js', array('bar' => 'foo<br/ >')));
- }
-
- public function escapingStrategyCallback($filename)
- {
- return $filename;
- }
-
- public function testGlobals()
- {
- // globals can be added after calling getGlobals
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addGlobal('foo', 'foo');
- $globals = $twig->getGlobals();
- $twig->addGlobal('foo', 'bar');
- $globals = $twig->getGlobals();
- $this->assertEquals('bar', $globals['foo']);
-
- // globals can be modified after runtime init
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addGlobal('foo', 'foo');
- $globals = $twig->getGlobals();
- $twig->initRuntime();
- $twig->addGlobal('foo', 'bar');
- $globals = $twig->getGlobals();
- $this->assertEquals('bar', $globals['foo']);
-
- // globals can be modified after extensions init
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addGlobal('foo', 'foo');
- $globals = $twig->getGlobals();
- $twig->getFunctions();
- $twig->addGlobal('foo', 'bar');
- $globals = $twig->getGlobals();
- $this->assertEquals('bar', $globals['foo']);
-
- // globals can be modified after extensions and runtime init
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addGlobal('foo', 'foo');
- $globals = $twig->getGlobals();
- $twig->getFunctions();
- $twig->initRuntime();
- $twig->addGlobal('foo', 'bar');
- $globals = $twig->getGlobals();
- $this->assertEquals('bar', $globals['foo']);
-
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->getGlobals();
- $twig->addGlobal('foo', 'bar');
- $template = $twig->loadTemplate('{{foo}}');
- $this->assertEquals('bar', $template->render(array()));
-
- /* to be uncomment in Twig 2.0
- // globals cannot be added after runtime init
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addGlobal('foo', 'foo');
- $globals = $twig->getGlobals();
- $twig->initRuntime();
- try {
- $twig->addGlobal('bar', 'bar');
- $this->fail();
- } catch (LogicException $e) {
- $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
- }
-
- // globals cannot be added after extensions init
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addGlobal('foo', 'foo');
- $globals = $twig->getGlobals();
- $twig->getFunctions();
- try {
- $twig->addGlobal('bar', 'bar');
- $this->fail();
- } catch (LogicException $e) {
- $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
- }
-
- // globals cannot be added after extensions and runtime init
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addGlobal('foo', 'foo');
- $globals = $twig->getGlobals();
- $twig->getFunctions();
- $twig->initRuntime();
- try {
- $twig->addGlobal('bar', 'bar');
- $this->fail();
- } catch (LogicException $e) {
- $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
- }
-
- // test adding globals after initRuntime without call to getGlobals
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->initRuntime();
- try {
- $twig->addGlobal('bar', 'bar');
- $this->fail();
- } catch (LogicException $e) {
- $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
- }
- */
- }
-
- public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate()
- {
- $options = array('cache' => sys_get_temp_dir().'/twig', 'auto_reload' => false, 'debug' => false);
-
- // force compilation
- $twig = new Twig_Environment(new Twig_Loader_String(), $options);
- $cache = $twig->getCacheFilename('{{ foo }}');
- if (!is_dir(dirname($cache))) {
- mkdir(dirname($cache), 0777, true);
- }
- file_put_contents($cache, $twig->compileSource('{{ foo }}', '{{ foo }}'));
-
- // check that extensions won't be initialized when rendering a template that is already in the cache
- $twig = $this
- ->getMockBuilder('Twig_Environment')
- ->setConstructorArgs(array(new Twig_Loader_String(), $options))
- ->setMethods(array('initExtensions'))
- ->getMock()
- ;
-
- $twig->expects($this->never())->method('initExtensions');
-
- // render template
- $output = $twig->render('{{ foo }}', array('foo' => 'bar'));
- $this->assertEquals('bar', $output);
-
- unlink($cache);
- }
-
- public function testAddExtension()
- {
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
-
- $this->assertArrayHasKey('test', $twig->getTags());
- $this->assertArrayHasKey('foo_filter', $twig->getFilters());
- $this->assertArrayHasKey('foo_function', $twig->getFunctions());
- $this->assertArrayHasKey('foo_test', $twig->getTests());
- $this->assertArrayHasKey('foo_unary', $twig->getUnaryOperators());
- $this->assertArrayHasKey('foo_binary', $twig->getBinaryOperators());
- $this->assertArrayHasKey('foo_global', $twig->getGlobals());
- $visitors = $twig->getNodeVisitors();
- $this->assertEquals('Twig_Tests_EnvironmentTest_NodeVisitor', get_class($visitors[2]));
- }
-
- public function testRemoveExtension()
- {
- $twig = new Twig_Environment(new Twig_Loader_String());
- $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
- $twig->removeExtension('environment_test');
-
- $this->assertFalse(array_key_exists('test', $twig->getTags()));
- $this->assertFalse(array_key_exists('foo_filter', $twig->getFilters()));
- $this->assertFalse(array_key_exists('foo_function', $twig->getFunctions()));
- $this->assertFalse(array_key_exists('foo_test', $twig->getTests()));
- $this->assertFalse(array_key_exists('foo_unary', $twig->getUnaryOperators()));
- $this->assertFalse(array_key_exists('foo_binary', $twig->getBinaryOperators()));
- $this->assertFalse(array_key_exists('foo_global', $twig->getGlobals()));
- $this->assertCount(2, $twig->getNodeVisitors());
- }
-}
-
-class Twig_Tests_EnvironmentTest_Extension extends Twig_Extension
-{
- public function getTokenParsers()
- {
- return array(
- new Twig_Tests_EnvironmentTest_TokenParser(),
- );
- }
-
- public function getNodeVisitors()
- {
- return array(
- new Twig_Tests_EnvironmentTest_NodeVisitor(),
- );
- }
-
- public function getFilters()
- {
- return array(
- 'foo_filter' => new Twig_Filter_Function('foo_filter'),
- );
- }
-
- public function getTests()
- {
- return array(
- 'foo_test' => new Twig_Test_Function('foo_test'),
- );
- }
-
- public function getFunctions()
- {
- return array(
- 'foo_function' => new Twig_Function_Function('foo_function'),
- );
- }
-
- public function getOperators()
- {
- return array(
- array('foo_unary' => array()),
- array('foo_binary' => array()),
- );
- }
-
- public function getGlobals()
- {
- return array(
- 'foo_global' => 'foo_global',
- );
- }
-
- public function getName()
- {
- return 'environment_test';
- }
-}
-
-class Twig_Tests_EnvironmentTest_TokenParser extends Twig_TokenParser
-{
- public function parse(Twig_Token $token)
- {
- }
-
- public function getTag()
- {
- return 'test';
- }
-}
-
-class Twig_Tests_EnvironmentTest_NodeVisitor implements Twig_NodeVisitorInterface
-{
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- return $node;
- }
-
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- return $node;
- }
-
- public function getPriority()
- {
- return 0;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_ErrorTest extends PHPUnit_Framework_TestCase
-{
- public function testErrorWithObjectFilename()
- {
- $error = new Twig_Error('foo');
- $error->setTemplateFile(new SplFileInfo(__FILE__));
-
- $this->assertContains('test'.DIRECTORY_SEPARATOR.'Twig'.DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR.'ErrorTest.php', $error->getMessage());
- }
-
- public function testErrorWithArrayFilename()
- {
- $error = new Twig_Error('foo');
- $error->setTemplateFile(array('foo' => 'bar'));
-
- $this->assertEquals('foo in {"foo":"bar"}', $error->getMessage());
- }
-
- public function testTwigExceptionAddsFileAndLineWhenMissing()
- {
- $loader = new Twig_Loader_Array(array('index' => "\n\n{{ foo.bar }}\n\n\n{{ 'foo' }}"));
- $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
-
- $template = $twig->loadTemplate('index');
-
- try {
- $template->render(array());
-
- $this->fail();
- } catch (Twig_Error_Runtime $e) {
- $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage());
- $this->assertEquals(3, $e->getTemplateLine());
- $this->assertEquals('index', $e->getTemplateFile());
- }
- }
-
- public function testRenderWrapsExceptions()
- {
- $loader = new Twig_Loader_Array(array('index' => "\n\n\n{{ foo.bar }}\n\n\n\n{{ 'foo' }}"));
- $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
-
- $template = $twig->loadTemplate('index');
-
- try {
- $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
-
- $this->fail();
- } catch (Twig_Error_Runtime $e) {
- $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 4.', $e->getMessage());
- $this->assertEquals(4, $e->getTemplateLine());
- $this->assertEquals('index', $e->getTemplateFile());
- }
- }
-
- public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritance()
- {
- $loader = new Twig_Loader_Array(array(
- 'index' => "{% extends 'base' %}
- {% block content %}
- {{ foo.bar }}
- {% endblock %}
- {% block foo %}
- {{ foo.bar }}
- {% endblock %}",
- 'base' => '{% block content %}{% endblock %}'
- ));
- $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
-
- $template = $twig->loadTemplate('index');
- try {
- $template->render(array());
-
- $this->fail();
- } catch (Twig_Error_Runtime $e) {
- $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage());
- $this->assertEquals(3, $e->getTemplateLine());
- $this->assertEquals('index', $e->getTemplateFile());
- }
-
- try {
- $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
-
- $this->fail();
- } catch (Twig_Error_Runtime $e) {
- $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 3.', $e->getMessage());
- $this->assertEquals(3, $e->getTemplateLine());
- $this->assertEquals('index', $e->getTemplateFile());
- }
- }
-
- public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceAgain()
- {
- $loader = new Twig_Loader_Array(array(
- 'index' => "{% extends 'base' %}
- {% block content %}
- {{ parent() }}
- {% endblock %}",
- 'base' => '{% block content %}{{ foo }}{% endblock %}'
- ));
- $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
-
- $template = $twig->loadTemplate('index');
- try {
- $template->render(array());
-
- $this->fail();
- } catch (Twig_Error_Runtime $e) {
- $this->assertEquals('Variable "foo" does not exist in "base" at line 1', $e->getMessage());
- $this->assertEquals(1, $e->getTemplateLine());
- $this->assertEquals('base', $e->getTemplateFile());
- }
- }
-
- public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceOnDisk()
- {
- $loader = new Twig_Loader_Filesystem(dirname(__FILE__).'/Fixtures/errors');
- $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
-
- $template = $twig->loadTemplate('index.html');
- try {
- $template->render(array());
-
- $this->fail();
- } catch (Twig_Error_Runtime $e) {
- $this->assertEquals('Variable "foo" does not exist in "index.html" at line 3', $e->getMessage());
- $this->assertEquals(3, $e->getTemplateLine());
- $this->assertEquals('index.html', $e->getTemplateFile());
- }
-
- try {
- $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
-
- $this->fail();
- } catch (Twig_Error_Runtime $e) {
- $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index.html" at line 3.', $e->getMessage());
- $this->assertEquals(3, $e->getTemplateLine());
- $this->assertEquals('index.html', $e->getTemplateFile());
- }
- }
-}
-
-class Twig_Tests_ErrorTest_Foo
-{
- public function bar()
- {
- throw new Exception('Runtime error...');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
-{
- /**
- * @expectedException Twig_Error_Syntax
- * @dataProvider getFailingTestsForAssignment
- */
- public function testCanOnlyAssignToNames($template)
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize($template, 'index'));
- }
-
- public function getFailingTestsForAssignment()
- {
- return array(
- array('{% set false = "foo" %}'),
- array('{% set true = "foo" %}'),
- array('{% set none = "foo" %}'),
- array('{% set 3 = "foo" %}'),
- array('{% set 1 + 2 = "foo" %}'),
- array('{% set "bar" = "foo" %}'),
- array('{% set %}{% endset %}')
- );
- }
-
- /**
- * @dataProvider getTestsForArray
- */
- public function testArrayExpression($template, $expected)
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $stream = $env->tokenize($template, 'index');
- $parser = new Twig_Parser($env);
-
- $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @dataProvider getFailingTestsForArray
- */
- public function testArraySyntaxError($template)
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize($template, 'index'));
- }
-
- public function getFailingTestsForArray()
- {
- return array(
- array('{{ [1, "a": "b"] }}'),
- array('{{ {"a": "b", 2} }}'),
- );
- }
-
- public function getTestsForArray()
- {
- return array(
- // simple array
- array('{{ [1, 2] }}', new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant(0, 1),
- new Twig_Node_Expression_Constant(1, 1),
-
- new Twig_Node_Expression_Constant(1, 1),
- new Twig_Node_Expression_Constant(2, 1),
- ), 1),
- ),
-
- // array with trailing ,
- array('{{ [1, 2, ] }}', new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant(0, 1),
- new Twig_Node_Expression_Constant(1, 1),
-
- new Twig_Node_Expression_Constant(1, 1),
- new Twig_Node_Expression_Constant(2, 1),
- ), 1),
- ),
-
- // simple hash
- array('{{ {"a": "b", "b": "c"} }}', new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant('a', 1),
- new Twig_Node_Expression_Constant('b', 1),
-
- new Twig_Node_Expression_Constant('b', 1),
- new Twig_Node_Expression_Constant('c', 1),
- ), 1),
- ),
-
- // hash with trailing ,
- array('{{ {"a": "b", "b": "c", } }}', new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant('a', 1),
- new Twig_Node_Expression_Constant('b', 1),
-
- new Twig_Node_Expression_Constant('b', 1),
- new Twig_Node_Expression_Constant('c', 1),
- ), 1),
- ),
-
- // hash in an array
- array('{{ [1, {"a": "b", "b": "c"}] }}', new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant(0, 1),
- new Twig_Node_Expression_Constant(1, 1),
-
- new Twig_Node_Expression_Constant(1, 1),
- new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant('a', 1),
- new Twig_Node_Expression_Constant('b', 1),
-
- new Twig_Node_Expression_Constant('b', 1),
- new Twig_Node_Expression_Constant('c', 1),
- ), 1),
- ), 1),
- ),
-
- // array in a hash
- array('{{ {"a": [1, 2], "b": "c"} }}', new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant('a', 1),
- new Twig_Node_Expression_Array(array(
- new Twig_Node_Expression_Constant(0, 1),
- new Twig_Node_Expression_Constant(1, 1),
-
- new Twig_Node_Expression_Constant(1, 1),
- new Twig_Node_Expression_Constant(2, 1),
- ), 1),
- new Twig_Node_Expression_Constant('b', 1),
- new Twig_Node_Expression_Constant('c', 1),
- ), 1),
- ),
- );
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- */
- public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
- $stream = $env->tokenize('{{ "a" "b" }}', 'index');
- $parser = new Twig_Parser($env);
-
- $parser->parse($stream);
- }
-
- /**
- * @dataProvider getTestsForString
- */
- public function testStringExpression($template, $expected)
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
- $stream = $env->tokenize($template, 'index');
- $parser = new Twig_Parser($env);
-
- $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
- }
-
- public function getTestsForString()
- {
- return array(
- array(
- '{{ "foo" }}', new Twig_Node_Expression_Constant('foo', 1),
- ),
- array(
- '{{ "foo #{bar}" }}', new Twig_Node_Expression_Binary_Concat(
- new Twig_Node_Expression_Constant('foo ', 1),
- new Twig_Node_Expression_Name('bar', 1),
- 1
- ),
- ),
- array(
- '{{ "foo #{bar} baz" }}', new Twig_Node_Expression_Binary_Concat(
- new Twig_Node_Expression_Binary_Concat(
- new Twig_Node_Expression_Constant('foo ', 1),
- new Twig_Node_Expression_Name('bar', 1),
- 1
- ),
- new Twig_Node_Expression_Constant(' baz', 1),
- 1
- )
- ),
-
- array(
- '{{ "foo #{"foo #{bar} baz"} baz" }}', new Twig_Node_Expression_Binary_Concat(
- new Twig_Node_Expression_Binary_Concat(
- new Twig_Node_Expression_Constant('foo ', 1),
- new Twig_Node_Expression_Binary_Concat(
- new Twig_Node_Expression_Binary_Concat(
- new Twig_Node_Expression_Constant('foo ', 1),
- new Twig_Node_Expression_Name('bar', 1),
- 1
- ),
- new Twig_Node_Expression_Constant(' baz', 1),
- 1
- ),
- 1
- ),
- new Twig_Node_Expression_Constant(' baz', 1),
- 1
- ),
- ),
- );
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- */
- public function testAttributeCallDoesNotSupportNamedArguments()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize('{{ foo.bar(name="Foo") }}', 'index'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- */
- public function testMacroCallDoesNotSupportNamedArguments()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage An argument must be a name. Unexpected token "string" of value "a" ("name" expected) in "index" at line 1
- */
- public function testMacroDefinitionDoesNotSupportNonNameVariableName()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize('{% macro foo("a") %}{% endmacro %}', 'index'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage A default value for an argument must be a constant (a boolean, a string, a number, or an array) in "index" at line 1
- * @dataProvider getMacroDefinitionDoesNotSupportNonConstantDefaultValues
- */
- public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template)
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize($template, 'index'));
- }
-
- public function getMacroDefinitionDoesNotSupportNonConstantDefaultValues()
- {
- return array(
- array('{% macro foo(name = "a #{foo} a") %}{% endmacro %}'),
- array('{% macro foo(name = [["b", "a #{foo} a"]]) %}{% endmacro %}'),
- );
- }
-
- /**
- * @dataProvider getMacroDefinitionSupportsConstantDefaultValues
- */
- public function testMacroDefinitionSupportsConstantDefaultValues($template)
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize($template, 'index'));
- }
-
- public function getMacroDefinitionSupportsConstantDefaultValues()
- {
- return array(
- array('{% macro foo(name = "aa") %}{% endmacro %}'),
- array('{% macro foo(name = 12) %}{% endmacro %}'),
- array('{% macro foo(name = true) %}{% endmacro %}'),
- array('{% macro foo(name = ["a"]) %}{% endmacro %}'),
- array('{% macro foo(name = [["a"]]) %}{% endmacro %}'),
- array('{% macro foo(name = {a: "a"}) %}{% endmacro %}'),
- array('{% macro foo(name = {a: {b: "a"}}) %}{% endmacro %}'),
- );
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage The function "cycl" does not exist. Did you mean "cycle" in "index" at line 1
- */
- public function testUnknownFunction()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize('{{ cycl() }}', 'index'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage The filter "lowe" does not exist. Did you mean "lower" in "index" at line 1
- */
- public function testUnknownFilter()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize('{{ 1|lowe }}', 'index'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage The test "nul" does not exist. Did you mean "null" in "index" at line 1
- */
- public function testUnknownTest()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $parser = new Twig_Parser($env);
-
- $parser->parse($env->tokenize('{{ 1 is nul }}', 'index'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Extension_CoreTest extends PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider getRandomFunctionTestData
- */
- public function testRandomFunction($value, $expectedInArray)
- {
- $env = new Twig_Environment();
-
- for ($i = 0; $i < 100; $i++) {
- $this->assertTrue(in_array(twig_random($env, $value), $expectedInArray, true)); // assertContains() would not consider the type
- }
- }
-
- public function getRandomFunctionTestData()
- {
- return array(
- array( // array
- array('apple', 'orange', 'citrus'),
- array('apple', 'orange', 'citrus'),
- ),
- array( // Traversable
- new ArrayObject(array('apple', 'orange', 'citrus')),
- array('apple', 'orange', 'citrus'),
- ),
- array( // unicode string
- 'Ä€é',
- array('Ä', '€', 'é'),
- ),
- array( // numeric but string
- '123',
- array('1', '2', '3'),
- ),
- array( // integer
- 5,
- range(0, 5, 1),
- ),
- array( // float
- 5.9,
- range(0, 5, 1),
- ),
- array( // negative
- -2,
- array(0, -1, -2),
- ),
- );
- }
-
- public function testRandomFunctionWithoutParameter()
- {
- $max = mt_getrandmax();
-
- for ($i = 0; $i < 100; $i++) {
- $val = twig_random(new Twig_Environment());
- $this->assertTrue(is_int($val) && $val >= 0 && $val <= $max);
- }
- }
-
- public function testRandomFunctionReturnsAsIs()
- {
- $this->assertSame('', twig_random(new Twig_Environment(), ''));
- $this->assertSame('', twig_random(new Twig_Environment(null, array('charset' => null)), ''));
-
- $instance = new stdClass();
- $this->assertSame($instance, twig_random(new Twig_Environment(), $instance));
- }
-
- /**
- * @expectedException Twig_Error_Runtime
- */
- public function testRandomFunctionOfEmptyArrayThrowsException()
- {
- twig_random(new Twig_Environment(), array());
- }
-
- public function testRandomFunctionOnNonUTF8String()
- {
- if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
- $this->markTestSkipped('needs iconv or mbstring');
- }
-
- $twig = new Twig_Environment();
- $twig->setCharset('ISO-8859-1');
-
- $text = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
- for ($i = 0; $i < 30; $i++) {
- $rand = twig_random($twig, $text);
- $this->assertTrue(in_array(twig_convert_encoding($rand, 'UTF-8', 'ISO-8859-1'), array('Ä', 'é'), true));
- }
- }
-
- public function testReverseFilterOnNonUTF8String()
- {
- if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
- $this->markTestSkipped('needs iconv or mbstring');
- }
-
- $twig = new Twig_Environment();
- $twig->setCharset('ISO-8859-1');
-
- $input = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
- $output = twig_convert_encoding(twig_reverse_filter($twig, $input), 'UTF-8', 'ISO-8859-1');
-
- $this->assertEquals($output, 'éÄ');
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase
-{
- protected static $params, $templates;
-
- public function setUp()
- {
- self::$params = array(
- 'name' => 'Fabien',
- 'obj' => new FooObject(),
- 'arr' => array('obj' => new FooObject()),
- );
-
- self::$templates = array(
- '1_basic1' => '{{ obj.foo }}',
- '1_basic2' => '{{ name|upper }}',
- '1_basic3' => '{% if name %}foo{% endif %}',
- '1_basic4' => '{{ obj.bar }}',
- '1_basic5' => '{{ obj }}',
- '1_basic6' => '{{ arr.obj }}',
- '1_basic7' => '{{ cycle(["foo","bar"], 1) }}',
- '1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}',
- '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
- '1_layout' => '{% block content %}{% endblock %}',
- '1_child' => '{% extends "1_layout" %}{% block content %}{{ "a"|json_encode }}{% endblock %}',
- );
- }
-
- /**
- * @expectedException Twig_Sandbox_SecurityError
- * @expectedExceptionMessage Filter "json_encode" is not allowed in "1_child".
- */
- public function testSandboxWithInheritance()
- {
- $twig = $this->getEnvironment(true, array(), self::$templates, array('block'));
- $twig->loadTemplate('1_child')->render(array());
- }
-
- public function testSandboxGloballySet()
- {
- $twig = $this->getEnvironment(false, array(), self::$templates);
- $this->assertEquals('FOO', $twig->loadTemplate('1_basic')->render(self::$params), 'Sandbox does nothing if it is disabled globally');
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('1_basic1')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception if an unallowed method is called');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('1_basic2')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception if an unallowed filter is called');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('1_basic3')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception if an unallowed tag is used in the template');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('1_basic4')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('1_basic5')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('1_basic6')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('1_basic7')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception if an unallowed function is called in the template');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
-
- $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo'));
- FooObject::reset();
- $this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
- $this->assertEquals(1, FooObject::$called['foo'], 'Sandbox only calls method once');
-
- $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__toString'));
- FooObject::reset();
- $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allow some methods');
- $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once');
-
- $twig = $this->getEnvironment(true, array(), self::$templates, array(), array('upper'));
- $this->assertEquals('FABIEN', $twig->loadTemplate('1_basic2')->render(self::$params), 'Sandbox allow some filters');
-
- $twig = $this->getEnvironment(true, array(), self::$templates, array('if'));
- $this->assertEquals('foo', $twig->loadTemplate('1_basic3')->render(self::$params), 'Sandbox allow some tags');
-
- $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array('FooObject' => 'bar'));
- $this->assertEquals('bar', $twig->loadTemplate('1_basic4')->render(self::$params), 'Sandbox allow some properties');
-
- $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('cycle'));
- $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions');
-
- foreach (array('getfoobar', 'getFoobar', 'getFooBar') as $name) {
- $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => $name));
- FooObject::reset();
- $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic8')->render(self::$params), 'Sandbox allow methods in a case-insensitive way');
- $this->assertEquals(2, FooObject::$called['getFooBar'], 'Sandbox only calls method once');
- }
- }
-
- public function testSandboxLocallySetForAnInclude()
- {
- self::$templates = array(
- '2_basic' => '{{ obj.foo }}{% include "2_included" %}{{ obj.foo }}',
- '2_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
- );
-
- $twig = $this->getEnvironment(false, array(), self::$templates);
- $this->assertEquals('fooFOOfoo', $twig->loadTemplate('2_basic')->render(self::$params), 'Sandbox does nothing if disabled globally and sandboxed not used for the include');
-
- self::$templates = array(
- '3_basic' => '{{ obj.foo }}{% sandbox %}{% include "3_included" %}{% endsandbox %}{{ obj.foo }}',
- '3_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
- );
-
- $twig = $this->getEnvironment(true, array(), self::$templates);
- try {
- $twig->loadTemplate('3_basic')->render(self::$params);
- $this->fail('Sandbox throws a SecurityError exception when the included file is sandboxed');
- } catch (Twig_Sandbox_SecurityError $e) {
- }
- }
-
- public function testMacrosInASandbox()
- {
- $twig = $this->getEnvironment(true, array('autoescape' => true), array('index' => <<<EOF
-{%- import _self as macros %}
-
-{%- macro test(text) %}<p>{{ text }}</p>{% endmacro %}
-
-{{- macros.test('username') }}
-EOF
- ), array('macro', 'import'), array('escape'));
-
- $this->assertEquals('<p>username</p>', $twig->loadTemplate('index')->render(array()));
- }
-
- protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array(), $functions = array())
- {
- $loader = new Twig_Loader_Array($templates);
- $twig = new Twig_Environment($loader, array_merge(array('debug' => true, 'cache' => false, 'autoescape' => false), $options));
- $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
- $twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed));
-
- return $twig;
- }
-}
-
-class FooObject
-{
- public static $called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
-
- public $bar = 'bar';
-
- public static function reset()
- {
- self::$called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
- }
-
- public function __toString()
- {
- ++self::$called['__toString'];
-
- return 'foo';
- }
-
- public function foo()
- {
- ++self::$called['foo'];
-
- return 'foo';
- }
-
- public function getFooBar()
- {
- ++self::$called['getFooBar'];
-
- return 'foobar';
- }
-}
+++ /dev/null
-<?php
-
-class Twig_Tests_FileCachingTest extends PHPUnit_Framework_TestCase
-{
- protected $fileName;
- protected $env;
- protected $tmpDir;
-
- public function setUp()
- {
- $this->tmpDir = sys_get_temp_dir().'/TwigTests';
- if (!file_exists($this->tmpDir)) {
- @mkdir($this->tmpDir, 0777, true);
- }
-
- if (!is_writable($this->tmpDir)) {
- $this->markTestSkipped(sprintf('Unable to run the tests as "%s" is not writable.', $this->tmpDir));
- }
-
- $this->env = new Twig_Environment(new Twig_Loader_String(), array('cache' => $this->tmpDir));
- }
-
- public function tearDown()
- {
- if ($this->fileName) {
- unlink($this->fileName);
- }
-
- $this->removeDir($this->tmpDir);
- }
-
- public function testWritingCacheFiles()
- {
- $name = 'This is just text.';
- $template = $this->env->loadTemplate($name);
- $cacheFileName = $this->env->getCacheFilename($name);
-
- $this->assertTrue(file_exists($cacheFileName), 'Cache file does not exist.');
- $this->fileName = $cacheFileName;
- }
-
- public function testClearingCacheFiles()
- {
- $name = 'I will be deleted.';
- $template = $this->env->loadTemplate($name);
- $cacheFileName = $this->env->getCacheFilename($name);
-
- $this->assertTrue(file_exists($cacheFileName), 'Cache file does not exist.');
- $this->env->clearCacheFiles();
- $this->assertFalse(file_exists($cacheFileName), 'Cache file was not cleared.');
- }
-
- private function removeDir($target)
- {
- $fp = opendir($target);
- while (false !== $file = readdir($fp)) {
- if (in_array($file, array('.', '..'))) {
- continue;
- }
-
- if (is_dir($target.'/'.$file)) {
- self::removeDir($target.'/'.$file);
- } else {
- unlink($target.'/'.$file);
- }
- }
- closedir($fp);
- rmdir($target);
- }
-}
+++ /dev/null
-{% block content %}{% endblock %}
+++ /dev/null
-{% extends 'base.html' %}
-{% block content %}
- {{ foo.bar }}
-{% endblock %}
-{% block foo %}
- {{ foo.bar }}
-{% endblock %}
+++ /dev/null
---TEST--
-Exception for an unclosed tag
---TEMPLATE--
-{% block foo %}
- {% if foo %}
-
-
-
-
- {% for i in fo %}
-
-
-
- {% endfor %}
-
-
-
-{% endblock %}
---EXCEPTION--
-Twig_Error_Syntax: Unexpected tag name "endblock" (expecting closing tag for the "if" tag defined near line 4) in "index.twig" at line 16
+++ /dev/null
---TEST--
-Twig supports array notation
---TEMPLATE--
-{# empty array #}
-{{ []|join(',') }}
-
-{{ [1, 2]|join(',') }}
-{{ ['foo', "bar"]|join(',') }}
-{{ {0: 1, 'foo': 'bar'}|join(',') }}
-{{ {0: 1, 'foo': 'bar'}|keys|join(',') }}
-
-{{ {0: 1, foo: 'bar'}|join(',') }}
-{{ {0: 1, foo: 'bar'}|keys|join(',') }}
-
-{# nested arrays #}
-{% set a = [1, 2, [1, 2], {'foo': {'foo': 'bar'}}] %}
-{{ a[2]|join(',') }}
-{{ a[3]["foo"]|join(',') }}
-
-{# works even if [] is used inside the array #}
-{{ [foo[bar]]|join(',') }}
-
-{# elements can be any expression #}
-{{ ['foo'|upper, bar|upper, bar == foo]|join(',') }}
-
-{# arrays can have a trailing , like in PHP #}
-{{
- [
- 1,
- 2,
- ]|join(',')
-}}
-
-{# keys can be any expression #}
-{% set a = 1 %}
-{% set b = "foo" %}
-{% set ary = { (a): 'a', (b): 'b', 'c': 'c', (a ~ b): 'd' } %}
-{{ ary|keys|join(',') }}
-{{ ary|join(',') }}
---DATA--
-return array('bar' => 'bar', 'foo' => array('bar' => 'bar'))
---EXPECT--
-1,2
-foo,bar
-1,bar
-0,foo
-
-1,bar
-0,foo
-
-1,2
-bar
-
-bar
-
-FOO,BAR,
-
-1,2
-
-1,foo,c,1foo
-a,b,c,d
+++ /dev/null
---TEST--
-Twig supports method calls
---TEMPLATE--
-{{ items.foo }}
-{{ items['foo'] }}
-{{ items[foo] }}
-{{ items[items[foo]] }}
---DATA--
-return array('foo' => 'bar', 'items' => array('foo' => 'bar', 'bar' => 'foo'))
---EXPECT--
-bar
-bar
-foo
-bar
+++ /dev/null
---TEST--
-Twig supports binary operations (+, -, *, /, ~, %, and, or)
---TEMPLATE--
-{{ 1 + 1 }}
-{{ 2 - 1 }}
-{{ 2 * 2 }}
-{{ 2 / 2 }}
-{{ 3 % 2 }}
-{{ 1 and 1 }}
-{{ 1 and 0 }}
-{{ 0 and 1 }}
-{{ 0 and 0 }}
-{{ 1 or 1 }}
-{{ 1 or 0 }}
-{{ 0 or 1 }}
-{{ 0 or 0 }}
-{{ 0 or 1 and 0 }}
-{{ 1 or 0 and 1 }}
-{{ "foo" ~ "bar" }}
-{{ foo ~ "bar" }}
-{{ "foo" ~ bar }}
-{{ foo ~ bar }}
-{{ 20 // 7 }}
---DATA--
-return array('foo' => 'bar', 'bar' => 'foo')
---EXPECT--
-2
-1
-4
-1
-1
-1
-
-
-
-1
-1
-1
-
-
-1
-foobar
-barbar
-foofoo
-barfoo
-2
+++ /dev/null
---TEST--
-Twig supports bitwise operations
---TEMPLATE--
-{{ 1 b-and 5 }}
-{{ 1 b-or 5 }}
-{{ 1 b-xor 5 }}
-{{ (1 and 0 b-or 0) is sameas(1 and (0 b-or 0)) ? 'ok' : 'ko' }}
---DATA--
-return array()
---EXPECT--
-1
-5
-4
-ok
+++ /dev/null
---TEST--
-Twig supports comparison operators (==, !=, <, >, >=, <=)
---TEMPLATE--
-{{ 1 > 2 }}/{{ 1 > 1 }}/{{ 1 >= 2 }}/{{ 1 >= 1 }}
-{{ 1 < 2 }}/{{ 1 < 1 }}/{{ 1 <= 2 }}/{{ 1 <= 1 }}
-{{ 1 == 1 }}/{{ 1 == 2 }}
-{{ 1 != 1 }}/{{ 1 != 2 }}
---DATA--
-return array()
---EXPECT--
-///1
-1//1/1
-1/
-/1
+++ /dev/null
---TEST--
-Twig supports the .. operator
---TEMPLATE--
-{% for i in 0..10 %}{{ i }} {% endfor %}
-
-{% for letter in 'a'..'z' %}{{ letter }} {% endfor %}
-
-{% for letter in 'a'|upper..'z'|upper %}{{ letter }} {% endfor %}
-
-{% for i in foo[0]..foo[1] %}{{ i }} {% endfor %}
-
-{% for i in 0 + 1 .. 10 - 1 %}{{ i }} {% endfor %}
---DATA--
-return array('foo' => array(1, 10))
---EXPECT--
-0 1 2 3 4 5 6 7 8 9 10
-a b c d e f g h i j k l m n o p q r s t u v w x y z
-A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
-1 2 3 4 5 6 7 8 9 10
-1 2 3 4 5 6 7 8 9
+++ /dev/null
---TEST--
-Twig supports grouping of expressions
---TEMPLATE--
-{{ (2 + 2) / 2 }}
---DATA--
-return array()
---EXPECT--
-2
+++ /dev/null
---TEST--
-Twig supports literals
---TEMPLATE--
-1 {{ true }}
-2 {{ TRUE }}
-3 {{ false }}
-4 {{ FALSE }}
-5 {{ none }}
-6 {{ NONE }}
-7 {{ null }}
-8 {{ NULL }}
---DATA--
-return array()
---EXPECT--
-1 1
-2 1
-3
-4
-5
-6
-7
-8
+++ /dev/null
---TEST--
-Twig supports __call() for attributes
---TEMPLATE--
-{{ foo.foo }}
-{{ foo.bar }}
---DATA--
-class TestClassForMagicCallAttributes
-{
- public function getBar()
- {
- return 'bar_from_getbar';
- }
-
- public function __call($method, $arguments)
- {
- if ('foo' === $method)
- {
- return 'foo_from_call';
- }
-
- return false;
- }
-}
-return array('foo' => new TestClassForMagicCallAttributes())
---EXPECT--
-foo_from_call
-bar_from_getbar
+++ /dev/null
---TEST--
-Twig supports method calls
---TEMPLATE--
-{{ items.foo.foo }}
-{{ items.foo.getFoo() }}
-{{ items.foo.bar }}
-{{ items.foo['bar'] }}
-{{ items.foo.bar('a', 43) }}
-{{ items.foo.bar(foo) }}
-{{ items.foo.self.foo() }}
-{{ items.foo.is }}
-{{ items.foo.in }}
-{{ items.foo.not }}
---DATA--
-return array('foo' => 'bar', 'items' => array('foo' => new TwigTestFoo(), 'bar' => 'foo'))
---CONFIG--
-return array('strict_variables' => false)
---EXPECT--
-foo
-foo
-bar
-
-bar_a-43
-bar_bar
-foo
-is
-in
-not
+++ /dev/null
---TEST--
-Twig parses postfix expressions
---TEMPLATE--
-{% import _self as macros %}
-
-{% macro foo() %}foo{% endmacro %}
-
-{{ 'a' }}
-{{ 'a'|upper }}
-{{ ('a')|upper }}
-{{ -1|upper }}
-{{ macros.foo() }}
-{{ (macros).foo() }}
---DATA--
-return array();
---EXPECT--
-a
-A
-A
--1
-foo
-foo
+++ /dev/null
---TEST--
-Twig supports string interpolation
---TEMPLATE--
-{{ "foo #{"foo #{bar} baz"} baz" }}
-{{ "foo #{bar}#{bar} baz" }}
---DATA--
-return array('bar' => 'BAR');
---EXPECT--
-foo foo BAR baz baz
-foo BARBAR baz
+++ /dev/null
---TEST--
-Twig supports the ternary operator
---TEMPLATE--
-{{ 1 ? 'YES' : 'NO' }}
-{{ 0 ? 'YES' : 'NO' }}
-{{ 0 ? 'YES' : (1 ? 'YES1' : 'NO1') }}
-{{ 0 ? 'YES' : (0 ? 'YES1' : 'NO1') }}
-{{ 1 == 1 ? 'foo<br />':'' }}
-{{ foo ~ (bar ? ('-' ~ bar) : '') }}
---DATA--
-return array('foo' => 'foo', 'bar' => 'bar')
---EXPECT--
-YES
-NO
-YES1
-NO1
-foo<br />
-foo-bar
+++ /dev/null
---TEST--
-Twig supports the ternary operator
---TEMPLATE--
-{{ 1 ? 'YES' }}
-{{ 0 ? 'YES' }}
---DATA--
-return array()
---EXPECT--
-YES
-
+++ /dev/null
---TEST--
-Twig supports the ternary operator
---TEMPLATE--
-{{ 'YES' ?: 'NO' }}
-{{ 0 ?: 'NO' }}
---DATA--
-return array()
---EXPECT--
-YES
-NO
+++ /dev/null
---TEST--
-Twig supports unary operators (not, -, +)
---TEMPLATE--
-{{ not 1 }}/{{ not 0 }}
-{{ +1 + 1 }}/{{ -1 - 1 }}
-{{ not (false or true) }}
---DATA--
-return array()
---EXPECT--
-/1
-2/-2
-
+++ /dev/null
---TEST--
-Twig unary operators precedence
---TEMPLATE--
-{{ -1 - 1 }}
-{{ -1 - -1 }}
-{{ -1 * -1 }}
-{{ 4 / -1 * 5 }}
---DATA--
-return array()
---EXPECT--
--2
-0
-1
--20
+++ /dev/null
---TEST--
-"abs" filter
---TEMPLATE--
-{{ (-5.5)|abs }}
-{{ (-5)|abs }}
-{{ (-0)|abs }}
-{{ 0|abs }}
-{{ 5|abs }}
-{{ 5.5|abs }}
-{{ number1|abs }}
-{{ number2|abs }}
-{{ number3|abs }}
-{{ number4|abs }}
-{{ number5|abs }}
-{{ number6|abs }}
---DATA--
-return array('number1' => -5.5, 'number2' => -5, 'number3' => -0, 'number4' => 0, 'number5' => 5, 'number6' => 5.5)
---EXPECT--
-5.5
-5
-0
-0
-5
-5.5
-5.5
-5
-0
-0
-5
-5.5
+++ /dev/null
---TEST--
-"batch" filter
---TEMPLATE--
-{% for row in items|batch(3) %}
- <div class=row>
- {% for column in row %}
- <div class=item>{{ column }}</div>
- {% endfor %}
- </div>
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
---EXPECT--
-<div class=row>
- <div class=item>a</div>
- <div class=item>b</div>
- <div class=item>c</div>
- </div>
- <div class=row>
- <div class=item>d</div>
- <div class=item>e</div>
- <div class=item>f</div>
- </div>
- <div class=row>
- <div class=item>g</div>
- <div class=item>h</div>
- <div class=item>i</div>
- </div>
- <div class=row>
- <div class=item>j</div>
- </div>
+++ /dev/null
---TEST--
-"batch" filter
---TEMPLATE--
-{% for row in items|batch(3.1) %}
- <div class=row>
- {% for column in row %}
- <div class=item>{{ column }}</div>
- {% endfor %}
- </div>
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
---EXPECT--
-<div class=row>
- <div class=item>a</div>
- <div class=item>b</div>
- <div class=item>c</div>
- </div>
- <div class=row>
- <div class=item>d</div>
- <div class=item>e</div>
- <div class=item>f</div>
- </div>
- <div class=row>
- <div class=item>g</div>
- <div class=item>h</div>
- <div class=item>i</div>
- </div>
- <div class=row>
- <div class=item>j</div>
- </div>
+++ /dev/null
---TEST--
-"batch" filter
---TEMPLATE--
-<table>
-{% for row in items|batch(3, '') %}
- <tr>
- {% for column in row %}
- <td>{{ column }}</td>
- {% endfor %}
- </tr>
-{% endfor %}
-</table>
---DATA--
-return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
---EXPECT--
-<table>
- <tr>
- <td>a</td>
- <td>b</td>
- <td>c</td>
- </tr>
- <tr>
- <td>d</td>
- <td>e</td>
- <td>f</td>
- </tr>
- <tr>
- <td>g</td>
- <td>h</td>
- <td>i</td>
- </tr>
- <tr>
- <td>j</td>
- <td></td>
- <td></td>
- </tr>
-</table>
+++ /dev/null
---TEST--
-"batch" filter
---TEMPLATE--
-<table>
-{% for row in items|batch(3, 'fill') %}
- <tr>
- {% for column in row %}
- <td>{{ column }}</td>
- {% endfor %}
- </tr>
-{% endfor %}
-</table>
---DATA--
-return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
---EXPECT--
-<table>
- <tr>
- <td>a</td>
- <td>b</td>
- <td>c</td>
- </tr>
- <tr>
- <td>d</td>
- <td>e</td>
- <td>f</td>
- </tr>
- <tr>
- <td>g</td>
- <td>h</td>
- <td>i</td>
- </tr>
- <tr>
- <td>j</td>
- <td>fill</td>
- <td>fill</td>
- </tr>
-</table>
+++ /dev/null
---TEST--
-"convert_encoding" filter
---CONDITION--
-function_exists('iconv') || function_exists('mb_convert_encoding')
---TEMPLATE--
-{{ "愛していますか?"|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }}
---DATA--
-return array()
---EXPECT--
-愛していますか?
+++ /dev/null
---TEST--
-"date" filter
---TEMPLATE--
-{{ date1|date }}
-{{ date1|date('d/m/Y') }}
-{{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
-{{ date1|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
-{{ date1|date('d/m/Y H:i:s P', 'America/Chicago') }}
-{{ date1|date('e') }}
-{{ date1|date('d/m/Y H:i:s') }}
-
-{{ date2|date }}
-{{ date2|date('d/m/Y') }}
-{{ date2|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
-{{ date2|date('d/m/Y H:i:s', timezone1) }}
-{{ date2|date('d/m/Y H:i:s') }}
-
-{{ date3|date }}
-{{ date3|date('d/m/Y') }}
-
-{{ date4|date }}
-{{ date4|date('d/m/Y') }}
-
-{{ date5|date }}
-{{ date5|date('d/m/Y') }}
-
-{{ date6|date('d/m/Y H:i:s P', 'Europe/Paris') }}
-{{ date6|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
-{{ date6|date('d/m/Y H:i:s P', false) }}
-{{ date6|date('e', 'Europe/Paris') }}
-{{ date6|date('e', false) }}
-
-{{ date7|date }}
---DATA--
-date_default_timezone_set('Europe/Paris');
-return array(
- 'date1' => mktime(13, 45, 0, 10, 4, 2010),
- 'date2' => new DateTime('2010-10-04 13:45'),
- 'date3' => '2010-10-04 13:45',
- 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT
- 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(),
- 'date6' => new DateTime('2010-10-04 13:45', new DateTimeZone('America/New_York')),
- 'date7' => '2010-01-28T15:00:00+05:00',
- 'timezone1' => new DateTimeZone('America/New_York'),
-)
---EXPECT--
-October 4, 2010 13:45
-04/10/2010
-04/10/2010 19:45:00
-04/10/2010 19:45:00 +08:00
-04/10/2010 06:45:00 -05:00
-Europe/Paris
-04/10/2010 13:45:00
-
-October 4, 2010 13:45
-04/10/2010
-04/10/2010 19:45:00
-04/10/2010 07:45:00
-04/10/2010 13:45:00
-
-October 4, 2010 13:45
-04/10/2010
-
-October 4, 2010 15:45
-04/10/2010
-
-January 2, 1964 04:04
-02/01/1964
-
-04/10/2010 19:45:00 +02:00
-05/10/2010 01:45:00 +08:00
-04/10/2010 13:45:00 -04:00
-Europe/Paris
-America/New_York
-
-January 28, 2010 11:00
+++ /dev/null
---TEST--
-"date" filter
---TEMPLATE--
-{{ date1|date }}
-{{ date1|date('d/m/Y') }}
---DATA--
-date_default_timezone_set('UTC');
-$twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours');
-return array(
- 'date1' => mktime(13, 45, 0, 10, 4, 2010),
-)
---EXPECT--
-2010-10-04
-04/10/2010
+++ /dev/null
---TEST--
-"date" filter (interval support as of PHP 5.3)
---CONDITION--
-version_compare(phpversion(), '5.3.0', '>=')
---TEMPLATE--
-{{ date2|date }}
-{{ date2|date('%d days') }}
---DATA--
-date_default_timezone_set('UTC');
-$twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours');
-return array(
- 'date2' => new DateInterval('P2D'),
-)
---EXPECT--
-2 days 0 hours
-2 days
+++ /dev/null
---TEST--
-"date" filter (interval support as of PHP 5.3)
---CONDITION--
-version_compare(phpversion(), '5.3.0', '>=')
---TEMPLATE--
-{{ date1|date }}
-{{ date1|date('%d days %h hours') }}
-{{ date1|date('%d days %h hours', timezone1) }}
---DATA--
-date_default_timezone_set('UTC');
-return array(
- 'date1' => new DateInterval('P2D'),
- // This should have no effect on DateInterval formatting
- 'timezone1' => new DateTimeZone('America/New_York'),
-)
---EXPECT--
-2 days
-2 days 0 hours
-2 days 0 hours
+++ /dev/null
---TEST--
-"date_modify" filter
---TEMPLATE--
-{{ date1|date_modify('-1day')|date('Y-m-d H:i:s') }}
-{{ date2|date_modify('-1day')|date('Y-m-d H:i:s') }}
---DATA--
-date_default_timezone_set('UTC');
-return array(
- 'date1' => '2010-10-04 13:45',
- 'date2' => new DateTime('2010-10-04 13:45'),
-)
---EXPECT--
-2010-10-03 13:45:00
-2010-10-03 13:45:00
+++ /dev/null
---TEST--
-"date" filter
---TEMPLATE--
-{{ date|date(format='d/m/Y H:i:s P', timezone='America/Chicago') }}
-{{ date|date(timezone='America/Chicago', format='d/m/Y H:i:s P') }}
-{{ date|date('d/m/Y H:i:s P', timezone='America/Chicago') }}
---DATA--
-date_default_timezone_set('UTC');
-return array('date' => mktime(13, 45, 0, 10, 4, 2010))
---EXPECT--
-04/10/2010 08:45:00 -05:00
-04/10/2010 08:45:00 -05:00
-04/10/2010 08:45:00 -05:00
+++ /dev/null
---TEST--
-"default" filter
---TEMPLATE--
-Variable:
-{{ definedVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ zeroVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ emptyVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ nullVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ undefinedVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
-Array access:
-{{ nested.definedVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ nested['definedVar'] |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ nested.zeroVar |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ nested.emptyVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ nested.nullVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ nested.undefinedVar |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ nested['undefinedVar'] |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ undefinedVar.foo |default('default') is sameas('default') ? 'ok' : 'ko' }}
-Plain values:
-{{ 'defined' |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ 0 |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ '' |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ null |default('default') is sameas('default') ? 'ok' : 'ko' }}
-Precedence:
-{{ 'o' ~ nullVar |default('k') }}
-{{ 'o' ~ nested.nullVar |default('k') }}
-Object methods:
-{{ object.foo |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ object.undefinedMethod |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ object.getFoo() |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ object.getFoo('a') |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ object.undefinedMethod() |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ object.undefinedMethod('a') |default('default') is sameas('default') ? 'ok' : 'ko' }}
-Deep nested:
-{{ nested.undefinedVar.foo.bar |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ nested.definedArray.0 |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ nested['definedArray'][0] |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ object.self.foo |default('default') is sameas('default') ? 'ko' : 'ok' }}
-{{ object.self.undefinedMethod |default('default') is sameas('default') ? 'ok' : 'ko' }}
-{{ object.undefinedMethod.self |default('default') is sameas('default') ? 'ok' : 'ko' }}
---DATA--
-return array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'emptyVar' => '',
- 'nullVar' => null,
- 'nested' => array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'emptyVar' => '',
- 'nullVar' => null,
- 'definedArray' => array(0),
- ),
- 'object' => new TwigTestFoo(),
-)
---CONFIG--
-return array('strict_variables' => false)
---EXPECT--
-Variable:
-ok
-ok
-ok
-ok
-ok
-Array access:
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-Plain values:
-ok
-ok
-ok
-ok
-Precedence:
-ok
-ok
-Object methods:
-ok
-ok
-ok
-ok
-ok
-ok
-Deep nested:
-ok
-ok
-ok
-ok
-ok
-ok
---DATA--
-return array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'emptyVar' => '',
- 'nullVar' => null,
- 'nested' => array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'emptyVar' => '',
- 'nullVar' => null,
- 'definedArray' => array(0),
- ),
- 'object' => new TwigTestFoo(),
-)
---CONFIG--
-return array('strict_variables' => true)
---EXPECT--
-Variable:
-ok
-ok
-ok
-ok
-ok
-Array access:
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-Plain values:
-ok
-ok
-ok
-ok
-Precedence:
-ok
-ok
-Object methods:
-ok
-ok
-ok
-ok
-ok
-ok
-Deep nested:
-ok
-ok
-ok
-ok
-ok
-ok
+++ /dev/null
---TEST--
-dynamic filter
---TEMPLATE--
-{{ 'bar'|foo_path }}
-{{ 'bar'|a_foo_b_bar }}
---DATA--
-return array()
---EXPECT--
-foo/bar
-a/b/bar
+++ /dev/null
---TEST--
-"escape" filter
---TEMPLATE--
-{{ "foo <br />"|e }}
---DATA--
-return array()
---EXPECT--
-foo <br />
+++ /dev/null
---TEST--
-"escape" filter
---TEMPLATE--
-{{ "愛していますか? <br />"|e }}
---DATA--
-return array()
---EXPECT--
-愛していますか? <br />
+++ /dev/null
---TEST--
-"first" filter
---TEMPLATE--
-{{ [1, 2, 3, 4]|first }}
-{{ {a: 1, b: 2, c: 3, d: 4}|first }}
-{{ '1234'|first }}
-{{ arr|first }}
---DATA--
-return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
---EXPECT--
-1
-1
-1
-1
+++ /dev/null
---TEST--
-"escape" filter
---TEMPLATE--
-{% set foo %}
- foo<br />
-{% endset %}
-
-{{ foo|e('html') -}}
-{{ foo|e('js') }}
-{% autoescape true %}
- {{ foo }}
-{% endautoescape %}
---DATA--
-return array()
---EXPECT--
- foo<br />
-\x20\x20\x20\x20foo\x3Cbr\x20\x2F\x3E\x0A
- foo<br />
+++ /dev/null
---TEST--
-"format" filter
---TEMPLATE--
-{{ string|format(foo, 3) }}
---DATA--
-return array('string' => '%s/%d', 'foo' => 'bar')
---EXPECT--
-bar/3
+++ /dev/null
---TEST--
-"join" filter
---TEMPLATE--
-{{ ["foo", "bar"]|join(', ') }}
-{{ foo|join(', ') }}
-{{ bar|join(', ') }}
---DATA--
-return array('foo' => new TwigTestFoo(), 'bar' => new ArrayObject(array(3, 4)))
---EXPECT--
-foo, bar
-1, 2
-3, 4
+++ /dev/null
---TEST--
-"json_encode" filter
---TEMPLATE--
-{{ "foo"|json_encode|raw }}
-{{ foo|json_encode|raw }}
-{{ [foo, "foo"]|json_encode|raw }}
---DATA--
-return array('foo' => new Twig_Markup('foo', 'UTF-8'))
---EXPECT--
-"foo"
-"foo"
-["foo","foo"]
+++ /dev/null
---TEST--
-"last" filter
---TEMPLATE--
-{{ [1, 2, 3, 4]|last }}
-{{ {a: 1, b: 2, c: 3, d: 4}|last }}
-{{ '1234'|last }}
-{{ arr|last }}
---DATA--
-return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
---EXPECT--
-4
-4
-4
-4
+++ /dev/null
---TEST--
-"length" filter
---TEMPLATE--
-{{ array|length }}
-{{ string|length }}
-{{ number|length }}
-{{ markup|length }}
---DATA--
-return array('array' => array(1, 4), 'string' => 'foo', 'number' => 1000, 'markup' => new Twig_Markup('foo', 'UTF-8'))
---EXPECT--
-2
-3
-4
-3
+++ /dev/null
---TEST--
-"length" filter
---CONDITION--
-function_exists('mb_get_info')
---TEMPLATE--
-{{ string|length }}
-{{ markup|length }}
---DATA--
-return array('string' => 'été', 'markup' => new Twig_Markup('foo', 'UTF-8'))
---EXPECT--
-3
-3
+++ /dev/null
---TEST--
-"merge" filter
---TEMPLATE--
-{{ items|merge({'bar': 'foo'})|join }}
-{{ items|merge({'bar': 'foo'})|keys|join }}
-{{ {'bar': 'foo'}|merge(items)|join }}
-{{ {'bar': 'foo'}|merge(items)|keys|join }}
-{{ numerics|merge([4, 5, 6])|join }}
---DATA--
-return array('items' => array('foo' => 'bar'), 'numerics' => array(1, 2, 3))
---EXPECT--
-barfoo
-foobar
-foobar
-barfoo
-123456
+++ /dev/null
---TEST--
-"nl2br" filter
---TEMPLATE--
-{{ "I like Twig.\nYou will like it too.\n\nEverybody like it!"|nl2br }}
-{{ text|nl2br }}
---DATA--
-return array('text' => "If you have some <strong>HTML</strong>\nit will be escaped.")
---EXPECT--
-I like Twig.<br />
-You will like it too.<br />
-<br />
-Everybody like it!
-If you have some <strong>HTML</strong><br />
-it will be escaped.
+++ /dev/null
---TEST--
-"number_format" filter
---TEMPLATE--
-{{ 20|number_format }}
-{{ 20.25|number_format }}
-{{ 20.25|number_format(2) }}
-{{ 20.25|number_format(2, ',') }}
-{{ 1020.25|number_format(2, ',') }}
-{{ 1020.25|number_format(2, ',', '.') }}
---DATA--
-return array();
---EXPECT--
-20
-20
-20.25
-20,25
-1,020,25
-1.020,25
+++ /dev/null
---TEST--
-"number_format" filter with defaults.
---TEMPLATE--
-{{ 20|number_format }}
-{{ 20.25|number_format }}
-{{ 20.25|number_format(1) }}
-{{ 20.25|number_format(2, ',') }}
-{{ 1020.25|number_format }}
-{{ 1020.25|number_format(2, ',') }}
-{{ 1020.25|number_format(2, ',', '.') }}
---DATA--
-$twig->getExtension('core')->setNumberFormat(2, '!', '=');
-return array();
---EXPECT--
-20!00
-20!25
-20!3
-20,25
-1=020!25
-1=020,25
-1.020,25
+++ /dev/null
---TEST--
-"replace" filter
---TEMPLATE--
-{{ "I like %this% and %that%."|replace({'%this%': "foo", '%that%': "bar"}) }}
---DATA--
-return array()
---EXPECT--
-I like foo and bar.
+++ /dev/null
---TEST--
-"reverse" filter
---TEMPLATE--
-{{ [1, 2, 3, 4]|reverse|join('') }}
-{{ '1234évènement'|reverse }}
-{{ arr|reverse|join('') }}
-{{ {'a': 'c', 'b': 'a'}|reverse()|join(',') }}
-{{ {'a': 'c', 'b': 'a'}|reverse(preserveKeys=true)|join(glue=',') }}
-{{ {'a': 'c', 'b': 'a'}|reverse(preserve_keys=true)|join(glue=',') }}
---DATA--
-return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
---EXPECT--
-4321
-tnemenèvé4321
-4321
-a,c
-a,c
-a,c
+++ /dev/null
---TEST--
-"slice" filter
---TEMPLATE--
-{{ [1, 2, 3, 4][1:2]|join('') }}
-{{ {a: 1, b: 2, c: 3, d: 4}[1:2]|join('') }}
-{{ [1, 2, 3, 4][start:length]|join('') }}
-{{ [1, 2, 3, 4]|slice(1, 2)|join('') }}
-{{ [1, 2, 3, 4]|slice(1, 2)|keys|join('') }}
-{{ [1, 2, 3, 4]|slice(1, 2, true)|keys|join('') }}
-{{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|join('') }}
-{{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|keys|join('') }}
-{{ '1234'|slice(1, 2) }}
-{{ '1234'[1:2] }}
-{{ arr|slice(1, 2)|join('') }}
-{{ arr[1:2]|join('') }}
-
-{{ [1, 2, 3, 4]|slice(1)|join('') }}
-{{ [1, 2, 3, 4][1:]|join('') }}
-{{ '1234'|slice(1) }}
-{{ '1234'[1:] }}
-{{ '1234'[:1] }}
---DATA--
-return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4)))
---EXPECT--
-23
-23
-23
-23
-01
-12
-23
-bc
-23
-23
-23
-23
-
-234
-234
-234
-234
-1
+++ /dev/null
---TEST--
-"sort" filter
---TEMPLATE--
-{{ array1|sort|join }}
-{{ array2|sort|join }}
---DATA--
-return array('array1' => array(4, 1), 'array2' => array('foo', 'bar'))
---EXPECT--
-14
-barfoo
+++ /dev/null
---TEST--
-"§" custom filter
---TEMPLATE--
-{{ 'foo'|§ }}
---DATA--
-return array()
---EXPECT--
-§foo§
+++ /dev/null
---TEST--
-"split" filter
---TEMPLATE--
-{{ "one,two,three,four,five"|split(',')|join('-') }}
-{{ foo|split(',')|join('-') }}
-{{ foo|split(',', 3)|join('-') }}
-{{ baz|split('')|join('-') }}
-{{ baz|split('', 2)|join('-') }}
-{{ foo|split(',', -2)|join('-') }}
---DATA--
-return array('foo' => "one,two,three,four,five", 'baz' => '12345',)
---EXPECT--
-one-two-three-four-five
-one-two-three-four-five
-one-two-three,four,five
-1-2-3-4-5
-12-34-5
-one-two-three
\ No newline at end of file
+++ /dev/null
---TEST--
-"trim" filter
---TEMPLATE--
-{{ " I like Twig. "|trim }}
-{{ text|trim }}
-{{ " foo/"|trim("/") }}
---DATA--
-return array('text' => " If you have some <strong>HTML</strong> it will be escaped. ")
---EXPECT--
-I like Twig.
-If you have some <strong>HTML</strong> it will be escaped.
- foo
+++ /dev/null
---TEST--
-"url_encode" filter
---TEMPLATE--
-{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode }}
-{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }}
-{{ {}|url_encode|default("default") }}
---DATA--
-return array()
---EXPECT--
-foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa+ce=
-foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa+ce=
-default
+++ /dev/null
---TEST--
-"attribute" function
---TEMPLATE--
-{{ attribute(obj, method) }}
-{{ attribute(array, item) }}
-{{ attribute(obj, "bar", ["a", "b"]) }}
---DATA--
-return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => array('foo' => 'bar'), 'item' => 'foo')
---EXPECT--
-foo
-bar
-bar_a-b
+++ /dev/null
---TEST--
-"block" function
---TEMPLATE--
-{% extends 'base.twig' %}
-{% block bar %}BAR{% endblock %}
---TEMPLATE(base.twig)--
-{% block foo %}{{ block('bar') }}{% endblock %}
-{% block bar %}BAR_BASE{% endblock %}
---DATA--
-return array()
---EXPECT--
-BARBAR
+++ /dev/null
---TEST--
-"constant" function
---TEMPLATE--
-{{ constant('DATE_W3C') == expect ? 'true' : 'false' }}
-{{ constant('ARRAY_AS_PROPS', object) }}
---DATA--
-return array('expect' => DATE_W3C, 'object' => new ArrayObject(array('hi')));
---EXPECT--
-true
-2
+++ /dev/null
---TEST--
-"cycle" function
---TEMPLATE--
-{% for i in 0..6 %}
-{{ cycle(array1, i) }}-{{ cycle(array2, i) }}
-{% endfor %}
---DATA--
-return array('array1' => array('odd', 'even'), 'array2' => array('apple', 'orange', 'citrus'))
---EXPECT--
-odd-apple
-even-orange
-odd-citrus
-even-apple
-odd-orange
-even-citrus
-odd-apple
+++ /dev/null
---TEST--
-"date" function
---TEMPLATE--
-{{ date() == date('now') ? 'OK' : 'KO' }}
-{{ date() > date('-1day') ? 'OK' : 'KO' }}
-{{ date(date1) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
-{{ date(date2) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
-{{ date(date3) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
-{{ date(date4) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
-{{ date(date5) == date('1964-01-02 03:04') ? 'OK' : 'KO' }}
---DATA--
-date_default_timezone_set('UTC');
-return array(
- 'date1' => mktime(13, 45, 0, 10, 4, 2010),
- 'date2' => new DateTime('2010-10-04 13:45'),
- 'date3' => '2010-10-04 13:45',
- 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT
- 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(),
-)
---EXPECT--
-OK
-OK
-OK
-OK
-OK
-OK
-OK
+++ /dev/null
---TEST--
-"date" function
---TEMPLATE--
-{{ date(date, "America/New_York")|date('d/m/Y H:i:s P', false) }}
-{{ date(timezone="America/New_York", date=date)|date('d/m/Y H:i:s P', false) }}
---DATA--
-date_default_timezone_set('UTC');
-return array('date' => mktime(13, 45, 0, 10, 4, 2010))
---EXPECT--
-04/10/2010 09:45:00 -04:00
-04/10/2010 09:45:00 -04:00
+++ /dev/null
---TEST--
-"dump" function
---CONDITION--
-!extension_loaded('xdebug')
---TEMPLATE--
-{{ dump('foo') }}
-{{ dump('foo', 'bar') }}
---DATA--
-return array('foo' => 'foo', 'bar' => 'bar')
---CONFIG--
-return array('debug' => true, 'autoescape' => false);
---EXPECT--
-string(3) "foo"
-
-string(3) "foo"
-string(3) "bar"
+++ /dev/null
---TEST--
-"dump" function, xdebug is not loaded or xdebug <2.2-dev is loaded
---CONDITION--
-!extension_loaded('xdebug') || (($r = new ReflectionExtension('xdebug')) && version_compare($r->getVersion(), '2.2-dev', '<'))
---TEMPLATE--
-{{ dump() }}
---DATA--
-return array('foo' => 'foo', 'bar' => 'bar')
---CONFIG--
-return array('debug' => true, 'autoescape' => false);
---EXPECT--
-array(3) {
- ["foo"]=>
- string(3) "foo"
- ["bar"]=>
- string(3) "bar"
- ["global"]=>
- string(6) "global"
-}
+++ /dev/null
---TEST--
-dynamic function
---TEMPLATE--
-{{ foo_path('bar') }}
-{{ a_foo_b_bar('bar') }}
---DATA--
-return array()
---EXPECT--
-foo/bar
-a/b/bar
+++ /dev/null
---TEST--
-"include" function
---TEMPLATE--
-{% set tmp = include("foo.twig") %}
-
-FOO{{ tmp }}BAR
---TEMPLATE(foo.twig)--
-FOOBAR
---DATA--
-return array()
---EXPECT--
-FOO
-FOOBARBAR
+++ /dev/null
---TEST--
-"include" function is safe for auto-escaping
---TEMPLATE--
-{{ include("foo.twig") }}
---TEMPLATE(foo.twig)--
-<p>Test</p>
---DATA--
-return array()
---EXPECT--
-<p>Test</p>
+++ /dev/null
---TEST--
-"include" function
---TEMPLATE--
-FOO
-{{ include("foo.twig") }}
-
-BAR
---TEMPLATE(foo.twig)--
-FOOBAR
---DATA--
-return array()
---EXPECT--
-FOO
-
-FOOBAR
-
-BAR
+++ /dev/null
---TEST--
-"include" function allows expressions for the template to include
---TEMPLATE--
-FOO
-{{ include(foo) }}
-
-BAR
---TEMPLATE(foo.twig)--
-FOOBAR
---DATA--
-return array('foo' => 'foo.twig')
---EXPECT--
-FOO
-
-FOOBAR
-
-BAR
+++ /dev/null
---TEST--
-"include" function
---TEMPLATE--
-{{ include(["foo.twig", "bar.twig"], ignore_missing = true) }}
-{{ include("foo.twig", ignore_missing = true) }}
-{{ include("foo.twig", ignore_missing = true, variables = {}) }}
-{{ include("foo.twig", ignore_missing = true, variables = {}, with_context = true) }}
---DATA--
-return array()
---EXPECT--
+++ /dev/null
---TEST--
-"include" function
---TEMPLATE--
-{{ include("foo.twig") }}
---DATA--
-return array();
---EXCEPTION--
-Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2.
+++ /dev/null
---TEST--
-"include" function
---TEMPLATE--
-{% extends "base.twig" %}
-
-{% block content %}
- {{ parent() }}
-{% endblock %}
---TEMPLATE(base.twig)--
-{% block content %}
- {{ include("foo.twig") }}
-{% endblock %}
---DATA--
-return array();
---EXCEPTION--
-Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3.
+++ /dev/null
---TEST--
-"include" tag sandboxed
---TEMPLATE--
-{{ include("foo.twig", sandboxed = true) }}
---TEMPLATE(foo.twig)--
-{{ foo|e }}
---DATA--
-return array()
---EXCEPTION--
-Twig_Sandbox_SecurityError: Filter "e" is not allowed in "index.twig" at line 2.
+++ /dev/null
---TEST--
-"include" function accepts Twig_Template instance
---TEMPLATE--
-{{ include(foo) }} FOO
---TEMPLATE(foo.twig)--
-BAR
---DATA--
-return array('foo' => $twig->loadTemplate('foo.twig'))
---EXPECT--
-BAR FOO
+++ /dev/null
---TEST--
-"include" function
---TEMPLATE--
-{{ include(["foo.twig", "bar.twig"]) }}
-{{- include(["bar.twig", "foo.twig"]) }}
---TEMPLATE(foo.twig)--
-foo
---DATA--
-return array()
---EXPECT--
-foo
-foo
+++ /dev/null
---TEST--
-"include" function accept variables and with_context
---TEMPLATE--
-{{ include("foo.twig") }}
-{{- include("foo.twig", with_context = false) }}
-{{- include("foo.twig", {'foo1': 'bar'}) }}
-{{- include("foo.twig", {'foo1': 'bar'}, with_context = false) }}
---TEMPLATE(foo.twig)--
-{% for k, v in _context %}{{ k }},{% endfor %}
---DATA--
-return array('foo' => 'bar')
---EXPECT--
-foo,global,_parent,
-global,_parent,
-foo,global,foo1,_parent,
-foo1,global,_parent,
+++ /dev/null
---TEST--
-"include" function accept variables
---TEMPLATE--
-{{ include("foo.twig", {'foo': 'bar'}) }}
-{{- include("foo.twig", vars) }}
---TEMPLATE(foo.twig)--
-{{ foo }}
---DATA--
-return array('vars' => array('foo' => 'bar'))
---EXPECT--
-bar
-bar
+++ /dev/null
---TEST--
-"range" function
---TEMPLATE--
-{{ range(low=0+1, high=10+0, step=2)|join(',') }}
---DATA--
-return array()
---EXPECT--
-1,3,5,7,9
+++ /dev/null
---TEST--
-"§" custom function
---TEMPLATE--
-{{ §('foo') }}
---DATA--
-return array()
---EXPECT--
-§foo§
+++ /dev/null
---TEST--
-"template_from_string" function
---TEMPLATE--
-{% include template_from_string(template) %}
-
-{% include template_from_string("Hello {{ name }}") %}
---DATA--
-return array('name' => 'Fabien', 'template' => "Hello {{ name }}")
---EXPECT--
-Hello Fabien
-Hello Fabien
+++ /dev/null
---TEST--
-macro
---TEMPLATE--
-{% from _self import test %}
-
-{% macro test(a, b = 'bar') -%}
-{{ a }}{{ b }}
-{%- endmacro %}
-
-{{ test('foo') }}
-{{ test('bar', 'foo') }}
---DATA--
-return array();
---EXPECT--
-foobar
-barfoo
+++ /dev/null
---TEST--
-macro
---TEMPLATE--
-{% import _self as macros %}
-
-{% macro foo(data) %}
- {{ data }}
-{% endmacro %}
-
-{% macro bar() %}
- <br />
-{% endmacro %}
-
-{{ macros.foo(macros.bar()) }}
---DATA--
-return array();
---EXPECT--
-<br />
+++ /dev/null
---TEST--
-macro
---TEMPLATE--
-{% from _self import test %}
-
-{% macro test(this) -%}
- {{ this }}
-{%- endmacro %}
-
-{{ test(this) }}
---DATA--
-return array('this' => 'foo');
---EXPECT--
-foo
+++ /dev/null
---TEST--
-macro
---TEMPLATE--
-{% import _self as test %}
-{% from _self import test %}
-
-{% macro test(a, b) -%}
- {{ a|default('a') }}<br />
- {{- b|default('b') }}<br />
-{%- endmacro %}
-
-{{ test.test() }}
-{{ test() }}
-{{ test.test(1, "c") }}
-{{ test(1, "c") }}
---DATA--
-return array();
---EXPECT--
-a<br />b<br />
-a<br />b<br />
-1<br />c<br />
-1<br />c<br />
+++ /dev/null
---TEST--
-macro with a filter
---TEMPLATE--
-{% import _self as test %}
-
-{% macro test() %}
- {% filter escape %}foo<br />{% endfilter %}
-{% endmacro %}
-
-{{ test.test() }}
---DATA--
-return array();
---EXPECT--
-foo<br />
+++ /dev/null
---TEST--
-Twig outputs 0 nodes correctly
---TEMPLATE--
-{{ foo }}0{{ foo }}
---DATA--
-return array('foo' => 'foo')
---EXPECT--
-foo0foo
+++ /dev/null
---TEST--
-Twig is able to deal with SimpleXMLElement instances as variables
---CONDITION--
-version_compare(phpversion(), '5.3.0', '>=')
---TEMPLATE--
-Hello '{{ images.image.0.group }}'!
-{{ images.children().count() }}
-{% for image in images %}
- - {{ image.group }}
-{% endfor %}
---DATA--
-return array('images' => new SimpleXMLElement('<images><image><group>foo</group></image><image><group>bar</group></image></images>'))
---EXPECT--
-Hello 'foo'!
-2
- - foo
- - bar
+++ /dev/null
---TEST--
-Twig does not confuse strings with integers in getAttribute()
---TEMPLATE--
-{{ hash['2e2'] }}
---DATA--
-return array('hash' => array('2e2' => 'works'))
---EXPECT--
-works
+++ /dev/null
---TEST--
-"autoescape" tag applies escaping on its children
---TEMPLATE--
-{% autoescape %}
-{{ var }}<br />
-{% endautoescape %}
-{% autoescape 'html' %}
-{{ var }}<br />
-{% endautoescape %}
-{% autoescape false %}
-{{ var }}<br />
-{% endautoescape %}
-{% autoescape true %}
-{{ var }}<br />
-{% endautoescape %}
-{% autoescape false %}
-{{ var }}<br />
-{% endautoescape %}
---DATA--
-return array('var' => '<br />')
---EXPECT--
-<br /><br />
-<br /><br />
-<br /><br />
-<br /><br />
-<br /><br />
+++ /dev/null
---TEST--
-"autoescape" tag applies escaping on embedded blocks
---TEMPLATE--
-{% autoescape 'html' %}
- {% block foo %}
- {{ var }}
- {% endblock %}
-{% endautoescape %}
---DATA--
-return array('var' => '<br />')
---EXPECT--
-<br />
+++ /dev/null
---TEST--
-"autoescape" tag does not double-escape
---TEMPLATE--
-{% autoescape 'html' %}
-{{ var|escape }}
-{% endautoescape %}
---DATA--
-return array('var' => '<br />')
---EXPECT--
-<br />
+++ /dev/null
---TEST--
-"autoescape" tag applies escaping after calling functions
---TEMPLATE--
-
-autoescape false
-{% autoescape false %}
-
-safe_br
-{{ safe_br() }}
-
-unsafe_br
-{{ unsafe_br() }}
-
-{% endautoescape %}
-
-autoescape 'html'
-{% autoescape 'html' %}
-
-safe_br
-{{ safe_br() }}
-
-unsafe_br
-{{ unsafe_br() }}
-
-unsafe_br()|raw
-{{ (unsafe_br())|raw }}
-
-safe_br()|escape
-{{ (safe_br())|escape }}
-
-safe_br()|raw
-{{ (safe_br())|raw }}
-
-unsafe_br()|escape
-{{ (unsafe_br())|escape }}
-
-{% endautoescape %}
-
-autoescape js
-{% autoescape 'js' %}
-
-safe_br
-{{ safe_br() }}
-
-{% endautoescape %}
---DATA--
-return array()
---EXPECT--
-
-autoescape false
-
-safe_br
-<br />
-
-unsafe_br
-<br />
-
-
-autoescape 'html'
-
-safe_br
-<br />
-
-unsafe_br
-<br />
-
-unsafe_br()|raw
-<br />
-
-safe_br()|escape
-<br />
-
-safe_br()|raw
-<br />
-
-unsafe_br()|escape
-<br />
-
-
-autoescape js
-
-safe_br
-\x3Cbr\x20\x2F\x3E
+++ /dev/null
---TEST--
-"autoescape" tag does not apply escaping on literals
---TEMPLATE--
-{% autoescape 'html' %}
-
-1. Simple literal
-{{ "<br />" }}
-
-2. Conditional expression with only literals
-{{ true ? "<br />" : "<br>" }}
-
-3. Conditional expression with a variable
-{{ true ? "<br />" : someVar }}
-
-4. Nested conditionals with only literals
-{{ true ? (true ? "<br />" : "<br>") : "\n" }}
-
-5. Nested conditionals with a variable
-{{ true ? (true ? "<br />" : someVar) : "\n" }}
-
-6. Nested conditionals with a variable marked safe
-{{ true ? (true ? "<br />" : someVar|raw) : "\n" }}
-
-{% endautoescape %}
---DATA--
-return array()
---EXPECT--
-
-1. Simple literal
-<br />
-
-2. Conditional expression with only literals
-<br />
-
-3. Conditional expression with a variable
-<br />
-
-4. Nested conditionals with only literals
-<br />
-
-5. Nested conditionals with a variable
-<br />
-
-6. Nested conditionals with a variable marked safe
-<br />
+++ /dev/null
---TEST--
-"autoescape" tags can be nested at will
---TEMPLATE--
-{{ var }}
-{% autoescape 'html' %}
- {{ var }}
- {% autoescape false %}
- {{ var }}
- {% autoescape 'html' %}
- {{ var }}
- {% endautoescape %}
- {{ var }}
- {% endautoescape %}
- {{ var }}
-{% endautoescape %}
-{{ var }}
---DATA--
-return array('var' => '<br />')
---EXPECT--
-<br />
- <br />
- <br />
- <br />
- <br />
- <br />
-<br />
+++ /dev/null
---TEST--
-"autoescape" tag applies escaping to object method calls
---TEMPLATE--
-{% autoescape 'html' %}
-{{ user.name }}
-{{ user.name|lower }}
-{{ user }}
-{% endautoescape %}
---DATA--
-class UserForAutoEscapeTest
-{
- public function getName()
- {
- return 'Fabien<br />';
- }
-
- public function __toString()
- {
- return 'Fabien<br />';
- }
-}
-return array('user' => new UserForAutoEscapeTest())
---EXPECT--
-Fabien<br />
-fabien<br />
-Fabien<br />
+++ /dev/null
---TEST--
-"autoescape" tag does not escape when raw is used as a filter
---TEMPLATE--
-{% autoescape 'html' %}
-{{ var|raw }}
-{% endautoescape %}
---DATA--
-return array('var' => '<br />')
---EXPECT--
-<br />
+++ /dev/null
---TEST--
-"autoescape" tag accepts an escaping strategy
---TEMPLATE--
-{% autoescape true js %}{{ var }}{% endautoescape %}
-
-{% autoescape true html %}{{ var }}{% endautoescape %}
-
-{% autoescape 'js' %}{{ var }}{% endautoescape %}
-
-{% autoescape 'html' %}{{ var }}{% endautoescape %}
---DATA--
-return array('var' => '<br />"')
---EXPECT--
-\x3Cbr\x20\x2F\x3E\x22
-<br />"
-\x3Cbr\x20\x2F\x3E\x22
-<br />"
+++ /dev/null
---TEST--
-escape types
---TEMPLATE--
-
-1. autoescape 'html' |escape('js')
-
-{% autoescape 'html' %}
-<a onclick="alert("{{ msg|escape('js') }}")"></a>
-{% endautoescape %}
-
-2. autoescape 'html' |escape('js')
-
-{% autoescape 'html' %}
-<a onclick="alert("{{ msg|escape('js') }}")"></a>
-{% endautoescape %}
-
-3. autoescape 'js' |escape('js')
-
-{% autoescape 'js' %}
-<a onclick="alert("{{ msg|escape('js') }}")"></a>
-{% endautoescape %}
-
-4. no escape
-
-{% autoescape false %}
-<a onclick="alert("{{ msg }}")"></a>
-{% endautoescape %}
-
-5. |escape('js')|escape('html')
-
-{% autoescape false %}
-<a onclick="alert("{{ msg|escape('js')|escape('html') }}")"></a>
-{% endautoescape %}
-
-6. autoescape 'html' |escape('js')|escape('html')
-
-{% autoescape 'html' %}
-<a onclick="alert("{{ msg|escape('js')|escape('html') }}")"></a>
-{% endautoescape %}
-
---DATA--
-return array('msg' => "<>\n'\"")
---EXPECT--
-
-1. autoescape 'html' |escape('js')
-
-<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a>
-
-2. autoescape 'html' |escape('js')
-
-<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a>
-
-3. autoescape 'js' |escape('js')
-
-<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a>
-
-4. no escape
-
-<a onclick="alert("<>
-'"")"></a>
-
-5. |escape('js')|escape('html')
-
-<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a>
-
-6. autoescape 'html' |escape('js')|escape('html')
-
-<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a>
-
+++ /dev/null
---TEST--
-"autoescape" tag applies escaping after calling filters
---TEMPLATE--
-{% autoescape 'html' %}
-
-(escape_and_nl2br is an escaper filter)
-
-1. Don't escape escaper filter output
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is not escaped )
-{{ var|escape_and_nl2br }}
-
-2. Don't escape escaper filter output
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is not escaped, |raw is redundant )
-{{ var|escape_and_nl2br|raw }}
-
-3. Explicit escape
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is explicitly escaped by |escape )
-{{ var|escape_and_nl2br|escape }}
-
-4. Escape non-escaper filter output
-( var is upper-cased by |upper,
- the output is auto-escaped )
-{{ var|upper }}
-
-5. Escape if last filter is not an escaper
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is upper-cased by |upper,
- the output is auto-escaped as |upper is not an escaper )
-{{ var|escape_and_nl2br|upper }}
-
-6. Don't escape escaper filter output
-( var is upper cased by upper,
- the output is escaped by |escape_and_nl2br, line-breaks are added,
- the output is not escaped as |escape_and_nl2br is an escaper )
-{{ var|upper|escape_and_nl2br }}
-
-7. Escape if last filter is not an escaper
-( the output of |format is "<b>" ~ var ~ "</b>",
- the output is auto-escaped )
-{{ "<b>%s</b>"|format(var) }}
-
-8. Escape if last filter is not an escaper
-( the output of |format is "<b>" ~ var ~ "</b>",
- |raw is redundant,
- the output is auto-escaped )
-{{ "<b>%s</b>"|raw|format(var) }}
-
-9. Don't escape escaper filter output
-( the output of |format is "<b>" ~ var ~ "</b>",
- the output is not escaped due to |raw filter at the end )
-{{ "<b>%s</b>"|format(var)|raw }}
-
-10. Don't escape escaper filter output
-( the output of |format is "<b>" ~ var ~ "</b>",
- the output is not escaped due to |raw filter at the end,
- the |raw filter on var is redundant )
-{{ "<b>%s</b>"|format(var|raw)|raw }}
-
-{% endautoescape %}
---DATA--
-return array('var' => "<Fabien>\nTwig")
---EXPECT--
-
-(escape_and_nl2br is an escaper filter)
-
-1. Don't escape escaper filter output
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is not escaped )
-<Fabien><br />
-Twig
-
-2. Don't escape escaper filter output
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is not escaped, |raw is redundant )
-<Fabien><br />
-Twig
-
-3. Explicit escape
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is explicitly escaped by |escape )
-&lt;Fabien&gt;<br />
-Twig
-
-4. Escape non-escaper filter output
-( var is upper-cased by |upper,
- the output is auto-escaped )
-<FABIEN>
-TWIG
-
-5. Escape if last filter is not an escaper
-( var is escaped by |escape_and_nl2br, line-breaks are added,
- the output is upper-cased by |upper,
- the output is auto-escaped as |upper is not an escaper )
-&LT;FABIEN&GT;<BR />
-TWIG
-
-6. Don't escape escaper filter output
-( var is upper cased by upper,
- the output is escaped by |escape_and_nl2br, line-breaks are added,
- the output is not escaped as |escape_and_nl2br is an escaper )
-<FABIEN><br />
-TWIG
-
-7. Escape if last filter is not an escaper
-( the output of |format is "<b>" ~ var ~ "</b>",
- the output is auto-escaped )
-<b><Fabien>
-Twig</b>
-
-8. Escape if last filter is not an escaper
-( the output of |format is "<b>" ~ var ~ "</b>",
- |raw is redundant,
- the output is auto-escaped )
-<b><Fabien>
-Twig</b>
-
-9. Don't escape escaper filter output
-( the output of |format is "<b>" ~ var ~ "</b>",
- the output is not escaped due to |raw filter at the end )
-<b><Fabien>
-Twig</b>
-
-10. Don't escape escaper filter output
-( the output of |format is "<b>" ~ var ~ "</b>",
- the output is not escaped due to |raw filter at the end,
- the |raw filter on var is redundant )
-<b><Fabien>
-Twig</b>
+++ /dev/null
---TEST--
-"autoescape" tag do not applies escaping on filter arguments
---TEMPLATE--
-{% autoescape 'html' %}
-{{ var|nl2br("<br />") }}
-{{ var|nl2br("<br />"|escape) }}
-{{ var|nl2br(sep) }}
-{{ var|nl2br(sep|raw) }}
-{{ var|nl2br(sep|escape) }}
-{% endautoescape %}
---DATA--
-return array('var' => "<Fabien>\nTwig", 'sep' => '<br />')
---EXPECT--
-<Fabien><br />
-Twig
-<Fabien><br />
-Twig
-<Fabien><br />
-Twig
-<Fabien><br />
-Twig
-<Fabien><br />
-Twig
+++ /dev/null
---TEST--
-"autoescape" tag applies escaping after calling filters, and before calling pre_escape filters
---TEMPLATE--
-{% autoescape 'html' %}
-
-(nl2br is pre_escaped for "html" and declared safe for "html")
-
-1. Pre-escape and don't post-escape
-( var|escape|nl2br )
-{{ var|nl2br }}
-
-2. Don't double-pre-escape
-( var|escape|nl2br )
-{{ var|escape|nl2br }}
-
-3. Don't escape safe values
-( var|raw|nl2br )
-{{ var|raw|nl2br }}
-
-4. Don't escape safe values
-( var|escape|nl2br|nl2br )
-{{ var|nl2br|nl2br }}
-
-5. Re-escape values that are escaped for an other contexts
-( var|escape_something|escape|nl2br )
-{{ var|escape_something|nl2br }}
-
-6. Still escape when using filters not declared safe
-( var|escape|nl2br|upper|escape )
-{{ var|nl2br|upper }}
-
-{% endautoescape %}
---DATA--
-return array('var' => "<Fabien>\nTwig")
---EXPECT--
-
-(nl2br is pre_escaped for "html" and declared safe for "html")
-
-1. Pre-escape and don't post-escape
-( var|escape|nl2br )
-<Fabien><br />
-Twig
-
-2. Don't double-pre-escape
-( var|escape|nl2br )
-<Fabien><br />
-Twig
-
-3. Don't escape safe values
-( var|raw|nl2br )
-<Fabien><br />
-Twig
-
-4. Don't escape safe values
-( var|escape|nl2br|nl2br )
-<Fabien><br /><br />
-Twig
-
-5. Re-escape values that are escaped for an other contexts
-( var|escape_something|escape|nl2br )
-<FABIEN><br />
-TWIG
-
-6. Still escape when using filters not declared safe
-( var|escape|nl2br|upper|escape )
-&LT;FABIEN&GT;<BR />
-TWIG
-
+++ /dev/null
---TEST--
-"autoescape" tag handles filters preserving the safety
---TEMPLATE--
-{% autoescape 'html' %}
-
-(preserves_safety is preserving safety for "html")
-
-1. Unsafe values are still unsafe
-( var|preserves_safety|escape )
-{{ var|preserves_safety }}
-
-2. Safe values are still safe
-( var|escape|preserves_safety )
-{{ var|escape|preserves_safety }}
-
-3. Re-escape values that are escaped for an other contexts
-( var|escape_something|preserves_safety|escape )
-{{ var|escape_something|preserves_safety }}
-
-4. Still escape when using filters not declared safe
-( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape )
-{{ var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'}) }}
-
-{% endautoescape %}
---DATA--
-return array('var' => "<Fabien>\nTwig")
---EXPECT--
-
-(preserves_safety is preserving safety for "html")
-
-1. Unsafe values are still unsafe
-( var|preserves_safety|escape )
-<FABIEN>
-TWIG
-
-2. Safe values are still safe
-( var|escape|preserves_safety )
-<FABIEN>
-TWIG
-
-3. Re-escape values that are escaped for an other contexts
-( var|escape_something|preserves_safety|escape )
-<FABIEN>
-TWIG
-
-4. Still escape when using filters not declared safe
-( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape )
-&LT;FABPOT&GT;
-TWIG
-
+++ /dev/null
---TEST--
-"block" tag
---TEMPLATE--
-{% block title1 %}FOO{% endblock %}
-{% block title2 foo|lower %}
---TEMPLATE(foo.twig)--
-{% block content %}{% endblock %}
---DATA--
-return array('foo' => 'bar')
---EXPECT--
-FOObar
+++ /dev/null
---TEST--
-"block" tag
---TEMPLATE--
-{% block content %}
- {% block content %}
- {% endblock %}
-{% endblock %}
---DATA--
-return array()
---EXCEPTION--
-Twig_Error_Syntax: The block 'content' has already been defined line 2 in "index.twig" at line 3
+++ /dev/null
---TEST--
-"§" special chars in a block name
---TEMPLATE--
-{% block § %}
-§
-{% endblock § %}
---DATA--
-return array()
---EXPECT--
-§
+++ /dev/null
---TEST--
-"embed" tag
---TEMPLATE--
-FOO
-{% embed "foo.twig" %}
- {% block c1 %}
- {{ parent() }}
- block1extended
- {% endblock %}
-{% endembed %}
-
-BAR
---TEMPLATE(foo.twig)--
-A
-{% block c1 %}
- block1
-{% endblock %}
-B
-{% block c2 %}
- block2
-{% endblock %}
-C
---DATA--
-return array()
---EXPECT--
-FOO
-
-A
- block1
-
- block1extended
- B
- block2
-C
-BAR
+++ /dev/null
---TEST--
-"embed" tag
---TEMPLATE(index.twig)--
-FOO
-{% embed "foo.twig" %}
- {% block c1 %}
- {{ nothing }}
- {% endblock %}
-{% endembed %}
-BAR
---TEMPLATE(foo.twig)--
-{% block c1 %}{% endblock %}
---DATA--
-return array()
---EXCEPTION--
-Twig_Error_Runtime: Variable "nothing" does not exist in "index.twig" at line 5
+++ /dev/null
---TEST--
-"embed" tag
---TEMPLATE--
-FOO
-{% embed "foo.twig" %}
- {% block c1 %}
- {{ parent() }}
- block1extended
- {% endblock %}
-{% endembed %}
-
-{% embed "foo.twig" %}
- {% block c1 %}
- {{ parent() }}
- block1extended
- {% endblock %}
-{% endembed %}
-
-BAR
---TEMPLATE(foo.twig)--
-A
-{% block c1 %}
- block1
-{% endblock %}
-B
-{% block c2 %}
- block2
-{% endblock %}
-C
---DATA--
-return array()
---EXPECT--
-FOO
-
-A
- block1
-
- block1extended
- B
- block2
-C
-
-A
- block1
-
- block1extended
- B
- block2
-C
-BAR
+++ /dev/null
---TEST--
-"embed" tag
---TEMPLATE--
-{% embed "foo.twig" %}
- {% block c1 %}
- {{ parent() }}
- {% embed "foo.twig" %}
- {% block c1 %}
- {{ parent() }}
- block1extended
- {% endblock %}
- {% endembed %}
-
- {% endblock %}
-{% endembed %}
---TEMPLATE(foo.twig)--
-A
-{% block c1 %}
- block1
-{% endblock %}
-B
-{% block c2 %}
- block2
-{% endblock %}
-C
---DATA--
-return array()
---EXPECT--
-A
- block1
-
-
-A
- block1
-
- block1extended
- B
- block2
-C
- B
- block2
-C
+++ /dev/null
---TEST--
-"embed" tag
---TEMPLATE--
-{% extends "base.twig" %}
-
-{% block c1 %}
- {{ parent() }}
- blockc1baseextended
-{% endblock %}
-
-{% block c2 %}
- {{ parent() }}
-
- {% embed "foo.twig" %}
- {% block c1 %}
- {{ parent() }}
- block1extended
- {% endblock %}
- {% endembed %}
-{% endblock %}
---TEMPLATE(base.twig)--
-A
-{% block c1 %}
- blockc1base
-{% endblock %}
-{% block c2 %}
- blockc2base
-{% endblock %}
-B
---TEMPLATE(foo.twig)--
-A
-{% block c1 %}
- block1
-{% endblock %}
-B
-{% block c2 %}
- block2
-{% endblock %}
-C
---DATA--
-return array()
---EXPECT--
-A
- blockc1base
-
- blockc1baseextended
- blockc2base
-
-
-
-A
- block1
-
- block1extended
- B
- block2
-CB
\ No newline at end of file
+++ /dev/null
---TEST--
-"filter" tag applies a filter on its children
---TEMPLATE--
-{% filter upper %}
-Some text with a {{ var }}
-{% endfilter %}
---DATA--
-return array('var' => 'var')
---EXPECT--
-SOME TEXT WITH A VAR
+++ /dev/null
---TEST--
-"filter" tag applies a filter on its children
---TEMPLATE--
-{% filter json_encode|raw %}test{% endfilter %}
---DATA--
-return array()
---EXPECT--
-"test"
+++ /dev/null
---TEST--
-"filter" tags accept multiple chained filters
---TEMPLATE--
-{% filter lower|title %}
- {{ var }}
-{% endfilter %}
---DATA--
-return array('var' => 'VAR')
---EXPECT--
- Var
+++ /dev/null
---TEST--
-"filter" tags can be nested at will
---TEMPLATE--
-{% filter lower|title %}
- {{ var }}
- {% filter upper %}
- {{ var }}
- {% endfilter %}
- {{ var }}
-{% endfilter %}
---DATA--
-return array('var' => 'var')
---EXPECT--
- Var
- Var
- Var
+++ /dev/null
---TEST--
-"filter" tag applies the filter on "for" tags
---TEMPLATE--
-{% filter upper %}
-{% for item in items %}
-{{ item }}
-{% endfor %}
-{% endfilter %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
-A
-B
+++ /dev/null
---TEST--
-"filter" tag applies the filter on "if" tags
---TEMPLATE--
-{% filter upper %}
-{% if items %}
-{{ items|join(', ') }}
-{% endif %}
-
-{% if items.3 is defined %}
-FOO
-{% else %}
-{{ items.1 }}
-{% endif %}
-
-{% if items.3 is defined %}
-FOO
-{% elseif items.1 %}
-{{ items.0 }}
-{% endif %}
-
-{% endfilter %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
-A, B
-
-B
-
-A
+++ /dev/null
---TEST--
-"for" tag takes a condition
---TEMPLATE--
-{% for i in 1..5 if i is odd -%}
- {{ loop.index }}.{{ i }}{{ foo.bar }}
-{% endfor %}
---DATA--
-return array('foo' => array('bar' => 'X'))
---CONFIG--
-return array('strict_variables' => false)
---EXPECT--
-1.1X
-2.3X
-3.5X
+++ /dev/null
---TEST--
-"for" tag keeps the context safe
---TEMPLATE--
-{% for item in items %}
- {% for item in items %}
- * {{ item }}
- {% endfor %}
- * {{ item }}
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
- * a
- * b
- * a
- * a
- * b
- * b
+++ /dev/null
---TEST--
-"for" tag can use an "else" clause
---TEMPLATE--
-{% for item in items %}
- * {{ item }}
-{% else %}
- no item
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
- * a
- * b
---DATA--
-return array('items' => array())
---EXPECT--
- no item
---DATA--
-return array()
---CONFIG--
-return array('strict_variables' => false)
---EXPECT--
- no item
+++ /dev/null
---TEST--
-"for" tag does not reset inner variables
---TEMPLATE--
-{% for i in 1..2 %}
- {% for j in 0..2 %}
- {{k}}{% set k = k+1 %} {{ loop.parent.loop.index }}
- {% endfor %}
-{% endfor %}
---DATA--
-return array('k' => 0)
---EXPECT--
- 0 1
- 1 1
- 2 1
- 3 2
- 4 2
- 5 2
+++ /dev/null
---TEST--
-"for" tag can iterate over keys
---TEMPLATE--
-{% for key in items|keys %}
- * {{ key }}
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
- * 0
- * 1
+++ /dev/null
---TEST--
-"for" tag can iterate over keys and values
---TEMPLATE--
-{% for key, item in items %}
- * {{ key }}/{{ item }}
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
- * 0/a
- * 1/b
+++ /dev/null
---TEST--
-"for" tag adds a loop variable to the context
---TEMPLATE--
-{% for item in items %}
- * {{ loop.index }}/{{ loop.index0 }}
- * {{ loop.revindex }}/{{ loop.revindex0 }}
- * {{ loop.first }}/{{ loop.last }}/{{ loop.length }}
-
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
- * 1/0
- * 2/1
- * 1//2
-
- * 2/1
- * 1/0
- * /1/2
+++ /dev/null
---TEST--
-"for" tag adds a loop variable to the context locally
---TEMPLATE--
-{% for item in items %}
-{% endfor %}
-{% if loop is not defined %}WORKS{% endif %}
---DATA--
-return array('items' => array())
---EXPECT--
-WORKS
+++ /dev/null
---TEST--
-"for" tag
---TEMPLATE--
-{% for i, item in items if i > 0 %}
- {{ loop.last }}
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXCEPTION--
-Twig_Error_Syntax: The "loop.last" variable is not defined when looping with a condition in "index.twig" at line 3
+++ /dev/null
---TEST--
-"for" tag
---TEMPLATE--
-{% for i, item in items if loop.last > 0 %}
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXCEPTION--
-Twig_Error_Syntax: The "loop" variable cannot be used in a looping condition in "index.twig" at line 2
+++ /dev/null
---TEST--
-"for" tag can use an "else" clause
---TEMPLATE--
-{% for item in items %}
- {% for item in items1 %}
- * {{ item }}
- {% else %}
- no {{ item }}
- {% endfor %}
-{% else %}
- no item1
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'), 'items1' => array())
---EXPECT--
-no a
- no b
+++ /dev/null
---TEST--
-"for" tag iterates over iterable objects
---TEMPLATE--
-{% for item in items %}
- * {{ item }}
- * {{ loop.index }}/{{ loop.index0 }}
- * {{ loop.first }}
-
-{% endfor %}
-
-{% for key, value in items %}
- * {{ key }}/{{ value }}
-{% endfor %}
-
-{% for key in items|keys %}
- * {{ key }}
-{% endfor %}
---DATA--
-class ItemsIterator implements Iterator
-{
- protected $values = array('foo' => 'bar', 'bar' => 'foo');
- public function current() { return current($this->values); }
- public function key() { return key($this->values); }
- public function next() { return next($this->values); }
- public function rewind() { return reset($this->values); }
- public function valid() { return false !== current($this->values); }
-}
-return array('items' => new ItemsIterator())
---EXPECT--
- * bar
- * 1/0
- * 1
-
- * foo
- * 2/1
- *
-
-
- * foo/bar
- * bar/foo
-
- * foo
- * bar
+++ /dev/null
---TEST--
-"for" tag iterates over iterable and countable objects
---TEMPLATE--
-{% for item in items %}
- * {{ item }}
- * {{ loop.index }}/{{ loop.index0 }}
- * {{ loop.revindex }}/{{ loop.revindex0 }}
- * {{ loop.first }}/{{ loop.last }}/{{ loop.length }}
-
-{% endfor %}
-
-{% for key, value in items %}
- * {{ key }}/{{ value }}
-{% endfor %}
-
-{% for key in items|keys %}
- * {{ key }}
-{% endfor %}
---DATA--
-class ItemsIteratorCountable implements Iterator, Countable
-{
- protected $values = array('foo' => 'bar', 'bar' => 'foo');
- public function current() { return current($this->values); }
- public function key() { return key($this->values); }
- public function next() { return next($this->values); }
- public function rewind() { return reset($this->values); }
- public function valid() { return false !== current($this->values); }
- public function count() { return count($this->values); }
-}
-return array('items' => new ItemsIteratorCountable())
---EXPECT--
- * bar
- * 1/0
- * 2/1
- * 1//2
-
- * foo
- * 2/1
- * 1/0
- * /1/2
-
-
- * foo/bar
- * bar/foo
-
- * foo
- * bar
+++ /dev/null
---TEST--
-"for" tags can be nested
---TEMPLATE--
-{% for key, item in items %}
-* {{ key }} ({{ loop.length }}):
-{% for value in item %}
- * {{ value }} ({{ loop.length }})
-{% endfor %}
-{% endfor %}
---DATA--
-return array('items' => array('a' => array('a1', 'a2', 'a3'), 'b' => array('b1')))
---EXPECT--
-* a (2):
- * a1 (3)
- * a2 (3)
- * a3 (3)
-* b (2):
- * b1 (1)
+++ /dev/null
---TEST--
-"for" tag iterates over item values
---TEMPLATE--
-{% for item in items %}
- * {{ item }}
-{% endfor %}
---DATA--
-return array('items' => array('a', 'b'))
---EXPECT--
- * a
- * b
+++ /dev/null
---TEST--
-global variables
---TEMPLATE--
-{% include "included.twig" %}
-{% from "included.twig" import foobar %}
-{{ foobar() }}
---TEMPLATE(included.twig)--
-{% macro foobar() %}
-called foobar
-{% endmacro %}
---DATA--
-return array();
---EXPECT--
-called foobar
+++ /dev/null
---TEST--
-"if" creates a condition
---TEMPLATE--
-{% if a is defined %}
- {{ a }}
-{% elseif b is defined %}
- {{ b }}
-{% else %}
- NOTHING
-{% endif %}
---DATA--
-return array('a' => 'a')
---EXPECT--
- a
---DATA--
-return array('b' => 'b')
---EXPECT--
- b
---DATA--
-return array()
---EXPECT--
- NOTHING
+++ /dev/null
---TEST--
-"if" takes an expression as a test
---TEMPLATE--
-{% if a < 2 %}
- A1
-{% elseif a > 10 %}
- A2
-{% else %}
- A3
-{% endif %}
---DATA--
-return array('a' => 1)
---EXPECT--
- A1
---DATA--
-return array('a' => 12)
---EXPECT--
- A2
---DATA--
-return array('a' => 7)
---EXPECT--
- A3
+++ /dev/null
---TEST--
-"include" tag
---TEMPLATE--
-FOO
-{% include "foo.twig" %}
-
-BAR
---TEMPLATE(foo.twig)--
-FOOBAR
---DATA--
-return array()
---EXPECT--
-FOO
-
-FOOBAR
-BAR
+++ /dev/null
---TEST--
-"include" tag allows expressions for the template to include
---TEMPLATE--
-FOO
-{% include foo %}
-
-BAR
---TEMPLATE(foo.twig)--
-FOOBAR
---DATA--
-return array('foo' => 'foo.twig')
---EXPECT--
-FOO
-
-FOOBAR
-BAR
+++ /dev/null
---TEST--
-"include" tag
---TEMPLATE--
-{% include ["foo.twig", "bar.twig"] ignore missing %}
-{% include "foo.twig" ignore missing %}
-{% include "foo.twig" ignore missing with {} %}
-{% include "foo.twig" ignore missing with {} only %}
---DATA--
-return array()
---EXPECT--
+++ /dev/null
---TEST--
-"include" tag
---TEMPLATE--
-{% include "foo.twig" %}
---DATA--
-return array();
---EXCEPTION--
-Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2.
+++ /dev/null
---TEST--
-"include" tag
---TEMPLATE--
-{% extends "base.twig" %}
-
-{% block content %}
- {{ parent() }}
-{% endblock %}
---TEMPLATE(base.twig)--
-{% block content %}
- {% include "foo.twig" %}
-{% endblock %}
---DATA--
-return array();
---EXCEPTION--
-Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3.
+++ /dev/null
---TEST--
-"include" tag accept variables and only
---TEMPLATE--
-{% include "foo.twig" %}
-{% include "foo.twig" only %}
-{% include "foo.twig" with {'foo1': 'bar'} %}
-{% include "foo.twig" with {'foo1': 'bar'} only %}
---TEMPLATE(foo.twig)--
-{% for k, v in _context %}{{ k }},{% endfor %}
---DATA--
-return array('foo' => 'bar')
---EXPECT--
-foo,global,_parent,
-global,_parent,
-foo,global,foo1,_parent,
-foo1,global,_parent,
+++ /dev/null
---TEST--
-"include" tag accepts Twig_Template instance
---TEMPLATE--
-{% include foo %} FOO
---TEMPLATE(foo.twig)--
-BAR
---DATA--
-return array('foo' => $twig->loadTemplate('foo.twig'))
---EXPECT--
-BAR FOO
+++ /dev/null
---TEST--
-"include" tag
---TEMPLATE--
-{% include ["foo.twig", "bar.twig"] %}
-{% include ["bar.twig", "foo.twig"] %}
---TEMPLATE(foo.twig)--
-foo
---DATA--
-return array()
---EXPECT--
-foo
-foo
+++ /dev/null
---TEST--
-"include" tag accept variables
---TEMPLATE--
-{% include "foo.twig" with {'foo': 'bar'} %}
-{% include "foo.twig" with vars %}
---TEMPLATE(foo.twig)--
-{{ foo }}
---DATA--
-return array('vars' => array('foo' => 'bar'))
---EXPECT--
-bar
-bar
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends "foo.twig" %}
-
-{% block content %}
-FOO
-{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}{% endblock %}
---DATA--
-return array()
---EXPECT--
-FOO
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends standalone ? foo : 'bar.twig' %}
-
-{% block content %}{{ parent() }}FOO{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}FOO{% endblock %}
---TEMPLATE(bar.twig)--
-{% block content %}BAR{% endblock %}
---DATA--
-return array('foo' => 'foo.twig', 'standalone' => true)
---EXPECT--
-FOOFOO
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends foo %}
-
-{% block content %}
-FOO
-{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}{% endblock %}
---DATA--
-return array('foo' => 'foo.twig')
---EXPECT--
-FOO
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends "foo.twig" %}
---TEMPLATE(foo.twig)--
-{% block content %}FOO{% endblock %}
---DATA--
-return array()
---EXPECT--
-FOO
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends ["foo.twig", "bar.twig"] %}
---TEMPLATE(bar.twig)--
-{% block content %}
-foo
-{% endblock %}
---DATA--
-return array()
---EXPECT--
-foo
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends "layout.twig" %}{% block content %}{{ parent() }}index {% endblock %}
---TEMPLATE(layout.twig)--
-{% extends "base.twig" %}{% block content %}{{ parent() }}layout {% endblock %}
---TEMPLATE(base.twig)--
-{% block content %}base {% endblock %}
---DATA--
-return array()
---EXPECT--
-base layout index
+++ /dev/null
---TEST--
-"block" tag
---TEMPLATE--
-{% extends "foo.twig" %}
-
-{% block content %}
- {% block subcontent %}
- {% block subsubcontent %}
- SUBSUBCONTENT
- {% endblock %}
- {% endblock %}
-{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}
- {% block subcontent %}
- SUBCONTENT
- {% endblock %}
-{% endblock %}
---DATA--
-return array()
---EXPECT--
-SUBSUBCONTENT
+++ /dev/null
---TEST--
-"block" tag
---TEMPLATE--
-{% block content %}
- CONTENT
- {%- block subcontent -%}
- SUBCONTENT
- {%- endblock -%}
- ENDCONTENT
-{% endblock %}
---TEMPLATE(foo.twig)--
---DATA--
-return array()
---EXPECT--
-CONTENTSUBCONTENTENDCONTENT
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends "layout.twig" %}
-{% block inside %}INSIDE{% endblock inside %}
---TEMPLATE(layout.twig)--
-{% extends "base.twig" %}
-{% block body %}
- {% block inside '' %}
-{% endblock body %}
---TEMPLATE(base.twig)--
-{% block body '' %}
---DATA--
-return array()
---EXPECT--
-INSIDE
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends "foo.twig" %}
-
-{% block content %}{{ parent() }}FOO{{ parent() }}{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}BAR{% endblock %}
---DATA--
-return array()
---EXPECT--
-BARFOOBAR
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends foo ? 'foo.twig' : 'bar.twig' %}
---TEMPLATE(foo.twig)--
-FOO
---TEMPLATE(bar.twig)--
-BAR
---DATA--
-return array('foo' => true)
---EXPECT--
-FOO
---DATA--
-return array('foo' => false)
---EXPECT--
-BAR
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% block content %}
- {% extends "foo.twig" %}
-{% endblock %}
---EXCEPTION--
-Twig_Error_Syntax: Cannot extend from a block in "index.twig" at line 3
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends "base.twig" %}
-{% block content %}{% include "included.twig" %}{% endblock %}
-
-{% block footer %}Footer{% endblock %}
---TEMPLATE(included.twig)--
-{% extends "base.twig" %}
-{% block content %}Included Content{% endblock %}
---TEMPLATE(base.twig)--
-{% block content %}Default Content{% endblock %}
-
-{% block footer %}Default Footer{% endblock %}
---DATA--
-return array()
---EXPECT--
-Included Content
-Default Footer
-Footer
+++ /dev/null
---TEST--
-"extends" tag
---TEMPLATE--
-{% extends "foo.twig" %}
-
-{% block content %}
- {% block inside %}
- INSIDE OVERRIDDEN
- {% endblock %}
-
- BEFORE
- {{ parent() }}
- AFTER
-{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}
- BAR
-{% endblock %}
---DATA--
-return array()
---EXPECT--
-
-INSIDE OVERRIDDEN
-
- BEFORE
- BAR
-
- AFTER
+++ /dev/null
---TEST--
-"parent" tag
---TEMPLATE--
-{% block content %}
- {{ parent() }}
-{% endblock %}
---EXCEPTION--
-Twig_Error_Syntax: Calling "parent" on a template that does not extend nor "use" another template is forbidden in "index.twig" at line 3
+++ /dev/null
---TEST--
-"parent" tag
---TEMPLATE--
-{% use 'foo.twig' %}
-
-{% block content %}
- {{ parent() }}
-{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}BAR{% endblock %}
---DATA--
-return array()
---EXPECT--
-BAR
+++ /dev/null
---TEST--
-"extends" tag accepts Twig_Template instance
---TEMPLATE--
-{% extends foo %}
-
-{% block content %}
-{{ parent() }}FOO
-{% endblock %}
---TEMPLATE(foo.twig)--
-{% block content %}BAR{% endblock %}
---DATA--
-return array('foo' => $twig->loadTemplate('foo.twig'))
---EXPECT--
-BARFOO
+++ /dev/null
---TEST--
-"parent" function
---TEMPLATE--
-{% extends "parent.twig" %}
-
-{% use "use1.twig" %}
-{% use "use2.twig" %}
-
-{% block content_parent %}
- {{ parent() }}
-{% endblock %}
-
-{% block content_use1 %}
- {{ parent() }}
-{% endblock %}
-
-{% block content_use2 %}
- {{ parent() }}
-{% endblock %}
-
-{% block content %}
- {{ block('content_use1_only') }}
- {{ block('content_use2_only') }}
-{% endblock %}
---TEMPLATE(parent.twig)--
-{% block content_parent 'content_parent' %}
-{% block content_use1 'content_parent' %}
-{% block content_use2 'content_parent' %}
-{% block content '' %}
---TEMPLATE(use1.twig)--
-{% block content_use1 'content_use1' %}
-{% block content_use2 'content_use1' %}
-{% block content_use1_only 'content_use1_only' %}
---TEMPLATE(use2.twig)--
-{% block content_use2 'content_use2' %}
-{% block content_use2_only 'content_use2_only' %}
---DATA--
-return array()
---EXPECT--
- content_parent
- content_use1
- content_use2
- content_use1_only
- content_use2_only
+++ /dev/null
---TEST--
-"macro" tag
---TEMPLATE--
-{% import _self as macros %}
-
-{{ macros.input('username') }}
-{{ macros.input('password', null, 'password', 1) }}
-
-{% macro input(name, value, type, size) %}
- <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
-{% endmacro %}
---DATA--
-return array()
---EXPECT--
- <input type="text" name="username" value="" size="20">
-
- <input type="password" name="password" value="" size="1">
+++ /dev/null
---TEST--
-"macro" tag supports name for endmacro
---TEMPLATE--
-{% import _self as macros %}
-
-{{ macros.foo() }}
-{{ macros.bar() }}
-
-{% macro foo() %}foo{% endmacro %}
-{% macro bar() %}bar{% endmacro bar %}
---DATA--
-return array()
---EXPECT--
-foo
-bar
-
+++ /dev/null
---TEST--
-"macro" tag
---TEMPLATE--
-{% import 'forms.twig' as forms %}
-
-{{ forms.input('username') }}
-{{ forms.input('password', null, 'password', 1) }}
---TEMPLATE(forms.twig)--
-{% macro input(name, value, type, size) %}
- <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
-{% endmacro %}
---DATA--
-return array()
---EXPECT--
- <input type="text" name="username" value="" size="20">
-
- <input type="password" name="password" value="" size="1">
+++ /dev/null
---TEST--
-"macro" tag
---TEMPLATE--
-{% from 'forms.twig' import foo %}
-{% from 'forms.twig' import foo as foobar, bar %}
-
-{{ foo('foo') }}
-{{ foobar('foo') }}
-{{ bar('foo') }}
---TEMPLATE(forms.twig)--
-{% macro foo(name) %}foo{{ name }}{% endmacro %}
-{% macro bar(name) %}bar{{ name }}{% endmacro %}
---DATA--
-return array()
---EXPECT--
-foofoo
-foofoo
-barfoo
+++ /dev/null
---TEST--
-"macro" tag
---TEMPLATE--
-{% from 'forms.twig' import foo %}
-
-{{ foo('foo') }}
-{{ foo() }}
---TEMPLATE(forms.twig)--
-{% macro foo(name) %}{{ name|default('foo') }}{{ global }}{% endmacro %}
---DATA--
-return array()
---EXPECT--
-fooglobal
-fooglobal
+++ /dev/null
---TEST--
-"macro" tag
---TEMPLATE--
-{% import _self as forms %}
-
-{{ forms.input('username') }}
-{{ forms.input('password', null, 'password', 1) }}
-
-{% macro input(name, value, type, size) %}
- <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
-{% endmacro %}
---DATA--
-return array()
---EXPECT--
- <input type="text" name="username" value="" size="20">
-
- <input type="password" name="password" value="" size="1">
+++ /dev/null
---TEST--
-"§" as a macro name
---TEMPLATE--
-{% import _self as macros %}
-
-{{ macros.§('foo') }}
-
-{% macro §(foo) %}
- §{{ foo }}§
-{% endmacro %}
---DATA--
-return array()
---EXPECT--
-§foo§
+++ /dev/null
---TEST--
-"raw" tag
---TEMPLATE--
-{% raw %}
-{{ foo }}
-{% endraw %}
---DATA--
-return array()
---EXPECT--
-{{ foo }}
+++ /dev/null
---TEST--
-"raw" tag
---TEMPLATE--
-{% raw %}
-{{ foo }}
-{% endverbatim %}
---DATA--
-return array()
---EXCEPTION--
-Twig_Error_Syntax: Unexpected end of file: Unclosed "raw" block in "index.twig" at line 2
+++ /dev/null
---TEST--
-"raw" tag
---TEMPLATE--
-1***
-
-{%- raw %}
- {{ 'bla' }}
-{% endraw %}
-
-1***
-2***
-
-{%- raw -%}
- {{ 'bla' }}
-{% endraw %}
-
-2***
-3***
-
-{%- raw -%}
- {{ 'bla' }}
-{% endraw -%}
-
-3***
-4***
-
-{%- raw -%}
- {{ 'bla' }}
-{%- endraw %}
-
-4***
-5***
-
-{%- raw -%}
- {{ 'bla' }}
-{%- endraw -%}
-
-5***
---DATA--
-return array()
---EXPECT--
-1***
- {{ 'bla' }}
-
-
-1***
-2***{{ 'bla' }}
-
-
-2***
-3***{{ 'bla' }}
-3***
-4***{{ 'bla' }}
-
-4***
-5***{{ 'bla' }}5***
+++ /dev/null
---TEST--
-sandbox tag
---TEMPLATE--
-{%- sandbox %}
- {%- include "foo.twig" %}
- a
-{%- endsandbox %}
---TEMPLATE(foo.twig)--
-foo
---EXCEPTION--
-Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 4
+++ /dev/null
---TEST--
-sandbox tag
---TEMPLATE--
-{%- sandbox %}
- {%- include "foo.twig" %}
-
- {% if 1 %}
- {%- include "foo.twig" %}
- {% endif %}
-{%- endsandbox %}
---TEMPLATE(foo.twig)--
-foo
---EXCEPTION--
-Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 5
+++ /dev/null
---TEST--
-sandbox tag
---TEMPLATE--
-{%- sandbox %}
- {%- include "foo.twig" %}
-{%- endsandbox %}
-
-{%- sandbox %}
- {%- include "foo.twig" %}
- {%- include "foo.twig" %}
-{%- endsandbox %}
-
-{%- sandbox %}{% include "foo.twig" %}{% endsandbox %}
---TEMPLATE(foo.twig)--
-foo
---DATA--
-return array()
---EXPECT--
-foo
-foo
-foo
-foo
+++ /dev/null
---TEST--
-"set" tag
---TEMPLATE--
-{% set foo = 'foo' %}
-{% set bar = 'foo<br />' %}
-
-{{ foo }}
-{{ bar }}
-
-{% set foo, bar = 'foo', 'bar' %}
-
-{{ foo }}{{ bar }}
---DATA--
-return array()
---EXPECT--
-foo
-foo<br />
-
-
-foobar
+++ /dev/null
---TEST--
-"set" tag block empty capture
---TEMPLATE--
-{% set foo %}{% endset %}
-
-{% if foo %}FAIL{% endif %}
---DATA--
-return array()
---EXPECT--
+++ /dev/null
---TEST--
-"set" tag block capture
---TEMPLATE--
-{% set foo %}f<br />o<br />o{% endset %}
-
-{{ foo }}
---DATA--
-return array()
---EXPECT--
-f<br />o<br />o
+++ /dev/null
---TEST--
-"set" tag
---TEMPLATE--
-{% set foo, bar = 'foo' ~ 'bar', 'bar' ~ 'foo' %}
-
-{{ foo }}
-{{ bar }}
---DATA--
-return array()
---EXPECT--
-foobar
-barfoo
+++ /dev/null
---TEST--
-"spaceless" tag removes whites between HTML tags
---TEMPLATE--
-{% spaceless %}
-
- <div> <div> foo </div> </div>
-
-{% endspaceless %}
---DATA--
-return array()
---EXPECT--
-<div><div> foo </div></div>
+++ /dev/null
---TEST--
-"§" custom tag
---TEMPLATE--
-{% § %}
---DATA--
-return array()
---EXPECT--
-§
+++ /dev/null
---TEST--
-Whitespace trimming on tags.
---TEMPLATE--
-{{ 5 * '{#-'|length }}
-{{ '{{-'|length * 5 + '{%-'|length }}
-
-Trim on control tag:
-{% for i in range(1, 9) -%}
- {{ i }}
-{%- endfor %}
-
-
-Trim on output tag:
-{% for i in range(1, 9) %}
- {{- i -}}
-{% endfor %}
-
-
-Trim comments:
-
-{#- Invisible -#}
-
-After the comment.
-
-Trim leading space:
-{% if leading %}
-
- {{- leading }}
-{% endif %}
-
-{%- if leading %}
- {{- leading }}
-
-{%- endif %}
-
-
-Trim trailing space:
-{% if trailing -%}
- {{ trailing -}}
-
-{% endif -%}
-
-Combined:
-
-{%- if both -%}
-<ul>
- <li> {{- both -}} </li>
-</ul>
-
-{%- endif -%}
-
-end
---DATA--
-return array('leading' => 'leading space', 'trailing' => 'trailing space', 'both' => 'both')
---EXPECT--
-15
-18
-
-Trim on control tag:
-123456789
-
-Trim on output tag:
-123456789
-
-Trim comments:After the comment.
-
-Trim leading space:
-leading space
-leading space
-
-Trim trailing space:
-trailing spaceCombined:<ul>
- <li>both</li>
-</ul>end
+++ /dev/null
---TEST--
-"use" tag
---TEMPLATE--
-{% use "blocks.twig" with content as foo %}
-
-{{ block('foo') }}
---TEMPLATE(blocks.twig)--
-{% block content 'foo' %}
---DATA--
-return array()
---EXPECT--
-foo
+++ /dev/null
---TEST--
-"use" tag
---TEMPLATE--
-{% use "blocks.twig" %}
-
-{{ block('content') }}
---TEMPLATE(blocks.twig)--
-{% block content 'foo' %}
---DATA--
-return array()
---EXPECT--
-foo
+++ /dev/null
---TEST--
-"use" tag
---TEMPLATE--
-{% use "foo.twig" %}
-
-{{ block('content') }}
-{{ block('foo') }}
-{{ block('bar') }}
---TEMPLATE(foo.twig)--
-{% use "bar.twig" %}
-
-{% block content 'foo' %}
-{% block foo 'foo' %}
---TEMPLATE(bar.twig)--
-{% block content 'bar' %}
-{% block bar 'bar' %}
---DATA--
-return array()
---EXPECT--
-foo
-foo
-bar
+++ /dev/null
---TEST--
-"use" tag
---TEMPLATE--
-{% use "foo.twig" %}
---TEMPLATE(foo.twig)--
-{% use "bar.twig" %}
---TEMPLATE(bar.twig)--
---DATA--
-return array()
---EXPECT--
+++ /dev/null
---TEST--
-"use" tag
---TEMPLATE--
-{% use "foo.twig" %}
-{% use "bar.twig" %}
-
-{{ block('content') }}
-{{ block('foo') }}
-{{ block('bar') }}
---TEMPLATE(foo.twig)--
-{% block content 'foo' %}
-{% block foo 'foo' %}
---TEMPLATE(bar.twig)--
-{% block content 'bar' %}
-{% block bar 'bar' %}
---DATA--
-return array()
---EXPECT--
-bar
-foo
-bar
+++ /dev/null
---TEST--
-"use" tag
---TEMPLATE--
-{% use "foo.twig" with content as foo_content %}
-{% use "bar.twig" %}
-
-{{ block('content') }}
-{{ block('foo') }}
-{{ block('bar') }}
-{{ block('foo_content') }}
---TEMPLATE(foo.twig)--
-{% block content 'foo' %}
-{% block foo 'foo' %}
---TEMPLATE(bar.twig)--
-{% block content 'bar' %}
-{% block bar 'bar' %}
---DATA--
-return array()
---EXPECT--
-bar
-foo
-bar
-foo
+++ /dev/null
---TEST--
-"verbatim" tag
---TEMPLATE--
-{% verbatim %}
-{{ foo }}
-{% endverbatim %}
---DATA--
-return array()
---EXPECT--
-{{ foo }}
+++ /dev/null
---TEST--
-"verbatim" tag
---TEMPLATE--
-{% verbatim %}
-{{ foo }}
-{% endraw %}
---DATA--
-return array()
---EXCEPTION--
-Twig_Error_Syntax: Unexpected end of file: Unclosed "verbatim" block in "index.twig" at line 2
+++ /dev/null
---TEST--
-"verbatim" tag
---TEMPLATE--
-1***
-
-{%- verbatim %}
- {{ 'bla' }}
-{% endverbatim %}
-
-1***
-2***
-
-{%- verbatim -%}
- {{ 'bla' }}
-{% endverbatim %}
-
-2***
-3***
-
-{%- verbatim -%}
- {{ 'bla' }}
-{% endverbatim -%}
-
-3***
-4***
-
-{%- verbatim -%}
- {{ 'bla' }}
-{%- endverbatim %}
-
-4***
-5***
-
-{%- verbatim -%}
- {{ 'bla' }}
-{%- endverbatim -%}
-
-5***
---DATA--
-return array()
---EXPECT--
-1***
- {{ 'bla' }}
-
-
-1***
-2***{{ 'bla' }}
-
-
-2***
-3***{{ 'bla' }}
-3***
-4***{{ 'bla' }}
-
-4***
-5***{{ 'bla' }}5***
+++ /dev/null
---TEST--
-array index test
---TEMPLATE--
-{% for key, value in days %}
-{{ key }}
-{% endfor %}
---DATA--
-return array('days' => array(
- 1 => array('money' => 9),
- 2 => array('money' => 21),
- 3 => array('money' => 38),
- 4 => array('money' => 6),
- 18 => array('money' => 6),
- 19 => array('money' => 3),
- 31 => array('money' => 11),
-));
---EXPECT--
-1
-2
-3
-4
-18
-19
-31
+++ /dev/null
---TEST--
-"const" test
---TEMPLATE--
-{{ 8 is constant('E_NOTICE') ? 'ok' : 'no' }}
-{{ 'bar' is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }}
-{{ value is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }}
-{{ 2 is constant('ARRAY_AS_PROPS', object) ? 'ok' : 'no' }}
---DATA--
-return array('value' => 'bar', 'object' => new ArrayObject(array('hi')));
---EXPECT--
-ok
-ok
-ok
-ok
\ No newline at end of file
+++ /dev/null
---TEST--
-"defined" test
---TEMPLATE--
-{{ definedVar is defined ? 'ok' : 'ko' }}
-{{ definedVar is not defined ? 'ko' : 'ok' }}
-{{ undefinedVar is defined ? 'ko' : 'ok' }}
-{{ undefinedVar is not defined ? 'ok' : 'ko' }}
-{{ zeroVar is defined ? 'ok' : 'ko' }}
-{{ nullVar is defined ? 'ok' : 'ko' }}
-{{ nested.definedVar is defined ? 'ok' : 'ko' }}
-{{ nested['definedVar'] is defined ? 'ok' : 'ko' }}
-{{ nested.definedVar is not defined ? 'ko' : 'ok' }}
-{{ nested.undefinedVar is defined ? 'ko' : 'ok' }}
-{{ nested['undefinedVar'] is defined ? 'ko' : 'ok' }}
-{{ nested.undefinedVar is not defined ? 'ok' : 'ko' }}
-{{ nested.zeroVar is defined ? 'ok' : 'ko' }}
-{{ nested.nullVar is defined ? 'ok' : 'ko' }}
-{{ nested.definedArray.0 is defined ? 'ok' : 'ko' }}
-{{ nested['definedArray'][0] is defined ? 'ok' : 'ko' }}
-{{ object.foo is defined ? 'ok' : 'ko' }}
-{{ object.undefinedMethod is defined ? 'ko' : 'ok' }}
-{{ object.getFoo() is defined ? 'ok' : 'ko' }}
-{{ object.getFoo('a') is defined ? 'ok' : 'ko' }}
-{{ object.undefinedMethod() is defined ? 'ko' : 'ok' }}
-{{ object.undefinedMethod('a') is defined ? 'ko' : 'ok' }}
-{{ object.self.foo is defined ? 'ok' : 'ko' }}
-{{ object.self.undefinedMethod is defined ? 'ko' : 'ok' }}
-{{ object.undefinedMethod.self is defined ? 'ko' : 'ok' }}
---DATA--
-return array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'nullVar' => null,
- 'nested' => array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'nullVar' => null,
- 'definedArray' => array(0),
- ),
- 'object' => new TwigTestFoo(),
-);
---EXPECT--
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
---DATA--
-return array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'nullVar' => null,
- 'nested' => array(
- 'definedVar' => 'defined',
- 'zeroVar' => 0,
- 'nullVar' => null,
- 'definedArray' => array(0),
- ),
- 'object' => new TwigTestFoo(),
-);
---CONFIG--
-return array('strict_variables' => false)
---EXPECT--
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
-ok
+++ /dev/null
---TEST--
-"empty" test
---TEMPLATE--
-{{ foo is empty ? 'ok' : 'ko' }}
-{{ bar is empty ? 'ok' : 'ko' }}
-{{ foobar is empty ? 'ok' : 'ko' }}
-{{ array is empty ? 'ok' : 'ko' }}
-{{ zero is empty ? 'ok' : 'ko' }}
-{{ string is empty ? 'ok' : 'ko' }}
-{{ countable_empty is empty ? 'ok' : 'ko' }}
-{{ countable_not_empty is empty ? 'ok' : 'ko' }}
-{{ markup_empty is empty ? 'ok' : 'ko' }}
-{{ markup_not_empty is empty ? 'ok' : 'ko' }}
---DATA--
-
-class CountableStub implements Countable
-{
- private $items;
-
- public function __construct(array $items)
- {
- $this->items = $items;
- }
-
- public function count()
- {
- return count($this->items);
- }
-}
-return array(
- 'foo' => '', 'bar' => null, 'foobar' => false, 'array' => array(), 'zero' => 0, 'string' => '0',
- 'countable_empty' => new CountableStub(array()), 'countable_not_empty' => new CountableStub(array(1, 2)),
- 'markup_empty' => new Twig_Markup('', 'UTF-8'), 'markup_not_empty' => new Twig_Markup('test', 'UTF-8'),
-);
---EXPECT--
-ok
-ok
-ok
-ok
-ko
-ko
-ok
-ko
-ok
-ko
+++ /dev/null
---TEST--
-"even" test
---TEMPLATE--
-{{ 1 is even ? 'ko' : 'ok' }}
-{{ 2 is even ? 'ok' : 'ko' }}
-{{ 1 is not even ? 'ok' : 'ko' }}
-{{ 2 is not even ? 'ko' : 'ok' }}
---DATA--
-return array()
---EXPECT--
-ok
-ok
-ok
-ok
+++ /dev/null
---TEST--
-Twig supports the in operator
---TEMPLATE--
-{% if bar in foo %}
-TRUE
-{% endif %}
-{% if not (bar in foo) %}
-{% else %}
-TRUE
-{% endif %}
-{% if bar not in foo %}
-{% else %}
-TRUE
-{% endif %}
-{% if 'a' in bar %}
-TRUE
-{% endif %}
-{% if 'c' not in bar %}
-TRUE
-{% endif %}
-{% if '' not in bar %}
-TRUE
-{% endif %}
-{% if '' in '' %}
-TRUE
-{% endif %}
-{% if '0' not in '' %}
-TRUE
-{% endif %}
-{% if 'a' not in '0' %}
-TRUE
-{% endif %}
-{% if '0' in '0' %}
-TRUE
-{% endif %}
---DATA--
-return array('bar' => 'bar', 'foo' => array('bar' => 'bar'))
---EXPECT--
-TRUE
-TRUE
-TRUE
-TRUE
-TRUE
-TRUE
-TRUE
-TRUE
-TRUE
-TRUE
+++ /dev/null
---TEST--
-Twig supports the in operator when using objects
---TEMPLATE--
-{% if object in object_list %}
-TRUE
-{% endif %}
---DATA--
-$foo = new TwigTestFoo();
-$foo1 = new TwigTestFoo();
-
-$foo->position = $foo1;
-$foo1->position = $foo;
-
-return array(
- 'object' => $foo,
- 'object_list' => array($foo1, $foo),
-);
---EXPECT--
-TRUE
+++ /dev/null
---TEST--
-"iterable" test
---TEMPLATE--
-{{ foo is iterable ? 'ok' : 'ko' }}
-{{ traversable is iterable ? 'ok' : 'ko' }}
-{{ obj is iterable ? 'ok' : 'ko' }}
-{{ val is iterable ? 'ok' : 'ko' }}
---DATA--
-return array(
- 'foo' => array(),
- 'traversable' => new ArrayIterator(array()),
- 'obj' => new stdClass(),
- 'val' => 'test',
-);
---EXPECT--
-ok
-ok
-ko
-ko
\ No newline at end of file
+++ /dev/null
---TEST--
-"odd" test
---TEMPLATE--
-{{ 1 is odd ? 'ok' : 'ko' }}
-{{ 2 is odd ? 'ko' : 'ok' }}
---DATA--
-return array()
---EXPECT--
-ok
-ok
\ No newline at end of file
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-// This function is defined to check that escaping strategies
-// like html works even if a function with the same name is defined.
-function html()
-{
- return 'foo';
-}
-
-class Twig_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
-{
- public function getExtensions()
- {
- $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(), array(), array());
-
- return array(
- new Twig_Extension_Debug(),
- new Twig_Extension_Sandbox($policy, false),
- new Twig_Extension_StringLoader(),
- new TwigTestExtension(),
- );
- }
-
- public function getFixturesDir()
- {
- return dirname(__FILE__).'/Fixtures/';
- }
-}
-
-function test_foo($value = 'foo')
-{
- return $value;
-}
-
-class TwigTestFoo implements Iterator
-{
- const BAR_NAME = 'bar';
-
- public $position = 0;
- public $array = array(1, 2);
-
- public function bar($param1 = null, $param2 = null)
- {
- return 'bar'.($param1 ? '_'.$param1 : '').($param2 ? '-'.$param2 : '');
- }
-
- public function getFoo()
- {
- return 'foo';
- }
-
- public function getSelf()
- {
- return $this;
- }
-
- public function is()
- {
- return 'is';
- }
-
- public function in()
- {
- return 'in';
- }
-
- public function not()
- {
- return 'not';
- }
-
- public function strToLower($value)
- {
- return strtolower($value);
- }
-
- public function rewind()
- {
- $this->position = 0;
- }
-
- public function current()
- {
- return $this->array[$this->position];
- }
-
- public function key()
- {
- return 'a';
- }
-
- public function next()
- {
- ++$this->position;
- }
-
- public function valid()
- {
- return isset($this->array[$this->position]);
- }
-}
-
-class TwigTestTokenParser_§ extends Twig_TokenParser
-{
- public function parse(Twig_Token $token)
- {
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node_Print(new Twig_Node_Expression_Constant('§', -1), -1);
- }
-
- public function getTag()
- {
- return '§';
- }
-}
-
-class TwigTestExtension extends Twig_Extension
-{
- public function getTokenParsers()
- {
- return array(
- new TwigTestTokenParser_§(),
- );
- }
-
- public function getFilters()
- {
- return array(
- '§' => new Twig_Filter_Method($this, '§Filter'),
- 'escape_and_nl2br' => new Twig_Filter_Method($this, 'escape_and_nl2br', array('needs_environment' => true, 'is_safe' => array('html'))),
- 'nl2br' => new Twig_Filter_Method($this, 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
- 'escape_something' => new Twig_Filter_Method($this, 'escape_something', array('is_safe' => array('something'))),
- 'preserves_safety' => new Twig_Filter_Method($this, 'preserves_safety', array('preserves_safety' => array('html'))),
- '*_path' => new Twig_Filter_Method($this, 'dynamic_path'),
- '*_foo_*_bar' => new Twig_Filter_Method($this, 'dynamic_foo'),
- );
- }
-
- public function getFunctions()
- {
- return array(
- '§' => new Twig_Function_Method($this, '§Function'),
- 'safe_br' => new Twig_Function_Method($this, 'br', array('is_safe' => array('html'))),
- 'unsafe_br' => new Twig_Function_Method($this, 'br'),
- '*_path' => new Twig_Function_Method($this, 'dynamic_path'),
- '*_foo_*_bar' => new Twig_Function_Method($this, 'dynamic_foo'),
- );
- }
-
- public function §Filter($value)
- {
- return "§{$value}§";
- }
-
- public function §Function($value)
- {
- return "§{$value}§";
- }
-
- /**
- * nl2br which also escapes, for testing escaper filters
- */
- public function escape_and_nl2br($env, $value, $sep = '<br />')
- {
- return $this->nl2br(twig_escape_filter($env, $value, 'html'), $sep);
- }
-
- /**
- * nl2br only, for testing filters with pre_escape
- */
- public function nl2br($value, $sep = '<br />')
- {
- // not secure if $value contains html tags (not only entities)
- // don't use
- return str_replace("\n", "$sep\n", $value);
- }
-
- public function dynamic_path($element, $item)
- {
- return $element.'/'.$item;
- }
-
- public function dynamic_foo($foo, $bar, $item)
- {
- return $foo.'/'.$bar.'/'.$item;
- }
-
- public function escape_something($value)
- {
- return strtoupper($value);
- }
-
- public function preserves_safety($value)
- {
- return strtoupper($value);
- }
-
- public function br()
- {
- return '<br />';
- }
-
- public function getName()
- {
- return 'integration_test';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase
-{
- public function testNameLabelForTag()
- {
- $template = '{% § %}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- $stream->expect(Twig_Token::BLOCK_START_TYPE);
- $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
- }
-
- public function testNameLabelForFunction()
- {
- $template = '{{ §() }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- $stream->expect(Twig_Token::VAR_START_TYPE);
- $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
- }
-
- public function testBracketsNesting()
- {
- $template = '{{ {"a":{"b":"c"}} }}';
-
- $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '{'));
- $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '}'));
- }
-
- protected function countToken($template, $type, $value = null)
- {
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- $count = 0;
- $tokens = array();
- while (!$stream->isEOF()) {
- $token = $stream->next();
- if ($type === $token->getType()) {
- if (null === $value || $value === $token->getValue()) {
- ++$count;
- }
- }
- }
-
- return $count;
- }
-
- public function testLineDirective()
- {
- $template = "foo\n"
- . "bar\n"
- . "{% line 10 %}\n"
- . "{{\n"
- . "baz\n"
- . "}}\n";
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- // foo\nbar\n
- $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
- // \n (after {% line %})
- $this->assertSame(10, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
- // {{
- $this->assertSame(11, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
- // baz
- $this->assertSame(12, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
- }
-
- public function testLineDirectiveInline()
- {
- $template = "foo\n"
- . "bar{% line 10 %}{{\n"
- . "baz\n"
- . "}}\n";
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- // foo\nbar
- $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
- // {{
- $this->assertSame(10, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
- // baz
- $this->assertSame(11, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
- }
-
- public function testLongComments()
- {
- $template = '{# '.str_repeat('*', 100000).' #}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $lexer->tokenize($template);
-
- // should not throw an exception
- }
-
- public function testLongRaw()
- {
- $template = '{% raw %}'.str_repeat('*', 100000).'{% endraw %}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- // should not throw an exception
- }
-
- public function testLongVar()
- {
- $template = '{{ '.str_repeat('x', 100000).' }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- // should not throw an exception
- }
-
- public function testLongBlock()
- {
- $template = '{% '.str_repeat('x', 100000).' %}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
-
- // should not throw an exception
- }
-
- public function testBigNumbers()
- {
- $template = '{{ 922337203685477580700 }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- $node = $stream->next();
- $node = $stream->next();
- $this->assertEquals(922337203685477580700, $node->getValue());
- }
-
- public function testStringWithEscapedDelimiter()
- {
- $tests = array(
- "{{ 'foo \' bar' }}" => 'foo \' bar',
- '{{ "foo \" bar" }}' => "foo \" bar",
- );
- $lexer = new Twig_Lexer(new Twig_Environment());
- foreach ($tests as $template => $expected) {
- $stream = $lexer->tokenize($template);
- $stream->expect(Twig_Token::VAR_START_TYPE);
- $stream->expect(Twig_Token::STRING_TYPE, $expected);
- }
- }
-
- public function testStringWithInterpolation()
- {
- $template = 'foo {{ "bar #{ baz + 1 }" }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- $stream->expect(Twig_Token::TEXT_TYPE, 'foo ');
- $stream->expect(Twig_Token::VAR_START_TYPE);
- $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
- $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
- $stream->expect(Twig_Token::NAME_TYPE, 'baz');
- $stream->expect(Twig_Token::OPERATOR_TYPE, '+');
- $stream->expect(Twig_Token::NUMBER_TYPE, '1');
- $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
- $stream->expect(Twig_Token::VAR_END_TYPE);
- }
-
- public function testStringWithEscapedInterpolation()
- {
- $template = '{{ "bar \#{baz+1}" }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- $stream->expect(Twig_Token::VAR_START_TYPE);
- $stream->expect(Twig_Token::STRING_TYPE, 'bar #{baz+1}');
- $stream->expect(Twig_Token::VAR_END_TYPE);
- }
-
- public function testStringWithHash()
- {
- $template = '{{ "bar # baz" }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- $stream->expect(Twig_Token::VAR_START_TYPE);
- $stream->expect(Twig_Token::STRING_TYPE, 'bar # baz');
- $stream->expect(Twig_Token::VAR_END_TYPE);
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Unclosed """
- */
- public function testStringWithUnterminatedInterpolation()
- {
- $template = '{{ "bar #{x" }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- }
-
- public function testStringWithNestedInterpolations()
- {
- $template = '{{ "bar #{ "foo#{bar}" }" }}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- $stream->expect(Twig_Token::VAR_START_TYPE);
- $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
- $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
- $stream->expect(Twig_Token::STRING_TYPE, 'foo');
- $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
- $stream->expect(Twig_Token::NAME_TYPE, 'bar');
- $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
- $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
- $stream->expect(Twig_Token::VAR_END_TYPE);
- }
-
- public function testStringWithNestedInterpolationsInBlock()
- {
- $template = '{% foo "bar #{ "foo#{bar}" }" %}';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- $stream->expect(Twig_Token::BLOCK_START_TYPE);
- $stream->expect(Twig_Token::NAME_TYPE, 'foo');
- $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
- $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
- $stream->expect(Twig_Token::STRING_TYPE, 'foo');
- $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
- $stream->expect(Twig_Token::NAME_TYPE, 'bar');
- $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
- $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- }
-
- public function testOperatorEndingWithALetterAtTheEndOfALine()
- {
- $template = "{{ 1 and\n0}}";
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- $stream->expect(Twig_Token::VAR_START_TYPE);
- $stream->expect(Twig_Token::NUMBER_TYPE, 1);
- $stream->expect(Twig_Token::OPERATOR_TYPE, 'and');
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Unclosed "variable" at line 3
- */
- public function testUnterminatedVariable()
- {
- $template = '
-
-{{
-
-bar
-
-
-';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Unclosed "block" at line 3
- */
- public function testUnterminatedBlock()
- {
- $template = '
-
-{%
-
-bar
-
-
-';
-
- $lexer = new Twig_Lexer(new Twig_Environment());
- $stream = $lexer->tokenize($template);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Loader_ArrayTest extends PHPUnit_Framework_TestCase
-{
- public function testGetSource()
- {
- $loader = new Twig_Loader_Array(array('foo' => 'bar'));
-
- $this->assertEquals('bar', $loader->getSource('foo'));
- }
-
- /**
- * @expectedException Twig_Error_Loader
- */
- public function testGetSourceWhenTemplateDoesNotExist()
- {
- $loader = new Twig_Loader_Array(array());
-
- $loader->getSource('foo');
- }
-
- public function testGetCacheKey()
- {
- $loader = new Twig_Loader_Array(array('foo' => 'bar'));
-
- $this->assertEquals('bar', $loader->getCacheKey('foo'));
- }
-
- /**
- * @expectedException Twig_Error_Loader
- */
- public function testGetCacheKeyWhenTemplateDoesNotExist()
- {
- $loader = new Twig_Loader_Array(array());
-
- $loader->getCacheKey('foo');
- }
-
- public function testSetTemplate()
- {
- $loader = new Twig_Loader_Array(array());
- $loader->setTemplate('foo', 'bar');
-
- $this->assertEquals('bar', $loader->getSource('foo'));
- }
-
- public function testIsFresh()
- {
- $loader = new Twig_Loader_Array(array('foo' => 'bar'));
- $this->assertTrue($loader->isFresh('foo', time()));
- }
-
- /**
- * @expectedException Twig_Error_Loader
- */
- public function testIsFreshWhenTemplateDoesNotExist()
- {
- $loader = new Twig_Loader_Array(array());
-
- $loader->isFresh('foo', time());
- }
-
- public function testTemplateReference()
- {
- $name = new Twig_Test_Loader_TemplateReference('foo');
- $loader = new Twig_Loader_Array(array('foo' => 'bar'));
-
- $loader->getCacheKey($name);
- $loader->getSource($name);
- $loader->isFresh($name, time());
- $loader->setTemplate($name, 'foobar');
- }
-}
-
-class Twig_Test_Loader_TemplateReference
-{
- private $name;
-
- public function __construct($name)
- {
- $this->name = $name;
- }
-
- public function __toString()
- {
- return $this->name;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Loader_ChainTest extends PHPUnit_Framework_TestCase
-{
- public function testGetSource()
- {
- $loader = new Twig_Loader_Chain(array(
- new Twig_Loader_Array(array('foo' => 'bar')),
- new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')),
- ));
-
- $this->assertEquals('bar', $loader->getSource('foo'));
- $this->assertEquals('foo', $loader->getSource('bar'));
- }
-
- /**
- * @expectedException Twig_Error_Loader
- */
- public function testGetSourceWhenTemplateDoesNotExist()
- {
- $loader = new Twig_Loader_Chain(array());
-
- $loader->getSource('foo');
- }
-
- public function testGetCacheKey()
- {
- $loader = new Twig_Loader_Chain(array(
- new Twig_Loader_Array(array('foo' => 'bar')),
- new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')),
- ));
-
- $this->assertEquals('bar', $loader->getCacheKey('foo'));
- $this->assertEquals('foo', $loader->getCacheKey('bar'));
- }
-
- /**
- * @expectedException Twig_Error_Loader
- */
- public function testGetCacheKeyWhenTemplateDoesNotExist()
- {
- $loader = new Twig_Loader_Chain(array());
-
- $loader->getCacheKey('foo');
- }
-
- public function testAddLoader()
- {
- $loader = new Twig_Loader_Chain();
- $loader->addLoader(new Twig_Loader_Array(array('foo' => 'bar')));
-
- $this->assertEquals('bar', $loader->getSource('foo'));
- }
-
- public function testExists()
- {
- $loader1 = $this->getMock('Twig_Loader_Array', array('exists', 'getSource'), array(), '', false);
- $loader1->expects($this->once())->method('exists')->will($this->returnValue(false));
- $loader1->expects($this->never())->method('getSource');
-
- $loader2 = $this->getMock('Twig_LoaderInterface');
- $loader2->expects($this->once())->method('getSource')->will($this->returnValue('content'));
-
- $loader = new Twig_Loader_Chain();
- $loader->addLoader($loader1);
- $loader->addLoader($loader2);
-
- $this->assertTrue($loader->exists('foo'));
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider getSecurityTests
- */
- public function testSecurity($template)
- {
- $loader = new Twig_Loader_Filesystem(array(dirname(__FILE__).'/../Fixtures'));
-
- try {
- $loader->getCacheKey($template);
- $this->fail();
- } catch (Twig_Error_Loader $e) {
- $this->assertNotContains('Unable to find template', $e->getMessage());
- }
- }
-
- public function getSecurityTests()
- {
- return array(
- array("AutoloaderTest\0.php"),
- array('..\\AutoloaderTest.php'),
- array('..\\\\\\AutoloaderTest.php'),
- array('../AutoloaderTest.php'),
- array('..////AutoloaderTest.php'),
- array('./../AutoloaderTest.php'),
- array('.\\..\\AutoloaderTest.php'),
- array('././././././../AutoloaderTest.php'),
- array('.\\./.\\./.\\./../AutoloaderTest.php'),
- array('foo/../../AutoloaderTest.php'),
- array('foo\\..\\..\\AutoloaderTest.php'),
- array('foo/../bar/../../AutoloaderTest.php'),
- array('foo/bar/../../../AutoloaderTest.php'),
- array('filters/../../AutoloaderTest.php'),
- array('filters//..//..//AutoloaderTest.php'),
- array('filters\\..\\..\\AutoloaderTest.php'),
- array('filters\\\\..\\\\..\\\\AutoloaderTest.php'),
- array('filters\\//../\\/\\..\\AutoloaderTest.php'),
- array('/../AutoloaderTest.php'),
- );
- }
-
- public function testPaths()
- {
- $basePath = dirname(__FILE__).'/Fixtures';
-
- $loader = new Twig_Loader_Filesystem(array($basePath.'/normal', $basePath.'/normal_bis'));
- $loader->setPaths(array($basePath.'/named', $basePath.'/named_bis'), 'named');
- $loader->addPath($basePath.'/named_ter', 'named');
- $loader->addPath($basePath.'/normal_ter');
- $loader->prependPath($basePath.'/normal_final');
- $loader->prependPath($basePath.'/named_final', 'named');
-
- $this->assertEquals(array(
- $basePath.'/normal_final',
- $basePath.'/normal',
- $basePath.'/normal_bis',
- $basePath.'/normal_ter',
- ), $loader->getPaths());
- $this->assertEquals(array(
- $basePath.'/named_final',
- $basePath.'/named',
- $basePath.'/named_bis',
- $basePath.'/named_ter',
- ), $loader->getPaths('named'));
-
- $this->assertEquals("path (final)\n", $loader->getSource('index.html'));
- $this->assertEquals("path (final)\n", $loader->getSource('@__main__/index.html'));
- $this->assertEquals("named path (final)\n", $loader->getSource('@named/index.html'));
- }
-
- public function testEmptyConstructor()
- {
- $loader = new Twig_Loader_Filesystem();
- $this->assertEquals(array(), $loader->getPaths());
- }
-
- public function testGetNamespaces()
- {
- $loader = new Twig_Loader_Filesystem(sys_get_temp_dir());
- $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE), $loader->getNamespaces());
-
- $loader->addPath(sys_get_temp_dir(), 'named');
- $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE, 'named'), $loader->getNamespaces());
- }
-}
+++ /dev/null
-named path
+++ /dev/null
-named path (bis)
+++ /dev/null
-named path (final)
+++ /dev/null
-named path (ter)
+++ /dev/null
-path (bis)
+++ /dev/null
-path (final)
+++ /dev/null
-path (ter)
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase
-{
- public function testGetProperties()
- {
- $twig = new Twig_Environment(new Twig_Loader_String(), array(
- 'debug' => true,
- 'cache' => false,
- 'autoescape' => false
- ));
-
- $d1 = new DateTime();
- $d2 = new DateTime();
- $output = $twig->render('{{ d1.date }}{{ d2.date }}', compact('d1', 'd2'));
-
- // If it fails, PHP will crash.
- $this->assertEquals($output, $d1->date . $d2->date);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_AutoEscapeTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_AutoEscape::__construct
- */
- public function testConstructor()
- {
- $body = new Twig_Node(array(new Twig_Node_Text('foo', 1)));
- $node = new Twig_Node_AutoEscape(true, $body, 1);
-
- $this->assertEquals($body, $node->getNode('body'));
- $this->assertEquals(true, $node->getAttribute('value'));
- }
-
- /**
- * @covers Twig_Node_AutoEscape::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $body = new Twig_Node(array(new Twig_Node_Text('foo', 1)));
- $node = new Twig_Node_AutoEscape(true, $body, 1);
-
- return array(
- array($node, "// line 1\necho \"foo\";"),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_BlockReferenceTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_BlockReference::__construct
- */
- public function testConstructor()
- {
- $node = new Twig_Node_BlockReference('foo', 1);
-
- $this->assertEquals('foo', $node->getAttribute('name'));
- }
-
- /**
- * @covers Twig_Node_BlockReference::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- return array(
- array(new Twig_Node_BlockReference('foo', 1), <<<EOF
-// line 1
-\$this->displayBlock('foo', \$context, \$blocks);
-EOF
- ),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_BlockTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Block::__construct
- */
- public function testConstructor()
- {
- $body = new Twig_Node_Text('foo', 1);
- $node = new Twig_Node_Block('foo', $body, 1);
-
- $this->assertEquals($body, $node->getNode('body'));
- $this->assertEquals('foo', $node->getAttribute('name'));
- }
-
- /**
- * @covers Twig_Node_Block::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $body = new Twig_Node_Text('foo', 1);
- $node = new Twig_Node_Block('foo', $body, 1);
-
- return array(
- array($node, <<<EOF
-// line 1
-public function block_foo(\$context, array \$blocks = array())
-{
- echo "foo";
-}
-EOF
- ),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_DoTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Do::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant('foo', 1);
- $node = new Twig_Node_Do($expr, 1);
-
- $this->assertEquals($expr, $node->getNode('expr'));
- }
-
- /**
- * @covers Twig_Node_Do::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $expr = new Twig_Node_Expression_Constant('foo', 1);
- $node = new Twig_Node_Do($expr, 1);
- $tests[] = array($node, "// line 1\n\"foo\";");
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_ArrayTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Array::__construct
- */
- public function testConstructor()
- {
- $elements = array(new Twig_Node_Expression_Constant('foo', 1), $foo = new Twig_Node_Expression_Constant('bar', 1));
- $node = new Twig_Node_Expression_Array($elements, 1);
-
- $this->assertEquals($foo, $node->getNode(1));
- }
-
- /**
- * @covers Twig_Node_Expression_Array::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $elements = array(
- new Twig_Node_Expression_Constant('foo', 1),
- new Twig_Node_Expression_Constant('bar', 1),
-
- new Twig_Node_Expression_Constant('bar', 1),
- new Twig_Node_Expression_Constant('foo', 1),
- );
- $node = new Twig_Node_Expression_Array($elements, 1);
-
- return array(
- array($node, 'array("foo" => "bar", "bar" => "foo")'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_AssignNameTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_AssignName::__construct
- */
- public function testConstructor()
- {
- $node = new Twig_Node_Expression_AssignName('foo', 1);
-
- $this->assertEquals('foo', $node->getAttribute('name'));
- }
-
- /**
- * @covers Twig_Node_Expression_AssignName::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $node = new Twig_Node_Expression_AssignName('foo', 1);
-
- return array(
- array($node, '$context["foo"]'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_AddTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_Add::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Add($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_Add::compile
- * @covers Twig_Node_Expression_Binary_Add::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Add($left, $right, 1);
-
- return array(
- array($node, '(1 + 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_AndTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_And::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_And($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_And::compile
- * @covers Twig_Node_Expression_Binary_And::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_And($left, $right, 1);
-
- return array(
- array($node, '(1 && 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_ConcatTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_Concat::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_Concat::compile
- * @covers Twig_Node_Expression_Binary_Concat::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1);
-
- return array(
- array($node, '(1 . 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_DivTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_Div::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Div($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_Div::compile
- * @covers Twig_Node_Expression_Binary_Div::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Div($left, $right, 1);
-
- return array(
- array($node, '(1 / 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_FloorDivTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_FloorDiv::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_FloorDiv::compile
- * @covers Twig_Node_Expression_Binary_FloorDiv::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1);
-
- return array(
- array($node, 'intval(floor((1 / 2)))'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_ModTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_Mod::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_Mod::compile
- * @covers Twig_Node_Expression_Binary_Mod::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1);
-
- return array(
- array($node, '(1 % 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_MulTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_Mul::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_Mul::compile
- * @covers Twig_Node_Expression_Binary_Mul::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1);
-
- return array(
- array($node, '(1 * 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_OrTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_Or::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Or($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_Or::compile
- * @covers Twig_Node_Expression_Binary_Or::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Or($left, $right, 1);
-
- return array(
- array($node, '(1 || 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Binary_SubTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Binary_Sub::__construct
- */
- public function testConstructor()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1);
-
- $this->assertEquals($left, $node->getNode('left'));
- $this->assertEquals($right, $node->getNode('right'));
- }
-
- /**
- * @covers Twig_Node_Expression_Binary_Sub::compile
- * @covers Twig_Node_Expression_Binary_Sub::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $left = new Twig_Node_Expression_Constant(1, 1);
- $right = new Twig_Node_Expression_Constant(2, 1);
- $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1);
-
- return array(
- array($node, '(1 - 2)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
-{
- public function testGetArguments()
- {
- $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
- $this->assertEquals(array('U'), $node->getArguments('date', array('format' => 'U')));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Positional arguments cannot be used after named arguments for function "date".
- */
- public function testGetArgumentsWhenPositionalArgumentsAfterNamedArguments()
- {
- $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
- $node->getArguments('date', array('timestamp' => 123456, 'Y-m-d'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Argument "format" is defined twice for function "date".
- */
- public function testGetArgumentsWhenArgumentIsDefinedTwice()
- {
- $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
- $node->getArguments('date', array('Y-m-d', 'format' => 'U'));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Unknown argument "unknown" for function "date".
- */
- public function testGetArgumentsWithWrongNamedArgumentName()
- {
- $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
- $node->getArguments('date', array('Y-m-d', 'unknown' => ''));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Unknown arguments "unknown1", "unknown2" for function "date".
- */
- public function testGetArgumentsWithWrongNamedArgumentNames()
- {
- $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
- $node->getArguments('date', array('Y-m-d', 'unknown1' => '', 'unknown2' => ''));
- }
-}
-
-class Twig_Tests_Node_Expression_Call extends Twig_Node_Expression_Call
-{
- public function getArguments($callable, $arguments)
- {
- return parent::getArguments($callable, $arguments);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_ConditionalTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Conditional::__construct
- */
- public function testConstructor()
- {
- $expr1 = new Twig_Node_Expression_Constant(1, 1);
- $expr2 = new Twig_Node_Expression_Constant(2, 1);
- $expr3 = new Twig_Node_Expression_Constant(3, 1);
- $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1);
-
- $this->assertEquals($expr1, $node->getNode('expr1'));
- $this->assertEquals($expr2, $node->getNode('expr2'));
- $this->assertEquals($expr3, $node->getNode('expr3'));
- }
-
- /**
- * @covers Twig_Node_Expression_Conditional::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $expr1 = new Twig_Node_Expression_Constant(1, 1);
- $expr2 = new Twig_Node_Expression_Constant(2, 1);
- $expr3 = new Twig_Node_Expression_Constant(3, 1);
- $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1);
- $tests[] = array($node, '((1) ? (2) : (3))');
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_ConstantTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Constant::__construct
- */
- public function testConstructor()
- {
- $node = new Twig_Node_Expression_Constant('foo', 1);
-
- $this->assertEquals('foo', $node->getAttribute('value'));
- }
-
- /**
- * @covers Twig_Node_Expression_Constant::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $node = new Twig_Node_Expression_Constant('foo', 1);
- $tests[] = array($node, '"foo"');
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Filter::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant('foo', 1);
- $name = new Twig_Node_Expression_Constant('upper', 1);
- $args = new Twig_Node();
- $node = new Twig_Node_Expression_Filter($expr, $name, $args, 1);
-
- $this->assertEquals($expr, $node->getNode('node'));
- $this->assertEquals($name, $node->getNode('filter'));
- $this->assertEquals($args, $node->getNode('arguments'));
- }
-
- /**
- * @covers Twig_Node_Expression_Filter::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $expr = new Twig_Node_Expression_Constant('foo', 1);
- $node = $this->createFilter($expr, 'upper');
- $node = $this->createFilter($node, 'number_format', array(new Twig_Node_Expression_Constant(2, 1), new Twig_Node_Expression_Constant('.', 1), new Twig_Node_Expression_Constant(',', 1)));
-
- if (function_exists('mb_get_info')) {
- $tests[] = array($node, 'twig_number_format_filter($this->env, twig_upper_filter($this->env, "foo"), 2, ".", ",")');
- } else {
- $tests[] = array($node, 'twig_number_format_filter($this->env, strtoupper("foo"), 2, ".", ",")');
- }
-
- // named arguments
- $date = new Twig_Node_Expression_Constant(0, 1);
- $node = $this->createFilter($date, 'date', array(
- 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
- 'format' => new Twig_Node_Expression_Constant('d/m/Y H:i:s P', 1),
- ));
- $tests[] = array($node, 'twig_date_format_filter($this->env, 0, "d/m/Y H:i:s P", "America/Chicago")');
-
- // skip an optional argument
- $date = new Twig_Node_Expression_Constant(0, 1);
- $node = $this->createFilter($date, 'date', array(
- 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
- ));
- $tests[] = array($node, 'twig_date_format_filter($this->env, 0, null, "America/Chicago")');
-
- // underscores vs camelCase for named arguments
- $string = new Twig_Node_Expression_Constant('abc', 1);
- $node = $this->createFilter($string, 'reverse', array(
- 'preserve_keys' => new Twig_Node_Expression_Constant(true, 1),
- ));
- $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
- $node = $this->createFilter($string, 'reverse', array(
- 'preserveKeys' => new Twig_Node_Expression_Constant(true, 1),
- ));
- $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
-
- // filter as an anonymous function
- if (version_compare(phpversion(), '5.3.0', '>=')) {
- $node = $this->createFilter(new Twig_Node_Expression_Constant('foo', 1), 'anonymous');
- $tests[] = array($node, 'call_user_func_array($this->env->getFilter(\'anonymous\')->getCallable(), array("foo"))');
- }
-
- return $tests;
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Unknown argument "foobar" for filter "date".
- */
- public function testCompileWithWrongNamedArgumentName()
- {
- $date = new Twig_Node_Expression_Constant(0, 1);
- $node = $this->createFilter($date, 'date', array(
- 'foobar' => new Twig_Node_Expression_Constant('America/Chicago', 1),
- ));
-
- $compiler = $this->getCompiler();
- $compiler->compile($node);
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Value for argument "from" is required for filter "replace".
- */
- public function testCompileWithMissingNamedArgument()
- {
- $value = new Twig_Node_Expression_Constant(0, 1);
- $node = $this->createFilter($value, 'replace', array(
- 'to' => new Twig_Node_Expression_Constant('foo', 1),
- ));
-
- $compiler = $this->getCompiler();
- $compiler->compile($node);
- }
-
- protected function createFilter($node, $name, array $arguments = array())
- {
- $name = new Twig_Node_Expression_Constant($name, 1);
- $arguments = new Twig_Node($arguments);
-
- return new Twig_Node_Expression_Filter($node, $name, $arguments, 1);
- }
-
- protected function getEnvironment()
- {
- if (version_compare(phpversion(), '5.3.0', '>=')) {
- return include 'PHP53/FilterInclude.php';
- }
-
- return parent::getEnvironment();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Function::__construct
- */
- public function testConstructor()
- {
- $name = 'function';
- $args = new Twig_Node();
- $node = new Twig_Node_Expression_Function($name, $args, 1);
-
- $this->assertEquals($name, $node->getAttribute('name'));
- $this->assertEquals($args, $node->getNode('arguments'));
- }
-
- /**
- * @covers Twig_Node_Expression_Function::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $environment = new Twig_Environment();
- $environment->addFunction('foo', new Twig_Function_Function('foo', array()));
- $environment->addFunction('bar', new Twig_Function_Function('bar', array('needs_environment' => true)));
- $environment->addFunction('foofoo', new Twig_Function_Function('foofoo', array('needs_context' => true)));
- $environment->addFunction('foobar', new Twig_Function_Function('foobar', array('needs_environment' => true, 'needs_context' => true)));
-
- $tests = array();
-
- $node = $this->createFunction('foo');
- $tests[] = array($node, 'foo()', $environment);
-
- $node = $this->createFunction('foo', array(new Twig_Node_Expression_Constant('bar', 1), new Twig_Node_Expression_Constant('foobar', 1)));
- $tests[] = array($node, 'foo("bar", "foobar")', $environment);
-
- $node = $this->createFunction('bar');
- $tests[] = array($node, 'bar($this->env)', $environment);
-
- $node = $this->createFunction('bar', array(new Twig_Node_Expression_Constant('bar', 1)));
- $tests[] = array($node, 'bar($this->env, "bar")', $environment);
-
- $node = $this->createFunction('foofoo');
- $tests[] = array($node, 'foofoo($context)', $environment);
-
- $node = $this->createFunction('foofoo', array(new Twig_Node_Expression_Constant('bar', 1)));
- $tests[] = array($node, 'foofoo($context, "bar")', $environment);
-
- $node = $this->createFunction('foobar');
- $tests[] = array($node, 'foobar($this->env, $context)', $environment);
-
- $node = $this->createFunction('foobar', array(new Twig_Node_Expression_Constant('bar', 1)));
- $tests[] = array($node, 'foobar($this->env, $context, "bar")', $environment);
-
- // named arguments
- $node = $this->createFunction('date', array(
- 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
- 'date' => new Twig_Node_Expression_Constant(0, 1),
- ));
- $tests[] = array($node, 'twig_date_converter($this->env, 0, "America/Chicago")');
-
- // function as an anonymous function
- if (version_compare(phpversion(), '5.3.0', '>=')) {
- $node = $this->createFunction('anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
- $tests[] = array($node, 'call_user_func_array($this->env->getFunction(\'anonymous\')->getCallable(), array("foo"))');
- }
-
- return $tests;
- }
-
- protected function createFunction($name, array $arguments = array())
- {
- return new Twig_Node_Expression_Function($name, new Twig_Node($arguments), 1);
- }
-
- protected function getEnvironment()
- {
- if (version_compare(phpversion(), '5.3.0', '>=')) {
- return include 'PHP53/FunctionInclude.php';
- }
-
- return parent::getEnvironment();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_GetAttr::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Name('foo', 1);
- $attr = new Twig_Node_Expression_Constant('bar', 1);
- $args = new Twig_Node_Expression_Array(array(), 1);
- $args->addElement(new Twig_Node_Expression_Name('foo', 1));
- $args->addElement(new Twig_Node_Expression_Constant('bar', 1));
- $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1);
-
- $this->assertEquals($expr, $node->getNode('node'));
- $this->assertEquals($attr, $node->getNode('attribute'));
- $this->assertEquals($args, $node->getNode('arguments'));
- $this->assertEquals(Twig_TemplateInterface::ARRAY_CALL, $node->getAttribute('type'));
- }
-
- /**
- * @covers Twig_Node_Expression_GetAttr::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $expr = new Twig_Node_Expression_Name('foo', 1);
- $attr = new Twig_Node_Expression_Constant('bar', 1);
- $args = new Twig_Node_Expression_Array(array(), 1);
- $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ANY_CALL, 1);
- $tests[] = array($node, sprintf('%s%s, "bar")', $this->getAttributeGetter(), $this->getVariableGetter('foo')));
-
- $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1);
- $tests[] = array($node, sprintf('%s%s, "bar", array(), "array")', $this->getAttributeGetter(), $this->getVariableGetter('foo')));
-
- $args = new Twig_Node_Expression_Array(array(), 1);
- $args->addElement(new Twig_Node_Expression_Name('foo', 1));
- $args->addElement(new Twig_Node_Expression_Constant('bar', 1));
- $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::METHOD_CALL, 1);
- $tests[] = array($node, sprintf('%s%s, "bar", array(0 => %s, 1 => "bar"), "method")', $this->getAttributeGetter(), $this->getVariableGetter('foo'), $this->getVariableGetter('foo')));
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_NameTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Name::__construct
- */
- public function testConstructor()
- {
- $node = new Twig_Node_Expression_Name('foo', 1);
-
- $this->assertEquals('foo', $node->getAttribute('name'));
- }
-
- /**
- * @covers Twig_Node_Expression_Name::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $node = new Twig_Node_Expression_Name('foo', 1);
- $self = new Twig_Node_Expression_Name('_self', 1);
- $context = new Twig_Node_Expression_Name('_context', 1);
-
- $env = new Twig_Environment(null, array('strict_variables' => true));
- $env1 = new Twig_Environment(null, array('strict_variables' => false));
-
- return array(
- version_compare(PHP_VERSION, '5.4.0') >= 0 ? array($node, '(isset($context["foo"]) ? $context["foo"] : $this->getContext($context, "foo"))', $env) : array($node, '$this->getContext($context, "foo")', $env),
- array($node, $this->getVariableGetter('foo'), $env1),
- array($self, '$this'),
- array($context, '$context'),
- );
- }
-}
+++ /dev/null
-<?php
-
-$env = new Twig_Environment();
-$env->addFilter(new Twig_SimpleFilter('anonymous', function () {}));
-
-return $env;
+++ /dev/null
-<?php
-
-$env = new Twig_Environment();
-$env->addFunction(new Twig_SimpleFunction('anonymous', function () {}));
-
-return $env;
+++ /dev/null
-<?php
-
-$env = new Twig_Environment();
-$env->addTest(new Twig_SimpleTest('anonymous', function () {}));
-
-return $env;
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_ParentTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Parent::__construct
- */
- public function testConstructor()
- {
- $node = new Twig_Node_Expression_Parent('foo', 1);
-
- $this->assertEquals('foo', $node->getAttribute('name'));
- }
-
- /**
- * @covers Twig_Node_Expression_Parent::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
- $tests[] = array(new Twig_Node_Expression_Parent('foo', 1), '$this->renderParentBlock("foo", $context, $blocks)');
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Test::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant('foo', 1);
- $name = new Twig_Node_Expression_Constant('null', 1);
- $args = new Twig_Node();
- $node = new Twig_Node_Expression_Test($expr, $name, $args, 1);
-
- $this->assertEquals($expr, $node->getNode('node'));
- $this->assertEquals($args, $node->getNode('arguments'));
- $this->assertEquals($name, $node->getAttribute('name'));
- }
-
- /**
- * @covers Twig_Node_Expression_Test::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $expr = new Twig_Node_Expression_Constant('foo', 1);
- $node = new Twig_Node_Expression_Test_Null($expr, 'null', new Twig_Node(array()), 1);
- $tests[] = array($node, '(null === "foo")');
-
- // test as an anonymous function
- if (version_compare(phpversion(), '5.3.0', '>=')) {
- $node = $this->createTest(new Twig_Node_Expression_Constant('foo', 1), 'anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
- $tests[] = array($node, 'call_user_func_array($this->env->getTest(\'anonymous\')->getCallable(), array("foo", "foo"))');
- }
-
- return $tests;
- }
-
- protected function createTest($node, $name, array $arguments = array())
- {
- return new Twig_Node_Expression_Test($node, $name, new Twig_Node($arguments), 1);
- }
-
- protected function getEnvironment()
- {
- if (version_compare(phpversion(), '5.3.0', '>=')) {
- return include 'PHP53/TestInclude.php';
- }
-
- return parent::getEnvironment();
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Unary_NegTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Unary_Neg::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant(1, 1);
- $node = new Twig_Node_Expression_Unary_Neg($expr, 1);
-
- $this->assertEquals($expr, $node->getNode('node'));
- }
-
- /**
- * @covers Twig_Node_Expression_Unary_Neg::compile
- * @covers Twig_Node_Expression_Unary_Neg::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $node = new Twig_Node_Expression_Constant(1, 1);
- $node = new Twig_Node_Expression_Unary_Neg($node, 1);
-
- return array(
- array($node, '(-1)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Unary_NotTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Unary_Not::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant(1, 1);
- $node = new Twig_Node_Expression_Unary_Not($expr, 1);
-
- $this->assertEquals($expr, $node->getNode('node'));
- }
-
- /**
- * @covers Twig_Node_Expression_Unary_Not::compile
- * @covers Twig_Node_Expression_Unary_Not::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $node = new Twig_Node_Expression_Constant(1, 1);
- $node = new Twig_Node_Expression_Unary_Not($node, 1);
-
- return array(
- array($node, '(!1)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_Expression_Unary_PosTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Expression_Unary_Pos::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant(1, 1);
- $node = new Twig_Node_Expression_Unary_Pos($expr, 1);
-
- $this->assertEquals($expr, $node->getNode('node'));
- }
-
- /**
- * @covers Twig_Node_Expression_Unary_Pos::compile
- * @covers Twig_Node_Expression_Unary_Pos::operator
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $node = new Twig_Node_Expression_Constant(1, 1);
- $node = new Twig_Node_Expression_Unary_Pos($node, 1);
-
- return array(
- array($node, '(+1)'),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_ForTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_For::__construct
- */
- public function testConstructor()
- {
- $keyTarget = new Twig_Node_Expression_AssignName('key', 1);
- $valueTarget = new Twig_Node_Expression_AssignName('item', 1);
- $seq = new Twig_Node_Expression_Name('items', 1);
- $ifexpr = new Twig_Node_Expression_Constant(true, 1);
- $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
- $else = null;
- $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
- $node->setAttribute('with_loop', false);
-
- $this->assertEquals($keyTarget, $node->getNode('key_target'));
- $this->assertEquals($valueTarget, $node->getNode('value_target'));
- $this->assertEquals($seq, $node->getNode('seq'));
- $this->assertTrue($node->getAttribute('ifexpr'));
- $this->assertEquals('Twig_Node_If', get_class($node->getNode('body')));
- $this->assertEquals($body, $node->getNode('body')->getNode('tests')->getNode(1)->getNode(0));
- $this->assertEquals(null, $node->getNode('else'));
-
- $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1);
- $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
- $node->setAttribute('with_loop', false);
- $this->assertEquals($else, $node->getNode('else'));
- }
-
- /**
- * @covers Twig_Node_For::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $keyTarget = new Twig_Node_Expression_AssignName('key', 1);
- $valueTarget = new Twig_Node_Expression_AssignName('item', 1);
- $seq = new Twig_Node_Expression_Name('items', 1);
- $ifexpr = null;
- $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
- $else = null;
- $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
- $node->setAttribute('with_loop', false);
-
- $tests[] = array($node, <<<EOF
-// line 1
-\$context['_parent'] = (array) \$context;
-\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('items')});
-foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) {
- echo {$this->getVariableGetter('foo')};
-}
-\$_parent = \$context['_parent'];
-unset(\$context['_seq'], \$context['_iterated'], \$context['key'], \$context['item'], \$context['_parent'], \$context['loop']);
-\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
-EOF
- );
-
- $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
- $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
- $seq = new Twig_Node_Expression_Name('values', 1);
- $ifexpr = null;
- $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
- $else = null;
- $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
- $node->setAttribute('with_loop', true);
-
- $tests[] = array($node, <<<EOF
-// line 1
-\$context['_parent'] = (array) \$context;
-\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
-\$context['loop'] = array(
- 'parent' => \$context['_parent'],
- 'index0' => 0,
- 'index' => 1,
- 'first' => true,
-);
-if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {
- \$length = count(\$context['_seq']);
- \$context['loop']['revindex0'] = \$length - 1;
- \$context['loop']['revindex'] = \$length;
- \$context['loop']['length'] = \$length;
- \$context['loop']['last'] = 1 === \$length;
-}
-foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
- echo {$this->getVariableGetter('foo')};
- ++\$context['loop']['index0'];
- ++\$context['loop']['index'];
- \$context['loop']['first'] = false;
- if (isset(\$context['loop']['length'])) {
- --\$context['loop']['revindex0'];
- --\$context['loop']['revindex'];
- \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
- }
-}
-\$_parent = \$context['_parent'];
-unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
-\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
-EOF
- );
-
- $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
- $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
- $seq = new Twig_Node_Expression_Name('values', 1);
- $ifexpr = new Twig_Node_Expression_Constant(true, 1);
- $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
- $else = null;
- $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
- $node->setAttribute('with_loop', true);
-
- $tests[] = array($node, <<<EOF
-// line 1
-\$context['_parent'] = (array) \$context;
-\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
-\$context['loop'] = array(
- 'parent' => \$context['_parent'],
- 'index0' => 0,
- 'index' => 1,
- 'first' => true,
-);
-foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
- if (true) {
- echo {$this->getVariableGetter('foo')};
- ++\$context['loop']['index0'];
- ++\$context['loop']['index'];
- \$context['loop']['first'] = false;
- }
-}
-\$_parent = \$context['_parent'];
-unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
-\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
-EOF
- );
-
- $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
- $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
- $seq = new Twig_Node_Expression_Name('values', 1);
- $ifexpr = null;
- $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
- $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1);
- $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
- $node->setAttribute('with_loop', true);
-
- $tests[] = array($node, <<<EOF
-// line 1
-\$context['_parent'] = (array) \$context;
-\$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
-\$context['_iterated'] = false;
-\$context['loop'] = array(
- 'parent' => \$context['_parent'],
- 'index0' => 0,
- 'index' => 1,
- 'first' => true,
-);
-if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {
- \$length = count(\$context['_seq']);
- \$context['loop']['revindex0'] = \$length - 1;
- \$context['loop']['revindex'] = \$length;
- \$context['loop']['length'] = \$length;
- \$context['loop']['last'] = 1 === \$length;
-}
-foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
- echo {$this->getVariableGetter('foo')};
- \$context['_iterated'] = true;
- ++\$context['loop']['index0'];
- ++\$context['loop']['index'];
- \$context['loop']['first'] = false;
- if (isset(\$context['loop']['length'])) {
- --\$context['loop']['revindex0'];
- --\$context['loop']['revindex'];
- \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
- }
-}
-if (!\$context['_iterated']) {
- echo {$this->getVariableGetter('foo')};
-}
-\$_parent = \$context['_parent'];
-unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
-\$context = array_intersect_key(\$context, \$_parent) + \$_parent;
-EOF
- );
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_IfTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_If::__construct
- */
- public function testConstructor()
- {
- $t = new Twig_Node(array(
- new Twig_Node_Expression_Constant(true, 1),
- new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
- ), array(), 1);
- $else = null;
- $node = new Twig_Node_If($t, $else, 1);
-
- $this->assertEquals($t, $node->getNode('tests'));
- $this->assertEquals(null, $node->getNode('else'));
-
- $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1);
- $node = new Twig_Node_If($t, $else, 1);
- $this->assertEquals($else, $node->getNode('else'));
- }
-
- /**
- * @covers Twig_Node_If::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $t = new Twig_Node(array(
- new Twig_Node_Expression_Constant(true, 1),
- new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
- ), array(), 1);
- $else = null;
- $node = new Twig_Node_If($t, $else, 1);
-
- $tests[] = array($node, <<<EOF
-// line 1
-if (true) {
- echo {$this->getVariableGetter('foo')};
-}
-EOF
- );
-
- $t = new Twig_Node(array(
- new Twig_Node_Expression_Constant(true, 1),
- new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
- new Twig_Node_Expression_Constant(false, 1),
- new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1),
- ), array(), 1);
- $else = null;
- $node = new Twig_Node_If($t, $else, 1);
-
- $tests[] = array($node, <<<EOF
-// line 1
-if (true) {
- echo {$this->getVariableGetter('foo')};
-} elseif (false) {
- echo {$this->getVariableGetter('bar')};
-}
-EOF
- );
-
- $t = new Twig_Node(array(
- new Twig_Node_Expression_Constant(true, 1),
- new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
- ), array(), 1);
- $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1);
- $node = new Twig_Node_If($t, $else, 1);
-
- $tests[] = array($node, <<<EOF
-// line 1
-if (true) {
- echo {$this->getVariableGetter('foo')};
-} else {
- echo {$this->getVariableGetter('bar')};
-}
-EOF
- );
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_ImportTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Import::__construct
- */
- public function testConstructor()
- {
- $macro = new Twig_Node_Expression_Constant('foo.twig', 1);
- $var = new Twig_Node_Expression_AssignName('macro', 1);
- $node = new Twig_Node_Import($macro, $var, 1);
-
- $this->assertEquals($macro, $node->getNode('expr'));
- $this->assertEquals($var, $node->getNode('var'));
- }
-
- /**
- * @covers Twig_Node_Import::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $macro = new Twig_Node_Expression_Constant('foo.twig', 1);
- $var = new Twig_Node_Expression_AssignName('macro', 1);
- $node = new Twig_Node_Import($macro, $var, 1);
-
- $tests[] = array($node, <<<EOF
-// line 1
-\$context["macro"] = \$this->env->loadTemplate("foo.twig");
-EOF
- );
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_IncludeTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Include::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
- $node = new Twig_Node_Include($expr, null, false, false, 1);
-
- $this->assertEquals(null, $node->getNode('variables'));
- $this->assertEquals($expr, $node->getNode('expr'));
- $this->assertFalse($node->getAttribute('only'));
-
- $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1);
- $node = new Twig_Node_Include($expr, $vars, true, false, 1);
- $this->assertEquals($vars, $node->getNode('variables'));
- $this->assertTrue($node->getAttribute('only'));
- }
-
- /**
- * @covers Twig_Node_Include::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
- $node = new Twig_Node_Include($expr, null, false, false, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-\$this->env->loadTemplate("foo.twig")->display(\$context);
-EOF
- );
-
- $expr = new Twig_Node_Expression_Conditional(
- new Twig_Node_Expression_Constant(true, 1),
- new Twig_Node_Expression_Constant('foo', 1),
- new Twig_Node_Expression_Constant('foo', 1),
- 0
- );
- $node = new Twig_Node_Include($expr, null, false, false, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-\$template = \$this->env->resolveTemplate(((true) ? ("foo") : ("foo")));
-\$template->display(\$context);
-EOF
- );
-
- $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
- $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1);
- $node = new Twig_Node_Include($expr, $vars, false, false, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-\$this->env->loadTemplate("foo.twig")->display(array_merge(\$context, array("foo" => true)));
-EOF
- );
-
- $node = new Twig_Node_Include($expr, $vars, true, false, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-\$this->env->loadTemplate("foo.twig")->display(array("foo" => true));
-EOF
- );
-
- $node = new Twig_Node_Include($expr, $vars, true, true, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-try {
- \$this->env->loadTemplate("foo.twig")->display(array("foo" => true));
-} catch (Twig_Error_Loader \$e) {
- // ignore missing template
-}
-EOF
- );
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_MacroTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Macro::__construct
- */
- public function testConstructor()
- {
- $body = new Twig_Node_Text('foo', 1);
- $arguments = new Twig_Node(array(new Twig_Node_Expression_Name('foo', 1)), array(), 1);
- $node = new Twig_Node_Macro('foo', $body, $arguments, 1);
-
- $this->assertEquals($body, $node->getNode('body'));
- $this->assertEquals($arguments, $node->getNode('arguments'));
- $this->assertEquals('foo', $node->getAttribute('name'));
- }
-
- /**
- * @covers Twig_Node_Macro::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $body = new Twig_Node_Text('foo', 1);
- $arguments = new Twig_Node(array(
- 'foo' => new Twig_Node_Expression_Constant(null, 1),
- 'bar' => new Twig_Node_Expression_Constant('Foo', 1),
- ), array(), 1);
- $node = new Twig_Node_Macro('foo', $body, $arguments, 1);
-
- return array(
- array($node, <<<EOF
-// line 1
-public function getfoo(\$_foo = null, \$_bar = "Foo")
-{
- \$context = \$this->env->mergeGlobals(array(
- "foo" => \$_foo,
- "bar" => \$_bar,
- ));
-
- \$blocks = array();
-
- ob_start();
- try {
- echo "foo";
- } catch (Exception \$e) {
- ob_end_clean();
-
- throw \$e;
- }
-
- return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
-}
-EOF
- ),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Module::__construct
- */
- public function testConstructor()
- {
- $body = new Twig_Node_Text('foo', 1);
- $parent = new Twig_Node_Expression_Constant('layout.twig', 1);
- $blocks = new Twig_Node();
- $macros = new Twig_Node();
- $traits = new Twig_Node();
- $filename = 'foo.twig';
- $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
-
- $this->assertEquals($body, $node->getNode('body'));
- $this->assertEquals($blocks, $node->getNode('blocks'));
- $this->assertEquals($macros, $node->getNode('macros'));
- $this->assertEquals($parent, $node->getNode('parent'));
- $this->assertEquals($filename, $node->getAttribute('filename'));
- }
-
- /**
- * @covers Twig_Node_Module::compile
- * @covers Twig_Node_Module::compileTemplate
- * @covers Twig_Node_Module::compileMacros
- * @covers Twig_Node_Module::compileClassHeader
- * @covers Twig_Node_Module::compileDisplayHeader
- * @covers Twig_Node_Module::compileDisplayBody
- * @covers Twig_Node_Module::compileDisplayFooter
- * @covers Twig_Node_Module::compileClassFooter
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $twig = new Twig_Environment(new Twig_Loader_String());
-
- $tests = array();
-
- $body = new Twig_Node_Text('foo', 1);
- $extends = null;
- $blocks = new Twig_Node();
- $macros = new Twig_Node();
- $traits = new Twig_Node();
- $filename = 'foo.twig';
-
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
- $tests[] = array($node, <<<EOF
-<?php
-
-/* foo.twig */
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
-{
- public function __construct(Twig_Environment \$env)
- {
- parent::__construct(\$env);
-
- \$this->parent = false;
-
- \$this->blocks = array(
- );
- }
-
- protected function doDisplay(array \$context, array \$blocks = array())
- {
- // line 1
- echo "foo";
- }
-
- public function getTemplateName()
- {
- return "foo.twig";
- }
-
- public function getDebugInfo()
- {
- return array ( 19 => 1,);
- }
-}
-EOF
- , $twig);
-
- $import = new Twig_Node_Import(new Twig_Node_Expression_Constant('foo.twig', 1), new Twig_Node_Expression_AssignName('macro', 1), 1);
-
- $body = new Twig_Node(array($import));
- $extends = new Twig_Node_Expression_Constant('layout.twig', 1);
-
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
- $tests[] = array($node, <<<EOF
-<?php
-
-/* foo.twig */
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
-{
- public function __construct(Twig_Environment \$env)
- {
- parent::__construct(\$env);
-
- \$this->parent = \$this->env->loadTemplate("layout.twig");
-
- \$this->blocks = array(
- );
- }
-
- protected function doGetParent(array \$context)
- {
- return "layout.twig";
- }
-
- protected function doDisplay(array \$context, array \$blocks = array())
- {
- // line 1
- \$context["macro"] = \$this->env->loadTemplate("foo.twig");
- \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks));
- }
-
- public function getTemplateName()
- {
- return "foo.twig";
- }
-
- public function isTraitable()
- {
- return false;
- }
-
- public function getDebugInfo()
- {
- return array ( 24 => 1,);
- }
-}
-EOF
- , $twig);
-
- $body = new Twig_Node();
- $extends = new Twig_Node_Expression_Conditional(
- new Twig_Node_Expression_Constant(true, 1),
- new Twig_Node_Expression_Constant('foo', 1),
- new Twig_Node_Expression_Constant('foo', 1),
- 0
- );
-
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
- $tests[] = array($node, <<<EOF
-<?php
-
-/* foo.twig */
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
-{
- protected function doGetParent(array \$context)
- {
- return \$this->env->resolveTemplate(((true) ? ("foo") : ("foo")));
- }
-
- protected function doDisplay(array \$context, array \$blocks = array())
- {
- \$this->getParent(\$context)->display(\$context, array_merge(\$this->blocks, \$blocks));
- }
-
- public function getTemplateName()
- {
- return "foo.twig";
- }
-
- public function isTraitable()
- {
- return false;
- }
-
- public function getDebugInfo()
- {
- return array ();
- }
-}
-EOF
- , $twig);
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_PrintTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Print::__construct
- */
- public function testConstructor()
- {
- $expr = new Twig_Node_Expression_Constant('foo', 1);
- $node = new Twig_Node_Print($expr, 1);
-
- $this->assertEquals($expr, $node->getNode('expr'));
- }
-
- /**
- * @covers Twig_Node_Print::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
- $tests[] = array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1), "// line 1\necho \"foo\";");
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_SandboxTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Sandbox::__construct
- */
- public function testConstructor()
- {
- $body = new Twig_Node_Text('foo', 1);
- $node = new Twig_Node_Sandbox($body, 1);
-
- $this->assertEquals($body, $node->getNode('body'));
- }
-
- /**
- * @covers Twig_Node_Sandbox::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $body = new Twig_Node_Text('foo', 1);
- $node = new Twig_Node_Sandbox($body, 1);
-
- $tests[] = array($node, <<<EOF
-// line 1
-\$sandbox = \$this->env->getExtension('sandbox');
-if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {
- \$sandbox->enableSandbox();
-}
-echo "foo";
-if (!\$alreadySandboxed) {
- \$sandbox->disableSandbox();
-}
-EOF
- );
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_SandboxedModuleTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_SandboxedModule::__construct
- */
- public function testConstructor()
- {
- $body = new Twig_Node_Text('foo', 1);
- $parent = new Twig_Node_Expression_Constant('layout.twig', 1);
- $blocks = new Twig_Node();
- $macros = new Twig_Node();
- $traits = new Twig_Node();
- $filename = 'foo.twig';
- $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
- $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
-
- $this->assertEquals($body, $node->getNode('body'));
- $this->assertEquals($blocks, $node->getNode('blocks'));
- $this->assertEquals($macros, $node->getNode('macros'));
- $this->assertEquals($parent, $node->getNode('parent'));
- $this->assertEquals($filename, $node->getAttribute('filename'));
- }
-
- /**
- * @covers Twig_Node_SandboxedModule::compile
- * @covers Twig_Node_SandboxedModule::compileDisplayBody
- * @covers Twig_Node_SandboxedModule::compileDisplayFooter
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $twig = new Twig_Environment(new Twig_Loader_String());
-
- $tests = array();
-
- $body = new Twig_Node_Text('foo', 1);
- $extends = null;
- $blocks = new Twig_Node();
- $macros = new Twig_Node();
- $traits = new Twig_Node();
- $filename = 'foo.twig';
-
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
- $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
-
- $tests[] = array($node, <<<EOF
-<?php
-
-/* foo.twig */
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
-{
- public function __construct(Twig_Environment \$env)
- {
- parent::__construct(\$env);
-
- \$this->parent = false;
-
- \$this->blocks = array(
- );
- }
-
- protected function doDisplay(array \$context, array \$blocks = array())
- {
- \$this->checkSecurity();
- // line 1
- echo "foo";
- }
-
- protected function checkSecurity()
- {
- \$this->env->getExtension('sandbox')->checkSecurity(
- array('upper'),
- array('for'),
- array('cycle')
- );
- }
-
- public function getTemplateName()
- {
- return "foo.twig";
- }
-
- public function getDebugInfo()
- {
- return array ( 20 => 1,);
- }
-}
-EOF
- , $twig);
-
- $body = new Twig_Node();
- $extends = new Twig_Node_Expression_Constant('layout.twig', 1);
- $blocks = new Twig_Node();
- $macros = new Twig_Node();
- $traits = new Twig_Node();
- $filename = 'foo.twig';
-
- $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $filename);
- $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
-
- $tests[] = array($node, <<<EOF
-<?php
-
-/* foo.twig */
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
-{
- public function __construct(Twig_Environment \$env)
- {
- parent::__construct(\$env);
-
- \$this->parent = \$this->env->loadTemplate("layout.twig");
-
- \$this->blocks = array(
- );
- }
-
- protected function doGetParent(array \$context)
- {
- return "layout.twig";
- }
-
- protected function doDisplay(array \$context, array \$blocks = array())
- {
- \$this->checkSecurity();
- \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks));
- }
-
- protected function checkSecurity()
- {
- \$this->env->getExtension('sandbox')->checkSecurity(
- array('upper'),
- array('for'),
- array('cycle')
- );
- }
-
- public function getTemplateName()
- {
- return "foo.twig";
- }
-
- public function isTraitable()
- {
- return false;
- }
-
- public function getDebugInfo()
- {
- return array ();
- }
-}
-EOF
- , $twig);
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_SandboxedPrintTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_SandboxedPrint::__construct
- */
- public function testConstructor()
- {
- $node = new Twig_Node_SandboxedPrint($expr = new Twig_Node_Expression_Constant('foo', 1), 1);
-
- $this->assertEquals($expr, $node->getNode('expr'));
- }
-
- /**
- * @covers Twig_Node_SandboxedPrint::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $tests[] = array(new Twig_Node_SandboxedPrint(new Twig_Node_Expression_Constant('foo', 1), 1), <<<EOF
-// line 1
-echo \$this->env->getExtension('sandbox')->ensureToStringAllowed("foo");
-EOF
- );
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_SetTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Set::__construct
- */
- public function testConstructor()
- {
- $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
- $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1);
- $node = new Twig_Node_Set(false, $names, $values, 1);
-
- $this->assertEquals($names, $node->getNode('names'));
- $this->assertEquals($values, $node->getNode('values'));
- $this->assertEquals(false, $node->getAttribute('capture'));
- }
-
- /**
- * @covers Twig_Node_Set::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
-
- $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
- $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1);
- $node = new Twig_Node_Set(false, $names, $values, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-\$context["foo"] = "foo";
-EOF
- );
-
- $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
- $values = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1)), array(), 1);
- $node = new Twig_Node_Set(true, $names, $values, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-ob_start();
-echo "foo";
-\$context["foo"] = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
-EOF
- );
-
- $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
- $values = new Twig_Node_Text('foo', 1);
- $node = new Twig_Node_Set(true, $names, $values, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-\$context["foo"] = ('' === \$tmp = "foo") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
-EOF
- );
-
- $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1), new Twig_Node_Expression_AssignName('bar', 1)), array(), 1);
- $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Name('bar', 1)), array(), 1);
- $node = new Twig_Node_Set(false, $names, $values, 1);
- $tests[] = array($node, <<<EOF
-// line 1
-list(\$context["foo"], \$context["bar"]) = array("foo", {$this->getVariableGetter('bar')});
-EOF
- );
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_SpacelessTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Spaceless::__construct
- */
- public function testConstructor()
- {
- $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1)));
- $node = new Twig_Node_Spaceless($body, 1);
-
- $this->assertEquals($body, $node->getNode('body'));
- }
-
- /**
- * @covers Twig_Node_Spaceless::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1)));
- $node = new Twig_Node_Spaceless($body, 1);
-
- return array(
- array($node, <<<EOF
-// line 1
-ob_start();
-echo "<div> <div> foo </div> </div>";
-echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));
-EOF
- ),
- );
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_Node_TextTest extends Twig_Test_NodeTestCase
-{
- /**
- * @covers Twig_Node_Text::__construct
- */
- public function testConstructor()
- {
- $node = new Twig_Node_Text('foo', 1);
-
- $this->assertEquals('foo', $node->getAttribute('data'));
- }
-
- /**
- * @covers Twig_Node_Text::compile
- * @dataProvider getTests
- */
- public function testCompile($node, $source, $environment = null)
- {
- parent::testCompile($node, $source, $environment);
- }
-
- public function getTests()
- {
- $tests = array();
- $tests[] = array(new Twig_Node_Text('foo', 1), "// line 1\necho \"foo\";");
-
- return $tests;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
-{
- public function testRenderBlockOptimizer()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
-
- $stream = $env->parse($env->tokenize('{{ block("foo") }}', 'index'));
-
- $node = $stream->getNode('body')->getNode(0);
-
- $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node));
- $this->assertTrue($node->getAttribute('output'));
- }
-
- public function testRenderParentBlockOptimizer()
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
-
- $stream = $env->parse($env->tokenize('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index'));
-
- $node = $stream->getNode('blocks')->getNode('content')->getNode(0)->getNode('body');
-
- $this->assertEquals('Twig_Node_Expression_Parent', get_class($node));
- $this->assertTrue($node->getAttribute('output'));
- }
-
- public function testRenderVariableBlockOptimizer()
- {
- if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
- return;
- }
-
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false, 'autoescape' => false));
- $stream = $env->parse($env->tokenize('{{ block(name|lower) }}', 'index'));
-
- $node = $stream->getNode('body')->getNode(0)->getNode(1);
-
- $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node));
- $this->assertTrue($node->getAttribute('output'));
- }
-
- /**
- * @dataProvider getTestsForForOptimizer
- */
- public function testForOptimizer($template, $expected)
- {
- $env = new Twig_Environment(new Twig_Loader_String(), array('cache' => false));
-
- $stream = $env->parse($env->tokenize($template, 'index'));
-
- foreach ($expected as $target => $withLoop) {
- $this->assertTrue($this->checkForConfiguration($stream, $target, $withLoop), sprintf('variable %s is %soptimized', $target, $withLoop ? 'not ' : ''));
- }
- }
-
- public function getTestsForForOptimizer()
- {
- return array(
- array('{% for i in foo %}{% endfor %}', array('i' => false)),
-
- array('{% for i in foo %}{{ loop.index }}{% endfor %}', array('i' => true)),
-
- array('{% for i in foo %}{% for j in foo %}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
-
- array('{% for i in foo %}{% include "foo" %}{% endfor %}', array('i' => true)),
-
- array('{% for i in foo %}{% include "foo" only %}{% endfor %}', array('i' => false)),
-
- array('{% for i in foo %}{% include "foo" with { "foo": "bar" } only %}{% endfor %}', array('i' => false)),
-
- array('{% for i in foo %}{% include "foo" with { "foo": loop.index } only %}{% endfor %}', array('i' => true)),
-
- array('{% for i in foo %}{% for j in foo %}{{ loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => true)),
-
- array('{% for i in foo %}{% for j in foo %}{{ loop.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
-
- array('{% for i in foo %}{% set l = loop %}{% for j in foo %}{{ l.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => false)),
-
- array('{% for i in foo %}{% for j in foo %}{{ foo.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
-
- array('{% for i in foo %}{% for j in foo %}{{ loop["parent"].loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
- );
- }
-
- public function checkForConfiguration(Twig_NodeInterface $node = null, $target, $withLoop)
- {
- if (null === $node) {
- return;
- }
-
- foreach ($node as $n) {
- if ($n instanceof Twig_Node_For) {
- if ($target === $n->getNode('value_target')->getAttribute('name')) {
- return $withLoop == $n->getAttribute('with_loop');
- }
- }
-
- $ret = $this->checkForConfiguration($n, $target, $withLoop);
- if (null !== $ret) {
- return $ret;
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Tests_ParserTest extends PHPUnit_Framework_TestCase
-{
- /**
- * @expectedException Twig_Error_Syntax
- */
- public function testSetMacroThrowsExceptionOnReservedMethods()
- {
- $parser = $this->getParser();
- $parser->setMacro('display', $this->getMock('Twig_Node_Macro', array(), array(), '', null));
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage Unknown tag name "foo". Did you mean "for" at line 1
- */
- public function testUnknownTag()
- {
- $stream = new Twig_TokenStream(array(
- new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
- new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1),
- new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
- new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
- ));
- $parser = new Twig_Parser(new Twig_Environment());
- $parser->parse($stream);
- }
-
- /**
- * @dataProvider getFilterBodyNodesData
- */
- public function testFilterBodyNodes($input, $expected)
- {
- $parser = $this->getParser();
-
- $this->assertEquals($expected, $parser->filterBodyNodes($input));
- }
-
- public function getFilterBodyNodesData()
- {
- return array(
- array(
- new Twig_Node(array(new Twig_Node_Text(' ', 1))),
- new Twig_Node(array()),
- ),
- array(
- $input = new Twig_Node(array(new Twig_Node_Set(false, new Twig_Node(), new Twig_Node(), 1))),
- $input,
- ),
- array(
- $input = new Twig_Node(array(new Twig_Node_Set(true, new Twig_Node(), new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1))))), 1))),
- $input,
- ),
- );
- }
-
- /**
- * @dataProvider getFilterBodyNodesDataThrowsException
- * @expectedException Twig_Error_Syntax
- */
- public function testFilterBodyNodesThrowsException($input)
- {
- $parser = $this->getParser();
-
- $parser->filterBodyNodes($input);
- }
-
- public function getFilterBodyNodesDataThrowsException()
- {
- return array(
- array(new Twig_Node_Text('foo', 1)),
- array(new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1)))))),
- );
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedExceptionMessage A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed at line 1.
- */
- public function testFilterBodyNodesWithBOM()
- {
- $parser = $this->getParser();
- $parser->filterBodyNodes(new Twig_Node_Text(chr(0xEF).chr(0xBB).chr(0xBF), 1));
- }
-
- public function testParseIsReentrant()
- {
- $twig = new Twig_Environment(null, array(
- 'autoescape' => false,
- 'optimizations' => 0,
- ));
- $twig->addTokenParser(new TestTokenParser());
-
- $parser = new Twig_Parser($twig);
-
- $parser->parse(new Twig_TokenStream(array(
- new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
- new Twig_Token(Twig_Token::NAME_TYPE, 'test', 1),
- new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
- new Twig_Token(Twig_Token::VAR_START_TYPE, '', 1),
- new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1),
- new Twig_Token(Twig_Token::VAR_END_TYPE, '', 1),
- new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
- )));
-
- $this->assertEquals(null, $parser->getParent());
- }
-
- // The getVarName() must not depend on the template loaders,
- // If this test does not throw any exception, that's good.
- // see https://github.com/symfony/symfony/issues/4218
- public function testGetVarName()
- {
- $twig = new Twig_Environment(null, array(
- 'autoescape' => false,
- 'optimizations' => 0,
- ));
-
- $twig->parse($twig->tokenize(<<<EOF
-{% from _self import foo %}
-
-{% macro foo() %}
- {{ foo }}
-{% endmacro %}
-EOF
- ));
- }
-
- protected function getParser()
- {
- $parser = new TestParser(new Twig_Environment());
- $parser->setParent(new Twig_Node());
- $parser->stream = $this->getMockBuilder('Twig_TokenStream')->disableOriginalConstructor()->getMock();
-
- return $parser;
- }
-}
-
-class TestParser extends Twig_Parser
-{
- public $stream;
-
- public function filterBodyNodes(Twig_NodeInterface $node)
- {
- return parent::filterBodyNodes($node);
- }
-}
-
-class TestTokenParser extends Twig_TokenParser
-{
- public function parse(Twig_Token $token)
- {
- // simulate the parsing of another template right in the middle of the parsing of the current template
- $this->parser->parse(new Twig_TokenStream(array(
- new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
- new Twig_Token(Twig_Token::NAME_TYPE, 'extends', 1),
- new Twig_Token(Twig_Token::STRING_TYPE, 'base', 1),
- new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
- new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
- )));
-
- $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
-
- return new Twig_Node(array());
- }
-
- public function getTag()
- {
- return 'test';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
-{
- /**
- * @dataProvider getAttributeExceptions
- */
- public function testGetAttributeExceptions($template, $message, $useExt)
- {
- $name = 'index_'.($useExt ? 1 : 0);
- $templates = array(
- $name => $template.$useExt, // appending $useExt makes the template content unique
- );
-
- $env = new Twig_Environment(new Twig_Loader_Array($templates), array('strict_variables' => true));
- if (!$useExt) {
- $env->addNodeVisitor(new CExtDisablingNodeVisitor());
- }
- $template = $env->loadTemplate($name);
-
- $context = array(
- 'string' => 'foo',
- 'array' => array('foo' => 'foo'),
- 'array_access' => new Twig_TemplateArrayAccessObject(),
- 'magic_exception' => new Twig_TemplateMagicPropertyObjectWithException(),
- );
-
- try {
- $template->render($context);
- $this->fail('Accessing an invalid attribute should throw an exception.');
- } catch (Twig_Error_Runtime $e) {
- $this->assertSame(sprintf($message, $name), $e->getMessage());
- }
- }
-
- public function getAttributeExceptions()
- {
- $tests = array(
- array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1', false),
- array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
- array('{{ array_access["a"] }}', 'Key "a" in object (with ArrayAccess) of type "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
- array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1', false),
- array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1', false),
- array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
- array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1', false),
- array('{{ array_access.a }}', 'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
- array('{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}', 'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
- array('{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.', false),
- );
-
- if (function_exists('twig_template_get_attributes')) {
- foreach (array_slice($tests, 0) as $test) {
- $test[2] = true;
- $tests[] = $test;
- }
- }
-
- return $tests;
- }
-
- /**
- * @dataProvider getGetAttributeWithSandbox
- */
- public function testGetAttributeWithSandbox($object, $item, $allowed, $useExt)
- {
- $twig = new Twig_Environment();
- $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(/*method*/), array(/*prop*/), array());
- $twig->addExtension(new Twig_Extension_Sandbox($policy, !$allowed));
- $template = new Twig_TemplateTest($twig, $useExt);
-
- try {
- $template->getAttribute($object, $item, array(), 'any');
-
- if (!$allowed) {
- $this->fail();
- }
- } catch (Twig_Sandbox_SecurityError $e) {
- if ($allowed) {
- $this->fail();
- }
-
- $this->assertContains('is not allowed', $e->getMessage());
- }
- }
-
- public function getGetAttributeWithSandbox()
- {
- $tests = array(
- array(new Twig_TemplatePropertyObject(), 'defined', false, false),
- array(new Twig_TemplatePropertyObject(), 'defined', true, false),
- array(new Twig_TemplateMethodObject(), 'defined', false, false),
- array(new Twig_TemplateMethodObject(), 'defined', true, false),
- );
-
- if (function_exists('twig_template_get_attributes')) {
- foreach (array_slice($tests, 0) as $test) {
- $test[3] = true;
- $tests[] = $test;
- }
- }
-
- return $tests;
- }
-
- /**
- * @dataProvider getGetAttributeWithTemplateAsObject
- */
- public function testGetAttributeWithTemplateAsObject($useExt)
- {
- $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
- $template1 = new Twig_TemplateTest(new Twig_Environment(), false);
-
- $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string'));
- $this->assertEquals('some_string', $template->getAttribute($template1, 'string'));
-
- $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true'));
- $this->assertEquals('1', $template->getAttribute($template1, 'true'));
-
- $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero'));
- $this->assertEquals('0', $template->getAttribute($template1, 'zero'));
-
- $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty'));
- $this->assertSame('', $template->getAttribute($template1, 'empty'));
- }
-
- public function getGetAttributeWithTemplateAsObject()
- {
- $bools = array(
- array(false),
- );
-
- if (function_exists('twig_template_get_attributes')) {
- $bools[] = array(true);
- }
-
- return $bools;
- }
-
- /**
- * @dataProvider getTestsDependingOnExtensionAvailability
- */
- public function testGetAttributeOnArrayWithConfusableKey($useExt = false)
- {
- $template = new Twig_TemplateTest(
- new Twig_Environment(),
- $useExt
- );
-
- $array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros');
-
- $this->assertSame('Zero', $array[false]);
- $this->assertSame('One', $array[true]);
- $this->assertSame('One', $array[1.5]);
- $this->assertSame('One', $array['1']);
- $this->assertSame('MinusOne', $array[-1.5]);
- $this->assertSame('FloatButString', $array['1.5']);
- $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']);
- $this->assertSame('EmptyString', $array[null]);
-
- $this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)');
- $this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)');
- $this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)');
- $this->assertSame('One', $template->getAttribute($array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)');
- $this->assertSame('MinusOne', $template->getAttribute($array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)');
- $this->assertSame('FloatButString', $template->getAttribute($array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)');
- $this->assertSame('IntegerButStringWithLeadingZeros', $template->getAttribute($array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)');
- $this->assertSame('EmptyString', $template->getAttribute($array, null), 'null is treated as "" when accessing an array (equals PHP behavior)');
- }
-
- public function getTestsDependingOnExtensionAvailability()
- {
- if (function_exists('twig_template_get_attributes')) {
- return array(array(false), array(true));
- }
-
- return array(array(false));
- }
-
- /**
- * @dataProvider getGetAttributeTests
- */
- public function testGetAttribute($defined, $value, $object, $item, $arguments, $type, $useExt = false)
- {
- $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
-
- $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
- }
-
- /**
- * @dataProvider getGetAttributeTests
- */
- public function testGetAttributeStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false, $exceptionMessage = null)
- {
- $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt);
-
- if ($defined) {
- $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
- } else {
- try {
- $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
-
- throw new Exception('Expected Twig_Error_Runtime exception.');
- } catch (Twig_Error_Runtime $e) {
- if (null !== $exceptionMessage) {
- $this->assertSame($exceptionMessage, $e->getMessage());
- }
- }
- }
- }
-
- /**
- * @dataProvider getGetAttributeTests
- */
- public function testGetAttributeDefined($defined, $value, $object, $item, $arguments, $type, $useExt = false)
- {
- $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
-
- $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
- }
-
- /**
- * @dataProvider getGetAttributeTests
- */
- public function testGetAttributeDefinedStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false)
- {
- $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt);
-
- $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
- }
-
- public function getGetAttributeTests()
- {
- $array = array(
- 'defined' => 'defined',
- 'zero' => 0,
- 'null' => null,
- '1' => 1,
- 'bar' => true,
- '09' => '09',
- '+4' => '+4',
- );
-
- $objectArray = new Twig_TemplateArrayAccessObject();
- $stdObject = (object) $array;
- $magicPropertyObject = new Twig_TemplateMagicPropertyObject();
- $propertyObject = new Twig_TemplatePropertyObject();
- $propertyObject1 = new Twig_TemplatePropertyObjectAndIterator();
- $propertyObject2 = new Twig_TemplatePropertyObjectAndArrayAccess();
- $methodObject = new Twig_TemplateMethodObject();
- $magicMethodObject = new Twig_TemplateMagicMethodObject();
-
- $anyType = Twig_TemplateInterface::ANY_CALL;
- $methodType = Twig_TemplateInterface::METHOD_CALL;
- $arrayType = Twig_TemplateInterface::ARRAY_CALL;
-
- $basicTests = array(
- // array(defined, value, property to fetch)
- array(true, 'defined', 'defined'),
- array(false, null, 'undefined'),
- array(false, null, 'protected'),
- array(true, 0, 'zero'),
- array(true, 1, 1),
- array(true, 1, 1.0),
- array(true, null, 'null'),
- array(true, true, 'bar'),
- array(true, '09', '09'),
- array(true, '+4', '+4'),
- );
- $testObjects = array(
- // array(object, type of fetch)
- array($array, $arrayType),
- array($objectArray, $arrayType),
- array($stdObject, $anyType),
- array($magicPropertyObject, $anyType),
- array($methodObject, $methodType),
- array($methodObject, $anyType),
- array($propertyObject, $anyType),
- array($propertyObject1, $anyType),
- array($propertyObject2, $anyType),
- );
-
- $tests = array();
- foreach ($testObjects as $testObject) {
- foreach ($basicTests as $test) {
- // properties cannot be numbers
- if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) {
- continue;
- }
-
- if ('+4' === $test[2] && $methodObject === $testObject[0]) {
- continue;
- }
-
- $tests[] = array($test[0], $test[1], $testObject[0], $test[2], array(), $testObject[1]);
- }
- }
-
- // additional method tests
- $tests = array_merge($tests, array(
- array(true, 'defined', $methodObject, 'defined', array(), $methodType),
- array(true, 'defined', $methodObject, 'DEFINED', array(), $methodType),
- array(true, 'defined', $methodObject, 'getDefined', array(), $methodType),
- array(true, 'defined', $methodObject, 'GETDEFINED', array(), $methodType),
- array(true, 'static', $methodObject, 'static', array(), $methodType),
- array(true, 'static', $methodObject, 'getStatic', array(), $methodType),
-
- array(true, '__call_undefined', $magicMethodObject, 'undefined', array(), $methodType),
- array(true, '__call_UNDEFINED', $magicMethodObject, 'UNDEFINED', array(), $methodType),
- ));
-
- // add the same tests for the any type
- foreach ($tests as $test) {
- if ($anyType !== $test[5]) {
- $test[5] = $anyType;
- $tests[] = $test;
- }
- }
-
- $methodAndPropObject = new Twig_TemplateMethodAndPropObject;
-
- // additional method tests
- $tests = array_merge($tests, array(
- array(true, 'a', $methodAndPropObject, 'a', array(), $anyType),
- array(true, 'a', $methodAndPropObject, 'a', array(), $methodType),
- array(false, null, $methodAndPropObject, 'a', array(), $arrayType),
-
- array(true, 'b_prop', $methodAndPropObject, 'b', array(), $anyType),
- array(true, 'b', $methodAndPropObject, 'B', array(), $anyType),
- array(true, 'b', $methodAndPropObject, 'b', array(), $methodType),
- array(true, 'b', $methodAndPropObject, 'B', array(), $methodType),
- array(false, null, $methodAndPropObject, 'b', array(), $arrayType),
-
- array(false, null, $methodAndPropObject, 'c', array(), $anyType),
- array(false, null, $methodAndPropObject, 'c', array(), $methodType),
- array(false, null, $methodAndPropObject, 'c', array(), $arrayType),
-
- ));
-
- // tests when input is not an array or object
- $tests = array_merge($tests, array(
- array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42")'),
- array(false, null, "string", 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string")'),
- array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" for array with keys "" does not exist'),
- ));
-
- // add twig_template_get_attributes tests
-
- if (function_exists('twig_template_get_attributes')) {
- foreach (array_slice($tests, 0) as $test) {
- $test = array_pad($test, 7, null);
- $test[6] = true;
- $tests[] = $test;
- }
- }
-
- return $tests;
- }
-}
-
-class Twig_TemplateTest extends Twig_Template
-{
- protected $useExtGetAttribute = false;
-
- public function __construct(Twig_Environment $env, $useExtGetAttribute = false)
- {
- parent::__construct($env);
- $this->useExtGetAttribute = $useExtGetAttribute;
- Twig_Template::clearCache();
- }
-
- public function getZero()
- {
- return 0;
- }
-
- public function getEmpty()
- {
- return '';
- }
-
- public function getString()
- {
- return 'some_string';
- }
-
- public function getTrue()
- {
- return true;
- }
-
- public function getTemplateName()
- {
- }
-
- public function getDebugInfo()
- {
- return array();
- }
-
- protected function doGetParent(array $context)
- {
- }
-
- protected function doDisplay(array $context, array $blocks = array())
- {
- }
-
- public function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
- {
- if ($this->useExtGetAttribute) {
- return twig_template_get_attributes($this, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
- } else {
- return parent::getAttribute($object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
- }
- }
-}
-
-class Twig_TemplateArrayAccessObject implements ArrayAccess
-{
- protected $protected = 'protected';
-
- public $attributes = array(
- 'defined' => 'defined',
- 'zero' => 0,
- 'null' => null,
- '1' => 1,
- 'bar' => true,
- '09' => '09',
- '+4' => '+4',
- );
-
- public function offsetExists($name)
- {
- return array_key_exists($name, $this->attributes);
- }
-
- public function offsetGet($name)
- {
- return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
- }
-
- public function offsetSet($name, $value)
- {
- }
-
- public function offsetUnset($name)
- {
- }
-}
-
-class Twig_TemplateMagicPropertyObject
-{
- public $defined = 'defined';
-
- public $attributes = array(
- 'zero' => 0,
- 'null' => null,
- '1' => 1,
- 'bar' => true,
- '09' => '09',
- '+4' => '+4',
- );
-
- protected $protected = 'protected';
-
- public function __isset($name)
- {
- return array_key_exists($name, $this->attributes);
- }
-
- public function __get($name)
- {
- return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
- }
-}
-
-class Twig_TemplateMagicPropertyObjectWithException
-{
- public function __isset($key)
- {
- throw new Exception("Hey! Don't try to isset me!");
- }
-}
-
-class Twig_TemplatePropertyObject
-{
- public $defined = 'defined';
- public $zero = 0;
- public $null = null;
- public $bar = true;
-
- protected $protected = 'protected';
-}
-
-class Twig_TemplatePropertyObjectAndIterator extends Twig_TemplatePropertyObject implements IteratorAggregate
-{
- public function getIterator()
- {
- return new ArrayIterator(array('foo', 'bar'));
- }
-}
-
-class Twig_TemplatePropertyObjectAndArrayAccess extends Twig_TemplatePropertyObject implements ArrayAccess
-{
- private $data = array();
-
- public function offsetExists($offset)
- {
- return array_key_exists($offset, $this->data);
- }
-
- public function offsetGet($offset)
- {
- return $this->offsetExists($offset) ? $this->data[$offset] : 'n/a';
- }
-
- public function offsetSet($offset, $value)
- {
- }
-
- public function offsetUnset($offset)
- {
- }
-}
-
-class Twig_TemplateMethodObject
-{
- public function getDefined()
- {
- return 'defined';
- }
-
- public function get1()
- {
- return 1;
- }
-
- public function get09()
- {
- return '09';
- }
-
- public function getZero()
- {
- return 0;
- }
-
- public function getNull()
- {
- return null;
- }
-
- public function isBar()
- {
- return true;
- }
-
- protected function getProtected()
- {
- return 'protected';
- }
-
- public static function getStatic()
- {
- return 'static';
- }
-}
-
-class Twig_TemplateMethodAndPropObject
-{
- private $a = 'a_prop';
- public function getA()
- {
- return 'a';
- }
-
- public $b = 'b_prop';
- public function getB()
- {
- return 'b';
- }
-
- private $c = 'c_prop';
- private function getC()
- {
- return 'c';
- }
-}
-
-class Twig_TemplateMagicMethodObject
-{
- public function __call($method, $arguments)
- {
- return '__call_'.$method;
- }
-}
-
-class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface
-{
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Expression_GetAttr) {
- $node->setAttribute('disable_c_ext', true);
- }
-
- return $node;
- }
-
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- return $node;
- }
-
- public function getPriority()
- {
- return 0;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-class Twig_Tests_TokenStreamTest extends PHPUnit_Framework_TestCase
-{
- protected static $tokens;
-
- public function setUp()
- {
- self::$tokens = array(
- new Twig_Token(Twig_Token::TEXT_TYPE, 1, 1),
- new Twig_Token(Twig_Token::TEXT_TYPE, 2, 1),
- new Twig_Token(Twig_Token::TEXT_TYPE, 3, 1),
- new Twig_Token(Twig_Token::TEXT_TYPE, 4, 1),
- new Twig_Token(Twig_Token::TEXT_TYPE, 5, 1),
- new Twig_Token(Twig_Token::TEXT_TYPE, 6, 1),
- new Twig_Token(Twig_Token::TEXT_TYPE, 7, 1),
- new Twig_Token(Twig_Token::EOF_TYPE, 0, 1),
- );
- }
-
- public function testNext()
- {
- $stream = new Twig_TokenStream(self::$tokens);
- $repr = array();
- while (!$stream->isEOF()) {
- $token = $stream->next();
-
- $repr[] = $token->getValue();
- }
- $this->assertEquals('1, 2, 3, 4, 5, 6, 7', implode(', ', $repr), '->next() advances the pointer and returns the current token');
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedMessage Unexpected end of template
- */
- public function testEndOfTemplateNext()
- {
- $stream = new Twig_TokenStream(array(
- new Twig_Token(Twig_Token::BLOCK_START_TYPE, 1, 1),
- ));
- while (!$stream->isEOF()) {
- $stream->next();
- }
- }
-
- /**
- * @expectedException Twig_Error_Syntax
- * @expectedMessage Unexpected end of template
- */
- public function testEndOfTemplateLook()
- {
- $stream = new Twig_TokenStream(array(
- new Twig_Token(Twig_Token::BLOCK_START_TYPE, 1, 1),
- ));
- while (!$stream->isEOF()) {
- $stream->look();
- $stream->next();
- }
- }
-}
+++ /dev/null
-<?php
-
-/**
- * This class is adapted from code coming from Zend Framework.
- *
- * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
-
-class Twig_Test_EscapingTest extends PHPUnit_Framework_TestCase
-{
- /**
- * All character encodings supported by htmlspecialchars()
- */
- protected $htmlSpecialChars = array(
- '\'' => ''',
- '"' => '"',
- '<' => '<',
- '>' => '>',
- '&' => '&'
- );
-
- protected $htmlAttrSpecialChars = array(
- '\'' => ''',
- /* Characters beyond ASCII value 255 to unicode escape */
- 'Ā' => 'Ā',
- /* Immune chars excluded */
- ',' => ',',
- '.' => '.',
- '-' => '-',
- '_' => '_',
- /* Basic alnums excluded */
- 'a' => 'a',
- 'A' => 'A',
- 'z' => 'z',
- 'Z' => 'Z',
- '0' => '0',
- '9' => '9',
- /* Basic control characters and null */
- "\r" => '
',
- "\n" => '
',
- "\t" => '	',
- "\0" => '�', // should use Unicode replacement char
- /* Encode chars as named entities where possible */
- '<' => '<',
- '>' => '>',
- '&' => '&',
- '"' => '"',
- /* Encode spaces for quoteless attribute protection */
- ' ' => ' ',
- );
-
- protected $jsSpecialChars = array(
- /* HTML special chars - escape without exception to hex */
- '<' => '\\x3C',
- '>' => '\\x3E',
- '\'' => '\\x27',
- '"' => '\\x22',
- '&' => '\\x26',
- /* Characters beyond ASCII value 255 to unicode escape */
- 'Ā' => '\\u0100',
- /* Immune chars excluded */
- ',' => ',',
- '.' => '.',
- '_' => '_',
- /* Basic alnums excluded */
- 'a' => 'a',
- 'A' => 'A',
- 'z' => 'z',
- 'Z' => 'Z',
- '0' => '0',
- '9' => '9',
- /* Basic control characters and null */
- "\r" => '\\x0D',
- "\n" => '\\x0A',
- "\t" => '\\x09',
- "\0" => '\\x00',
- /* Encode spaces for quoteless attribute protection */
- ' ' => '\\x20',
- );
-
- protected $urlSpecialChars = array(
- /* HTML special chars - escape without exception to percent encoding */
- '<' => '%3C',
- '>' => '%3E',
- '\'' => '%27',
- '"' => '%22',
- '&' => '%26',
- /* Characters beyond ASCII value 255 to hex sequence */
- 'Ā' => '%C4%80',
- /* Punctuation and unreserved check */
- ',' => '%2C',
- '.' => '.',
- '_' => '_',
- '-' => '-',
- ':' => '%3A',
- ';' => '%3B',
- '!' => '%21',
- /* Basic alnums excluded */
- 'a' => 'a',
- 'A' => 'A',
- 'z' => 'z',
- 'Z' => 'Z',
- '0' => '0',
- '9' => '9',
- /* Basic control characters and null */
- "\r" => '%0D',
- "\n" => '%0A',
- "\t" => '%09',
- "\0" => '%00',
- /* PHP quirks from the past */
- ' ' => '%20',
- '~' => '~',
- '+' => '%2B',
- );
-
- protected $cssSpecialChars = array(
- /* HTML special chars - escape without exception to hex */
- '<' => '\\3C ',
- '>' => '\\3E ',
- '\'' => '\\27 ',
- '"' => '\\22 ',
- '&' => '\\26 ',
- /* Characters beyond ASCII value 255 to unicode escape */
- 'Ā' => '\\100 ',
- /* Immune chars excluded */
- ',' => '\\2C ',
- '.' => '\\2E ',
- '_' => '\\5F ',
- /* Basic alnums excluded */
- 'a' => 'a',
- 'A' => 'A',
- 'z' => 'z',
- 'Z' => 'Z',
- '0' => '0',
- '9' => '9',
- /* Basic control characters and null */
- "\r" => '\\D ',
- "\n" => '\\A ',
- "\t" => '\\9 ',
- "\0" => '\\0 ',
- /* Encode spaces for quoteless attribute protection */
- ' ' => '\\20 ',
- );
-
- protected $env;
-
- public function setUp()
- {
- $this->env = new Twig_Environment();
- }
-
- public function testHtmlEscapingConvertsSpecialChars()
- {
- foreach ($this->htmlSpecialChars as $key => $value) {
- $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html'), 'Failed to escape: '.$key);
- }
- }
-
- public function testHtmlAttributeEscapingConvertsSpecialChars()
- {
- foreach ($this->htmlAttrSpecialChars as $key => $value) {
- $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html_attr'), 'Failed to escape: '.$key);
- }
- }
-
- public function testJavascriptEscapingConvertsSpecialChars()
- {
- foreach ($this->jsSpecialChars as $key => $value) {
- $this->assertEquals($value, twig_escape_filter($this->env, $key, 'js'), 'Failed to escape: '.$key);
- }
- }
-
- public function testJavascriptEscapingReturnsStringIfZeroLength()
- {
- $this->assertEquals('', twig_escape_filter($this->env, '', 'js'));
- }
-
- public function testJavascriptEscapingReturnsStringIfContainsOnlyDigits()
- {
- $this->assertEquals('123', twig_escape_filter($this->env, '123', 'js'));
- }
-
- public function testCssEscapingConvertsSpecialChars()
- {
- foreach ($this->cssSpecialChars as $key => $value) {
- $this->assertEquals($value, twig_escape_filter($this->env, $key, 'css'), 'Failed to escape: '.$key);
- }
- }
-
- public function testCssEscapingReturnsStringIfZeroLength()
- {
- $this->assertEquals('', twig_escape_filter($this->env, '', 'css'));
- }
-
- public function testCssEscapingReturnsStringIfContainsOnlyDigits()
- {
- $this->assertEquals('123', twig_escape_filter($this->env, '123', 'css'));
- }
-
- public function testUrlEscapingConvertsSpecialChars()
- {
- foreach ($this->urlSpecialChars as $key => $value) {
- $this->assertEquals($value, twig_escape_filter($this->env, $key, 'url'), 'Failed to escape: '.$key);
- }
- }
-
- /**
- * Range tests to confirm escaped range of characters is within OWASP recommendation
- */
-
- /**
- * Only testing the first few 2 ranges on this prot. function as that's all these
- * other range tests require
- */
- public function testUnicodeCodepointConversionToUtf8()
- {
- $expected = " ~ޙ";
- $codepoints = array(0x20, 0x7e, 0x799);
- $result = '';
- foreach ($codepoints as $value) {
- $result .= $this->codepointToUtf8($value);
- }
- $this->assertEquals($expected, $result);
- }
-
- /**
- * Convert a Unicode Codepoint to a literal UTF-8 character.
- *
- * @param int Unicode codepoint in hex notation
- * @return string UTF-8 literal string
- */
- protected function codepointToUtf8($codepoint)
- {
- if ($codepoint < 0x80) {
- return chr($codepoint);
- }
- if ($codepoint < 0x800) {
- return chr($codepoint >> 6 & 0x3f | 0xc0)
- . chr($codepoint & 0x3f | 0x80);
- }
- if ($codepoint < 0x10000) {
- return chr($codepoint >> 12 & 0x0f | 0xe0)
- . chr($codepoint >> 6 & 0x3f | 0x80)
- . chr($codepoint & 0x3f | 0x80);
- }
- if ($codepoint < 0x110000) {
- return chr($codepoint >> 18 & 0x07 | 0xf0)
- . chr($codepoint >> 12 & 0x3f | 0x80)
- . chr($codepoint >> 6 & 0x3f | 0x80)
- . chr($codepoint & 0x3f | 0x80);
- }
- throw new Exception('Codepoint requested outside of Unicode range');
- }
-
- public function testJavascriptEscapingEscapesOwaspRecommendedRanges()
- {
- $immune = array(',', '.', '_'); // Exceptions to escaping ranges
- for ($chr=0; $chr < 0xFF; $chr++) {
- if ($chr >= 0x30 && $chr <= 0x39
- || $chr >= 0x41 && $chr <= 0x5A
- || $chr >= 0x61 && $chr <= 0x7A) {
- $literal = $this->codepointToUtf8($chr);
- $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
- } else {
- $literal = $this->codepointToUtf8($chr);
- if (in_array($literal, $immune)) {
- $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
- } else {
- $this->assertNotEquals(
- $literal,
- twig_escape_filter($this->env, $literal, 'js'),
- "$literal should be escaped!");
- }
- }
- }
- }
-
- public function testHtmlAttributeEscapingEscapesOwaspRecommendedRanges()
- {
- $immune = array(',', '.', '-', '_'); // Exceptions to escaping ranges
- for ($chr=0; $chr < 0xFF; $chr++) {
- if ($chr >= 0x30 && $chr <= 0x39
- || $chr >= 0x41 && $chr <= 0x5A
- || $chr >= 0x61 && $chr <= 0x7A) {
- $literal = $this->codepointToUtf8($chr);
- $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
- } else {
- $literal = $this->codepointToUtf8($chr);
- if (in_array($literal, $immune)) {
- $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
- } else {
- $this->assertNotEquals(
- $literal,
- twig_escape_filter($this->env, $literal, 'html_attr'),
- "$literal should be escaped!");
- }
- }
- }
- }
-
- public function testCssEscapingEscapesOwaspRecommendedRanges()
- {
- $immune = array(); // CSS has no exceptions to escaping ranges
- for ($chr=0; $chr < 0xFF; $chr++) {
- if ($chr >= 0x30 && $chr <= 0x39
- || $chr >= 0x41 && $chr <= 0x5A
- || $chr >= 0x61 && $chr <= 0x7A) {
- $literal = $this->codepointToUtf8($chr);
- $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'css'));
- } else {
- $literal = $this->codepointToUtf8($chr);
- $this->assertNotEquals(
- $literal,
- twig_escape_filter($this->env, $literal, 'css'),
- "$literal should be escaped!");
- }
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php';
-Twig_Autoloader::register(true);
+++ /dev/null
-vendor
-phpunit.xml
-composer.lock
+++ /dev/null
-language: php
-
-before_script:
- - curl -s http://getcomposer.org/installer | php
- - php composer.phar install --dev
-
-php:
- - 5.3
- - 5.4
-
+++ /dev/null
-Copyright (c) Саша Стаменковић <umpirsky@gmail.com>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
\ No newline at end of file
+++ /dev/null
-Twig Gettext Extractor [![Build Status](https://secure.travis-ci.org/umpirsky/Twig-Gettext-Extractor.png?branch=master)](http://travis-ci.org/umpirsky/Twig-Gettext-Extractor)
-======================
-
-The Twig Gettext Extractor is [Poedit](http://www.poedit.net/download.php)
-friendly tool which extracts translations from twig templates.
-
-## Installation
-
-The recommended way to install Twig Gettext Extractor is through
-[composer](http://getcomposer.org).
-
-```json
-{
- "require": {
- "umpirsky/twig-gettext-extractor": "1.1.*"
- }
-}
-```
-
-## Setup
-
-By default, Poedit does not have the ability to parse Twig templates.
-This can be resolved by adding an additional parser (Edit > Preferences > Parsers)
-with the following options:
-
-- Language: `Twig`
-- List of extensions: `*.twig`
-- Invocation:
- - Parser command: `<project>/vendor/bin/twig-gettext-extractor --sort-output --force-po -o %o %C %K -L PHP --files %F`
- - An item in keyword list: `-k%k`
- - An item in input file list: `%f`
- - Source code charset: `--from-code=%c`
-
-<img src="http://i.imgur.com/f9px2.png" />
-
-Now you can update your catalog and Poedit will synchronize it with your twig
-templates.
-
-## Tests
-
-To run the test suite, you need [composer](http://getcomposer.org) and
-[PHPUnit](https://github.com/sebastianbergmann/phpunit).
-
- $ composer install --dev
- $ phpunit
-
-## License
-
-Twig Gettext Extractor is licensed under the MIT license.
+++ /dev/null
-<?php
-
-/**
- * This file is part of the Twig Gettext utility.
- *
- * (c) Саша Стаменковић <umpirsky@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Twig\Gettext;
-
-use Symfony\Component\Filesystem\Filesystem;
-
-/**
- * Extracts translations from twig templates.
- *
- * @author Саша Стаменковић <umpirsky@gmail.com>
- */
-class Extractor
-{
- /**
- * @var \Twig_Environment
- */
- protected $environment;
-
- /**
- * Template cached file names.
- *
- * @var string[]
- */
- protected $templates;
-
- /**
- * Gettext parameters.
- *
- * @var string[]
- */
- protected $parameters;
-
- public function __construct(\Twig_Environment $environment)
- {
- $this->environment = $environment;
- $this->reset();
- }
-
- protected function reset()
- {
- $this->templates = array();
- $this->parameters = array();
- }
-
- public function addTemplate($path)
- {
- $this->environment->loadTemplate($path);
- $this->templates[] = $this->environment->getCacheFilename($path);
- }
-
- public function addGettextParameter($parameter)
- {
- $this->parameters[] = $parameter;
- }
-
- public function setGettextParameters(array $parameters)
- {
- $this->parameters = $parameters;
- }
-
- public function extract()
- {
- $command = 'xgettext';
- $command .= ' '.join(' ', $this->parameters);
- $command .= ' '.join(' ', $this->templates);
-
- $error = 0;
- $output = system($command, $error);
- if (0 !== $error) {
- throw new \RuntimeException(sprintf(
- 'Gettext command "%s" failed with error code %s and output: %s',
- $command,
- $error,
- $output
- ));
- }
-
- $this->reset();
- }
-
- public function __destruct()
- {
- $filesystem = new Filesystem();
- $filesystem->remove($this->environment->getCache());
- }
-}
+++ /dev/null
-<?php
-
-/**
- * This file is part of the Twig Gettext utility.
- *
- * (c) Саша Стаменковић <umpirsky@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Twig\Gettext\Loader;
-
-/**
- * Loads template from the filesystem.
- *
- * @author Саша Стаменковић <umpirsky@gmail.com>
- */
-class Filesystem extends \Twig_Loader_Filesystem
-{
- /**
- * Hacked find template to allow loading templates by absolute path.
- *
- * @param string $name template name or absolute path
- */
- protected function findTemplate($name)
- {
- // normalize name
- $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
-
- if (isset($this->cache[$name])) {
- return $this->cache[$name];
- }
-
- $this->validateName($name);
-
- $namespace = '__main__';
- if (isset($name[0]) && '@' == $name[0]) {
- if (false === $pos = strpos($name, '/')) {
- throw new \InvalidArgumentException(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
- }
-
- $namespace = substr($name, 1, $pos - 1);
-
- $name = substr($name, $pos + 1);
- }
-
- if (!isset($this->paths[$namespace])) {
- throw new \Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
- }
-
- if (is_file($name)) {
- return $this->cache[$name] = $name;
- }
-
- return __DIR__.'/../Test/Fixtures/twig/empty.twig';
- }
-}
+++ /dev/null
-<?php
-
-/**
- * This file is part of the Twig Gettext utility.
- *
- * (c) Саша Стаменковић <umpirsky@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Twig\Gettext\Routing\Generator;
-
-use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
-use Symfony\Component\Routing\RequestContext;
-
-/**
- * Dummy url generator.
- *
- * @author Саша Стаменковић <umpirsky@gmail.com>
- */
-class UrlGenerator implements UrlGeneratorInterface
-{
- protected $context;
-
- public function generate($name, $parameters = array(), $absolute = false)
- {
- }
-
- public function getContext()
- {
- return $this->context;
- }
-
- public function setContext(RequestContext $context)
- {
- $this->context = $context;
- }
-}
+++ /dev/null
-<?php
-
-/**
- * This file is part of the Twig Gettext utility.
- *
- * (c) Саша Стаменковић <umpirsky@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Twig\Gettext\Test;
-
-use Twig\Gettext\Extractor;
-use Twig\Gettext\Loader\Filesystem;
-use Symfony\Component\Translation\Loader\PoFileLoader;
-
-/**
- * @author Саша Стаменковић <umpirsky@gmail.com>
- */
-class ExtractorTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @var \Twig_Environment
- */
- protected $twig;
-
- /**
- * @var PoFileLoader
- */
- protected $loader;
-
- protected function setUp()
- {
- $this->twig = new \Twig_Environment(new Filesystem('/'), array(
- 'cache' => '/tmp/cache/'.uniqid(),
- 'auto_reload' => true
- ));
- $this->twig->addExtension(new \Twig_Extensions_Extension_I18n());
-
- $this->loader = new PoFileLoader();
- }
-
- /**
- * @dataProvider testExtractDataProvider
- */
- public function testExtract(array $templates, array $parameters, array $messages)
- {
- $extractor = new Extractor($this->twig);
-
- foreach ($templates as $template) {
- $extractor->addTemplate($template);
- }
- foreach ($parameters as $parameter) {
- $extractor->addGettextParameter($parameter);
- }
-
- $extractor->extract();
-
- $catalog = $this->loader->load($this->getPotFile(), null);
-
- foreach ($messages as $message) {
- $this->assertTrue(
- $catalog->has($message),
- sprintf('Message "%s" not found in catalog.', $message)
- );
- }
- }
-
- public function testExtractDataProvider()
- {
- return array(
- array(
- array(
- __DIR__.'/Fixtures/twig/singular.twig',
- __DIR__.'/Fixtures/twig/plural.twig',
- ),
- $this->getGettextParameters(),
- array(
- 'Hello %name%!',
- 'Hello World!',
- 'Hey %name%, I have one apple.',
- 'Hey %name%, I have %count% apples.',
- ),
- ),
- );
- }
-
- public function testExtractNoTranslations()
- {
- $extractor = new Extractor($this->twig);
-
- $extractor->addTemplate(__DIR__.'/Fixtures/twig/empty.twig');
- $extractor->setGettextParameters($this->getGettextParameters());
-
- $extractor->extract();
-
- $catalog = $this->loader->load($this->getPotFile(), null);
-
- $this->assertEmpty($catalog->all('messages'));
- }
-
- private function getPotFile()
- {
- return __DIR__.'/Fixtures/messages.pot';
- }
-
- private function getGettextParameters()
- {
- return array(
- '--force-po',
- '-o',
- $this->getPotFile(),
- );
- }
-
- protected function tearDown()
- {
- if (file_exists($this->getPotFile())) {
- unlink($this->getPotFile());
- }
- }
-}
+++ /dev/null
-Nothing to translate here.
+++ /dev/null
-{% trans %}
- Hey {{ name }}, I have one apple.
-{% plural apple_count %}
- Hey {{ name }}, I have {{ count }} apples.
-{% endtrans %}
+++ /dev/null
-{% trans "Hello World!" %}
-
-{% trans %}
- Hello World!
-{% endtrans %}
-
-{% trans %}
- Hello {{ name }}!
-{% endtrans %}
+++ /dev/null
-{
- "name": "umpirsky/twig-gettext-extractor",
- "type": "application",
- "description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates.",
- "license": "MIT",
- "authors": [
- {
- "name": "Саша Стаменковић",
- "email": "umpirsky@gmail.com"
- }
- ],
- "require": {
- "php": ">=5.3.3",
- "twig/twig": ">=1.2.0,<2.0-dev",
- "twig/extensions": "1.0.*",
- "symfony/twig-bridge": ">=2.0,<3.0",
- "symfony/routing": ">=2.0,<3.0",
- "symfony/filesystem": ">=2.0,<3.0",
- "symfony/translation": ">=2.0,<3.0",
- "symfony/form": ">=2.0,<3.0"
- },
- "require-dev": {
- "symfony/config": "2.1.*"
- },
- "minimum-stability": "dev",
- "autoload": {
- "psr-0": { "Twig\\Gettext": "." }
- },
- "bin": ["twig-gettext-extractor"]
-}
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- bootstrap="./vendor/autoload.php"
->
- <testsuites>
- <testsuite name="Twig Gettext Extractor Test Suite">
- <directory>./Twig/Gettext/Test/</directory>
- </testsuite>
- </testsuites>
-</phpunit>
+++ /dev/null
-#!/usr/bin/env php
-<?php
-
-/**
- * This file is part of the Twig Gettext utility.
- *
- * (c) Саша Стаменковић <umpirsky@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Extracts translations from twig templates.
- *
- * @author Саша Стаменковић <umpirsky@gmail.com>
- */
-
-if (file_exists($a = __DIR__.'/../../autoload.php')) {
- require_once $a;
-} else {
- require_once __DIR__.'/vendor/autoload.php';
-}
-
-$twig = new Twig_Environment(new Twig\Gettext\Loader\Filesystem('/'), array(
- 'cache' => '/tmp/cache/'.uniqid(),
- 'auto_reload' => true
-));
-$twig->addExtension(new Symfony\Bridge\Twig\Extension\TranslationExtension(
- new Symfony\Component\Translation\Translator(null)
-));
-$twig->addExtension(new Twig_Extensions_Extension_I18n());
-$twig->addExtension(new Symfony\Bridge\Twig\Extension\RoutingExtension(
- new Twig\Gettext\Routing\Generator\UrlGenerator()
-));
-$twig->addExtension(new Symfony\Bridge\Twig\Extension\FormExtension(
- new Symfony\Bridge\Twig\Form\TwigRenderer(
- new Symfony\Bridge\Twig\Form\TwigRendererEngine()
- )
-));
-// You can add more extensions here.
-
-array_shift($_SERVER['argv']);
-$addTemplate = false;
-
-$extractor = new Twig\Gettext\Extractor($twig);
-
-foreach ($_SERVER['argv'] as $arg) {
- if ('--files' == $arg) {
- $addTemplate = true;
- } else if ($addTemplate) {
- $extractor->addTemplate(getcwd().DIRECTORY_SEPARATOR.$arg);
- } else {
- $extractor->addGettextParameter($arg);
- }
-}
-
-$extractor->extract();