src/Cms/CoreBundle/Model/Context.php line 112

Open in your IDE?
  1. <?php
  2. namespace Cms\CoreBundle\Model;
  3. /**
  4.  * Class Context
  5.  * @package Cms\CoreBundle\Model
  6.  */
  7. abstract class Context
  8. {
  9.     const LOCKED true;
  10.     const UNLOCKED false;
  11.     /**
  12.      * Flag for whether or not the context is locked.
  13.      *
  14.      * @var bool
  15.      */
  16.     private $locked true;
  17.     /**
  18.      * Holds context data.
  19.      *
  20.      * @var array
  21.      */
  22.     private $data = [];
  23.     /**
  24.      * Determines the usable keys in the context.
  25.      * Also designates whether or not they are protected.
  26.      *
  27.      * @var array
  28.      */
  29.     private $keys = [];
  30.     /**
  31.      * @param array $keys
  32.      */
  33.     public function __construct(array $keys)
  34.     {
  35.         $this->keys $keys;
  36.     }
  37.     /**
  38.      * Locks protected keys to keep them from being written to.
  39.      *
  40.      * @return $this
  41.      */
  42.     public function lock()
  43.     {
  44.         $this->locked true;
  45.         return $this;
  46.     }
  47.     /**
  48.      * Unlocks protected keys to allow them to be written to.
  49.      *
  50.      * @return $this
  51.      */
  52.     public function unlock()
  53.     {
  54.         $this->locked false;
  55.         return $this;
  56.     }
  57.     /**
  58.      * @param array $keys
  59.      * @return $this
  60.      */
  61.     public function reset(array $keys null)
  62.     {
  63.         if ($keys === null) {
  64.             $keys array_keys($this->keys);
  65.         }
  66.         foreach ($keys as $key) {
  67.             $this->clear($key);
  68.         }
  69.         return $this;
  70.     }
  71.     /**
  72.      * @param callable $callable
  73.      * @return $this
  74.      * @throws \Exception
  75.      */
  76.     public function transactional(callable $callable)
  77.     {
  78.         $copy $this->data;
  79.         try {
  80.             $this->unlock();
  81.             $result $callable($this);
  82.         } catch(\Exception $e) {
  83.             $result $e;
  84.         } finally {
  85.             $this->lock();
  86.         }
  87.         $this->data $copy;
  88.         if ($result instanceof \Exception) {
  89.             throw $result;
  90.         }
  91.         return $result;
  92.     }
  93.     /**
  94.      * Allows for a transactional attempt at writing to a protected key.
  95.      * It will always lock when finished.
  96.      * Using this method is preferred to manual locking/unlocking.
  97.      *
  98.      * @param callable $callable
  99.      * @return $this
  100.      */
  101.     public function escort(callable $callable)
  102.     {
  103.         try {
  104.             $this->unlock();
  105.             $callable($this);
  106.         } finally {
  107.             $this->lock();
  108.         }
  109.         return $this;
  110.     }
  111.     /**
  112.      * Gets the value for the given key.
  113.      *
  114.      * @param string $key
  115.      * @return mixed
  116.      */
  117.     private function get($key)
  118.     {
  119.         return $this->allocate($key)->data[$key];
  120.     }
  121.     /**
  122.      * Setter that protects a value from being written to more than once.
  123.      * The context can be "unlocked" to allow writing to these protected properties if needed.
  124.      *
  125.      * @param string $key
  126.      * @param mixed $value
  127.      * @return $this
  128.      * @throws \Exception
  129.      */
  130.     protected function set($key$value)
  131.     {
  132.         if ($this->locked && $this->isProtected($key) && ! $this->isEmpty($key)) {
  133.             throw new \Exception();
  134.         }
  135.         $this->data[$key] = $value;
  136.         return $this;
  137.     }
  138.     /**
  139.      * Forces a value to be cleared (set to null).
  140.      * Respects protection.
  141.      *
  142.      * @param string $key
  143.      * @return $this
  144.      * @throws \Exception
  145.      */
  146.     private function clear($key)
  147.     {
  148.         if ($this->isEmpty($key)) {
  149.             return $this;
  150.         }
  151.         return $this->set($keynull);
  152.     }
  153.     /**
  154.      * Makes sure the given key exists in the data holder.
  155.      *
  156.      * @param string $key
  157.      * @return $this
  158.      */
  159.     private function allocate($key)
  160.     {
  161.         if ( ! isset($this->data[$key])) {
  162.             $this->data[$key] = null;
  163.         }
  164.         return $this;
  165.     }
  166.     /**
  167.      * Determines whether or not the given key is protected.
  168.      *
  169.      * @param string $key
  170.      * @return bool
  171.      * @throws \Exception
  172.      */
  173.     private function isProtected($key)
  174.     {
  175.         if ( ! isset($this->keys[$key])) {
  176.             throw new \Exception();
  177.         }
  178.         return ($this->keys[$key] === true);
  179.     }
  180.     /**
  181.      * Determines whether or not the value for the given key is empty/null.
  182.      *
  183.      * @param string $key
  184.      * @return bool
  185.      */
  186.     private function isEmpty($key)
  187.     {
  188.         return ($this->allocate($key)->data[$key] === null);
  189.     }
  190.     /**
  191.      * @param string $name
  192.      * @param array $arguments
  193.      * @return mixed
  194.      * @throws \Exception
  195.      */
  196.     public function __call($name, array $arguments)
  197.     {
  198.         if (preg_match('/^(get|set|clear)(.+)$/'$name$matches) === 1) {
  199.             $method $matches[1];
  200.             $key lcfirst($matches[2]);
  201.             if ( ! isset($this->keys[$key])) {
  202.                 throw new \Exception();
  203.             }
  204.             switch ($method) {
  205.                 case 'get':
  206.                     return $this->get($key);
  207.                 case 'set':
  208.                     if (count($arguments) !== 1) {
  209.                         throw new \Exception();
  210.                     }
  211.                     return $this->set($key$arguments[0]);
  212.                 case 'clear':
  213.                     return $this->clear($key);
  214.             }
  215.         }
  216.         throw new \Exception();
  217.     }
  218.     /**
  219.      * @param string $name
  220.      * @return mixed
  221.      */
  222.     public function __get($name)
  223.     {
  224.         return $this->get($name);
  225.     }
  226.     /**
  227.      * @param string $name
  228.      * @return bool
  229.      */
  230.     public function __isset($name)
  231.     {
  232.         return array_key_exists($name$this->data);
  233.     }
  234. }