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

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CHANGELOG

* Make `#[AsTaggedItem]` repeatable
* Support `@>` as a shorthand for `!service_closure` in yaml files
* Don't skip classes with private constructor when autodiscovering

7.2
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ protected function getConstructor(Definition $definition, bool $required): ?\Ref
throw new RuntimeException(\sprintf('Invalid service "%s": class%s has no constructor.', $this->currentId, \sprintf($class !== $this->currentId ? ' "%s"' : '', $class)));
}
} elseif (!$r->isPublic()) {
throw new RuntimeException(\sprintf('Invalid service "%s": ', $this->currentId).\sprintf($class !== $this->currentId ? 'constructor of class "%s"' : 'its constructor', $class).' must be public.');
throw new RuntimeException(\sprintf('Invalid service "%s": ', $this->currentId).\sprintf($class !== $this->currentId ? 'constructor of class "%s"' : 'its constructor', $class).' must be public. Did you miss configuring a factory or a static constructor? Try using the "#[Autoconfigure(constructor: ...)]" attribute for the latter.');
}

return $r;
Expand Down
75 changes: 38 additions & 37 deletions src/Symfony/Component/DependencyInjection/Loader/FileLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public function registerClasses(Definition $prototype, string $namespace, string

$autoconfigureAttributes = new RegisterAutoconfigureAttributesPass();
$autoconfigureAttributes = $autoconfigureAttributes->accept($prototype) ? $autoconfigureAttributes : null;
$classes = $this->findClasses($namespace, $resource, (array) $exclude, $autoconfigureAttributes, $source);
$classes = $this->findClasses($namespace, $resource, (array) $exclude, $source);

$getPrototype = static fn () => clone $prototype;
$serialized = serialize($prototype);
Expand Down Expand Up @@ -188,41 +188,46 @@ public function registerClasses(Definition $prototype, string $namespace, string
}
}

