PHP code example of wol-soft / php-workflow

1. Go to this page and download the library: Download wol-soft/php-workflow library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

wol-soft / php-workflow example snippets


$workflowResult = (new \PHPWorkflow\Workflow('AddSongToPlaylist'))
    ->validate(new CurrentUserIsAllowedToEditPlaylistValidator())
    ->validate(new PlaylistAlreadyContainsSongValidator())
    ->before(new AcceptOpenSuggestionForSong())
    ->process(new AddSongToPlaylist())
    ->onSuccess(new NotifySubscribers())
    ->onSuccess(new AddPlaylistLogEntry())
    ->onSuccess(new UpdateLastAddedToPlaylists())
    ->onError(new RecoverLog())
    ->executeWorkflow();

class AcceptOpenSuggestionForSong implements \PHPWorkflow\Step\WorkflowStep {
    /**
     * Each step must provide a description. The description will be used in the debug
     * log of the workflow to get a readable representation of an executed workflow 
     */
    public function getDescription(): string
    {
        return 'Accept open suggestions for songs which shall be added to a playlist';
    }

    /**
     * Each step will get access to two objects to interact with the workflow.
     * First the WorkflowControl object $control which provides methods to skip
     * steps, mark tests as failed, add debug information etc.
     * Second the WorkflowContainer object $container which allows us to get access
     * to various workflow related objects.
     */
    public function run(
        \PHPWorkflow\WorkflowControl $control,
        \PHPWorkflow\State\WorkflowContainer $container
    ) {
        $openSuggestions = (new SuggestionRepository())
            ->getOpenSuggestionsByPlaylistId($container->get('playlist')->getId());

        // If we detect a condition which makes a further execution of the step
        // unnecessary we can simply skip the further execution.
        // By providing a meaningful reason our workflow debug log will be helpful.
        if (empty($openSuggestions)) {
            $control->skipStep('No open suggestions for playlist');
        }

        foreach ($openSuggestions as $suggestion) {
            if ($suggestion->getSongId() === $container->get('song')->getId()) {
                if ((new SuggestionService())->acceptSuggestion($suggestion)) {
                    // If we detect a condition where the further workflow execution is
                    // unnecessary we can skip the further execution.
                    // In this example the open suggestion was accepted successfully so
                    // the song must not be added to the playlist via the workflow.
                    $control->skipWorkflow('Accepted open suggestion');
                }

                // We can add warnings to the debug log. Another option in this case could
                // be to call $control->failWorkflow() if we want the workflow to fail in
                // an error case.
                // In our example, if the suggestion can't be accepted, we want to add the
                // song to the playlist via the workflow.
                $control->warning("Failed to accept open suggestion {$suggestion->getId()}");
            }
        }

        // for completing the debug log we mark this step as skipped if no action has been
        // performed. If we don't mark the step as skipped and no action has been performed
        // the step will occur as 'ok' in the debug log - depends on your preferences :)
        $control->skipStep('No matching open suggestion');
    }
}

$workflowContainer = (new \PHPWorkflow\State\WorkflowContainer())
    ->set('user', Session::getUser())
    ->set('song', (new SongRepository())->getSongById($request->get('songId')))
    ->set('playlist', (new PlaylistRepository())->getPlaylistById($request->get('playlistId')));

// returns an item or null if the key doesn't exist
public function get(string $key)
// set or update a value
public function set(string $key, $value): self
// remove an entry
public function unset(string $key): self
// check if a key exists
public function has(string $key): bool

class AddSongToPlaylistWorkflowContainer extends \PHPWorkflow\State\WorkflowContainer {
    public function __construct(
        public User $user,
        public Song $song,
        public Playlist $playlist,
    ) {}
}

$workflowContainer = new AddSongToPlaylistWorkflowContainer(
    Session::getUser(),
    (new SongRepository())->getSongById($request->get('songId')),
    (new PlaylistRepository())->getPlaylistById($request->get('playlistId')),
);

$workflowResult = (new \PHPWorkflow\Workflow('AddSongToPlaylist'))
    // ...
    ->executeWorkflow($workflowContainer);


$workflowResult = (new \PHPWorkflow\Workflow('AddSongToPlaylist'))
    // hard validator: if the user isn't allowed to edit the playlist
    // the workflow execution will be cancelled immediately
    ->validate(new CurrentUserIsAllowedToEditPlaylistValidator(), true)
    // soft validators: all validators will be executed
    ->validate(new PlaylistAlreadyContainsSongValidator())
    ->validate(new SongGenreMatchesPlaylistGenreValidator())
    ->validate(new PlaylistContainsNoSongsFromInterpret())
    // ...

// Mark the current step as skipped.
// Use this if you detect, that the step execution is not necessary
// (e.g. disabled by config, no entity to process, ...)
public function skipStep(string $reason): void;

// Mark the current step as failed. A failed step before and during the processing of
// a workflow leads to a failed workflow.
public function failStep(string $reason): void;

// Mark the workflow as failed. If the workflow is failed after the process stage has
// been executed it's handled like a failed step.
public function failWorkflow(string $reason): void;

