利用Redis 加速 Yii CDbAuthManager
公司的客服系统是用 Yii 开发的,权限系统是基于 Yii CDbAuthManager 开发的,随着权限项目的增加和权限组以及人员的增多,导致加入页面的时候打开很慢,因为没进入一个页面会去检查一下该用户对于该操作的权限。下面是用XHProf查看的结果部分截图,会发现CDbAuthManager::checkAccess 和CDbAuthManager::checkAccessRecursive 等CDbAuthManager 方法会调用很多次,而 CDbAuthManage 是基于数据库,所以每次调用还要去进行数据库的查询,这样难免会给性能带来瓶颈。(该图只要关注第一和第二列就可以了,其他列是优化过的结果且本机的测试数据库)。
利用 Redis 加速 Yii CDbAuthManager
再来看下CDbAuthManager::checkAccessRecursive这个方法的实现,这个方法会去递归的查询数据库来验证用户的授权项目。
protected function checkAccessRecursive($itemName, $userId, $params, $assignments) {
if (($item = $this->getAuthItem($itemName)) === null)
return false;
Yii::trace('Checking permission "' . $item->getName() . '"', 'system.web.auth.CDbAuthManager');
if ($this->executeBizRule($item->getBizRule(), $params, $item->getData())) {
if (in_array($itemName, $this->defaultRoles))
return true;
if (isset($assignments[$itemName])) {
$assignment = $assignments[$itemName];
if ($this->executeBizRule($assignment->getBizRule(), $params, $assignment->getData()))
return true;
}
$parents = $this->db->createCommand()
->select('parent')
->from($this->itemChildTable)
->where('child=:name', array(':name' => $itemName))
->queryColumn();
foreach ($parents as $parent) {
if ($this->checkAccessRecursive($parent, $userId, $params, $assignments))
return true;
}
}
return false;
}
CDbAuthManager的其他对授权项目的操作都是基于数据库的读写,具体源码实现:http://code.google.com/p/yii/source/browse/tags/1.1.10/framework/web/auth/CDbAuthManager.php
好了,现在要做的就是把CDbAuthManager中的对数据库的操作进行改装成缓存中的操作,这样就可以大大的提高验证时的执行熟读了,同时加一个生成缓存的脚本:/protected/commands/AuthCacheCommand.php 来跑一下这个脚本生成缓存数据。 表对于的 Redis 的数据结构主要是:
- 表:auth_item_child =>;Redis Set
- 表:auth_item => Redis String
- 表:auth_assignment => Redis Hash
AuthCacheCommand.php 源码:
<?php
class AuthCacheCommand extends CConsoleCommand {
public function run($args) {
$items = Yii::app()->db->createCommand()
->select('*')
->from('kf_auth_item_child')
->queryAll();
foreach ($items as $item) {
$item['parent'] = strtolower($item['parent']);
$item['child'] = strtolower($item['child']);
Yii::app()->redis->sAdd("authItemChild:" . $item['parent'], $item['child']);
Yii::app()->redis->sAdd("authItemChildParent:" . $item['child'], $item['parent']);
}
$rows = Yii::app()->db->createCommand()
->select()
->from('kf_auth_item')
->queryAll();
foreach ($rows as $row) {
if (($data = @unserialize($row['data'])) === false)
$data = null;
$cache = array(
'type' => $row['type'],
'description' => $row['description'],
'bizrule' => $row['bizrule'],
'data' => serialize($data)
);
Yii::app()->redis->set('authItem:' . strtolower($row['name']), serialize($cache));
}
}
}
改装后的CDbAuthManager源码:
<?php
class UCDbAuthManager extends CAuthManager {
/**
* @var string the ID of the {@link CDbConnection} application component. Defaults to 'db'.
* The database must have the tables as declared in "framework/web/auth/*.sql".
*/
public $connectionID = 'db';
/**
* @var string the name of the table storing authorization items. Defaults to 'AuthItem'.
*/
public $itemTable = 'AuthItem';
/**
* @var string the name of the table storing authorization item hierarchy. Defaults to 'AuthItemChild'.
*/
public $itemChildTable = 'AuthItemChild';
/**
* @var string the name of the table storing authorization item assignments. Defaults to 'AuthAssignment'.
*/
public $assignmentTable = 'AuthAssignment';
/**
* @var CDbConnection the database connection. By default, this is initialized
* automatically as the application component whose ID is indicated as {@link connectionID}.
*/
public $connectionRedis = 'redis';
public $db;
private $_usingSqlite;
public $redis;
private static $_data;
/**
* Initializes the application component.
* This method overrides the parent implementation by establishing the database connection.
*/
public function init() {
parent::init();
$this->getRedisConnection();
$this->_usingSqlite = !strncmp($this->getDbConnection()->getDriverName(), 'sqlite', 6);
}
/**
* Performs access check for the specified user.
* @param string $itemName the name of the operation that need access check
* @param mixed $userId the user ID. This should can be either an integer and a string representing
* the unique identifier of a user. See {@link IWebUser::getId}.
* @param array $params name-value pairs that would be passed to biz rules associated
* with the tasks and roles assigned to the user.
* @return boolean whether the operations can be performed by the user.
*/
public function checkAccess($itemName, $userId, $params = array()) {
$assignments = $this->getAuthAssignments($userId);
return $this->checkAccessRecursive($itemName, $userId, $params, $assignments);
}
/**
* Performs access check for the specified user.
* This method is internally called by {@link checkAccess}.
* @param string $itemName the name of the operation that need access check
* @param mixed $userId the user ID. This should can be either an integer and a string representing
* the unique identifier of a user. See {@link IWebUser::getId}.
* @param array $params name-value pairs that would be passed to biz rules associated
* with the tasks and roles assigned to the user.
* @param array $assignments the assignments to the specified user
* @return boolean whether the operations can be performed by the user.
* @since 1.1.3
*/
protected function checkAccessRecursive($itemName, $userId, $params, $assignments) {
$itemKey = md5($itemName . "|" . $userId . "|" . http_build_query($params) . "|" . serialize($assignments));
if (isset(self::$_data[$itemKey]))
return self::$_data[$itemKey];
if (($item = $this->getAuthItem($itemName)) === null) {
self::$_data[$itemKey] = false;
return false;
}
if ($this->executeBizRule($item->getBizRule(), $params, $item->getData())) {
if (in_array($itemName, $this->defaultRoles)) {
self::$_data[$itemKey] = true;
return true;
}
if (isset($assignments[$itemName])) {
$assignment = $assignments[$itemName];
if ($this->executeBizRule($assignment->getBizRule(), $params, $assignment->getData())) {
self::$_data[$itemKey] = true;
return true;
}
}
// 读取 set authItemChild 缓存
$parents = $this->redis->sMembers('authItemChildParent:' . strtolower($itemName));
foreach ($parents as $parent) {
//$this->redis->sAdd("authItemChild:" . $parent, $itemName);
if ($this->checkAccessRecursive($parent, $userId, $params, $assignments)) {
self::$_data[$itemKey] = true;
return true;
}
}
}
self::$_data[$itemKey] = false;
return false;
}
/**
* Adds an item as a child of another item.
* @param string $itemName the parent item name
* @param string $childName the child item name
* @throws CException if either parent or child doesn't exist or if a loop has been detected.
*/
public function addItemChild($itemName, $childName) {
if ($itemName === $childName)
throw new CException(Yii::t('yii', 'Cannot add "{name}" as a child of itself.', array('{name}' => $itemName)));
// 先从string authItem 缓存中读取
if ($this->redis->get('authItem:' . $itemName)) {
$rows[0] = unserialize($this->redis->get('authItem:' . $itemName));
$rows[0]['name'] = $itemName;
}
if ($this->redis->get('authItem:' . $childName)) {
$rows[1] = unserialize($this->redis->get('authItem:' . $childName));
$rows[1]['name'] = $childName;
}
if (count($rows) == 2) {
if ($rows[0]['name'] === $itemName) {
$parentType = $rows[0]['type'];
$childType = $rows[1]['type'];
} else {
$childType = $rows[0]['type'];
$parentType = $rows[1]['type'];
}
$this->checkItemChildType($parentType, $childType);
if ($this->detectLoop($itemName, $childName))
throw new CException(Yii::t('yii', 'Cannot add "{child}" as a child of "{name}". A loop has been detected.', array('{child}' => $childName, '{name}' => $itemName)));
$this->db->createCommand()
->insert($this->itemChildTable, array(
'parent' => $itemName,
'child' => $childName,
));
// 写入 set authItemChild 缓存
$this->redis->sAdd('authItemChild:' . strtolower($itemName), strtolower($childName));
$this->redis->sAdd('authItemChildParent:' . strtolower($childName), strtolower($itemName));
}
else {
exit();
throw new CException(Yii::t('yii', 'Either "{parent}" or "{child}" does not exist.', array('{child}' => $childName, '{parent}' => $itemName)));
}
}
/**
* Removes a child from its parent.
* Note, the child item is not deleted. Only the parent-child relationship is removed.
* @param string $itemName the parent item name
* @param string $childName the child item name
* @return boolean whether the removal is successful
*/
public function removeItemChild($itemName, $childName) {
// 删除对应的 set authItemChild 缓存
$this->redis->sRem('authItemChild:' . strtolower($itemName), strtolower($childName));
$this->redis->sRem('authItemChildParent:' . strtolower($childName), strtolower($itemName));
return $this->db->createCommand()
->delete($this->itemChildTable, 'parent=:parent AND child=:child', array(
':parent' => $itemName,
':child' => $childName
)) > 0;
}
/**
* Returns a value indicating whether a child exists within a parent.
* @param string $itemName the parent item name
* @param string $childName the child item name
* @return boolean whether the child exists
*/
public function hasItemChild($itemName, $childName) {
return $this->redis->sIsMember('authItemChild:' . strtolower($itemName), strtolower($childName));
}
/**
* Returns the children of the specified item.
* @param mixed $names the parent item name. This can be either a string or an array.
* The latter represents a list of item names (available since version 1.0.5).
* @return array all child items of the parent
*/
public function getItemChildren($names) {
$cacheChildren = array();
if (is_string($names)) {
$condition = 'parent=' . $this->db->quoteValue($names);
//取缓存
$cacheChildren[] = $this->redis->sMembers('authItemChild:' . strtolower($names));
} else if (is_array($names) && $names !== array()) {
foreach ($names as &$name) {
$name = $this->db->quoteValue($name);
//取缓存
$cacheChildren[] = $this->redis->sMembers('authItemChild:' . strtolower($name));
}
$condition = 'parent IN (' . implode(', ', $names) . ')';
}
$rows = array();
if (count($cacheChildren) >= 2) {
foreach ($cacheChildren as $cacheChild) {
foreach ($cacheChild as $child) {
$tmp = unserialize($this->redis->get('authItem:' . $child));
$tmp['name'] = $child;
$rows[] = $tmp;
}
}
} else {
$rows = $this->db->createCommand()
->select('name, type, description, bizrule, data')
->from(array(
$this->itemTable,
$this->itemChildTable
))
->where($condition . ' AND name=child')
->queryAll();
}
$children = array();
foreach ($rows as $row) {
if (($data = @unserialize($row['data'])) === false)
$data = null;
$children[$row['name']] = new CAuthItem($this, $row['name'], $row['type'], $row['description'], $row['bizrule'], $data);
}
return $children;
}
/**
* Assigns an authorization item to a user.
* @param string $itemName the item name
* @param mixed $userId the user ID (see {@link IWebUser::getId})
* @param string $bizRule the business rule to be executed when {@link checkAccess} is called
* for this particular authorization item.
* @param mixed $data additional data associated with this assignment
* @return CAuthAssignment the authorization assignment information.
* @throws CException if the item does not exist or if the item has already been assigned to the user
*/
public function assign($itemName, $userId, $bizRule = null, $data = null) {
if ($this->usingSqlite() && $this->getAuthItem($itemName) === null)
throw new CException(Yii::t('yii', 'The item "{name}" does not exist.', array('{name}' => $itemName)));
$this->db->createCommand()
->insert($this->assignmentTable, array(
'itemname' => $itemName,
'userid' => $userId,
'bizrule' => $bizRule,
'data' => serialize($data)
));
// 同时写入hash authAssignment缓存
$assignment = new CAuthAssignment($this, $itemName, $userId, $bizRule, $data);
$this->redis->hSet('authAssignment:' . $userId, $itemName, serialize($assignment));
return $assignment;
}
/**
* Revokes an authorization assignment from a user.
* @param string $itemName the item name
* @param mixed $userId the user ID (see {@link IWebUser::getId})
* @return boolean whether removal is successful
*/
public function revoke($itemName, $userId) {
// 同时删除 hash authAssignment缓存
$this->redis->hDel('authAssignment:' . $userId, $itemName);
$result = $this->db->createCommand()
->delete($this->assignmentTable, 'itemname=:itemname AND userid=:userid', array(
':itemname' => $itemName,
':userid' => $userId
));
return $result;
}
/**
* Returns a value indicating whether the item has been assigned to the user.
* @param string $itemName the item name
* @param mixed $userId the user ID (see {@link IWebUser::getId})
* @return boolean whether the item has been assigned to the user.
*/
public function isAssigned($itemName, $userId) {
return $this->redis->hGet('authAssignment:' . $userId, $itemName);
}
/**
* Returns the item assignment information.
* @param string $itemName the item name
* @param mixed $userId the user ID (see {@link IWebUser::getId})
* @return CAuthAssignment the item assignment information. Null is returned if
* the item is not assigned to the user.
*/
public function getAuthAssignment($itemName, $userId) {
// 首先从hash authAssignment缓存中读取
if ($this->redis->hGet('authAssignment:' . $userId, $itemName)) {
return unserialize($this->redis->hGet('authAssignment:' . $userId, $itemName));
} else {
// 读库
$row = $this->db->createCommand()
->select()
->from($this->assignmentTable)
->where('itemname=:itemname AND userid=:userid', array(
':itemname' => $itemName,
':userid' => $userId))
->queryRow();
if ($row !== false) {
if (($data = @unserialize($row['data'])) === false)
$data = null;
// 同时写到hash authAssignment缓存中
$assignment = new CAuthAssignment($this, $row['itemname'], $row['userid'], $row['bizrule'], $data);
$this->redis->hSet('authAssignment:' . $userId, $row['itemname'], serialize($assignment));
return $assignment;
}
else
return null;
}
}
/**
* Returns the item assignments for the specified user.
* @param mixed $userId the user ID (see {@link IWebUser::getId})
* @return array the item assignment information for the user. An empty array will be
* returned if there is no item assigned to the user.
*/
public function getAuthAssignments($userId) {
if (true || !$this->redis->hLen('authAssignment:' . $userId)) {
// 没有 hash authAssignment 缓存 则读库
$rows = $this->db->createCommand()
->select()
->from($this->assignmentTable)
->where('userid=:userid', array(':userid' => $userId))
->queryAll();
$assignments = array();
foreach ($rows as $row) {
if (($data = @unserialize($row['data'])) === false)
$data = null;
$assignments[$row['itemname']] = new CAuthAssignment($this, $row['itemname'], $row['userid'], $row['bizrule'], $data);
// 写入 hash authAssignment 缓存
$this->redis->hSet('authAssignment:' . $userId, $row['itemname'], serialize($assignments[$row['itemname']]));
}
}else {
// 有 hash authAssignment 缓存 则读缓存
$assignments = array();
$rows = $this->redis->hGetAll('authAssignment:' . $userId);
foreach ($rows as $key => $value) {
$assignments[$key] = unserialize($value);
}
}
return $assignments;
}
/**
* Saves the changes to an authorization assignment.
* @param CAuthAssignment $assignment the assignment that has been changed.
*/
public function saveAuthAssignment($assignment) {
$this->db->createCommand()
->update($this->assignmentTable, array(
'bizrule' => $assignment->getBizRule(),
'data' => serialize($assignment->getData()),
), 'itemname=:itemname AND userid=:userid', array(
'itemname' => $assignment->getItemName(),
'userid' => $assignment->getUserId()
));
// 更新AuthAssignment 的同时更新 用户的hash authAssignment缓存
if (($data = $assignment->getData()) === false)
$data = null;
$this->redis->hDel('authAssignment:' . $assignment->getUserId(), $assignment->getItemName());
$assignments = new CAuthAssignment($this, $assignment->getItemName(), $assignment->getUserId(), $assignment->getBizRule(), $data);
$this->redis->hSet('authAssignment:' . $assignment->getUserId(), $assignment->getItemName(), serialize($assignments));
}
/**
* Returns the authorization items of the specific type and user.
* @param integer $type the item type (0: operation, 1: task, 2: role). Defaults to null,
* meaning returning all items regardless of their type.
* @param mixed $userId the user ID. Defaults to null, meaning returning all items even if
* they are not assigned to a user.
* @return array the authorization items of the specific type.
*/
public function getAuthItems($type = null, $userId = null) {
if ($type === null && $userId === null) {
$command = $this->db->createCommand()
->select()
->from($this->itemTable);
} else if ($userId === null) {
$command = $this->db->createCommand()
->select()
->from($this->itemTable)
->where('type=:type', array(':type' => $type));
} else if ($type === null) {
$command = $this->db->createCommand()
->select('name,type,description,t1.bizrule,t1.data')
->from(array(
$this->itemTable . ' t1',
$this->assignmentTable . ' t2'
))
->where('name=itemname AND userid=:userid', array(':userid' => $userId));
} else {
$command = $this->db->createCommand()
->select('name,type,description,t1.bizrule,t1.data')
->from(array(
$this->itemTable . ' t1',
$this->assignmentTable . ' t2'
))
->where('name=itemname AND type=:type AND userid=:userid', array(
':type' => $type,
':userid' => $userId
));
}
$items = array();
foreach ($command->queryAll() as $row) {
if (($data = @unserialize($row['data'])) === false)
$data = null;
$items[$row['name']] = new CAuthItem($this, $row['name'], $row['type'], $row['description'], $row['bizrule'], $data);
}
return $items;
}
/**
* Creates an authorization item.
* An authorization item represents an action permission (e.g. creating a post).
* It has three types: operation, task and role.
* Authorization items form a hierarchy. Higher level items inheirt permissions representing
* by lower level items.
* @param string $name the item name. This must be a unique identifier.
* @param integer $type the item type (0: operation, 1: task, 2: role).
* @param string $description description of the item
* @param string $bizRule business rule associated with the item. This is a piece of
* PHP code that will be executed when {@link checkAccess} is called for the item.
* @param mixed $data additional data associated with the item.
* @return CAuthItem the authorization item
* @throws CException if an item with the same name already exists
*/
public function createAuthItem($name, $type, $description = '', $bizRule = null, $data = null) {
$this->db->createCommand()
->insert($this->itemTable, array(
'name' => $name,
'type' => $type,
'description' => $description,
'bizrule' => $bizRule,
'data' => serialize($data)
));
// 写入 string authItem缓存
$cache = array(
'type' => $type,
'description' => $description,
'bizrule' => $bizRule,
'data' => serialize($data)
);
$this->redis->set('authItem:' . $name, serialize($cache));
return new CAuthItem($this, $name, $type, $description, $bizRule, $data);
}
/**
* Removes the specified authorization item.
* @param string $name the name of the item to be removed
* @return boolean whether the item exists in the storage and has been removed
*/
public function removeAuthItem($name) {
if ($this->usingSqlite()) {
$this->db->createCommand()
->delete($this->itemChildTable, 'parent=:name1 OR child=:name2', array(
':name1' => $name,
':name2' => $name
));
// 删除 set 为 $name 的 authItemChild 缓存
$this->redis->delete('authItemChild:' . strtolower($name));
$this->redis->delete('authItemChildParent:' .strtolower($name));
$this->db->createCommand()
->delete($this->assignmentTable, 'itemname=:name', array(
':name' => $name,
));
// 删除 hkey 为 $name 的 uathAssignment 缓存
$keys = $this->redis->keys("authAssignment:*");
if ($keys) {
foreach ($keys as $key) {
$hKeys = $this->redis->hKeys($key);
if ($hKeys) {
foreach ($hKeys as $hkey) {
if ($hkey == $name) {
$this->redis->hDel($key, $hkey);
}
}
}
}
}
}
// 删除 set authItem 缓存
$this->redis->delete('authItem:' . $name);
return $this->db->createCommand()
->delete($this->itemTable, 'name=:name', array(
':name' => $name
)) > 0;
}
/**
* Returns the authorization item with the specified name.
* @param string $name the name of the item
* @return CAuthItem the authorization item. Null if the item cannot be found.
*/
public function getAuthItem($name) {
if ($this->redis->get('authItem:' . $name)) {
// 先读取 string authItem缓存
$row = unserialize($this->redis->get('authItem:' . $name));
$row['name'] = $name;
} else {
$row = $this->db->createCommand()
->select()
->from($this->itemTable)
->where('name=:name', array(':name' => $name))
->queryRow();
}
if ($row !== false) {
if (($data = @unserialize($row['data'])) === false)
$data = null;
//回写缓存
$cache = array(
'type' => $row['type'],
'description' => $row['description'],
'bizrule' => $row['bizrule'],
'data' => serialize($data),
);
$this->redis->set('authItem:' . $name, serialize($cache));
return new CAuthItem($this, $row['name'], $row['type'], $row['description'], $row['bizrule'], $data);
}
else
return null;
}
/**
* Saves an authorization item to persistent storage.
* @param CAuthItem $item the item to be saved.
* @param string $oldName the old item name. If null, it means the item name is not changed.
*/
public function saveAuthItem($item, $oldName = null) {
if ($this->usingSqlite() && $oldName !== null && $item->getName() !== $oldName) {
$this->db->createCommand()
->update($this->itemChildTable, array(
'parent' => $item->getName(),
), 'parent=:whereName', array(
':whereName' => $oldName,
));
$this->db->createCommand()
->update($this->itemChildTable, array(
'child' => $item->getName(),
), 'child=:whereName', array(
':whereName' => $oldName,
));
// 更新 set authItemChild 缓存
$children = $this->redis->sMembers('authItemChild:' . strtolower($oldName));
$this->redis->delete('authItemChild:' . strtolower($oldName));
$this->redis->sAdd('authItemChild:' . strtolower($item->getName()), strtolower($children));
$parents = $this->redis->sMembers('authItemChildParent:' . strtolower($oldName));
$this->redis->delete('authItemChildParent:' . strtolower($oldName));
$this->redis->sAdd('authItemChildParent:' . strtolower($item->getName()), strtolower($parents));
$this->db->createCommand()
->update($this->assignmentTable, array(
'itemname' => $item->getName(),
), 'itemname=:whereName', array(
':whereName' => $oldName,
));
// 同时更新 hash uathAssignment 缓存 中hkey为$oldName的缓存
$keys = $this->redis->keys("authAssignment:*");
if ($keys) {
foreach ($keys as $key) {
$hKeys = $this->redis->hKeys($key);
if ($hKeys) {
foreach ($hKeys as $hkey) {
if ($hkey == $oldName) {
$value = $this->redis->hGet($key, $hkey);
$this->redis->hDel($key, $hkey);
$this->redis->hSet($key, $item->getName(), $value);
}
}
}
}
}
}
$this->db->createCommand()
->update($this->itemTable, array(
'name' => $item->getName(),
'type' => $item->getType(),
'description' => $item->getDescription(),
'bizrule' => $item->getBizRule(),
'data' => serialize($item->getData()),
), 'name=:whereName', array(
':whereName' => $oldName === null ? $item->getName() : $oldName,
));
// 更新string authItem 缓存
$name = $oldName === null ? $item->getName() : $oldName;
$value = $this->redis->get('authItem:' . $name);
if ($value) {
$this->redis->delete('authItem:' . $name);
$cache = array(
'type' => $item->getType(),
'description' => $item->getDescription(),
'bizrule' => $item->getBizRule(),
'data' => serialize($item->getData()),
);
$this->redis->set('authItem:' . $item->getName(), serialize($cache));
}
}
/**
* Saves the authorization data to persistent storage.
*/
public function save() {
}
/**
* Removes all authorization data.
*/
public function clearAll() {
$this->clearAuthAssignments();
$this->db->createCommand()->delete($this->itemChildTable);
// 删除所有set 缓存
$this->deleteAllRedisKeys("authItemChild:*");
$this->deleteAllRedisKeys("authItemChildParent:*");
$this->db->createCommand()->delete($this->itemTable);
// 删除所有string authItem 缓存
$this->deleteAllRedisKeys("authItem:*");
}
/**
* Removes all authorization assignments.
*/
public function clearAuthAssignments() {
$this->db->createCommand()->delete($this->assignmentTable);
// 删除所有hash authAssignment 缓存
$this->deleteAllRedisKeys("authAssignment:*");
}
/**
* Checks whether there is a loop in the authorization item hierarchy.
* @param string $itemName parent item name
* @param string $childName the name of the child item that is to be added to the hierarchy
* @return boolean whether a loop exists
*/
protected function detectLoop($itemName, $childName) {
if ($childName === $itemName)
return true;
foreach ($this->getItemChildren($childName) as $child) {
if ($this->detectLoop($itemName, $child->getName()))
return true;
}
return false;
}
/**
* @return CDbConnection the DB connection instance
* @throws CException if {@link connectionID} does not point to a valid application component.
*/
protected function getDbConnection() {
if ($this->db !== null)
return $this->db;
else if (($this->db = Yii::app()->getComponent($this->connectionID)) instanceof CDbConnection)
return $this->db;
else
throw new CException(Yii::t('yii', 'CDbAuthManager.connectionID "{id}" is invalid. Please make sure it refers to the ID of a CDbConnection application component.', array('{id}' => $this->connectionID)));
}
protected function getRedisConnection() {
if ($this->redis !== null)
return $this->redis;
else if (($this->redis = Yii::app()->getComponent($this->connectionRedis)) instanceof URedis)
return $this->redis;
else
throw new CException(Yii::t('yii', 'UCDbAuthManager.connectionRedis "{id}" is invalid.', array('{id}' => $this->connectionRedis)));
}
/**
* @return boolean whether the database is a SQLite database
*/
protected function usingSqlite() {
return $this->_usingSqlite;
}
/**
* 删除所有的模糊匹配的redis key
* @param string $keyString
*/
protected function deleteAllRedisKeys($keyString) {
$keys = $this->redis->keys($keyString);
if ($keys) {
foreach ($keys as $key) {
$this->redis->delete($key);
}
}
}
}
加入配置文件:
'authManager' => array(
'class' => '你存放得位置/UCDbAuthManager',
'connectionID' => 'db',
'connectionRedis' => 'redis',
'itemTable' => 'kf_auth_item',
'assignmentTable' => 'kf_auth_assignment',
'itemChildTable' => 'kf_auth_item_child'
),
OK,结束!
转载请注明: 转载自Yuansir-web 菜鸟 | LAMP 学习笔记
本文链接地址: 利用 Redis 加速 Yii CDbAuthManager
本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可