yokai-php / sonata-workflow

Integrate Symfony workflow component in Sonata Admin
MIT License
22 stars 11 forks source link

Workflow and inherited entities #3

Closed danaki closed 6 years ago

danaki commented 6 years ago

Hello, I'm getting "An exception has been thrown during the rendering of a template ("unable to find the route admin.verification.workflow_apply_transition")." and I believe this is sonata-workflow's issue. Here's my setup:

I have an abstract entity:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="verification")
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="verification_type", type="string")
 * @ORM\DiscriminatorMap({"personal"="PersonalVerification", "address"="AddressVerification"})
 */
abstract class Verification
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=100, nullable=false, unique=true)
     */
    private $status;
}

and two inherited entities PersonalVerification and AddressVerification.

/**
 * @ORM\Table(name="verification_personal")
 * @ORM\Entity
 */
class PersonalVerification extends Verification
{
    // ...
}

/**
 * @ORM\Table(name="verification_address")
 * @ORM\Entity()
 */
class AddressVerification extends Verification
{
    // ...
}

My worflow.yaml looks like this:

framework:
    workflows:
        verification_state:
            type: 'state_machine'
            places:
                - unverified
                - verified
                - rejected
            initial_place: unverified
            marking_store:
                type: "single_state"
                arguments: ['status']
            supports:
                - App\Entity\Verification
            transitions:
                accept:
                    from: unverified
                    to: verified
                reject:
                    from: unverified
                    to: rejected

My sonata_admin.yaml looks like:

services:
    admin.verification:
        class: App\Admin\VerificationAdmin
        arguments: [~, App\Entity\Verification, Yokai\SonataWorkflow\Controller\WorkflowController]
        tags:
            - { name: sonata.admin, manager_type: orm, label: 'Verifications' }
        public: true
        calls:
            - [setSubclasses, [{'Personal': App\Entity\PersonalVerification, 'Address': App\Entity\AddressVerification}]]

    admin.extension.verification_state_workflow:
        class: Yokai\SonataWorkflow\Admin\Extension\WorkflowExtension
        public: true
        arguments:
            - "@workflow.registry"
            - workflow_name: verification_state

    Yokai\SonataWorkflow\Controller\WorkflowController:
        autowire: true
        tags: ['controller.service_arguments']

sonata_admin:
    extensions:
        admin.extension.verification_state_workflow:
            admins:
                - admin.verification

I tried to change workflow's "supports" section to:

            supports:
                - App\Entity\PersonalVerification
                - App\Entity\AddressVerification

It results to successful render of "edit" page but without "transition" dropdown (seems like due to an exception in WorkflowExtension::configureSideMenu() inside getWorkflow() call which is dropped silently). Anyway I think

            supports:
                - App\Entity\Verification

more correct in this case, because "status" is the state property of the base class.

Thank you.

yann-eugone commented 6 years ago

Hello ! Thank you for using this bundle.

I never tried using this extension with inheritance & admin subclasses.

Maybe we can try to get some more information :

danaki commented 6 years ago
yann-eugone commented 6 years ago

Just tried it myself, i have no issue with it.

In src/Entity/Verification.php

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="verification")
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="verification_type", type="string")
 * @ORM\DiscriminatorMap({"personal"="PersonalVerification", "address"="AddressVerification"})
 */
abstract class Verification
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;
    /**
     * @ORM\Column(type="string", length=100, nullable=false, unique=true)
     */
    private $status;
    public function getId()
    {
        return $this->id;
    }
    public function getStatus()
    {
        return $this->status;
    }
    public function setStatus($status): void
    {
        $this->status = $status;
    }
}

In src/Entity/AddressVerification.php

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="verification_address")
 * @ORM\Entity
 */
class AddressVerification extends Verification
{
}

In src/Entity/PersonalVerification.php

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="verification_personal")
 * @ORM\Entity
 */
class PersonalVerification extends Verification
{
}

In src/Admin/VerificationAdmin.php

<?php

namespace App\Admin;

use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Route\RouteCollection;

class VerificationAdmin extends AbstractAdmin
{
    protected function configureRoutes(RouteCollection $collection)
    {
        $collection
            ->remove('create')
            ->remove('delete')
        ;
    }
    protected function configureListFields(ListMapper $list)
    {
        $list
            ->addIdentifier('id')
            ->add('status')
        ;
    }
    protected function configureFormFields(FormMapper $form)
    {
        $form
            ->add('status')
        ;
    }
}

In config/packages/sonata_admin.yaml

sonata_admin:
    extensions:
        admin.extension.workflow:
            admins:
                - admin.verification

services:
    admin.verification:
        class: App\Admin\VerificationAdmin
        arguments: [~, App\Entity\Verification, Yokai\SonataWorkflow\Controller\WorkflowController]
        tags:
            - { name: sonata.admin, manager_type: orm, label: 'Verifications' }
        public: true
        calls:
            - [setSubclasses, [{'Personal': App\Entity\PersonalVerification, 'Address': App\Entity\AddressVerification}]]

    admin.extension.workflow:
        class: Yokai\SonataWorkflow\Admin\Extension\WorkflowExtension
        public: true
        arguments:
            - '@workflow.registry'

    Yokai\SonataWorkflow\Controller\WorkflowController:
        autowire: true
        tags: ['controller.service_arguments']

In config/packages/workflow.yaml

framework:
    workflows:
        verification_state:
            type: 'state_machine'
            places:
                - unverified
                - verified
                - rejected
            initial_place: unverified
            marking_store:
                type: "single_state"
                arguments: ['status']
            supports:
                - App\Entity\Verification
            transitions:
                accept:
                    from: unverified
                    to: verified
                reject:
                    from: unverified
                    to: rejected

And the result :

capture d ecran_2018-09-05_11-47-33

danaki commented 6 years ago

Ok, give me time I'll check if I missed something.

danaki commented 6 years ago

Oops, try to add similar method to your Admin class, may be that's the issue?

    protected function configureFormFields(FormMapper $formMapper)
    {
        $subject = $this->getSubject();

        $formMapper
            ->add('status', null, ['disabled' => true])
            ->add('user.email', null, ['disabled' => true])
        ;

        if ($subject instanceof PersonalVerification) {
            $formMapper
                ->add('firstname')
                ->add('lastname')
                ->add('birthday')
            ;
        } elseif ($subject instanceof AddressVerification) {
            $formMapper
                ->add('street')
                ->add('city')
                ->add('country', CountryType::class)
                ->add('zip')
                ->add('state')
            ;
        }
    }
yann-eugone commented 6 years ago

I don't think that this code may break something.

danaki commented 6 years ago

Not sure what happened, probably the issue has gone after composer update while I was preparing a repo to demonstrate the bug.