vendor/codeages/biz-framework/src/Dao/DaoProxy.php line 115

Open in your IDE?
  1. <?php
  2. namespace Codeages\Biz\Framework\Dao;
  3. use Codeages\Biz\Framework\Dao\Annotation\MetadataReader;
  4. class DaoProxy
  5. {
  6.     /**
  7.      * @var GeneralDaoInterface
  8.      */
  9.     protected $dao;
  10.     /**
  11.      * @var SerializerInterface
  12.      */
  13.     protected $serializer;
  14.     /**
  15.      * @var CacheStrategy
  16.      */
  17.     protected $cacheStrategy;
  18.     /**
  19.      * @var ArrayStorage
  20.      */
  21.     protected $arrayStorage;
  22.     /**
  23.      * @var MetadataReader
  24.      */
  25.     protected $metadataReader;
  26.     public function __construct($containerDaoInterface $daoMetadataReader $metadataReaderSerializerInterface $serializerArrayStorage $arrayStorage null)
  27.     {
  28.         $this->container $container;
  29.         $this->dao $dao;
  30.         $this->metadataReader $metadataReader;
  31.         $this->serializer $serializer;
  32.         $this->arrayStorage $arrayStorage;
  33.     }
  34.     public function __call($method$arguments)
  35.     {
  36.         $proxyMethod $this->getProxyMethod($method);
  37.         if ($proxyMethod) {
  38.             return $this->$proxyMethod($method$arguments);
  39.         } else {
  40.             return $this->callRealDao($method$arguments);
  41.         }
  42.     }
  43.     protected function getProxyMethod($method)
  44.     {
  45.         foreach (array('get''find''search''count''create''batchCreate''batchUpdate''batchDelete''update''wave''delete') as $prefix) {
  46.             if (=== strpos($method$prefix)) {
  47.                 return $prefix;
  48.             }
  49.         }
  50.         return null;
  51.     }
  52.     /**
  53.      * 代理 get 开头的方法调用
  54.      *
  55.      * @param string $method 被调用的 Dao 方法名
  56.      * @param array $arguments 调用参数
  57.      * @return array|null
  58.      */
  59.     protected function get($method$arguments)
  60.     {
  61.         $lastArgument end($arguments);
  62.         reset($arguments);
  63.         
  64.         // lock模式下,因为需要借助mysql的锁,不走cache
  65.         if (is_array($lastArgument) && isset($lastArgument['lock']) && true === $lastArgument['lock']) {
  66.             $row $this->callRealDao($method$arguments);
  67.             $this->unserialize($row);
  68.             return $row;
  69.         }
  70.         if ($this->arrayStorage) {
  71.             $key $this->getCacheKey($this->dao$method$arguments);
  72.             if (!empty($this->arrayStorage[$key])) {
  73.                 return $this->arrayStorage[$key];
  74.             }
  75.         }
  76.         $strategy $this->buildCacheStrategy();
  77.         if ($strategy) {
  78.             $cache $strategy->beforeQuery($this->dao$method$arguments);
  79.             // 命中 cache, 直接返回 cache 数据
  80.             if (false !== $cache) {
  81.                 return $cache;
  82.             }
  83.         }
  84.         $row $this->callRealDao($method$arguments);
  85.         $this->unserialize($row);
  86.         // 将结果缓存至 ArrayStorage
  87.         $this->arrayStorage && ($this->arrayStorage[$this->getCacheKey($this->dao$method$arguments)] = $row);
  88.         if ($strategy) {
  89.             $strategy->afterQuery($this->dao$method$arguments$row);
  90.         }
  91.         return $row;
  92.     }
  93.     protected function find($method$arguments)
  94.     {
  95.         return $this->search($method$arguments);
  96.     }
  97.     protected function search($method$arguments)
  98.     {
  99.         $strategy $this->buildCacheStrategy();
  100.         if ($strategy) {
  101.             $cache $strategy->beforeQuery($this->dao$method$arguments);
  102.             if (false !== $cache) {
  103.                 return $cache;
  104.             }
  105.         }
  106.         $rows $this->callRealDao($method$arguments);
  107.         if (!empty($rows)) {
  108.             $this->unserializes($rows);
  109.         }
  110.         if ($strategy) {
  111.             $strategy->afterQuery($this->dao$method$arguments$rows);
  112.         }
  113.         return $rows;
  114.     }
  115.     protected function count($method$arguments)
  116.     {
  117.         $strategy $this->buildCacheStrategy();
  118.         if ($strategy) {
  119.             $cache $strategy->beforeQuery($this->dao$method$arguments);
  120.             if (false !== $cache) {
  121.                 return $cache;
  122.             }
  123.         }
  124.         $count $this->callRealDao($method$arguments);
  125.         if ($strategy) {
  126.             $strategy->afterQuery($this->dao$method$arguments$count);
  127.         }
  128.         return $count;
  129.     }
  130.     protected function create($method$arguments)
  131.     {
  132.         $declares $this->dao->declares();
  133.         $generator $this->getIdGenerator();
  134.         if ($generator) {
  135.             $id $arguments[0]['id'] = $generator->generate();
  136.         }
  137.         $time time();
  138.         if (isset($declares['timestamps'][0])) {
  139.             $arguments[0][$declares['timestamps'][0]] = $time;
  140.         }
  141.         if (isset($declares['timestamps'][1])) {
  142.             $arguments[0][$declares['timestamps'][1]] = $time;
  143.         }
  144.         $this->serialize($arguments[0]);
  145.         $row $this->callRealDao($method$arguments);
  146.         $this->unserialize($row);
  147.         $this->arrayStorage && $this->arrayStorage->flush();
  148.         $strategy $this->buildCacheStrategy();
  149.         if ($strategy) {
  150.             $this->buildCacheStrategy()->afterCreate($this->dao$method$arguments$row);
  151.         }
  152.         return $row;
  153.     }
  154.     protected function batchCreate($method$arguments)
  155.     {
  156.         $declares $this->dao->declares();
  157.         end($arguments);
  158.         $lastKey key($arguments);
  159.         reset($arguments);
  160.         if (!is_array($arguments[$lastKey])) {
  161.             throw new DaoException('batchCreate method arguments last element must be array type');
  162.         }
  163.         $time time();
  164.         $rows $arguments[$lastKey];
  165.         $generator $this->getIdGenerator();
  166.         foreach ($rows as &$row) {
  167.             if ($generator) {
  168.                 $row['id'] = $generator->generate();
  169.             }
  170.             if (isset($declares['timestamps'][0])) {
  171.                 $row[$declares['timestamps'][0]] = $time;
  172.             }
  173.             if (isset($declares['timestamps'][1])) {
  174.                 $row[$declares['timestamps'][1]] = $time;
  175.             }
  176.             $this->serialize($row);
  177.             unset($row);
  178.         }
  179.         $arguments[$lastKey] = $rows;
  180.         $result $this->callRealDao($method$arguments);
  181.         $this->flushTableCache();
  182.         return $result;
  183.     }
  184.     protected function batchUpdate($method$arguments)
  185.     {
  186.         $declares $this->dao->declares();
  187.         $time time();
  188.         $rows $arguments[1];
  189.         foreach ($rows as &$row) {
  190.             if (isset($declares['timestamps'][1])) {
  191.                 $row[$declares['timestamps'][1]] = $time;
  192.             }
  193.             $this->serialize($row);
  194.         }
  195.         $arguments[1] = $rows;
  196.         $result $this->callRealDao($method$arguments);
  197.         $this->flushTableCache();
  198.         return $result;
  199.     }
  200.     protected function batchDelete($method$arguments)
  201.     {
  202.         $result $this->callRealDao($method$arguments);
  203.         $this->flushTableCache();
  204.         return $result;
  205.     }
  206.     protected function wave($method$arguments)
  207.     {
  208.         $result $this->callRealDao($method$arguments);
  209.         $this->arrayStorage && $this->arrayStorage->flush();
  210.         $strategy $this->buildCacheStrategy();
  211.         if ($strategy) {
  212.             $this->buildCacheStrategy()->afterWave($this->dao$method$arguments$result);
  213.         }
  214.         return $result;
  215.     }
  216.     protected function update($method$arguments)
  217.     {
  218.         $declares $this->dao->declares();
  219.         end($arguments);
  220.         $lastKey key($arguments);
  221.         reset($arguments);
  222.         if (!is_array($arguments[$lastKey])) {
  223.             throw new DaoException('update method arguments last element must be array type');
  224.         }
  225.         if (isset($declares['timestamps'][1])) {
  226.             $arguments[$lastKey][$declares['timestamps'][1]] = time();
  227.         }
  228.         $this->serialize($arguments[$lastKey]);
  229.         $row $this->callRealDao($method$arguments);
  230.         if (is_array($row)) {
  231.             $this->unserialize($row);
  232.         }
  233.         if (!is_array($row) && !is_numeric($row) && !is_null($row)) {
  234.             throw new DaoException('update method return value must be array type or int type');
  235.         }
  236.         $this->arrayStorage && $this->arrayStorage->flush();
  237.         $strategy $this->buildCacheStrategy();
  238.         if ($strategy) {
  239.             $this->buildCacheStrategy()->afterUpdate($this->dao$method$arguments$row);
  240.         }
  241.         return $row;
  242.     }
  243.     protected function delete($method$arguments)
  244.     {
  245.         $result $this->callRealDao($method$arguments);
  246.         $this->arrayStorage && $this->arrayStorage->flush();
  247.         $strategy $this->buildCacheStrategy();
  248.         if ($strategy) {
  249.             $this->buildCacheStrategy()->afterDelete($this->dao$method$arguments);
  250.         }
  251.         return $result;
  252.     }
  253.     protected function callRealDao($method$arguments)
  254.     {
  255.         return call_user_func_array(array($this->dao$method), $arguments);
  256.     }
  257.     protected function unserialize(&$row)
  258.     {
  259.         if (empty($row)) {
  260.             return;
  261.         }
  262.         $declares $this->dao->declares();
  263.         $serializes = empty($declares['serializes']) ? array() : $declares['serializes'];
  264.         foreach ($serializes as $key => $method) {
  265.             if (!array_key_exists($key$row)) {
  266.                 continue;
  267.             }
  268.             $row[$key] = $this->serializer->unserialize($method$row[$key]);
  269.         }
  270.     }
  271.     protected function unserializes(array &$rows)
  272.     {
  273.         foreach ($rows as &$row) {
  274.             $this->unserialize($row);
  275.         }
  276.     }
  277.     protected function serialize(&$row)
  278.     {
  279.         $declares $this->dao->declares();
  280.         $serializes = empty($declares['serializes']) ? array() : $declares['serializes'];
  281.         foreach ($serializes as $key => $method) {
  282.             if (!array_key_exists($key$row)) {
  283.                 continue;
  284.             }
  285.             $row[$key] = $this->serializer->serialize($method$row[$key]);
  286.         }
  287.     }
  288.     protected function getIdGenerator()
  289.     {
  290.         $declares $this->declares();
  291.         if (empty($declares['id_generator'])) {
  292.             return null;
  293.         }
  294.         return $this->container['dao.id_generator.'.$declares['id_generator']];
  295.     }
  296.     private function flushTableCache()
  297.     {
  298.         $this->arrayStorage && ($this->arrayStorage->flush());
  299.         $strategy $this->buildCacheStrategy();
  300.         if ($strategy) {
  301.             $this->buildCacheStrategy()->flush($this->dao);
  302.         }
  303.     }
  304.     /**
  305.      * @return CacheStrategy|null
  306.      */
  307.     private function buildCacheStrategy()
  308.     {
  309.         if (!empty($this->cacheStrategy)) {
  310.             return $this->cacheStrategy;
  311.         }
  312.         if (empty($this->container['dao.cache.enabled'])) {
  313.             return null;
  314.         }
  315.         if (!empty($this->container['dao.cache.annotation'])) {
  316.             $strategy $this->getCacheStrategyFromAnnotation($this->dao);
  317.             if ($strategy) {
  318.                 return $strategy;
  319.             }
  320.         }
  321.         $declares $this->dao->declares();
  322.         // 未指定 cache 策略,则使用默认策略
  323.         if (!isset($declares['cache'])) {
  324.             return $this->container['dao.cache.strategy.default'];
  325.         }
  326.         // 针对某个 Dao 关闭 Cache
  327.         if (false === $declares['cache']) {
  328.             return null;
  329.         }
  330.         // 针对某个 Dao 指定 Cache 策略
  331.         $strategyServiceId 'dao.cache.strategy.'.strtolower($declares['cache']);
  332.         if (!isset($this->container[$strategyServiceId])) {
  333.             throw new DaoException("Dao %s cache strategy is not defined, please define first in biz container use %s service id."get_class($this->dao), $strategyServiceId);
  334.         }
  335.         return $this->container[$strategyServiceId];
  336.     }
  337.     private function getCacheStrategyFromAnnotation($dao)
  338.     {
  339.         $metadata $this->metadataReader->read($dao);
  340.         if (empty($metadata)) {
  341.             return null;
  342.         }
  343.         $strategyServiceId 'dao.cache.strategy.'.strtolower($metadata['strategy']);
  344.         if (!isset($this->container[$strategyServiceId])) {
  345.             throw new DaoException("Dao %s cache strategy is not defined, please define first in biz container use %s service id."get_class($this->dao), $strategyServiceId);
  346.         }
  347.         return $this->container[$strategyServiceId];
  348.     }
  349.     private function getCacheKey(GeneralDaoInterface $dao$method$arguments)
  350.     {
  351.         $key sprintf('dao:%s:%s:%s'$dao->table(), $methodjson_encode($arguments));
  352.         return $key;
  353.     }
  354. }