8000 [DI] scope singly-implemented interfaces detection by file by daniel-iwaniec · Pull Request #33350 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DI] scope singly-implemented interfaces detection by file #33350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
[DI] add FileLoader::registerAliasesForSinglyImplementedInterfaces()
  • Loading branch information
nicolas-grekas committed Sep 7, 2019
commit c1f39709ffd35843d1090fab5ba17cef414e0d7b
69 changes: 33 additions & 36 deletions UPGRADE-4.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,37 @@ Debug
DependencyInjection
-------------------

* Made singly-implemented interfaces detection be scoped by file
* Deprecated support for short factories and short configurators in Yaml

Before:
```yaml
services:
my_service:
factory: factory_service:method
my_service:
factory: factory_service:method
```

After:
```yaml
services:
my_service:
factory: ['@factory_service', method]
my_service:
factory: ['@factory_service', method]
```

* Deprecated `tagged` in favor of `tagged_iterator`

Before:
```yaml
services:
App\Handler:
tags: ['app.handler']

App\HandlerCollection:
arguments: [!tagged app.handler]
arguments: [!tagged my_tag]
```

After:
```yaml
services:
App\Handler:
tags: ['app.handler']

App\HandlerCollection:
arguments: [!tagged_iterator app.handler]
App\HandlerCollection:
arguments: [!tagged_iterator my_tag]
```

* Passing an instance of `Symfony\Component\DependencyInjection\Parameter` as class name to `Symfony\Component\DependencyInjection\Definition` is deprecated.
Expand Down Expand Up @@ -143,6 +139,7 @@ HttpKernel

As many bundles must be compatible with a range of Symfony versions, the current
directory convention is not deprecated yet, but it will be in the future.

* Deprecated the second and third argument of `KernelInterface::locateResource`
* Deprecated the second and third argument of `FileLocator::__construct`
* Deprecated loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as
Expand Down Expand Up @@ -244,37 +241,37 @@ TwigBundle
Before (`templates/bundles/TwigBundle/Exception/error.jsonld.twig`):
```twig
{
"@id": "https://example.com",
"@type": "error",
"@context": {
"title": "{{ status_text }}",
"code": {{ status_code }},
"message": "{{ exception.message }}"
}
"@id": "https://example.com",
"@type": "error",
"@context": {
"title": "{{ status_text }}",
"code": {{ status_code }},
"message": "{{ exception.message }}"
}
}
```

After (`App\ErrorRenderer\JsonLdErrorRenderer`):
```php
class JsonLdErrorRenderer implements ErrorRendererInterface
{
public static function getFormat(): string
{
return 'jsonld';
}
public static function getFormat(): string
{
return 'jsonld';
}

public function render(FlattenException $exception): string
{
return json_encode([
'@id' => 'https://example.com',
'@type' => 'error',
'@context' => [
'title' => $exception->getTitle(),
'code' => $exception->getStatusCode(),
'message' => $exception->getMessage(),
],
]);
}
public function render(FlattenException $exception): string
{
return json_encode([
'@id' => 'https://example.com',
'@type' => 'error',
'@context' => [
'title' => $exception->getTitle(),
'code' => $exception->getStatusCode(),
'message' => $exception->getMessage(),
],
]);
}
}
```

Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CHANGELOG
* deprecated support for short factories and short configurators in Yaml
* deprecated `tagged` in favor of `tagged_iterator`
* deprecated passing an instance of `Symfony\Component\DependencyInjection\Parameter` as class name to `Symfony\Component\DependencyInjection\Definition`
* made singly-implemented interfaces detection be scoped by file

4.3.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ final public function parameters(): ParametersConfigurator

final public function services(): ServicesConfigurator
{
$this->loader->resetBeforeConfiguringServices();

return new ServicesConfigurator($this->container, $this->loader, $this->instanceof, $this->path, $this->anonymousCount);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ final public function alias(string $id, string $referencedId): AliasConfigurator
$ref = static::processValue($referencedId, true);
$alias = new Alias((string) $ref, $this->defaults->isPublic());
$this->container->setAlias($id, $alias);
$this->loader->removeSinglyImplementedAlias((string) $ref);

return new AliasConfigurator($this, $alias);
}
Expand Down Expand Up @@ -140,4 +139,9 @@ final public function __invoke(string $id, string $class = null): ServiceConfigu
{
return $this->set($id, $class);
}

