myks92
@myks92
Нашёл решение — пометь вопрос ответом!

YII как сделать наследование CRUD операции от базового контроллера? Как использовать?

Всем привет! В проекте очень много повторяющихся действий для CRUD операций, много видов с однотипным кодом. Хочется это все упросить с помощью наследования или другого метода. Таким образом у нас получится единый круд, а динамические данные будем передавать параметрами. Есть ли что-то подобное? Как вообще это можно сделать? Ведь тогда нужно будет создавать лишь один контроллер, а виды будут сами подтягиваться, кроме формы и _columns

Может быть имеет смысл вынести CRUD действия контроллеров в классы?
  • Вопрос задан
  • 454 просмотра
Решения вопроса 2
butteff
@butteff
Раз в тысячу лет заправляю свитер в носки
Я что-то не понимаю, наверное, но ведь это классика - создать модель, где будут нужные методы, и использовать их в контроллере. Т.е. все CRUD операции держать в отдельном классе, которые будут в models, подключать этот класс в нужных контроллерах и использовать методы там (обращаясь к ним статически)

Пример:

в frontend/models создаете файл Crud.php:

namespace frontend\models;

Class Crud extends Model {
    public static function getData() {
        return ... // тут какие-нибудь вычисления или берем что-то из БД и т.п.
    }
}


После в любом контроллере подключаете эту модель:
use frontend\models\Crud;

И используете:
$some_res = Crud::getData();
Ответ написан
kimono
@kimono
Web developer
Я использую нечто такое:
abstract CrudController extends Controller {
  public $modelClass;
  public $searchModelClass;

  public function actionIndex(){
    $searchModel = new $this->searchModel;
    // ...
  }

  public function actionView($id){
    $model = $this->findModel($id);
    // ...
    return $this->render('view', ['model' => $model]);
  }
  public function actionCreate(){
    $model = new $this->modelClass;
    // ...
  }
  public function actionUpdate($id){
    $model = $this->findModel($id);
    // ...
  }
  public function actionDelete($id){
    $model = $this->findModel($id);
    // ...
  }
  private function findModel($id){
    $modelCLass = new $this->modelClass;
    $model = $modelClass::findOne($id);
    // ...
    return $model;
  }
}

class ProductController extends CrudController {
  public $modelClass = '\app\common\models\Product';
  public $searchModelClass = '\backend\modules\product\models\Product';
}

class ItemController extends CrudController {
  public $modelClass = '\app\common\models\Item';
  public $searchModelClass = '\backend\modules\product\models\Item';
}

Фишка в том, что если использовать разделение на модули, то и не нужно прописывать каждому контроллеру пути для вьюшек, все будет лежать в модулях на своих местах.

Так же можно добавить проверку прав доступа:
abstract CrudController extends Controller {
  public $permissions = [
    'index' => null,
    'view' => null,
    'create' => null,
    'update' => null,
    'delete' => null,
  ];
  // ...
  public function actionView(){
    if (isset($this->permissions['view']) && !Yii::$app->user->can($this->permissions['view']){
      throw new ForbiddenException();
    }
  }
}

class ProductController extends CrudController {
  public $permissions = [
    'index' => 'indexProduct',
    'view' => 'viewProduct',
    //...
  ];
}

class ItemController extends CrudController {
  public function beforeAction() {
    $this->permissions = array_merge(parent::$permissions, [
      'view' => 'viewItem',
    ]);
    return parent::beforeAction();
  }
}


Еще можно добавить сценарии на свой вкус:
abstract CrudController extends Controller {
  public $scenarios = [
    'index' => Model::SCENARIO_DEFAULT,
    'view' => Model::SCENARIO_DEFAULT,
    'create' => Model::SCENARIO_DEFAULT,
    'update' => Model::SCENARIO_DEFAULT,
    'delete' => Model::SCENARIO_DEFAULT,
  ];

  public function actionView($id){
    $model = $this->findModel($id);
    $model->scenario = $this->scenario['view'];
  }
  // ...
}
class ProductController extends CrudController {
  public function beforeAction() {
    $this->scenarios['view'] = Product::SCENARIO_VIEW;
    return parent::beforeAction();
  }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы