-
-
Save kimulisiraj/c858f2beccfd67e98e083fcfcc1f4be9 to your computer and use it in GitHub Desktop.
Laravel: State-machine on Eloquent Model
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // database/migrations/yyyy_mm_dd_hhmmss_add_last_state_to_orders_table.php | |
| use Illuminate\Support\Facades\Schema; | |
| use Illuminate\Database\Schema\Blueprint; | |
| use Illuminate\Database\Migrations\Migration; | |
| class AddLastStateToOrdersTable extends Migration | |
| { | |
| public function up() | |
| { | |
| Schema::table('orders', function($table) { | |
| $table->string('last_state'); | |
| }); | |
| } | |
| public function down() | |
| { | |
| Schema::table('oders', function($table) { | |
| $table->dropColumn('last_state'); | |
| }); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // database/migrations/yyyy_mm_dd_hhmmss_create_order_states_table.php | |
| use Illuminate\Support\Facades\Schema; | |
| use Illuminate\Database\Schema\Blueprint; | |
| use Illuminate\Database\Migrations\Migration; | |
| class CreateOrderStatesTable extends Migration | |
| { | |
| public function up() | |
| { | |
| Schema::create('order_states', function (Blueprint $table) { | |
| $table->increments('id'); | |
| $table->string('order_id'); | |
| $table->string('transition'); | |
| $table->string('to'); | |
| $table->integer('user_id'); | |
| $table->timestamps(); | |
| }); | |
| } | |
| public function down() | |
| { | |
| Schema::dropIfExists('order_states'); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // app/Order.php | |
| namespace App; | |
| use Traits\Statable; | |
| use Illuminate\Database\Eloquent\Model; | |
| class Order extends Model | |
| { | |
| use Statable; | |
| const HISTORY_MODEL = 'App\OrderState'; // the related model to store the history | |
| const SM_CONFIG = 'order'; // the SM graph to use | |
| // other relations and methods of the model | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // app/OrderState.php | |
| namespace App; | |
| use Illuminate\Database\Eloquent\Model; | |
| class OrderState extends Model | |
| { | |
| protected $fillable = ['transition','from','user_id','order_id','to']; | |
| public function order() { | |
| return $this->belongsTo('App\Order'); | |
| } | |
| public function user() { | |
| return $this->belongsTo('App\User'); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // app/Traits/Statable.php | |
| namespace App\Traits | |
| use SM\Factory\FactoryInterface; | |
| trait Statable | |
| { | |
| /** | |
| * @var StateMachine $stateMachine | |
| */ | |
| protected $stateMachine; | |
| public function getStateMachine() | |
| { | |
| if (!$this->stateMachine) { | |
| $this->stateMachine = app(FactoryInterface::class)->get($this, self::SM_CONFIG); | |
| } | |
| return $this->stateMachine; | |
| } | |
| public function state($transition = null) | |
| { | |
| if ($transition) { | |
| return $this->getStateMachine()->apply($transition); | |
| } | |
| else { | |
| return $this->getStateMachine()->getState(); | |
| } | |
| } | |
| public function transitionAllowed($transition) | |
| { | |
| return $this->getStateMachine()->can($transition); | |
| } | |
| public function history() | |
| { | |
| return $this->hasMany(self::HISTORY_MODEL); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // tests/Unit/StatableOrderTest.php | |
| namespace Tests\Unit; | |
| use Tests\TestCase; | |
| use Illuminate\Foundation\Testing\DatabaseMigrations; | |
| use Illuminate\Foundation\Testing\DatabaseTransactions; | |
| use App\Order; | |
| use App\User; | |
| use SM\SMException; | |
| use Illuminate\Support\Facades\Auth; | |
| class StatebleOrderTest extends TestCase | |
| { | |
| protected $order; | |
| protected function setUp() | |
| { | |
| parent::setup(); | |
| $this->order = factory(Order::class)->create([ | |
| "user_id" => factory(User::class)->create()->id | |
| ]); | |
| Auth::login(User::find($this->order->user->id)); | |
| } | |
| public function testCreation() | |
| { | |
| $this->assertInstanceOf('SM\StateMachine\StateMachine', $this->order->getStateMachine()); | |
| } | |
| public function testGetState() | |
| { | |
| $this->assertEquals('new', $this->order->state()); | |
| } | |
| public function testApplyState() | |
| { | |
| $this->order->state('process'); | |
| $this->assertEquals('processed', $this->order->state()); | |
| $this->assertEquals(1,$this->order->history()->count()); | |
| $this->order->state('ship'); | |
| $this->assertEquals('shipped', $this->order->state()); | |
| $this->assertEquals(2,$this->order->history()->count()); | |
| } | |
| public function testCanTransitState() | |
| { | |
| $this->assertTrue($this->order->transitionAllowed('process')); | |
| $this->assertFalse($this->order->transitionAllowed('ship')); | |
| } | |
| public function testInvalidTransition() | |
| { | |
| $this->expectException(SMException::class); | |
| $this->order->state('ship'); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // config/state_machine.php | |
| return [ | |
| 'order' => [ | |
| 'class' => App\Order::class, | |
| 'property_path' => 'last_state', | |
| 'states' => [ | |
| 'new', | |
| 'processed', | |
| 'cancelled', | |
| 'shipped', | |
| 'delivered', | |
| 'returned' | |
| ], | |
| 'transitions' => [ | |
| 'process' => [ | |
| 'from' => ['new'], | |
| 'to' => 'processed' | |
| ], | |
| 'cancel' => [ | |
| 'from' => ['new','processed'], | |
| 'to' => 'cancelled' | |
| ], | |
| 'ship' => [ | |
| 'from' => ['processed'], | |
| 'to' => 'shipped' | |
| ], | |
| 'deliver' => [ | |
| 'from' => ['shipped'], | |
| 'to' => 'delivered' | |
| ], | |
| 'return' => [ | |
| 'from' => ['delivered'], | |
| 'to' => 'returned' | |
| ] | |
| ] | |
| ], | |
| //... | |
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // app/Listeners/StateHistoryManager.php | |
| namespace App\Listeners; | |
| use SM\Event\TransitionEvent; | |
| class StateHistroyManager | |
| { | |
| public function postTransition(TransitionEvent $event) | |
| { | |
| $sm = $event->getStateMachine(); | |
| $model = $sm->getObject(); | |
| $model->history()->create([ | |
| "transition" => $event->getTransition(), | |
| "to" => $sm->getState(), | |
| "user_id" => auth()->id() | |
| ]); | |
| $model->save(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment