persistence icon indicating copy to clipboard operation
persistence copied to clipboard

Remove dependency to `doctrine/common`

Open greg0ire opened this issue 2 years ago • 19 comments

Two good reasons to do this move:

  • This was a circular dependency.
  • doctrine/common is being sunset.

greg0ire avatar Jun 16 '22 21:06 greg0ire

The code does not properly handle cases where code implements the Proxy interface without the future methods

stof avatar Jun 17 '22 09:06 stof

The code does not properly handle cases where code implements the Proxy interface without the future methods

I see several paths forward:

  1. deprecate the Proxy interface in favor of a more complete one, check it in addition to the one from common. Drawbacks: it will have a worse name, the best name being already taken (unless you can find something ?). Also, it won't allow us to drop the dependency to doctrine/common
  2. add a complementary interface with only the missing methods, extend it in doctrine/common, release doctrine/common, add a conflict on persistence with versions older than the latest doctrine/common, and throw unless both interfaces are implemented. Drawback: it's quite complicated
  3. add method_exists checks and throw in the appropriate case. Drawback: I'm not sure how performance-sensitive the code where the check happens is, or if having those checks could become an issue. Maybe check just for one method and assuming the rest is implemented would be sufficient. Anyway, even if all methods exist, that's not a guarantee that they have the required signature.

What would you recommend? I'm leaning towards 3.

greg0ire avatar Jun 17 '22 17:06 greg0ire

I went ahead and implemented a check, but just for the methods that are called.

greg0ire avatar Jun 19 '22 12:06 greg0ire

It's been a while since I had to touch proxied-public-properties-voodoo magic but here goes nothing: can't we outsource the optimization to doctrine/common and/or employ consumers (well, ORM) to do some check beforehand and remove code altogether? Given ORM is the only consumer, and it already relies on doctrine/common, it could even provide its own implementation for needed reflection.

malarzm avatar Jun 20 '22 20:06 malarzm

@malarzm no idea yet, but it sounds better indeed, I'll try to look into that 👍

greg0ire avatar Jun 22 '22 06:06 greg0ire

@malarzm I've taken a look at ORM, and getValue() seems to be called in a lot of places. I'm not quite sure the check is useful in 100% of the call sites. Maybe somebody will know which one actually require the check.

I think one way to do this in a simple way would be to override AbstractClassMetadataFactory::getReflectionService() so that it returns a service implemented in the ORM with an overridden getAccessibleProperty method which would return 3 types inheriting the 3 ones from persistence, with an overridden method… this looks quite hairy.

@derrabus @beberlei what do you think about this?

It should be noted that if we decide to go that way, we will have to deprecate passing a proxy object to getValue(), and postpone the removal of the check to 4.0. Because of how this will slow things down, I think we should merge this PR regardless of whether we do what @malarzm suggests, that way we get rid of the (circular!) dependency now.

greg0ire avatar Jun 22 '22 17:06 greg0ire

GetValue is Performance critical, i would like to avoid to increase the number of method calls there.

beberlei avatar Jun 29 '22 18:06 beberlei

I need to look at this on a proper display, on mobile i cant fully review

beberlei avatar Jun 29 '22 18:06 beberlei

Here goes nothing #2 to keep the changes minimal: instanceof works just fine with possibly-non-existing classes, how about keeping things as is reflection-wise and just moving doctrine/common to require-dev for the sake of tests? It's hacky a bit but will work :)

malarzm avatar Jun 29 '22 20:06 malarzm

@malarzm it's already in require-dev :wink: This PR is a step towards sunsetting doctrine/common.

greg0ire avatar Jun 29 '22 21:06 greg0ire

it's already in require-dev

Oh, missed that. What's the point then? Once we get rid of old Proxies in ORM (and enough time passes) we'll be able to just get rid of it. What's the benefit now?

malarzm avatar Jun 30 '22 06:06 malarzm

  1. I'm trying to migrate ORM to PHP 8 syntax: https://github.com/doctrine/orm/projects/6
  2. It's better to add type declarations to doctrine/common beforehand, that way I can add them as well on inheriting types, but @derrabus suggested we kill doctrine/common instead
  3. I'm trying to kill it

greg0ire avatar Jun 30 '22 07:06 greg0ire

Shouldn't ORM switch to ProxyManager first and continue PHP 8 syntax afterwards? Then doctrine/common will be dropped from its requirements. We can't really kill doctrine/common before releasing ORM 3.0 and even after that we'll have to provide support for 2.x for quite some time

malarzm avatar Jun 30 '22 14:06 malarzm

Shouldn't ORM switch to ProxyManager first and continue PHP 8 syntax afterwards?

This comment says we shouldn't: https://github.com/doctrine/orm/issues/8518#issuecomment-1124805479

We can't really kill doctrine/common before releasing ORM 3.0

Can't we? If we copy proxy classes to the ORM, maybe we can?

greg0ire avatar Jun 30 '22 17:06 greg0ire

If we copy proxy classes to the ORM, maybe we can?

All right, had no idea it was the plan :)

malarzm avatar Jul 01 '22 08:07 malarzm

@beberlei after #299, the extra method calls are moved to setValue, is that better performance-wise? This method is called less than getValue I suppose.

greg0ire avatar Aug 20 '22 11:08 greg0ire

Converting to draft as determining how to replace doctrine/common proxy functionality might have some influence on this PR.

greg0ire avatar Aug 21 '22 21:08 greg0ire

See follow up at #307

nicolas-grekas avatar Oct 03 '22 13:10 nicolas-grekas

@greg0ire Generally setValue is used in hydration, getValue in changeset computation. So setValue is probably called much more often as its for every read.

beberlei avatar Oct 09 '22 01:10 beberlei