public function __destruct()
{
$this->loader->registerAliasesForSinglyImplementedInterfaces();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ abstract class FileLoader extends BaseFileLoader
protected $instanceof = [];
protected $interfaces = [];
protected $singlyImplemented = [];
protected $singlyImplementedAliases = [];

public function __construct(ContainerBuilder $container, FileLocatorInterface $locator)
{
Expand Down Expand Up @@ -76,15 +75,17 @@ public function registerClasses(Definition $prototype, $namespace, $resource, $e
}
}
}
}

public function registerAliasesForSinglyImplementedInterfaces()
{
foreach ($this->interfaces as $interface) {
if (!empty($this->singlyImplemented[$interface]) && !$this->container->hasAlias($interface)) {
$this->container->setAlias($interface, $this->singlyImplemented[$interface])->setPublic(false);
$this->singlyImplementedAliases[$interface] = true;
} elseif ($this->singlyImplementedAliases[$interface] ?? false) {
$this->container->removeAlias($interface);
}
}

$this->interfaces = $this->singlyImplemented = [];
}

/**
Expand Down
23 changes: 8 additions & 15 deletions src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ public function load($resource, $type = null)
return include $path;
}, $this, ProtectedPhpFileLoader::class);

$callback = $load($path);
try {
$callback = $load($path);

if (\is_object($callback) && \is_callable($callback)) {
$callback(new ContainerConfigurator($this->container, $this, $this->instanceof, $path, $resource), $this->container, $this);
if (\is_object($callback) && \is_callable($callback)) {
$callback(new ContainerConfigurator($this->container, $this, $this->instanceof, $path, $resource), $this->container, $this);
}
} finally {
$this->instanceof = [];
$this->registerAliasesForSinglyImplementedInterfaces();
}
}

Expand All @@ -63,18 +68,6 @@ public function supports($resource, $type = null)

return 'php' === $type;
}

public function resetBeforeConfiguringServices(): void
{
$this->interfaces = [];
$this->singlyImplemented = [];
$this->singlyImplementedAliases = [];
}

public function removeSinglyImplementedAlias(string $alias): void
{
unset($this->singlyImplementedAliases[$alias]);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ public function load($resource, $type = null)
$this->parseDefinitions($xml, $path, $defaults);
} finally {
$this->instanceof = [];
$this->interfaces = [];
$this->singlyImplemented = [];
$this->singlyImplementedAliases = [];
$this->registerAliasesForSinglyImplementedInterfaces();
}
}

Expand Down Expand Up @@ -197,7 +195,6 @@ private function parseDefinition(\DOMElement $service, string $file, array $defa
$this->validateAlias($service, $file);

$this->container->setAlias((string) $service->getAttribute('id'), $alias = new Alias($alias));
unset($this->singlyImplementedAliases[(string) $service->getAttribute('id')]);
if ($publicAttr = $service->getAttribute('public')) {
$alias->setPublic(XmlUtils::phpize($publicAttr));
} elseif (isset($defaults['public'])) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@ public function load($resource, $type = null)
$this->parseDefinitions($content, $path);
} finally {
$this->instanceof = [];
$this->interfaces = [];
$this->singlyImplemented = [];
$this->singlyImplementedAliases = [];
$this->registerAliasesForSinglyImplementedInterfaces();
}
}

Expand Down Expand Up @@ -321,7 +319,6 @@ private function parseDefinition(string $id, $service, string $file, array $defa

if (\is_string($service) && 0 === strpos($service, '@')) {
$this->container->setAlias($id, $alias = new Alias(substr($service, 1)));
unset($this->singlyImplementedAliases[$id]);
if (isset($defaults['public'])) {
$alias->setPublic($defaults['public']);
}
Expand All @@ -345,7 +342,6 @@ private function parseDefinition(string $id, $service, string $file, array $defa

if (isset($service['alias'])) {
$this->container->setAlias($id, $alias = new Alias($service['alias']));
unset($this->singlyImplementedAliases[$id]);
if (\array_key_exists('public', $service)) {
$alias->setPublic($service['public']);
} elseif (isset($defaults['public'])) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,10 @@ public function supports($resource, $type = null): bool
{
return false;
}

public function registerClasses(Definition $prototype, $namespace, $resource, $exclude = null)
{
parent::registerClasses($prototype, $namespace, $resource, $exclude);
$this->registerAliasesForSinglyImplementedInterfaces();
}
}
0