diff --git a/src/Symfony/Bridge/Twig/Tests/TwigEngineTest.php b/src/Symfony/Bridge/Twig/Tests/TwigEngineTest.php new file mode 100644 index 0000000000..1e6a3c4933 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Tests/TwigEngineTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests; + +use Symfony\Bridge\Twig\TwigEngine; + +class TwigEngineTest extends TestCase +{ + public function testExistsWithTemplateInstances() + { + $engine = $this->getTwig(); + + $this->assertTrue($engine->exists($this->getMockForAbstractClass('Twig_Template', array(), '', false))); + } + + public function testExistsWithNonExistentTemplates() + { + $engine = $this->getTwig(); + + $this->assertFalse($engine->exists('foobar')); + } + + public function testExistsWithTemplateWithSyntaxErrors() + { + $engine = $this->getTwig(); + + $this->assertTrue($engine->exists('error')); + } + + public function testExists() + { + $engine = $this->getTwig(); + + $this->assertTrue($engine->exists('index')); + } + + protected function getTwig() + { + $twig = new \Twig_Environment(new \Twig_Loader_Array(array( + 'index' => 'foo', + 'error' => '{{ foo }', + ))); + $parser = $this->getMock('Symfony\Component\Templating\TemplateNameParserInterface'); + + return new TwigEngine($twig, $parser); + } +} diff --git a/src/Symfony/Bridge/Twig/TwigEngine.php b/src/Symfony/Bridge/Twig/TwigEngine.php index 955d4e0bae..41e15bacaa 100644 --- a/src/Symfony/Bridge/Twig/TwigEngine.php +++ b/src/Symfony/Bridge/Twig/TwigEngine.php @@ -75,9 +75,19 @@ class TwigEngine implements EngineInterface, StreamingEngineInterface */ public function exists($name) { + if ($name instanceof \Twig_Template) { + return true; + } + + $loader = $this->environment->getLoader(); + + if ($loader instanceof \Twig_ExistsLoaderInterface) { + return $loader->exists($name); + } + try { - $this->load($name); - } catch (\InvalidArgumentException $e) { + $loader->getSource($name); + } catch (\Twig_Error_Loader $e) { return false; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php index 59df4ae2a6..8d515d4bcb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php @@ -49,7 +49,7 @@ class RedirectController extends ContainerAware $attributes = array(); if (false === $ignoreAttributes || is_array($ignoreAttributes)) { $attributes = $request->attributes->get('_route_params'); - unset($attributes['route'], $attributes['permanent']); + unset($attributes['route'], $attributes['permanent'], $attributes['ignoreAttributes']); if ($ignoreAttributes) { $attributes = array_diff_key($attributes, array_flip($ignoreAttributes)); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php index 6bd636ae2a..9baec8dd95 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php @@ -53,6 +53,7 @@ class RedirectControllerTest extends TestCase 'route' => $route, 'permanent' => $permanent, 'additional-parameter' => 'value', + 'ignoreAttributes' => $ignoreAttributes ), ); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php index 4fb5b0d3bf..c5187f3b91 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php @@ -87,6 +87,7 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface $def->setConfigurator($parentDef->getConfigurator()); $def->setFile($parentDef->getFile()); $def->setPublic($parentDef->isPublic()); + $def->setLazy($parentDef->isLazy()); // overwrite with values specified in the decorator $changes = $definition->getChanges(); @@ -111,6 +112,9 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface if (isset($changes['public'])) { $def->setPublic($definition->isPublic()); } + if (isset($changes['lazy'])){ + $def->setLazy($definition->isLazy()); + } // merge arguments foreach ($definition->getArguments() as $k => $v) { diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index b285722edb..ab0abf316f 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -184,6 +184,9 @@ class Container implements IntrospectableContainerInterface /** * Sets a service. * + * Setting a service to null resets the service: has() returns false and get() + * behaves in the same way as if the service was never created. + * * @param string $id The service identifier * @param object $service The service instance * @param string $scope The scope of the service @@ -214,6 +217,14 @@ class Container implements IntrospectableContainerInterface if (method_exists($this, $method = 'synchronize'.strtr($id, array('_' => '', '.' => '_')).'Service')) { $this->$method(); } + + if (self::SCOPE_CONTAINER !== $scope && null === $service) { + unset($this->scopedServices[$scope][$id]); + } + + if (null === $service) { + unset($this->services[$id]); + } } /** diff --git a/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php b/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php index ad3c3c1dd0..1f72b8f16b 100644 --- a/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php +++ b/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php @@ -149,6 +149,18 @@ class DefinitionDecorator extends Definition return parent::setPublic($boolean); } + /** + * {@inheritDoc} + * + * @api + */ + public function setLazy($boolean) + { + $this->changes['lazy'] = true; + + return parent::setLazy($boolean); + } + /** * Gets an argument to pass to the service constructor/factory method. * diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php index f3c5b1544d..98e0c871e0 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php @@ -143,6 +143,36 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase $this->assertEquals('foo', $def->getClass()); } + public function testSetLazyOnServiceHasParent() + { + $container = new ContainerBuilder(); + + $container->register('parent','stdClass'); + + $container->setDefinition('child1',new DefinitionDecorator('parent')) + ->setLazy(true) + ; + + $this->process($container); + + $this->assertTrue($container->getDefinition('child1')->isLazy()); + } + + public function testSetLazyOnServiceIsParent() + { + $container = new ContainerBuilder(); + + $container->register('parent','stdClass') + ->setLazy(true) + ; + + $container->setDefinition('child1',new DefinitionDecorator('parent')); + + $this->process($container); + + $this->assertTrue($container->getDefinition('child1')->isLazy()); + } + protected function process(ContainerBuilder $container) { $pass = new ResolveDefinitionTemplatesPass(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php index f1dcde5a8f..6c49982bea 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php @@ -135,6 +135,16 @@ class ContainerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($foo, $sc->get('foo'), '->set() sets a service'); } + /** + * @covers Symfony\Component\DependencyInjection\Container::set + */ + public function testSetWithNullResetTheService() + { + $sc = new Container(); + $sc->set('foo', null); + $this->assertFalse($sc->has('foo')); + } + /** * @expectedException \InvalidArgumentException */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionDecoratorTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionDecoratorTest.php index bf1bab1e29..8be8b64230 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionDecoratorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionDecoratorTest.php @@ -61,6 +61,16 @@ class DefinitionDecoratorTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array('public' => true), $def->getChanges()); } + public function testSetLazy() + { + $def = new DefinitionDecorator('foo'); + + $this->assertFalse($def->isLazy()); + $this->assertSame($def, $def->setLazy(false)); + $this->assertFalse($def->isLazy()); + $this->assertEquals(array('lazy' => true), $def->getChanges()); + } + public function testSetArgument() { $def = new DefinitionDecorator('foo'); diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index e151484708..43f46ca228 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -546,7 +546,7 @@ class Form implements \IteratorAggregate, FormInterface foreach ($this->children as $name => $child) { $fieldValue = null; - if (isset($submittedData[$name])) { + if (array_key_exists($name, $submittedData)) { $fieldValue = $submittedData[$name]; unset($submittedData[$name]); } diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php index 71c7b2a734..34b11d3949 100644 --- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php +++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Tests; use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; use Symfony\Component\Form\FormError; +use Symfony\Component\Form\Forms; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; @@ -73,6 +74,19 @@ class CompoundFormTest extends AbstractFormTest $this->form->submit(array(), false); } + public function testSubmitDoesNotAddExtraFieldForNullValues() + { + $factory = Forms::createFormFactoryBuilder() + ->getFormFactory(); + + $child = $factory->create('file', null, array('auto_initialize' => false)); + + $this->form->add($child); + $this->form->submit(array('file' => null)); + + $this->assertCount(0, $this->form->getExtraData()); + } + public function testClearMissingFlagIsForwarded() { $child = $this->getMockForm('firstName'); diff --git a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php index b9a20aded5..74d7616bf9 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php @@ -78,6 +78,10 @@ class TimeDataCollector extends DataCollector */ public function getDuration() { + if (!isset($this->data['events']['__section__'])) { + return 0; + } + $lastEvent = $this->data['events']['__section__']; return $lastEvent->getOrigin() + $lastEvent->getDuration() - $this->getStartTime(); @@ -92,6 +96,10 @@ class TimeDataCollector extends DataCollector */ public function getInitTime() { + if (!isset($this->data['events']['__section__'])) { + return 0; + } + return $this->data['events']['__section__']->getOrigin() - $this->getStartTime(); } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf old mode 100755 new mode 100644