Skip to content

[WORKFLOW] [RFC] Pass context/metadata in the entire workflow process #27925

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
noniagriconomie opened this issue Jul 11, 2018 · 21 comments
Closed
Labels
RFC RFC = Request For Comments (proposals about features that you want to be discussed) Workflow

Comments

@noniagriconomie
Copy link
Contributor

Description

Hi

We are using the workflow component to redesign our internal processing of some business entities.

We are now facing some logic we did not know how to deal with on our code port.

Previously we were doing on our entities status change this logic:

$entity->setStatus(Entity::STATUS_X, $specificComment); // comment can be a tech comment, a context comment, or anything else

and the setStatus() method is like this

public function setStatus(int $status, ?string $comment = null)
{
        $this->status = $status;
        $this->addStatusLogRecord(new StatusLog($this, $comment));

        return $this;
}

We were storing a statusLog on every status change with the new status, the date of change, the user (blameable) and an optionnal comment => for log/debug/history purpose

But now with the workflow, it is our internal marking store that call the setStatus() (mapping of the current place to our internal status because we store an int not a string),
and unfortunately we are not able to pass some other metadata.

Feature Request

Discussion on the availability to have a workflow business context to allow the developper to pass some context in the workflow process,
and get this context inside the workflow process, all workflow events and in the workflow marking store logic as well.
Is this a feature that can be usefull for this component? giving some possibility to developpers?
Or maybe developpers are already dealing differently for this kind of purpose?

Obviously we can add an in memory property on the entity for storing the comment and if it is not null, get it for the addStatusLogRecord() but this design is not pleasant at all.

Many thank for your time and thank you for this component that helps us a lot

@xabbuh xabbuh added RFC RFC = Request For Comments (proposals about features that you want to be discussed) Workflow labels Jul 11, 2018
@lyrixx
Copy link
Member

lyrixx commented Jul 16, 2018

What about adding WorkflowInterface::apply($entity, $transitionName, array $context = [])

@noniagriconomie
Copy link
Contributor Author

@lyrixx I am ok for that 👍
just to be sure, did you understand the main purpose/idea and is there any other way to do it properly right now?
thank you

@lyrixx
Copy link
Member

lyrixx commented Jul 16, 2018

Right now you you can do it like this:

class Entity
{
    public function applyTransition(WorkflowInterface $workflow, string $transitionName, array $context)
    {
        $workflow->apply($this, $transitionName);
        $this->context = $context;
    }
}

This is not perfect, but could do the job

@noniagriconomie
Copy link
Contributor Author

noniagriconomie commented Jul 17, 2018

@lyrixx yes it was my first idea but kind of hack :/

do you think it could be a nice additional feature?

@Padam87
Copy link
Contributor

Padam87 commented Jul 21, 2018

#20789

@noniagriconomie
Copy link
Contributor Author

Interesting PR, thank you for posting it
I really think this use case could be a very usefull option for devs as i explained in the description
It allows to do things properly imo
And in a correct way of coding and not « hacking » way

@lyrixx
Copy link
Member

lyrixx commented Jul 23, 2018

@Padam87 The intent is different here. In your case, it was done to control things.
Here it's just extra information during the save.

@Padam87
Copy link
Contributor

Padam87 commented Jul 23, 2018

My intent was exacly the same. :) The ability to pass parameters. #20774

If by control you mean that the parameters were also passed to the can method that is because if passing parameters is enabled, then guards should also have access to them.

@lyrixx
Copy link
Member

lyrixx commented Jul 23, 2018

IMHO, this contest should on by used by the marking store, to store more information.
So, This context should not goes through the workflow::can method

@noniagriconomie
Copy link
Contributor Author

in my example the context was intended to be passed to the whole workflow, but of course for getting data to set, not validation with the can (guard)

@Padam87
Copy link
Contributor

Padam87 commented Jul 23, 2018

Hm, I don't know. On one hand it makes sense to allow the dev to deal with this outside of the workflow, on the other that could lead to this:

if ($someParam === 'someValue' && $workflow->can($object, 'transition')) {
    $worflow->apply($object, 'transition', ['someParam' => $someParam])
}

Now the decision is made at 2 places, guard and controller. I don't like that.

Anyway, event params would be nice, even if it is just for the apply method.

@bbaga
Copy link

bbaga commented Jul 30, 2018

Hi, I'd like +1 the idea.
We are facing a very similar issue. Our entity is a carton that we want to load onto a truck. We would like to pass the tuck id as a context parameter into the can and apply methods as we would like verify that we can in fact load the carton to a specific truck (goes the right place etc). We'd like to do the verification in the can, because we have multiple workflows for different types of cartons where the verification is different, but the actual loading logic is the same.

As for now we are likely to use a wrapper around our actual carton entity with a context property on the wrapper as we don't want to pollute the entity it self. We plan to have a custom marking store that will operate on the carton entity's state property through the intermediate wrapper.

Far from ideal, but we would like to keep the logic in the workflow guards and transitions as much as possible.

PS: yohang/Finite does something similar, but I'd rather use this SF component for the attached utilities.

@stlrnz
Copy link
Contributor

stlrnz commented Aug 8, 2018

+1 for this idea from my side.
Also, I'd love to see the additional data in guard events. As for today we cannot perform all required checks in the guards. We have to define some of them in our controllers.

@alexhaker
Copy link

+1
That feature allows us to use Workflow component for our business processes in the system.
It would be very useful to have additional data in transition events.

@Nyholm
Copy link
Member

Nyholm commented Aug 30, 2018

Is anyone willing to provide a PR for this feature?

@Padam87
Copy link
Contributor

Padam87 commented Aug 30, 2018

Did it already. Just needs a touch up, and ready to go if it gets the go ahead.

(The PR was for 3.2, and the $context argument name is much better than what I used.)

#20789

@walva
Copy link
Contributor

walva commented Oct 4, 2018

+1
I'm facing many cases where I miss this feature.

Here is an example:

Let's take an auction as exemple described in workflow.yaml below. The auction is simple, user can create an auction but only an admin can start the auction. After that, each user can bid only one to an auction. Also, to be able to bid, you must have an active membership. pretty simple business logic.

framework:
    workflows:
        auction:
            type: state_machine
            marking_store:
                type: single_state
                arguments:
                    - status
            supports:
                - App\Entity\Auction
            places:
                - draft
                - started
                - ended
            transitions:
                start:
                    from: draft
                    to:     submitted
                    metadata:
                        roles: [ROLE_ADMIN, ROLE_SUPERADMIN]
                make_an_offer:
                    from: started
                    to:     started
                    metadata:
                        roles: [ROLE_USER]

Thanks to the metadata, I can specify which role is required to start an auction. Fine it as been put in place.
Secondly, I would like to validate that a user can "make an offer". For that, I will use the method Workflow::can($auction, 'make_an_offer', ['user' => $user]) .
From there, I can create a guard that will check if that current user already bid or not on the auction.
I really miss this feature and any alternative seems to be so expensive so far. Still thinking about alternatives.

lyrixx added a commit that referenced this issue Mar 6, 2019
…ixx)

This PR was merged into the 4.3-dev branch.

Discussion
----------

[Workflow] Added a context to `Workflow::apply()`

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #27925 (maybe #28253 and #28266)
| License       | MIT
| Doc PR        |

Commits
-------

7d5b7a3 [Workflow] Added a context to `Workflow::apply()`
@lyrixx
Copy link
Member

lyrixx commented Mar 6, 2019

#29146 is now merged. You can test it and give me some feedback. Thanks

@lyrixx lyrixx closed this as completed Mar 6, 2019
@walva
Copy link
Contributor

walva commented Aug 9, 2019

@lyrixx do you still need help on this? Do you have any advice on how to test this?

@lyrixx
Copy link
Member

lyrixx commented Aug 9, 2019

It's in symfony 4.3 😁 everything works fine. Thanks

@brizzz
Copy link
Contributor

brizzz commented Oct 8, 2019

@SulivanDotEu you can handle your use case using custom Security Voter and 'guard' property of transition. Like that:

...
            transitions:
                start:
                    guard: "is_granted('ROLE_ADMIN', subject) or is_granted('ROLE_SUPERADMIN', subject)"
                    from: draft
                    to:     submitted
                make_an_offer:
                    guard: "is_granted('ALLOW_TO_BID', subject)"
                    from: started
                    to:     started

ALLOW_TO_BID - is your custom security voter where you can check if the current user have rights to create a new bid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC RFC = Request For Comments (proposals about features that you want to be discussed) Workflow
Projects
None yet
Development

No branches or pull requests

10 participants