Skip to content
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

Fix BC break with DoctrineType::reset() for all Symfony versions #970

Merged
merged 1 commit into from Jun 4, 2019

Conversation

javer
Copy link
Contributor

@javer javer commented May 14, 2019

Fixes BC break with mistakenly removed kernel.reset tag from form.type.entity service, because DoctrineType implements ResetInterface only in Symfony 4.2+, therefore all previous versions starting from 3.4 are affected.

This BC break was introduced in version 1.11.0 in commit 6b25ea4

Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

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

See feedback on the conditional.

@javer
Copy link
Contributor Author

javer commented May 16, 2019

@alcaeus Fixed, please check.

@@ -343,6 +344,11 @@ protected function ormLoad(array $config, ContainerBuilder $container)
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('orm.xml');

// This check can be removed when support for Symfony < 4.2 is dropped
if (!method_exists(AbstractController::class, 'addLink')) {
Copy link
Member

Choose a reason for hiding this comment

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

This checks the version of the FrameworkBundle which doesn't have to be the same as the one of the DoctrineBridge (which provides the type).

Copy link
Member

Choose a reason for hiding this comment

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

So we also need to check whether the type implements the ResetInterface?

@javer
Copy link
Contributor Author

javer commented May 16, 2019

@alcaeus @xabbuh What do you think about this solution?

// This check can be removed when support for Symfony < 4.2 is dropped
if (! interface_exists(ResetInterface::class)
|| ! is_a(DoctrineType::class, ResetInterface::class)
|| ! $container->getDefinition('form.type.entity')->hasTag('kernel.reset')) {
Copy link
Member

Choose a reason for hiding this comment

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

If this works reliably (I’m not sure because I don’t know when autoconfig is applied, ping @nicolas-grekas) I don’t believe we need the other checks at all 🤔

@javer javer force-pushed the fix-doctrine-type-reset branch 2 times, most recently from 0b636c8 to 5e66303 Compare May 16, 2019 15:00
@javer
Copy link
Contributor Author

javer commented May 16, 2019

@alcaeus It seems to be the most reliable solution according to above comments, because method reset could be removed from DoctrineType in the future versions of DoctrineBridge.

Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

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

Sorry, more feedback needed from @doctrine/team-symfony-integration.

@alcaeus
Copy link
Member

alcaeus commented May 16, 2019

@alcaeus It seems to be the most reliable solution according to above comments, because method reset could be removed from DoctrineType in the future versions of DoctrineBridge.

That would be a BC break which would only be possible in a major release: this bundle would not install such a version without modifications.

@javer
Copy link
Contributor Author

javer commented May 17, 2019

@alcaeus So we return to the first solution, which was correct, because it:

  • checks whether symfony/form component is installed
  • checks whether DoctrineType class has method reset
  • adds kernel.reset tag to the service regardless it's already added or not

@javer
Copy link
Contributor Author

javer commented May 20, 2019

@alcaeus @xabbuh Any thoughts?

@alcaeus
Copy link
Member

alcaeus commented May 21, 2019

The safe choice:

  • check whether symfony/form is installed. If not, skip the rest and don't do anything.
  • check whether ResetInterface exists. If not, skip the rest of the checks and add the tag.
  • check whether DoctrineType implements ResetInterface. If not, skip the rest of the checks and add the tag.
  • check whether AbstractController has an addLink method. If not, add the tag.

Note that checking for the reset method is unnecessary - the minimum version we require has that. It's the ResetInterface that's only available in newer versions and is also tied to autoconfiguration.

The "yeah, this won't break choice":

  • Just add the tag.

As I said - I couldn't find any side effects from having two kernel.reset tags in there, so we may as well just add the tag. I'm also not sure if the tag would even be added a second time by the autoconfiguration mechanism.

@javer
Copy link
Contributor Author

javer commented May 21, 2019

@alcaeus Done, please check.

@alcaeus alcaeus requested a review from xabbuh May 21, 2019 17:23
@javer
Copy link
Contributor Author

javer commented Jun 2, 2019

@alcaeus @xabbuh Hi guys, I have tested this fix with Symfony 4.2 and 4.3 and have just realized that even in these recent versions of Symfony kernel.reset tag isn't added automatically, because automatic tagging works only for autoconfigured services: https://github.com/symfony/symfony/blob/4.3/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php#L50
But this service is not marked as autoconfigured, even when you make all your services in the app autoconfigurable, because autoconfigure option works only for services defined in the same yml file: https://symfony.com/doc/current/service_container.html#the-autoconfigure-option

Actually this ResetInterface haven't ever worked since adding it by @nicolas-grekas in commit symfony/symfony@8982036#diff-0b86d71e1a20e98ac050dd33c4e79373R29

So I modified code to explicitly add kernel.reset tag always if we have symfony/form component installed. All other checks aren't necessary and even wrong.

@javer javer changed the title Fix BC break with DoctrineType::reset() for Symfony 3.4-4.1 Fix BC break with DoctrineType::reset() for all Symfony versions Jun 2, 2019
@xabbuh
Copy link
Member

xabbuh commented Jun 2, 2019

The check for the existence of the method is still necessary, isn't it? Otherwise the kernel might call try to call the method because of the tag while it actually doesn't exist.

@javer
Copy link
Contributor Author

javer commented Jun 2, 2019

@xabbuh Well, actually this check is not so critical, because removing reset method from DoctrineType will be a BC break in Symfony Doctrine Bridge, but I added this check for safety.

By the way, we returned to the implementation I already did 16 days ago: #970 (comment)

@xabbuh
Copy link
Member

xabbuh commented Jun 2, 2019

Ah sorry, that's my mistake. I thought the method wasn't present in Symfony 3.4.

@xabbuh
Copy link
Member

xabbuh commented Jun 2, 2019

So if we don't need the check, can't we just add the tag in the XML config file where we define the service config?

@javer
Copy link
Contributor Author

javer commented Jun 2, 2019

No, unfortunately we cannot hardcode this tag, because this bundle doesn't have symfony/form as a dependency, so we should add this tag only when application uses this component.

I have already tried to do this unconditionally, and unit tests were failed.

Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

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

Sorry for all the back and forth here - I guess we were all blind. However, we can just check if symfony/form is installed, everything else is (as you already mentioned) unnecessary. I'll tag a new release once the changes below have been made.

DependencyInjection/DoctrineExtension.php Outdated Show resolved Hide resolved
Fixes BC break with mistakenly removed `kernel.reset` tag from
`form.type.entity` service, because `DoctrineType` implements
`ResetInterface`, but this service is not autoconfigured, so
the `kernel.reset` tag won't be added automatically.

This BC break was introduced in version 1.11.0 in commit 6b25ea4
Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

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

Thanks @javer, and sorry for taking a few laps around the block to realise what's going on here!

@alcaeus alcaeus merged commit 28101e2 into doctrine:1.11.x Jun 4, 2019
@alcaeus alcaeus self-assigned this Jun 4, 2019
@alcaeus alcaeus added the Bug label Jun 4, 2019
@alcaeus alcaeus added this to the 1.11.2 milestone Jun 4, 2019
@alcaeus alcaeus added this to 1.11 in Roadmap Jun 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants