Merge branch '2.8'

* 2.8:
  [Bridge\PhpUnit] Add extra clock-mocked namespaces in phpunit.xml.dist
  [DependencyInjection] Autowing: exclude abstract definitons
  [DependencyInjection] Autowiring: support parent/decorators
  [FrameworkBundle] Autowiring support for debug:container
  Fixing bad type-hint auto-wiring bug
  [Yaml] deprecate unquoted indicator characters
  added a micro kernel
  Re-adding the ability to add a resource to the RouteCollectionBuilder
  [DependencyInjection] Add autowiring support to dumpers
  ldap_set_option should be called with a valid link identifier
  [FrameworkBundle][Form] Better exception message for private form tagged services

Conflicts:
	src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_1.xml
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.json
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.md
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.txt
	src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/legacy_synchronized_service_definition_2.xml
	src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
	src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
This commit is contained in:
Nicolas Grekas 2015-11-09 11:46:27 +01:00
commit b1ad6232b7
53 changed files with 668 additions and 65 deletions

View File

@ -20,11 +20,26 @@ use Doctrine\Common\Annotations\AnnotationRegistry;
*/
class SymfonyTestsListener extends \PHPUnit_Framework_BaseTestListener
{
private static $globallyEnabled = false;
private $state = -1;
private $skippedFile = false;
private $wasSkipped = array();
private $isSkipped = array();
public function __construct(array $extraClockMockedNamespaces = array())
{
if ($extraClockMockedNamespaces) {
foreach ($extraClockMockedNamespaces as $ns) {
ClockMock::register($ns.'\DummyClass');
}
}
if (self::$globallyEnabled) {
$this->state = -2;
} else {
self::$globallyEnabled = true;
}
}
public function __destruct()
{
if (0 < $this->state) {
@ -56,9 +71,16 @@ class SymfonyTestsListener extends \PHPUnit_Framework_BaseTestListener
}
}
}
foreach ($suite->tests() as $test) {
if ($test instanceof \PHPUnit_Framework_TestSuite && in_array('time-sensitive', \PHPUnit_Util_Test::getGroups($test->getName()), true)) {
ClockMock::register($test->getName());
$testSuites = array($suite);
for ($i = 0; isset($testSuites[$i]); ++$i) {
foreach ($testSuites[$i]->tests() as $test) {
if ($test instanceof \PHPUnit_Framework_TestSuite) {
if (class_exists($test->getName(), false) && in_array('time-sensitive', \PHPUnit_Util_Test::getGroups($test->getName()), true)) {
ClockMock::register($test->getName());
} else {
$testSuites[] = $test;
}
}
}
}
} elseif (2 === $this->state) {
@ -91,7 +113,7 @@ class SymfonyTestsListener extends \PHPUnit_Framework_BaseTestListener
public function startTest(\PHPUnit_Framework_Test $test)
{
if ($test instanceof \PHPUnit_Framework_TestCase) {
if (-2 < $this->state && $test instanceof \PHPUnit_Framework_TestCase) {
$groups = \PHPUnit_Util_Test::getGroups(get_class($test), $test->getName());
if (in_array('time-sensitive', $groups, true)) {
@ -103,7 +125,7 @@ class SymfonyTestsListener extends \PHPUnit_Framework_BaseTestListener
public function endTest(\PHPUnit_Framework_Test $test, $time)
{
if ($test instanceof \PHPUnit_Framework_TestCase) {
if (-2 < $this->state && $test instanceof \PHPUnit_Framework_TestCase) {
$groups = \PHPUnit_Util_Test::getGroups(get_class($test), $test->getName());
if (in_array('time-sensitive', $groups, true)) {

View File

@ -215,6 +215,16 @@ class JsonDescriptor extends Descriptor
}
$data['abstract'] = $definition->isAbstract();
if (method_exists($definition, 'isAutowired')) {
$data['autowire'] = $definition->isAutowired();
$data['autowiring_types'] = array();
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$data['autowiring_types'][] = $autowiringType;
}
}
$data['file'] = $definition->getFile();
if ($factory = $definition->getFactory()) {

View File

@ -187,6 +187,14 @@ class MarkdownDescriptor extends Descriptor
$output .= "\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no');
if (method_exists($definition, 'isAutowired')) {
$output .= "\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no');
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$output .= "\n".'- Autowiring Type: `'.$autowiringType.'`';
}
}
if ($definition->getFile()) {
$output .= "\n".'- File: `'.$definition->getFile().'`';
}

View File

@ -283,6 +283,19 @@ class TextDescriptor extends Descriptor
}
$tableRows[] = array('Abstract', $definition->isAbstract() ? 'yes' : 'no');
if (method_exists($definition, 'isAutowired')) {
$tableRows[] = array('Autowired', $definition->isAutowired() ? 'yes' : 'no');
$autowiringTypes = $definition->getAutowiringTypes();
if (count($autowiringTypes)) {
$autowiringTypesInformation = implode(', ', $autowiringTypes);
} else {
$autowiringTypesInformation = '-';
}
$tableRows[] = array('Autowiring Types', $autowiringTypesInformation);
}
if ($definition->getFile()) {
$tableRows[] = array('Required File', $definition->getFile() ? $definition->getFile() : '-');
}

View File

@ -353,6 +353,11 @@ class XmlDescriptor extends Descriptor
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
}
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
if (method_exists($definition, 'isAutowired')) {
$serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false');
}
$serviceXML->setAttribute('file', $definition->getFile());
if (!$omitTags) {

View File

@ -34,8 +34,12 @@ class FormPass implements CompilerPassInterface
$types = array();
foreach ($container->findTaggedServiceIds('form.type') as $serviceId => $tag) {
// Support type access by FQCN
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as form types are lazy-loaded.', $serviceId));
}
// Support type access by FQCN
$types[$serviceDefinition->getClass()] = $serviceId;
}
@ -44,6 +48,11 @@ class FormPass implements CompilerPassInterface
$typeExtensions = array();
foreach ($container->findTaggedServiceIds('form.type_extension') as $serviceId => $tag) {
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as form type extensions are lazy-loaded.', $serviceId));
}
if (isset($tag[0]['extended_type'])) {
$extendedType = $tag[0]['extended_type'];
} else {
@ -57,6 +66,12 @@ class FormPass implements CompilerPassInterface
// Find all services annotated with "form.type_guesser"
$guessers = array_keys($container->findTaggedServiceIds('form.type_guesser'));
foreach ($guessers as $serviceId) {
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as form type guessers are lazy-loaded.', $serviceId));
}
}
$definition->replaceArgument(3, $guessers);
}

View File

@ -0,0 +1,87 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Routing\RouteCollectionBuilder;
/**
* A Kernel that provides configuration hooks.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
trait MicroKernelTrait
{
/**
* Add or import routes into your application.
*
* $routes->import('config/routing.yml');
* $routes->add('/admin', 'AppBundle:Admin:dashboard', 'admin_dashboard');
*
* @param RouteCollectionBuilder $routes
*/
abstract protected function configureRoutes(RouteCollectionBuilder $routes);
/**
* Configures the container.
*
* You can register extensions:
*
* $c->loadFromExtension('framework', array(
* 'secret' => '%secret%'
* ));
*
* Or services:
*
* $c->register('halloween', 'FooBundle\HalloweenProvider');
*
* Or parameters:
*
* $c->setParameter('halloween', 'lot of fun');
*
* @param ContainerBuilder $c
* @param LoaderInterface $loader
*/
abstract protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader);
/**
* {@inheritdoc}
*/
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(function (ContainerBuilder $container) use ($loader) {
$container->loadFromExtension('framework', array(
'router' => array(
'resource' => 'kernel:loadRoutes',
'type' => 'service',
),
));
$this->configureContainer($container, $loader);
$container->addObjectResource($this);
});
}
/**
* @internal
*/
public function loadRoutes(LoaderInterface $loader)
{
$routes = new RouteCollectionBuilder($loader);
$this->configureRoutes($routes);
return $routes->build();
}
}

View File

@ -148,6 +148,39 @@ class FormPassTest extends \PHPUnit_Framework_TestCase
'my.guesser2',
), $extDefinition->getArgument(3));
}
/**
* @dataProvider privateTaggedServicesProvider
*/
public function testPrivateTaggedServices($id, $tagName, $expectedExceptionMessage)
{
$container = new ContainerBuilder();
$container->addCompilerPass(new FormPass());
$extDefinition = new Definition('Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension');
$extDefinition->setArguments(array(
new Reference('service_container'),
array(),
array(),
array(),
));
$container->setDefinition('form.extension', $extDefinition);
$container->register($id, 'stdClass')->setPublic(false)->addTag($tagName);
$this->setExpectedException('\InvalidArgumentException', $expectedExceptionMessage);
$container->compile();
}
public function privateTaggedServicesProvider()
{
return array(
array('my.type', 'form.type', 'The service "my.type" must be public as form types are lazy-loaded'),
array('my.type_extension', 'form.type_extension', 'The service "my.type_extension" must be public as form type extensions are lazy-loaded'),
array('my.guesser', 'form.type_guesser', 'The service "my.guesser" must be public as form type guessers are lazy-loaded'),
);
}
}
class FormPassTest_Type1 extends AbstractType

