| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097 |
- <?php
- /**
- * The cache library of zentaopms.
- *
- * @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
- * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Gang Liu <liugang@chandao.com>
- * @package cache
- * @link https://www.zentao.net
- */
- namespace Zentao\Cache;
- \helper::import(dirname(__FILE__) . DS . 'simple-cache' . DS . 'CacheInterface.php');
- \helper::import(dirname(__FILE__) . DS . 'simple-cache' . DS . 'CacheException.php');
- \helper::import(dirname(__FILE__) . DS . 'simple-cache' . DS . 'InvalidArgumentException.php');
- \helper::import(dirname(__FILE__) . DS . 'driver' . DS . 'ApcuDriver.php');
- \helper::import(dirname(__FILE__) . DS . 'driver' . DS . 'RedisDriver.php');
- \helper::import(dirname(__FILE__) . DS . 'driver' . DS . 'YacDriver.php');
- \helper::import(dirname(__FILE__) . DS . 'driver' . DS . 'FileDriver.php');
- use ZenTao\Cache\SimpleCache\InvalidArgumentException;
- class cache
- {
- const DRIVER_APCU = 'Apcu';
- const DRIVER_FILE = 'File';
- const DRIVER_YAC = 'Yac';
- const DRIVER_REDIS = 'Redis';
- const DRIVER_LIST = [self::DRIVER_APCU, self::DRIVER_FILE, self::DRIVER_YAC, self::DRIVER_REDIS];
- /**
- * 全局应用程序对象。
- * Global application object.
- *
- * @access private
- * @var object
- */
- private $app;
- /**
- * 全局数据库操作对象。
- * Global database operation object.
- *
- * @access private
- * @var object
- */
- private $dao;
- /**
- * 全局数据库操作句柄。
- * Global database operation handler.
- *
- * @access private
- * @var object
- */
- private $dbh;
- /**
- * 全局配置对象。
- * Global configuration object.
- *
- * @access private
- * @var object
- */
- private $config;
- /**
- * 全局缓存对象。
- * Global cache object.
- *
- * @access private
- * @var object
- */
- private $cache;
- /**
- * 缓存状态。
- * Cache status.
- *
- * @access private
- * @var string
- */
- private $status = 'enabled';
- /**
- * 缓存命名空间。
- * Cache namespace.
- *
- * @access private
- * @var string
- */
- private $namespace;
- /**
- * 缓存键连接符。
- * Cache key connector.
- *
- * @access private
- * @var string
- */
- private $connector;
- /**
- * 缓存键。
- * Cache key.
- *
- * @access private
- * @var string
- */
- private $key = '';
- /**
- * 缓存标签。
- * Cache label.
- *
- * @access private
- * @var array
- */
- private $labels = [];
- /**
- * 影响缓存的表名。
- * Table name that affects cache.
- *
- * @access private
- * @var string
- */
- private $table = '';
- /**
- * 影响缓存的事件。
- * Event that affects cache.
- *
- * @access private
- * @var string
- */
- private $event = '';
- /**
- * 影响缓存的 WHERE 子句。
- * WHERE clause that affects cache.
- *
- * @access private
- * @var string
- */
- private $where = '';
- /**
- * 受影响的对象列表。
- * Affected object list.
- *
- * @access private
- * @var array
- */
- private $objects = [];
- /**
- * 构造函数,根据配置文件初始化缓存对象。
- * Constructor, initialize cache object according to the configuration file.
- *
- * @param object $app 全局应用程序对象。
- * @access public
- * @return void
- */
- public function __construct($app)
- {
- $this->app = $app;
- $this->dao = $app->dao;
- $this->dbh = $app->dbh;
- $this->config = $app->config;
- if(empty($this->config->cache->enable)) return $this->log('The cache is not enabled', __FILE__, __LINE__);
- $driver = ucfirst(strtolower($this->config->cache->driver));
- if(!in_array($driver, self::DRIVER_LIST)) return $this->log("Driver {$driver} is not supported.", __FILE__, __LINE__);
- if($driver != self::DRIVER_FILE && !extension_loaded($driver)) return $this->log("Driver ext-{$driver} is not loaded.", __FILE__, __LINE__);
- $connector = $driver == self::DRIVER_REDIS ? ':' : '-';
- $className = "ZenTao\Cache\Driver\\{$driver}Driver";
- $scope = $this->config->cache->scope;
- $namespace = $this->config->cache->namespace;
- $lifetime = $this->config->cache->lifetime;
- $redis = $this->config->redis;
- $this->setNamespace($namespace);
- $this->setConnector($connector);
- if($driver == self::DRIVER_APCU) return $this->cache = new $className($namespace, $lifetime, $scope, $connector);
- if($driver == self::DRIVER_REDIS) return $this->cache = new $className($namespace, $lifetime, $scope, $connector, $redis);
- if($driver == self::DRIVER_YAC) return $this->cache = new $className($namespace, $lifetime);
- if($driver == self::DRIVER_FILE) return $this->cache = new $className($namespace, $lifetime, $app->getCacheRoot());
- }
- /**
- * 设置缓存状态。
- * Set cache status.
- *
- * @param string $status 缓存状态。enabled: 启用缓存;disabled: 禁用缓存。
- * @access private
- * @return void
- */
- private function setStatus($status)
- {
- $this->status = $status;
- }
- /**
- * 设置缓存命名空间。
- * Set cache namespace.
- *
- * @param string $namespace 缓存命名空间。
- * @access private
- * @return void
- */
- private function setNamespace($namespace)
- {
- $this->namespace = $namespace;
- }
- /**
- * 设置缓存键连接符。
- * Set cache key connector.
- *
- * @param string $connector 缓存键连接符。
- * @access private
- * @return void
- */
- private function setConnector($connector)
- {
- $this->connector = $connector;
- }
- /**
- * 设置缓存键。
- * Set cache key.
- *
- * @param string $key 缓存键。
- * @access private
- * @return void
- */
- private function setKey($key)
- {
- $this->key = $key;
- }
- /**
- * 设置影响缓存的表名。
- * Set the table name that affects the cache.
- *
- * @param string $table 表名。
- * @access private
- * @return void
- */
- private function setTable($table)
- {
- $this->table = $table;
- }
- /**
- * 设置影响缓存的事件。
- * Set the event that affects the cache.
- *
- * @param string $event 事件。
- * @access private
- * @return void
- */
- private function setEvent($event)
- {
- $this->event = $event;
- }
- /**
- * 设置影响缓存的 WHERE 子句。
- * Set the WHERE clause that affects the cache.
- *
- * @param string $where WHERE 子句。
- * @access private
- * @return void
- */
- private function setWhere($where)
- {
- $this->where = $where;
- }
- /**
- * 设置受影响的对象列表。
- * Set the list of affected objects.
- *
- * @param array $objects 对象列表。
- * @access private
- * @return void
- */
- private function setObjects($objects)
- {
- $this->objects = $objects;
- }
- /**
- * 获取表的主键字段。
- * Get the primary key field of the table.
- *
- * @access private
- * @return string
- */
- public function getTableField()
- {
- return $this->config->cache->raw[$this->table];
- }
- /**
- * 获取表的缓存代号。
- * Get the cache code of the table.
- *
- * @access private
- * @return string
- */
- private function getTableCode()
- {
- return str_replace(['`', $this->config->db->prefix], '', $this->table);
- }
- /**
- * 获取原始数据类型缓存的键。该缓存用于保存表的原始数据。
- * Get the key of the raw data type cache. This cache is used to save the original data of the table.
- *
- * @param string $code 缓存代号。
- * @param int|string $id 主键值。
- * @access private
- * @return string
- */
- private function getRawCacheKey($code, $id)
- {
- return $this->createKey('raw', $code, $id);
- }
- /**
- * 获取集合类型缓存的键。该缓存用于保存表的主键字段。
- * Get the key of the set type cache. This cache is used to save the primary key field of the table.
- *
- * @param string $code 缓存代号。
- * @access private
- * @return string
- */
- private function getSetCacheKey($code)
- {
- return $this->createKey('set', $code, 'list');
- }
- /**
- * 获取结果类型缓存的键。该缓存用于保存表的计算结果。
- * Get the key of the result type cache. This cache is used to save the calculation results of the table.
- *
- * @param string $key 缓存键。
- * @access private
- * @return string
- */
- private function getResCacheKey($key)
- {
- $args = explode('_', str_replace('cache', 'res', strtolower($key)));
- return $this->createKey(...$args);
- }
- /**
- * 新增数据时更新缓存。
- * Update cache when adding data.
- *
- * @access private
- * @return void
- */
- private function create()
- {
- $code = $this->getTableCode();
- $setCacheKey = $this->getSetCacheKey($code);
- $objectIdList = $this->cache->get($setCacheKey);
- if(!is_array($objectIdList)) return;
- $objectID = $this->dbh->lastInsertID();
- if(!$objectID) return $this->log('Failed to fetch last insert id.', __FILE__, __LINE__);
- /* 获取新增的数据。Get the new data. */
- $sql = $this->dao->select('*')->from($this->table)->where('id')->eq($objectID)->sqlobj->get();
- $object = $this->query($sql, 'fetch');
- if(!$object) return $this->log('Failed to fetch new object. The sql is: ' . $sql, __FILE__, __LINE__);
- /* 把新增的数据保存到缓存中。Save the new data to cache. */
- $field = $this->getTableField();
- $rawCacheKey = $this->getRawCacheKey($code, $object->$field);
- $this->cache->set($rawCacheKey, $object);
- /* 把新增的数据的 id 保存到缓存中。Save the id of the new data to cache. */
- $this->cache->set($setCacheKey, $objectIdList ? array_merge($objectIdList, [$object->$field]) : [$object->$field]);
- if(empty($this->config->cache->res[$this->table])) return;
- /* 删除受影响的缓存。Delete the affected cache. */
- $this->deleteAffectedCache([$object]);
- }
- /**
- * 更新数据时更新缓存。
- * Update cache when updating data.
- *
- * @access private
- * @return void
- */
- private function update()
- {
- if(empty($this->objects)) return $this->log('No objects to update.', __FILE__, __LINE__);
- $field = $this->getTableField();
- $code = $this->getTableCode();
- /* 获取被更新数据的 id 列表。Get the id list of the updated data. */
- $objectIdList = array_map(function($object) use ($field) { return $object->$field; }, $this->objects);
- /* 获取更新后的数据。Get the updated data. */
- $sql = $this->dao->select('*')->from($this->table)->where($field)->in($objectIdList)->sqlobj->get();
- $objects = $this->query($sql, 'fetchAll', $field);
- if(!$objects) return $this->log('Failed to fetch updated objects. The sql is: ' . $sql, __FILE__, __LINE__);
- /* 把更新后的数据保存到缓存中。Save the updated data to cache. */
- $values = [];
- foreach($objects as $object)
- {
- $rawCacheKey = $this->getRawCacheKey($code, $object->$field);
- $values[$rawCacheKey] = $object;
- }
- $this->cache->setMultiple($values);
- if(empty($this->config->cache->res[$this->table])) return;
- /* 获取受影响的数据。Get the affected data. */
- foreach($objectIdList as $objectID)
- {
- if(isset($this->objects[$objectID]) && isset($objects[$objectID]) && $this->objects[$objectID] == $objects[$objectID]) unset($this->objects[$objectID], $objects[$objectID]);
- }
- $affectedObjects = array_merge($this->objects, $objects);
- /* 删除受影响的缓存。Delete the affected cache. */
- $this->deleteAffectedCache($affectedObjects);
- }
- /**
- * 删除数据时更新缓存。
- * Update cache when deleting data.
- *
- * @access private
- * @return void
- */
- private function delete()
- {
- if(empty($this->objects)) return $this->log('No objects to delete.', __FILE__, __LINE__);
- $code = $this->getTableCode();
- $setCacheKey = $this->getSetCacheKey($code);
- $objectIdList = $this->cache->get($setCacheKey);
- if(!is_array($objectIdList)) return;
- $field = $this->getTableField();
- /* 把被删除的数据从缓存中删除。Delete the deleted data from cache. */
- $affectedKeys = [];
- foreach($this->objects as $object) $affectedKeys[] = $this->getRawCacheKey($code, $object->$field);
- $this->cache->deleteMultiple($affectedKeys);
- /* 把被删除的数据的 id 从缓存中删除。Delete the id of the deleted data from cache. */
- $this->cache->set($setCacheKey, array_diff($objectIdList, array_map(function($object) use ($field) { return $object->$field; }, $this->objects)));
- if(empty($this->config->cache->res[$this->table])) return;
- /* 删除受影响的缓存。Delete the affected cache. */
- $this->deleteAffectedCache($this->objects);
- }
- /**
- * 删除受影响的缓存。
- * Delete the affected cache.
- *
- * @param array $objects 受影响的对象列表。
- * @access private
- * @return void
- */
- private function deleteAffectedCache($objects)
- {
- /* 根据受影响的数据查找受影响的缓存。Find the affected cache by the affected data. */
- $keys = [];
- foreach($this->config->cache->res[$this->table] as $res)
- {
- $res = (object)$res;
- /* 如果没有设置关联字段则整个缓存都受影响。If no associated fields are set, the entire cache is affected. */
- if(empty($res->fields))
- {
- $keys[] = $this->getResCacheKey($res->name);
- continue;
- }
- /* 根据关联字段查找受影响的缓存。Find the affected cache by the associated fields. */
- foreach($objects as $object)
- {
- $key = $this->getResCacheKey($res->name);
- foreach($res->fields as $field)
- {
- if(!isset($object->$field)) return $this->log("Field {$field} does not exist in table {$this->table}.", __FILE__, __LINE__);
- $key .= $this->connector . $object->$field;
- }
- $keys[] = $key;
- }
- }
- /* 删除受影响的缓存。Delete the affected cache. */
- $this->cache->deleteMultiple($keys);
- }
- /**
- * 执行数据库查询操作。
- * Execute database query operation.
- *
- * @param string $sql SQL语句。
- * @param string $function 查询函数。
- * @param string $field 字段名。
- * @access private
- * @return array|object
- */
- private function query($sql, $function = 'fetchAll', $field = '')
- {
- $rows = $this->dao->query($sql)->$function();
- if($function == 'fetchAll' && !empty($field))
- {
- $objects = [];
- foreach($rows as $row) $objects[$row->$field] = $row;
- return $objects;
- }
- return $rows;
- }
- /**
- * 检查表是否有缓存设置。
- * Check if the table has cache settings.
- *
- * @param string $table 表名。
- * @access private
- * @return bool
- */
- private function checkTable($table = '')
- {
- if(empty($table)) $table = $this->table;
- return !empty($this->config->cache->raw[$table]);
- }
- /**
- * 记录日志信息。
- * Record log information.
- *
- * @param string $message 日志信息。
- * @param string $file 文件名。
- * @param string $line 行号。
- * @access private
- * @return false
- */
- private function log($message, $file, $line)
- {
- if(!$this->config->debug) return false;
- $runMode = PHP_SAPI == 'cli' ? '_cli' : '';
- $logFile = $this->app->getLogRoot() . 'cache' . $runMode . '.' . date('Ymd') . '.log.php';
- if(!file_exists($logFile)) file_put_contents($logFile, '<?php die(); ?' . ">\n");
- $content = date('Ymd H:i:s') . ': ' . $this->getURI() . "\nError: {$message} in $file on line $line\n";
- file_put_contents($logFile, $content, FILE_APPEND);
- if($this->config->debug >= 2) $this->app->triggerError($message, __FILE__, __LINE__, true);
- return false;
- }
- /**
- * 获取 URI。
- * Get URI.
- *
- * @access private
- * @return string
- */
- private function getURI()
- {
- $uri = $this->app->getURI();
- if($uri) return $uri;
- if($this->config->requestType == 'GET') return $_SERVER['REQUEST_URI'];
- if($this->config->requestType == 'PATH_INFO' || $this->config->requestType == 'PATH_INFO2')
- {
- $pathInfo = $this->app->getPathInfo();
- if(empty($pathInfo)) return '';
- $dotPos = strrpos($pathInfo, '.');
- if($dotPos) return substr($pathInfo, 0, $dotPos);
- return $pathInfo;
- }
- return '';
- }
- /**
- * 初始化指定表的缓存。
- * Initialize the cache of the specified table.
- *
- * @access private
- * @return array
- */
- private function initTableCache()
- {
- $field = $this->getTableField();
- $sql = $this->dao->select('*')->from($this->table)->sqlobj->get();
- $objects = $this->query($sql, 'fetchAll', $field);
- if(!$objects) return [];
- $values = [];
- $code = $this->getTableCode();
- foreach($objects as $key => $object)
- {
- $rawCacheKey = $this->getRawCacheKey($code, $key);
- $values[$rawCacheKey] = $object;
- }
- $this->cache->setMultiple($values);
- $setCacheKey = $this->getSetCacheKey($code);
- $this->cache->set($setCacheKey, array_keys($objects));
- return $objects;
- }
- /**
- * 生成缓存键。
- * Generate cache key.
- *
- * @param mixed ...$args 缓存键的参数。
- * @access public
- * @return string
- */
- public function createKey(...$args)
- {
- return $this->namespace . $this->connector . implode($this->connector, $args);
- }
- /**
- * 从缓存中获取指定表指定 id 的数据。
- * Get the data of the specified table and id from the cache.
- *
- * @param string $table 表名。
- * @param int|string $id 主键值。
- * @access public
- * @return object|false
- */
- public function fetch($table, $id)
- {
- if($this->status == 'disabled') return null;
- if(!$this->checkTable($table)) return $this->log("Table {$table} is not set in the cache configuration", __FILE__, __LINE__);
- if(empty($table)) return $this->log('The table name is empty', __FILE__, __LINE__);
- if(empty($id)) return $this->log('The id is empty', __FILE__, __LINE__);
- $this->setTable($table);
- $code = $this->getTableCode();
- $key = $this->getRawCacheKey($code, $id);
- $object = $this->cache->get($key);
- if($object) return $object;
- $objects = $this->initTableCache();
- return isset($objects[$id]) ? $objects[$id] : null;
- }
- /**
- * 从缓存中获取指定表的所有数据。
- * Get all data of the specified table from the cache.
- *
- * @param string $table 表名。
- * @param array $objectIdList 主键值列表。
- * @access public
- * @return array
- */
- public function fetchAll($table, $objectIdList = [])
- {
- if($this->status == 'disabled') return [];
- if(!$this->checkTable($table)) return $this->log("Table {$table} is not set in the cache configuration", __FILE__, __LINE__);
- if(empty($table)) return $this->log('The table name is empty', __FILE__, __LINE__);
- $this->setTable($table);
- $code = $this->getTableCode();
- /* 尝试获取指定表的所有主键字段的值。Try to get the values of all primary key fields of the specified table. */
- $setCacheKey = $this->getSetCacheKey($code);
- $allObjectIdList = $this->cache->get($setCacheKey);
- /* 如果主键字段的值为空,则初始化指定表的缓存。If the value of the primary key field is empty, initialize the cache of the specified table. */
- if(!$allObjectIdList)
- {
- $allData = $this->initTableCache();
- if(empty($objectIdList)) return $allData;
- return array_intersect_key($allData, $objectIdList);
- }
- /* 如果主键字段的值不为空,则从缓存中获取数据。If the value of the primary key field is not empty, get the data from the cache. */
- if(empty($objectIdList)) $objectIdList = $allObjectIdList;
- $keys = [];
- foreach($objectIdList as $objectID)
- {
- if(!$objectID) continue;
- $keys[$objectID] = $this->getRawCacheKey($code, $objectID);
- }
- $objects = $this->cache->getMultiple(array_values($keys));
- /* 如果缓存中没有全部的数据,则从数据库中获取缺失的数据。If not all data in cache, get the missing data from the database. */
- if(count($keys) > count($objects))
- {
- $lostObjects = [];
- $diffIdList = array_keys(array_diff($keys, array_keys($objects)));
- $sql = $this->dao->select('*')->from($table)->where('id')->in($diffIdList)->sqlobj->get();
- $diffObjects = $this->query($sql, 'fetchAll');
- foreach($diffObjects as $object)
- {
- $rawCacheKey = $this->getRawCacheKey($code, $object->id);
- $lostObjects[$rawCacheKey] = $object;
- }
- /* 把缺失的数据保存到缓存中。Save the missing data to cache. */
- $this->cache->setMultiple($lostObjects);
- $objects += $lostObjects;
- }
- if(!$objects) return [];
- $result = [];
- $field = $this->getTableField();
- foreach($objects as $object) $result[$object->$field] = $object;
- return $result;
- }
- /**
- * 从自动缓存的计算结果中获取符合查询条件的数据。
- * Get data that meets the query conditions from the calculation results of the automatic cache.
- *
- * @param string $table 表名。
- * @param array $conditions 查询条件。
- * @access public
- * @return array
- */
- public function fetchAutoCache($table, $conditions)
- {
- if($this->status == 'disabled') return [];
- if(!$this->checkTable($table)) return $this->log("Table {$table} is not set in the cache configuration", __FILE__, __LINE__);
- $conditions = array_filter($conditions, function($condition)
- {
- return $condition['operator'] == 'eq';
- });
- if(empty($conditions)) return [];
- $this->setTable($table);
- /* 按字段排序查询条件以确保缓存的唯一性。Sort the query conditions by field to ensure the uniqueness of the cache. */
- usort($conditions, function($a, $b)
- {
- return strcmp($a['field'], $b['field']);
- });
- /* 根据查询条件生成缓存键。Generate a cache key based on the query conditions. */
- $values = array_column($conditions, 'value');
- $code = $this->getTableCode();
- $cacheKey = $this->createKey('cache', $code, 'auto', ...$values);
- /* 从缓存中获取符合查询条件的主键字段的值。Get the value of the primary key field that meets the query conditions from the cache. */
- $idList = $this->getByKey($cacheKey);
- if(is_null($idList))
- {
- /* 如果没有缓存,从数据库中获取符合查询条件的主键字段的值并更新缓存。If there is no cache, get the value of the primary key field that meets the query conditions from the database and update the cache. */
- $field = $this->getTableField();
- $dao = $this->dao->select($field)->from($table)->where('1=1');
- foreach($conditions as $condition) $dao->andWhere($condition['field'])->eq($condition['value']);
- $sql = $dao->sqlobj->get();
- $objects = $this->query($sql, 'fetchAll');
- foreach($objects as $object) $idList[] = $object->$field;
- $this->saveByKey($cacheKey, $idList);
- /* 把缓存键写入数据库以便执行 dao::exec() 时自动更新。Write the cache key to the database for automatic update when executing dao::exec(). */
- $fields = implode(',', array_column($conditions, 'field'));
- $sql = $this->dao->select('1')->from(TABLE_AUTOCACHE)->where('code')->eq($code)->andWhere('fields')->eq($fields)->sqlobj->get();
- $autoCache = $this->query($sql, 'fetch');
- if(!$autoCache)
- {
- $autoCache = new \stdClass();
- $autoCache->code = $code;
- $autoCache->fields = $fields;
- $sql = $this->dao->insert(TABLE_AUTOCACHE)->data($autoCache)->get();
- try
- {
- $this->dbh->exec($sql);
- }
- catch(PDOException $e)
- {
- $this->dao->sqlError($e);
- }
- }
- }
- if(!$idList) return [];
- /* 根据主键字段的值从缓存中获取数据。Get data from the cache according to the value of the primary key field. */
- return $this->fetchAll($table, $idList);
- }
- /**
- * 设置缓存键。
- * Set cache key.
- *
- * @param string $key 缓存键。
- * @param mixed ...$args 缓存键的参数。
- * @access public
- * @return object
- */
- public function key($key, ...$args)
- {
- if(empty($this->config->cache->keys[$key])) return $this->log("Key {$key} is not defined", __FILE__, __LINE__);
- $cache = $this->config->cache->keys[$key];
- if(!empty($cache->fields) && !empty($args))
- {
- $tableFields = $this->dao->descTable($cache->table);
- foreach($cache->fields as $index => $field)
- {
- if(!isset($tableFields[$field])) return $this->log("Field {$field} does not exist in table {$cache->table}", __FILE__, __LINE__);
- if(!isset($args[$index])) continue;
- $tableField = $tableFields[$field];
- if(stripos($tableField->type, 'int') !== false) $args[$index] = (int) $args[$index];
- if(stripos($tableField->type, 'float') !== false) $args[$index] = (float)$args[$index];
- if(stripos($tableField->type, 'decimal') !== false) $args[$index] = (float)$args[$index];
- if(stripos($tableField->type, 'double') !== false) $args[$index] = (float)$args[$index];
- }
- }
- $key = $this->getResCacheKey(constant($key));
- foreach($args as $arg) $key .= $this->connector . $arg;
- $this->setKey($key);
- return $this;
- }
- /**
- * 设置缓存标签。
- * Set cache label.
- *
- * @param string $label 缓存标签。
- * @access public
- * @return object
- */
- public function label($label)
- {
- if(empty($label)) return $this->log('The label is empty', __FILE__, __LINE__);
- if(empty($this->key)) return $this->log('The key is empty', __FILE__, __LINE__);
- if(isset($this->labels[$label])) return $this->log("Label {$label} already used", __FILE__, __LINE__);
- $this->labels[$label] = $this->key;
- return $this;
- }
- /**
- * 根据当前缓存键获取缓存。
- * Get cache according to the current cache key.
- *
- * @access public
- * @return mixed
- */
- public function get()
- {
- if($this->status == 'disabled') return null;
- if(empty($this->key)) return $this->log('The key is empty', __FILE__, __LINE__);
- return $this->cache->get($this->key);
- }
- /**
- * 根据指定缓存键获取缓存。
- * Get cache according to the specified cache key.
- *
- * @param string $key 缓存键。
- * @access public
- * @return mixed
- */
- public function getByKey($key)
- {
- if($this->status == 'disabled') return null;
- if(empty($key)) return $this->log('The key is empty', __FILE__, __LINE__);
- return $this->cache->get($key);
- }
- /**
- * 根据当前缓存键保存缓存。
- * Save cache according to the current cache key.
- *
- * @param mixed $value 缓存值。
- * @access public
- * @return bool
- */
- public function save($value)
- {
- if($this->status == 'disabled') return false;
- if(empty($this->key)) return $this->log('The key is empty', __FILE__, __LINE__);
- return $this->cache->set($this->key, $value);
- }
- /**
- * 根据指定缓存建保存缓存。
- * Save cache according to the specified cache key.
- *
- * @param string $key 缓存键。
- * @param mixed $value 缓存值。
- * @param int $ttl 缓存时间。
- * @access public
- * @return bool
- */
- public function saveByKey($key, $value, $ttl = 0)
- {
- if($this->status == 'disabled') return false;
- if(empty($key)) return $this->log('The key is empty', __FILE__, __LINE__);
- return $this->cache->set($key, $value, $ttl);
- }
- /**
- * 根据指定缓存标签保存缓存。
- * Save cache according to the specified cache label.
- *
- * @param string $label 缓存标签。
- * @param mixed $value 缓存值。
- * @access public
- * @return bool
- */
- public function saveByLabel($label, $value)
- {
- if($this->status == 'disabled') return false;
- if(empty($label)) return $this->log('The label is empty', __FILE__, __LINE__);
- if(empty($this->labels[$label])) return $this->log("Label {$label} does not exist", __FILE__, __LINE__);
- return $this->cache->set($this->labels[$label], $value);
- }
- /**
- * 重置缓存相关设置项。
- * Reset cache related settings.
- *
- * @access public
- * @return void
- */
- public function reset()
- {
- $this->setKey('');
- $this->setTable('');
- $this->setEvent('');
- $this->setWhere('');
- $this->setObjects([]);
- }
- /**
- * 执行数据库操作前准备更新缓存需要的设置项。
- * Prepare the settings required to update the cache before executing the database operation.
- *
- * @param string $table 表名。
- * @param string $event 事件。
- * @param string $sql SQL 语句。
- * @access public
- * @return void
- */
- public function prepare($table, $event, $sql)
- {
- $this->reset();
- if($this->status == 'disabled') return;
- if(!$this->checkTable($table)) return;
- if(empty($table)) return $this->log('Table name is required.', __FILE__, __LINE__);
- if(empty($event)) return $this->log('Event type is required.', __FILE__, __LINE__);
- if(empty($sql)) return $this->log('SQL statement is required.', __FILE__, __LINE__);
- $this->setTable($table);
- $this->setEvent($event);
- if($event == 'update' || $event == 'delete')
- {
- /* 获取 WHERE 子句的内容。Get the content of WHERE clause. */
- $whereLen = strlen(\DAO::WHERE);
- $wherePOS = strrpos($sql, \DAO::WHERE);
- $groupPOS = strrpos($sql, \DAO::GROUPBY);
- $havingPOS = strrpos($sql, \DAO::HAVING);
- $orderPOS = strrpos($sql, \DAO::ORDERBY);
- $limitPOS = strrpos($sql, \DAO::LIMIT);
- $splitPOS = $orderPOS ? $orderPOS : $limitPOS;
- $splitPOS = $havingPOS ? $havingPOS : $splitPOS;
- $splitPOS = $groupPOS ? $groupPOS : $splitPOS;
- $where = '';
- if($wherePOS)
- {
- if($splitPOS)
- {
- $where = substr($sql, $wherePOS + $whereLen, $splitPOS - $wherePOS - $whereLen);
- }
- else
- {
- $where = substr($sql, $wherePOS + $whereLen);
- }
- }
- /* 执行操作后数据已经被修改,所以需要提前获取被影响的数据。*/
- $field = $this->getTableField();
- $sql = $this->dao->select('*')->from($table)->beginIF($where)->where($where)->fi()->sqlobj->get();
- $objects = $this->query($sql, 'fetchAll', $field);
- $this->setWhere($where);
- $this->setObjects($objects);
- }
- }
- /**
- * 执行数据库操作后更新缓存。
- * Update the cache after executing the database operation.
- *
- * @access public
- * @return void
- */
- public function sync()
- {
- if($this->status == 'disabled') return;
- if(!$this->checkTable()) return;
- if(empty($this->table)) return $this->log('Table name is required.', __FILE__, __LINE__);
- if(empty($this->event)) return $this->log('Event type is required.', __FILE__, __LINE__);
- if($this->event == 'insert') $this->create();
- if($this->event == 'update') $this->update();
- if($this->event == 'delete') $this->delete();
- $this->reset();
- }
- /**
- * 清空缓存。
- * Clear cache.
- *
- * @access public
- * @return void
- */
- public function clear()
- {
- $this->setStatus('disabled');
- $this->cache->clear();
- $this->setStatus('normal');
- }
- /**
- * 关闭缓存连接。
- * Close cache connection.
- *
- * @access public
- * @return void
- */
- public function close()
- {
- if(method_exists($this->cache, 'close')) $this->cache->close();
- }
- /**
- * 获取内存使用情况。
- * Get memory usage.
- *
- * @param string $type
- * @return string
- */
- public function memory($type)
- {
- return $this->cache->memory($type);
- }
- }
|