Commit fd238f57919408dbd91ae5d9d5c8fe4cddaaed7f
1 parent
93c267f7
Admin begin refactor.
Showing
8 changed files
with
257 additions
and
115 deletions
Show diff stats
backend/controllers/ArticlesController.php
| ... | ... | @@ -9,7 +9,6 @@ |
| 9 | 9 | use yii\web\NotFoundHttpException; |
| 10 | 10 | use yii\filters\VerbFilter; |
| 11 | 11 | use developeruz\db_rbac\behaviors\AccessBehavior; |
| 12 | - use yii\web\UploadedFile; | |
| 13 | 12 | |
| 14 | 13 | /** |
| 15 | 14 | * ArticlesController implements the CRUD actions for Articles model. |
| ... | ... | @@ -86,18 +85,12 @@ |
| 86 | 85 | $model_langs = $model->generateLangs(); |
| 87 | 86 | if($model->load(Yii::$app->request->post())) { |
| 88 | 87 | $model->loadLangs(\Yii::$app->request, $model_langs); |
| 89 | - if($model->save()) { | |
| 90 | - if($model->linkLangs($model_langs) && $model->saveLangs($model_langs)) { | |
| 91 | - return $this->redirect([ | |
| 92 | - 'view', | |
| 93 | - 'id' => $model->id, | |
| 94 | - ]); | |
| 95 | - } else { | |
| 96 | - return $this->redirect([ | |
| 97 | - 'update', | |
| 98 | - 'id' => $model->id, | |
| 99 | - ]); | |
| 100 | - } | |
| 88 | + $model->model_langs = $model_langs; | |
| 89 | + if($model->save() && $model->transactionStatus) { | |
| 90 | + return $this->redirect([ | |
| 91 | + 'view', | |
| 92 | + 'id' => $model->id, | |
| 93 | + ]); | |
| 101 | 94 | } |
| 102 | 95 | } |
| 103 | 96 | return $this->render('create', [ |
| ... | ... | @@ -120,13 +113,12 @@ |
| 120 | 113 | $model_langs = $model->generateLangs(); |
| 121 | 114 | if($model->load(Yii::$app->request->post())) { |
| 122 | 115 | $model->loadLangs(\Yii::$app->request, $model_langs); |
| 123 | - if($model->save()) { | |
| 124 | - if($model->linkLangs($model_langs) && $model->saveLangs($model_langs)) { | |
| 125 | - return $this->redirect([ | |
| 126 | - 'view', | |
| 127 | - 'id' => $model->id, | |
| 128 | - ]); | |
| 129 | - } | |
| 116 | + $model->model_langs = $model_langs; | |
| 117 | + if($model->save() && $model->transactionStatus) { | |
| 118 | + return $this->redirect([ | |
| 119 | + 'view', | |
| 120 | + 'id' => $model->id, | |
| 121 | + ]); | |
| 130 | 122 | } |
| 131 | 123 | } |
| 132 | 124 | return $this->render('update', [ |
| ... | ... | @@ -162,7 +154,11 @@ |
| 162 | 154 | */ |
| 163 | 155 | protected function findModel($id) |
| 164 | 156 | { |
| 165 | - if(( $model = Articles::findOne($id) ) !== NULL) { | |
| 157 | + if(( $model = Articles::find() | |
| 158 | + ->where([ 'id' => $id ]) | |
| 159 | + ->with('lang') | |
| 160 | + ->one() ) !== NULL | |
| 161 | + ) { | |
| 166 | 162 | return $model; |
| 167 | 163 | } else { |
| 168 | 164 | throw new NotFoundHttpException('The requested page does not exist.'); | ... | ... |
backend/views/articles/index.php
| 1 | 1 | <?php |
| 2 | - | |
| 3 | -use yii\helpers\Html; | |
| 4 | -use yii\grid\GridView; | |
| 5 | - | |
| 6 | -/* @var $this yii\web\View */ | |
| 7 | -/* @var $searchModel common\models\ArticlesSearch */ | |
| 8 | -/* @var $dataProvider yii\data\ActiveDataProvider */ | |
| 9 | - | |
| 10 | -$this->title = \Yii::t('app', 'Articles'); | |
| 11 | -$this->params['breadcrumbs'][] = $this->title; | |
| 2 | + | |
| 3 | + use yii\helpers\Html; | |
| 4 | + use yii\grid\GridView; | |
| 5 | + | |
| 6 | + /** | |
| 7 | + * @var yii\web\View $this | |
| 8 | + * @var common\models\ArticlesSearch $searchModel | |
| 9 | + * @var yii\data\ActiveDataProvider $dataProvider | |
| 10 | + */ | |
| 11 | + | |
| 12 | + $this->title = \Yii::t('app', 'Articles'); | |
| 13 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
| 12 | 14 | ?> |
| 13 | 15 | <div class="articles-index"> |
| 14 | 16 | <h1><?= Html::encode($this->title) ?></h1> |
| 15 | 17 | <p> |
| 16 | - <?= Html::a(\Yii::t('app', 'Create Articles'), ['create'], ['class' => 'btn btn-success']) ?> | |
| 18 | + <?= Html::a(\Yii::t('app', 'Create Articles'), [ 'create' ], [ 'class' => 'btn btn-success' ]) ?> | |
| 17 | 19 | </p> |
| 18 | 20 | <?= GridView::widget([ |
| 19 | 21 | 'dataProvider' => $dataProvider, |
| 20 | - 'filterModel' => $searchModel, | |
| 21 | - 'columns' => [ | |
| 22 | - ['class' => 'yii\grid\SerialColumn'], | |
| 22 | + 'filterModel' => $searchModel, | |
| 23 | + 'columns' => [ | |
| 23 | 24 | 'id', |
| 24 | - 'date', | |
| 25 | + [ | |
| 26 | + 'attribute' => 'title', | |
| 27 | + 'value' => 'lang.title', | |
| 28 | + ], | |
| 29 | + 'date:date', | |
| 25 | 30 | 'imageUrl:image', |
| 26 | - ['class' => 'yii\grid\ActionColumn'], | |
| 31 | + [ 'class' => 'yii\grid\ActionColumn' ], | |
| 27 | 32 | ], |
| 28 | 33 | ]); ?> |
| 29 | 34 | </div> | ... | ... |
backend/views/articles/view.php
| 1 | 1 | <?php |
| 2 | - | |
| 3 | -use yii\helpers\Html; | |
| 4 | -use yii\widgets\DetailView; | |
| 5 | - | |
| 6 | -/* @var $this yii\web\View */ | |
| 7 | -/* @var $model common\models\Articles */ | |
| 8 | - | |
| 9 | -$this->title = $model->id; | |
| 10 | -$this->params['breadcrumbs'][] = ['label' => \Yii::t('app', 'Articles'), 'url' => ['index']]; | |
| 11 | -$this->params['breadcrumbs'][] = $this->title; | |
| 2 | + | |
| 3 | + use yii\helpers\Html; | |
| 4 | + use yii\widgets\DetailView; | |
| 5 | + | |
| 6 | + /** | |
| 7 | + * @var yii\web\View $this | |
| 8 | + * @var common\models\Articles $model | |
| 9 | + */ | |
| 10 | + | |
| 11 | + $this->title = $model->lang->title; | |
| 12 | + $this->params[ 'breadcrumbs' ][] = [ | |
| 13 | + 'label' => \Yii::t('app', 'Articles'), | |
| 14 | + 'url' => [ 'index' ], | |
| 15 | + ]; | |
| 16 | + $this->params[ 'breadcrumbs' ][] = $this->title; | |
| 12 | 17 | ?> |
| 13 | 18 | <div class="articles-view"> |
| 14 | 19 | <h1><?= Html::encode($this->title) ?></h1> |
| 15 | 20 | <p> |
| 16 | - <?= Html::a(\Yii::t('app', 'Update'), ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?> | |
| 17 | - <?= Html::a(\Yii::t('app', 'Delete'), ['delete', 'id' => $model->id], [ | |
| 21 | + <?= Html::a(\Yii::t('app', 'Update'), [ | |
| 22 | + 'update', | |
| 23 | + 'id' => $model->id, | |
| 24 | + ], [ 'class' => 'btn btn-primary' ]) ?> | |
| 25 | + <?= Html::a(\Yii::t('app', 'Delete'), [ | |
| 26 | + 'delete', | |
| 27 | + 'id' => $model->id, | |
| 28 | + ], [ | |
| 18 | 29 | 'class' => 'btn btn-danger', |
| 19 | - 'data' => [ | |
| 30 | + 'data' => [ | |
| 20 | 31 | 'confirm' => \Yii::t('app', 'Are you sure you want to delete this item?'), |
| 21 | - 'method' => 'post', | |
| 32 | + 'method' => 'post', | |
| 22 | 33 | ], |
| 23 | 34 | ]) ?> |
| 24 | 35 | </p> |
| 25 | 36 | <?= DetailView::widget([ |
| 26 | - 'model' => $model, | |
| 37 | + 'model' => $model, | |
| 27 | 38 | 'attributes' => [ |
| 28 | 39 | 'id', |
| 29 | - 'date', | |
| 40 | + 'date:date', | |
| 41 | + 'lang.title', | |
| 42 | + 'lang.body:html', | |
| 43 | + 'imageUrl:image', | |
| 30 | 44 | ], |
| 31 | 45 | ]) ?> |
| 32 | 46 | </div> | ... | ... |
backend/web/css/site.css
common/models/Articles.php
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace common\models; |
| 4 | - | |
| 4 | + | |
| 5 | + use common\modules\language\behaviors\TransactionBehavior; | |
| 5 | 6 | use common\modules\language\behaviors\LanguageBehavior; |
| 6 | 7 | use common\behaviors\SaveImgBehavior; |
| 7 | 8 | use common\modules\comment\models\CommentModel; |
| ... | ... | @@ -32,6 +33,11 @@ |
| 32 | 33 | * @method bool linkLangs(ActiveRecord[] $model_langs) |
| 33 | 34 | * @method bool saveLangs(ActiveRecord[] $model_langs) |
| 34 | 35 | * * End language behavior * |
| 36 | + * * From transaction behavior * | |
| 37 | + * @property ArticlesLang[] $model_langs | |
| 38 | + * @property bool $transactionStatus | |
| 39 | + * @method bool getTransactionStatus() | |
| 40 | + * * End transaction behavior * | |
| 35 | 41 | */ |
| 36 | 42 | class Articles extends \yii\db\ActiveRecord |
| 37 | 43 | { |
| ... | ... | @@ -63,6 +69,9 @@ |
| 63 | 69 | 'language' => [ |
| 64 | 70 | 'class' => LanguageBehavior::className(), |
| 65 | 71 | ], |
| 72 | + 'transaction' => [ | |
| 73 | + 'class' => TransactionBehavior::className(), | |
| 74 | + ], | |
| 66 | 75 | ]; |
| 67 | 76 | } |
| 68 | 77 | ... | ... |
common/models/ArticlesSearch.php
| 1 | 1 | <?php |
| 2 | - | |
| 3 | -namespace common\models; | |
| 4 | - | |
| 5 | -use yii\base\Model; | |
| 6 | -use yii\data\ActiveDataProvider; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * ArticlesSearch represents the model behind the search form about `common\models\Articles`. | |
| 10 | - */ | |
| 11 | -class ArticlesSearch extends Articles | |
| 12 | -{ | |
| 13 | - /** | |
| 14 | - * @inheritdoc | |
| 15 | - */ | |
| 16 | - public function rules() | |
| 17 | - { | |
| 18 | - return [ | |
| 19 | - [['id'], 'integer'], | |
| 20 | - ]; | |
| 21 | - } | |
| 22 | 2 | |
| 23 | - public function behaviors() | |
| 24 | - { | |
| 25 | - return []; | |
| 26 | - } | |
| 3 | + namespace common\models; | |
| 27 | 4 | |
| 28 | - /** | |
| 29 | - * @inheritdoc | |
| 30 | - */ | |
| 31 | - public function scenarios() | |
| 32 | - { | |
| 33 | - // bypass scenarios() implementation in the parent class | |
| 34 | - return Model::scenarios(); | |
| 35 | - } | |
| 5 | + use yii\base\Model; | |
| 6 | + use yii\data\ActiveDataProvider; | |
| 7 | + use yii\data\Sort; | |
| 36 | 8 | |
| 37 | 9 | /** |
| 38 | - * Creates data provider instance with search query applied | |
| 39 | - * | |
| 40 | - * @param array $params | |
| 41 | - * | |
| 42 | - * @return ActiveDataProvider | |
| 10 | + * ArticlesSearch represents the model behind the search form about `common\models\Articles`. | |
| 43 | 11 | */ |
| 44 | - public function search($params) | |
| 12 | + class ArticlesSearch extends Articles | |
| 45 | 13 | { |
| 46 | - $query = Articles::find(); | |
| 47 | - | |
| 48 | - // add conditions that should always apply here | |
| 49 | - | |
| 50 | - $dataProvider = new ActiveDataProvider([ | |
| 51 | - 'query' => $query, | |
| 52 | - ]); | |
| 53 | - | |
| 54 | - $this->load($params); | |
| 55 | - | |
| 56 | - if (!$this->validate()) { | |
| 57 | - // uncomment the following line if you do not want to return any records when validation fails | |
| 58 | - // $query->where('0=1'); | |
| 14 | + | |
| 15 | + public $title; | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * @inheritdoc | |
| 19 | + */ | |
| 20 | + public function rules() | |
| 21 | + { | |
| 22 | + return [ | |
| 23 | + [ | |
| 24 | + [ 'id' ], | |
| 25 | + 'integer', | |
| 26 | + ], | |
| 27 | + [ | |
| 28 | + [ 'title' ], | |
| 29 | + 'string', | |
| 30 | + ], | |
| 31 | + ]; | |
| 32 | + } | |
| 33 | + | |
| 34 | + public function behaviors() | |
| 35 | + { | |
| 36 | + return []; | |
| 37 | + } | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * @inheritdoc | |
| 41 | + */ | |
| 42 | + public function scenarios() | |
| 43 | + { | |
| 44 | + // bypass scenarios() implementation in the parent class | |
| 45 | + return Model::scenarios(); | |
| 46 | + } | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Creates data provider instance with search query applied | |
| 50 | + * | |
| 51 | + * @param array $params | |
| 52 | + * | |
| 53 | + * @return ActiveDataProvider | |
| 54 | + */ | |
| 55 | + public function search($params) | |
| 56 | + { | |
| 57 | + $query = Articles::find() | |
| 58 | + ->joinWith('lang'); | |
| 59 | + | |
| 60 | + // add conditions that should always apply here | |
| 61 | + | |
| 62 | + $dataProvider = new ActiveDataProvider([ | |
| 63 | + 'query' => $query, | |
| 64 | + 'sort' => [ | |
| 65 | + 'attributes' => [ | |
| 66 | + 'id', | |
| 67 | + 'title' => [ | |
| 68 | + 'asc' => [ 'articles_lang.title' => SORT_ASC ], | |
| 69 | + 'desc' => [ 'articles_lang.title' => SORT_DESC ], | |
| 70 | + ], | |
| 71 | + ], | |
| 72 | + ], | |
| 73 | + ]); | |
| 74 | + | |
| 75 | + $this->load($params); | |
| 76 | + | |
| 77 | + if(!$this->validate()) { | |
| 78 | + // uncomment the following line if you do not want to return any records when validation fails | |
| 79 | + // $query->where('0=1'); | |
| 80 | + return $dataProvider; | |
| 81 | + } | |
| 82 | + | |
| 83 | + // grid filtering conditions | |
| 84 | + $query->andFilterWhere([ | |
| 85 | + 'id' => $this->id, | |
| 86 | + ]); | |
| 87 | + | |
| 88 | + $query->andFilterWhere([ | |
| 89 | + 'like', | |
| 90 | + 'articles_lang.title', | |
| 91 | + $this->title, | |
| 92 | + ]); | |
| 93 | + | |
| 59 | 94 | return $dataProvider; |
| 60 | 95 | } |
| 61 | - | |
| 62 | - // grid filtering conditions | |
| 63 | - $query->andFilterWhere([ | |
| 64 | - 'id' => $this->id, | |
| 65 | - ]); | |
| 66 | - | |
| 67 | - return $dataProvider; | |
| 68 | 96 | } |
| 69 | -} | ... | ... |
common/modules/language/behaviors/TransactionBehavior.php
0 → 100644
| 1 | +<?php | |
| 2 | + | |
| 3 | + namespace common\modules\language\behaviors; | |
| 4 | + | |
| 5 | + use yii\base\Behavior; | |
| 6 | + use yii\db\ActiveRecord; | |
| 7 | + use yii\db\Transaction; | |
| 8 | + | |
| 9 | + /** | |
| 10 | + * Class Save Image Behavior | |
| 11 | + * @property ActiveRecord $owner | |
| 12 | + * @package common\behaviors | |
| 13 | + */ | |
| 14 | + class TransactionBehavior extends Behavior | |
| 15 | + { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * @var Transaction $_transaction | |
| 19 | + */ | |
| 20 | + private $_transaction; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * @var bool $_transaction_status | |
| 24 | + */ | |
| 25 | + private $_transaction_status = false; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * @var ActiveRecord[] $model_langs | |
| 29 | + */ | |
| 30 | + public $model_langs = []; | |
| 31 | + | |
| 32 | + public function events() | |
| 33 | + { | |
| 34 | + return [ | |
| 35 | + ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave', | |
| 36 | + ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeSave', | |
| 37 | + ActiveRecord::EVENT_AFTER_INSERT => 'afterSave', | |
| 38 | + ActiveRecord::EVENT_AFTER_UPDATE => 'afterSave', | |
| 39 | + ]; | |
| 40 | + } | |
| 41 | + | |
| 42 | + public function beforeSave($event) { | |
| 43 | + /** | |
| 44 | + * @var ActiveRecord $owner | |
| 45 | + */ | |
| 46 | + $owner = $this->owner; | |
| 47 | + $db = $owner::getDb(); | |
| 48 | + $this->_transaction = $db->beginTransaction(); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public function afterSave($event) { | |
| 52 | + /** | |
| 53 | + * @var ActiveRecord $owner | |
| 54 | + */ | |
| 55 | + $owner = $this->owner; | |
| 56 | + if(!empty($this->model_langs) && $owner->getBehavior('language')) { | |
| 57 | + if($owner->linkLangs($this->model_langs) && $owner->saveLangs($this->model_langs)) { | |
| 58 | + $this->_transaction->commit(); | |
| 59 | + $this->_transaction_status = true; | |
| 60 | + } else { | |
| 61 | + $this->_transaction->rollBack(); | |
| 62 | + $this->_transaction_status = false; | |
| 63 | + } | |
| 64 | + } else { | |
| 65 | + $this->_transaction->commit(); | |
| 66 | + $this->_transaction_status = true; | |
| 67 | + } | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * @return bool | |
| 72 | + */ | |
| 73 | + public function getTransactionStatus():bool { | |
| 74 | + return $this->_transaction_status; | |
| 75 | + } | |
| 76 | + | |
| 77 | + } | |
| 0 | 78 | \ No newline at end of file | ... | ... |
common/modules/language/readme.txt
| ... | ... | @@ -45,6 +45,9 @@ public function behaviors() { |
| 45 | 45 | 'ownerKey' => {Table}->id //optional, default to {Table}->primaryKey()[0] |
| 46 | 46 | 'langKey' => {TableLang}->table_id //optional, default to {Table}->tableName().'_id' |
| 47 | 47 | ], |
| 48 | + 'transaction' => [ | |
| 49 | + 'class' => TransactionBehavior::className(), | |
| 50 | + ], | |
| 48 | 51 | ]; |
| 49 | 52 | } |
| 50 | 53 | 3.1. PHPDoc для {Table}: |
| ... | ... | @@ -65,6 +68,11 @@ public function behaviors() { |
| 65 | 68 | * @method bool linkLangs(ActiveRecord[] $model_langs) |
| 66 | 69 | * @method bool saveLangs(ActiveRecord[] $model_langs) |
| 67 | 70 | * * End language behavior * |
| 71 | + * * From transaction behavior * | |
| 72 | + * @property {TableLang}[] $model_langs | |
| 73 | + * @property bool $transactionStatus | |
| 74 | + * @method bool getTransactionStatus() | |
| 75 | + * * End transaction behavior * | |
| 68 | 76 | 3.2. Убрать language behavior с наследуемых таблиц от {Table} ({TableSearch}...) |
| 69 | 77 | 4. Доступные полезные методы: |
| 70 | 78 | {Table}->getLangs() - получить все текущие {TableLang} для {Table} проиндексированные по language_id |
| ... | ... | @@ -83,6 +91,6 @@ public function behaviors() { |
| 83 | 91 | 6. Обрабатывать данные в контроллере. |
| 84 | 92 | 1. После создания/поиска {Table} создаем/находим языковые модели {Table}->generateLangs() |
| 85 | 93 | 2. При POST запросе загружаем данные в языковые модели {Table}->loadLangs(Request $request, {TableLangs[]} $model_langs) |
| 86 | - 3. Связываем модель {Table} с языковыми моделями {Table}->linkLangs({TableLang[]} $model_langs). Возвращает true при успехе. | |
| 87 | - 4. Сохраняе языковые модели в базу {Table}->saveLangs({TableLang[]} $model_langs). Возвращает true при успешной валидации каждого {TableLang}. | |
| 94 | + 3. Передаем в свойство model_langs модели {Table} массив {TableLang[]}: $model->model_langs = $model_langs | |
| 95 | + 4. После сохранения, если транзанкция успешна, то свойство {Table}->transactionStatus будет true, иначе возникла ошибка в какой то модели. | |
| 88 | 96 | 7. Получать данные на публичной части сайта через {Table}->lang. |
| 89 | 97 | \ No newline at end of file | ... | ... |