Search code examples
symfonysymfony4symfony-workflows

Symfony Workflow - Is it possible to use doctrine relation as state holder?


I am trying to adopt the Symfony workflow component to my app.

As documentation says marking_store points to string. I was googling for it - it can be a string or json_array-field of a Doctrine entity.

But what if I have an Entity BlogPost with a relation BlogPostStatus that have two fields: some primary id and statusName. Can I configure the workflow component to change statuses of my BlogPost (i.e set new BlogPostStatus to BlogPost entity) and persist it to database?

Now I have only one solution: Add to my BlogPost entity non-mapped field and when it's changed change status of Entity.

Do you have a better solution?


Solution

  • For all built-in marking_store implementations the following is true:

    If the functions setMarking or getMarking exist on the object holding the state, they will be used to set or get the marking respectively.

    There are 3 built-in marking stores, the SingleStateMarkingStore (using the property accessor, hence setMarking/getMarking), the MultiStateMarkingStore (same), the MethodMarkingStore (explicitly calling those functions, you can change the function via the property setting of your marking_store config).

    The difference lies within the argument provided in the setMarking call, for single state (this is the state_machine type, and by default NOT the the workflow type), the argument is the place (or state) where the mark is placed. For multi state (workflow type by default), the argument is an array where the keys are places and the values are marks, usually the marks are 1, and empty places are omitted.

    So, I'll assume that your BlogPost (currently) only has a single state at any given time, and what you have to do now is to transform the marking given into the status entity - I will assume your workflow has type state_machine:

    /** in class BlogPost */
    public function setMarking(string $marking/*, array $context*/) {
        $this->status->statusName = $marking;
    }
    
    public function getMarking() {
        return $this->status->statusName;
    }
    

    special cases

    If the BlogPostStatus should be a different one (for example, a constant object), then you'd have to use the new interface that dbrumann linked, and hook into the event to add that to the context.

    If the BlogPostStatus may not exist at the time of the setMarking/getMarking, you have to create it on the fly in the setter and check for it in the getter. But I'm sure you're capable of doing that ;o)

    Also if you're not using the single state workflows but multi state instead, you have to find a way to transform the array of (places->marks) into your status object and vice versa.