在 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

图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"
}

图2

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

图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

图4

20、清空缓存,DELETE http://www.cmcp-api.localhost/v1/caches/flush/redisCache?tenantid=default&api_gateway_user_id=1 ,响应200,如图5

图5

21、查看Redis,发现不仅是Redis cache被全部删除了,且Redis 活动记录等数据也被全部删除了,得出结论:redisCache组件中flush()操作,删除Redis中的所有数据,如图6

图6

 

永夜