diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000000..b03e61ef338c1 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ +| Q | A +| ------------- | --- +| Branch | master for features and deprecations / lowest applicable and maintained version otherwise +| Bug fix? | yes/no +| New feature? | yes/no +| BC breaks? | yes/no +| Deprecations? | yes/no +| Tests pass? | yes/no +| Fixed tickets | comma-separated list of tickets fixed by the PR, if any +| License | MIT +| Doc PR | reference to the documentation PR, if any diff --git a/.travis.yml b/.travis.yml index 6da2fb04da51c..50427f628e1f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ language: php sudo: false +git: + depth: 1 + addons: apt_packages: - parallel @@ -29,7 +32,9 @@ cache: services: mongodb before_install: + # Matrix lines for intermediate PHP versions are skipped for pull requests - if [[ ! $deps && ! $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && $TRAVIS_PHP_VERSION != hhvm && $TRAVIS_PULL_REQUEST != false ]]; then deps=skip; fi; + # A sigchild-enabled-PHP is used to test the Process component on the lowest PHP matrix line - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://museum.php.net/php5/php-$MIN_PHP.tar.bz2 -O - | tar -xj; (cd php-$MIN_PHP; ./configure --enable-sigchild --enable-pcntl; make -j2); fi; - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi; - echo memory_limit = -1 >> $INI_FILE @@ -49,9 +54,12 @@ before_install: install: - if [[ $deps != skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi; + # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - if [[ $deps != skip && $deps ]]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi; + # For the master branch when deps=high, the version before master is checked out and tested with the locally patched components - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi; - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi; + # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number than the next one - if [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]]; then LEGACY=,legacy; fi; - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev; - if [[ ! $deps ]]; then composer update --prefer-dist; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi; diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 4f119cb3603da..0679502162dc1 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -7,6 +7,49 @@ in 3.0 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.0.0...v3.0.1 +* 3.0.3 (2016-02-28) + + * bug #17919 #17676 - making the proxy instantiation compatible with ProxyManager 2.x by detecting proxy features (Ocramius) + * bug #17947 Fix - #17676 (backport #17919 to 2.3) (Ocramius) + * bug #17942 Fix bug when using an private aliased factory service (WouterJ) + * bug #17798 [Form] Fix BC break by allowing 'choice_label' option to be 'false' in ChoiceType (HeahDude) + * bug #17542 ChoiceFormField of type "select" could be "disabled" (bouland) + * bug #17602 [HttpFoundation] Fix BinaryFileResponse incorrect behavior with if-range header (bburnichon) + * bug #17760 [Form] fix choice value "false" in ChoiceType (HeahDude) + * bug #17914 [Console] Fix escaping of trailing backslashes (nicolas-grekas) + * bug #17074 Fix constraint validator alias being required (Triiistan) + * bug #17866 [DependencyInjection] replace alias in factories (xabbuh) + * bug #17867 [DependencyInjection] replace alias in factory services (xabbuh) + * bug #17865 [FrameworkBundle] disable the assets helper when assets are disabled (xabbuh) + * bug #17860 Fixed the antialiasing of the toolbar text (javiereguiluz) + * bug #17569 [FrameworkBundle] read commands from bundles when accessing list (havvg) + * bug #16987 [FileSystem] Windows fix (flip111) + * bug #17787 [Form] Fix choice placeholder edge cases (Tobion) + * bug #17835 [Yaml] fix default timezone to be UTC (xabbuh) + * bug #17823 [DependencyInjection] fix dumped YAML string (xabbuh) + * bug #17818 [Console] InvalidArgumentException is thrown under wrong condition (robinkanters) + * bug #17819 [HttpKernel] Prevent a fatal error when DebugHandlersListener is used with a kernel with no terminateWithException() method (jakzal) + * bug #17814 [DependencyInjection] fix dumped YAML snytax (xabbuh) + * bug #17099 [Form] Fixed violation mapping if multiple forms are using the same (or part of the same) property path (alekitto) + * bug #17694 [DoctrineBridge] [Form] fix choice_value in EntityType (HeahDude) + * bug #17790 [Config] Fix EnumNodeDefinition to allow building enum nodes with one element (ogizanagi) + * bug #17729 [Yaml] properly parse lists in object maps (xabbuh) + * bug #17719 [DependencyInjection] fixed exceptions thrown by get method of ContainerBuilder (lukaszmakuch) + * bug #17742 [DependencyInjection] Fix #16461 Container::set() replace aliases (mnapoli) + * bug #17745 Added more exceptions to singularify method (javiereguiluz) + * bug #17691 Fixed (string) catchable fatal error for PHP Incomplete Class instances (yceruto) + * bug #17766 Fixed (string) catchable fatal error for PHP Incomplete Class instances (yceruto) + * bug #17757 [HttpFoundation] BinaryFileResponse sendContent return as parent. (2.3) (SpacePossum) + * bug #17748 [DomCrawler] Remove the overridden getHash() method to prevent problems when cloning the crawler (jakzal) + * bug #17725 [WebProfilerBundle] Add width attribute on SVG - Fix toolbar profiler on microsoft edge (AlexandrePavy) + * bug #17703 [FrameworkBundle] Support autowiring for TranslationInterface (dunglas) + * bug #17613 [WebProfiler] Fixed logo and menu profiler for Microsoft Edge (WhiteEagle88) + * bug #17702 [TwigBridge] forward compatibility with Yaml 3.1 (xabbuh) + * bug #17673 [Routing] add files used in FileResource objects (xabbuh) + * bug #17672 [DependencyInjection][Routing] add files used in FileResource objects (xabbuh) + * bug #17669 [Console] remove readline support (xabbuh) + * bug #17600 Fixed the Bootstrap form theme for inlined checkbox/radio (javiereguiluz) + * 3.0.2 (2016-02-03) * bug #17658 [FrameworkBundle] fix assets and templating tests (xabbuh) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 123d5aa755911..ae18925cb6e20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,29 +5,20 @@ Symfony is an open source, community-driven project. If you'd like to contribute, please read the following documents: -* [Contributing Code][1]: The document index related to contributions; - -* [Submitting a Patch][2]: Guidelines for submitting a pull request; - -* [Pull Request Template][3]: Template header to use in your pull request - description; - -```markdown -| Q | A -| ------------- | --- -| Bug fix? | yes/no -| New feature? | yes/no -| BC breaks? | no -| Deprecations? | no -| Tests pass? | yes -| Fixed tickets | #1234 -| License | MIT -| Doc PR | symfony/symfony-docs#1234 -``` - -* [Backwards Compatibility][4]: Backward compatibility rules. - -[1]: https://symfony.com/doc/current/contributing/code/index.html -[2]: https://symfony.com/doc/current/contributing/code/patches.html#check-list -[3]: https://symfony.com/doc/current/contributing/code/patches.html#make-a-pull-request -[4]: https://symfony.com/doc/current/contributing/code/bc.html#working-on-symfony-code +* [Reporting a Bug][1] +* [Submitting a Patch][2] +* [Symfony Core Team][3] +* [Security Issues][4] +* [Running Symfony Tests][5] +* [Our Backwards Compatibility Promise][6] +* [Coding Standards][7] +* [Conventions][8] + +[1]: https://symfony.com/doc/current/contributing/code/bugs.html +[2]: https://symfony.com/doc/current/contributing/code/patches.html +[3]: https://symfony.com/doc/current/contributing/code/core_team.html +[4]: https://symfony.com/doc/current/contributing/code/security.html +[5]: https://symfony.com/doc/current/contributing/code/tests.html +[6]: https://symfony.com/doc/current/contributing/code/bc.html +[7]: https://symfony.com/doc/current/contributing/code/standards.html +[8]: https://symfony.com/doc/current/contributing/code/conventions.html diff --git a/appveyor.yml b/appveyor.yml index 6456c27916d13..ee7373076a745 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,5 @@ build: false -shallow_clone: true -platform: x86 +clone_depth: 1 clone_folder: c:\projects\symfony cache: diff --git a/composer.json b/composer.json index 7fe4d1436a671..46f82d5990262 100644 --- a/composer.json +++ b/composer.json @@ -78,7 +78,7 @@ "doctrine/orm": "~2.4,>=2.4.5", "doctrine/doctrine-bundle": "~1.4", "monolog/monolog": "~1.11", - "ocramius/proxy-manager": "~0.4|~1.0", + "ocramius/proxy-manager": "~0.4|~1.0|~2.0", "egulias/email-validator": "~1.2", "symfony/polyfill-apcu": "~1.1", "symfony/security-acl": "~2.8|~3.0", diff --git a/phpunit b/phpunit index dba1222189066..9cf03f071ecbf 100755 --- a/phpunit +++ b/phpunit @@ -160,8 +160,8 @@ if (isset($argv[1]) && 'symfony' === $argv[1]) { unlink($file); } - // Fail on any individual component failures but ignore STATUS_STACK_BUFFER_OVERRUN (-1073740791) on Windows when APCu is enabled - if ($procStatus && ('\\' !== DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !ini_get('apc.enable_cli') || -1073740791 !== $procStatus)) { + // Fail on any individual component failures but ignore STATUS_STACK_BUFFER_OVERRUN (-1073740791/0xC0000409) and STATUS_ACCESS_VIOLATION (-1073741819/0xC0000005) on Windows when APCu is enabled + if ($procStatus && ('\\' !== DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !ini_get('apc.enable_cli') || (-1073740791 !== $procStatus && -1073741819 !== $procStatus))) { $exit = $procStatus; echo "\033[41mKO\033[0m $component\n\n"; } else { diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php index 1a09609b28556..2dc8c2cb2b28d 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php @@ -146,7 +146,7 @@ public function loadChoicesForValues(array $values, $value = null) // Optimize performance in case we have an object loader and // a single-field identifier - if (!$this->choiceList && $this->objectLoader && $this->idReader->isSingleId()) { + if (null === $value && !$this->choiceList && $this->objectLoader && $this->idReader->isSingleId()) { $unorderedObjects = $this->objectLoader->getEntitiesByIds($this->idReader->getIdField(), $values); $objectsById = array(); $objects = array(); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 0303c355c055b..5b12c5bdcacab 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -753,6 +753,55 @@ public function testOverrideChoices() $this->assertSame('2', $field->getViewData()); } + public function testOverrideChoicesValues() + { + $entity1 = new SingleIntIdEntity(1, 'Foo'); + $entity2 = new SingleIntIdEntity(2, 'Bar'); + + $this->persist(array($entity1, $entity2)); + + $field = $this->factory->createNamed('name', 'Symfony\Bridge\Doctrine\Form\Type\EntityType', null, array( + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + 'choice_label' => 'name', + 'choice_value' => 'name', + )); + + $field->submit('Bar'); + + $this->assertEquals(array('Foo' => new ChoiceView($entity1, 'Foo', 'Foo'), 'Bar' => new ChoiceView($entity2, 'Bar', 'Bar')), $field->createView()->vars['choices']); + $this->assertTrue($field->isSynchronized(), 'Field should be synchronized.'); + $this->assertSame($entity2, $field->getData(), 'Entity should be loaded by custom value.'); + $this->assertSame('Bar', $field->getViewData()); + } + + public function testOverrideChoicesValuesWithCallable() + { + $entity1 = new GroupableEntity(1, 'Foo', 'BazGroup'); + $entity2 = new GroupableEntity(2, 'Bar', 'BooGroup'); + + $this->persist(array($entity1, $entity2)); + + $field = $this->factory->createNamed('name', 'Symfony\Bridge\Doctrine\Form\Type\EntityType', null, array( + 'em' => 'default', + 'class' => self::ITEM_GROUP_CLASS, + 'choice_label' => 'name', + 'choice_value' => function (GroupableEntity $entity) { + return $entity->groupName.'/'.$entity->name; + }, + )); + + $field->submit('BooGroup/Bar'); + + $this->assertEquals(array( + 'BazGroup/Foo' => new ChoiceView($entity1, 'BazGroup/Foo', 'Foo'), + 'BooGroup/Bar' => new ChoiceView($entity2, 'BooGroup/Bar', 'Bar'), + ), $field->createView()->vars['choices']); + $this->assertTrue($field->isSynchronized(), 'Field should be synchronized.'); + $this->assertSame($entity2, $field->getData(), 'Entity should be loaded by custom value.'); + $this->assertSame('BooGroup/Bar', $field->getViewData()); + } + public function testGroupByChoices() { $item1 = new GroupableEntity(1, 'Foo', 'Group1'); diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php index 550786d5d716a..cf2520a371549 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php @@ -74,10 +74,16 @@ public function getProxyFactoryCode(Definition $definition, $id) $methodName = 'get'.Container::camelize($id).'Service'; $proxyClass = $this->getProxyClassName($definition); + $generatedClass = $this->generateProxyClass($definition); + + $constructorCall = $generatedClass->hasMethod('staticProxyConstructor') + ? $proxyClass.'::staticProxyConstructor' + : 'new '.$proxyClass; + return <<$methodName(false); @@ -97,11 +103,7 @@ function (&\$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface \$proxy) */ public function getProxyCode(Definition $definition) { - $generatedClass = new ClassGenerator($this->getProxyClassName($definition)); - - $this->proxyGenerator->generate(new \ReflectionClass($definition->getClass()), $generatedClass); - - return $this->classGenerator->generate($generatedClass); + return $this->classGenerator->generate($this->generateProxyClass($definition)); } /** @@ -115,4 +117,16 @@ private function getProxyClassName(Definition $definition) { return str_replace('\\', '', $definition->getClass()).'_'.spl_object_hash($definition).$this->salt; } + + /** + * @return ClassGenerator + */ + private function generateProxyClass(Definition $definition) + { + $generatedClass = new ClassGenerator($this->getProxyClassName($definition)); + + $this->proxyGenerator->generate(new \ReflectionClass($definition->getClass()), $generatedClass); + + return $generatedClass; + } } diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php index 412674ee3f680..789799bce6e19 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\ProxyManager\Tests\LazyProxy\Dumper; +use ProxyManager\ProxyGenerator\LazyLoading\MethodGenerator\StaticProxyConstructor; use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; @@ -49,7 +50,11 @@ public function testDumpContainerWithProxyService() */ public function testDumpContainerWithProxyServiceWillShareProxies() { - require_once __DIR__.'/../Fixtures/php/lazy_service.php'; + if (class_exists(StaticProxyConstructor::class)) { // detecting ProxyManager v2 + require_once __DIR__.'/../Fixtures/php/lazy_service_with_hints.php'; + } else { + require_once __DIR__.'/../Fixtures/php/lazy_service.php'; + } $container = new \LazyServiceProjectServiceContainer(); diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt index 7bd36c13ef6a2..9b73cdeb70ca2 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt @@ -7,7 +7,7 @@ class ProjectServiceContainer extends Container { if ($lazyLoad) { - return $this->services['foo'] = new stdClass_%s( + return $this->services['foo'] =%sstdClass_%s( function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) { $wrappedInstance = $this->getFooService(false); @@ -22,5 +22,5 @@ class ProjectServiceContainer extends Container } } -class stdClass_%s extends \stdClass implements \ProxyManager\Proxy\VirtualProxyInterface +class stdClass_%s extends \stdClass implements \ProxyManager\%s {%a}%A diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php new file mode 100644 index 0000000000000..e786523121b8e --- /dev/null +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php @@ -0,0 +1,187 @@ +services = array(); + } + + /** + * Gets the 'foo' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @param bool $lazyLoad whether to try lazy-loading the service with a proxy + * + * @return stdClass A stdClass instance. + */ + public function getFooService($lazyLoad = true) + { + if ($lazyLoad) { + return $this->services['foo'] = new stdClass_c1d194250ee2e2b7d2eab8b8212368a8( + function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) { + $wrappedInstance = $this->getFooService(false); + + $proxy->setProxyInitializer(null); + + return true; + } + ); + } + + return new \stdClass(); + } +} + +class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \ProxyManager\Proxy\LazyLoadingInterface, \ProxyManager\Proxy\ValueHolderInterface +{ + /** + * @var \Closure|null initializer responsible for generating the wrapped object + */ + private $valueHolder5157dd96e88c0 = null; + + /** + * @var \Closure|null initializer responsible for generating the wrapped object + */ + private $initializer5157dd96e8924 = null; + + /** + * @override constructor for lazy initialization + * + * @param \Closure|null $initializer + */ + public function __construct($initializer) + { + $this->initializer5157dd96e8924 = $initializer; + } + + /** + * @param string $name + */ + public function __get($name) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__get', array('name' => $name)); + + return $this->valueHolder5157dd96e88c0->$name; + } + + /** + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__set', array('name' => $name, 'value' => $value)); + + $this->valueHolder5157dd96e88c0->$name = $value; + } + + /** + * @param string $name + * + * @return bool + */ + public function __isset($name) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__isset', array('name' => $name)); + + return isset($this->valueHolder5157dd96e88c0->$name); + } + + /** + * @param string $name + */ + public function __unset($name) + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__unset', array('name' => $name)); + + unset($this->valueHolder5157dd96e88c0->$name); + } + + /** + * + */ + public function __clone() + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__clone', array()); + + $this->valueHolder5157dd96e88c0 = clone $this->valueHolder5157dd96e88c0; + } + + /** + * + */ + public function __sleep() + { + $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__sleep', array()); + + return array('valueHolder5157dd96e88c0'); + } + + /** + * + */ + public function __wakeup() + { + } + + /** + * {@inheritdoc} + */ + public function setProxyInitializer(\Closure $initializer = null) + { + $this->initializer5157dd96e8924 = $initializer; + } + + /** + * {@inheritdoc} + */ + public function getProxyInitializer() + { + return $this->initializer5157dd96e8924; + } + + /** + * {@inheritdoc} + */ + public function initializeProxy() : bool + { + return $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, 'initializeProxy', array()); + } + + /** + * {@inheritdoc} + */ + public function isProxyInitialized() : bool + { + return null !== $this->valueHolder5157dd96e88c0; + } + + /** + * {@inheritdoc} + */ + public function getWrappedValueHolderValue() + { + return $this->valueHolder5157dd96e88c0; + } +} diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php index 52f83e8db4c90..de7f9ea221a7e 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php @@ -69,7 +69,7 @@ public function testGetProxyFactoryCode() $code = $this->dumper->getProxyFactoryCode($definition, 'foo'); $this->assertStringMatchesFormat( - '%wif ($lazyLoad) {%wreturn $this->services[\'foo\'] = new ' + '%wif ($lazyLoad) {%wreturn $this->services[\'foo\'] =%s' .'SymfonyBridgeProxyManagerTestsLazyProxyPhpDumperProxyDumperTest_%s(%wfunction ' .'(&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) {' .'%w$wrappedInstance = $this->getFooService(false);%w$proxy->setProxyInitializer(null);' diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index e91f237825ad4..b9020dc30c3ea 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.5.9", "symfony/dependency-injection": "~2.8|~3.0", - "ocramius/proxy-manager": "~0.4|~1.0" + "ocramius/proxy-manager": "~0.4|~1.0|~2.0" }, "require-dev": { "symfony/config": "~2.8|~3.0" diff --git a/src/Symfony/Bridge/Twig/Extension/YamlExtension.php b/src/Symfony/Bridge/Twig/Extension/YamlExtension.php index fc9bf0e9e3308..2d46795b4a81e 100644 --- a/src/Symfony/Bridge/Twig/Extension/YamlExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/YamlExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Twig\Extension; use Symfony\Component\Yaml\Dumper as YamlDumper; +use Symfony\Component\Yaml\Yaml; /** * Provides integration of the Yaml component with Twig. @@ -39,6 +40,10 @@ public function encode($input, $inline = 0, $dumpObjects = false) $dumper = new YamlDumper(); } + if (defined('Symfony\Component\Yaml\Yaml::DUMP_OBJECT')) { + return $dumper->dump($input, $inline, 0, is_bool($dumpObjects) ? Yaml::DUMP_OBJECT : 0); + } + return $dumper->dump($input, $inline, 0, false, $dumpObjects); } diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig index 5affc7a6a1b92..dfb1965ca1048 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig @@ -115,7 +115,7 @@ {%- endblock choice_widget_expanded %} {% block checkbox_widget -%} - {% set parent_label_class = parent_label_class|default('') -%} + {%- set parent_label_class = parent_label_class|default(label_attr.class|default('')) -%} {% if 'checkbox-inline' in parent_label_class %} {{- form_label(form, null, { widget: parent() }) -}} {% else -%} @@ -126,7 +126,7 @@ {%- endblock checkbox_widget %} {% block radio_widget -%} - {%- set parent_label_class = parent_label_class|default('') -%} + {%- set parent_label_class = parent_label_class|default(label_attr.class|default('')) -%} {% if 'radio-inline' in parent_label_class %} {{- form_label(form, null, { widget: parent() }) -}} {% else -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 20c6e02c7ec01..63104def7d3eb 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -52,7 +52,7 @@ {%- endblock choice_widget_expanded -%} {%- block choice_widget_collapsed -%} - {%- if required and placeholder is none and not placeholder_in_choices and not multiple -%} + {%- if required and placeholder is none and not placeholder_in_choices and not multiple and (attr.size is not defined or attr.size <= 1) -%} {% set required = false %} {%- endif -%} block($form, 'widget_attributes', array( @@ -7,7 +7,7 @@ )) ?> multiple="multiple" > - + 0): ?> block($form, 'choice_widget_options', array('choices' => $preferred_choices)) ?> 0 && null !== $separator): ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php index 612d6325dd26d..fc0e7654db2ca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php @@ -11,8 +11,9 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Console; -use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Tester\ApplicationTester; @@ -23,7 +24,7 @@ public function testBundleInterfaceImplementation() { $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface'); - $kernel = $this->getKernel(array($bundle)); + $kernel = $this->getKernel(array($bundle), true); $application = new Application($kernel); $application->doRun(new ArrayInput(array('list')), new NullOutput()); @@ -34,10 +35,73 @@ public function testBundleCommandsAreRegistered() $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); $bundle->expects($this->once())->method('registerCommands'); - $kernel = $this->getKernel(array($bundle)); + $kernel = $this->getKernel(array($bundle), true); $application = new Application($kernel); $application->doRun(new ArrayInput(array('list')), new NullOutput()); + + // Calling twice: registration should only be done once. + $application->doRun(new ArrayInput(array('list')), new NullOutput()); + } + + public function testBundleCommandsAreRetrievable() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getKernel(array($bundle)); + + $application = new Application($kernel); + $application->all(); + + // Calling twice: registration should only be done once. + $application->all(); + } + + public function testBundleSingleCommandIsRetrievable() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getKernel(array($bundle)); + + $application = new Application($kernel); + + $command = new Command('example'); + $application->add($command); + + $this->assertSame($command, $application->get('example')); + } + + public function testBundleCommandCanBeFound() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getKernel(array($bundle)); + + $application = new Application($kernel); + + $command = new Command('example'); + $application->add($command); + + $this->assertSame($command, $application->find('example')); + } + + public function testBundleCommandCanBeFoundByAlias() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\Bundle'); + $bundle->expects($this->once())->method('registerCommands'); + + $kernel = $this->getKernel(array($bundle)); + + $application = new Application($kernel); + + $command = new Command('example'); + $command->setAliases(array('alias')); + $application->add($command); + + $this->assertSame($command, $application->find('alias')); } public function testBundleCommandsHaveRightContainer() @@ -46,7 +110,7 @@ public function testBundleCommandsHaveRightContainer() $command->setCode(function () {}); $command->expects($this->exactly(2))->method('setContainer'); - $application = new Application($this->getKernel(array())); + $application = new Application($this->getKernel(array(), true)); $application->setAutoExit(false); $application->setCatchExceptions(false); $application->add($command); @@ -59,21 +123,23 @@ public function testBundleCommandsHaveRightContainer() $tester->run(array('command' => 'foo')); } - private function getKernel(array $bundles) + private function getKernel(array $bundles, $useDispatcher = false) { - $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); - $dispatcher - ->expects($this->atLeastOnce()) - ->method('dispatch') - ; - $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); - $container - ->expects($this->atLeastOnce()) - ->method('get') - ->with($this->equalTo('event_dispatcher')) - ->will($this->returnValue($dispatcher)) - ; + + if ($useDispatcher) { + $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $dispatcher + ->expects($this->atLeastOnce()) + ->method('dispatch') + ; + $container + ->expects($this->atLeastOnce()) + ->method('get') + ->with($this->equalTo('event_dispatcher')) + ->will($this->returnValue($dispatcher)); + } + $container ->expects($this->once()) ->method('hasParameter') diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConstraintValidatorsPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConstraintValidatorsPassTest.php new file mode 100644 index 0000000000000..0629d1ebafd1f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConstraintValidatorsPassTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass; + +class AddConstraintValidatorsPassTest extends \PHPUnit_Framework_TestCase +{ + public function testThatConstraintValidatorServicesAreProcessed() + { + $services = array( + 'my_constraint_validator_service1' => array(0 => array('alias' => 'my_constraint_validator_alias1')), + 'my_constraint_validator_service2' => array(), + ); + + $validatorFactoryDefinition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $container = $this->getMock( + 'Symfony\Component\DependencyInjection\ContainerBuilder', + array('findTaggedServiceIds', 'getDefinition', 'hasDefinition') + ); + + $validatorDefinition1 = $this->getMock('Symfony\Component\DependencyInjection\Definition', array('getClass')); + $validatorDefinition2 = $this->getMock('Symfony\Component\DependencyInjection\Definition', array('getClass')); + + $validatorDefinition1->expects($this->atLeastOnce()) + ->method('getClass') + ->willReturn('My\Fully\Qualified\Class\Named\Validator1'); + $validatorDefinition2->expects($this->atLeastOnce()) + ->method('getClass') + ->willReturn('My\Fully\Qualified\Class\Named\Validator2'); + + $container->expects($this->any()) + ->method('getDefinition') + ->with($this->anything()) + ->will($this->returnValueMap(array( + array('my_constraint_validator_service1', $validatorDefinition1), + array('my_constraint_validator_service2', $validatorDefinition2), + array('validator.validator_factory', $validatorFactoryDefinition), + ))); + + $container->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->returnValue($services)); + $container->expects($this->atLeastOnce()) + ->method('hasDefinition') + ->with('validator.validator_factory') + ->will($this->returnValue(true)); + + $validatorFactoryDefinition->expects($this->once()) + ->method('replaceArgument') + ->with(1, array( + 'My\Fully\Qualified\Class\Named\Validator1' => 'my_constraint_validator_service1', + 'my_constraint_validator_alias1' => 'my_constraint_validator_service1', + 'My\Fully\Qualified\Class\Named\Validator2' => 'my_constraint_validator_service2', + )); + + $addConstraintValidatorsPass = new AddConstraintValidatorsPass(); + $addConstraintValidatorsPass->process($container); + } + + public function testThatCompilerPassIsIgnoredIfThereIsNoConstraintValidatorFactoryDefinition() + { + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $container = $this->getMock( + 'Symfony\Component\DependencyInjection\ContainerBuilder', + array('hasDefinition', 'findTaggedServiceIds', 'getDefinition') + ); + + $container->expects($this->never())->method('findTaggedServiceIds'); + $container->expects($this->never())->method('getDefinition'); + $container->expects($this->atLeastOnce()) + ->method('hasDefinition') + ->with('validator.validator_factory') + ->will($this->returnValue(false)); + $definition->expects($this->never())->method('replaceArgument'); + + $addConstraintValidatorsPass = new AddConstraintValidatorsPass(); + $addConstraintValidatorsPass->process($container); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_no_assets.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_no_assets.php new file mode 100644 index 0000000000000..bf12a8bc47e5f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_no_assets.php @@ -0,0 +1,7 @@ +loadFromExtension('framework', array( + 'templating' => array( + 'engines' => array('php', 'twig'), + ), +)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_php_assets_disabled.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_php_assets_disabled.php new file mode 100644 index 0000000000000..535a9a2e99c96 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_php_assets_disabled.php @@ -0,0 +1,8 @@ +loadFromExtension('framework', array( + 'assets' => false, + 'templating' => array( + 'engines' => array('php'), + ), +)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/templating_no_assets.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/templating_no_assets.xml new file mode 100644 index 0000000000000..d579ed4c0a181 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/templating_no_assets.xml @@ -0,0 +1,14 @@ + + + + + + php + twig + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml index d3285ff58102c..ba87d98b42ba6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml @@ -1,7 +1,7 @@ framework: assets: version: SomeVersionScheme - version_format: %%s?version=%%s + version_format: '%%s?version=%%s' base_urls: http://cdn.example.com packages: images_path: @@ -11,7 +11,7 @@ framework: base_urls: ["http://images1.example.com", "http://images2.example.com"] foo: version: 1.0.0 - version_format: %%s-%%s + version_format: '%%s-%%s' bar: base_urls: ["https://bar2.example.com"] bar_null_version: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 1c49d145f1c14..64bb38cb44682 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -13,7 +13,7 @@ framework: only_exceptions: true enabled: false router: - resource: %kernel.root_dir%/config/routing.xml + resource: '%kernel.root_dir%/config/routing.xml' type: xml session: storage_id: session.storage.native @@ -48,7 +48,7 @@ framework: annotations: cache: file debug: true - file_cache_dir: %kernel.cache_dir%/annotations + file_cache_dir: '%kernel.cache_dir%/annotations' serializer: enabled: true enable_annotations: true diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_no_assets.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_no_assets.yml new file mode 100644 index 0000000000000..393477aeb49ac --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_no_assets.yml @@ -0,0 +1,3 @@ +framework: + templating: + engines: [php, twig] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_php_assets_disabled.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_php_assets_disabled.yml new file mode 100644 index 0000000000000..7ef6b3e57c292 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_php_assets_disabled.yml @@ -0,0 +1,4 @@ +framework: + assets: false + templating: + engines: [php] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index e655b52654d2c..a8aced55dd7fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -436,14 +436,21 @@ public function testAssetHelperWhenAssetsAreEnabled() $this->assertSame('assets.packages', (string) $packages); } - public function testAssetHelperWhenTemplatesAreEnabledAndAssetsAreDisabled() + public function testAssetHelperWhenTemplatesAreEnabledAndNoAssetsConfiguration() { - $container = $this->createContainerFromFile('full'); + $container = $this->createContainerFromFile('templating_no_assets'); $packages = $container->getDefinition('templating.helper.assets')->getArgument(0); $this->assertSame('assets.packages', (string) $packages); } + public function testAssetsHelperIsRemovedWhenPhpTemplatingEngineIsEnabledAndAssetsAreDisabled() + { + $container = $this->createContainerFromFile('templating_php_assets_disabled'); + + $this->assertTrue(!$container->has('templating.helper.assets'), 'The templating.helper.assets helper service is removed when assets are disabled.'); + } + public function testAssetHelperWhenAssetsAndTemplatesAreDisabled() { $container = $this->createContainerFromFile('default_config'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php index 2c27eb0325112..03401e2482942 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php @@ -22,4 +22,9 @@ protected function loadFromFile(ContainerBuilder $container, $file) $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/xml')); $loader->load($file.'.xml'); } + + public function testAssetsHelperIsRemovedWhenPhpTemplatingEngineIsEnabledAndAssetsAreDisabled() + { + $this->markTestSkipped('The assets key cannot be set to false using the XML configuration format.'); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/icon.svg b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/icon.svg index 02033fdc7f5e9..5bd2f3b8f3799 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/icon.svg +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/icon.svg @@ -1,3 +1,3 @@ - + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml index 861b1e709fd13..61c1a54d99ba5 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/twig.yml @@ -3,5 +3,5 @@ framework: # Twig Configuration twig: - debug: %kernel.debug% - strict_variables: %kernel.debug% + debug: '%kernel.debug%' + strict_variables: '%kernel.debug%' diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/ajax.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/ajax.svg index d8cad847d4710..bd878c3c6c21f 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/ajax.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/ajax.svg @@ -1,4 +1,4 @@ - + + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/config.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/config.svg index 9bafe3830175f..a407719e8c761 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/config.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/config.svg @@ -1,3 +1,3 @@ - + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/event.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/event.svg index 7d15a66f01033..898117ef94558 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/event.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/event.svg @@ -1,4 +1,4 @@ - + + + + + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/menu.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/menu.svg index 856ea09ff85cb..51870801cf284 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/menu.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/menu.svg @@ -1,3 +1,3 @@ - + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no.svg index 02eb4e9c6abbb..c0bb768d40433 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no.svg @@ -1,4 +1,4 @@ - + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/request.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/request.svg index d74a72850dc04..68b092c6b8809 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/request.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/request.svg @@ -1,4 +1,4 @@ - + + + + + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/translation.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/translation.svg index 93d42327ed859..b7aa1249304b2 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/translation.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/translation.svg @@ -1,4 +1,4 @@ - + + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/yes.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/yes.svg index 0f129bffc21b0..da650231d520d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/yes.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/yes.svg @@ -1,4 +1,4 @@ - + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index 77db944870255..6e07edeb3f2a0 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -588,6 +588,7 @@ tr.status-warning td { #menu-profiler { margin: 0; padding: 0; + list-style-type: none; } #menu-profiler li { position: relative; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig index cade19d0b4c1a..5dd26a41eb9fa 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -47,6 +47,10 @@ text-align: left; text-transform: none; z-index: 99999; + + /* neutralize the aliasing defined by external CSS styles */ + -webkit-font-smoothing: subpixel-antialiased; + -moz-osx-font-smoothing: auto; } .sf-toolbarreset abbr { border: dashed #777; diff --git a/src/Symfony/Component/Config/Definition/Builder/EnumNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/EnumNodeDefinition.php index dc25fcbd26f26..5d3ff014f1823 100644 --- a/src/Symfony/Component/Config/Definition/Builder/EnumNodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/EnumNodeDefinition.php @@ -31,8 +31,8 @@ public function values(array $values) { $values = array_unique($values); - if (count($values) <= 1) { - throw new \InvalidArgumentException('->values() must be called with at least two distinct values.'); + if (empty($values)) { + throw new \InvalidArgumentException('->values() must be called with at least one value.'); } $this->values = $values; diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/EnumNodeDefinitionTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/EnumNodeDefinitionTest.php index 69f7fcfb22e9a..8d7ab2f7f03e9 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/EnumNodeDefinitionTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/EnumNodeDefinitionTest.php @@ -15,14 +15,22 @@ class EnumNodeDefinitionTest extends \PHPUnit_Framework_TestCase { - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage ->values() must be called with at least two distinct values. - */ - public function testNoDistinctValues() + public function testWithOneValue() + { + $def = new EnumNodeDefinition('foo'); + $def->values(array('foo')); + + $node = $def->getNode(); + $this->assertEquals(array('foo'), $node->getValues()); + } + + public function testWithOneDistinctValue() { $def = new EnumNodeDefinition('foo'); $def->values(array('foo', 'foo')); + + $node = $def->getNode(); + $this->assertEquals(array('foo'), $node->getValues()); } /** @@ -35,6 +43,16 @@ public function testNoValuesPassed() $def->getNode(); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage ->values() must be called with at least one value. + */ + public function testWithNoValues() + { + $def = new EnumNodeDefinition('foo'); + $def->values(array()); + } + public function testGetNode() { $def = new EnumNodeDefinition('foo'); diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php index 00e27c630a1dc..a146e89c32ae8 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php @@ -120,7 +120,7 @@ public function testDefinitionExampleGetsTransferredToNode() $tree = $builder->buildTree(); $children = $tree->getChildren(); - $this->assertTrue(is_array($tree->getExample())); + $this->assertInternalType('array', $tree->getExample()); $this->assertEquals('example', $children['child']->getExample()); } } diff --git a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php index 2bbaadc3a721e..0e64b4ce80917 100644 --- a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php @@ -19,7 +19,7 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->directory = sys_get_temp_dir().'/symfonyDirectoryIterator'; + $this->directory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'symfonyDirectoryIterator'; if (!file_exists($this->directory)) { mkdir($this->directory); } diff --git a/src/Symfony/Component/Config/composer.json b/src/Symfony/Component/Config/composer.json index d686929699913..81edb12fd00f3 100644 --- a/src/Symfony/Component/Config/composer.json +++ b/src/Symfony/Component/Config/composer.json @@ -19,6 +19,9 @@ "php": ">=5.5.9", "symfony/filesystem": "~2.8|~3.0" }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, "autoload": { "psr-4": { "Symfony\\Component\\Config\\": "" }, "exclude-from-classmap": [ diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 41c6657e0862a..a01d66952e3ef 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -424,7 +424,7 @@ public function has($name) public function getNamespaces() { $namespaces = array(); - foreach ($this->commands as $command) { + foreach ($this->all() as $command) { $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); foreach ($command->getAliases() as $alias) { diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 4e29d2ed4517d..8021068edfb13 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +2.8.3 +----- + + * remove readline support from the question helper as it caused issues + 2.8.0 ----- diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index cb870939b1cf3..c8429845a2634 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -383,7 +383,7 @@ public function addArgument($name, $mode = null, $description = '', $default = n * @param string $shortcut The shortcut (can be null) * @param int $mode The option mode: One of the InputOption::VALUE_* constants * @param string $description A description text - * @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or InputOption::VALUE_NONE) + * @param mixed $default The default value (must be null for InputOption::VALUE_NONE) * * @return Command The current instance */ diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index 244e25c61fbb6..56cd5e568f16d 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -33,7 +33,15 @@ class OutputFormatter implements OutputFormatterInterface */ public static function escape($text) { - return preg_replace('/([^\\\\]?)#ix", $message, $matches, PREG_OFFSET_CAPTURE); foreach ($matches[0] as $i => $match) { $pos = $match[1]; @@ -166,6 +174,10 @@ public function format($message) $output .= $this->applyCurrentStyle(substr($message, $offset)); + if (false !== strpos($output, '<<')) { + return strtr($output, array('\\<' => '<', '<<' => '\\')); + } + return str_replace('\\<', '<', $output); } diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 15b7cd6891e7c..c6f5a409c3dc8 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -130,7 +130,11 @@ private function doAsk(OutputInterface $output, Question $question) } if (false === $ret) { - $ret = $this->readFromInput($inputStream); + $ret = fgets($inputStream, 4096); + if (false === $ret) { + throw new \RuntimeException('Aborted'); + } + $ret = trim($ret); } } else { $ret = trim($this->autocomplete($output, $question, $inputStream)); @@ -423,30 +427,6 @@ private function getShell() return self::$shell; } - /** - * Reads user input. - * - * @param resource $stream The input stream - * - * @return string User input - * - * @throws RuntimeException - */ - private function readFromInput($stream) - { - if (STDIN === $stream && function_exists('readline')) { - $ret = readline(''); - } else { - $ret = fgets($stream, 4096); - } - - if (false === $ret) { - throw new RuntimeException('Aborted'); - } - - return trim($ret); - } - /** * Returns whether Stty is available or not. * diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index 3a752cb700dbe..f08c5f26c104a 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -39,7 +39,7 @@ class InputOption * @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param int $mode The option mode: One of the VALUE_* constants * @param string $description A description text - * @param mixed $default The default value (must be null for self::VALUE_REQUIRED or self::VALUE_NONE) + * @param mixed $default The default value (must be null for self::VALUE_NONE) * * @throws InvalidArgumentException If option mode is invalid or incompatible */ diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php index 71cb8f5c8b5a3..310a2bfed5274 100644 --- a/src/Symfony/Component/Console/Question/Question.php +++ b/src/Symfony/Component/Console/Question/Question.php @@ -143,7 +143,7 @@ public function setAutocompleterValues($values) } if (null !== $values && !is_array($values)) { - if (!$values instanceof \Traversable || $values instanceof \Countable) { + if (!$values instanceof \Traversable || !$values instanceof \Countable) { throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.'); } } diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index 46d5fe1580faf..b8d5ca6d9bebb 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -98,8 +98,8 @@ public function testStyleEscaping() $formatter = new OutputFormatter(true); $this->assertEquals( - "(\033[32mz>=2.0,format('('.$formatter->escape('z>=2.0,)') + "(\033[32mz>=2.0,<<format('('.$formatter->escape('z>=2.0,<\\<)') ); $this->assertEquals( diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index ec7880be89b95..67b9008423bb2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -148,45 +148,17 @@ private function populateAvailableType($id, Definition $definition) $this->types[$type] = $id; } - // Cannot use reflection if the class isn't set - if (!$definition->getClass()) { + if (!$reflectionClass = $this->getReflectionClass($id, $definition)) { return; } - if ($reflectionClass = $this->getReflectionClass($id, $definition)) { - $this->extractInterfaces($id, $reflectionClass); - $this->extractAncestors($id, $reflectionClass); - } - } - - /** - * Extracts the list of all interfaces implemented by a class. - * - * @param string $id - * @param \ReflectionClass $reflectionClass - */ - private function extractInterfaces($id, \ReflectionClass $reflectionClass) - { - foreach ($reflectionClass->getInterfaces() as $interfaceName => $reflectionInterface) { - $this->set($interfaceName, $id); - - $this->extractInterfaces($id, $reflectionInterface); + foreach ($reflectionClass->getInterfaces() as $reflectionInterface) { + $this->set($reflectionInterface->name, $id); } - } - - /** - * Extracts all inherited types of a class. - * - * @param string $id - * @param \ReflectionClass $reflectionClass - */ - private function extractAncestors($id, \ReflectionClass $reflectionClass) - { - $this->set($reflectionClass->name, $id); - if ($reflectionParentClass = $reflectionClass->getParentClass()) { - $this->extractAncestors($id, $reflectionParentClass); - } + do { + $this->set($reflectionClass->name, $id); + } while ($reflectionClass = $reflectionClass->getParentClass()); } /** @@ -256,6 +228,7 @@ private function getReflectionClass($id, Definition $definition) return $this->reflectionClasses[$id]; } + // Cannot use reflection if the class isn't set if (!$class = $definition->getClass()) { return; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php index 8308937d4a512..cb79c111afc41 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -95,6 +95,8 @@ private function updateReferences($container, $currentId, $newId) $definition->setProperties( $this->updateArgumentReferences($definition->getProperties(), $currentId, $newId) ); + + $definition->setFactory($this->updateFactoryReference($definition->getFactory(), $currentId, $newId)); } } @@ -122,4 +124,17 @@ private function updateArgumentReferences(array $arguments, $currentId, $newId) return $arguments; } + + private function updateFactoryReference($factory, $currentId, $newId) + { + if (null === $factory || !is_array($factory) || !$factory[0] instanceof Reference) { + return $factory; + } + + if ($currentId === (string) $factory[0]) { + $factory[0] = new Reference($newId, $factory[0]->getInvalidBehavior()); + } + + return $factory; + } } diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index f383744f2121b..3a144de90d1e0 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -169,6 +169,10 @@ public function set($id, $service) throw new InvalidArgumentException('You cannot set service "service_container".'); } + if (isset($this->aliases[$id])) { + unset($this->aliases[$id]); + } + $this->services[$id] = $service; if (null === $service) { diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index cd0b64c731c38..aae5460ace603 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -18,6 +18,8 @@ use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Resource\ResourceInterface; @@ -259,7 +261,9 @@ public function addClassResource(\ReflectionClass $class) } do { - $this->addResource(new FileResource($class->getFileName())); + if (is_file($class->getFileName())) { + $this->addResource(new FileResource($class->getFileName())); + } } while ($class = $class->getParentClass()); return $this; @@ -396,8 +400,9 @@ public function has($id) * * @return object The associated service * - * @throws InvalidArgumentException when no definitions are available - * @throws LogicException when a circular dependency is detected + * @throws InvalidArgumentException when no definitions are available + * @throws ServiceCircularReferenceException When a circular reference is detected + * @throws ServiceNotFoundException When the service is not defined * @throws \Exception * * @see Reference @@ -416,7 +421,7 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV try { $definition = $this->getDefinition($id); - } catch (InvalidArgumentException $e) { + } catch (ServiceNotFoundException $e) { if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) { return; } @@ -756,14 +761,14 @@ public function hasDefinition($id) * * @return Definition A Definition instance * - * @throws InvalidArgumentException if the service definition does not exist + * @throws ServiceNotFoundException if the service definition does not exist */ public function getDefinition($id) { $id = strtolower($id); if (!array_key_exists($id, $this->definitions)) { - throw new InvalidArgumentException(sprintf('The service definition "%s" does not exist.', $id)); + throw new ServiceNotFoundException($id); } return $this->definitions[$id]; @@ -778,7 +783,7 @@ public function getDefinition($id) * * @return Definition A Definition instance * - * @throws InvalidArgumentException if the service definition does not exist + * @throws ServiceNotFoundException if the service definition does not exist */ public function findDefinition($id) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 8f9192f356c0e..32b261cd96adf 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -315,7 +315,7 @@ private function addServiceInlinedDefinitions($id, $definition) throw new ServiceCircularReferenceException($id, array($id)); } - $code .= $this->addNewInstance($id, $sDefinition, '$'.$name, ' = '); + $code .= $this->addNewInstance($sDefinition, '$'.$name, ' = '); if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) { $code .= $this->addServiceMethodCalls(null, $sDefinition, $name); @@ -389,7 +389,7 @@ private function addServiceInstance($id, $definition) $instantiation .= ' = '; } - $code = $this->addNewInstance($id, $definition, $return, $instantiation); + $code = $this->addNewInstance($definition, $return, $instantiation); if (!$simple) { $code .= "\n"; @@ -676,7 +676,7 @@ private function addServices() return $publicServices.$privateServices; } - private function addNewInstance($id, Definition $definition, $return, $instantiation) + private function addNewInstance(Definition $definition, $return, $instantiation) { $class = $this->dumpValue($definition->getClass()); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index 14c7022cfb226..24ec562a403c7 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -65,7 +65,7 @@ private function addService($id, $definition) $class = substr($class, 1); } - $code .= sprintf(" class: %s\n", $class); + $code .= sprintf(" class: %s\n", $this->dumper->dump($class)); } if (!$definition->isPublic()) { @@ -89,7 +89,7 @@ private function addService($id, $definition) } if ($definition->getFile()) { - $code .= sprintf(" file: %s\n", $definition->getFile()); + $code .= sprintf(" file: %s\n", $this->dumper->dump($definition->getFile())); } if ($definition->isSynthetic()) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index f1ed72e94a4cd..28d6ab6339eea 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -61,9 +61,10 @@ public function testProcessAutowireInterface() $pass = new AutowirePass(); $pass->process($container); - $this->assertCount(2, $container->getDefinition('g')->getArguments()); + $this->assertCount(3, $container->getDefinition('g')->getArguments()); $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(0)); $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(1)); + $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(2)); } public function testCompleteExistingDefinition() @@ -317,13 +318,21 @@ interface EInterface extends DInterface { } -class F implements EInterface +interface IInterface +{ +} + +class I implements IInterface +{ +} + +class F extends I implements EInterface { } class G { - public function __construct(DInterface $d, EInterface $e) + public function __construct(DInterface $d, EInterface $e, IInterface $i) { } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php index e4d22401d3cdd..474c0eb9c726e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php @@ -14,6 +14,9 @@ use Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +require_once __DIR__.'/../Fixtures/includes/foo.php'; class ReplaceAliasByActualDefinitionPassTest extends \PHPUnit_Framework_TestCase { @@ -21,7 +24,8 @@ public function testProcess() { $container = new ContainerBuilder(); - $container->register('a', '\stdClass'); + $aDefinition = $container->register('a', '\stdClass'); + $aDefinition->setFactory(array(new Reference('b'), 'createA')); $bDefinition = new Definition('\stdClass'); $bDefinition->setPublic(false); @@ -39,6 +43,9 @@ public function testProcess() $container->has('b_alias') && !$container->hasAlias('b_alias'), '->process() replaces alias to actual.' ); + + $resolvedFactory = $aDefinition->getFactory(false); + $this->assertSame('b_alias', (string) $resolvedFactory[0]); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index f252b56b13b64..87bfd012b33f7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -20,6 +20,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Exception\InactiveScopeException; +use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; @@ -49,9 +52,9 @@ public function testDefinitions() try { $builder->getDefinition('baz'); - $this->fail('->getDefinition() throws an InvalidArgumentException if the service definition does not exist'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals('The service definition "baz" does not exist.', $e->getMessage(), '->getDefinition() throws an InvalidArgumentException if the service definition does not exist'); + $this->fail('->getDefinition() throws a ServiceNotFoundException if the service definition does not exist'); + } catch (ServiceNotFoundException $e) { + $this->assertEquals('You have requested a non-existent service "baz".', $e->getMessage(), '->getDefinition() throws a ServiceNotFoundException if the service definition does not exist'); } } @@ -101,9 +104,9 @@ public function testGet() $builder = new ContainerBuilder(); try { $builder->get('foo'); - $this->fail('->get() throws an InvalidArgumentException if the service does not exist'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals('The service definition "foo" does not exist.', $e->getMessage(), '->get() throws an InvalidArgumentException if the service does not exist'); + $this->fail('->get() throws a ServiceNotFoundException if the service does not exist'); + } catch (ServiceNotFoundException $e) { + $this->assertEquals('You have requested a non-existent service "foo".', $e->getMessage(), '->get() throws a ServiceNotFoundException if the service does not exist'); } $this->assertNull($builder->get('foo', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service does not exist and NULL_ON_INVALID_REFERENCE is passed as a second argument'); @@ -231,6 +234,16 @@ public function testAddAliases() $this->assertTrue(isset($aliases['foobar'])); } + public function testSetReplacesAlias() + { + $builder = new ContainerBuilder(); + $builder->setAlias('alias', 'aliased'); + $builder->set('aliased', new \stdClass()); + + $builder->set('alias', $foo = new \stdClass()); + $this->assertSame($foo, $builder->get('alias'), '->set() replaces an existing alias'); + } + public function testAddGetCompilerPass() { $builder = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php index 17b6ee6e9c79a..a9f41c56a22bb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php @@ -142,6 +142,14 @@ public function testSetWithNullResetTheService() $this->assertFalse($sc->has('foo'), '->set() with null service resets the service'); } + public function testSetReplacesAlias() + { + $c = new ProjectServiceContainer(); + + $c->set('alias', $foo = new \stdClass()); + $this->assertSame($foo, $c->get('alias'), '->set() replaces an existing alias'); + } + public function testGet() { $sc = new ProjectServiceContainer(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index a2ed68cd0b0f9..cd403c6d43104 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\YamlDumper; +use Symfony\Component\Yaml\Yaml; class YamlDumperTest extends \PHPUnit_Framework_TestCase { @@ -27,24 +28,21 @@ public function testDump() { $dumper = new YamlDumper($container = new ContainerBuilder()); - $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services1.yml', $dumper->dump(), '->dump() dumps an empty container as an empty YAML file'); - - $container = new ContainerBuilder(); - $dumper = new YamlDumper($container); + $this->assertEqualYamlStructure(file_get_contents(self::$fixturesPath.'/yaml/services1.yml'), $dumper->dump(), '->dump() dumps an empty container as an empty YAML file'); } public function testAddParameters() { $container = include self::$fixturesPath.'/containers/container8.php'; $dumper = new YamlDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services8.yml', $dumper->dump(), '->dump() dumps parameters'); + $this->assertEqualYamlStructure(file_get_contents(self::$fixturesPath.'/yaml/services8.yml'), $dumper->dump(), '->dump() dumps parameters'); } public function testAddService() { $container = include self::$fixturesPath.'/containers/container9.php'; $dumper = new YamlDumper($container); - $this->assertEquals(str_replace('%path%', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/yaml/services9.yml')), $dumper->dump(), '->dump() dumps services'); + $this->assertEqualYamlStructure(str_replace('%path%', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/yaml/services9.yml')), $dumper->dump(), '->dump() dumps services'); $dumper = new YamlDumper($container = new ContainerBuilder()); $container->register('foo', 'FooClass')->addArgument(new \stdClass()); @@ -63,4 +61,9 @@ public function testDumpAutowireData() $dumper = new YamlDumper($container); $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services24.yml', $dumper->dump()); } + + private function assertEqualYamlStructure($yaml, $expected, $message = '') + { + $this->assertEquals(Yaml::parse($expected), Yaml::parse($yaml), $message); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml index f2f8d953d57a3..c66084cdbe8e6 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services10.yml @@ -6,4 +6,4 @@ services: class: BAR project: - test: %project.parameter.foo% + test: '%project.parameter.foo%' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml index db554d7f5feb3..08a1df1e6bfcc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml @@ -2,7 +2,7 @@ services: foo: { class: FooClass } baz: { class: BazClass } not_shared: { class: FooClass, shared: false } - file: { class: FooClass, file: %path%/foo.php } + file: { class: FooClass, file: '%path%/foo.php' } arguments: { class: FooClass, arguments: [foo, '@foo', [true, false]] } configurator1: { class: FooClass, configurator: sc_configure } configurator2: { class: FooClass, configurator: ['@baz', configure] } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml index 37f7e1951631e..6efeb37e747d4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml @@ -18,7 +18,7 @@ services: factory: [Bar\FooClass, getInstance] configurator: sc_configure foo.baz: - class: %baz_class% + class: '%baz_class%' factory: ['%baz_class%', getInstance] configurator: ['%baz_class%', configureStatic1] bar: @@ -26,11 +26,11 @@ services: arguments: [foo, '@foo.baz', '%foo_bar%'] configurator: ['@foo.baz', configure] foo_bar: - class: %foo_class% + class: '%foo_class%' shared: false method_call1: class: Bar\FooClass - file: %path%foo.php + file: '%path%foo.php' calls: - [setBar, ['@foo']] - [setBar, ['@?foo2']] diff --git a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php index fcf510c370a06..3e05015873588 100644 --- a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php +++ b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php @@ -59,6 +59,10 @@ public function hasValue() */ public function isDisabled() { + if (parent::isDisabled() && 'select' === $this->type) { + return true; + } + foreach ($this->options as $option) { if ($option['value'] == $this->value && $option['disabled']) { return true; diff --git a/src/Symfony/Component/DomCrawler/Form.php b/src/Symfony/Component/DomCrawler/Form.php index 0c7a3b2ec5c6c..c9c3c139b112b 100644 --- a/src/Symfony/Component/DomCrawler/Form.php +++ b/src/Symfony/Component/DomCrawler/Form.php @@ -157,8 +157,12 @@ public function getPhpValues() * * This method converts fields with the array notation * (like foo[bar] to arrays) like PHP does. + * The returned array is consistent with the array for field values + * (@see getPhpValues), rather than uploaded files found in $_FILES. + * For a compound file field foo[bar] it will create foo[bar][name], + * instead of foo[name][bar] which would be found in $_FILES. * - * @return array An array of field values. + * @return array An array of file field values. */ public function getPhpFiles() { diff --git a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php index 9b31945b237f8..8b35cc9ac5ba0 100644 --- a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php @@ -120,6 +120,14 @@ public function testSelectWithEmptyBooleanAttribute() $this->assertEquals('bar', $field->getValue()); } + public function testSelectIsDisabled() + { + $node = $this->createSelectNode(array('foo' => false, 'bar' => true), array('disabled' => 'disabled')); + $field = new ChoiceFormField($node); + + $this->assertTrue($field->isDisabled(), '->isDisabled() returns true for selects with a disabled attribute'); + } + public function testMultipleSelects() { $node = $this->createSelectNode(array('foo' => false, 'bar' => false), array('multiple' => 'multiple')); diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 8e96f1a87da8b..604568565ee93 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -115,6 +115,10 @@ public function mkdir($dirs, $mode = 0777) public function exists($files) { foreach ($this->toIterator($files) as $file) { + if ('\\' === DIRECTORY_SEPARATOR && strlen($file) > 258) { + throw new IOException('Could not check if file exist because path length exceeds 258 characters.', 0, null, $file); + } + if (!file_exists($file)) { return false; } @@ -154,7 +158,7 @@ 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)) { + if (!$this->exists($file) && !is_link($file)) { continue; } @@ -268,7 +272,7 @@ public function chgrp($files, $group, $recursive = false) public function rename($origin, $target, $overwrite = false) { // we check that target does not exist - if (!$overwrite && is_readable($target)) { + if (!$overwrite && $this->isReadable($target)) { throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); } @@ -277,6 +281,22 @@ public function rename($origin, $target, $overwrite = false) } } + /** + * Tells whether a file exists and is readable. + * + * @param string $filename Path to the file. + * + * @throws IOException When windows path is longer than 258 characters + */ + private function isReadable($filename) + { + if ('\\' === DIRECTORY_SEPARATOR && strlen($filename) > 258) { + throw new IOException('Could not check if file is readable because path length exceeds 258 characters.', 0, null, $filename); + } + + return is_readable($filename); + } + /** * Creates a symbolic link or copy a directory. * diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 847694a5054ce..a5d234d3b7da2 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -358,6 +358,28 @@ public function testFilesExists() $this->assertTrue($this->filesystem->exists($basePath.'folder')); } + /** + * @expectedException \Symfony\Component\Filesystem\Exception\IOException + */ + public function testFilesExistsFails() + { + if ('\\' !== DIRECTORY_SEPARATOR) { + $this->markTestSkipped('Test covers edge case on Windows only.'); + } + + $basePath = $this->workspace.'\\directory\\'; + + $oldPath = getcwd(); + mkdir($basePath); + chdir($basePath); + $file = str_repeat('T', 259 - strlen($basePath)); + $path = $basePath.$file; + exec('TYPE NUL >>'.$file); // equivalent of touch, we can not use the php touch() here because it suffers from the same limitation + self::$longPathNamesWindows[] = $path; // save this so we can clean up later + chdir($oldPath); + $this->filesystem->exists($path); + } + public function testFilesExistsTraversableObjectOfFilesAndDirectories() { $basePath = $this->workspace.DIRECTORY_SEPARATOR; diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php index 1df8c078a6b6e..e1955c38b733c 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php @@ -17,6 +17,8 @@ class FilesystemTestCase extends \PHPUnit_Framework_TestCase { private $umask; + static protected $longPathNamesWindows = array(); + /** * @var \Symfony\Component\Filesystem\Filesystem */ @@ -31,6 +33,12 @@ class FilesystemTestCase extends \PHPUnit_Framework_TestCase public static function setUpBeforeClass() { + if (!empty(self::$longPathNamesWindows)) { + foreach (self::$longPathNamesWindows as $path) { + exec('DEL '.$path); + } + } + if ('\\' === DIRECTORY_SEPARATOR && null === self::$symlinkOnWindows) { $target = tempnam(sys_get_temp_dir(), 'sl'); $link = sys_get_temp_dir().'/sl'.microtime(true).mt_rand(); diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index b8bb200b54919..80cb6a39dd8d6 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -70,7 +70,7 @@ public function __construct($choices, callable $value = null) if (null === $value && $this->castableToString($choices)) { $value = function ($choice) { - return (string) $choice; + return false === $choice ? '0' : (string) $choice; }; } @@ -229,11 +229,11 @@ private function castableToString(array $choices, array &$cache = array()) continue; } elseif (!is_scalar($choice)) { return false; - } elseif (isset($cache[(string) $choice])) { + } elseif (isset($cache[$choice])) { return false; } - $cache[(string) $choice] = true; + $cache[$choice] = true; } return true; diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php index e632c1238c861..3398c98edd742 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php @@ -120,11 +120,21 @@ private static function addChoiceView($choice, $value, $label, $keys, &$index, $ $key = $keys[$value]; $nextIndex = is_int($index) ? $index++ : call_user_func($index, $choice, $key, $value); + // BC normalize label to accept a false value + if (null === $label) { + // If the labels are null, use the original choice key by default + $label = (string) $key; + } elseif (false !== $label) { + // If "choice_label" is set to false and "expanded" is true, the value false + // should be passed on to the "label" option of the checkboxes/radio buttons + $dynamicLabel = call_user_func($label, $choice, $key, $value); + $label = false === $dynamicLabel ? false : (string) $dynamicLabel; + } + $view = new ChoiceView( $choice, $value, - // If the labels are null, use the original choice key by default - null === $label ? (string) $key : (string) call_user_func($label, $choice, $key, $value), + $label, // The attributes may be a callable or a mapping from choice indices // to nested arrays is_callable($attr) ? call_user_func($attr, $choice, $key, $value) : (isset($attr[$key]) ? $attr[$key] : array()) @@ -211,7 +221,7 @@ private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label $groupLabel = (string) $groupLabel; - // Initialize the group views if necessary. Unnnecessarily built group + // Initialize the group views if necessary. Unnecessarily built group // views will be cleaned up at the end of createView() if (!isset($preferredViews[$groupLabel])) { $preferredViews[$groupLabel] = new ChoiceGroupView($groupLabel); diff --git a/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php b/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php index 9641f4b1d9435..99308b826f7a5 100644 --- a/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php +++ b/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php @@ -48,4 +48,24 @@ public function __construct(array $choices = array(), array $preferredChoices = $this->choices = $choices; $this->preferredChoices = $preferredChoices; } + + /** + * Returns whether a placeholder is in the choices. + * + * A placeholder must be the first child element, not be in a group and have an empty value. + * + * @return bool + */ + public function hasPlaceholder() + { + if ($this->preferredChoices) { + $firstChoice = reset($this->preferredChoices); + + return $firstChoice instanceof ChoiceView && '' === $firstChoice->value; + } + + $firstChoice = reset($this->choices); + + return $firstChoice instanceof ChoiceView && '' === $firstChoice->value; + } } diff --git a/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php b/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php index 19db183a28394..d08a603b5c90e 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php +++ b/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php @@ -38,13 +38,11 @@ public function __construct(ChoiceListInterface $choiceList) /** * {@inheritdoc} */ - public function mapDataToForms($choice, $radios) + public function mapDataToForms($data, $radios) { - $valueMap = array_flip($this->choiceList->getValuesForChoices(array($choice))); - foreach ($radios as $radio) { $value = $radio->getConfig()->getOption('value'); - $radio->setData(isset($valueMap[$value]) ? true : false); + $radio->setData($value === $data ? true : false); } } diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php index ffffddedc3bef..c7a6655b4e65a 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php @@ -39,8 +39,8 @@ public function transform($choice) public function reverseTransform($value) { - if (null !== $value && !is_scalar($value)) { - throw new TransformationFailedException('Expected a scalar.'); + if (null !== $value && !is_string($value)) { + throw new TransformationFailedException('Expected a string or null.'); } $choices = $this->choiceList->getChoicesForValues(array((string) $value)); diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php index 197f556308f25..d8369abfd4889 100644 --- a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php +++ b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php @@ -102,10 +102,6 @@ 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)) { $data = array(); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index dfe4ffb092d56..65d607077bf59 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -144,6 +144,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) $event->setData(null); } }); + // For radio lists, pre selection of the choice needs to pre set data + // with the string value so it can be matched in + // {@link \Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper::mapDataToForms()} + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $choiceList = $event->getForm()->getConfig()->getAttribute('choice_list'); + $value = current($choiceList->getValuesForChoices(array($event->getData()))); + $event->setData((string) $value); + }); } } elseif ($options['multiple']) { // An authentication exception occurred. - En autentiserings feil har skjedd. + En autentiseringsfeil har skjedd. Authentication credentials could not be found. @@ -24,7 +24,7 @@ Not privileged to request the resource. - Ingen tilgang til å be om gitt kilde. + Ingen tilgang til å be om gitt ressurs. Invalid CSRF token. diff --git a/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php new file mode 100644 index 0000000000000..dc38e4a776f07 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Tests\Resources; + +class TranslationFilesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValid($filePath) + { + \PHPUnit_Util_XML::loadfile($filePath, false, false, true); + } + + public function provideTranslationFiles() + { + return array_map( + function ($filePath) { return (array) $filePath; }, + glob(dirname(dirname(__DIR__)).'/Resources/translations/*.xlf') + ); + } +} diff --git a/src/Symfony/Component/Validator/ConstraintValidatorFactory.php b/src/Symfony/Component/Validator/ConstraintValidatorFactory.php index cc6981b9461ce..86e44e2a5580f 100644 --- a/src/Symfony/Component/Validator/ConstraintValidatorFactory.php +++ b/src/Symfony/Component/Validator/ConstraintValidatorFactory.php @@ -26,11 +26,8 @@ class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface { protected $validators = array(); - private $propertyAccessor; - - public function __construct($propertyAccessor = null) + public function __construct() { - $this->propertyAccessor = $propertyAccessor; } /** @@ -42,7 +39,7 @@ public function getInstance(Constraint $constraint) if (!isset($this->validators[$className])) { $this->validators[$className] = 'validator.expression' === $className - ? new ExpressionValidator($this->propertyAccessor) + ? new ExpressionValidator() : new $className(); } diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php index 46ddceece0276..e2f3139af73b8 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php @@ -12,12 +12,8 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; -use Symfony\Component\PropertyAccess\PropertyAccess; -use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Exception\RuntimeException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -27,19 +23,13 @@ */ class ExpressionValidator extends ConstraintValidator { - /** - * @var PropertyAccessorInterface - */ - private $propertyAccessor; - /** * @var ExpressionLanguage */ private $expressionLanguage; - public function __construct(PropertyAccessorInterface $propertyAccessor = null, ExpressionLanguage $expressionLanguage = null) + public function __construct($propertyAccessor = null, ExpressionLanguage $expressionLanguage = null) { - $this->propertyAccessor = $propertyAccessor; $this->expressionLanguage = $expressionLanguage; } @@ -53,28 +43,8 @@ public function validate($value, Constraint $constraint) } $variables = array(); - - // Symfony 2.5+ - if ($this->context instanceof ExecutionContextInterface) { - $variables['value'] = $value; - $variables['this'] = $this->context->getObject(); - } elseif (null === $this->context->getPropertyName()) { - $variables['value'] = $value; - $variables['this'] = $value; - } else { - $root = $this->context->getRoot(); - $variables['value'] = $value; - - if (is_object($root)) { - // Extract the object that the property belongs to from the object - // graph - $path = new PropertyPath($this->context->getPropertyPath()); - $parentPath = $path->getParent(); - $variables['this'] = $parentPath ? $this->getPropertyAccessor()->getValue($root, $parentPath) : $root; - } else { - $variables['this'] = null; - } - } + $variables['value'] = $value; + $variables['this'] = $this->context->getObject(); if (!$this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) { $this->context->buildViolation($constraint->message) @@ -95,16 +65,4 @@ private function getExpressionLanguage() return $this->expressionLanguage; } - - private function getPropertyAccessor() - { - if (null === $this->propertyAccessor) { - if (!class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) { - throw new RuntimeException('Unable to use expressions as the Symfony PropertyAccess component is not installed.'); - } - $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); - } - - return $this->propertyAccessor; - } } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index b50ecbc63a1b5..72d4d92973fdc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -310,6 +310,10 @@ This value does not match the expected {{ charset }} charset. Cette valeur ne correspond pas au jeu de caractères {{ charset }} attendu. + + This is not a valid Business Identifier Code (BIC). + Ce n'est pas un code universel d'identification des banques (BIC) valide. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf deleted file mode 100644 index a8b790c7d8640..0000000000000 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - This value should be false. - Verdien skal være falsk. - - - This value should be true. - Verdien skal være sann. - - - This value should be of type {{ type }}. - Verdien skal være av typen {{ type }}. - - - This value should be blank. - Verdien skal være blank. - - - The value you selected is not a valid choice. - Verdien skal være en av de gitte valg. - - - You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Du skal velge minst {{ limit }} valg. - - - You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Du kan maks velge {{ limit }} valg. - - - One or more of the given values is invalid. - En eller flere av de oppgitte verdier er ugyldige. - - - This field was not expected. - Dette feltet ikke var forventet. - - - This field is missing. - Dette feltet mangler. - - - This value is not a valid date. - Verdien er ikke en gyldig dato. - - - This value is not a valid datetime. - Verdien er ikke en gyldig dato og tid. - - - This value is not a valid email address. - Verdien er ikke en gyldig e-mail adresse. - - - The file could not be found. - Filen kunne ikke finnes. - - - The file is not readable. - Filen kan ikke leses. - - - The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - Filen er for stor ({{ size }} {{ suffix }}). Tilatte maksimale størrelse {{ limit }} {{ suffix }}. - - - The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Mimetypen av filen er ugyldig ({{ type }}). Tilatte mimetyper er {{ types }}. - - - This value should be {{ limit }} or less. - Verdien skal være {{ limit }} eller mindre. - - - This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Verdien er for lang. Den skal ha {{ limit }} bokstaver eller mindre. - - - This value should be {{ limit }} or more. - Verdien skal være {{ limit }} eller mer. - - - This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Verdien er for kort. Den skal ha {{ limit }} tegn eller flere. - - - This value should not be blank. - Verdien må ikke være blank. - - - This value should not be null. - Verdien må ikke være tom (null). - - - This value should be null. - Verdien skal være tom (null). - - - This value is not valid. - Verdien er ikke gyldig. - - - This value is not a valid time. - Verdien er ikke en gyldig tid. - - - This value is not a valid URL. - Verdien er ikke en gyldig URL. - - - The two values should be equal. - De to verdier skal være ens. - - - The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - Filen er for stor. Den maksimale størrelse er {{ limit }} {{ suffix }}. - - - The file is too large. - Filen er for stor. - - - The file could not be uploaded. - Filen kunne ikke lastes opp. - - - This value should be a valid number. - Denne verdi skal være et gyldig tall. - - - This file is not a valid image. - Denne filen er ikke et gyldig bilde. - - - This is not a valid IP address. - Dette er ikke en gyldig IP adresse. - - - This value is not a valid language. - Denne verdi er ikke et gyldig språk. - - - This value is not a valid locale. - Denne verdi er ikke en gyldig lokalitet. - - - This value is not a valid country. - Denne verdi er ikke et gyldig land. - - - - diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf new file mode 100644 index 0000000000000..ea01c63ee4aa4 --- /dev/null +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf @@ -0,0 +1,227 @@ + + + + + + This value should be false. + Verdien skulle ha vore tom/nei. + + + This value should be true. + Verdien skulla ha vore satt/ja. + + + This value should be of type {{ type }}. + Verdien må vere av typen {{ type }}. + + + This value should be blank. + Verdien skal vere blank. + + + The value you selected is not a valid choice. + Verdien du valgte er ikkje gyldig. + + + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. + Du må velge minst {{ limit }} valg. + + + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. + Du kan maksimalt gjere {{ limit }} valg. + + + One or more of the given values is invalid. + Ein eller fleire av dei opplyste verdiane er ugyldige. + + + This field was not expected. + Dette feltet var ikke forventet. + + + This field is missing. + Dette feltet mangler. + + + This value is not a valid date. + Verdien er ikkje ein gyldig dato. + + + This value is not a valid datetime. + Verdien er ikkje ein gyldig dato og tid. + + + This value is not a valid email address. + Verdien er ikkje ei gyldig e-postadresse. + + + The file could not be found. + Fila kunne ikkje finnes. + + + The file is not readable. + Fila kan ikkje lesast. + + + The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. + Fila er for stor ({{ size }} {{ suffix }}). Tillatt maksimal størrelse er {{ limit }} {{ suffix }}. + + + The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. + Mime-typen av fila er ugyldig ({{ type }}). Tillatte mime-typar er {{ types }}. + + + This value should be {{ limit }} or less. + Verdien må vere {{ limit }} eller mindre. + + + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. + Verdien er for lang. Den må vere {{ limit }} bokstavar eller mindre. + + + This value should be {{ limit }} or more. + Verdien må vere {{ limit }} eller meir. + + + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. + Verdien er for kort. Den må ha {{ limit }} teikn eller fleire. + + + This value should not be blank. + Verdien må ikkje vere blank. + + + This value should not be null. + Verdien må ikkje vere tom (null). + + + This value should be null. + Verdien må vere tom (null). + + + This value is not valid. + Verdien er ikkje gyldig. + + + This value is not a valid time. + Verdien er ikkje gyldig tidseining. + + + This value is not a valid URL. + Verdien er ikkje ein gyldig URL. + + + The two values should be equal. + Dei to verdiane må vere like. + + + The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. + Fila er for stor. Den maksimale storleik er {{ limit }} {{ suffix }}. + + + The file is too large. + Fila er for stor. + + + The file could not be uploaded. + Fila kunne ikkje bli lasta opp. + + + This value should be a valid number. + Verdien må vere eit gyldig tal. + + + This file is not a valid image. + Fila er ikkje eit gyldig bilete. + + + This is not a valid IP address. + Dette er ikkje ei gyldig IP-adresse. + + + This value is not a valid language. + Verdien er ikkje eit gyldig språk. + + + This value is not a valid locale. + Verdien er ikkje ein gyldig lokalitet (språk/region). + + + This value is not a valid country. + Verdien er ikkje eit gyldig land. + + + This value is already used. + Verdien er allereie i bruk. + + + The size of the image could not be detected. + Storleiken på biletet kunne ikkje oppdagast. + + + The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. + Biletbreidda er for stor, ({{ width }} pikslar). Tillatt maksimumsbreidde er {{ max_width }} pikslar. + + + The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. + Biletbreidda er for liten, ({{ width }} pikslar). Forventa minimumsbreidde er {{ min_width }} pikslar. + + + The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. + Bilethøgda er for stor, ({{ height }} pikslar). Tillatt maksimumshøgde er {{ max_height }} pikslar. + + + The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. + Billethøgda er for låg, ({{ height }} pikslar). Forventa minimumshøgde er {{ min_height }} pikslar. + + + This value should be the user's current password. + Verdien må vere brukaren sitt noverande passord. + + + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. + Verdien må vere nøyaktig {{ limit }} teikn. + + + The file was only partially uploaded. + Fila vart kun delvis opplasta. + + + No file was uploaded. + Inga fil vart lasta opp. + + + No temporary folder was configured in php.ini. + Førebels mappe (tmp) er ikkje konfigurert i php.ini. + + + Cannot write temporary file to disk. + Kan ikkje skrive førebels fil til disk. + + + A PHP extension caused the upload to fail. + Ei PHP-udviding forårsaka feil under opplasting. + + + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. + Denne samlinga må innehalde {{ limit }} element eller meir.|Denne samlinga må innehalde {{ limit }} element eller meir. + + + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. + Denne samlinga må innehalde {{ limit }} element eller færre.|Denne samlinga må innehalde {{ limit }} element eller færre. + + + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. + Denne samlinga må innehalde nøyaktig {{ limit }} element.|Denne samlinga må innehalde nøyaktig {{ limit }} element. + + + Invalid card number. + Ugyldig kortnummer. + + + Unsupported card type or invalid card number. + Korttypen er ikkje støtta eller ugyldig kortnummer. + + + + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index ea01c63ee4aa4..5a9347652a911 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -4,23 +4,23 @@ This value should be false. - Verdien skulle ha vore tom/nei. + Verdien må være usann. This value should be true. - Verdien skulla ha vore satt/ja. + Verdien må være sann. This value should be of type {{ type }}. - Verdien må vere av typen {{ type }}. + Verdien må være av typen {{ type }}. This value should be blank. - Verdien skal vere blank. + Verdien må være blank. The value you selected is not a valid choice. - Verdien du valgte er ikkje gyldig. + Den valgte verdien er ikke gyldig. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. @@ -28,11 +28,11 @@ You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Du kan maksimalt gjere {{ limit }} valg. + Du kan maks velge {{ limit }} valg. One or more of the given values is invalid. - Ein eller fleire av dei opplyste verdiane er ugyldige. + En eller flere av de oppgitte verdiene er ugyldige. This field was not expected. @@ -44,175 +44,175 @@ This value is not a valid date. - Verdien er ikkje ein gyldig dato. + Verdien er ikke en gyldig dato. This value is not a valid datetime. - Verdien er ikkje ein gyldig dato og tid. + Verdien er ikke en gyldig dato/tid. This value is not a valid email address. - Verdien er ikkje ei gyldig e-postadresse. + Verdien er ikke en gyldig e-postadresse. The file could not be found. - Fila kunne ikkje finnes. + Filen kunne ikke finnes. The file is not readable. - Fila kan ikkje lesast. + Filen er ikke lesbar. The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - Fila er for stor ({{ size }} {{ suffix }}). Tillatt maksimal størrelse er {{ limit }} {{ suffix }}. + Filen er for stor ({{ size }} {{ suffix }}). Tilatte maksimale størrelse {{ limit }} {{ suffix }}. The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Mime-typen av fila er ugyldig ({{ type }}). Tillatte mime-typar er {{ types }}. + Mimetypen av filen er ugyldig ({{ type }}). Tilatte mimetyper er {{ types }}. This value should be {{ limit }} or less. - Verdien må vere {{ limit }} eller mindre. + Verdien må være {{ limit }} tegn lang eller mindre. This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Verdien er for lang. Den må vere {{ limit }} bokstavar eller mindre. + Verdien er for lang. Den må ha {{ limit }} tegn eller mindre. This value should be {{ limit }} or more. - Verdien må vere {{ limit }} eller meir. + Verdien må være {{ limit }} eller mer. This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Verdien er for kort. Den må ha {{ limit }} teikn eller fleire. + Verdien er for kort. Den må ha {{ limit }} tegn eller flere. This value should not be blank. - Verdien må ikkje vere blank. + Verdien må ikke være blank. This value should not be null. - Verdien må ikkje vere tom (null). + Verdien må ikke være tom (null). This value should be null. - Verdien må vere tom (null). + Verdien må være tom (null). This value is not valid. - Verdien er ikkje gyldig. + Verdien er ikke gyldig. This value is not a valid time. - Verdien er ikkje gyldig tidseining. + Verdien er ikke en gyldig tid. This value is not a valid URL. - Verdien er ikkje ein gyldig URL. + Verdien er ikke en gyldig URL. The two values should be equal. - Dei to verdiane må vere like. + Verdiene må være identiske. The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - Fila er for stor. Den maksimale storleik er {{ limit }} {{ suffix }}. + Filen er for stor. Den maksimale størrelsen er {{ limit }} {{ suffix }}. The file is too large. - Fila er for stor. + Filen er for stor. The file could not be uploaded. - Fila kunne ikkje bli lasta opp. + Filen kunne ikke lastes opp. This value should be a valid number. - Verdien må vere eit gyldig tal. + Verdien må være et gyldig tall. This file is not a valid image. - Fila er ikkje eit gyldig bilete. + Denne filen er ikke et gyldig bilde. This is not a valid IP address. - Dette er ikkje ei gyldig IP-adresse. + Dette er ikke en gyldig IP adresse. This value is not a valid language. - Verdien er ikkje eit gyldig språk. + Verdien er ikke et gyldig språk. This value is not a valid locale. - Verdien er ikkje ein gyldig lokalitet (språk/region). + Verdien er ikke en gyldig lokalitet. This value is not a valid country. - Verdien er ikkje eit gyldig land. + Verdien er ikke et gyldig navn på land. This value is already used. - Verdien er allereie i bruk. + Verdien er allerede brukt. The size of the image could not be detected. - Storleiken på biletet kunne ikkje oppdagast. + Bildestørrelsen kunne ikke oppdages. The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - Biletbreidda er for stor, ({{ width }} pikslar). Tillatt maksimumsbreidde er {{ max_width }} pikslar. + Bildebredden er for stor ({{ width }} piksler). Tillatt maksimumsbredde er {{ max_width }} piksler. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - Biletbreidda er for liten, ({{ width }} pikslar). Forventa minimumsbreidde er {{ min_width }} pikslar. + Bildebredden er for liten ({{ width }} piksler). Forventet minimumsbredde er {{ min_width }} piksler. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - Bilethøgda er for stor, ({{ height }} pikslar). Tillatt maksimumshøgde er {{ max_height }} pikslar. + Bildehøyden er for stor ({{ height }} piksler). Tillatt maksimumshøyde er {{ max_height }} piksler. The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Billethøgda er for låg, ({{ height }} pikslar). Forventa minimumshøgde er {{ min_height }} pikslar. + Bildehøyden er for liten ({{ height }} piksler). Forventet minimumshøyde er {{ min_height }} piksler. This value should be the user's current password. - Verdien må vere brukaren sitt noverande passord. + Verdien må være brukerens sitt nåværende passord. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Verdien må vere nøyaktig {{ limit }} teikn. + Verdien må være nøyaktig {{ limit }} tegn. The file was only partially uploaded. - Fila vart kun delvis opplasta. + Filen var kun delvis opplastet. No file was uploaded. - Inga fil vart lasta opp. + Ingen fil var lastet opp. No temporary folder was configured in php.ini. - Førebels mappe (tmp) er ikkje konfigurert i php.ini. + Den midlertidige mappen (tmp) er ikke konfigurert i php.ini. Cannot write temporary file to disk. - Kan ikkje skrive førebels fil til disk. + Kan ikke skrive midlertidig fil til disk. A PHP extension caused the upload to fail. - Ei PHP-udviding forårsaka feil under opplasting. + En PHP-utvidelse forårsaket en feil under opplasting. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Denne samlinga må innehalde {{ limit }} element eller meir.|Denne samlinga må innehalde {{ limit }} element eller meir. + Denne samlingen må inneholde {{ limit }} element eller flere.|Denne samlingen må inneholde {{ limit }} elementer eller flere. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Denne samlinga må innehalde {{ limit }} element eller færre.|Denne samlinga må innehalde {{ limit }} element eller færre. + Denne samlingen må inneholde {{ limit }} element eller færre.|Denne samlingen må inneholde {{ limit }} elementer eller færre. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Denne samlinga må innehalde nøyaktig {{ limit }} element.|Denne samlinga må innehalde nøyaktig {{ limit }} element. + Denne samlingen må inneholde nøyaktig {{ limit }} element.|Denne samlingen må inneholde nøyaktig {{ limit }} elementer. Invalid card number. @@ -220,7 +220,99 @@ Unsupported card type or invalid card number. - Korttypen er ikkje støtta eller ugyldig kortnummer. + Korttypen er ikke støttet eller ugyldig kortnummer. + + + This is not a valid International Bank Account Number (IBAN). + Dette er ikke en gyldig IBAN. + + + This value is not a valid ISBN-10. + Verdien er ikke en gyldig ISBN-10. + + + This value is not a valid ISBN-13. + Verdien er ikke en gyldig ISBN-13. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Verdien er hverken en gyldig ISBN-10 eller ISBN-13. + + + This value is not a valid ISSN. + Verdien er ikke en gyldig ISSN. + + + This value is not a valid currency. + Verdien er ikke gyldig valuta. + + + This value should be equal to {{ compared_value }}. + Verdien må være lik {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Verdien må være større enn {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Verdien må være større enn eller lik {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Verdien må være identisk med {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Verdien må være mindre enn {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Verdien må være mindre enn eller lik {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Verdien må ikke være lik {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Verdien må ikke være identisk med {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Bildeforholdet er for stort ({{ ratio }}). Tillatt maksimumsbildeforhold er {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Bildeforholdet er for lite ({{ ratio }}). Forventet maksimumsbildeforhold er {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Bildet er en kvadrat ({{ width }}x{{ height }}px). Kvadratiske bilder er ikke tillatt. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Bildet er i liggende retning ({{ width }}x{{ height }}px). Bilder i liggende retning er ikke tillatt. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Bildet er i stående retning ({{ width }}x{{ height }}px). Bilder i stående retning er ikke tillatt. + + + An empty file is not allowed. + Tomme filer er ikke tilatt. + + + The host could not be resolved. + Vertsnavn kunne ikke løses. + + + This value does not match the expected {{ charset }} charset. + Verdien samsvarer ikke med forventet tegnsett {{ charset }}. + + + This is not a valid Business Identifier Code (BIC). + Dette er ikke en gyldig BIC. diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php index 03f998f8109ff..c76920fbb20d4 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Validator\Tests\Constraints; -use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Validator\Constraints\Expression; use Symfony\Component\Validator\Constraints\ExpressionValidator; use Symfony\Component\Validator\Tests\Fixtures\Entity; @@ -20,7 +19,7 @@ class ExpressionValidatorTest extends AbstractConstraintValidatorTest { protected function createValidator() { - return new ExpressionValidator(PropertyAccess::createPropertyAccessor()); + return new ExpressionValidator(); } public function testExpressionIsEvaluatedWithNullValue() diff --git a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php new file mode 100644 index 0000000000000..8a766611cd4f9 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Resources; + +class TranslationFilesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValid($filePath) + { + \PHPUnit_Util_XML::loadfile($filePath, false, false, true); + } + + public function provideTranslationFiles() + { + return array_map( + function ($filePath) { return (array) $filePath; }, + glob(dirname(dirname(__DIR__)).'/Resources/translations/*.xlf') + ); + } +} diff --git a/src/Symfony/Component/Validator/ValidatorBuilder.php b/src/Symfony/Component/Validator/ValidatorBuilder.php index fc3abd342355f..d82aca5612cdd 100644 --- a/src/Symfony/Component/Validator/ValidatorBuilder.php +++ b/src/Symfony/Component/Validator/ValidatorBuilder.php @@ -15,7 +15,6 @@ use Doctrine\Common\Annotations\CachedReader; use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Cache\ArrayCache; -use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Translation\IdentityTranslator; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\Context\ExecutionContextFactory; @@ -89,11 +88,6 @@ class ValidatorBuilder implements ValidatorBuilderInterface */ private $translationDomain; - /** - * @var PropertyAccessorInterface|null - */ - private $propertyAccessor; - /** * {@inheritdoc} */ @@ -263,10 +257,6 @@ public function setMetadataCache(CacheInterface $cache) */ public function setConstraintValidatorFactory(ConstraintValidatorFactoryInterface $validatorFactory) { - if (null !== $this->propertyAccessor) { - throw new ValidatorException('You cannot set a validator factory after setting a custom property accessor. Remove the call to setPropertyAccessor() if you want to call setConstraintValidatorFactory().'); - } - $this->validatorFactory = $validatorFactory; return $this; @@ -333,7 +323,7 @@ public function getValidator() $metadataFactory = new LazyLoadingMetadataFactory($loader, $this->metadataCache); } - $validatorFactory = $this->validatorFactory ?: new ConstraintValidatorFactory($this->propertyAccessor); + $validatorFactory = $this->validatorFactory ?: new ConstraintValidatorFactory(); $translator = $this->translator; if (null === $translator) { diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 7365981fd6750..48d431cc79a54 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -24,7 +24,6 @@ "symfony/intl": "~2.8|~3.0", "symfony/yaml": "~2.8|~3.0", "symfony/config": "~2.8|~3.0", - "symfony/property-access": "~2.8|~3.0", "symfony/expression-language": "~2.8|~3.0", "doctrine/annotations": "~1.0", "doctrine/cache": "~1.0", diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index cd6d64d1c0368..e6de7371b2760 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -62,15 +62,12 @@ public function testGet() 7 => b"é\\x00" "[]" => [] "res" => stream resource {@{$res} - wrapper_type: "plainfile" +%A wrapper_type: "plainfile" stream_type: "STDIO" mode: "r" unread_bytes: 0 seekable: true - timed_out: false - blocked: true - eof: false - options: [] +%A options: [] } "obj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d +foo: "foo" @@ -211,16 +208,13 @@ public function testThrowingCaster() $this->assertStringMatchesFormat( <<7 => b"&%s;\\x00" "[]" => [] "res" => stream resource @{$res} - wrapper_type: "plainfile" +%A wrapper_type: "plainfile" stream_type: "STDIO" mode: "r" unread_bytes: 0 seekable: true - timed_out: false - blocked: true - eof: false - options: [] +%A options: [] } "obj" => DumbFoo {#%d +foo: "foo" diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 0e0b4ee01e20f..10fbd898f0257 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -519,7 +519,12 @@ private static function evaluateScalar($scalar, $references = array()) case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): return (float) str_replace(',', '', $scalar); case preg_match(self::getTimestampRegex(), $scalar): - return strtotime($scalar); + $timeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + $time = strtotime($scalar); + date_default_timezone_set($timeZone); + + return $time; } default: return (string) $scalar; diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 9e4da1766431e..28b58c36c1e33 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -301,8 +301,14 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = mb_internal_encoding($mbEncoding); } - if ($objectForMap && !is_object($data)) { - $data = (object) $data; + if ($objectForMap && !is_object($data) && 'mapping' === $context) { + $object = new \stdClass(); + + foreach ($data as $key => $value) { + $object->$key = $value; + } + + $data = $object; } return empty($data) ? null : $data; diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml index d69e97a1a5c65..ec1c4c3a1ab40 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml @@ -754,7 +754,7 @@ yaml: | Billsmer @ 338-4338. php: | array( - 'invoice' => 34843, 'date' => mktime(0, 0, 0, 1, 23, 2001), + 'invoice' => 34843, 'date' => gmmktime(0, 0, 0, 1, 23, 2001), 'bill-to' => array( 'given' => 'Chris', 'family' => 'Dumars', 'address' => array( 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 ) ) , 'ship-to' => @@ -879,7 +879,7 @@ yaml: | php: | array( 'invoice' => 34843, - 'date' => mktime(0, 0, 0, 1, 23, 2001), + 'date' => gmmktime(0, 0, 0, 1, 23, 2001), 'total' => 4443.52 ) --- diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index ab541dade2bdf..3da5dd532cd0f 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -251,7 +251,7 @@ public function getTestsForParse() array("'on'", 'on'), array("'off'", 'off'), - array('2007-10-30', mktime(0, 0, 0, 10, 30, 2007)), + array('2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)), array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)), @@ -318,7 +318,7 @@ public function getTestsForParseWithMapObjects() array("'#cfcfcf'", '#cfcfcf'), array('::form_base.html.twig', '::form_base.html.twig'), - array('2007-10-30', mktime(0, 0, 0, 10, 30, 2007)), + array('2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)), array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)), diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 81f97916a8ca6..fc15c32cd8a5d 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -442,35 +442,75 @@ public function testObjectSupportDisabledButNoExceptions($input) $this->assertEquals(array('foo' => null, 'bar' => 1), $this->parser->parse($input), '->parse() does not parse objects'); } - public function testObjectForMapEnabledWithMapping() + /** + * @dataProvider getObjectForMapTests + */ + public function testObjectForMap($yaml, $expected) + { + $this->assertEquals($expected, $this->parser->parse($yaml, false, false, true)); + } + + public function getObjectForMapTests() { + $tests = array(); + $yaml = <<parser->parse($yaml, false, false, true); - - $this->assertInstanceOf('stdClass', $result); - $this->assertInstanceOf('stdClass', $result->foo); - $this->assertEquals(array('cat'), $result->foo->fiz); - } - - public function testObjectForMapEnabledWithInlineMapping() - { - $result = $this->parser->parse('{ "foo": "bar", "fiz": "cat" }', false, false, true); + $expected = new \stdClass(); + $expected->foo = new \stdClass(); + $expected->foo->fiz = array('cat'); + $tests['mapping'] = array($yaml, $expected); - $this->assertInstanceOf('stdClass', $result); - $this->assertEquals('bar', $result->foo); - $this->assertEquals('cat', $result->fiz); - } + $yaml = '{ "foo": "bar", "fiz": "cat" }'; + $expected = new \stdClass(); + $expected->foo = 'bar'; + $expected->fiz = 'cat'; + $tests['inline-mapping'] = array($yaml, $expected); - public function testObjectForMapIsAppliedAfterParsing() - { + $yaml = "foo: bar\nbaz: foobar"; $expected = new \stdClass(); $expected->foo = 'bar'; $expected->baz = 'foobar'; + $tests['object-for-map-is-applied-after-parsing'] = array($yaml, $expected); - $this->assertEquals($expected, $this->parser->parse("foo: bar\nbaz: foobar", false, false, true)); + $yaml = <<array = array(); + $expected->array[0] = new \stdClass(); + $expected->array[0]->key = 'one'; + $expected->array[1] = new \stdClass(); + $expected->array[1]->key = 'two'; + $tests['nest-map-and-sequence'] = array($yaml, $expected); + + $yaml = <<map = new \stdClass(); + $expected->map->{1} = 'one'; + $expected->map->{2} = 'two'; + $tests['numeric-keys'] = array($yaml, $expected); + + $yaml = <<map = new \stdClass(); + $expected->map->{0} = 'one'; + $expected->map->{1} = 'two'; + $tests['zero-indexed-numeric-keys'] = array($yaml, $expected); + + return $tests; } /**