@@ -502,6 +502,226 @@ when needed and vice-versa when working with your objects::
502502 // ...
503503 };
504504
505+ Using Weighted Transitions
506+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
507+
508+ Weighted transitions allow you to define transitions where multiple tokens (instances)
509+ are consumed from or produced to places. This is useful for modeling complex workflows
510+ such as manufacturing processes, resource allocation, or any scenario where multiple
511+ instances of something need to be produced or consumed.
512+
513+ ..versionadded ::7.4
514+
515+ The support for weighted transitions was introduced in Symfony 7.4.
516+
517+ For example, imagine a table-making workflow where you need to create 4 legs, 1 top,
518+ and track the process with a stopwatch. You can use weighted transitions to model this:
519+
520+ ..configuration-block ::
521+
522+ ..code-block ::yaml
523+
524+ # config/packages/workflow.yaml
525+ framework :
526+ workflows :
527+ make_table :
528+ type :' workflow'
529+ marking_store :
530+ type :' method'
531+ property :' marking'
532+ supports :
533+ -App\Entity\TableProject
534+ initial_marking :init
535+ places :
536+ -init
537+ -prepare_leg
538+ -prepare_top
539+ -stopwatch_running
540+ -leg_created
541+ -top_created
542+ -finished
543+ transitions :
544+ start :
545+ from :init
546+ to :
547+ -place :prepare_leg
548+ weight :4
549+ -place :prepare_top
550+ weight :1
551+ -place :stopwatch_running
552+ weight :1
553+ build_leg :
554+ from :prepare_leg
555+ to :leg_created
556+ build_top :
557+ from :prepare_top
558+ to :top_created
559+ join :
560+ from :
561+ -place :leg_created
562+ weight :4
563+ -top_created # weight defaults to 1
564+ -stopwatch_running
565+ to :finished
566+
567+ ..code-block ::xml
568+
569+ <!-- config/packages/workflow.xml-->
570+ <?xml version =" 1.0" encoding =" UTF-8" ?>
571+ <container xmlns =" http://symfony.com/schema/dic/services"
572+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
573+ xmlns : framework =" http://symfony.com/schema/dic/symfony"
574+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
575+ https://symfony.com/schema/dic/services/services-1.0.xsd
576+ http://symfony.com/schema/dic/symfony
577+ https://symfony.com/schema/dic/symfony/symfony-1.0.xsd" >
578+
579+ <framework : config >
580+ <framework : workflow name =" make_table" type =" workflow" >
581+ <framework : marking-store type =" method" >
582+ <framework : argument >marking</framework : argument >
583+ </framework : marking-store >
584+ <framework : support >App\Entity\TableProject</framework : support >
585+ <framework : initial-marking >init</framework : initial-marking >
586+
587+ <framework : place >init</framework : place >
588+ <framework : place >prepare_leg</framework : place >
589+ <framework : place >prepare_top</framework : place >
590+ <framework : place >stopwatch_running</framework : place >
591+ <framework : place >leg_created</framework : place >
592+ <framework : place >top_created</framework : place >
593+ <framework : place >finished</framework : place >
594+
595+ <framework : transition name =" start" >
596+ <framework : from >init</framework : from >
597+ <framework : to weight =" 4" >prepare_leg</framework : to >
598+ <framework : to weight =" 1" >prepare_top</framework : to >
599+ <framework : to weight =" 1" >stopwatch_running</framework : to >
600+ </framework : transition >
601+ <framework : transition name =" build_leg" >
602+ <framework : from >prepare_leg</framework : from >
603+ <framework : to >leg_created</framework : to >
604+ </framework : transition >
605+ <framework : transition name =" build_top" >
606+ <framework : from >prepare_top</framework : from >
607+ <framework : to >top_created</framework : to >
608+ </framework : transition >
609+ <framework : transition name =" join" >
610+ <framework : from weight =" 4" >leg_created</framework : from >
611+ <framework : from >top_created</framework : from >
612+ <framework : from >stopwatch_running</framework : from >
613+ <framework : to >finished</framework : to >
614+ </framework : transition >
615+ </framework : workflow >
616+ </framework : config >
617+ </container >
618+
619+ ..code-block ::php
620+
621+ // config/packages/workflow.php
622+ use App\Entity\TableProject;
623+ use Symfony\Config\FrameworkConfig;
624+
625+ return static function (FrameworkConfig $framework): void {
626+ $makeTable = $framework->workflows()->workflows('make_table');
627+ $makeTable
628+ ->type('workflow')
629+ ->supports([TableProject::class])
630+ ->initialMarking(['init']);
631+
632+ $makeTable->markingStore()
633+ ->type('method')
634+ ->property('marking');
635+
636+ $makeTable->place()->name('init');
637+ $makeTable->place()->name('prepare_leg');
638+ $makeTable->place()->name('prepare_top');
639+ $makeTable->place()->name('stopwatch_running');
640+ $makeTable->place()->name('leg_created');
641+ $makeTable->place()->name('top_created');
642+ $makeTable->place()->name('finished');
643+
644+ $makeTable->transition()
645+ ->name('start')
646+ ->from(['init'])
647+ ->to([
648+ ['place' => 'prepare_leg', 'weight' => 4],
649+ ['place' => 'prepare_top', 'weight' => 1],
650+ ['place' => 'stopwatch_running', 'weight' => 1],
651+ ]);
652+
653+ $makeTable->transition()
654+ ->name('build_leg')
655+ ->from(['prepare_leg'])
656+ ->to(['leg_created']);
657+
658+ $makeTable->transition()
659+ ->name('build_top')
660+ ->from(['prepare_top'])
661+ ->to(['top_created']);
662+
663+ $makeTable->transition()
664+ ->name('join')
665+ ->from([
666+ ['place' => 'leg_created', 'weight' => 4],
667+ 'top_created', // weight defaults to 1
668+ 'stopwatch_running',
669+ ])
670+ ->to(['finished']);
671+ };
672+
673+ In this example, when the ``start `` transition is applied, it creates 4 tokens in
674+ the ``prepare_leg `` place, 1 token in ``prepare_top ``, and 1 token in
675+ ``stopwatch_running ``. Then, the ``build_leg `` transition must be applied 4 times
676+ (once for each token), and the ``build_top `` transition once. Finally, the ``join ``
677+ transition can only be applied when all 4 legs are created, the top is created,
678+ and the stopwatch is still running.
679+
680+ Weighted transitions can also be defined programmatically using the
681+ :class: `Symfony\\ Component\\ Workflow\\ Arc ` class::
682+
683+ use Symfony\Component\Workflow\Arc;
684+ use Symfony\Component\Workflow\Definition;
685+ use Symfony\Component\Workflow\Transition;
686+ use Symfony\Component\Workflow\Workflow;
687+
688+ $definition = new Definition(
689+ ['init', 'prepare_leg', 'prepare_top', 'stopwatch_running', 'leg_created', 'top_created', 'finished'],
690+ [
691+ new Transition('start', 'init', [
692+ new Arc('prepare_leg', 4),
693+ new Arc('prepare_top', 1),
694+ 'stopwatch_running', // defaults to weight 1
695+ ]),
696+ new Transition('build_leg', 'prepare_leg', 'leg_created'),
697+ new Transition('build_top', 'prepare_top', 'top_created'),
698+ new Transition('join', [
699+ new Arc('leg_created', 4),
700+ 'top_created',
701+ 'stopwatch_running',
702+ ], 'finished'),
703+ ]
704+ );
705+
706+ $workflow = new Workflow($definition);
707+ $workflow->apply($subject, 'start');
708+
709+ // Build each leg (4 times)
710+ $workflow->apply($subject, 'build_leg');
711+ $workflow->apply($subject, 'build_leg');
712+ $workflow->apply($subject, 'build_leg');
713+ $workflow->apply($subject, 'build_leg');
714+
715+ // Build the top
716+ $workflow->apply($subject, 'build_top');
717+
718+ // Now we can join all parts
719+ $workflow->apply($subject, 'join');
720+
721+ The ``Arc `` class takes two parameters: the place name and the weight (which must be
722+ greater than or equal to 1). When a place is specified as a simple string instead of
723+ an ``Arc `` object, it defaults to a weight of 1.
724+
505725Using a multiple state marking store
506726~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
507727