📜 ⬆️ ⬇️

Backend in the project on Yii

The network has very little information on the creation of administrative pages in applications and probably everyone uses their own solutions. Right now I would like to tell what I have come to over half a year of developing websites on Yii (the article is only for those who understand the framework).

When setting goals, you should always think what you really need. In the case of the backend-part of the site it is:


Minimum code

I think many developers who generated the CRUD using the built-in Yii generator know that almost the same code is being created, which is annoying and a bit contrary to the principles of OOP. In addition to this, we can say that the Create and Update actions differ only in the presence of id (the new record has not yet created an id), so we can exclude the Create action.

Some generalization of data

At the moment, the only data compilation I use is the “In Cart” status for the record in the table. If you talk about it very briefly, then it turns out that in almost all the tables I have a status (tinyint, index) field with values ​​of 0 — normal and 1 — remote state.
')
Expandable for special sections

Probably all the rules have exceptions, and we must necessarily provide for their decision. In the case of backend, this is the ability to override any standard behavior of the basic functionality.

Lack of direct communication frontend with backend

Backend is an additional functionality and should be safely removed from the application. In my case, this is a painless removal of the module of the same name.

Practice in 7 steps


1. Create a backend module using standard Gii tools (I will not describe it in detail, there is official documentation for this).
2. Create a basic model that, in a case, knows how to work with a basket.
abstract class TModel extends CActiveRecord { const STATUS_DEFAULT = 0; const STATUS_REMOVED = 1; public function defaultScope() { return array( 'condition' => 'status=' . self::STATUS_DEFAULT ); } public function removed() { $this->resetScope()->getDbCriteria()->mergeWith(array( 'condition' => 'status=' . self::STATUS_REMOVED )); return $this; } public function restore() { if($this->getIsNewRecord()) throw new CDbException(Yii::t('yii','The active record cannot be deleted because it is new.')); if($this->status != self::STATUS_REMOVED) return false; $this->status = self::STATUS_DEFAULT; $this->save(false, array('status')); return true; } public function beforeDelete() { if($this->status == self::STATUS_DEFAULT) { $this->status = self::STATUS_REMOVED; $this->save(false, array('status')); return false; } return parent::beforeDelete(); } } 

3. Create a base controller for CRUD.
 class BackendController extends CController { public $defaultAction = 'list'; public function actions() { return array( 'list' => 'backend.actions.ListAction', 'update' => 'backend.actions.UpdateAction', 'delete' => 'backend.actions.DeleteAction', 'restore' => 'backend.actions.RestoreAction', ); } } 

4. Create a basic action that “guesses” with which model and presentation it works (usually I don’t comment on the code, but here I made a few comments specifically for the article).
 abstract class BackendAction extends CAction { private $_modelName; private $_view; /** *      * -      */ public function redirect($actionId = null) { if($actionId === null) $actionId = $this->controller->defaultAction; $this->controller->redirect(array($actionId)); } /** *  . * -    */ public function render($data, $return = false) { if($this->_view === null) $this->_view = $this->id; return $this->controller->render($this->_view, $data, $return); } /** *        *  ,   id */ public function getModel($scenario = 'insert') { if(($id = Yii::app()->request->getParam('id')) === null) $model = new $this->modelName($scenario); else if(($model = CActiveRecord::model($this->modelName)->resetScope()->findByPk($id)) === null) throw new CHttpException(404, Yii::t('base', 'The specified record cannot be found.')); return $model; } /** *   ,     * -       */ public function getModelName() { if($this->_modelName === null) $this->_modelName = ucfirst($this->controller->id); return $this->_modelName; } public function setView($value) { $this->_view = $value; } public function setModelName($value) { $this->_modelName = $value; } } 

5. Create a basic List action.
 class ListAction extends BackendAction { public function run($showRemoved = null) { $model = $this->getModel('search'); if($showRemoved !== null) $model->removed(); if(isset($_GET[$this->modelName])) $model->attributes = $_GET[$this->modelName]; $this->render(array( 'model' => $model, 'showRemoved' => $showRemoved, )); } } 

6. Create a basic Update action.
 class UpdateAction extends BackendAction { public function run() { $model = $this->getModel(); if(isset($_POST[$this->modelName])) { $model->attributes = $_POST[$this->modelName]; if($model->save()) $this->redirect(); } $this->render(array('model' => $model)); } } 

6. Create a base Delete action.
 class DeleteAction extends BackendAction { public function run() { $this->getModel()->delete(); $this->redirect(); } } 

7. Create a basic Restore action.
 class RestoreAction extends BackendAction { public function run() { $this->getModel()->restore(); $this->redirect(); } } 


Check


To test all of the above, let's create a model and an Article controller.
 class Article extends TModel { public static function model($className=__CLASS__) { return parent::model($className); } public function tableName() { return 'article'; } public function rules() { return array( array('name, content, createTime', 'required'), ); } } class ArticleController extends BackendController { //   ,      } 


Total


In the simplest version, it turns out that to create a new CRUD, you need to create an empty controller and two views (list, update). If you need additional functionality, we simply add it or rewrite the current one.

Note


I will not describe the code of representations, because it will most likely be unique for each developer, and it can be taken from the standard CRUD.

Source: https://habr.com/ru/post/126576/


All Articles