Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Version Workflow Bundle Laravel Package

coosos/version-workflow-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the bundle to your composer.json:

    composer require coosos/version-workflow-bundle
    

    Enable it in config/bundles.php:

    return [
        // ...
        Coosos\VersionWorkflowBundle\CoososVersionWorkflowBundle::class => ['all' => true],
    ];
    
  2. Basic Configuration Define a workflow in config/packages/coosos_version_workflow.yaml:

    coosos_version_workflow:
        workflows:
            my_workflow:
                type: 'state_machine'
                marking_store:
                    type: 'method'
                    method: 'getStatus'
                supports:
                    - 'App\Entity\MyEntity'
                initial_marking: 'draft'
                places: ['draft', 'published', 'archived']
                transitions:
                    publish:
                        from: 'draft'
                        to: 'published'
                    archive:
                        from: 'published'
                        to: 'archived'
    
  3. First Use Case Apply the workflow to an entity by adding the VersionableInterface trait:

    use Coosos\VersionWorkflowBundle\Model\VersionableInterface;
    use Coosos\VersionWorkflowBundle\Model\VersionableTrait;
    
    class MyEntity implements VersionableInterface
    {
        use VersionableTrait;
    
        // ...
    }
    

    Trigger a transition in a controller:

    use Coosos\VersionWorkflowBundle\Workflow\WorkflowService;
    
    public function publish(MyEntity $entity, WorkflowService $workflowService)
    {
        $workflowService->apply($entity, 'publish');
    }
    

Implementation Patterns

Workflow Integration

  1. Entity Versioning Workflow Use the bundle to track state transitions (e.g., draftpublishedarchived) while preserving SEO by merging final states into the original table.

    // Apply transition
    $workflowService->apply($entity, 'publish');
    
    // Check current state
    $state = $workflowService->getMarking($entity);
    
  2. Doctrine Integration Extend the bundle’s VersionableTrait to handle versioned entities:

    class MyEntity extends BaseEntity implements VersionableInterface
    {
        use VersionableTrait;
    
        #[ORM\Column]
        private ?string $status = 'draft';
    
        public function getStatus(): string
        {
            return $this->status;
        }
    }
    
  3. Serialization Leverage JMS Serializer to handle versioned entities in APIs:

    # config/packages/jms_serializer.yaml
    jms_serializer:
        metadata:
            directories:
                App:
                    namespace_prefix: "App\\Serializer"
                    path: "%kernel.project_dir%/config/serializer"
    

    Create a custom serializer context for versioned entities:

    // src/Serializer/VersionedEntityHandler.php
    use Coosos\VersionWorkflowBundle\Model\VersionableInterface;
    
    class VersionedEntityHandler extends AbstractHandler
    {
        public function serialize($data, SerializationContext $context)
        {
            if ($data instanceof VersionableInterface) {
                $context->addGroups(['versioned']);
            }
        }
    }
    
  4. Event-Driven Transitions Use Symfony events to trigger workflows:

    // src/EventListener/WorkflowTransitionListener.php
    class WorkflowTransitionListener
    {
        public function onPrePersist(MyEntity $entity, WorkflowService $workflowService)
        {
            if ($entity->isVersioned()) {
                $workflowService->apply($entity, 'publish');
            }
        }
    }
    

Gotchas and Tips

Pitfalls

  1. State Machine vs. Workflow The bundle defaults to state_machine but may require method_marking_store for dynamic states. Ensure your marking_store config matches your entity’s state retrieval logic:

    marking_store:
        type: 'method'
        method: 'getCustomStatusMethod'  # Must exist in your entity
    
  2. SEO Merging Quirks The "merge into original table" feature assumes a merge() method exists in your entity. Override it to handle custom logic:

    public function merge(VersionedEntity $versionedEntity)
    {
        $this->status = $versionedEntity->getStatus();
        $this->content = $versionedEntity->getContent();
    }
    
  3. Doctrine Proxy Issues If using proxies, ensure lazy-loaded properties (e.g., status) are accessible during workflow checks. Add @ORM\HasLifecycleCallbacks and initialize properties in preLoad():

    #[ORM\HasLifecycleCallbacks]
    class MyEntity
    {
        #[ORM\PreLoad]
        public function initializeStatus()
        {
            if (null === $this->status) {
                $this->status = 'draft';
            }
        }
    }
    
  4. Transition Validation Validate transitions before applying them to avoid silent failures:

    if (!$workflowService->can($entity, 'publish')) {
        throw new \RuntimeException('Cannot publish entity: invalid state');
    }
    

Debugging Tips

  1. Workflow Dump Use the WorkflowService to debug states:

    $workflow = $workflowService->getWorkflow('my_workflow');
    dump($workflow->getEnabledTransitions($entity));
    
  2. Symfony Profiler Enable the workflow panel in the profiler to inspect active workflows and transitions.

  3. Logging Log workflow events for auditing:

    $logger->info('Transition applied', [
        'entity' => $entity->getId(),
        'transition' => 'publish',
        'from' => $workflowService->getMarking($entity),
    ]);
    

Extension Points

  1. Custom Marking Stores Extend MethodMarkingStore to support non-Doctrine entities or custom logic:

    class CustomMarkingStore extends MethodMarkingStore
    {
        protected function getMarkingValue($entity)
        {
            return $entity->getCustomState(); // Your logic
        }
    }
    
  2. Post-Merge Hooks Add callbacks after merging versioned entities into the original:

    // src/EventSubscriber/PostMergeSubscriber.php
    class PostMergeSubscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents()
        {
            return [
                'coosos.version_workflow.post_merge' => 'onPostMerge',
            ];
        }
    
        public function onPostMerge(PostMergeEvent $event)
        {
            $event->getOriginalEntity()->updateSeoMetadata();
        }
    }
    
  3. Async Transitions Use Symfony Messenger to decouple workflow transitions from requests:

    $message = new ApplyWorkflowTransitionMessage($entity->getId(), 'publish');
    $bus->dispatch($message);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor