Skip to content

[DependencyInjection] Use a service locator in AddConstraintValidatorsPass #21730

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

Closed
wants to merge 4 commits into from

Conversation

GuilhemN
Copy link
Contributor

@GuilhemN GuilhemN commented Feb 23, 2017

Q A
Branch? master
Bug fix? no
New feature? no
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets
License MIT
Doc PR

Use a service locator to load constraint validators: it allows them to be private.

@@ -11,7 +11,7 @@

namespace Symfony\Bundle\FrameworkBundle\Validator;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Psr\Container\ContainerInterface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given $container is protected I think that's a BC break

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's acceptable, the methods defined are the same and it will only fail if someone checks its interface which is unlikely.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. ContainerInterface contains more methods than the Psr one, calling $this->container->getParameter() would break. We had to write a BC layer for a similar case in #21451

Copy link
Member

@chalasr chalasr Feb 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note also that adding deprecations for using experimental features has been rejected in #21625. I would wait for 4.0 on this one (that's why I did not proposed it), let's see what other think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

about deprecating in this PR, see #21625 (comment)
this needs to be resolved before acting to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've an idea of a BC layer (including deprecations but not about experimental features), I'll update the pr soon.

@GuilhemN
Copy link
Contributor Author

Considering your comment, I think it's better to delay this change to 4.0 and to just deprecate ConstraintValidatorFactory::$container and ConstraintValidatorFactory::$validators for now, it will be much easier to do this way.

@GuilhemN GuilhemN changed the title [DependencyInjection] Use a service locator in AddConstraintValidatorsPass [DependencyInjection] Deprecate ConstraintValidatorFactory::$validators and $container Feb 23, 2017
@nicolas-grekas
Copy link
Member

nicolas-grekas commented Feb 23, 2017

Is there any BC break really?
I mean, code that exists won't suddenly get a PSR11-only object injected, will they?

@GuilhemN
Copy link
Contributor Author

If someone uses $container he would receive a psr-11 only container as I updated the first argument to a service locator.
I think we can change the type hint now but we can't update the service config to a service locator before 4.0.

@nicolas-grekas
Copy link
Member

If someone uses $container he would receive a psr-11 only container as I updated the first argument to a service locator

BC breaks are about existing code - ie already written ones - that may break because of a change here. How can this change break existing code?

@chalasr
Copy link
Member

chalasr commented Feb 23, 2017

Anyone extending this code and wiring it on its own doesn't have to check that what it receives is a symfony container until now since we guarantee it, after this change such code would work by luck if it relies on any method that is not part of the PSR-11 replacement. It would truly break only when decorating the service of this factory, maybe we don't care.

@GuilhemN
Copy link
Contributor Author

@chalasr as discussed with @nicolas-grekas, there is no bc break as it won't break existing code: the only time the container will no longer be an instance of the symfony container when upgrading will be when using the validator.validator_factory service but it doesn't matter as we know it's not extended (its class is fixed).
So maybe a class extending ConstraintValidatorFactory won't support the psr-11 container but that's not truly a bc break as it won't break existing code, the container will always be a symfony container, only new code could be broken but that's not part of bc.

@chalasr
Copy link
Member

chalasr commented Feb 23, 2017

Pleased to see one more container injection removed then.

@GuilhemN GuilhemN changed the title [DependencyInjection] Deprecate ConstraintValidatorFactory::$validators and $container [DependencyInjection] Use a service locator in AddConstraintValidatorsPass Feb 23, 2017

$this->validators[$name] = new $name();
$this->validators[$name] = new $name();
}
} elseif (is_string($this->validators[$name])) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should has() be called here too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? In case what is returned by the container is a string ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get() is called if this check succeeds. We're checking has() before get() in the first check above so I'm wondering if we need it here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above it's needed because we want to know when to fallback to manual instantiating, here it just depends of the exception we want, with a has the code will fail a few lines later with an InvalidArgumentException, otherwise it will fail in the container.
This should not happen unless the user entered a wrong service, imo it's not worth supporting it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@chalasr
Copy link
Member

chalasr commented Feb 24, 2017

The Validator's CHANGELOG should mention the deprecation

@GuilhemN
Copy link
Contributor Author

Changelog updated ☺

UPGRADE-3.3.md Outdated
@@ -71,6 +71,9 @@ FrameworkBundle
deprecated and will be removed in 4.0. Use the `Symfony\Component\Form\DependencyInjection\FormPass`
class instead.

* Extending `ConstraintValidatorFactory` is deprecated and won't be supported
in 4.0.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be on one line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

throw new InvalidArgumentException(sprintf('The service "%s" must be public as it can be lazy-loaded.', $id));
}

if ($definition->isAbstract()) {
Copy link
Member

@nicolas-grekas nicolas-grekas Feb 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Abstract services should be ignored ie you should "continue". Note that this applies to many other cases in the code base: many passes throw on abstract services, but now that tags can be inherited in child definitions, we should just "continue" instead. Deserves another PR if you'd like to do it :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like ContainerBuilder::findTaggedServiceIds() deserves a new argument ;)
I can't do it this week so I opened #21761 in case someone is interested.

@nicolas-grekas nicolas-grekas added this to the 3.3 milestone Feb 25, 2017
fabpot added a commit that referenced this pull request Feb 26, 2017
…ument type (chalasr)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DI] Remove experimental status from service-locator argument type

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #21625 (comment), #21625 (comment), #21710
| License       | MIT

The `service-locator` argument type is not controversial to me. We know its scope, nothing really surprising, just a map of services to be lazily loaded like `iterator` is (which is not experimental) but keyed.
About its api, it's just PSR-11 restricted to objects, nothing that can't be changed safely in the future.

As stated in #21625 (comment), it proven its usefulness already. I think what we were looking for by flagging it experimental is just to see it in action, we've 3 opened PRs for that (#21625, #21690, #21730).

This allows introducing deprecations for making use of the feature in the core, thus unlocks #21625 and #21690.

Commits
-------

46dc47a [DI] Remove experimental status from service-locator argument type
@nicolas-grekas
Copy link
Member

rebase needed

@GuilhemN
Copy link
Contributor Author

GuilhemN commented Mar 1, 2017

@nicolas-grekas done.

Also, abstract definitions are now ignored and I improved the test readability by removing mocks.

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@fabpot
Copy link
Member

fabpot commented Mar 1, 2017

Thank you @GuilhemN.

@fabpot fabpot closed this in 69374da Mar 1, 2017
@GuilhemN GuilhemN deleted the SERVICELOCATOR branch March 1, 2017 16:28
));
$container = new ContainerBuilder();
$validatorFactory = $container->register('validator.validator_factory')
->setArguments(array(new ServiceLocatorArgument()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

broken here, the constructor expects an argument. See #21821

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants