rm vendor

This commit is contained in:
Nicolas Lœuillet 2013-08-04 17:50:34 +02:00
parent 68abd9c71b
commit 46b77928f7
1349 changed files with 0 additions and 122372 deletions

1
.gitignore vendored
View file

@ -1 +0,0 @@
vendor/

7
vendor/autoload.php vendored
View file

@ -1,7 +0,0 @@
<?php
// autoload.php generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit1c7743925d207055d2ad189b1f10a029::getLoader();

View file

@ -1 +0,0 @@
../umpirsky/twig-gettext-extractor/twig-gettext-extractor

View file

@ -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;
}
}

View file

@ -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',
);

View file

@ -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',
);

View file

@ -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'),
);

View file

@ -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;
}
}

View file

@ -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."
}
]

View file

@ -1,4 +0,0 @@
vendor/
composer.lock
phpunit.xml

View file

@ -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

View file

@ -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;
}
}
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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]);
}
}
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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

View file

@ -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)
{
}
}

View file

@ -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)
));
}
}

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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"
}
}
}

View file

@ -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>

View file

@ -1,4 +0,0 @@
vendor/
composer.lock
phpunit.xml

View file

@ -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

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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

View file

@ -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');
}
}
}

View file

@ -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"
}
}
}

View file

@ -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>

View file

@ -1,4 +0,0 @@
vendor/
composer.lock
phpunit.xml

View file

@ -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');
}
}
}

View file

@ -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;
}
}

View file

@ -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';
}
}

View file

@ -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)
{
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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
{
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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
{
}

View file

@ -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)));
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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)));
}
}
}
}

View file

@ -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;
}
}

View file

@ -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(),
);
}
}

View file

@ -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());
}
}
}
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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');
}
}

View file

@ -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');
}
}

View file

@ -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');
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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');
}
}

View file

@ -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',
));
}
}

View file

@ -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';
}
}

View file

@ -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';
}
}

View file

@ -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';
}
}

View file

@ -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