-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[ProxyManagerBridge][DI] allow proxifying interfaces with "lazy: Some\ProxifiedInterface" #27697
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
Conversation
Maybe throw exception for |
I'm going to do this good idea. I'm also wondering about allowing lazy: Some\Interface at the loader level. Would be equivalent to lazy: true + adding the tag. WDYT? |
Waiting for a resolution of Ocramius/ProxyManager#419 Status: needs work |
<tag name="proxy" interface="Some\ProxifiedInterface" />
287c039
to
534200c
Compare
Not needed actually, and won't be fixed in ProxyManager v2.1 which is in security-only fixes mode, but is the version compatible with PHP 7.1, thus Symfony 4. This PR deals with the issue on its own. Ready. Status: needs review |
3a2b6ce
to
311cbd5
Compare
@@ -22,6 +23,11 @@ class LazyLoadingValueHolderFactoryV2 extends BaseFactory | |||
{ | |||
private $generator; | |||
|
|||
public function getProxifiedClass(Definition $definition): ?string | |||
{ | |||
return $this->getGenerator()->getProxifiedClass($definition); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that looks weird to me. getProxifiedClass(Definition $definition)
is not part of ProxyGeneratorInterface
used as return type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest keeping this logic in RuntimeInstantiator instead (or in a separate class if needed elsewhere)
if (!$definition->isLazy()) { | ||
throw new \InvalidArgumentException(sprintf('Invalid definition for service of class "%s": setting the "proxy" tag on a service requires it to be "lazy".', $definition->getClass())); | ||
} | ||
if (!isset($definition->getTag('proxy')[0]['interface'])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if we have multiple tags ? Should we support implementing multiple interfaces ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not supported by ProxyManager AFAIK (ping @Ocramius)
Should we throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, implementing multiple interfaces is not supported. I tried doing so when playing around with DCI implementations, but never pursued, because the use-case is too narrow compared with the added complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the confirmation, this situation is now throwing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I managed to make it work actually, now supports proxying several interfaces :)
When they're not compatible, a PHP fatal error is thrown at compile time, there is no other way around.
* @return $this | ||
*/ | ||
final public function lazy(bool $lazy = true) | ||
final public function lazy($lazy = true) | ||
{ | ||
$this->definition->setLazy($lazy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this always set a bool here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same in all loaders btw
@@ -267,7 +267,10 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) | |||
foreach (array('class', 'public', 'shared', 'synthetic', 'lazy', 'abstract') as $key) { | |||
if ($value = $service->getAttribute($key)) { | |||
$method = 'set'.$key; | |||
$definition->$method(XmlUtils::phpize($value)); | |||
$definition->$method($value = XmlUtils::phpize($value)); | |||
if ('lazy' === $key && \is_string($value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as lazy
has a special logic, I would rather remove it from the loop and handle it on its own (as done for some other properties)
Do we still need LazyLoadingValueHolderFactoryV1 in master ? |
@stof comments addressed, thanks. |
d6a94d7
to
5094785
Compare
…\ProxifiedInterface"
Thank you @nicolas-grekas. |
…ith "lazy: Some\ProxifiedInterface" (nicolas-grekas) This PR was merged into the 4.2-dev branch. Discussion ---------- [ProxyManagerBridge][DI] allow proxifying interfaces with "lazy: Some\ProxifiedInterface" | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #20656 | License | MIT | Doc PR | - By adding `<tag name="proxy" interface="Some\ProxifiedInterface" />` to your service definitions, this PR allows generating interface-based proxies. This would allow two things: - generating lazy proxies for final classes - wrapping a service into such proxy to forbid using the methods that are on a specific implementation but not on some interface - the proxy acting as a safe guard. The generated proxies are always lazy, so that lazy=true/false makes no difference. As a shortcut, you can also use `lazy: Some\ProxifiedInterface` to do the same (yaml example this time.) Commits ------- 1d9f1d1 [ProxyManagerBridge][DI] allow proxifying interfaces with "lazy: Some\ProxifiedInterface"
…ers and pass it to child definitions (nicolas-grekas) This PR was merged into the 4.4 branch. Discussion ---------- [DependencyInjection] Fix "proxy" tag: resolve its parameters and pass it to child definitions | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - Forgotten in #27697 "proxy" tags are special: they must follow like the "lazy" attribute of definitions. Commits ------- 4cc3b3d [DependencyInjection] Fix "proxy" tag: resolve its parameters and pass it to child definitions
…oxies out of the box (nicolas-grekas) This PR was merged into the 6.2 branch. Discussion ---------- [DependencyInjection] Use lazy-loading ghost object proxies out of the box | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #35345 | License | MIT | Doc PR | - This PR builds on #46751. It also replaces #46458. Instead of using ProxyManager to make lazy services actually lazy, using `LazyGhostObjectTrait` from #46751 allows doing so *out of the box* - aka without the need to install any optional dependencies. When a virtual proxy is required (typically when using [the `proxy` tag](#27697)), ProxyManager is still required (and the dep remains optional.) But for most services, using `LazyGhostObjectTrait` just works \o/ Commits ------- 58a1848 [DependencyInjection] Use lazy-loading ghost object proxies out of the box
…oxies out of the box (nicolas-grekas) This PR was merged into the 6.2 branch. Discussion ---------- [DependencyInjection] Use lazy-loading ghost object proxies out of the box | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #35345 | License | MIT | Doc PR | - This PR builds on #46751. It also replaces #46458. Instead of using ProxyManager to make lazy services actually lazy, using `LazyGhostObjectTrait` from #46751 allows doing so *out of the box* - aka without the need to install any optional dependencies. When a virtual proxy is required (typically when using [the `proxy` tag](symfony/symfony#27697)), ProxyManager is still required (and the dep remains optional.) But for most services, using `LazyGhostObjectTrait` just works \o/ Commits ------- 58a184826a [DependencyInjection] Use lazy-loading ghost object proxies out of the box
…oxies out of the box (nicolas-grekas) This PR was merged into the 6.2 branch. Discussion ---------- [DependencyInjection] Use lazy-loading ghost object proxies out of the box | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #35345 | License | MIT | Doc PR | - This PR builds on #46751. It also replaces #46458. Instead of using ProxyManager to make lazy services actually lazy, using `LazyGhostObjectTrait` from #46751 allows doing so *out of the box* - aka without the need to install any optional dependencies. When a virtual proxy is required (typically when using [the `proxy` tag](symfony/symfony#27697)), ProxyManager is still required (and the dep remains optional.) But for most services, using `LazyGhostObjectTrait` just works \o/ Commits ------- 58a184826a [DependencyInjection] Use lazy-loading ghost object proxies out of the box
…oxies out of the box (nicolas-grekas) This PR was merged into the 6.2 branch. Discussion ---------- [DependencyInjection] Use lazy-loading ghost object proxies out of the box | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #35345 | License | MIT | Doc PR | - This PR builds on #46751. It also replaces #46458. Instead of using ProxyManager to make lazy services actually lazy, using `LazyGhostObjectTrait` from #46751 allows doing so *out of the box* - aka without the need to install any optional dependencies. When a virtual proxy is required (typically when using [the `proxy` tag](symfony/symfony#27697)), ProxyManager is still required (and the dep remains optional.) But for most services, using `LazyGhostObjectTrait` just works \o/ Commits ------- 58a184826a [DependencyInjection] Use lazy-loading ghost object proxies out of the box
By adding
<tag name="proxy" interface="Some\ProxifiedInterface" />
to your service definitions, this PR allows generating interface-based proxies.This would allow two things:
The generated proxies are always lazy, so that lazy=true/false makes no difference.
As a shortcut, you can also use
lazy: Some\ProxifiedInterface
to do the same (yaml example this time.)