// Skip the further workflow execution (e.g. if you detect it's not necessary to process
// the workflow). If the workflow is skipped after the process stage has been executed
// it's handled like a skipped step.
public function skipWorkflow(string $reason): void;

// Useful when using loops to cancel the current iteration (all upcoming steps).
// If used outside a loop, it behaves like skipStep.
public function continue(string $reason): void;

// Useful when using loops to break the loop (all upcoming steps and iterations).
// If used outside a loop, it behaves like skipStep.
public function break(string $reason): void;

// Attach any additional debug info to your current step.
// The infos will be shown in the workflow debug log.
public function attachStepInfo(string $info): void

// Add a warning to the workflow.
// All warnings will be collected and shown in the workflow debug log.
// You can provide an additional exception which caused the warning.
// If you provide the exception, exception details will be added to the debug log.
public function warning(string $message, ?Exception $exception = null): void;

$parentWorkflowContainer = (new \PHPWorkflow\State\WorkflowContainer())->set('parent-data', 'Hello');
$nestedWorkflowContainer = (new \PHPWorkflow\State\WorkflowContainer())->set('nested-data', 'World');

$workflowResult = (new \PHPWorkflow\Workflow('AddSongToPlaylist'))
    ->validate(new CurrentUserIsAllowedToEditPlaylistValidator())
    ->before(new \PHPWorkflow\Step\NestedWorkflow(
        (new \PHPWorkflow\Workflow('AcceptOpenSuggestions'))
            ->validate(new PlaylistAcceptsSuggestionsValidator())
            ->before(new LoadOpenSuggestions())
            ->process(new AcceptOpenSuggestions())
            ->onSuccess(new NotifySuggestor()),
        $nestedWorkflowContainer,
    ))
    ->process(new AddSongToPlaylist())
    ->onSuccess(new NotifySubscribers())
    ->executeWorkflow($parentWorkflowContainer);

$workflowResult = (new \PHPWorkflow\Workflow('AddSongToPlaylist'))
    ->validate(new CurrentUserIsAllowedToEditPlaylistValidator())
    ->process(
        (new \PHPWorkflow\Step\Loop(new SongLoop()))
            ->addStep(new AddSongToPlaylist())
            ->addStep(new ClearSongCache())
    )
    ->onSuccess(new NotifySubscribers())
    ->executeWorkflow($workflowContainer);

class SongLoop implements \PHPWorkflow\Step\LoopControl {
    /**
     * As well as each step also each loop must provide a description.
     */
    public function getDescription(): string
    {
        return 'Loop over all provided songs';
    }

    /**
     * This method will be called before each loop run.
     * $iteration will contain the current iteration (0 on first run etc)
     * You have access to the WorkflowControl and the WorkflowContainer.
     * If the method returns true the next iteration will be executed.
     * Otherwise the loop is completed.
     */
    public function executeNextIteration(
        int $iteration,
        \PHPWorkflow\WorkflowControl $control,
        \PHPWorkflow\State\WorkflowContainer $container
    ): bool {
        // all songs handled - end the loop
        if ($iteration === count($container->get('songs'))) {
            return false;
        }

        // add the current song to the container so the steps
        // of the loop can access the entry
        $container->set('currentSong', $container->get('songs')[$iteration]);

        return true;
    }
}

public function run(
    \PHPWorkflow\WorkflowControl $control,
    // The key customerId must contain a string
    #[\PHPWorkflow\Step\Dependency\Required('customerId', 'string')]
    // The customerAge must contain an integer. But also null is accepted.
    // Each type definition can be prefixed with a ? to accept null.
    #[\PHPWorkflow\Step\Dependency\Required('customerAge', '?int')]
    // Objects can also be type hinted
    #[\PHPWorkflow\Step\Dependency\Required('created', \DateTime::class)]
    \PHPWorkflow\State\WorkflowContainer $container,
) {
    // Implementation which can rely on the defined keys to be present in the container.
}

// check if the workflow execution was successful
public function success(): bool;
// check if warnings were emitted during the workflow execution
public function hasWarnings(): bool;
// get a list of warnings, grouped by stage
public function getWarnings(): array;
// get the exception which caused the workflow to fail
public function getException(): ?Exception;
// get the debug execution log of the workflow
public function debug(?OutputFormat $formatter = null);
// access the container which was used for the workflow
public function getContainer(): WorkflowContainer;
// get the last executed step
// (e.g. useful to determine which step caused a workflow to fail)
public function getLastStep(): WorkflowStep;

// assert the debug output of the workflow. See library tests for example usages
protected function assertDebugLog(string $expected, WorkflowResult $result): void
// provide a step which you expect to fail the workflow.
// example: $this->expectFailAtStep(MyFailingStep::class, $workflowResult);
protected function expectFailAtStep(string $step, WorkflowResult $result): void
// provide a step which you expect to skip the workflow.
// example: $this->expectSkipAtStep(MySkippingStep::class, $workflowResult);
protected function expectSkipAtStep(string $step, WorkflowResult $result): void

[
    'firstname' => string,
    'lastname' => string,
    'age' => int,
]

$ composer