Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c8e2f67

Browse files
committed
[DI][DX] Allow exclude to be an array of patterns (taking #24428 over)
1 parent 00ca74e commit c8e2f67

File tree

9 files changed

+119
-14
lines changed

9 files changed

+119
-14
lines changed

src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class PrototypeConfigurator extends AbstractServiceConfigurator
3939

4040
private $loader;
4141
private $resource;
42-
private $exclude;
42+
private $excludes;
4343
private $allowParent;
4444

4545
public function __construct(ServicesConfigurator $parent, PhpFileLoader $loader, Definition $defaults, string $namespace, string $resource, bool $allowParent)
@@ -63,19 +63,21 @@ public function __destruct()
6363
parent::__destruct();
6464

6565
if ($this->loader) {
66-
$this->loader->registerClasses($this->definition, $this->id, $this->resource, $this->exclude);
66+
$this->loader->registerClasses($this->definition, $this->id, $this->resource, $this->excludes);
6767
}
6868
$this->loader = null;
6969
}
7070

7171
/**
72-
* Excludes files from registration using a glob pattern.
72+
* Excludes files from registration using glob patterns.
73+
*
74+
* @param string[]|string $excludes
7375
*
7476
* @return $this
7577
*/
76-
final public function exclude(string $exclude)
78+
final public function exclude($excludes)
7779
{
78-
$this->exclude = $exclude;
80+
$this->excludes = (array) $excludes;
7981

8082
return $this;
8183
}

src/Symfony/Component/DependencyInjection/Loader/FileLoader.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ public function __construct(ContainerBuilder $container, FileLocatorInterface $l
4040
/**
4141
* Registers a set of classes as services using PSR-4 for discovery.
4242
*
43-
* @param Definition $prototype A definition to use as template
44-
* @param string $namespace The namespace prefix of classes in the scanned directory
45-
* @param string $resource The directory to look for classes, glob-patterns allowed
46-
* @param string $exclude A globed path of files to exclude
43+
* @param Definition $prototype A definition to use as template
44+
* @param string $namespace The namespace prefix of classes in the scanned directory
45+
* @param string $resource The directory to look for classes, glob-patterns allowed
46+
* @param string|string[]|null $exclude A globed path of files to exclude or an array of globed paths of files to exclude
4747
*/
4848
public function registerClasses(Definition $prototype, $namespace, $resource, $exclude = null)
4949
{
@@ -54,7 +54,7 @@ public function registerClasses(Definition $prototype, $namespace, $resource, $e
5454
throw new InvalidArgumentException(sprintf('Namespace is not a valid PSR-4 prefix: %s.', $namespace));
5555
}
5656

57-
$classes = $this->findClasses($namespace, $resource, $exclude);
57+
$classes = $this->findClasses($namespace, $resource, (array) $exclude);
5858
// prepare for deep cloning
5959
$serializedPrototype = serialize($prototype);
6060
$interfaces = array();
@@ -101,14 +101,14 @@ protected function setDefinition($id, Definition $definition)
101101
}
102102
}
103103

