A statemachine is always uniquely identified by the combination of an entity id and a machine name (that provides the relation to the statemachine the entity is governed by). the machine name should be a 'machine readable' string, since it will be stored in different backends and might be used as a key there (eg: in redis). The entity id is something that uniquely identifies a domain model. Probably something that is stored in your application, like a primary key in a table, a GUID or a hash. This object thus stores the minimum data needed from other processes in your application domain to succesfully work with the statemachine.
Author: Rolf Vreijdenberger
 public function isPersisted(Identifier $identifier)
 {
     $key = $identifier->getId();
     if (!isset($_SESSION[$this->namespace][$key])) {
         return false;
     }
     return true;
 }
 /**
  *
  * @param Identifier $identifier          
  * @param string $state            
  */
 public function __construct(Identifier $identifier, $state, $message = null)
 {
     $this->id = $identifier->getEntityId();
     $this->machine = $identifier->getMachine();
     $this->state = $state;
     $this->timestamp = time();
     $this->message = $message;
 }
 protected function build(Identifier $identifier)
 {
     $light = new TrafficLight($identifier->getEntityId());
     return $light;
 }
 /**
  * {@inheritDoc}
  */
 public function isPersisted(Identifier $identifier)
 {
     $is_persisted = false;
     try {
         //https://php.net/manual/en/mongocollection.findone.php
         $query = array("entity_id" => $identifier->getEntityId(), "machine" => $identifier->getMachine());
         $data = $this->getClient()->izzum->states->findOne($query);
         if ($data) {
             $is_persisted = true;
         }
     } catch (\Exception $e) {
         throw new Exception(sprintf('getting persistence info failed: [%s]', $e->getMessage()), Exception::PERSISTENCE_LAYER_EXCEPTION);
     }
     return $is_persisted;
 }
 /**
  * {@inheritDoc}
  */
 public function addHistory(Identifier $identifier, $state, $message = null, $is_exception = false)
 {
     $redis = $this->getRedis();
     try {
         $machine = $identifier->getMachine();
         $entity_id = $identifier->getEntityId();
         //counter for the number of transitions.
         $key = self::KEY_COUNTERS_TRANSITIONS_ALL;
         //this will function as the id of the transition data, stored as a redis hash
         $counter = $redis->incr($key);
         //now that we have the counter, start a redis multi command in pipeline mode
         $redis->multi(\Redis::PIPELINE);
         //create the record for the transition to store in a redis hash
         $timestamp = time();
         $record = array();
         $record['state'] = $state;
         $record['machine'] = $machine;
         $record['entity_id'] = $entity_id;
         if ($message) {
             if (is_string($message)) {
                 $info = new \stdClass();
                 $info->message = $message;
                 $message = $info;
             }
             //always json_encode so we can pass objects as messages
             $message = json_encode($message);
         }
         $record['message'] = $message;
         $record['timestamp'] = $timestamp;
         $record['datetime'] = date('Y-m-d H:i:s', $timestamp);
         //ISO_8601
         $record['exception'] = $is_exception ? 1 : 0;
         $record['id'] = $counter;
         /*
          * set the canonical form of the transition as a hash with the counter as the id.
          * This allows you to get data from the canonical from by storing a reference to the transaction id
          * in other lists or sets (memory optimization) via:
          * sort izzum:transitions:all:normal by nosort get izzum:transitions:canonical:*->message STORE mymessages
          * @see http://redis.io/commands/sort
          */
         $key_hash_id = sprintf(self::KEY_TRANSITIONS_CANONICAL, $counter);
         $redis->hmset($key_hash_id, $record);
         //store all transitions referencing the id of the canonical form in sorted sets (keyed by timestamp),
         //set manipulations are powerful in redis (diff, union, intersect etc with the exceptions for example)
         $key = self::KEY_TRANSITIONS_ALL;
         $redis->zadd($key, $timestamp, $counter);
         $key = sprintf(self::KEY_TRANSITIONS_MACHINES, $machine);
         $redis->zadd($key, $timestamp, $counter);
         $key = sprintf(self::KEY_TRANSITIONS_STATES, $machine, $state);
         $redis->zadd($key, $timestamp, $counter);
         $key = sprintf(self::KEY_TRANSITIONS_ENTITIES, $machine, $entity_id);
         $redis->zadd($key, $timestamp, $counter);
         if ($is_exception) {
             //store all failed transitions referencing the id of the canonical form in sets
             $key = self::KEY_TRANSITIONS_ALL_FAILED;
             $redis->zadd($key, $timestamp, $counter);
             $key = sprintf(self::KEY_TRANSITIONS_MACHINES_FAILED, $machine);
             $redis->zadd($key, $timestamp, $counter);
             $key = sprintf(self::KEY_TRANSITIONS_STATES_FAILED, $machine, $state);
             $redis->zadd($key, $timestamp, $counter);
             $key = sprintf(self::KEY_TRANSITIONS_ENTITIES_FAILED, $machine, $entity_id);
             $redis->zadd($key, $timestamp, $counter);
         }
         //execute the sequence of redis commands
         $redis->exec();
     } catch (\Exception $e) {
         $redis->discard();
         throw new Exception(sprintf('adding history failed: [%s]', $e->getMessage()), Exception::PERSISTENCE_LAYER_EXCEPTION);
     }
 }
 /**
  *{@inheritDoc}
  */
 public function addHistory(Identifier $identifier, $state, $message = null, $is_exception = false)
 {
     $connection = $this->getConnection();
     $prefix = $this->getPrefix();
     try {
         $query = 'INSERT INTO ' . $prefix . 'statemachine_history
                 (machine, entity_id, state, message, changetime, exception)
                     VALUES
                 (:machine, :entity_id, :state, :message, :timestamp, :exception)';
         $statement = $connection->prepare($query);
         $machine = $identifier->getMachine();
         $entity_id = $identifier->getEntityId();
         $timestamp = $this->getTimestampForDriver();
         $is_exception = $this->getBooleanForDriver($is_exception);
         $statement->bindParam(":machine", $machine);
         $statement->bindParam(":entity_id", $entity_id);
         $statement->bindParam(":state", $state);
         if ($message) {
             if (is_string($message)) {
                 $info = new \stdClass();
                 $info->message = $message;
                 $message = $info;
             }
             //always json encode it so we can pass objects as the message and store it
             $message = json_encode($message);
         }
         $statement->bindParam(":message", $message);
         $statement->bindParam(":timestamp", $timestamp);
         $statement->bindParam(":exception", $is_exception);
         $result = $statement->execute();
         if ($result === false) {
             throw new Exception($this->getErrorInfo($statement));
         }
     } catch (\Exception $e) {
         throw new Exception(sprintf('query for updating state failed: [%s]', $e->getMessage()), Exception::PERSISTENCE_LAYER_EXCEPTION);
     }
 }
 public function getStorageFromRegistry(Identifier $identifier)
 {
     $registry = $this->getRegistry();
     if (!isset($registry[$identifier->getId()])) {
         $storage = null;
     } else {
         $storage = $registry[$identifier->getId()];
     }
     return $storage;
 }
 protected function build(Identifier $identifier)
 {
     $output = new \stdClass();
     $output->entity_id = $identifier->getEntityId();
     $output->machine = $identifier->getMachine();
     return $output;
 }