mateusbs17
5/16/2017 - 6:55 PM

Testes para aplicar máquina de estados com laravel

Testes para aplicar máquina de estados com laravel

Utilizando Máquina de estados com Laravel

Fiz alguns testes para aplicarmos máquina de estados no Laravel, e acho que seria legal compartilhar esse conhecimento para quem achar que pode ser útil :)

Conceito de máquina de estados

Wikipédia define melhor do que eu poderia resumir:

Uma máquina de estados finita (FSM - do inglês Finite State Machine) ou autômato finito é um modelo matemático usado para representar programas de computadores ou circuitos lógicos. O conceito é concebido como uma máquina abstrata que deve estar em um de um número finito de estados. A máquina está em apenas um estado por vez, este estado é chamado de estado atual. Um estado armazena informações sobre o passado, isto é, ele reflete as mudanças desde a entrada num estado, no início do sistema, até o momento presente. Uma transição indica uma mudança de estado e é descrita por uma condição que precisa ser realizada para que a transição ocorra. Uma ação é a descrição de uma atividade que deve ser realizada num determinado momento.

Definindo uma máquina de estados

Para testes defini uma máquina de estados representado 4 diferentes estágios do desenvolvedor:

  1. Acordando
  2. Comendo
  3. Fritando
  4. Dormindo

Só esses 4 estados são possíveis, e para trocar entre eles é preciso definir os 'caminhos'. Defini as seguintes transições para trocar entre os estados:

  • Comer (vai pro estado Comendo)
  • Tomar café (vai pro estado Fritando)
  • Dormir (vai pro estado Dormindo)
  • Acordar (vai pro estado Acordando)

Como uma imagem vale mais que mil palavras, taí um gif pra explicar as transições:

Testando plugin

Para aplicar o conceito de máquina de estados no PHP um pacote bastante recomendado foi o do winzou, e para minha sorte, já existe um service provider pro laravel disponível no Github.

Instalei o plugin no laravel, defini a máquina de estados e fiz os seguintes testes:


// Pegando um usuario do banco                                                         
$u = App\Usuario::find(1); 
// Definindo um estado inicial
$u->estado = 'dormindo'; 
// Iniciando a maquina de estados para o usuario                             
$fsm = StateMachine::get($u, 'fsm'); 

// Perguntando o estado atual
$fsm->getState();                                                                                                 
=> "dormindo"                                                                                                        

// Verificar quais os possíveis estado futuros
$fsm->getPossibleTransitions();                                                                                  
=> [                                                                                                                 
     1 => "levantar",                                                                                                
   ]                                                                                                                 

// Aplicando uma transição
$fsm->apply("levantar");                                                                                         
=> true                                                                                                              

$fsm->getState();                                                                                                
=> "acordando"                                                                                                       

$fsm->getPossibleTransitions();                                                                                  
=> [                                                                                                                 
     0 => "comer",                                                                                                   
     2 => "tomar_cafe",                                                                                              
   ]                                                                                                                 

// Vendo se pode aplicar a transição dormir
$fsm->apply("dormir");                                                                                            
=> false
// Não pode, acabou de acordar!

// Vendo se pode aplicar a transição comer
$fsm->apply("comer");                                                                                            
=> true
// Pode comer sim

// Bateu a larica?
$fsm->apply("comer");                                                                                            
=> true                                                                                                              

$fsm->getState();                                                                                                
=> "comendo"                                                                                                         


$fsm->getPossibleTransitions();                                                                                  
=> [                                                                                                                 
     2 => "tomar_cafe",                                                                                              
     3 => "dormir",                                                                                                  
   ]                                                                                                                 

// Tomar um cafézinho pra dar uma acordada
$fsm->apply("tomar_cafe");                                                                                       
=> true                                                                                                             

$fsm->getState();                                                                                                
=> "fritando"                                                                                                         

$fsm->getPossibleTransitions();                                                                                 
=> [                                                               
     0 => "comer",                                                                                                  
     2 => "tomar_cafe",                                                                                             
     3 => "dormir",                                                                                                 
   ]

Para salvar o estado do usuário é necessário dar um $u->save(). A máquina de estados também pode chamar métodos dos controllers, antes e depois de aplicar uma transição, dando total controle ao trocar estados e aplicar regras de negócios específicos.