在 Yii 2 Starter Kit 中实现 RESTful 应用的删除缓存(获取缓存列表(基于缓存组件ID)、删除缓存(基于缓存组件ID + 缓存键)、清空缓存,即删除某个缓存组件ID中的所有数据)
1、编辑缓存的控制器类,\api\controllers\CacheController.php
<?php namespace api\controllers; use yii\rest\ActiveController; /** * Class CacheController * @package api\controllers * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class CacheController extends ActiveController { public $serializer = [ 'class' => 'api\rests\cache\Serializer', 'collectionEnvelope' => 'items', ]; /** * @inheritdoc */ public function actions() { $actions = parent::actions(); // 禁用"view"、"create"、"update"、"options"动作 unset($actions['view'], $actions['create'], $actions['update'], $actions['options']); $actions['index']['class'] = 'api\rests\cache\IndexAction'; $actions['delete']['class'] = 'api\rests\cache\DeleteAction'; $actions['flush'] = [ 'class' => 'api\rests\cache\FlushAction', 'modelClass' => $this->modelClass, 'checkAccess' => [$this, 'checkAccess'], ]; return $actions; } }
2、创建缓存的资源类的数据层(相应的模型语言包文件),\common\models\redis\Cache.php
<?php namespace common\models\redis; use Yii; use common\components\redis\ActiveRecord; /** * This is the model class for table "{{%cache}}". * * @property int $id * @property string $cache_component_name 组件ID * @property string $key 缓存键 * @property string $value 缓存值 */ class Cache extends ActiveRecord { /** * @return array the list of attributes for this record */ public function attributes() { return ['id', 'cache_component_name', 'key', 'value']; } /** * @inheritdoc */ public function rules() { return [ [['id', 'cache_component_name', 'key', 'value'], 'safe'], ]; } /** * @inheritdoc */ public function attributeLabels() { return [ 'id' => Yii::t('model/redis/cache', 'ID'), 'cache_component_name' => Yii::t('model/redis/cache', 'Cache Component Name'), 'key' => Yii::t('model/redis/cache', 'Key'), 'value' => Yii::t('model/redis/cache', 'Value'), ]; } }
3、创建缓存的资源类的逻辑层,\common\logics\redis\Cache.php
<?php namespace common\logics\redis; use Yii; use common\logics\redis\CacheComponent as RedisCacheComponent; use yii\web\NotFoundHttpException; class Cache extends \common\models\redis\Cache { /** * 返回缓存组件下的所有key(拼接规则),键是缓存组件名,值是键名列表 * @param string $cacheComponentName 组件ID * @return array|false * * 格式如下: * * 缓存组件下的所有key * [ * 'tenantKey' => [ * 'key' => 'tenantKey' * 'value' => 'tenant:{tenantid}' * ] * 'idaKey' => [ * 'key' => 'idaKey' * 'value' => 'tenant:{tenantid}:ida:{uid}' * ] * ] * * 失败 * false */ function getCacheKeys($cacheComponentName) { $redisCacheComponent = new RedisCacheComponent(); $cacheComponents = $redisCacheComponent->getCacheComponents([$cacheComponentName]); if (empty($cacheComponents)) { return false; } $cacheKeys = []; if (isset(Yii::$app->params['cache'][$cacheComponentName])) { foreach (Yii::$app->params['cache'][$cacheComponentName]['keys'] as $k => $v) { $cacheKeys[$k] = ['key' => $k, 'value' => $v]; } } return $cacheKeys; } /** * @param $id * @return \yii\caching\Cache|null * @throws HttpException * @throws \yii\base\InvalidConfigException */ public static function getCacheComponent($id) { $redisCacheComponent = new RedisCacheComponent(); $cacheComponents = $redisCacheComponent->getCacheComponents(); if (!in_array($id, array_keys($cacheComponents))) { throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20015'), ['id' => $id])), 20015); } return Yii::$app->get($id); } }
4、在接口应用中,创建缓存的资源类,\api\models\redis\Cache.php
<?php namespace api\models\redis; class Cache extends \common\logics\redis\Cache { }
5、在接口应用的v1模块中,创建缓存的资源类,\api\modules\v1\models\redis\Cache.php
<?php namespace api\modules\v1\models\redis; class Cache extends \api\models\redis\Cache { }
6、在接口应用的v1模块中,创建缓存的控制器类,定义模型类,\api\modules\v1\controllers\CacheController.php
<?php namespace api\modules\v1\controllers; /** * Cache controller for the `v1` module */ class CacheController extends \api\controllers\CacheController { public $modelClass = 'api\modules\v1\models\redis\Cache'; }
7、创建参数配置文件,获取某缓存组件下的所有key,缓存 API 不支持,因此决定基于配置返回所有key的拼接规则,\common\config\params.php
<?php return [ 'adminEmail' => env('ADMIN_EMAIL'), 'robotEmail' => env('ROBOT_EMAIL'), 'availableLocales'=>[ 'en-US'=>'English (US)', 'ru-RU'=>'Русский (РФ)', 'uk-UA'=>'Українська (Україна)', 'es' => 'Español', 'vi' => 'Tiếng Việt', 'zh-CN' => '简体中文', 'pl-PL' => 'Polski (PL)', ], 'cache' => [ 'redisCache' => [ 'keys' => [ 'tenantKey' => 'tenant:{tenantid}', //多租户数据的缓存键 'idaKey' => 'tenant:{tenantid}:ida:{uid}', //权限中心数据的缓存键 ], ], ], ];
8、编辑 \common\config\base.php,引入参数配置文件,如图1
9、创建获取缓存列表的方法类(获取某缓存组件下的所有key),\api\rests\cache\IndexAction.php
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace api\rests\cache; use Yii; use yii\data\ArrayDataProvider; use yii\web\NotFoundHttpException; /** * IndexAction implements the API endpoint for listing multiple models. * * For more details and usage information on IndexAction, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class IndexAction extends \yii\rest\IndexAction { /** * Prepares the data provider that should return the requested collection of the models. * @return ActiveDataProvider */ protected function prepareDataProvider() { $requestParams = Yii::$app->getRequest()->getBodyParams(); if (empty($requestParams)) { $requestParams = Yii::$app->getRequest()->getQueryParams(); } $filter = null; if ($this->dataFilter !== null) { $this->dataFilter = Yii::createObject($this->dataFilter); if ($this->dataFilter->load($requestParams)) { $filter = $this->dataFilter->build(); if ($filter === false) { return $this->dataFilter; } } } if ($this->prepareDataProvider !== null) { return call_user_func($this->prepareDataProvider, $this, $filter); } /* @var $modelClass \yii\db\BaseActiveRecord */ $modelClass = $this->modelClass; $model = new $modelClass(); if (empty($requestParams['cache_component_name'])) { return ['code' => 20014, 'message' => Yii::t('error', '20014')]; } $allModels = $model->getCacheKeys($requestParams['cache_component_name']); if ($allModels === false) { throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20015'), ['id' => $requestParams['cache_component_name']])), 20015); } return Yii::createObject([ 'class' => ArrayDataProvider::className(), 'allModels' => $allModels, 'pagination' => [ 'params' => $requestParams, ], 'sort' => [ 'params' => $requestParams, ], ]); } }
10、创建获取缓存列表的数据序列化类,\api\rests\cache\Serializer.php
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace api\rests\cache; use Yii; use yii\data\DataProviderInterface; /** * Serializer converts resource objects and collections into array representation. * * Serializer is mainly used by REST controllers to convert different objects into array representation * so that they can be further turned into different formats, such as JSON, XML, by response formatters. * * The default implementation handles resources as [[Model]] objects and collections as objects * implementing [[DataProviderInterface]]. You may override [[serialize()]] to handle more types. * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class Serializer extends \yii\rest\Serializer { /** * Serializes a data provider. * @param DataProviderInterface $dataProvider * @return array the array representation of the data provider. */ protected function serializeDataProvider($dataProvider) { if ($this->preserveKeys) { $models = $dataProvider->getModels(); } else { $models = array_values($dataProvider->getModels()); } $models = $this->serializeModels($models); if (($pagination = $dataProvider->getPagination()) !== false) { $this->addPaginationHeaders($pagination); } if ($this->request->getIsHead()) { return null; } elseif ($this->collectionEnvelope === null) { return $models; } $result = [ $this->collectionEnvelope => $models, ]; if (empty($result['items'])) { return ['code' => 20016, 'message' => Yii::t('error', '20016')]; } if ($pagination !== false) { return ['code' => 10000, 'message' => Yii::t('app', '10008'), 'data' => array_merge($result, $this->serializePagination($pagination))]; } return ['code' => 10000, 'message' => Yii::t('app', '10008'), 'data' => $result]; } }
11、新增获取缓存列表的路由配置,编辑 \api\config\_urlManager.php
[ 'class' => 'yii\rest\UrlRule', 'controller' => ['v1/cache'], 'only' => ['index', 'delete', 'flush'], 'extraPatterns' => [ 'DELETE flush/{id}' => 'flush', ], ],
12、GET http://www.cmcp-api.localhost/v1/caches?tenantid=default&api_gateway_user_id=1&cache_component_name=redisCache ,响应成功
{ "code": 10000, "message": "获取缓存列表成功", "data": { "items": [ { "key": "tenantKey", "value": "tenant:{tenantid}" }, { "key": "idaKey", "value": "tenant:{tenantid}:ida:{uid}" } ], "_links": { "self": { "href": "http://www.cmcp-api.localhost/v1/caches?tenantid=default&api_gateway_user_id=1&cache_component_name=redisCache&page=1" } }, "_meta": { "totalCount": 2, "pageCount": 1, "currentPage": 1, "perPage": 20 } } }
13、DELETE http://www.cmcp-api.localhost/v1/caches/tenant:default?tenantid=default&api_gateway_user_id=1 ,响应404,如图2
{ "name": "Not Found", "message": "页面未找到。", "code": 0, "status": 404, "type": "yii\\web\\NotFoundHttpException" }
14、编辑获取缓存列表的路由配置,编辑 \api\config\_urlManager.php,配置正则,表示允许{id}的值为任意一个字母、数字、下划线、逗号、冒号所组成的字符串(逗号、冒号不能够做为开头字符)
[ 'class' => 'yii\rest\UrlRule', 'controller' => ['v1/cache'], 'only' => ['index', 'delete', 'flush'], 'extraPatterns' => [ 'DELETE flush/{id}' => 'flush', ], 'tokens' => ['{id}' => '<id:\\w[\\w,:]*>'], ],
15、创建Action类,其是实现RESTful API的动作类的基类,\api\rests\cache\Action.php
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace api\rests\cache; use Yii; use yii\db\ActiveRecordInterface; use yii\web\NotFoundHttpException; /** * Action is the base class for action classes that implement RESTful API. * * For more details and usage information on Action, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class Action extends \yii\rest\Action { /** * Returns the data model based on the primary key given. * If the data model is not found, a 404 HTTP exception will be raised. * @param string $id the ID of the model to be loaded. If the model has a composite primary key, * the ID must be a string of the primary key values separated by commas. * The order of the primary key values should follow that returned by the `primaryKey()` method * of the model. * @return ActiveRecordInterface the model found * @throws NotFoundHttpException if the model cannot be found */ public function findModel($id) { $requestParams = Yii::$app->getRequest()->getBodyParams(); if (empty($requestParams)) { $requestParams = Yii::$app->getRequest()->getQueryParams(); } if ($this->findModel !== null) { return call_user_func($this->findModel, $id, $this); } /* @var $modelClass ActiveRecordInterface */ $modelClass = $this->modelClass; if ($id !== null) { $model = $modelClass::getCacheComponent($id); } if (isset($model)) { return $model; } throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20015'), ['id' => $id])), 20015); } }
16、创建删除缓存的方法类(基于缓存组件ID + 缓存键),\api\rests\cache\DeleteAction.php
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace api\rests\cache; use Yii; use yii\web\NotFoundHttpException; use yii\web\ServerErrorHttpException; /** * DeleteAction implements the API endpoint for deleting a model. * * For more details and usage information on DeleteAction, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class DeleteAction extends Action { /** * Deletes a model. * @param mixed $id id of the model to be deleted. * @throws ServerErrorHttpException on failure. */ public function run($id) { $requestParams = Yii::$app->getRequest()->getBodyParams(); if (empty($requestParams)) { $requestParams = Yii::$app->getRequest()->getQueryParams(); } if (empty($requestParams['cache_component_name'])) { return ['code' => 20014, 'message' => Yii::t('error', '20014')]; } $model = $this->findModel($requestParams['cache_component_name']); if ($this->checkAccess) { call_user_func($this->checkAccess, $this->id, $model); } if ($model->get($id) === false) { throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20017'), ['key' => $id])), 20017); } if ($model->delete($id) === false) { throw new ServerErrorHttpException('Failed to delete the object for unknown reason.'); } return ['code' => 10000, 'message' => Yii::t('app', '10009')]; } }
17、删除缓存,DELETE http://www.cmcp-api.localhost/v1/caches/tenant:default?tenantid=default&api_gateway_user_id=1&cache_component_name=redisCache ,响应200,如图3
18、创建清空缓存,即删除某个缓存组件ID中的所有数据的方法类,\api\rests\cache\FlushAction.php
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace api\rests\cache; use Yii; use yii\web\NotFoundHttpException; use yii\web\ServerErrorHttpException; /** * DeleteAction implements the API endpoint for deleting a model. * * For more details and usage information on DeleteAction, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class FlushAction extends Action { /** * Deletes a model. * @param mixed $id id of the model to be deleted. * @throws ServerErrorHttpException on failure. */ public function run($id) { $model = $this->findModel($id); if ($this->checkAccess) { call_user_func($this->checkAccess, $this->id, $model); } if ($model->flush() === false) { throw new ServerErrorHttpException('Failed to delete the object for unknown reason.'); } return ['code' => 10000, 'message' => Yii::t('app', '10010')]; } }
19、查看Redis,包含Redis cache、Redis 活动记录等数据,如图4
20、清空缓存,DELETE http://www.cmcp-api.localhost/v1/caches/flush/redisCache?tenantid=default&api_gateway_user_id=1 ,响应200,如图5
21、查看Redis,发现不仅是Redis cache被全部删除了,且Redis 活动记录等数据也被全部删除了,得出结论:redisCache组件中flush()操作,删除Redis中的所有数据,如图6
近期评论