Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add BackedEnums support in Symfony Workflow Marking Store #54582

Closed as not planned
@Caroga

Description

@Caroga

Symfony version(s) affected

7.0.x

Description

Configure a backed enum as enumType on your doctrine entity together with the workflow component throws a "unable to convert to string"-error when retrieving the enabled transitions.

How to reproduce

Create a backed enum:

enum CustomerStatus: string
{
    case New = 'new';
    case AccountActive = 'account_active';
    case AccountActivationExpired = 'account_activation_expired';
    case AccountDeletedByCustomer = 'account_deleted_by_customer';
    case AccountDisabledByAdmin = 'account_disabled_by_admin';
    case AccountDeletedByAdmin = 'account_deleted_by_admin';
}

Create an entity and use the enum above as enumType:

 #[ORM\Column(type: 'string', length: 255, enumType: CustomerStatus::class)]
    private CustomerStatus $status;

    public function getStatus(): CustomerStatus
    {
        return $this->status;
    }

    public function setStatus(CustomerStatus $status): static
    {
        $this->status = $status;

        return $this;
    }

Configure the following workflow:

framework:
  workflows:
    customer:
      type: 'state_machine'
      marking_store:
        type: 'method'
        property: 'status'
      initial_marking: 'new'
      supports:
        - 'App\Entity\Customer'
      places:
        new: ~
        account_active:
        account_activation_expired:
        account_deleted_by_customer:
        account_disabled_by_admin:
        account_deleted_by_admin:
      transitions:
        activate:
          from: [ 'new', 'account_disabled_by_admin' ]
          to: 'account_active'
          guard: "is_granted('ROLE_ADMIN')"
        activation_expires:
          from: 'new'
          to: 'account_activation_expired'
          guard: "is_granted('ROLE_ADMIN')"
        delete_by_customer:
          from: [ 'new', 'account_active' ]
          to: 'account_deleted_by_customer'
          guard: "is_granted('ROLE_CUSTOMER')"
        disable_by_admin:
          from: [ 'new', 'account_active' ]
          to: 'account_disabled_by_admin'
          guard: "is_granted('ROLE_ADMIN')"
        delete_by_admin:
          from: [ 'new', 'account_active' ]
          to: 'account_deleted_by_admin'
          guard: "is_granted('ROLE_ADMIN')"

Retrieve the enabled transitions using the workflow component:

 public function __construct(private WorkflowInterface $customerStateMachine)
    {}

public function something() 
{
    $this->customerStateMachine->getEnabledTransitions(new Customer()); // throws error
}

Will throw the following error:

Object of class App\Enum\CustomerStatus could not be converted to string

Possible Solution

in vendor/symfony/workflow/MarkingStore/MethodMarkingStore.php:67

if ($this->singleState) {
    $marking = [(string) $marking => 1]; // throws error due to explicit cast to string
} elseif (!\is_array($marking)) {
    throw new LogicException(sprintf('The marking stored in "%s::$%s" is not an array and the Workflow\'s Marking store is instantiated with $singleState=false.', get_debug_type($subject), $this->property));
}

Check if type is backed enum, get value and set as string:

if ($this->singleState) {
    if ($marking instanceof \BackedEnum){
        $marking = $marking->value;
    }
    $marking = [(string) $marking => 1];
} elseif (!\is_array($marking)) {
    throw new LogicException(sprintf('The marking stored in "%s::$%s" is not an array and the Workflow\'s Marking store is instantiated with $singleState=false.', get_debug_type($subject), $this->property));
}

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions