Implement deletion cache of RESTful applications in Yii 2 Starter Kit (get cache list (based on cache component ID), delete cache (based on cache component ID + cache key), clear the cache, that is, delete all data in a cache component ID)
1. Edit the cached controller class, \API\Controllers\CacheController.php
* @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. Create the data layer of the cached resource class (the corresponding model language package file), \common\models\redis\cache.php
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. Create the logical layer of the cached resource class, \common\logics\redis\cache.php
[
* '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. In the interface application, create a cached resource class, \API\Models\Redis\Cache.php
5. In the V1 module of the interface application, create the cached resource class, \api\modules\v1\models\redis\cache.php
6. In the V1 module of the interface application, create a cached controller class, define the model class, \api\modules\v1\controllers\cacheController.php
7. Create a parameter configuration file to get all the keys under a cache component. The cache API is not supported, so it is decided to return all the splicing rules of the keys based on the configuration, \common\config\params.php
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. Edit \common\config\base.php, and introduce the parameter configuration file, as shown in Figure 1
9. Create a method class that gets the cache list (get all keys under a cache component), \api\rests\cache\indexaction.php
* @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. Create a data serialization class that gets the cache list, \api\rests\cache\serializer.php
* @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. Add the routing configuration of obtaining the cache list, edit \api\config\_urlmanager.php
[
'class' => 'yii\rest\UrlRule',
'controller' => ['v1/cache'],
'only' => ['index', 'delete', 'flush'],
'extraPatterns' => [
'DELETE flush/{id}' => 'flush',
],
],
12. Gethttp://www.cmcp-api.localhost/v1/caches?tenantid=default&api_gateway_user_id=1&cache_component_name=redisCache, respond to success
{
"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. Deletehttp://www.cmcp-api.localhost/v1/caches/tenant:default?tenantid=default&api_gateway_user_id=1, response 404, as shown in Figure 2
{
"name": "Not Found",
"message": "页面未找到。",
"code": 0,
"status": 404,
"type": "yii\\web\\NotFoundHttpException"
}
14. Edit the routing configuration of the cache list, edit \api\config\_urlmanager.php, configure regular, indicating that the value of {id} is allowed to be any letter, number, underscore, comma, colon (comma, colon cannot be used as the opening character)
[
'class' => 'yii\rest\UrlRule',
'controller' => ['v1/cache'],
'only' => ['index', 'delete', 'flush'],
'extraPatterns' => [
'DELETE flush/{id}' => 'flush',
],
'tokens' => ['{id}' => ''],
],
15. Create an Action class, which is the base class of the action class of the RESTful API, \API\RESTS\Cache\Action.php
* @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. Create a method class that deletes the cache (based on the cache component ID + cache key), \api\rests\cache\deleteAction.php
* @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 the cache, deletehttp://www.cmcp-api.localhost/v1/caches/tenant:default?tenantid=default&api_gateway_user_id=1&cache_component_name=redisCache, response 200, as shown in Figure 3
18. Create a method class to clear the cache, that is, to delete all the data in a cache component ID, \api\rests\cache\flushaction.php
* @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. Check Redis, including Redis Cache, Redis activity records and other data, as shown in Figure 4
20. Clear the cache, deletehttp://www.cmcp-api.localhost/v1/caches/flush/redisCache?tenantid=default&api_gateway_user_id=1, response 200, as shown in Figure 5
21. Looking at Redis, it is found that not only the Redis cache has been deleted, but the data such as the Redis activity record have also been deleted.