View File

@ -12,7 +12,9 @@
"factory_method": "get",
"tags": [
]
],
"autowire": false,
"autowiring_types": []
}
},
"aliases": {

View File

@ -13,6 +13,7 @@ definition_1
- Lazy: yes
- Shared: yes
- Abstract: yes
- Autowired: no
- Factory Class: `Full\Qualified\FactoryClass`
- Factory Method: `get`
@ -36,4 +37,4 @@ alias_2
Services
--------
- `service_container`: `Symfony\Component\DependencyInjection\ContainerBuilder`
- `service_container`: `Symfony\Component\DependencyInjection\ContainerBuilder`

View File

@ -2,7 +2,7 @@
<container>
<alias id="alias_1" service="service_1" public="true"/>
<alias id="alias_2" service="service_2" public="false"/>
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" file="">
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/>
</definition>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerBuilder"/>

View File

@ -12,7 +12,9 @@
"factory_method": "get",
"tags": [
]
],
"autowire": false,
"autowiring_types": []
},
"definition_2": {
"class": "Full\\Qualified\\Class2",
@ -44,7 +46,9 @@
]
}
]
],
"autowire": false,
"autowiring_types": []
}
},
"aliases": {

View File

@ -13,6 +13,7 @@ definition_1
- Lazy: yes
- Shared: yes
- Abstract: yes
- Autowired: no
- Factory Class: `Full\Qualified\FactoryClass`
- Factory Method: `get`
@ -25,6 +26,7 @@ definition_2
- Lazy: no
- Shared: yes
- Abstract: no
- Autowired: no
- File: `/path/to/file`
- Factory Service: `factory.service`
- Factory Method: `get`
@ -55,4 +57,4 @@ alias_2
Services
--------
- `service_container`: `Symfony\Component\DependencyInjection\ContainerBuilder`
- `service_container`: `Symfony\Component\DependencyInjection\ContainerBuilder`

View File

@ -2,10 +2,10 @@
<container>
<alias id="alias_1" service="service_1" public="true"/>
<alias id="alias_2" service="service_2" public="false"/>
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" file="">
<definition id="definition_1" class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/>
</definition>
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
<tags>
<tag name="tag1">

View File

@ -30,7 +30,9 @@
]
}
]
],
"autowire": false,
"autowiring_types": []
}
},
"aliases": [

View File

@ -13,6 +13,7 @@ definition_2
- Lazy: no
- Shared: yes
- Abstract: no
- Autowired: no
- File: `/path/to/file`
- Factory Service: `factory.service`
- Factory Method: `get`

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<container>
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
<tags>
<tag name="tag1">

View File

@ -9,7 +9,9 @@
"abstract": false,
"file": "\/path\/to\/file",
"factory_service": "factory.service",
"factory_method": "get"
"factory_method": "get",
"autowire": false,
"autowiring_types": []
}
],
"tag2": [
@ -22,7 +24,9 @@
"abstract": false,
"file": "\/path\/to\/file",
"factory_service": "factory.service",
"factory_method": "get"
"factory_method": "get",
"autowire": false,
"autowiring_types": []
}
]
}

View File

@ -13,6 +13,7 @@ definition_2
- Lazy: no
- Shared: yes
- Abstract: no
- Autowired: no
- File: `/path/to/file`
- Factory Service: `factory.service`
- Factory Method: `get`
@ -30,6 +31,7 @@ definition_2
- Lazy: no
- Shared: yes
- Abstract: no
- Autowired: no
- File: `/path/to/file`
- Factory Service: `factory.service`
- Factory Method: `get`

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<container>
<tag name="tag1">
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
</definition>
</tag>
<tag name="tag2">
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<definition id="definition_2" class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
</definition>
</tag>

View File

@ -10,5 +10,7 @@
"factory_method": "get",
"tags": [
]
],
"autowire": false,
"autowiring_types": []
}

View File

@ -4,5 +4,6 @@
- Lazy: yes
- Shared: yes
- Abstract: yes
- Autowired: no
- Factory Class: `Full\Qualified\FactoryClass`
- Factory Method: `get`
- Factory Method: `get`

View File

@ -1,15 +1,17 @@
---------------- -----------------------------
Option Value
---------------- -----------------------------
Service ID -
Class Full\Qualified\Class1
Tags -
Public yes
Synthetic no
Lazy yes
Shared yes
Abstract yes
Factory Class Full\Qualified\FactoryClass
Factory Method get
---------------- -----------------------------
------------------ -----------------------------
Option Value
------------------ -----------------------------
Service ID -
Class Full\Qualified\Class1
Tags -
Public yes
Synthetic no
Lazy yes
Shared yes
Abstract yes
Autowired no
Autowiring Types -
Factory Class Full\Qualified\FactoryClass
Factory Method get
------------------ -----------------------------

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" file="">
<definition class="Full\Qualified\Class1" public="true" synthetic="false" lazy="true" shared="true" abstract="true" autowired="false" file="">
<factory class="Full\Qualified\FactoryClass" method="get"/>
</definition>

View File

@ -28,5 +28,7 @@
]
}
]
],
"autowire": false,
"autowiring_types": []
}

View File

@ -4,6 +4,7 @@
- Lazy: no
- Shared: yes
- Abstract: no
- Autowired: no
- File: `/path/to/file`
- Factory Service: `factory.service`
- Factory Method: `get`

View File

@ -1,16 +1,18 @@
----------------- -------------------------------------------------------
Option Value
----------------- -------------------------------------------------------
Service ID -
Class Full\Qualified\Class2
Tags tag1 (attr1: val1, attr2: val2)tag1 (attr3: val3)tag2
Public no
Synthetic yes
Lazy no
Shared yes
Abstract no
Required File /path/to/file
Factory Service factory.service
Factory Method get
----------------- -------------------------------------------------------
------------------ -------------------------------------------------------
Option Value
------------------ -------------------------------------------------------
Service ID -
Class Full\Qualified\Class2
Tags tag1 (attr1: val1, attr2: val2)tag1 (attr3: val3)tag2
Public no
Synthetic yes
Lazy no
Shared yes
Abstract no
Autowired no
Autowiring Types -
Required File /path/to/file
Factory Service factory.service
Factory Method get
------------------ -------------------------------------------------------

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<definition class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" file="/path/to/file">
<definition class="Full\Qualified\Class2" public="false" synthetic="true" lazy="false" shared="true" abstract="false" autowired="false" file="/path/to/file">
<factory service="factory.service" method="get"/>
<tags>
<tag name="tag1">

View File

@ -0,0 +1,71 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\Kernel;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
class ConcreteMicroKernel extends Kernel
{
use MicroKernelTrait;
private $cacheDir;
public function halloweenAction()
{
return new Response('halloween');
}
public function registerBundles()
{
return array(
new FrameworkBundle(),
);
}
public function getCacheDir()
{
return $this->cacheDir = sys_get_temp_dir().'/sf_micro_kernel';
}
public function getLogDir()
{
return $this->cacheDir;
}
public function __destruct()
{
$fs = new Filesystem();
$fs->remove($this->cacheDir);
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
$routes->add('/', 'kernel:halloweenAction');
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
$c->loadFromExtension('framework', array(
'secret' => '$ecret',
));
$c->setParameter('halloween', 'Have a great day!');
$c->register('halloween', 'stdClass');
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\Kernel;
use Symfony\Component\HttpFoundation\Request;
class MicroKernelTraitTest extends \PHPUnit_Framework_TestCase
{
public function test()
{
$kernel = new ConcreteMicroKernel('test', true);
$kernel->boot();
$request = Request::create('/');
$response = $kernel->handle($request);
$this->assertEquals('halloween', $response->getContent());
$this->assertEquals('Have a great day!', $kernel->getContainer()->getParameter('halloween'));
$this->assertInstanceOf('stdClass', $kernel->getContainer()->get('halloween'));
}
}

View File

@ -104,7 +104,7 @@ class AutowirePass implements CompilerPassInterface
// Typehint against a non-existing class
if (!$parameter->isDefaultValueAvailable()) {
continue;
throw new RuntimeException(sprintf('Cannot autowire argument %s for %s because the type-hinted class does not exist (%s).', $index + 1, $definition->getClass(), $reflectionException->getMessage()), 0, $reflectionException);
}
$value = $parameter->getDefaultValue();
@ -138,7 +138,8 @@ class AutowirePass implements CompilerPassInterface
*/
private function populateAvailableType($id, Definition $definition)
{
if (!$definition->getClass()) {
// Never use abstract services
if ($definition->isAbstract()) {
return;
}
@ -147,6 +148,11 @@ class AutowirePass implements CompilerPassInterface
$this->types[$type] = $id;
}
// Cannot use reflection if the class isn't set
if (!$definition->getClass()) {
return;
}
if ($reflectionClass = $this->getReflectionClass($id, $definition)) {
$this->extractInterfaces($id, $reflectionClass);
$this->extractAncestors($id, $reflectionClass);

View File

@ -118,6 +118,7 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
$def->setArguments($parentDef->getArguments());
$def->setMethodCalls($parentDef->getMethodCalls());
$def->setProperties($parentDef->getProperties());
$def->setAutowiringTypes($parentDef->getAutowiringTypes());
if ($parentDef->isDeprecated()) {
$def->setDeprecated(true, $parentDef->getDeprecationMessage('%service_id%'));
}
@ -184,6 +185,11 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
}
// merge autowiring types
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$def->addAutowiringType($autowiringType);
}
// these attributes are always taken from the child
$def->setAbstract($definition->isAbstract());
$def->setTags($definition->getTags());

View File

@ -596,6 +596,15 @@ EOF;
EOF;
}
if ($definition->isAutowired()) {
$doc = <<<EOF
*
* This service is autowired.
EOF;
}
if ($definition->isLazy()) {
$lazyInitialization = '$lazyLoad = true';
$lazyInitializationDoc = "\n * @param bool \$lazyLoad whether to try lazy-loading the service with a proxy\n *";

View File

@ -189,6 +189,17 @@ class XmlDumper extends Dumper
$service->appendChild($deprecated);
}
if ($definition->isAutowired()) {
$service->setAttribute('autowire', 'true');
}
foreach ($definition->getAutowiringTypes() as $autowiringTypeValue) {
$autowiringType = $this->document->createElement('autowiring-type');
$autowiringType->appendChild($this->document->createTextNode($autowiringTypeValue));
$service->appendChild($autowiringType);
}
if ($callable = $definition->getConfigurator()) {
$configurator = $this->document->createElement('configurator');

View File

@ -100,6 +100,18 @@ class YamlDumper extends Dumper
$code .= sprintf(" deprecated: %s\n", $definition->getDeprecationMessage('%service_id%'));
}
if ($definition->isAutowired()) {
$code .= " autowire: true\n";
}
$autowiringTypesCode = '';
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$autowiringTypesCode .= sprintf(" - %s\n", $this->dumper->dump($autowiringType));
}
if ($autowiringTypesCode) {
$code .= sprintf(" autowiring_types:\n%s", $autowiringTypesCode);
}
if ($definition->isLazy()) {
$code .= sprintf(" lazy: true\n");
}

View File

@ -189,7 +189,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo', $definition->getArgument(2));
}
public function testDontTriggeruAutowiring()
public function testDontTriggerAutowiring()
{
$container = new ContainerBuilder();
@ -201,6 +201,36 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
$this->assertCount(0, $container->getDefinition('bar')->getArguments());
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Cannot autowire argument 2 for Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument because the type-hinted class does not exist (Class Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass does not exist).
*/
public function testClassNotFoundThrowsException()
{
$container = new ContainerBuilder();
$aDefinition = $container->register('a', __NAMESPACE__.'\BadTypeHintedArgument');
$aDefinition->setAutowired(true);
$pass = new AutowirePass();
$pass->process($container);
}
public function testDontUseAbstractServices()
{
$container = new ContainerBuilder();
$container->register('abstract_foo', __NAMESPACE__.'\Foo')->setAbstract(true);
$container->register('foo', __NAMESPACE__.'\Foo');
$container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true);
$pass = new AutowirePass();
$pass->process($container);
$arguments = $container->getDefinition('bar')->getArguments();
$this->assertSame('foo', (string) $arguments[0]);
}
}
class Foo
@ -298,3 +328,10 @@ class OptionalParameter
{
}
}
class BadTypeHintedArgument
{
public function __construct(Dunglas $k, NotARealClass $r)
{
}
}

View File

@ -252,6 +252,26 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($container->getDefinition('decorated_deprecated_parent')->isDeprecated());
}
public function testProcessMergeAutowiringTypes()
{
$container = new ContainerBuilder();
$container
->register('parent')
->addAutowiringType('Foo')
;
$container
->setDefinition('child', new DefinitionDecorator('parent'))
->addAutowiringType('Bar')
;
$this->process($container);
$def = $container->getDefinition('child');
$this->assertEquals(array('Foo', 'Bar'), $def->getAutowiringTypes());
}
protected function process(ContainerBuilder $container)
{
$pass = new ResolveDefinitionTemplatesPass();

View File

@ -208,4 +208,12 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
$dumper = new PhpDumper($container);
$dumper->dump();
}
public function testDumpAutowireData()
{
$container = include self::$fixturesPath.'/containers/container24.php';
$dumper = new PhpDumper($container);
$this->assertEquals(file_get_contents(self::$fixturesPath.'/php/services24.php'), $dumper->dump());
}
}

View File

@ -160,4 +160,12 @@ class XmlDumperTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services21.xml'), $dumper->dump());
}
public function testDumpAutowireData()
{
$container = include self::$fixturesPath.'/containers/container24.php';
$dumper = new XmlDumper($container);
$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services24.xml'), $dumper->dump());
}
}

View File

@ -56,4 +56,11 @@ class YamlDumperTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
}
}
public function testDumpAutowireData()
{
$container = include self::$fixturesPath.'/containers/container24.php';
$dumper = new YamlDumper($container);
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services24.yml', $dumper->dump());
}
}

View File

@ -0,0 +1,15 @@
<?php
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
$container = new ContainerBuilder();
$container
->register('foo', 'Foo')
->setAutowired(true)
->addAutowiringType('A')
->addAutowiringType('B')
;
return $container;

View File

