mirror of
https://github.com/moparisthebest/wallabag
synced 2024-11-27 11:22:17 -05:00
rm vendor
This commit is contained in:
parent
68abd9c71b
commit
46b77928f7
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
||||
vendor/
|
7
vendor/autoload.php
vendored
7
vendor/autoload.php
vendored
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload.php generated by Composer
|
||||
|
||||
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029::getLoader();
|
1
vendor/bin/twig-gettext-extractor
vendored
1
vendor/bin/twig-gettext-extractor
vendored
@ -1 +0,0 @@
|
||||
../umpirsky/twig-gettext-extractor/twig-gettext-extractor
|
246
vendor/composer/ClassLoader.php
vendored
246
vendor/composer/ClassLoader.php
vendored
@ -1,246 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
13
vendor/composer/autoload_classmap.php
vendored
13
vendor/composer/autoload_classmap.php
vendored
@ -1,13 +0,0 @@
|
||||
<?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',
|
||||
);
|
10
vendor/composer/autoload_files.php
vendored
10
vendor/composer/autoload_files.php
vendored
@ -1,10 +0,0 @@
|
||||
<?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',
|
||||
);
|
22
vendor/composer/autoload_namespaces.php
vendored
22
vendor/composer/autoload_namespaces.php
vendored
@ -1,22 +0,0 @@
|
||||
<?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'),
|
||||
);
|
47
vendor/composer/autoload_real.php
vendored
47
vendor/composer/autoload_real.php
vendored
@ -1,47 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
747
vendor/composer/installed.json
vendored
747
vendor/composer/installed.json
vendored
@ -1,747 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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."
|
||||
}
|
||||
]
|
@ -1,4 +0,0 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
|
@ -1,16 +0,0 @@
|
||||
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
|
@ -1,202 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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();
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,185 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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();
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
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.
|
@ -1,25 +0,0 @@
|
||||
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
|
@ -1,257 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,320 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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)
|
||||
));
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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());
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
<?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>
|
@ -1,4 +0,0 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
|
@ -1,18 +0,0 @@
|
||||
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
|
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
|
||||
}
|
@ -1,471 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
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.
|
@ -1,45 +0,0 @@
|
||||
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
|
@ -1,982 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<?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>
|
@ -1,4 +0,0 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
|
@ -1,195 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,206 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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';
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,436 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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();
|
||||
}
|
||||
}
|
@ -1,864 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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();
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,238 +0,0 @@
|
||||
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
|
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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();
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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
|
||||
{
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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)));
|
||||
}
|
||||
}
|
@ -1,510 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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(),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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();
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,231 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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');
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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');
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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');
|
||||
}
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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');
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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',
|
||||
));
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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';
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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';
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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';
|
||||
}
|
||||
}
|
@ -1,274 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user