Я использую нечто такое:
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();
}
}