@ -0,0 +1,43 @@
<?php
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
/**
* ProjectServiceContainer.
*
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*/
class ProjectServiceContainer extends Container
{
private $parameters;
private $targetDirs = array();
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->methodMap = array(
'foo' => 'getFooService',
);
}
/**
* Gets the 'foo' service.
*
* This service is autowired.
*
* @return \Foo A Foo instance.
*/
protected function getFooService()
{
return $this->services['foo'] = new \Foo();
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="foo" class="Foo" autowire="true">
<autowiring-type>A</autowiring-type>
<autowiring-type>B</autowiring-type>
</service>
</services>
</container>

View File

@ -0,0 +1,8 @@
services:
foo:
class: Foo
autowire: true
autowiring_types:
- A
- B

View File

@ -25,4 +25,14 @@
</exclude>
</whitelist>
</filter>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
<arguments>
<array>
<element><string>Symfony\Component\HttpFoundation</string></element>
</array>
</arguments>
</listener>
</listeners>
</phpunit>

View File

@ -109,11 +109,11 @@ class LdapClient implements LdapClientInterface
$host = 'ldaps://'.$host;
}
$this->connection = ldap_connect($host, $this->port);
ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->version);
ldap_set_option($this->connection, LDAP_OPT_REFERRALS, $this->optReferrals);
$this->connection = ldap_connect($host, $this->port);
if ($this->useStartTls) {
ldap_start_tls($this->connection);
}

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Routing;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* Helps add and import routes into a RouteCollection.
@ -35,6 +36,7 @@ class RouteCollectionBuilder
private $options = array();
private $schemes;
private $methods;
private $resources = array();
/**
* @param LoaderInterface $loader
@ -237,6 +239,20 @@ class RouteCollectionBuilder
return $this;
}
/**
* Adds a resource for this collection.
*
* @param ResourceInterface $resource
*
* @return $this
*/
private function addResource(ResourceInterface $resource)
{
$this->resources[] = $resource;
return $this;
}
/**
* Creates the final RouteCollection and returns it.
*
@ -291,6 +307,10 @@ class RouteCollectionBuilder
$routeCollection->addCollection($subCollection);
}
foreach ($this->resources as $resource) {
$routeCollection->addResource($resource);
}
}
return $routeCollection;

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Routing\Tests;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouteCollectionBuilder;
@ -29,6 +30,7 @@ class RouteCollectionBuilderTest extends \PHPUnit_Framework_TestCase
$originalRoute = new Route('/foo/path');
$expectedCollection = new RouteCollection();
$expectedCollection->add('one_test_route', $originalRoute);
$expectedCollection->addResource(new FileResource('file_resource.yml'));
$resolvedLoader
->expects($this->once())
@ -52,6 +54,8 @@ class RouteCollectionBuilderTest extends \PHPUnit_Framework_TestCase
$addedCollection = $importedRoutes->build();
$route = $addedCollection->get('one_test_route');
$this->assertSame($originalRoute, $route);
// should return file_resource.yml, which is in the original collection
$this->assertCount(1, $addedCollection->getResources());
}
/**

View File

@ -236,8 +236,8 @@ class Inline
throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
}
// a non-quoted string cannot start with @ or ` (reserved)
if ($output && ('@' === $output[0] || '`' === $output[0])) {
// a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
@trigger_error(sprintf('Not quoting a scalar starting with "%s" is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $output[0]), E_USER_DEPRECATED);
// to be thrown in 3.0

View File

@ -112,7 +112,7 @@ class Parser
$data[] = $parser->parse($block, $exceptionOnInvalidType, $objectSupport, $objectForMap);
} else {
$data[] = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap);
$data[] = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
}
}
if ($isRef) {
@ -228,7 +228,7 @@ class Parser
}
}
} else {
$value = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap);
$value = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node is used in current block.
if ($allowOverwrite || !isset($data[$key])) {
@ -443,12 +443,13 @@ class Parser
* @param bool $exceptionOnInvalidType True if an exception must be thrown on invalid types false otherwise
* @param bool $objectSupport True if object support is enabled, false otherwise
* @param bool $objectForMap true if maps should return a stdClass instead of array()
* @param string $context The parser context (either sequence or mapping)
*
* @return mixed A PHP value
*
* @throws ParseException When reference does not exist
*/
private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $objectForMap)
private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $context)
{
if (0 === strpos($value, '*')) {
if (false !== $pos = strpos($value, '#')) {
@ -470,6 +471,13 @@ class Parser
return $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
}
if ('mapping' === $context && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($value, ': ')) {
@trigger_error(sprintf('Using a colon in an unquoted mapping value in line %d is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED);
// to be thrown in 3.0
// throw new ParseException('A colon cannot be used in an unquoted mapping value.');
}
try {
return Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
} catch (ParseException $e) {

View File

@ -3,7 +3,7 @@ test: Some characters at the beginning of a string must be escaped
brief: >
Some characters at the beginning of a string must be escaped
yaml: |
foo: | bar
foo: '| bar'
php: |
array('foo' => '| bar')
---

View File

@ -203,6 +203,21 @@ class InlineTest extends \PHPUnit_Framework_TestCase
return array(array('@'), array('`'));
}
/**
* @group legacy
* @dataProvider getScalarIndicators
* throws \Symfony\Component\Yaml\Exception\ParseException in 3.0
*/
public function testParseUnquotedScalarStartingWithScalarIndicator($indicator)
{
Inline::parse(sprintf('{ foo: %sfoo }', $indicator));
}
public function getScalarIndicators()
{
return array(array('|'), array('>'));
}
public function getTestsForParse()
{
return array(

View File

@ -783,6 +783,31 @@ EOF;
$this->assertEquals($expected, $this->parser->parse($yaml));
}
/**
* @group legacy
* throw ParseException in Symfony 3.0
*/
public function testColonInMappingValueException()
{
$yaml = <<<EOF
foo: bar: baz
EOF;
$deprecations = array();
set_error_handler(function ($type, $msg) use (&$deprecations) {
if (E_USER_DEPRECATED === $type) {
$deprecations[] = $msg;
}
});
$this->parser->parse($yaml);
$this->assertCount(1, $deprecations);
$this->assertContains('Using a colon in an unquoted mapping value in line 1 is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $deprecations[0]);
restore_error_handler();
}
}
class B