if (interface_exists($class, false)) {
$this->interfaces[] = $class;
} else {
$this->setDefinition($class, $definition = $getPrototype());
if (null !== $errorMessage) {
$definition->addError($errorMessage);

continue;
$r = null === $errorMessage ? $this->container->getReflectionClass($class) : null;
if ($r?->isAbstract() || $r?->isInterface()) {
if ($r->isInterface()) {
$this->interfaces[] = $class;
}
$definition->setClass($class);
$autoconfigureAttributes?->processClass($this->container, $r);
continue;
}

$interfaces = [];
foreach (class_implements($class, false) as $interface) {
$this->singlyImplemented[$interface] = ($this->singlyImplemented[$interface] ?? $class) !== $class ? false : $class;
$interfaces[] = $interface;
}
$this->setDefinition($class, $definition = $getPrototype());
if (null !== $errorMessage) {
$definition->addError($errorMessage);

if (!$autoconfigureAttributes) {
continue;
continue;
}
$definition->setClass($class);

$interfaces = [];
foreach (class_implements($class, false) as $interface) {
$this->singlyImplemented[$interface] = ($this->singlyImplemented[$interface] ?? $class) !== $class ? false : $class;
$interfaces[] = $interface;
}

if (!$autoconfigureAttributes) {
continue;
}
$r = $this->container->getReflectionClass($class);
$defaultAlias = 1 === \count($interfaces) ? $interfaces[0] : null;
foreach ($r->getAttributes(AsAlias::class) as $attr) {
/** @var AsAlias $attribute */
$attribute = $attr->newInstance();
$alias = $attribute->id ?? $defaultAlias;
$public = $attribute->public;
if (null === $alias) {
throw new LogicException(\sprintf('Alias cannot be automatically determined for class "%s". If you have used the #[AsAlias] attribute with a class implementing multiple interfaces, add the interface you want to alias to the first parameter of #[AsAlias].', $class));
}
$r = $this->container->getReflectionClass($class);
$defaultAlias = 1 === \count($interfaces) ? $interfaces[0] : null;
foreach ($r->getAttributes(AsAlias::class) as $attr) {
/** @var AsAlias $attribute */
$attribute = $attr->newInstance();
$alias = $attribute->id ?? $defaultAlias;
$public = $attribute->public;
if (null === $alias) {
throw new LogicException(\sprintf('Alias cannot be automatically determined for class "%s". If you have used the #[AsAlias] attribute with a class implementing multiple interfaces, add the interface you want to alias to the first parameter of #[AsAlias].', $class));
}
if (isset($this->aliases[$alias])) {
throw new LogicException(\sprintf('The "%s" alias has already been defined with the #[AsAlias] attribute in "%s".', $alias, $this->aliases[$alias]));
}
$this->aliases[$alias] = new Alias($class, $public);
if (isset($this->aliases[$alias])) {
throw new LogicException(\sprintf('The "%s" alias has already been defined with the #[AsAlias] attribute in "%s".', $alias, $this->aliases[$alias]));
}
$this->aliases[$alias] = new Alias($class, $public);
}
}

Expand Down Expand Up @@ -304,7 +309,7 @@ protected function setDefinition(string $id, Definition $definition): void
}
}

private function findClasses(string $namespace, string $pattern, array $excludePatterns, ?RegisterAutoconfigureAttributesPass $autoconfigureAttributes, ?string $source): array
private function findClasses(string $namespace, string $pattern, array $excludePatterns, ?string $source): array
{
$parameterBag = $this->container->getParameterBag();

Expand Down Expand Up @@ -356,13 +361,9 @@ private function findClasses(string $namespace, string $pattern, array $excludeP
throw new InvalidArgumentException(\sprintf('Expected to find class "%s" in file "%s" while importing services from resource "%s", but it was not found! Check the namespace prefix used with the resource.', $class, $path, $pattern));
}

if ($r->isInstantiable() || $r->isInterface()) {
if (!$r->isTrait()) {
$classes[$class] = null;
}

if ($autoconfigureAttributes && !$r->isInstantiable()) {
$autoconfigureAttributes->processClass($this->container, $r);
}
}

// track only for new & removed files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public function testPrivateConstructorThrowsAutowireException()
$pass->process($container);
$this->fail('AutowirePass should have thrown an exception');
} catch (AutowiringFailedException $e) {
$this->assertSame('Invalid service "private_service": constructor of class "Symfony\Component\DependencyInjection\Tests\Compiler\PrivateConstructor" must be public.', (string) $e->getMessage());
$this->assertSame('Invalid service "private_service": constructor of class "Symfony\Component\DependencyInjection\Tests\Compiler\PrivateConstructor" must be public. Did you miss configuring a factory or a static constructor? Try using the "#[Autoconfigure(constructor: ...)]" attribute for the latter.', (string) $e->getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

class PrototypeStaticConstructor implements PrototypeStaticConstructorInterface
{
private function __construct()
{
}

public static function create(): static
{
return new self();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\AnotherSub;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\AnotherSub\DeeperBaz;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Baz;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\StaticConstructor\PrototypeStaticConstructor;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\BarInterface;
use Symfony\Component\DependencyInjection\Tests\Fixtures\PrototypeAsAlias\AliasBarInterface;
Expand Down Expand Up @@ -380,11 +381,11 @@ public static function provideResourcesWithAsAliasAttributes(): iterable
*/
public function testRegisterClassesWithDuplicatedAsAlias(string $resource, string $expectedExceptionMessage)
{
$this->expectException(LogicException::class);
$this->expectExceptionMessage($expectedExceptionMessage);

$container = new ContainerBuilder();
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));

$this->expectException(LogicException::class);
$this->expectExceptionMessage($expectedExceptionMessage);
$loader->registerClasses(
(new Definition())->setAutoconfigured(true),
'Symfony\Component\DependencyInjection\Tests\Fixtures\PrototypeAsAlias\\',
Expand All @@ -400,17 +401,28 @@ public static function provideResourcesWithDuplicatedAsAliasAttributes(): iterab

public function testRegisterClassesWithAsAliasAndImplementingMultipleInterfaces()
{
$this->expectException(LogicException::class);
$this->expectExceptionMessage('Alias cannot be automatically determined for class "Symfony\Component\DependencyInjection\Tests\Fixtures\PrototypeAsAlias\WithAsAliasMultipleInterface". If you have used the #[AsAlias] attribute with a class implementing multiple interfaces, add the interface you want to alias to the first parameter of #[AsAlias].');

$container = new ContainerBuilder();
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));

$this->expectException(LogicException::class);
$this->expectExceptionMessage('Alias cannot be automatically determined for class "Symfony\Component\DependencyInjection\Tests\Fixtures\PrototypeAsAlias\WithAsAliasMultipleInterface". If you have used the #[AsAlias] attribute with a class implementing multiple interfaces, add the interface you want to alias to the first parameter of #[AsAlias].');
$loader->registerClasses(
(new Definition())->setAutoconfigured(true),
'Symfony\Component\DependencyInjection\Tests\Fixtures\PrototypeAsAlias\\',
'PrototypeAsAlias/{WithAsAliasMultipleInterface,AliasBarInterface,AliasFooInterface}.php'
);
}

public function testRegisterClassesWithStaticConstructor()
{
$container = new ContainerBuilder();
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));

$prototype = (new Definition())->setAutoconfigured(true);
$loader->registerClasses($prototype, 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\StaticConstructor\\', 'Prototype/StaticConstructor');

$this->assertTrue($container->has(PrototypeStaticConstructor::class));
}
}

class TestFileLoader extends FileLoader
Expand Down
Loading