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

Allow DataPersister to return a new instance instead of mutating #1967

Conversation

gorghoa
Copy link
Contributor

@gorghoa gorghoa commented May 23, 2018

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? unit tests are green, bdd are red, master too seems wrecked 🎶
Fixed tickets #1799
License MIT
Doc PR @todo

closes #1799

DataPersisterInterface can now return the result of the persistence call instead of relying on data mutation. Thus allowing persistence layer to deal with immutable data.

At least, this PR breaks the technical detail that was implicitly using objects instance reference as an identifier for an entity, and conceptually I find this a huge win :)

@gorghoa gorghoa force-pushed the feat/1799-handle-immutable-resource-on-persist branch from a73fad3 to 1723b86 Compare May 23, 2018 20:13
@gorghoa
Copy link
Contributor Author

gorghoa commented May 23, 2018

I hope, I have not forgotten any DataPersisterInterface implementation in the code base. Any hint on some part of the code I may have missed is welcome!

@@ -58,7 +58,9 @@ public function onKernelView(GetResponseForControllerResultEvent $event)

switch ($request->getMethod()) {
case 'POST':
$objectManager->persist($controllerResult);
$event->setControllerResult(
Copy link
Contributor

Choose a reason for hiding this comment

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

CS: We usually don't split into multiple lines like this... Just keep it in one line.

Copy link
Contributor Author

@gorghoa gorghoa May 23, 2018

Choose a reason for hiding this comment

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

I won’t argue on CS, but in this case, given the low visual impact of ??, I fear that relegating the ?? at the end of the line somehow hides what’s going on.

For instance, to me, this is far less self-explanatory than the splitted version.

    case 'POST':
                $event->setControllerResult($this->dataPersister->persist($controllerResult) ?? $controllerResult));
                break;

As I said, this will be my only point of view on CS, I wont argue furthermore if you want to stick to the one line version ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nevermind, adding the deprecation notice forces me to assign persist result to a temp var anyway, so the one line will be of fine size 👍

@@ -50,7 +50,10 @@ public function onKernelView(GetResponseForControllerResultEvent $event)
case 'PUT':
case 'PATCH':
case 'POST':
$this->dataPersister->persist($controllerResult);
$event->setControllerResult(
Copy link
Contributor

Choose a reason for hiding this comment

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

CS: We usually don't split into multiple lines like this... Just keep it in one line.

@@ -33,6 +33,8 @@ public function supports($data): bool;
* Persists the data.
*
* @param mixed $data
*
* @return object|void Void will not be supported in API Platform 3, an object should always be returned
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it might be better if we add deprecation errors where this method is called in API Platform?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a deprecation notice in the WriteListener, and ItemMutationResolverFactory.

Copy link
Member

Choose a reason for hiding this comment

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

Doing it in ChainDataPersister should be enough. If we deprecate returning void, please remove it from the supported types and only keep it in the comment.

Copy link
Member

Choose a reason for hiding this comment

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

Ok you already made the changes, so keep them :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Doing it in ChainDataPersister should be enough.

It's not enough because ChainDataPersister is only an implementation which might or might not be used by the user.

@gorghoa gorghoa force-pushed the feat/1799-handle-immutable-resource-on-persist branch 3 times, most recently from 435ad99 to 6056ad5 Compare May 23, 2018 21:01
@gorghoa
Copy link
Contributor Author

gorghoa commented May 23, 2018

Thanks for your review @teohhanhui 👍 , code updated :)

$dummy->setName('Dummyrino');

$dummy2 = new Dummy();
$dummy2->setName('Dummyferoce');
Copy link
Member

Choose a reason for hiding this comment

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

Dummycorn 🦄 ?

Copy link
Member

@soyuka soyuka left a comment

Choose a reason for hiding this comment

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

👍

@soyuka
Copy link
Member

soyuka commented May 24, 2018

@teohhanhui please merge after taking a last quick look :) thanks!

@teohhanhui
Copy link
Contributor

@gorghoa Looks like we need a rebase to merge. 👍

@teohhanhui teohhanhui force-pushed the feat/1799-handle-immutable-resource-on-persist branch from 6056ad5 to 96a6148 Compare May 24, 2018 16:57
@teohhanhui teohhanhui force-pushed the feat/1799-handle-immutable-resource-on-persist branch from 96a6148 to 5f050fe Compare May 24, 2018 16:59
@teohhanhui teohhanhui merged commit dcc9736 into api-platform:master May 24, 2018
@teohhanhui
Copy link
Contributor

Thanks @gorghoa! 🎉

@gorghoa
Copy link
Contributor Author

gorghoa commented May 24, 2018

Thank you all for your kind reviews and making api platform always better! 💪

@@ -51,7 +51,7 @@ public function persist($data)
{
foreach ($this->persisters as $persister) {
if ($persister->supports($data)) {
$persister->persist($data);
return $persister->persist($data) ?? $data;
Copy link
Contributor

Choose a reason for hiding this comment

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

I know it's a bit late, but wouldn't this prevent all persisters to run, and wouldn't this stop at the first persister that supports this data ? what if I need to apply multiple data persisters ?

Copy link
Member

@dunglas dunglas Jul 3, 2018

Choose a reason for hiding this comment

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

Good catch... We may return after the loop instead of inside. WYT? (ping @gorghoa)

Copy link
Contributor Author

@gorghoa gorghoa Jul 3, 2018

Choose a reason for hiding this comment

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

indeed, nice catch… Thanks @Taluu for your review!

We may return after the loop instead of inside. WYT?

But from which persister shall we return? First one? Last one? Custom strategy based on priority? (somehow, this question was in fact already valid with the former implementation: the last was the winner, but was it “safe” to assume it was the one that should win the refresh battle?).

I’m now ashamed that my implementation causes two BC breaks:

  • 1st, as @Taluu found out, it skips other registered persisters
  • 2nd. It changes the refresher order

Maybe the best option in term of confidence should be not return data from persister but somehow re-trigger a read item operation. At the cost of an extra read query.

afterthoughts:

This may fix everything…

re-assign $data to the previous persister returned value, then return $data outside the loop as @dunglas suggests.

   foreach ($this->persisters as $persister) {
            if ($persister->supports($data)) {
                $data = $persister->persist($data) ?? $data;
            }
        }

  return $data;

Everything should be as before 🎉

ps. I would personally rather have a recursive function instead of re-assigning $data in the loop, but I’ve the feeling that we could lose some perfs + inconsistent coding style :)

Copy link
Member

Choose a reason for hiding this comment

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

afterthoughts

It was exactly what i've in mind (last win)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, that's what I had in mind too

Copy link
Contributor Author

@gorghoa gorghoa Jul 3, 2018

Choose a reason for hiding this comment

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

Here is the PR #2064

Sorry for the inconvenience, hope this had not causing too much troubles for you @Taluu

On the plus side, tests are now covering this feature :)

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.

API Platform does not play well with immutable resource
5 participants