104-
private function findClasses($namespace, $pattern, $excludePattern)
104+
private function findClasses($namespace, $pattern, array $excludePatterns)
105105
{
106106
$parameterBag = $this->container->getParameterBag();
107107

108108
$excludePaths = array();
109109
$excludePrefix = null;
110-
if ($excludePattern) {
111-
$excludePattern = $parameterBag->unescapeValue($parameterBag->resolveValue($excludePattern));
110+
$excludePatterns = $parameterBag->unescapeValue($parameterBag->resolveValue($excludePatterns));
111+
foreach ($excludePatterns as $excludePattern) {
112112
foreach ($this->glob($excludePattern, true, $resource) as $path => $info) {
113113
if (null === $excludePrefix) {
114114
$excludePrefix = $resource->getPrefix();

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,14 @@ private function parseDefinitions(\DOMDocument $xml, $file, $defaults)
146146
foreach ($services as $service) {
147147
if (null !== $definition = $this->parseDefinition($service, $file, $defaults)) {
148148
if ('prototype' === $service->tagName) {
149-
$this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), (string) $service->getAttribute('exclude'));
149+
$excludes = array_column($this->getChildren($service, 'exclude'), 'nodeValue');
150+
if ($service->hasAttribute('exclude')) {
151+
if (count($excludes) > 0) {
152+
throw new InvalidArgumentException('You cannot use both the attribute "exclude" and <exclude> tags at the same time.');
153+
}
154+
$excludes = array($service->getAttribute('exclude'));
155+
}
156+
$this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), $excludes);
150157
} else {
151158
$this->setDefinition((string) $service->getAttribute('id'), $definition);
152159
}

src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
161161
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
162162
<xsd:element name="bind" type="bind" minOccurs="0" maxOccurs="unbounded" />
163+
<xsd:element name="exclude" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
163164
</xsd:choice>
164165
<xsd:attribute name="namespace" type="xsd:string" use="required" />
165166
<xsd:attribute name="resource" type="xsd:string" use="required" />
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
services:
3+
service_container:
4+
class: Symfony\Component\DependencyInjection\ContainerInterface
5+
public: true
6+
synthetic: true
7+
Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo:
8+
class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo
9+
public: true
10+
tags:
11+
- { name: foo }
12+
- { name: baz }
13+
deprecated: "%service_id%"
14+
arguments: [1]
15+
factory: f
16+
Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar:
17+
class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar
18+
public: true
19+
tags:
20+
- { name: foo }
21+
- { name: baz }
22+
deprecated: "%service_id%"
23+
lazy: true
24+
arguments: [1]
25+
factory: f
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
4+
5+
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
6+
7+
return function (ContainerConfigurator $c) {
8+
$di = $c->services()->defaults()
9+
->tag('baz');
10+
$di->load(Prototype::class.'\\', '../Prototype')
11+
->autoconfigure()
12+
->exclude(array('../Prototype/OtherDir', '../Prototype/BadClasses'))
13+
->factory('f')
14+
->deprecate('%service_id%')
15+
->args(array(0))
16+
->args(array(1))
17+
->autoconfigure(false)
18+
->tag('foo')
19+
->parent('foo');
20+
$di->set('foo')->lazy()->abstract();
21+
$di->get(Prototype\Foo::class)->lazy(false);
22+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<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">
3+
<services>
4+
<prototype namespace="Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\" resource="../Prototype/*">
5+
<exclude>../Prototype/OtherDir</exclude>
6+
<exclude>../Prototype/BadClasses</exclude>
7+
</prototype>
8+
</services>
9+
</container>

src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,25 @@ public function testRegisterClassesWithExclude()
136136
);
137137
}
138138

139+
public function testRegisterClassesWithExcludeAsArray()
140+
{
141+
$container = new ContainerBuilder();
142+
$container->setParameter('sub_dir', 'Sub');
143+
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));
144+
$loader->registerClasses(
145+
new Definition(),
146+
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
147+
'Prototype/*', array(
148+
'Prototype/%sub_dir%',
149+
'Prototype/OtherDir/AnotherSub/DeeperBaz.php',
150+
)
151+
);
152+
$this->assertTrue($container->has(Foo::class));
153+
$this->assertTrue($container->has(Baz::class));
154+
$this->assertFalse($container->has(Bar::class));
155+
$this->assertFalse($container->has(DeeperBaz::class));
156+
}
157+
139158
public function testNestedRegisterClasses()
140159
{
141160
$container = new ContainerBuilder();

src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,26 @@ public function testPrototype()
617617
$this->assertContains('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar', $resources);
618618
}
619619

620+
public function testPrototypeExcludeWithArray()
621+
{
622+
$container = new ContainerBuilder();
623+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
624+
$loader->load('services_prototype_array.xml');
625+
626+
$ids = array_keys($container->getDefinitions());
627+
sort($ids);
628+
$this->assertSame(array(Prototype\Foo::class, Prototype\Sub\Bar::class, 'service_container'), $ids);
629+
630+
$resources = $container->getResources();
631+
632+
$fixturesDir = dirname(__DIR__).DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR;
633+
$this->assertTrue(false !== array_search(new FileResource($fixturesDir.'xml'.DIRECTORY_SEPARATOR.'services_prototype_array.xml'), $resources));
634+
$this->assertTrue(false !== array_search(new GlobResource($fixturesDir.'Prototype', '/*', true), $resources));
635+
$resources = array_map('strval', $resources);
636+
$this->assertContains('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo', $resources);
637+
$this->assertContains('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar', $resources);
638+
}
639+
620640
/**
621641
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
622642
* @expectedExceptionMessage Invalid attribute "class" defined for alias "bar" in

0 commit comments

Comments
 (0)