Download the PHP package asantibanez/laravel-eloquent-state-machines without Composer
On this page you can find all versions of the php package asantibanez/laravel-eloquent-state-machines. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download asantibanez/laravel-eloquent-state-machines
More information about asantibanez/laravel-eloquent-state-machines
Files in asantibanez/laravel-eloquent-state-machines
Package laravel-eloquent-state-machines
Short Description State machines for your Laravel Eloquent models
License MIT
Homepage https://github.com/asantibanez/laravel-eloquent-state-machines
Informations about the package laravel-eloquent-state-machines
Introduction
This package allows you to simplify the transitioning of states an Eloquent model could have by defining the transition logic in specific StateMachine classes. Each class allows you to register validations, hooks and allowed transitions and states making each StateMachine class the only source of truth when moving from a state to the next.
Laravel Eloquent State Machines also allow you to automatically record history of all states a model may have and query this history to take specific actions accordingly.
At its core, this package has been created to provide a simple but powerful API so Laravel developers feel right at home.
Examples
Model with two status fields
Transitioning from one state to another
Checking available transitions
Checking current state
Checking transitions history
Demo
You can check a demo and examples here
Installation
You can install the package via composer:
Next, you must export the package migrations
Finally, prepare required database tables
Usage
Defining our StateMachine
Imagine we have a SalesOrder
model which has a status
field for tracking the different stages
our sales order can be in the system: REGISTERED
, APPROVED
, PROCESSED
or DECLINED
.
We can manage and centralize all of these stages and transitions within a StateMachine class. To define
one, we can use the php artisan make:state-machine
command.
For example, we can create a StatusStateMachine
for our SalesOrder model
After running the command, we will have a new StateMachine class created
in the App\StateMachines
directory. The class will have the following code.
Inside this class, we can define our states and allowed transitions
Wildcards are allowed to allow any state change
We can define the default/starting state too
The StateMachine class allows recording each one of the transitions automatically for you. To
enable this behavior, we must set recordHistory()
to return true
;
Registering our StateMachine
Once we have defined our StateMachine, we can register it in our SalesOrder
model, in a $stateMachine
attribute. Here, we set the bound model field
and state machine class that will control it.
State Machine Methods
When registering $stateMachines
in our model, each state field will have it's own custom method to
interact with the state machine and transitioning methods. The HasStateMachines
trait defines
one method per each field mapped in $stateMachines
. Eg.
For
We will have an accompanying method
with which we can use to check our current state, history and apply transitions.
Note: the field "status" will be kept intact and in sync with the state machine
Transitioning States
To transition from one state to another, we can use the transitionTo
method. Eg:
You can also pass in $customProperties
if needed
A $responsible
can be also specified. By default, auth()->user()
will be used
When applying the transition, the state machine will verify if the state transition is allowed according
to the transitions()
states we've defined. If the transition is not allowed, a TransitionNotAllowed
exception will be thrown.
Querying History
If recordHistory()
is set to true
in our State Machine, each state transition will be recorded in
the package StateHistory
model using the state_histories
table that was exported when installing the
package.
With recordHistory()
turned on, we can query the history of states our field has transitioned to. Eg:
As seen above, we can check whether or not our field has transitioned to one of the queried states.
We can also get the latest snapshot or all snapshots for a given state
The full history of transitioned states is also available
The history()
method returns an Eloquent relationship that can be chained with the following
scopes to further down the results.
Using Query Builder
The HasStateMachines
trait introduces a helper method when querying your models based on the state history of each
state machine. You can use the whereHas{FIELD_NAME}
(eg: whereHasStatus
, whereHasFulfillment
) to add constraints
to your model queries depending on state transitions, responsible and custom properties.
The whereHas{FIELD_NAME}
method accepts a closure where you can add the following type of constraints:
withTransition($from, $to)
transitionedFrom($to)
transitionedTo($to)
withResponsible($responsible|$id)
withCustomProperty($property, $operator, $value)
The $from
and $to
parameters can be either a status name as a string or an array of status names.
Getting Custom Properties
When applying transitions with custom properties, we can get our registered values using the
getCustomProperty($key)
method. Eg.
This method will reach for the custom properties of the current state. You can get custom properties of previous states using the snapshotWhen($state) method.
Getting Responsible
Similar to custom properties, you can retrieve the $responsible
object that applied the state transition.
This method will reach for the responsible of the current state. You can get responsible of previous states using the snapshotWhen($state) method.
Note:
responsible
can benull
if not specified and when the transition happens in a background job. This is because noauth()->user()
is available.
Advanced Usage
Tracking Attribute Changes
When recordHistory()
is active, model state transitions are recorded in the state_histories
table. Each transition
record contains information about the attributes that changed during the state transition. You can get information
about what has changed via the changedAttributesNames()
method. This method will return an array of the attributes
names that changed. With these attributes names, you can then use the methods changedAttributeOldValue($attributeName)
and changedAttributeNewValue($attributeName)
to get the old and new values respectively.
Adding Validations
Before transitioning to a new state, we can add validations that will allow/disallow the transition. To
do so, we can override the validatorForTransition($from, $to, $model)
method in our state machine class.
This method must return a Validator
that will be used to check the transition before applying it. If
the validator fails()
, a ValidationException
is thrown. Eg:
In the example above, we are validating that our Sales Order model total is greater than 0 before applying the transition.
Adding Hooks
We can also add custom hooks/callbacks that will be executed before/after a transition is applied.
To do so, we must override the beforeTransitionHooks()
and afterTransitionHooks()
methods in our state machine
accordingly.
Both transition hooks methods must return a keyed array with the state as key, and an array of callbacks/closures to be executed.
NOTE: The keys for beforeTransitionHooks() must be the
$from
states. NOTE: The keys for afterTransitionHooks() must be the$to
states.
Example
Postponing Transitions
You can also postpone transitions to other states by using the postponeTransitionTo
method.
This method accepts the same parameters as transitionTo
plus a $when
Carbon instance to specify
when the transition is to be run.
postponeTransitionTo
doesn't apply the transition immediately. Instead, it saves it
into a pending_transitions
table where it keeps track of all pending transitions for all
models.
To enable running this transitions at a later time, you must schedule the
PendingTransitionsDispatcher
job class into your scheduler to run every one, five or ten minutes.
PendingTransitionsDispatcher
is responsible for applying the postponed transitions at the specified
$when
date/time.
You can check if a model has pending transitions for a particular state machine using the
hasPendingTransitions()
method
Testing
Changelog
Please see CHANGELOG for more information what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
Credits
- Andrés Santibáñez
- All Contributors
License
The MIT License (MIT). Please see License File for more information.
All versions of laravel-eloquent-state-machines with dependencies
javoscript/laravel-macroable-models Version ^1.0
illuminate/support Version ^6.0|^7.0|^8.0|^9.0|^10.0|^11.0