php - Implement a State Pattern with Doctrine ORM -


i have class using state pattern. here's simple example

/**  * @enitity  **/ class door {   protected $id;   protected $state;   public function __construct($id, doorstate $state)   public function setstate(doorstate $state)   {     $this->state = $state;   }   public function close()   {     $this->setstate($this->state->close())   }   ... }  interface doorstate {   public function close;   public function open;   public function lock;   public function unlock; }  class dooraction implements doorstate {   public function close()   {      throw new doorerror();   }   ... } 

then several classes define appropriate actions in states

class openeddoor extends dooraction {   public function close()   {       return new closeddoor();   } } 

so have thing like

$door = new door('1', new openeddoor()); doctrinedoorrepository::save($door); $door->close(); doctrinedoorrepository::save($door); 

how implement mapping in doctrine can persist it? i'm hung on $state property. save whole dooraction based object have map dooraction super class or each individual sub class?

i've looked @ implementing using embeddable or supermapping run problems each.

doctrine2 dbal has feature in documentation allows enum's

http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/cookbook/mysql-enums.html

when take solution 2: defining type base, 1 create own type, instance called doorstatetype or similar represent open/closed state. instance this:

<?php namespace acme\model\door;  use doctrine\dbal\types\type; use doctrine\dbal\platforms\abstractplatform;  class doorstatetype extends type {     const enum_doorstate = 'enumdoorstate';     const state_open = 'open';     const state_closed = 'closed';      public function getsqldeclaration(array $fielddeclaration, abstractplatform $platform)     {         return "enum('" . self::state_open . "', '" . self::state_closed . "') comment '(dc2type:" . enum_doorstate  . ")'";     }      public function converttophpvalue($value, abstractplatform $platform)     {         return $value;     }      public function converttodatabasevalue($value, abstractplatform $platform)     {         if (!in_array($value, array(self::state_open, self::state_closed))) {             throw new \invalidargumentexception("invalid state");         }          return $value;     }      public function getname()     {         return self::enum_doorstate;     } } 

and use this:

<?php  namespace acme\model\door;  /** @entity */ class door {     /** @column(type="enumdoorstate") */     private $state;      public function open()     {         if (!doorstatetype::state_open === $this->state) {             throw new \logicexception('cannot open open door');         }          $this->state = doorstatetype::state_open;     }      public function close()     {         if (!doorstatetype::state_closed === $this->state) {             throw new \logicexception('cannot close closed door');         }          $this->state = doorstatetype::state_closed;     } } 

this allows searching states:

$opendoors = $repository->findby(array('state' => doorstatetype::state_open)); 

you have converttophpvalue method create objects of desired states allow logic, checking if open door can locked or similar.

in case state has class contains logic, implement this:

first define normal state can inherit:

<?php namespace acme\model\door;  abstract class doorstate {     // methods define default behaviour when isn't possible     public function open()     {         throw new \logicexception('cannot open door');     }      public function close()     {         throw new \logicexception('cannot close door');     }       abstract public function getstatename(); } 

then openstate:

<?php namespace acme\model\door;  class openstate extends doorstate {     const state = 'open';      public function close()     {         return new closedstate();     }      public function getstatename()     {         return self::state;     }      // more logic } 

and closedstate:

<?php namespace acme\model\door;  class closedstate extends doorstate {     const state = 'open';      public function open()     {         return new openstate();     }      public function getstatename()     {         return self::state;     }      // more logic } 

we can then, persistence, use different convert methods:

<?php namespace acme\model\door;  use doctrine\dbal\types\type; use doctrine\dbal\platforms\abstractplatform;  class doorstatetype extends type {     // sql declarations etc.      public function converttophpvalue($value, abstractplatform $platform)     {         if ($value === openstate::state) {             return new openstate();         }          if ($value === closedstate::state) {             return new closedstate();         }          throw new \exception(sprintf('unknown state "%s", expected 1 of "%s"', $value, implode('", "', [openstate::state, closedstate::state])));     }      public function converttodatabasevalue($value, abstractplatform $platform)     {         return $value->getstatename();     } } 

Comments

Popular posts from this blog

javascript - Using jquery append to add option values into a select element not working -

Android soft keyboard reverts to default keyboard on orientation change -

Rendering JButton to get the JCheckBox behavior in a JTable by using images does not update my table -