rootlocal/yii2-crud

View on GitHub
src/controllers/ActiveController.php

Summary

Maintainability
A
2 hrs
Test Coverage
B
88%
<?php

namespace rootlocal\crud\controllers;

use yii\helpers\ArrayHelper;
use rootlocal\crud\components\SearchModelInterface;
use rootlocal\crud\components\Controller;
use rootlocal\crud\actions\CreateAction;
use rootlocal\crud\actions\DeleteAction;
use rootlocal\crud\actions\IndexAction;
use rootlocal\crud\actions\UpdateAction;
use rootlocal\crud\actions\ValidateAction;
use rootlocal\crud\actions\ViewAction;
use yii\data\ActiveDataProvider;

/**
 * Base CRUD Controller
 *
 * The class of the ActiveRecord should be specified via [[modelClass]], [[modelSearchClass]]
 * which must implement [[\yii\db\ActiveRecordInterface]]. By default, the following actions are supported:
 *
 * - `index`: list of models
 * - `view`: return the details of a model
 * - `create`: create a new model
 * - `update`: update an existing model
 * - `delete`: delete an existing model
 * - `validate`: validate model
 *
 * Example:
 *
 * ```php
 * namespace rootlocal\crud\test\app\models\controllers;
 *
 * use rootlocal\crud\test\app\models\db\Book;
 * use rootlocal\crud\test\app\models\search\BookSearch;
 *
 * class CrudController extends ActiveController
 * {
 *      public $modelClass = Book::class;
 *      public $modelSearchClass = BookSearch::class;
 *      public $updateScenario = Book::SCENARIO_DEFAULT;
 *      public $createScenario = Book::SCENARIO_DEFAULT;
 * }
 * ```
 *
 * You may disable some of these actions by overriding [[actions()]] and unsetting the corresponding actions.
 *
 * To add a new action, either override [[actions()]] by appending a new action class or write a new action method.
 * Make sure you also override [[verbs()]] to properly declare what HTTP methods are allowed by the new action.
 *
 * You should usually override [[checkAccess()]] to check whether the current user has the privilege to perform
 * the specified action against the specified model.
 *
 * @property string $modelClass string model class name
 * @property string $modelSearchClass string search model name
 *
 * @author Alexander Zakharov <sys@eml.ru>
 * @since 1.0.6
 * @package rootlocal\crud\controllers
 */
class ActiveController extends Controller
{
    /** @var array */
    private $_actions = [];
    /** @var array */
    private $_verbs = [];


    /**
     * {@inheritdoc}
     * @return array
     */
    public function verbs()
    {
        $actions = $this->actions();

        if (empty($this->_verbs) && !empty($actions)) {

            $verbs = [
                'index' => ['GET'],
                'view' => ['GET'],
                'create' => ['GET', 'POST'],
                'update' => ['GET', 'PUT', 'POST'],
                'delete' => ['POST', 'DELETE'],
                'validate' => ['POST'],
            ];

            $verbs = ArrayHelper::merge(parent::verbs(), $verbs);

            foreach ($verbs as $key => $value) {
                if (array_key_exists($key, $actions)) {
                    $this->_verbs[$key] = $value;
                }
            }
        }

        return $this->_verbs;
    }

    /**
     * Declares external actions for the controller
     *
     * {@inheritdoc}
     *
     * Examples:
     *
     * ```php
     * public function actions()
     * {
     *      $actions = parent::actions();
     *      unset($actions['delete'], $actions['create']);
     *      $actions['index']['dataProvider'] = [$this, 'getDataProvider'];
     *      return $actions;
     * }
     *
     * public function getDataProvider()
     * {
     * }
     * ```
     *
     * @return array
     */
    public function actions()
    {
        if (empty($this->_actions)) {
            $actions = [
                'index' => [
                    'class' => IndexAction::class,
                    'searchModel' => $this->modelSearchClass,
                    'checkAccess' => [$this, 'checkAccess'],
                    'dataProvider' => [$this, 'getDataProvider'],
                ],

                'view' => [
                    'class' => ViewAction::class,
                    'model' => $this->modelClass,
                    'checkAccess' => [$this, 'checkAccess'],
                ],

                'validate' => [
                    'class' => ValidateAction::class,
                    'model' => $this->modelClass,
                    'scenario' => $this->createScenario,
                    'checkAccess' => [$this, 'checkAccess'],
                ],

                'create' => [
                    'class' => CreateAction::class,
                    'model' => $this->modelClass,
                    'scenario' => $this->createScenario,
                    'checkAccess' => [$this, 'checkAccess'],
                ],

                'update' => [
                    'class' => UpdateAction::class,
                    'model' => $this->modelClass,
                    'scenario' => $this->updateScenario,
                    'checkAccess' => [$this, 'checkAccess'],
                ],

                'delete' => [
                    'class' => DeleteAction::class,
                    'model' => $this->modelClass,
                    'checkAccess' => [$this, 'checkAccess'],
                ],
            ];

            $this->_actions = ArrayHelper::merge(parent::actions(), $actions);
        }

        return $this->_actions;
    }

    /**
     * Creates data provider instance with search query applied
     *
     * @param SearchModelInterface $model ActiveRecord searchModel
     * @param array $queryParams The request GET parameter values.
     * @return ActiveDataProvider ActiveDataProvider object
     *
     * @see SearchModelInterface::search()
     * @see ActiveDataProvider
     */
    public function getDataProvider($model, $queryParams = []): ActiveDataProvider
    {
        return $model->search($queryParams);
    }

    /**
     * Checks the privilege of the current user.
     *
     * This method should be overridden to check whether the current user has the privilege
     * to run the specified action against the specified data model.
     * If the user does not have access, a [[\yii\web\ForbiddenHttpException]] should be thrown.
     *
     * Example:
     *
     * ```php
     * public function checkAccess($action, $model = null)
     * {
     *      if ($action === 'update' || $action === 'delete') {
     *          if ($model->author_id !== \Yii::$app->user->id){
     *              throw new \yii\web\ForbiddenHttpException(sprintf(
     *                  'You can only %s articles that you\'ve created.', $action));
     *          }
     *      }
     * }
     * ```
     *
     * @param string $action the ID of the action to be executed
     * @param object|null $model the model to be accessed. If null, it means no specific model is being accessed.
     */
    public function checkAccess($action, $model = null)
    {
    }

    /**
     * {@inheritdoc}
     * @return array
     */
    public function accessControl()
    {
        return parent::accessControl();
    }

}