-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Workflow] make $registry->get(Entity::class) consistent with the doctrine way (by using class name) #37883
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
The failed tests do not seem to be related to workflow ^^ |
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.
Good idea 👍🏼
I left some minor comment
src/Symfony/Component/Workflow/SupportStrategy/InstanceOfSupportStrategy.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Workflow/SupportStrategy/InstanceOfSupportStrategy.php
Outdated
Show resolved
Hide resolved
@@ -18,5 +18,5 @@ | |||
*/ | |||
interface WorkflowSupportStrategyInterface | |||
{ | |||
public function supports(WorkflowInterface $workflow, object $subject): bool; | |||
public function supports(WorkflowInterface $workflow, $subject): bool; |
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 don't know if it's a BC break / cc @fabpot or @nicolas-grekas
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.
It is a BC break, so it's not allowed.
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 don't think I can do what I want without all these BC Breaks :/
So, shall we move it to Symfony6 or it's not worth it ?
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.
We never break BC without an upgrade path. So, Symfony 6 won’t help.
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.
This PR brings a good change in my opinion. Providing an upgrade path for those kind of changes was easier in the bad old days without typing.
Is there another good or even better name for the interface to deprecated this one?
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 have a stupid question that I can't answer.
I'm sorry to bother you with this.
How loosening the typing makes it a BC break ?
I tried this code :
<?php
class A {
function f($arg) {
var_dump($arg);
}
}
class B extends A {
function f(object $arg) {
var_dump($arg);
}
}
$a = new A();
$a->f((new \stdClass));
$a = new A();
$a->f(1);
$b = new B();
$b->f((new \stdClass));
But everything is working as expected.
What am I missing ?
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.
The declaration of B::f
violates LSP since A states that $arg
accept anything, restricting it to only objects in B
means that an instance of B
can't be used as an instance of A
.
I'm not sure why you didn't get an error, your code should fail with the following error:
Declaration of B::f(object $arg) must be compatible with A::f($arg)
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.
Indeed
if I add declare(strict_types=1);
I have the error.
Thank you @jvasseur
Co-authored-by: Grégoire Pineau <lyrixx@lyrixx.info>
Co-authored-by: Grégoire Pineau <lyrixx@lyrixx.info>
@@ -18,5 +18,5 @@ | |||
*/ | |||
interface WorkflowSupportStrategyInterface | |||
{ | |||
public function supports(WorkflowInterface $workflow, object $subject): bool; | |||
public function supports(WorkflowInterface $workflow, $subject): bool; |
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.
It is a BC break, so it's not allowed.
@@ -41,7 +41,7 @@ public function has(object $subject, string $workflowName = null): bool | |||
/** | |||
* @return Workflow | |||
*/ | |||
public function get(object $subject, string $workflowName = null) | |||
public function get($subject, string $workflowName = null) |
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.
This is a BC break as the class is not final
.
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.
Still a BC break.
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.
oups, I deleted my comment unintentionally.
Anyway, I'm new to this. I don't understand what kind of path you want me to take.
Should I, for example :
- create another method
- deprecate this one
And that case, how can I have the consistency I am looking for (which only goes through this BC Breaks) ?
@@ -29,9 +30,17 @@ public function __construct(string $className) | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function supports(WorkflowInterface $workflow, object $subject): bool | |||
public function supports(WorkflowInterface $workflow, $subject): bool |
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.
This one is not a BC break as the class is final
.
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.
this seems only useful for InstanceOfSupportStrategy, not sure we should make this design change.
alternatively, we could consider otherwise, i'd argue the usefulness of strategies in general (e.g in favor of mapping by class by design) |
I agree, but this was asked in an issue / pr |
wait, to solve this, isnt it simply matter of adding assuming your definitions are "class named" (that's our convention at least). That seems like a much cleaner and explicit approach to me. (To me getting a random workflow, based on "strategies" always seemed like a WTF :)) |
@@ -41,7 +41,7 @@ public function has(object $subject, string $workflowName = null): bool | |||
/** | |||
* @return Workflow | |||
*/ | |||
public function get(object $subject, string $workflowName = null) | |||
public function get($subject, string $workflowName = null) |
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.
Still a BC break.
@@ -31,6 +32,10 @@ public function __construct(string $className) | |||
*/ | |||
public function supports(WorkflowInterface $workflow, object $subject): bool | |||
{ | |||
if ($subject instanceof \stdClass && property_exists($subject, 'class')) { |
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.
Is it really worth it?
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.
consistency is part of a good programming. Unfortunately, it is not PHP's strong suit.
I'm not a big fan of this.
Might not be worth it, indeed.
@lyrixx @ro0NL @simonberger @fabpot What do you prefer ? Or do you have a 4️⃣ option ? |
it should be clear subject (an object) and workflow name (a string) are different things
a new then, if you use "class named" workflows, |
I wouldn't change anything. But @lyrixx has the last word. |
@ro0NL The workflow name does not have to be unique (among different workflows), right? Not absolutely a showstopper for a |
The Then, you should not forget that a subject (doctrine entity or anything else) can have multiple workflows on it. So getting the workflow by name should not be encouraged. But your usecase is valid so I'm bit embarrassed by not having a nice solution :/. But I like the @ro0NL idea a lot. We can index all workflows by name (and not by subject FQCN). But you can use the FQCN for the workflow name :) Do you want to give a try to? |
@lyrixx ok, I'll see what I can do. |
Actually, I don't think this is a good idea: An object can have many workflow, so getting the workflow by its name does not make sens. Then, someone has the same need than you and I think #37979 is a simpler / better solution. WDYT? |
I did not use Definition before so I'm not really familiar with it. If I understand correctly, Definition is specific to a workflow. How do you inject a specific Definition ? With services.yaml ? Is it possible to inject a specific Workflow ? I think I don't understand how it helps me. Maybe a PR in symfony-docs might help me :D And I also have another use case, totally different (and maybe not relevant)
I feel that something more intuitive would be :
I can also do something like
^^ But I probably missed your point, sorry :/ Do you have an example ? |
First, you don't need to use the registry to get a workflow. For the record, the Registry has been implemented to be able to get a workflow in twig template. In pure PHP code, I recommend you to inject directly the workflow instance that match your entity. If you have many workflows, you can use typed + named parameter. For example, with the following configuration, the following services are available:
This means, I'm able to inject a workflow like this: https://github.com/lyrixx/SFLive-Paris2016-Workflow/blob/master/src/Controller/ArticleController.php#L54 or like this: class A
{
public function __contruct(WorkflowInterface $articleWorkflow)
} I found the list of available service with the following command:
With that in mind, You don't need the registry anymore, and so I think we can close the PR. A note about the definition (the class that holds the workflow configuration (place + transition + metadata store) and the metadata store (the class that holds all metadata) : You can inject theme in any class. But they are not autowireable. Your need the following code: class A
{
public function __contruct(Definition $definition)
} # services.yaml
services:
App\A:
parameters:
$definition: @workflow.article.definition Note: I found the service to inject thanks to the following command
I hope I solved all your issues and question. If you learnt new things, may I ask you to open a PR to the doc to explain to others what you learnt ? 🙏🏼 Thanks a lot
|
@lyrixx I will update my PR-docs because the injection of Registry is the recommended way in the docs and AFAIK there's no mention of typed + named parameter injection. |
Thanks a lot for your efforts. I'm closing this pr. But if you have others questions don't hesitate to ask here |
For this, I had to change some Interface, but I don't think it causes BC Breaks
Now that I'm submitting it, I wonder if it's been submitted before 🤔
Anyway, I think it's more consistent to use the class name to retrieve a workflow.
It's particularly convenient when you need the metadata of the workflow. In that case, you might not have an instance available and you have to do something like
$registry->get(new Entity())
.With this PR,
$registry->get(Entity::class)
will work :)