Commit a83704822d340f1b8b9a049b889046ee095f6cc8
0 parents
init project
Showing
368 changed files
with
23203 additions
and
0 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 368 files are displayed.
| 1 | +++ a/.gitignore | |
| 1 | +# yii console command | |
| 2 | +/yii | |
| 3 | + | |
| 4 | +# phpstorm project files | |
| 5 | +.idea | |
| 6 | + | |
| 7 | +# netbeans project files | |
| 8 | +nbproject | |
| 9 | + | |
| 10 | +# zend studio for eclipse project files | |
| 11 | +.buildpath | |
| 12 | +.project | |
| 13 | +.settings | |
| 14 | + | |
| 15 | +# windows thumbnail cache | |
| 16 | +Thumbs.db | |
| 17 | + | |
| 18 | +# composer vendor dir | |
| 19 | +/vendor | |
| 20 | + | |
| 21 | +# composer itself is not needed | |
| 22 | +composer.phar | |
| 23 | + | |
| 24 | +# Mac DS_Store Files | |
| 25 | +.DS_Store | |
| 26 | + | |
| 27 | +# phpunit itself is not needed | |
| 28 | +phpunit.phar | |
| 29 | +# local phpunit config | |
| 30 | +/phpunit.xml | |
| 31 | + | |
| 32 | +/storage | |
| 33 | +common/config/main-local.php | |
| 34 | +common/config/params-local.php | |
| 35 | +backend/config/main-local.php | |
| 36 | +backend/config/params-local.php | |
| 37 | +backend/assets/* | |
| 38 | +frontend/config/main-local.php | |
| 39 | +frontend/config/params-local.php | |
| 40 | +frontend/assets/* | |
| 0 | 41 | \ No newline at end of file | ... | ... |
| 1 | +++ a/.htaccess | |
| 1 | +AddDefaultCharset utf-8 | |
| 2 | +<IfModule mod_rewrite.c> | |
| 3 | + | |
| 4 | + | |
| 5 | + Options +FollowSymlinks | |
| 6 | + | |
| 7 | + RewriteEngine On | |
| 8 | + | |
| 9 | +</IfModule> | |
| 10 | + | |
| 11 | +<IfModule mod_rewrite.c> | |
| 12 | + | |
| 13 | + RewriteBase / | |
| 14 | + # deal with admin first | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + RewriteRule ^storage/(.*)?$ /storage/$1 [L,PT] | |
| 19 | + | |
| 20 | + RewriteCond %{REQUEST_URI} ^/(admin) | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + RewriteRule ^admin/assets/(.*)$ backend/web/assets/$1 [L] | |
| 25 | + | |
| 26 | + RewriteRule ^admin/css/(.*)$ backend/web/css/$1 [L] | |
| 27 | + | |
| 28 | + RewriteRule ^admin/js/(.*)$ backend/web/js/$1 [L] | |
| 29 | + | |
| 30 | + RewriteRule ^admin/images/(.*)$ backend/web/images/$1 [L] | |
| 31 | + | |
| 32 | + RewriteRule ^admin/fonts/(.*)$ backend/web/fonts/$1 [L] | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + RewriteCond %{REQUEST_URI} !^/backend/web/(assets|css|js|images|fonts)/ | |
| 39 | + | |
| 40 | + RewriteCond %{REQUEST_URI} ^/(admin) | |
| 41 | + | |
| 42 | + RewriteRule ^.*$ backend/web/index.php [L] | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + RewriteCond %{REQUEST_URI} ^/(assets|css) | |
| 47 | + | |
| 48 | + RewriteRule ^assets/(.*)$ frontend/web/assets/$1 [L] | |
| 49 | + | |
| 50 | + RewriteRule ^css/(.*)$ frontend/web/css/$1 [L] | |
| 51 | + | |
| 52 | + RewriteRule ^js/(.*)$ frontend/web/js/$1 [L] | |
| 53 | + | |
| 54 | + RewriteRule ^images/(.*)$ frontend/web/images/$1 [L] | |
| 55 | + | |
| 56 | + RewriteRule ^fonts/(.*)$ frontend/web/fonts/$1 [L] | |
| 57 | + | |
| 58 | + | |
| 59 | + RewriteCond %{REQUEST_URI} !^/(frontend|backend)/web/(assets|css|js|images|fonts)/ | |
| 60 | + | |
| 61 | + RewriteCond %{REQUEST_URI} !index.php | |
| 62 | + | |
| 63 | + RewriteCond %{REQUEST_FILENAME} !-f [OR] | |
| 64 | + | |
| 65 | + RewriteCond %{REQUEST_FILENAME} !-d | |
| 66 | + | |
| 67 | + RewriteRule ^.*$ frontend/web/index.php [L] | |
| 68 | + | |
| 69 | +</IfModule> | |
| 70 | + | |
| 71 | +#для возможности загрузки файлов парсера | |
| 72 | +<IfModule mod_php5.c> | |
| 73 | + php_value upload_max_filesize 20M | |
| 74 | + php_value post_max_size 30M | |
| 75 | +</IfModule> | |
| 0 | 76 | \ No newline at end of file | ... | ... |
| 1 | +++ a/LICENSE.md | |
| 1 | +The Yii framework is free software. It is released under the terms of | |
| 2 | +the following BSD License. | |
| 3 | + | |
| 4 | +Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) | |
| 5 | +All rights reserved. | |
| 6 | + | |
| 7 | +Redistribution and use in source and binary forms, with or without | |
| 8 | +modification, are permitted provided that the following conditions | |
| 9 | +are met: | |
| 10 | + | |
| 11 | + * Redistributions of source code must retain the above copyright | |
| 12 | + notice, this list of conditions and the following disclaimer. | |
| 13 | + * Redistributions in binary form must reproduce the above copyright | |
| 14 | + notice, this list of conditions and the following disclaimer in | |
| 15 | + the documentation and/or other materials provided with the | |
| 16 | + distribution. | |
| 17 | + * Neither the name of Yii Software LLC nor the names of its | |
| 18 | + contributors may be used to endorse or promote products derived | |
| 19 | + from this software without specific prior written permission. | |
| 20 | + | |
| 21 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 22 | +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 23 | +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 24 | +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 25 | +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 26 | +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 27 | +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 28 | +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| 29 | +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 30 | +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
| 31 | +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| 32 | +POSSIBILITY OF SUCH DAMAGE. | ... | ... |
| 1 | +++ a/README.md | |
| 1 | +Yii 2 Advanced Project Template | |
| 2 | +=============================== | |
| 3 | + | |
| 4 | +Yii 2 Advanced Project Template is a skeleton [Yii 2](http://www.yiiframework.com/) application best for | |
| 5 | +developing complex Web applications with multiple tiers. | |
| 6 | + | |
| 7 | +The template includes three tiers: front end, back end, and console, each of which | |
| 8 | +is a separate Yii application. | |
| 9 | + | |
| 10 | +The template is designed to work in a team development environment. It supports | |
| 11 | +deploying the application in different environments. | |
| 12 | + | |
| 13 | +Documentation is at [docs/guide/README.md](docs/guide/README.md). | |
| 14 | + | |
| 15 | +[](https://packagist.org/packages/yiisoft/yii2-app-advanced) | |
| 16 | +[](https://packagist.org/packages/yiisoft/yii2-app-advanced) | |
| 17 | +[](https://travis-ci.org/yiisoft/yii2-app-advanced) | |
| 18 | + | |
| 19 | +DIRECTORY STRUCTURE | |
| 20 | +------------------- | |
| 21 | + | |
| 22 | +``` | |
| 23 | +common | |
| 24 | + config/ contains shared configurations | |
| 25 | + mail/ contains view files for e-mails | |
| 26 | + models/ contains model classes used in both backend and frontend | |
| 27 | +console | |
| 28 | + config/ contains console configurations | |
| 29 | + controllers/ contains console controllers (commands) | |
| 30 | + migrations/ contains database migrations | |
| 31 | + models/ contains console-specific model classes | |
| 32 | + runtime/ contains files generated during runtime | |
| 33 | +backend | |
| 34 | + assets/ contains application assets such as JavaScript and CSS | |
| 35 | + config/ contains backend configurations | |
| 36 | + controllers/ contains Web controller classes | |
| 37 | + models/ contains backend-specific model classes | |
| 38 | + runtime/ contains files generated during runtime | |
| 39 | + views/ contains view files for the Web application | |
| 40 | + web/ contains the entry script and Web resources | |
| 41 | +frontend | |
| 42 | + assets/ contains application assets such as JavaScript and CSS | |
| 43 | + config/ contains frontend configurations | |
| 44 | + controllers/ contains Web controller classes | |
| 45 | + models/ contains frontend-specific model classes | |
| 46 | + runtime/ contains files generated during runtime | |
| 47 | + views/ contains view files for the Web application | |
| 48 | + web/ contains the entry script and Web resources | |
| 49 | + widgets/ contains frontend widgets | |
| 50 | +vendor/ contains dependent 3rd-party packages | |
| 51 | +environments/ contains environment-based overrides | |
| 52 | +tests contains various tests for the advanced application | |
| 53 | + codeception/ contains tests developed with Codeception PHP Testing Framework | |
| 54 | +``` | ... | ... |
| 1 | +++ a/backend/config/main.php | |
| 1 | +<?php | |
| 2 | +$params = array_merge( | |
| 3 | + require(__DIR__ . '/../../common/config/params.php'), | |
| 4 | + require(__DIR__ . '/../../common/config/params-local.php'), | |
| 5 | + require(__DIR__ . '/params.php'), | |
| 6 | + require(__DIR__ . '/params-local.php') | |
| 7 | +); | |
| 8 | + | |
| 9 | +return [ | |
| 10 | + 'id' => 'app-backend', | |
| 11 | + 'basePath' => dirname(__DIR__), | |
| 12 | + 'layout' => 'admin', | |
| 13 | + 'controllerNamespace' => 'backend\controllers', | |
| 14 | + 'bootstrap' => ['log'], | |
| 15 | + 'modules' => [ | |
| 16 | + 'rubrication' => [ | |
| 17 | + 'class' => 'common\modules\rubrication\Module', | |
| 18 | + 'types' => [ | |
| 19 | + 'string' => 'Strings', | |
| 20 | + 'float' => 'Floating number', | |
| 21 | + 'int' => 'Integer number', | |
| 22 | + 'link' => 'Web-link', | |
| 23 | + ] | |
| 24 | + ], | |
| 25 | + 'product' => [ | |
| 26 | + 'class' => 'common\modules\product\Module' | |
| 27 | + ], | |
| 28 | + ], | |
| 29 | + 'components' => [ | |
| 30 | + 'user' => [ | |
| 31 | + 'identityClass' => 'common\models\User', | |
| 32 | + 'enableAutoLogin' => true, | |
| 33 | + ], | |
| 34 | + 'log' => [ | |
| 35 | + 'traceLevel' => YII_DEBUG ? 3 : 0, | |
| 36 | + 'targets' => [ | |
| 37 | + [ | |
| 38 | + 'class' => 'yii\log\FileTarget', | |
| 39 | + 'levels' => ['error', 'warning'], | |
| 40 | + ], | |
| 41 | + ], | |
| 42 | + ], | |
| 43 | + 'errorHandler' => [ | |
| 44 | + 'errorAction' => 'site/error', | |
| 45 | + ], | |
| 46 | + 'request'=>[ | |
| 47 | + 'cookieValidationKey' => 'j4iuot9u5894e7tu8reyh78g9y54sy7i', | |
| 48 | + 'csrfParam' => '_backendCSRF', | |
| 49 | + | |
| 50 | + 'class' => 'common\components\Request', | |
| 51 | + | |
| 52 | + 'web'=> '/backend/web', | |
| 53 | + | |
| 54 | + 'adminUrl' => '/admin' | |
| 55 | + | |
| 56 | + ], | |
| 57 | + | |
| 58 | + ], | |
| 59 | + 'params' => $params, | |
| 60 | +]; | ... | ... |
| 1 | +++ a/backend/controllers/BlogController.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace backend\controllers; | |
| 4 | + | |
| 5 | +use common\models\Fields; | |
| 6 | +use Yii; | |
| 7 | +use common\models\Blog; | |
| 8 | +use common\models\BlogSearch; | |
| 9 | +use yii\web\Controller; | |
| 10 | +use yii\web\NotFoundHttpException; | |
| 11 | +use yii\filters\VerbFilter; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * BlogController implements the CRUD actions for Blog model. | |
| 15 | + */ | |
| 16 | +class BlogController extends Controller | |
| 17 | +{ | |
| 18 | + | |
| 19 | + public $layout = '/admin'; | |
| 20 | + /** | |
| 21 | + * @inheritdoc | |
| 22 | + */ | |
| 23 | + public function behaviors() | |
| 24 | + { | |
| 25 | + return [ | |
| 26 | + 'verbs' => [ | |
| 27 | + 'class' => VerbFilter::className(), | |
| 28 | + 'actions' => [ | |
| 29 | + 'delete' => ['POST'], | |
| 30 | + ], | |
| 31 | + ], | |
| 32 | + ]; | |
| 33 | + } | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * Lists all Blog models. | |
| 37 | + * @return mixed | |
| 38 | + */ | |
| 39 | + public function actionIndex() | |
| 40 | + { | |
| 41 | + $searchModel = new BlogSearch(); | |
| 42 | + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); | |
| 43 | + | |
| 44 | + return $this->render('index', [ | |
| 45 | + 'searchModel' => $searchModel, | |
| 46 | + 'dataProvider' => $dataProvider, | |
| 47 | + ]); | |
| 48 | + } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Displays a single Blog model. | |
| 52 | + * @param integer $id | |
| 53 | + * @return mixed | |
| 54 | + */ | |
| 55 | + public function actionView($id) | |
| 56 | + { | |
| 57 | + return $this->render('view', [ | |
| 58 | + 'model' => $this->findModel($id), | |
| 59 | + ]); | |
| 60 | + } | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Creates a new Blog model. | |
| 64 | + * If creation is successful, the browser will be redirected to the 'view' page. | |
| 65 | + * @return mixed | |
| 66 | + */ | |
| 67 | + public function actionCreate() | |
| 68 | + { | |
| 69 | + $model = new Blog(); | |
| 70 | + | |
| 71 | + if ($model->load(Yii::$app->request->post()) && $model->save()) { | |
| 72 | + | |
| 73 | + Fields::saveFieldData(Yii::$app->request->post('Fields'), $model->blog_id, Blog::className(), 'ru'); | |
| 74 | + | |
| 75 | + return $this->redirect(['view', 'id' => $model->blog_id]); | |
| 76 | + } else { | |
| 77 | + return $this->render('create', [ | |
| 78 | + 'model' => $model, | |
| 79 | + ]); | |
| 80 | + } | |
| 81 | + } | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Updates an existing Blog model. | |
| 85 | + * If update is successful, the browser will be redirected to the 'view' page. | |
| 86 | + * @param integer $id | |
| 87 | + * @return mixed | |
| 88 | + */ | |
| 89 | + public function actionUpdate($id) | |
| 90 | + { | |
| 91 | + $model = $this->findModel($id); | |
| 92 | + | |
| 93 | + if ($model->load(Yii::$app->request->post()) && $model->save()) { | |
| 94 | + Fields::saveFieldData(Yii::$app->request->post('Fields'), $model->blog_id, Blog::className(), 'ru'); | |
| 95 | + return $this->redirect(['view', 'id' => $model->blog_id]); | |
| 96 | + } else { | |
| 97 | + return $this->render('update', [ | |
| 98 | + 'model' => $model, | |
| 99 | + ]); | |
| 100 | + } | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Deletes an existing Blog model. | |
| 105 | + * If deletion is successful, the browser will be redirected to the 'index' page. | |
| 106 | + * @param integer $id | |
| 107 | + * @return mixed | |
| 108 | + */ | |
| 109 | + public function actionDelete($id) | |
| 110 | + { | |
| 111 | + $this->findModel($id)->delete(); | |
| 112 | + | |
| 113 | + return $this->redirect(['index']); | |
| 114 | + } | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Finds the Blog model based on its primary key value. | |
| 118 | + * If the model is not found, a 404 HTTP exception will be thrown. | |
| 119 | + * @param integer $id | |
| 120 | + * @return Blog the loaded model | |
| 121 | + * @throws NotFoundHttpException if the model cannot be found | |
| 122 | + */ | |
| 123 | + protected function findModel($id) | |
| 124 | + { | |
| 125 | + if (($model = Blog::findOne($id)) !== null) { | |
| 126 | + return $model; | |
| 127 | + } else { | |
| 128 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
| 129 | + } | |
| 130 | + } | |
| 131 | +} | ... | ... |
| 1 | +++ a/backend/controllers/SiteController.php | |
| 1 | +<?php | |
| 2 | +namespace backend\controllers; | |
| 3 | + | |
| 4 | +use Yii; | |
| 5 | +use yii\filters\AccessControl; | |
| 6 | +use yii\web\Controller; | |
| 7 | +use common\models\LoginForm; | |
| 8 | +use yii\filters\VerbFilter; | |
| 9 | +use common\models\Blog; | |
| 10 | +/** | |
| 11 | + * Site controller | |
| 12 | + */ | |
| 13 | +class SiteController extends Controller | |
| 14 | +{ | |
| 15 | + | |
| 16 | + public $layout = '/admin'; | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * @inheritdoc | |
| 20 | + */ | |
| 21 | + public function behaviors() | |
| 22 | + { | |
| 23 | + return [ | |
| 24 | + 'access' => [ | |
| 25 | + 'class' => AccessControl::className(), | |
| 26 | + 'rules' => [ | |
| 27 | + [ | |
| 28 | + 'actions' => ['login', 'error'], | |
| 29 | + 'allow' => true, | |
| 30 | + ], | |
| 31 | + [ | |
| 32 | + 'actions' => ['logout', 'index'], | |
| 33 | + 'allow' => true, | |
| 34 | + 'roles' => ['@'], | |
| 35 | + ], | |
| 36 | + ], | |
| 37 | + ], | |
| 38 | + 'verbs' => [ | |
| 39 | + 'class' => VerbFilter::className(), | |
| 40 | + 'actions' => [ | |
| 41 | + 'logout' => ['post'], | |
| 42 | + ], | |
| 43 | + ], | |
| 44 | + ]; | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * @inheritdoc | |
| 49 | + */ | |
| 50 | + public function actions() | |
| 51 | + { | |
| 52 | + return [ | |
| 53 | + 'error' => [ | |
| 54 | + 'class' => 'yii\web\ErrorAction', | |
| 55 | + ], | |
| 56 | + ]; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public function actionIndex() | |
| 60 | + { | |
| 61 | + $blog = new Blog(); | |
| 62 | + $post = \Yii::$app->request->post(); | |
| 63 | + if($blog->load($post)) { | |
| 64 | + $blog->save(); | |
| 65 | + } | |
| 66 | + return $this->render('index',[ | |
| 67 | + 'blog' => $blog | |
| 68 | + ]); | |
| 69 | + } | |
| 70 | + | |
| 71 | + public function actionLogin() | |
| 72 | + { | |
| 73 | + $this->layout = '/none'; | |
| 74 | + | |
| 75 | + if (!\Yii::$app->user->isGuest) { | |
| 76 | + return $this->goHome(); | |
| 77 | + } | |
| 78 | + | |
| 79 | + $model = new LoginForm(); | |
| 80 | + if ($model->load(Yii::$app->request->post()) && $model->login()) { | |
| 81 | + return $this->goBack(); | |
| 82 | + } else { | |
| 83 | + return $this->render('login', [ | |
| 84 | + 'model' => $model, | |
| 85 | + ]); | |
| 86 | + } | |
| 87 | + } | |
| 88 | + | |
| 89 | + public function actionLogout() | |
| 90 | + { | |
| 91 | + Yii::$app->user->logout(); | |
| 92 | + | |
| 93 | + return $this->goHome(); | |
| 94 | + } | |
| 95 | +} | ... | ... |
| 1 | +++ a/backend/views/blog/_form.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use common\widgets\FieldEditor; | |
| 4 | +use yii\helpers\Html; | |
| 5 | +use yii\widgets\ActiveForm; | |
| 6 | +use common\modules\file\widgets\ImageUploader; | |
| 7 | +use mihaildev\ckeditor\CKEditor; | |
| 8 | +use mihaildev\elfinder\ElFinder; | |
| 9 | +use common\components\Request; | |
| 10 | + | |
| 11 | +/* @var $this yii\web\View */ | |
| 12 | +/* @var $model common\models\Blog */ | |
| 13 | +/* @var $form yii\widgets\ActiveForm */ | |
| 14 | +?> | |
| 15 | + | |
| 16 | +<div class="blog-form"> | |
| 17 | + | |
| 18 | + <?php $form = ActiveForm::begin(); ?> | |
| 19 | + | |
| 20 | + <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?> | |
| 21 | + | |
| 22 | + <?= $form->field($model, 'link')->textInput(['maxlength' => true]) ?> | |
| 23 | + | |
| 24 | + <?= $form->field($model, 'description')->widget(CKEditor::className(), | |
| 25 | + [ | |
| 26 | + 'editorOptions' => ElFinder::ckeditorOptions('elfinder',[ | |
| 27 | + 'preset' => 'full', //разработанны стандартные настройки basic, standard, full данную возможность не обязательно использовать | |
| 28 | + 'inline' => false, //по умолчанию false]), | |
| 29 | + 'filebrowserUploadUrl'=>Yii::$app->getUrlManager()->createUrl('file/uploader/images-upload') | |
| 30 | + ] | |
| 31 | + ) | |
| 32 | + ]) ?> | |
| 33 | + | |
| 34 | + <?= ImageUploader::widget([ | |
| 35 | + 'model'=> $model, | |
| 36 | + 'field'=>'cover', | |
| 37 | + 'size' => [ | |
| 38 | + [ | |
| 39 | + 'width'=>340, | |
| 40 | + 'height'=>260, | |
| 41 | + ] | |
| 42 | + ], | |
| 43 | + 'multi'=>true, | |
| 44 | + 'gallery' =>$model->cover, | |
| 45 | + 'name' => 'Загрузить миниатюру статьи' | |
| 46 | + ]); | |
| 47 | + ?> | |
| 48 | + | |
| 49 | + <?= FieldEditor::widget([ | |
| 50 | + 'template' => 'education', | |
| 51 | + 'item_id' => $model->blog_id, | |
| 52 | + 'model' => 'common\models\Blog', | |
| 53 | + 'language' => 'ru', | |
| 54 | + ]); ?> | |
| 55 | + <div class="form-group"> | |
| 56 | + <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> | |
| 57 | + </div> | |
| 58 | + | |
| 59 | + <?php ActiveForm::end(); ?> | |
| 60 | + | |
| 61 | +</div> | ... | ... |
| 1 | +++ a/backend/views/blog/_search.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\helpers\Html; | |
| 4 | +use yii\widgets\ActiveForm; | |
| 5 | + | |
| 6 | +/* @var $this yii\web\View */ | |
| 7 | +/* @var $model common\models\BlogSearch */ | |
| 8 | +/* @var $form yii\widgets\ActiveForm */ | |
| 9 | +?> | |
| 10 | + | |
| 11 | +<div class="blog-search"> | |
| 12 | + | |
| 13 | + <?php $form = ActiveForm::begin([ | |
| 14 | + 'action' => ['index'], | |
| 15 | + 'method' => 'get', | |
| 16 | + ]); ?> | |
| 17 | + | |
| 18 | + <?= $form->field($model, 'blog_id') ?> | |
| 19 | + | |
| 20 | + <?= $form->field($model, 'user_id') ?> | |
| 21 | + | |
| 22 | + <?= $form->field($model, 'name') ?> | |
| 23 | + | |
| 24 | + <?= $form->field($model, 'link') ?> | |
| 25 | + | |
| 26 | + <?= $form->field($model, 'date_add') ?> | |
| 27 | + | |
| 28 | + <?php // echo $form->field($model, 'user_add_id') ?> | |
| 29 | + | |
| 30 | + <?php // echo $form->field($model, 'view_count') ?> | |
| 31 | + | |
| 32 | + <?php // echo $form->field($model, 'description') ?> | |
| 33 | + | |
| 34 | + <?php // echo $form->field($model, 'cover') ?> | |
| 35 | + | |
| 36 | + <div class="form-group"> | |
| 37 | + <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?> | |
| 38 | + <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?> | |
| 39 | + </div> | |
| 40 | + | |
| 41 | + <?php ActiveForm::end(); ?> | |
| 42 | + | |
| 43 | +</div> | ... | ... |
| 1 | +++ a/backend/views/blog/create.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\helpers\Html; | |
| 4 | + | |
| 5 | + | |
| 6 | +/* @var $this yii\web\View */ | |
| 7 | +/* @var $model common\models\Blog */ | |
| 8 | + | |
| 9 | +$this->title = 'Create Blog'; | |
| 10 | +$this->params['breadcrumbs'][] = ['label' => 'Blogs', 'url' => ['index']]; | |
| 11 | +$this->params['breadcrumbs'][] = $this->title; | |
| 12 | +?> | |
| 13 | +<div class="blog-create"> | |
| 14 | + | |
| 15 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 16 | + | |
| 17 | + <?= $this->render('_form', [ | |
| 18 | + 'model' => $model, | |
| 19 | + ]) ?> | |
| 20 | + | |
| 21 | +</div> | ... | ... |
| 1 | +++ a/backend/views/blog/index.php | |
| 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\BlogSearch */ | |
| 8 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | |
| 9 | + | |
| 10 | +$this->title = 'Blogs'; | |
| 11 | +$this->params['breadcrumbs'][] = $this->title; | |
| 12 | +?> | |
| 13 | +<div class="blog-index"> | |
| 14 | + | |
| 15 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 16 | + <?php // echo $this->render('_search', ['model' => $searchModel]); ?> | |
| 17 | + | |
| 18 | + <p> | |
| 19 | + <?= Html::a('Create Blog', ['create'], ['class' => 'btn btn-success']) ?> | |
| 20 | + </p> | |
| 21 | + <?= GridView::widget([ | |
| 22 | + 'dataProvider' => $dataProvider, | |
| 23 | + 'filterModel' => $searchModel, | |
| 24 | + 'columns' => [ | |
| 25 | + ['class' => 'yii\grid\SerialColumn'], | |
| 26 | + | |
| 27 | + 'blog_id', | |
| 28 | + 'user_id', | |
| 29 | + 'name', | |
| 30 | + 'link', | |
| 31 | + 'date_add', | |
| 32 | + // 'user_add_id', | |
| 33 | + // 'view_count', | |
| 34 | + // 'description:ntext', | |
| 35 | + // 'cover', | |
| 36 | + | |
| 37 | + ['class' => 'yii\grid\ActionColumn'], | |
| 38 | + ], | |
| 39 | + ]); ?> | |
| 40 | +</div> | ... | ... |
| 1 | +++ a/backend/views/blog/update.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\helpers\Html; | |
| 4 | + | |
| 5 | +/* @var $this yii\web\View */ | |
| 6 | +/* @var $model common\models\Blog */ | |
| 7 | + | |
| 8 | +$this->title = 'Update Blog: ' . ' ' . $model->name; | |
| 9 | +$this->params['breadcrumbs'][] = ['label' => 'Blogs', 'url' => ['index']]; | |
| 10 | +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->blog_id]]; | |
| 11 | +$this->params['breadcrumbs'][] = 'Update'; | |
| 12 | +?> | |
| 13 | +<div class="blog-update"> | |
| 14 | + | |
| 15 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 16 | + | |
| 17 | + <?= $this->render('_form', [ | |
| 18 | + 'model' => $model, | |
| 19 | + ]) ?> | |
| 20 | + | |
| 21 | +</div> | ... | ... |
| 1 | +++ a/backend/views/blog/view.php | |
| 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\Blog */ | |
| 8 | + | |
| 9 | +$this->title = $model->name; | |
| 10 | +$this->params['breadcrumbs'][] = ['label' => 'Blogs', 'url' => ['index']]; | |
| 11 | +$this->params['breadcrumbs'][] = $this->title; | |
| 12 | +?> | |
| 13 | +<div class="blog-view"> | |
| 14 | + | |
| 15 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 16 | + | |
| 17 | + <p> | |
| 18 | + <?= Html::a('Update', ['update', 'id' => $model->blog_id], ['class' => 'btn btn-primary']) ?> | |
| 19 | + <?= Html::a('Delete', ['delete', 'id' => $model->blog_id], [ | |
| 20 | + 'class' => 'btn btn-danger', | |
| 21 | + 'data' => [ | |
| 22 | + 'confirm' => 'Are you sure you want to delete this item?', | |
| 23 | + 'method' => 'post', | |
| 24 | + ], | |
| 25 | + ]) ?> | |
| 26 | + </p> | |
| 27 | + | |
| 28 | + <?= DetailView::widget([ | |
| 29 | + 'model' => $model, | |
| 30 | + 'attributes' => [ | |
| 31 | + 'blog_id', | |
| 32 | + 'user_id', | |
| 33 | + 'name', | |
| 34 | + 'link', | |
| 35 | + 'date_add', | |
| 36 | + 'user_add_id', | |
| 37 | + 'view_count', | |
| 38 | + 'description:ntext', | |
| 39 | + 'cover', | |
| 40 | + ], | |
| 41 | + ]) ?> | |
| 42 | + | |
| 43 | +</div> | ... | ... |
| 1 | +++ a/backend/views/layouts/admin.php | |
| 1 | +<?php | |
| 2 | +use yii\widgets\Breadcrumbs; | |
| 3 | +use common\widgets\Alert; | |
| 4 | + | |
| 5 | +/* @var $content string */ | |
| 6 | +$this->beginContent('@app/views/layouts/main.php'); | |
| 7 | +?> | |
| 8 | + | |
| 9 | + <?= $this->render('header') ?> | |
| 10 | + <!-- Left side column. contains the logo and sidebar --> | |
| 11 | + <?= $this->render('main-sidebar') ?> | |
| 12 | + | |
| 13 | + <!-- Content Wrapper. Contains page content --> | |
| 14 | + <div class="content-wrapper"> | |
| 15 | + <section class="content"> | |
| 16 | + <?= Breadcrumbs::widget([ | |
| 17 | + 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], | |
| 18 | + ]) ?> | |
| 19 | + <?= Alert::widget() ?> | |
| 20 | + | |
| 21 | + <?= $content; ?> | |
| 22 | + </section> | |
| 23 | + </div><!-- /.content-wrapper --> | |
| 24 | + <?= $this->render('footer') ?> | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + <!-- Control Sidebar --> | |
| 29 | + <?= $this->render('control-sidebar') ?> | |
| 30 | + <!-- /.control-sidebar --> | |
| 31 | + <!-- Add the sidebar's background. This div must be placed | |
| 32 | + immediately after the control sidebar --> | |
| 33 | + <div class="control-sidebar-bg"></div> | |
| 34 | + | |
| 35 | +<?php $this->endContent() ?> | |
| 0 | 36 | \ No newline at end of file | ... | ... |
| 1 | +++ a/backend/views/layouts/control-sidebar.php | |
| 1 | +<aside class="control-sidebar control-sidebar-dark"> | |
| 2 | + <!-- Create the tabs --> | |
| 3 | + <ul class="nav nav-tabs nav-justified control-sidebar-tabs"> | |
| 4 | + <li><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li> | |
| 5 | + <li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li> | |
| 6 | + </ul> | |
| 7 | + <!-- Tab panes --> | |
| 8 | + <div class="tab-content"> | |
| 9 | + <!-- Home tab content --> | |
| 10 | + <div class="tab-pane" id="control-sidebar-home-tab"> | |
| 11 | + <h3 class="control-sidebar-heading">Recent Activity</h3> | |
| 12 | + <ul class="control-sidebar-menu"> | |
| 13 | + <li> | |
| 14 | + <a href="javascript::;"> | |
| 15 | + <i class="menu-icon fa fa-birthday-cake bg-red"></i> | |
| 16 | + | |
| 17 | + <div class="menu-info"> | |
| 18 | + <h4 class="control-sidebar-subheading">Langdon's Birthday</h4> | |
| 19 | + | |
| 20 | + <p>Will be 23 on April 24th</p> | |
| 21 | + </div> | |
| 22 | + </a> | |
| 23 | + </li> | |
| 24 | + <li> | |
| 25 | + <a href="javascript::;"> | |
| 26 | + <i class="menu-icon fa fa-user bg-yellow"></i> | |
| 27 | + | |
| 28 | + <div class="menu-info"> | |
| 29 | + <h4 class="control-sidebar-subheading">Frodo Updated His Profile</h4> | |
| 30 | + | |
| 31 | + <p>New phone +1(800)555-1234</p> | |
| 32 | + </div> | |
| 33 | + </a> | |
| 34 | + </li> | |
| 35 | + <li> | |
| 36 | + <a href="javascript::;"> | |
| 37 | + <i class="menu-icon fa fa-envelope-o bg-light-blue"></i> | |
| 38 | + | |
| 39 | + <div class="menu-info"> | |
| 40 | + <h4 class="control-sidebar-subheading">Nora Joined Mailing List</h4> | |
| 41 | + | |
| 42 | + <p>nora@example.com</p> | |
| 43 | + </div> | |
| 44 | + </a> | |
| 45 | + </li> | |
| 46 | + <li> | |
| 47 | + <a href="javascript::;"> | |
| 48 | + <i class="menu-icon fa fa-file-code-o bg-green"></i> | |
| 49 | + | |
| 50 | + <div class="menu-info"> | |
| 51 | + <h4 class="control-sidebar-subheading">Cron Job 254 Executed</h4> | |
| 52 | + | |
| 53 | + <p>Execution time 5 seconds</p> | |
| 54 | + </div> | |
| 55 | + </a> | |
| 56 | + </li> | |
| 57 | + </ul> | |
| 58 | + <!-- /.control-sidebar-menu --> | |
| 59 | + | |
| 60 | + <h3 class="control-sidebar-heading">Tasks Progress</h3> | |
| 61 | + <ul class="control-sidebar-menu"> | |
| 62 | + <li> | |
| 63 | + <a href="javascript::;"> | |
| 64 | + <h4 class="control-sidebar-subheading"> | |
| 65 | + Custom Template Design | |
| 66 | + <span class="label label-danger pull-right">70%</span> | |
| 67 | + </h4> | |
| 68 | + | |
| 69 | + <div class="progress progress-xxs"> | |
| 70 | + <div class="progress-bar progress-bar-danger" style="width: 70%"></div> | |
| 71 | + </div> | |
| 72 | + </a> | |
| 73 | + </li> | |
| 74 | + <li> | |
| 75 | + <a href="javascript::;"> | |
| 76 | + <h4 class="control-sidebar-subheading"> | |
| 77 | + Update Resume | |
| 78 | + <span class="label label-success pull-right">95%</span> | |
| 79 | + </h4> | |
| 80 | + | |
| 81 | + <div class="progress progress-xxs"> | |
| 82 | + <div class="progress-bar progress-bar-success" style="width: 95%"></div> | |
| 83 | + </div> | |
| 84 | + </a> | |
| 85 | + </li> | |
| 86 | + <li> | |
| 87 | + <a href="javascript::;"> | |
| 88 | + <h4 class="control-sidebar-subheading"> | |
| 89 | + Laravel Integration | |
| 90 | + <span class="label label-warning pull-right">50%</span> | |
| 91 | + </h4> | |
| 92 | + | |
| 93 | + <div class="progress progress-xxs"> | |
| 94 | + <div class="progress-bar progress-bar-warning" style="width: 50%"></div> | |
| 95 | + </div> | |
| 96 | + </a> | |
| 97 | + </li> | |
| 98 | + <li> | |
| 99 | + <a href="javascript::;"> | |
| 100 | + <h4 class="control-sidebar-subheading"> | |
| 101 | + Back End Framework | |
| 102 | + <span class="label label-primary pull-right">68%</span> | |
| 103 | + </h4> | |
| 104 | + | |
| 105 | + <div class="progress progress-xxs"> | |
| 106 | + <div class="progress-bar progress-bar-primary" style="width: 68%"></div> | |
| 107 | + </div> | |
| 108 | + </a> | |
| 109 | + </li> | |
| 110 | + </ul> | |
| 111 | + <!-- /.control-sidebar-menu --> | |
| 112 | + | |
| 113 | + </div> | |
| 114 | + <!-- /.tab-pane --> | |
| 115 | + <!-- Stats tab content --> | |
| 116 | + <div class="tab-pane" id="control-sidebar-stats-tab">Stats Tab Content</div> | |
| 117 | + <!-- /.tab-pane --> | |
| 118 | + <!-- Settings tab content --> | |
| 119 | + <div class="tab-pane" id="control-sidebar-settings-tab"> | |
| 120 | + <form method="post"> | |
| 121 | + <h3 class="control-sidebar-heading">General Settings</h3> | |
| 122 | + | |
| 123 | + <div class="form-group"> | |
| 124 | + <label class="control-sidebar-subheading"> | |
| 125 | + Report panel usage | |
| 126 | + <input type="checkbox" class="pull-right" checked> | |
| 127 | + </label> | |
| 128 | + | |
| 129 | + <p> | |
| 130 | + Some information about this general settings option | |
| 131 | + </p> | |
| 132 | + </div> | |
| 133 | + <!-- /.form-group --> | |
| 134 | + | |
| 135 | + <div class="form-group"> | |
| 136 | + <label class="control-sidebar-subheading"> | |
| 137 | + Allow mail redirect | |
| 138 | + <input type="checkbox" class="pull-right" checked> | |
| 139 | + </label> | |
| 140 | + | |
| 141 | + <p> | |
| 142 | + Other sets of options are available | |
| 143 | + </p> | |
| 144 | + </div> | |
| 145 | + <!-- /.form-group --> | |
| 146 | + | |
| 147 | + <div class="form-group"> | |
| 148 | + <label class="control-sidebar-subheading"> | |
| 149 | + Expose author name in posts | |
| 150 | + <input type="checkbox" class="pull-right" checked> | |
| 151 | + </label> | |
| 152 | + | |
| 153 | + <p> | |
| 154 | + Allow the user to show his name in blog posts | |
| 155 | + </p> | |
| 156 | + </div> | |
| 157 | + <!-- /.form-group --> | |
| 158 | + | |
| 159 | + <h3 class="control-sidebar-heading">Chat Settings</h3> | |
| 160 | + | |
| 161 | + <div class="form-group"> | |
| 162 | + <label class="control-sidebar-subheading"> | |
| 163 | + Show me as online | |
| 164 | + <input type="checkbox" class="pull-right" checked> | |
| 165 | + </label> | |
| 166 | + </div> | |
| 167 | + <!-- /.form-group --> | |
| 168 | + | |
| 169 | + <div class="form-group"> | |
| 170 | + <label class="control-sidebar-subheading"> | |
| 171 | + Turn off notifications | |
| 172 | + <input type="checkbox" class="pull-right"> | |
| 173 | + </label> | |
| 174 | + </div> | |
| 175 | + <!-- /.form-group --> | |
| 176 | + | |
| 177 | + <div class="form-group"> | |
| 178 | + <label class="control-sidebar-subheading"> | |
| 179 | + Delete chat history | |
| 180 | + <a href="javascript::;" class="text-red pull-right"><i class="fa fa-trash-o"></i></a> | |
| 181 | + </label> | |
| 182 | + </div> | |
| 183 | + <!-- /.form-group --> | |
| 184 | + </form> | |
| 185 | + </div> | |
| 186 | + <!-- /.tab-pane --> | |
| 187 | + </div> | |
| 188 | +</aside> | |
| 0 | 189 | \ No newline at end of file | ... | ... |
| 1 | +++ a/backend/views/layouts/footer.php | |
| 1 | +<footer class="main-footer"> | |
| 2 | + <div class="pull-right hidden-xs"> | |
| 3 | + <b>Version</b> 2.3.2 | |
| 4 | + </div> | |
| 5 | + <strong>Copyright © 2014-2015 <a href="http://almsaeedstudio.com">Almsaeed Studio</a>.</strong> All rights | |
| 6 | + reserved. | |
| 7 | +</footer> | |
| 0 | 8 | \ No newline at end of file | ... | ... |
| 1 | +++ a/backend/views/layouts/header.php | |
| 1 | +<header class="main-header"> | |
| 2 | + <!-- Logo --> | |
| 3 | + <a href="index2.html" class="logo"> | |
| 4 | + <!-- mini logo for sidebar mini 50x50 pixels --> | |
| 5 | + <span class="logo-mini"><b>A</b>LT</span> | |
| 6 | + <!-- logo for regular state and mobile devices --> | |
| 7 | + <span class="logo-lg"><b>Admin</b>LTE</span> | |
| 8 | + </a> | |
| 9 | + <!-- Header Navbar: style can be found in header.less --> | |
| 10 | + <nav class="navbar navbar-static-top" role="navigation"> | |
| 11 | + <!-- Sidebar toggle button--> | |
| 12 | + <a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"> | |
| 13 | + <span class="sr-only">Toggle navigation</span> | |
| 14 | + </a> | |
| 15 | + | |
| 16 | + <div class="navbar-custom-menu"> | |
| 17 | + <ul class="nav navbar-nav"> | |
| 18 | + <!-- Messages: style can be found in dropdown.less--> | |
| 19 | + <li class="dropdown messages-menu"> | |
| 20 | + <a href="#" class="dropdown-toggle" data-toggle="dropdown"> | |
| 21 | + <i class="fa fa-envelope-o"></i> | |
| 22 | + <span class="label label-success">4</span> | |
| 23 | + </a> | |
| 24 | + <ul class="dropdown-menu"> | |
| 25 | + <li class="header">You have 4 messages</li> | |
| 26 | + <li> | |
| 27 | + <!-- inner menu: contains the actual data --> | |
| 28 | + <ul class="menu"> | |
| 29 | + <li><!-- start message --> | |
| 30 | + <a href="#"> | |
| 31 | + <div class="pull-left"> | |
| 32 | + <img src="dist/img/user2-160x160.jpg" class="img-circle" alt="User Image"> | |
| 33 | + </div> | |
| 34 | + <h4> | |
| 35 | + Support Team | |
| 36 | + <small><i class="fa fa-clock-o"></i> 5 mins</small> | |
| 37 | + </h4> | |
| 38 | + <p>Why not buy a new awesome theme?</p> | |
| 39 | + </a> | |
| 40 | + </li> | |
| 41 | + <!-- end message --> | |
| 42 | + <li> | |
| 43 | + <a href="#"> | |
| 44 | + <div class="pull-left"> | |
| 45 | + <img src="dist/img/user3-128x128.jpg" class="img-circle" alt="User Image"> | |
| 46 | + </div> | |
| 47 | + <h4> | |
| 48 | + AdminLTE Design Team | |
| 49 | + <small><i class="fa fa-clock-o"></i> 2 hours</small> | |
| 50 | + </h4> | |
| 51 | + <p>Why not buy a new awesome theme?</p> | |
| 52 | + </a> | |
| 53 | + </li> | |
| 54 | + <li> | |
| 55 | + <a href="#"> | |
| 56 | + <div class="pull-left"> | |
| 57 | + <img src="dist/img/user4-128x128.jpg" class="img-circle" alt="User Image"> | |
| 58 | + </div> | |
| 59 | + <h4> | |
| 60 | + Developers | |
| 61 | + <small><i class="fa fa-clock-o"></i> Today</small> | |
| 62 | + </h4> | |
| 63 | + <p>Why not buy a new awesome theme?</p> | |
| 64 | + </a> | |
| 65 | + </li> | |
| 66 | + <li> | |
| 67 | + <a href="#"> | |
| 68 | + <div class="pull-left"> | |
| 69 | + <img src="dist/img/user3-128x128.jpg" class="img-circle" alt="User Image"> | |
| 70 | + </div> | |
| 71 | + <h4> | |
| 72 | + Sales Department | |
| 73 | + <small><i class="fa fa-clock-o"></i> Yesterday</small> | |
| 74 | + </h4> | |
| 75 | + <p>Why not buy a new awesome theme?</p> | |
| 76 | + </a> | |
| 77 | + </li> | |
| 78 | + <li> | |
| 79 | + <a href="#"> | |
| 80 | + <div class="pull-left"> | |
| 81 | + <img src="dist/img/user4-128x128.jpg" class="img-circle" alt="User Image"> | |
| 82 | + </div> | |
| 83 | + <h4> | |
| 84 | + Reviewers | |
| 85 | + <small><i class="fa fa-clock-o"></i> 2 days</small> | |
| 86 | + </h4> | |
| 87 | + <p>Why not buy a new awesome theme?</p> | |
| 88 | + </a> | |
| 89 | + </li> | |
| 90 | + </ul> | |
| 91 | + </li> | |
| 92 | + <li class="footer"><a href="#">See All Messages</a></li> | |
| 93 | + </ul> | |
| 94 | + </li> | |
| 95 | + <!-- Notifications: style can be found in dropdown.less --> | |
| 96 | + <li class="dropdown notifications-menu"> | |
| 97 | + <a href="#" class="dropdown-toggle" data-toggle="dropdown"> | |
| 98 | + <i class="fa fa-bell-o"></i> | |
| 99 | + <span class="label label-warning">10</span> | |
| 100 | + </a> | |
| 101 | + <ul class="dropdown-menu"> | |
| 102 | + <li class="header">You have 10 notifications</li> | |
| 103 | + <li> | |
| 104 | + <!-- inner menu: contains the actual data --> | |
| 105 | + <ul class="menu"> | |
| 106 | + <li> | |
| 107 | + <a href="#"> | |
| 108 | + <i class="fa fa-users text-aqua"></i> 5 new members joined today | |
| 109 | + </a> | |
| 110 | + </li> | |
| 111 | + <li> | |
| 112 | + <a href="#"> | |
| 113 | + <i class="fa fa-warning text-yellow"></i> Very long description here that may not fit into the | |
| 114 | + page and may cause design problems | |
| 115 | + </a> | |
| 116 | + </li> | |
| 117 | + <li> | |
| 118 | + <a href="#"> | |
| 119 | + <i class="fa fa-users text-red"></i> 5 new members joined | |
| 120 | + </a> | |
| 121 | + </li> | |
| 122 | + <li> | |
| 123 | + <a href="#"> | |
| 124 | + <i class="fa fa-shopping-cart text-green"></i> 25 sales made | |
| 125 | + </a> | |
| 126 | + </li> | |
| 127 | + <li> | |
| 128 | + <a href="#"> | |
| 129 | + <i class="fa fa-user text-red"></i> You changed your username | |
| 130 | + </a> | |
| 131 | + </li> | |
| 132 | + </ul> | |
| 133 | + </li> | |
| 134 | + <li class="footer"><a href="#">View all</a></li> | |
| 135 | + </ul> | |
| 136 | + </li> | |
| 137 | + <!-- Tasks: style can be found in dropdown.less --> | |
| 138 | + <li class="dropdown tasks-menu"> | |
| 139 | + <a href="#" class="dropdown-toggle" data-toggle="dropdown"> | |
| 140 | + <i class="fa fa-flag-o"></i> | |
| 141 | + <span class="label label-danger">9</span> | |
| 142 | + </a> | |
| 143 | + <ul class="dropdown-menu"> | |
| 144 | + <li class="header">You have 9 tasks</li> | |
| 145 | + <li> | |
| 146 | + <!-- inner menu: contains the actual data --> | |
| 147 | + <ul class="menu"> | |
| 148 | + <li><!-- Task item --> | |
| 149 | + <a href="#"> | |
| 150 | + <h3> | |
| 151 | + Design some buttons | |
| 152 | + <small class="pull-right">20%</small> | |
| 153 | + </h3> | |
| 154 | + <div class="progress xs"> | |
| 155 | + <div class="progress-bar progress-bar-aqua" style="width: 20%" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"> | |
| 156 | + <span class="sr-only">20% Complete</span> | |
| 157 | + </div> | |
| 158 | + </div> | |
| 159 | + </a> | |
| 160 | + </li> | |
| 161 | + <!-- end task item --> | |
| 162 | + <li><!-- Task item --> | |
| 163 | + <a href="#"> | |
| 164 | + <h3> | |
| 165 | + Create a nice theme | |
| 166 | + <small class="pull-right">40%</small> | |
| 167 | + </h3> | |
| 168 | + <div class="progress xs"> | |
| 169 | + <div class="progress-bar progress-bar-green" style="width: 40%" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"> | |
| 170 | + <span class="sr-only">40% Complete</span> | |
| 171 | + </div> | |
| 172 | + </div> | |
| 173 | + </a> | |
| 174 | + </li> | |
| 175 | + <!-- end task item --> | |
| 176 | + <li><!-- Task item --> | |
| 177 | + <a href="#"> | |
| 178 | + <h3> | |
| 179 | + Some task I need to do | |
| 180 | + <small class="pull-right">60%</small> | |
| 181 | + </h3> | |
| 182 | + <div class="progress xs"> | |
| 183 | + <div class="progress-bar progress-bar-red" style="width: 60%" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"> | |
| 184 | + <span class="sr-only">60% Complete</span> | |
| 185 | + </div> | |
| 186 | + </div> | |
| 187 | + </a> | |
| 188 | + </li> | |
| 189 | + <!-- end task item --> | |
| 190 | + <li><!-- Task item --> | |
| 191 | + <a href="#"> | |
| 192 | + <h3> | |
| 193 | + Make beautiful transitions | |
| 194 | + <small class="pull-right">80%</small> | |
| 195 | + </h3> | |
| 196 | + <div class="progress xs"> | |
| 197 | + <div class="progress-bar progress-bar-yellow" style="width: 80%" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"> | |
| 198 | + <span class="sr-only">80% Complete</span> | |
| 199 | + </div> | |
| 200 | + </div> | |
| 201 | + </a> | |
| 202 | + </li> | |
| 203 | + <!-- end task item --> | |
| 204 | + </ul> | |
| 205 | + </li> | |
| 206 | + <li class="footer"> | |
| 207 | + <a href="#">View all tasks</a> | |
| 208 | + </li> | |
| 209 | + </ul> | |
| 210 | + </li> | |
| 211 | + <!-- User Account: style can be found in dropdown.less --> | |
| 212 | + <li class="dropdown user user-menu"> | |
| 213 | + <a href="#" class="dropdown-toggle" data-toggle="dropdown"> | |
| 214 | + <!--img src="dist/img/user2-160x160.jpg" class="user-image" alt="User Image"--> | |
| 215 | + <span class="hidden-xs">Alexander Pierce</span> | |
| 216 | + </a> | |
| 217 | + <ul class="dropdown-menu"> | |
| 218 | + <!-- User image --> | |
| 219 | + <li class="user-header"> | |
| 220 | + <img src="dist/img/user2-160x160.jpg" class="img-circle" alt="User Image"> | |
| 221 | + | |
| 222 | + <p> | |
| 223 | + Alexander Pierce - Web Developer | |
| 224 | + <small>Member since Nov. 2012</small> | |
| 225 | + </p> | |
| 226 | + </li> | |
| 227 | + <!-- Menu Body --> | |
| 228 | + <li class="user-body"> | |
| 229 | + <div class="row"> | |
| 230 | + <div class="col-xs-4 text-center"> | |
| 231 | + <a href="#">Followers</a> | |
| 232 | + </div> | |
| 233 | + <div class="col-xs-4 text-center"> | |
| 234 | + <a href="#">Sales</a> | |
| 235 | + </div> | |
| 236 | + <div class="col-xs-4 text-center"> | |
| 237 | + <a href="#">Friends</a> | |
| 238 | + </div> | |
| 239 | + </div> | |
| 240 | + <!-- /.row --> | |
| 241 | + </li> | |
| 242 | + <!-- Menu Footer--> | |
| 243 | + <li class="user-footer"> | |
| 244 | + <div class="pull-left"> | |
| 245 | + <a href="#" class="btn btn-default btn-flat">Profile</a> | |
| 246 | + </div> | |
| 247 | + <div class="pull-right"> | |
| 248 | + <a href="#" class="btn btn-default btn-flat">Sign out</a> | |
| 249 | + </div> | |
| 250 | + </li> | |
| 251 | + </ul> | |
| 252 | + </li> | |
| 253 | + <!-- Control Sidebar Toggle Button --> | |
| 254 | + <li> | |
| 255 | + <a href="#" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a> | |
| 256 | + </li> | |
| 257 | + </ul> | |
| 258 | + </div> | |
| 259 | + </nav> | |
| 260 | +</header> | |
| 0 | 261 | \ No newline at end of file | ... | ... |
| 1 | +++ a/backend/views/layouts/main-sidebar.php | |
| 1 | +<?php | |
| 2 | +use yii\widgets\Menu; | |
| 3 | +?> | |
| 4 | +<aside class="main-sidebar"> | |
| 5 | + <!-- sidebar: style can be found in sidebar.less --> | |
| 6 | + <section class="sidebar"> | |
| 7 | + <!-- Sidebar user panel --> | |
| 8 | + <div class="user-panel" style="min-height: 60px;"> | |
| 9 | + <div class="pull-left image"> | |
| 10 | + <!--img src="dist/img/user2-160x160.jpg" class="img-circle" alt="User Image"--> | |
| 11 | + </div> | |
| 12 | + <div class="pull-left info"> | |
| 13 | + <p>Alexander Pierce</p> | |
| 14 | + <a href="#"><i class="fa fa-circle text-success"></i> Online</a> | |
| 15 | + </div> | |
| 16 | + </div> | |
| 17 | + <!-- search form --> | |
| 18 | + <form action="#" method="get" class="sidebar-form"> | |
| 19 | + <div class="input-group"> | |
| 20 | + <input type="text" name="q" class="form-control" placeholder="Search..."> | |
| 21 | + <span class="input-group-btn"> | |
| 22 | + <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i> | |
| 23 | + </button> | |
| 24 | + </span> | |
| 25 | + </div> | |
| 26 | + </form> | |
| 27 | + <!-- /.search form --> | |
| 28 | + <?= | |
| 29 | + Menu::widget([ | |
| 30 | + 'options' => ['class' => 'sidebar-menu'], | |
| 31 | + 'submenuTemplate' => "\n<ul class='treeview-menu'>\n{items}\n</ul>\n", | |
| 32 | + | |
| 33 | + 'items' => [ | |
| 34 | + ['label' => 'MAIN NAVIGATION', 'options'=>['class'=>'header']], | |
| 35 | + ['label' => "Блог", 'options'=>['class'=>'treeview'], 'url' => ['#'], | |
| 36 | + 'template'=>'<a href="{url}"> <i class="fa fa-dashboard"></i> <span>{label}</span> <i class="fa fa-angle-left pull-right"></i></a>', | |
| 37 | + 'items' => [ | |
| 38 | + ['label' => 'Просмотр', 'url' => ['blog/index']], | |
| 39 | + ['label' => 'Создать', 'url' => ['blog/create']], | |
| 40 | + ], | |
| 41 | + ], | |
| 42 | + ['label' => 'Заказы', 'url' => ['cart/index'], 'template'=>'<a href="{url}"> <i class="fa fa-dashboard"></i> <span>{label}</span></a>'], | |
| 43 | + ['label' => 'Products', 'url' => ['/product/manage']], | |
| 44 | + ['label' => 'Rubrication', 'url' => ['/rubrication/tax-group']], | |
| 45 | + ['label' => 'Relation', 'url' => ['/relation/manage']], | |
| 46 | + ], | |
| 47 | + | |
| 48 | + ]); | |
| 49 | + ?> | |
| 50 | + <!-- sidebar menu: : style can be found in sidebar.less --> | |
| 51 | + | |
| 52 | + </section> | |
| 53 | + <!-- /.sidebar --> | |
| 54 | +</aside> | |
| 0 | 55 | \ No newline at end of file | ... | ... |
| 1 | +++ a/backend/views/layouts/main-sidebar1.php | |
| 1 | +<?php | |
| 2 | +use yii\widgets\Menu; | |
| 3 | +?> | |
| 4 | +<aside class="main-sidebar"> | |
| 5 | + <!-- sidebar: style can be found in sidebar.less --> | |
| 6 | + <section class="sidebar"> | |
| 7 | + <!-- Sidebar user panel --> | |
| 8 | + <div class="user-panel"> | |
| 9 | + <div class="pull-left image"> | |
| 10 | + <img src="/admin/images/img/user2-160x160.jpg" class="img-circle" alt="User Image" /> | |
| 11 | + </div> | |
| 12 | + <div class="pull-left info"> | |
| 13 | + <p>Alexander Pierce</p> | |
| 14 | + <a href="#"><i class="fa fa-circle text-success"></i> Online</a> | |
| 15 | + </div> | |
| 16 | + </div> | |
| 17 | + <!-- search form --> | |
| 18 | + <form action="#" method="get" class="sidebar-form"> | |
| 19 | + <div class="input-group"> | |
| 20 | + <input type="text" name="q" class="form-control" placeholder="Search..." /> | |
| 21 | + <span class="input-group-btn"> | |
| 22 | + <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button> | |
| 23 | + </span> | |
| 24 | + </div> | |
| 25 | + </form> | |
| 26 | + <!-- /.search form --> | |
| 27 | + <!-- sidebar menu: : style can be found in sidebar.less --> | |
| 28 | + <?= | |
| 29 | + Menu::widget([ | |
| 30 | + 'options' => ['class' => 'sidebar-menu'], | |
| 31 | + 'linkTemplate'=>'<a href="{url}"><i class="fa fa-th"></i>{label}</a>', | |
| 32 | + 'submenuTemplate' => "\n<ul class='treeview-menu'>\n{items}\n</ul>\n", | |
| 33 | + 'items' => [ | |
| 34 | + ['label' => 'Главное меню', 'options'=>['class'=>'header']], | |
| 35 | + ['label' => 'Заказы', 'url' => ['cart/index']], | |
| 36 | + ['label' => "Загрузка файлов", 'options'=>['class'=>'treeview'], 'url' => ['#'], | |
| 37 | + 'items' => [ | |
| 38 | + ['label' => 'Кросс файлы', 'url' => ['crossing-upload/index']], | |
| 39 | + ['label' => 'Группы RG', 'url' => ['rg-grup/index']], | |
| 40 | + ['label' => "Прайс файлы", 'url' => ['#'], 'items' => [ | |
| 41 | + ['label' => 'Файлы на сервере', 'url' => ['parser/server-files']], | |
| 42 | + ['label' => 'Загрузить файл на сервер', 'url' => ['parser/index', 'mode' => 1]], | |
| 43 | + ['label' => 'Журнал загрузок', 'url' => ['log/index']], | |
| 44 | + ['label' => 'Ручная загрузка', 'url' => ['parser/index']], | |
| 45 | + ['label' => 'Проверка прайс файлов', 'url' => ['check-price/index']], | |
| 46 | + ['label' => 'Управление префиксами', 'url' => ['importers-prefix/index']], | |
| 47 | + ], | |
| 48 | + ], | |
| 49 | + ], | |
| 50 | + ], | |
| 51 | + ['label' => 'Управление ролями', 'options'=>['class'=>'label_3'],'url' => ['#'], 'items' => [ | |
| 52 | + ['label' => 'Покупатели', 'url' => ['accounts/index']], | |
| 53 | + ['label' => 'Поставщики', 'url' => ['importers/index']], | |
| 54 | + ['label' => 'Администраторы', 'url' => ['user/index']], | |
| 55 | + ['label' => 'Команда', 'url' => ['team/index']], | |
| 56 | + ['label' => 'Группы команды', 'url' => ['team-group/index']], | |
| 57 | + ], | |
| 58 | + ], | |
| 59 | + ['label' => 'Ценообразование', 'options'=>['class'=>'label_4'], 'url' => ['#'], 'items' => [ | |
| 60 | + ['label' => 'Курс', 'url' => ['currency/index']], | |
| 61 | + ['label' => 'Типы цен', 'url' => ['margins/index']], | |
| 62 | + ['label' => 'Коэфициенты на поставщиков', 'url' => ['margins-importers/index']], | |
| 63 | + ['label' => 'Коэфициенты на импорт поставщиков', 'url' => ['margins-importers-import/index']], | |
| 64 | + ['label' => 'Коэфициенты на группы RG', 'url' => ['margins-groups/index']], | |
| 65 | + ], | |
| 66 | + ], | |
| 67 | + ['label' => 'Справочник', 'options'=>['class'=>'label_5'], 'url' => ['#'], 'items' => [ | |
| 68 | + ['label' => 'Замены брендов', 'url' => ['brands-replace/index']], | |
| 69 | + ['label' => 'Карточки товаров', 'url' => ['details-description/index']], | |
| 70 | + ['label' => 'Товары поставщиков', 'url' => ['details/index']], | |
| 71 | + ['label' => 'Кроссы', 'url' => ['details-crosses/index']], | |
| 72 | + ['label' => 'Бренды', 'url' => ['brands/index']], | |
| 73 | + ['label' => 'Марки авто', 'url' => ['manufacturers/index']], | |
| 74 | + ['label' => 'Статусы заказов', 'url' => ['currency/index']], | |
| 75 | + ['label' => 'Типы доставок', 'url' => ['deliveries/index']], | |
| 76 | + ['label' => 'Категории товаров', 'url' => ['currency/index']], | |
| 77 | + ['label' => 'Vin коды', 'url' => ['currency/index']], | |
| 78 | + ['label' => 'Запросы по номеру', 'url' => ['currency/index']], | |
| 79 | + ['label' => 'Офисы', 'url' => ['offices/index']], | |
| 80 | + ], | |
| 81 | + ], | |
| 82 | + ['label' => 'Анализ', 'options'=>['class'=>'label_6'], 'url' => ['#'], 'items' => [ | |
| 83 | + ['label' => 'Бренды', 'url' => ['#']], | |
| 84 | + ], | |
| 85 | + ], | |
| 86 | + ['label' => 'Письма', 'options'=>['class'=>'label_7'], 'url' => ['#'], 'items' => [ | |
| 87 | + ['label' => 'Рассылка', 'url' => ['#']], | |
| 88 | + ['label' => 'Рассылка Прайсов', 'url' => ['price-mailing/index']], | |
| 89 | + ['label' => 'Сообщения об оплате', 'url' => ['pay-messages/index']], | |
| 90 | + ['label' => 'Шаблоны писем', 'url' => ['emails/index']], | |
| 91 | + ], | |
| 92 | + ], | |
| 93 | + ['label' => 'Элементы сайта', 'options'=>['class'=>'label_8'], 'url' => ['#'], 'items' => [ | |
| 94 | + ['label' => 'Текстовые страницы', 'url' => ['page/index']], | |
| 95 | + ['label' => 'Новости', 'url' => ['news/index']], | |
| 96 | + ['label' => 'Слайдер', 'url' => ['slider/index']], | |
| 97 | + ], | |
| 98 | + ], | |
| 99 | + ['label' => 'Платежные системы', 'options'=>['class'=>'label_9'], 'url' => ['#'], 'items' => [ | |
| 100 | + ['label' => 'Описание систем', 'url' => ['settings-merchants-list/index']], | |
| 101 | + ['label' => 'Хутки грош', 'url' => ['news/index']], | |
| 102 | + ['label' => 'QIWI', 'url' => ['slider/index']], | |
| 103 | + ['label' => 'ASSIST', 'url' => ['partners/index']], | |
| 104 | + ['label' => 'iPay', 'url' => ['team/index']], | |
| 105 | + ['label' => 'WEBPAY', 'url' => ['team-group/index']], | |
| 106 | + ['label' => 'Деньги.Online', 'url' => ['team-group/index']], | |
| 107 | + ['label' => 'ROBOKASSA', 'url' => ['team-group/index']], | |
| 108 | + ['label' => 'MONEXY', 'url' => ['team-group/index']], | |
| 109 | + ], | |
| 110 | + ], | |
| 111 | + | |
| 112 | + ], | |
| 113 | + | |
| 114 | + ]); | |
| 115 | + ?> | |
| 116 | + </section> | |
| 117 | + <!-- /.sidebar --> | |
| 118 | +</aside> | |
| 0 | 119 | \ No newline at end of file | ... | ... |
| 1 | +++ a/backend/views/layouts/main.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/* @var $this \yii\web\View */ | |
| 4 | +/* @var $content string */ | |
| 5 | + | |
| 6 | +use backend\assets\AdminLteAsset; | |
| 7 | +use backend\assets\AppAsset; | |
| 8 | +use yii\helpers\Html; | |
| 9 | + | |
| 10 | +AppAsset::register($this); | |
| 11 | +AdminLteAsset::register($this); | |
| 12 | +?> | |
| 13 | +<?php $this->beginPage() ?> | |
| 14 | +<!DOCTYPE html> | |
| 15 | +<html lang="<?= Yii::$app->language ?>" > | |
| 16 | +<head> | |
| 17 | + <meta charset="<?= Yii::$app->charset ?>"> | |
| 18 | + <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 19 | + <?= Html::csrfMetaTags() ?> | |
| 20 | + <title><?= Html::encode($this->title) ?></title> | |
| 21 | + <?php $this->head() ?> | |
| 22 | +</head> | |
| 23 | +<body class="hold-transition skin-blue sidebar-mini"> | |
| 24 | +<?php $this->beginBody() ?> | |
| 25 | +<div class="wrapper"> | |
| 26 | + | |
| 27 | + <?= $content ?> | |
| 28 | + | |
| 29 | +</div> | |
| 30 | +<!-- ./wrapper --> | |
| 31 | +<?php $this->endBody() ?> | |
| 32 | +</body> | |
| 33 | +</html> | |
| 34 | +<?php $this->endPage() ?> | ... | ... |
| 1 | +++ a/backend/views/site/error.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/* @var $this yii\web\View */ | |
| 4 | +/* @var $name string */ | |
| 5 | +/* @var $message string */ | |
| 6 | +/* @var $exception Exception */ | |
| 7 | + | |
| 8 | +use yii\helpers\Html; | |
| 9 | + | |
| 10 | +$this->title = $name; | |
| 11 | +?> | |
| 12 | +<div class="site-error"> | |
| 13 | + | |
| 14 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 15 | + | |
| 16 | + <div class="alert alert-danger"> | |
| 17 | + <?= nl2br(Html::encode($message)) ?> | |
| 18 | + </div> | |
| 19 | + | |
| 20 | + <p> | |
| 21 | + The above error occurred while the Web server was processing your request. | |
| 22 | + </p> | |
| 23 | + <p> | |
| 24 | + Please contact us if you think this is a server error. Thank you. | |
| 25 | + </p> | |
| 26 | + | |
| 27 | +</div> | ... | ... |
| 1 | +++ a/backend/views/site/index.php | ... | ... |
| 1 | +++ a/backend/views/site/login.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/* @var $this yii\web\View */ | |
| 4 | +/* @var $form yii\bootstrap\ActiveForm */ | |
| 5 | +/* @var $model \common\models\LoginForm */ | |
| 6 | + | |
| 7 | +use yii\helpers\Html; | |
| 8 | +use yii\bootstrap\ActiveForm; | |
| 9 | + | |
| 10 | +$this->title = 'Login'; | |
| 11 | +$this->params['breadcrumbs'][] = $this->title; | |
| 12 | +?> | |
| 13 | +<div class="site-login"> | |
| 14 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 15 | + | |
| 16 | + <p>Please fill out the following fields to login:</p> | |
| 17 | + | |
| 18 | + <div class="row"> | |
| 19 | + <div class="col-lg-5"> | |
| 20 | + <?php $form = ActiveForm::begin(['id' => 'login-form']); ?> | |
| 21 | + | |
| 22 | + <?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?> | |
| 23 | + | |
| 24 | + <?= $form->field($model, 'password')->passwordInput() ?> | |
| 25 | + | |
| 26 | + <?= $form->field($model, 'rememberMe')->checkbox() ?> | |
| 27 | + | |
| 28 | + <div class="form-group"> | |
| 29 | + <?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?> | |
| 30 | + </div> | |
| 31 | + | |
| 32 | + <?php ActiveForm::end(); ?> | |
| 33 | + </div> | |
| 34 | + </div> | |
| 35 | +</div> | ... | ... |
| 1 | +++ a/backend/web/css/site.css | |
| 1 | +html, | |
| 2 | +body { | |
| 3 | + height: 100%; | |
| 4 | +} | |
| 5 | + | |
| 6 | +.wrap { | |
| 7 | + min-height: 100%; | |
| 8 | + height: auto; | |
| 9 | + margin: 0 auto -60px; | |
| 10 | + padding: 0 0 60px; | |
| 11 | +} | |
| 12 | + | |
| 13 | +.wrap > .container { | |
| 14 | + padding: 70px 15px 20px; | |
| 15 | +} | |
| 16 | + | |
| 17 | +.footer { | |
| 18 | + height: 60px; | |
| 19 | + background-color: #f5f5f5; | |
| 20 | + border-top: 1px solid #ddd; | |
| 21 | + padding-top: 20px; | |
| 22 | +} | |
| 23 | + | |
| 24 | +.jumbotron { | |
| 25 | + text-align: center; | |
| 26 | + background-color: transparent; | |
| 27 | +} | |
| 28 | + | |
| 29 | +.jumbotron .btn { | |
| 30 | + font-size: 21px; | |
| 31 | + padding: 14px 24px; | |
| 32 | +} | |
| 33 | + | |
| 34 | +.not-set { | |
| 35 | + color: #c55; | |
| 36 | + font-style: italic; | |
| 37 | +} | |
| 38 | + | |
| 39 | +/* add sorting icons to gridview sort links */ | |
| 40 | +a.asc:after, a.desc:after { | |
| 41 | + position: relative; | |
| 42 | + top: 1px; | |
| 43 | + display: inline-block; | |
| 44 | + font-family: 'Glyphicons Halflings'; | |
| 45 | + font-style: normal; | |
| 46 | + font-weight: normal; | |
| 47 | + line-height: 1; | |
| 48 | + padding-left: 5px; | |
| 49 | +} | |
| 50 | + | |
| 51 | +a.asc:after { | |
| 52 | + content: /*"\e113"*/ "\e151"; | |
| 53 | +} | |
| 54 | + | |
| 55 | +a.desc:after { | |
| 56 | + content: /*"\e114"*/ "\e152"; | |
| 57 | +} | |
| 58 | + | |
| 59 | +.sort-numerical a.asc:after { | |
| 60 | + content: "\e153"; | |
| 61 | +} | |
| 62 | + | |
| 63 | +.sort-numerical a.desc:after { | |
| 64 | + content: "\e154"; | |
| 65 | +} | |
| 66 | + | |
| 67 | +.sort-ordinal a.asc:after { | |
| 68 | + content: "\e155"; | |
| 69 | +} | |
| 70 | + | |
| 71 | +.sort-ordinal a.desc:after { | |
| 72 | + content: "\e156"; | |
| 73 | +} | |
| 74 | + | |
| 75 | +.grid-view td { | |
| 76 | + white-space: nowrap; | |
| 77 | +} | |
| 78 | + | |
| 79 | +.grid-view .filters input, | |
| 80 | +.grid-view .filters select { | |
| 81 | + min-width: 50px; | |
| 82 | +} | |
| 83 | + | |
| 84 | +.hint-block { | |
| 85 | + display: block; | |
| 86 | + margin-top: 5px; | |
| 87 | + color: #999; | |
| 88 | +} | |
| 89 | + | |
| 90 | +.error-summary { | |
| 91 | + color: #a94442; | |
| 92 | + background: #fdf7f7; | |
| 93 | + border-left: 3px solid #eed3d7; | |
| 94 | + padding: 10px 20px; | |
| 95 | + margin: 0 0 15px 0; | |
| 96 | +} | |
| 97 | + | |
| 98 | +/* align the logout "link" (button in form) of the navbar */ | |
| 99 | +.nav > li > form { | |
| 100 | + padding: 8px; | |
| 101 | +} | |
| 102 | + | |
| 103 | +.nav > li > form > button:hover { | |
| 104 | + text-decoration: none; | |
| 105 | +} | ... | ... |
No preview for this file type
| 1 | +++ a/backend/web/js/fieldWidget.js | |
| 1 | +$(function(){ | |
| 2 | + $.each($('.delete-field-item'), function(index, value) { | |
| 3 | + var container = $(value).parents('.field_list').first(); | |
| 4 | + var count = $(container).find('.form-group').length; | |
| 5 | + if(count <= 1) { | |
| 6 | + $(container).find('.delete-field-item').addClass('hidden'); | |
| 7 | + } | |
| 8 | + }); | |
| 9 | + $(document).on('click', '.delete-field-item', function(){ | |
| 10 | + var container = $(this).parents('.field_list').first(); | |
| 11 | + $(this).parent('.form-group').remove(); | |
| 12 | + var count = $(container).find('.form-group').length; | |
| 13 | + if(count <= 1) { | |
| 14 | + $(container).find('.delete-field-item').addClass('hidden'); | |
| 15 | + } | |
| 16 | + }); | |
| 17 | + $(document).on('click', '[class*=add_field_w]', function() { | |
| 18 | + var container = $(this).siblings('.field_list').first(); | |
| 19 | + var count = $(container).find('.form-group').length; | |
| 20 | + if(count > 1) { | |
| 21 | + $(container).find('.delete-field-item').removeClass('hidden'); | |
| 22 | + } | |
| 23 | + }); | |
| 24 | +}); | |
| 0 | 25 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/behaviors/ShowImage.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\behaviors; | |
| 4 | + | |
| 5 | +use yii; | |
| 6 | +use yii\base\Behavior; | |
| 7 | + | |
| 8 | +class ShowImage extends Behavior | |
| 9 | +{ | |
| 10 | + function minImg($dir, $width, $height=null){ | |
| 11 | + if(empty($dir)){ | |
| 12 | + return $dir; | |
| 13 | + } | |
| 14 | + | |
| 15 | + if($width=='original'){ | |
| 16 | + $preg = '/\/(.[^\/]*)$/'; | |
| 17 | + preg_match('/\.(.[^.]*)$/', $dir, $type); | |
| 18 | + $row = preg_replace( $preg, '/original.'.$type[1], $dir); | |
| 19 | + } else { | |
| 20 | + $preg = '/\/(.[^\/]*)$/'; | |
| 21 | + preg_match('/\.(.[^.]*)$/', $dir, $type); | |
| 22 | + $row = preg_replace( $preg, '/'.$width.'x'.$height.'.'.$type[1], $dir); | |
| 23 | + } | |
| 24 | + | |
| 25 | + return $row; | |
| 26 | + | |
| 27 | + | |
| 28 | + } | |
| 29 | + | |
| 30 | + function ShowGallery($array){ | |
| 31 | + | |
| 32 | + $gallery = explode(',', $array ); | |
| 33 | + if(is_array($gallery)){ | |
| 34 | + array_splice($gallery,-1); | |
| 35 | + return $gallery; | |
| 36 | + } else { | |
| 37 | + return []; | |
| 38 | + } | |
| 39 | + | |
| 40 | + } | |
| 41 | + | |
| 42 | + | |
| 43 | +} | |
| 0 | 44 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/behaviors/Slug.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\behaviors; | |
| 4 | + | |
| 5 | +use yii; | |
| 6 | +use yii\base\Behavior; | |
| 7 | +use yii\db\ActiveRecord; | |
| 8 | +use dosamigos\transliterator\TransliteratorHelper; | |
| 9 | +class Slug extends Behavior | |
| 10 | +{ | |
| 11 | + public $in_attribute = 'name'; | |
| 12 | + public $out_attribute = 'slug'; | |
| 13 | + public $translit = true; | |
| 14 | + | |
| 15 | + public function events() | |
| 16 | + { | |
| 17 | + return [ | |
| 18 | + ActiveRecord::EVENT_BEFORE_VALIDATE => 'getSlug' | |
| 19 | + ]; | |
| 20 | + } | |
| 21 | + | |
| 22 | + public function getSlug( $event ) | |
| 23 | + { | |
| 24 | + if ( empty( $this->owner->{$this->out_attribute} ) ) { | |
| 25 | + $this->owner->{$this->out_attribute} = $this->generateSlug( $this->owner->{$this->in_attribute} ); | |
| 26 | + } else { | |
| 27 | + $this->owner->{$this->out_attribute} = $this->generateSlug( $this->owner->{$this->out_attribute} ); | |
| 28 | + } | |
| 29 | + } | |
| 30 | + | |
| 31 | + private function generateSlug( $slug ) | |
| 32 | + { | |
| 33 | + $slug = $this->slugify( $slug ); | |
| 34 | + if ( $this->checkUniqueSlug( $slug ) ) { | |
| 35 | + return $slug; | |
| 36 | + } else { | |
| 37 | + for ( $suffix = 2; !$this->checkUniqueSlug( $new_slug = $slug . '-' . $suffix ); $suffix++ ) {} | |
| 38 | + return $new_slug; | |
| 39 | + } | |
| 40 | + } | |
| 41 | + | |
| 42 | + private function slugify( $slug ) | |
| 43 | + { | |
| 44 | + if ( $this->translit ) { | |
| 45 | + return yii\helpers\Inflector::slug( TransliteratorHelper::process( $slug ), '-', true ); | |
| 46 | + } else { | |
| 47 | + return $this->slug( $slug, '-', true ); | |
| 48 | + } | |
| 49 | + } | |
| 50 | + | |
| 51 | + private function slug( $string, $replacement = '-', $lowercase = true ) | |
| 52 | + { | |
| 53 | + $string = preg_replace( '/[^\p{L}\p{Nd}]+/u', $replacement, $string ); | |
| 54 | + $string = trim( $string, $replacement ); | |
| 55 | + return $lowercase ? strtolower( $string ) : $string; | |
| 56 | + } | |
| 57 | + | |
| 58 | + private function checkUniqueSlug( $slug ) | |
| 59 | + { | |
| 60 | + $pk = $this->owner->primaryKey(); | |
| 61 | + $pk = $pk[0]; | |
| 62 | + | |
| 63 | + $condition = $this->out_attribute . ' = :out_attribute'; | |
| 64 | + $params = [ ':out_attribute' => $slug ]; | |
| 65 | + if ( !$this->owner->isNewRecord ) { | |
| 66 | + $condition .= ' and ' . $pk . ' != :pk'; | |
| 67 | + $params[':pk'] = $this->owner->{$pk}; | |
| 68 | + } | |
| 69 | + | |
| 70 | + return !$this->owner->find() | |
| 71 | + ->where( $condition, $params ) | |
| 72 | + ->one(); | |
| 73 | + } | |
| 74 | + | |
| 75 | +} | |
| 0 | 76 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/components/LangRequest.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components; | |
| 4 | + | |
| 5 | +use Yii; | |
| 6 | +use yii\base\InvalidConfigException; | |
| 7 | +use yii\web\Request; | |
| 8 | +use common\models\Language; | |
| 9 | +use common\models\Page; | |
| 10 | +use yii\helpers\Url; | |
| 11 | + | |
| 12 | +class LangRequest extends Request | |
| 13 | +{ | |
| 14 | + private $_lang_url; | |
| 15 | + | |
| 16 | + public function getBaseUrl() | |
| 17 | + { | |
| 18 | + return str_replace ((IS_FRONT ? '/frontend/web' : '/backend/web'), '', parent::getBaseUrl()) . (IS_FRONT ? '' : '/admin'); | |
| 19 | + } | |
| 20 | + | |
| 21 | + public function getLangUrl() | |
| 22 | + { | |
| 23 | + if ($this->_lang_url === null) | |
| 24 | + { | |
| 25 | + $this->_lang_url = $this->getUrl(); | |
| 26 | + | |
| 27 | + $url_list = explode ('/', $this->_lang_url); | |
| 28 | + | |
| 29 | + $lang_url = isset ($url_list[1]) ? $url_list[1] : null; | |
| 30 | + | |
| 31 | + Language::setCurrent($lang_url); | |
| 32 | + | |
| 33 | + if ($lang_url !== null && $lang_url === Language::getCurrent()->language_code | |
| 34 | + && strpos($this->_lang_url, Language::getCurrent()->language_code) === 1) | |
| 35 | + { | |
| 36 | + $this->_lang_url = substr ($this->_lang_url, strlen (Language::getCurrent()->language_code) + 1); | |
| 37 | + } | |
| 38 | + } | |
| 39 | + | |
| 40 | + return $this->_lang_url; | |
| 41 | + } | |
| 42 | + | |
| 43 | + protected function resolvePathInfo() | |
| 44 | + { | |
| 45 | + $pathInfo = $this->getLangUrl(); | |
| 46 | + | |
| 47 | + if (($pos = strpos ($pathInfo, '?')) !== false) | |
| 48 | + { | |
| 49 | + $pathInfo = substr ($pathInfo, 0, $pos); | |
| 50 | + } | |
| 51 | + | |
| 52 | + $pathInfo = urldecode ($pathInfo); | |
| 53 | + | |
| 54 | + // try to encode in UTF8 if not so | |
| 55 | + // http://w3.org/International/questions/qa-forms-utf-8.html | |
| 56 | + if (! preg_match ('%^(?: | |
| 57 | + [\x09\x0A\x0D\x20-\x7E] # ASCII | |
| 58 | + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | |
| 59 | + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | |
| 60 | + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | |
| 61 | + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | |
| 62 | + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | |
| 63 | + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | |
| 64 | + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 | |
| 65 | + )*$%xs', $pathInfo) | |
| 66 | + ) | |
| 67 | + { | |
| 68 | + $pathInfo = utf8_encode($pathInfo); | |
| 69 | + } | |
| 70 | + | |
| 71 | + $scriptUrl = $this->getScriptUrl(); | |
| 72 | + | |
| 73 | + $baseUrl = $this->getBaseUrl(); | |
| 74 | + | |
| 75 | + if (strpos($pathInfo, $scriptUrl) === 0) | |
| 76 | + { | |
| 77 | + $pathInfo = substr($pathInfo, strlen($scriptUrl)); | |
| 78 | + } | |
| 79 | + else if ($baseUrl === '' || strpos($pathInfo, $baseUrl) === 0) | |
| 80 | + { | |
| 81 | + $pathInfo = substr($pathInfo, strlen($baseUrl)); | |
| 82 | + } | |
| 83 | + elseif (isset ($_SERVER['PHP_SELF']) && strpos ($_SERVER['PHP_SELF'], $scriptUrl) === 0) | |
| 84 | + { | |
| 85 | + $pathInfo = substr($_SERVER['PHP_SELF'], strlen($scriptUrl)); | |
| 86 | + } | |
| 87 | + else | |
| 88 | + { | |
| 89 | + throw new InvalidConfigException('Unable to determine the path info of the current request.'); | |
| 90 | + } | |
| 91 | + | |
| 92 | + if ($pathInfo[0] === '/') | |
| 93 | + { | |
| 94 | + $pathInfo = substr ($pathInfo, 1); | |
| 95 | + } | |
| 96 | + | |
| 97 | + return (string) $pathInfo; | |
| 98 | + } | |
| 99 | +} | |
| 0 | 100 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/components/LangUrlManager.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components; | |
| 4 | + | |
| 5 | +use yii\web\UrlManager; | |
| 6 | +use common\models\Language; | |
| 7 | + | |
| 8 | +class LangUrlManager extends UrlManager | |
| 9 | +{ | |
| 10 | + public function createUrl ($params) | |
| 11 | + { | |
| 12 | + if (isset ($params['language_id'])) | |
| 13 | + { | |
| 14 | + //Если указан идентификатор языка, то делаем попытку найти язык в БД, | |
| 15 | + //иначе работаем с языком по умолчанию | |
| 16 | + if (($lang_code = Language::findOne($params['language_id'])) === null) | |
| 17 | + { | |
| 18 | + $lang_code = Language::getDefaultLang(); | |
| 19 | + } | |
| 20 | + | |
| 21 | + unset ($params['language_id']); | |
| 22 | + | |
| 23 | + } | |
| 24 | + else | |
| 25 | + { | |
| 26 | + //Если не указан параметр языка, то работаем с текущим языком | |
| 27 | + $lang_code = Language::getCurrent(); | |
| 28 | + } | |
| 29 | + | |
| 30 | + //Получаем сформированный URL(без префикса идентификатора языка) | |
| 31 | + $url = parent::createUrl($params); | |
| 32 | + | |
| 33 | + // Добавляем к URL префикс - буквенный идентификатор языка | |
| 34 | + | |
| 35 | + return $url == '/' ? '/'.$url : ($lang_code->is_default == 1 ? $url : '/'.$lang_code->lang_code.$url); | |
| 36 | + } | |
| 37 | +} | |
| 0 | 38 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/components/Request.php | |
| 1 | +<?php | |
| 2 | +namespace common\components; | |
| 3 | + | |
| 4 | +class Request extends \yii\web\Request | |
| 5 | + | |
| 6 | +{ | |
| 7 | + | |
| 8 | + public $web; | |
| 9 | + | |
| 10 | + public $adminUrl; | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + public function getBaseUrl() | |
| 15 | + | |
| 16 | + { | |
| 17 | + | |
| 18 | + return str_replace($this->web, "", parent::getBaseUrl()) . $this->adminUrl; | |
| 19 | + | |
| 20 | + } | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + public function resolvePathInfo() | |
| 25 | + | |
| 26 | + { | |
| 27 | + | |
| 28 | + if ($this->getUrl() === $this->adminUrl) { | |
| 29 | + | |
| 30 | + return ""; | |
| 31 | + | |
| 32 | + } else { | |
| 33 | + | |
| 34 | + return parent::resolvePathInfo(); | |
| 35 | + | |
| 36 | + } | |
| 37 | + | |
| 38 | + } | |
| 39 | + | |
| 40 | +} | |
| 0 | 41 | \ No newline at end of file | ... | ... |
common/components/artboxtree/ArtboxTreeBehavior.php
0 → 100644
| 1 | +++ a/common/components/artboxtree/ArtboxTreeBehavior.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree; | |
| 4 | + | |
| 5 | +use common\modules\rubrication\models\TaxOption; | |
| 6 | +use Yii; | |
| 7 | +use yii\base\Behavior; | |
| 8 | +use yii\base\Exception; | |
| 9 | +use yii\base\NotSupportedException; | |
| 10 | +use yii\db\ActiveRecord; | |
| 11 | +use yii\db\Expression; | |
| 12 | + | |
| 13 | +class ArtboxTreeBehavior extends Behavior { | |
| 14 | + | |
| 15 | + /** @var ActiveRecord $owner */ | |
| 16 | + public $owner; | |
| 17 | + | |
| 18 | + public $keyNameId; | |
| 19 | + public $keyNameParentId = 'parent_id'; | |
| 20 | + public $keyNameGroup = 'group'; | |
| 21 | + public $keyNamePath = 'path_int'; | |
| 22 | + public $keyNameDepth = 'depth'; // @todo -> $keyNameDepth; | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * @var string | |
| 26 | + */ | |
| 27 | + public $delimiter = '|'; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * @var ActiveRecord|self|null | |
| 31 | + */ | |
| 32 | + protected $entity; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * @param ActiveRecord $owner | |
| 36 | + * @throws Exception | |
| 37 | + */ | |
| 38 | + public function attach($owner) | |
| 39 | + { | |
| 40 | + parent::attach($owner); | |
| 41 | + if ($this->keyNameId === null) { | |
| 42 | + $primaryKey = $owner->primaryKey(); | |
| 43 | + if (!isset($primaryKey[0])) { | |
| 44 | + throw new Exception('"' . $owner->className() . '" must have a primary key.'); | |
| 45 | + } | |
| 46 | + $this->keyNameId = $primaryKey[0]; | |
| 47 | + } | |
| 48 | + } | |
| 49 | + | |
| 50 | + public function events() | |
| 51 | + { | |
| 52 | + return [ | |
| 53 | + // @todo Use beforeSave for automatic set MP-params | |
| 54 | + ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeUpdate', | |
| 55 | + ActiveRecord::EVENT_AFTER_INSERT => 'afterInsert', | |
| 56 | + ]; | |
| 57 | + } | |
| 58 | + | |
| 59 | + /* | |
| 60 | + * Main methods | |
| 61 | + */ | |
| 62 | + | |
| 63 | + /* | |
| 64 | + * get one parent | |
| 65 | + * use AL-method | |
| 66 | + */ | |
| 67 | + public function getParent() { | |
| 68 | + return $this->getParentAL(); | |
| 69 | + } | |
| 70 | + | |
| 71 | + /* | |
| 72 | + * get all parents | |
| 73 | + * use MP-method | |
| 74 | + */ | |
| 75 | + public function getParents() { | |
| 76 | + return $this->getParentsMP(); | |
| 77 | + } | |
| 78 | + | |
| 79 | + /* | |
| 80 | + * get one-level children items | |
| 81 | + * use AL-method | |
| 82 | + */ | |
| 83 | + public function getChildren() { | |
| 84 | + return $this->getChildrenAL(); | |
| 85 | + } | |
| 86 | + | |
| 87 | + /* | |
| 88 | + * get all-level children items | |
| 89 | + * use MP-method | |
| 90 | + */ | |
| 91 | + public function getAllChildren($depth = null) { | |
| 92 | + return $this->getAllChildrenMP($depth); | |
| 93 | + } | |
| 94 | + | |
| 95 | + | |
| 96 | + /* | |
| 97 | + * ================================ | |
| 98 | + * MP-methods | |
| 99 | + * ================================ | |
| 100 | + */ | |
| 101 | + | |
| 102 | + /* | |
| 103 | + * Full-path (use MP-method) | |
| 104 | + */ | |
| 105 | + public function getParentsMP($depth = null) { | |
| 106 | + $path = $this->getParentPath(); | |
| 107 | + if ($path !== null) { | |
| 108 | + $paths = str_replace(['{', '}'], '', explode(',', $path)); | |
| 109 | + if (!$this->primaryKeyMode) { | |
| 110 | + $path = null; | |
| 111 | + $paths = array_map( | |
| 112 | + function ($value) use (&$path) { | |
| 113 | + return $path = ($path !== null ? $path . ',' : '') . $value; | |
| 114 | + }, | |
| 115 | + $paths | |
| 116 | + ); | |
| 117 | + } | |
| 118 | + if ($depth !== null) { | |
| 119 | + $paths = array_slice($paths, -$depth); | |
| 120 | + } | |
| 121 | + } else { | |
| 122 | + $paths = []; | |
| 123 | + } | |
| 124 | + | |
| 125 | + $tableName = $this->owner->tableName(); | |
| 126 | + $condition = ['and']; | |
| 127 | + if ($this->primaryKeyMode) { | |
| 128 | + $condition[] = ["{$tableName}.[[{$this->keyNameId}]]" => $paths]; | |
| 129 | + } else { | |
| 130 | + $condition[] = ["{$tableName}.[[{$this->keyNamePath}]]" => $paths]; | |
| 131 | + } | |
| 132 | + | |
| 133 | + $query = $this->owner->find() | |
| 134 | + ->andWhere($condition) | |
| 135 | + ->andWhere($this->treeCondition()) | |
| 136 | + ->addOrderBy(["{$tableName}.[[{$this->keyNamePath}]]" => SORT_ASC]); | |
| 137 | + $query->multiple = true; | |
| 138 | + | |
| 139 | + return $query; | |
| 140 | + } | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * @param bool $asArray = false | |
| 144 | + * @return null|string|array | |
| 145 | + */ | |
| 146 | + public function getParentPath($asArray = false) | |
| 147 | + { | |
| 148 | + return static::getParentPathInternal($this->owner->getAttribute($this->keyNamePath), $asArray); | |
| 149 | + } | |
| 150 | + | |
| 151 | + public function getAllChildrenMP($depth = null) | |
| 152 | + { | |
| 153 | + $tableName = $this->owner->tableName(); | |
| 154 | + $path = $this->owner->getAttribute($this->keyNamePath); | |
| 155 | + $query = $this->owner->find() | |
| 156 | + ->andWhere(['@>', "{$tableName}.[[{$this->keyNamePath}]]", $this->getLike($path), false]); | |
| 157 | + | |
| 158 | + | |
| 159 | + if ($depth > 0) { | |
| 160 | + $query->andWhere(['<=', "{$tableName}.[[{$this->keyNameDepth}]]", $this->owner->getAttribute($this->keyNameDepth) + $depth]); | |
| 161 | + } | |
| 162 | + | |
| 163 | + $orderBy = []; | |
| 164 | + $orderBy["{$tableName}.[[{$this->keyNameDepth}]]"] = SORT_ASC; | |
| 165 | + $orderBy["{$tableName}.[[{$this->keyNameId}]]"] = SORT_ASC; | |
| 166 | + | |
| 167 | + $query | |
| 168 | + ->andWhere($this->treeCondition()) | |
| 169 | + ->addOrderBy($orderBy); | |
| 170 | + $query->multiple = true; | |
| 171 | + | |
| 172 | + return $query; | |
| 173 | + } | |
| 174 | + | |
| 175 | + /* | |
| 176 | + * ================================ | |
| 177 | + * AL methods | |
| 178 | + * ================================ | |
| 179 | + */ | |
| 180 | + | |
| 181 | + /* | |
| 182 | + * Parent entity (use AL-method) | |
| 183 | + * @return \yii\db\ActiveRecord | |
| 184 | + */ | |
| 185 | + public function getParentAL() { | |
| 186 | + $parent_id = $this->owner->getAttribute($this->keyNameParentId); | |
| 187 | + if (empty($parent_id)) | |
| 188 | + return null; | |
| 189 | + return $this->owner->find()->where([$this->keyNameId => $parent_id, $this->keyNameGroup => $this->owner->getAttribute($this->keyNameGroup)])->one(); | |
| 190 | + } | |
| 191 | + | |
| 192 | + /* | |
| 193 | + * Get parents by AL-method | |
| 194 | + * @return array | |
| 195 | + */ | |
| 196 | + public function getParentsAL() { | |
| 197 | + $parent_id = $this->owner->getAttribute($this->keyNameParentId); | |
| 198 | + if ($parent_id == 0) { | |
| 199 | + return []; | |
| 200 | + } | |
| 201 | + | |
| 202 | + $parent = $this->owner; | |
| 203 | + $parents = []; | |
| 204 | + while(true) { | |
| 205 | + $parent = $parent->getParentAL(); | |
| 206 | + if (is_null($parent)) | |
| 207 | + break; | |
| 208 | + $parents[] = $parent; | |
| 209 | + } | |
| 210 | + | |
| 211 | + return array_reverse($parents); | |
| 212 | + } | |
| 213 | + | |
| 214 | + /* | |
| 215 | + * Children entities (one-step) (use AL-method) | |
| 216 | + * @return ActiveQuery | |
| 217 | + */ | |
| 218 | + public function getChildrenAL() { | |
| 219 | + return $this->owner->find()->where([$this->keyNameParentId => $this->owner->getAttribute($this->keyNameId), $this->keyNameGroup => $this->owner->getAttribute($this->keyNameGroup)]); | |
| 220 | + } | |
| 221 | + | |
| 222 | + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 223 | + | |
| 224 | + /** | |
| 225 | + * @param array $changedAttributes | |
| 226 | + * @throws Exception | |
| 227 | + */ | |
| 228 | + protected function _rebuildChildren($changedAttributes) | |
| 229 | + { | |
| 230 | + $path = isset($changedAttributes[$this->keyNamePath]) ? $changedAttributes[$this->keyNamePath] : $this->owner->getAttribute($this->keyNamePath); | |
| 231 | + $update = []; | |
| 232 | + $condition = [ | |
| 233 | + 'and', | |
| 234 | + ['@>', "[[{$this->keyNamePath}]]", $path, false], | |
| 235 | + ]; | |
| 236 | + if ($this->keyNameGroup !== null) { | |
| 237 | + $group = isset($changedAttributes[$this->keyNameGroup]) ? $changedAttributes[$this->keyNameGroup] : $this->owner->getAttribute($this->keyNameGroup); | |
| 238 | + $condition[] = [$this->keyNameGroup => $group]; | |
| 239 | + } | |
| 240 | + $params = []; | |
| 241 | + | |
| 242 | + if (isset($changedAttributes[$this->keyNamePath])) { | |
| 243 | + $substringExpr = $this->substringExpression( | |
| 244 | + "[[{$this->keyNamePath}]]", | |
| 245 | + 'array_length(:pathOld) + 1', | |
| 246 | + "array_length([[{$this->keyNamePath}]]) - array_length(:pathOld)" | |
| 247 | + ); | |
| 248 | + $update[$this->keyNamePath] = new Expression($this->concatExpression([':pathNew', $substringExpr])); | |
| 249 | + $params[':pathOld'] = $path; | |
| 250 | + $params[':pathNew'] = $this->owner->getAttribute($this->keyNamePath); | |
| 251 | + } | |
| 252 | + | |
| 253 | + if ($this->keyNameGroup !== null && isset($changedAttributes[$this->keyNameGroup])) { | |
| 254 | + $update[$this->keyNameGroup] = $this->owner->getAttribute($this->keyNameGroup); | |
| 255 | + } | |
| 256 | + | |
| 257 | + if ($this->keyNameDepth !== null && isset($changedAttributes[$this->keyNameDepth])) { | |
| 258 | + $delta = $this->owner->getAttribute($this->keyNameDepth) - $changedAttributes[$this->keyNameDepth]; | |
| 259 | + $update[$this->keyNameDepth] = new Expression("[[{$this->keyNameDepth}]]" . sprintf('%+d', $delta)); | |
| 260 | + } | |
| 261 | + if (!empty($update)) { | |
| 262 | + $this->owner->updateAll($update, $condition, $params); | |
| 263 | + } | |
| 264 | + } | |
| 265 | + | |
| 266 | + /** | |
| 267 | + * @param string $path | |
| 268 | + * @param string $delimiter | |
| 269 | + * @param bool $asArray = false | |
| 270 | + * @return null|string|array | |
| 271 | + */ | |
| 272 | + protected static function getParentPathInternal($path, $asArray = false) | |
| 273 | + { | |
| 274 | + $path = str_replace(['{', '}'], '', explode(',', $path)); | |
| 275 | + array_pop($path); | |
| 276 | + if ($asArray) { | |
| 277 | + return $path; | |
| 278 | + } | |
| 279 | + return count($path) > 0 ? implode(',', $path) : null; | |
| 280 | + } | |
| 281 | + | |
| 282 | + protected function toLike($path) { | |
| 283 | + return strtr($path . ',', ['%' => '\%', '_' => '\_', '\\' => '\\\\']) . '%'; | |
| 284 | + } | |
| 285 | + | |
| 286 | + protected function concatExpression($items) | |
| 287 | + { | |
| 288 | + if ($this->owner->getDb()->driverName === 'sqlite' || $this->owner->getDb()->driverName === 'pgsql') { | |
| 289 | + return implode(' || ', $items); | |
| 290 | + } | |
| 291 | + return 'CONCAT(' . implode(',', $items) . ')'; | |
| 292 | + } | |
| 293 | + | |
| 294 | + protected function substringExpression($string, $from, $length) | |
| 295 | + { | |
| 296 | + if ($this->owner->getDb()->driverName === 'sqlite') { | |
| 297 | + return "SUBSTR({$string}, {$from}, {$length})"; | |
| 298 | + } | |
| 299 | + return "SUBSTRING({$string}, {$from}, {$length})"; | |
| 300 | + } | |
| 301 | + | |
| 302 | + // ======================================================= | |
| 303 | + public function afterInsert() { | |
| 304 | + $this->withSave(); | |
| 305 | + $this->owner->updateAttributes([$this->keyNamePath => $this->owner->getAttribute($this->keyNamePath), $this->keyNameDepth => $this->owner->getAttribute($this->keyNameDepth)]); | |
| 306 | + } | |
| 307 | + | |
| 308 | + public function beforeUpdate() | |
| 309 | + { | |
| 310 | + if ($this->owner->getIsNewRecord()) { | |
| 311 | + throw new NotSupportedException('Method "' . $this->owner->className() . '::insert" is not supported for inserting new entitys.'); | |
| 312 | + } | |
| 313 | + $this->withSave(); | |
| 314 | + } | |
| 315 | + | |
| 316 | + protected function withSave() { | |
| 317 | + $id = $this->owner->getAttribute($this->keyNameId); | |
| 318 | + $parent_id = $this->owner->getAttribute($this->keyNameParentId); | |
| 319 | + | |
| 320 | + if (is_null($parent_id)) { | |
| 321 | + $parent_id = 0; | |
| 322 | + } | |
| 323 | + | |
| 324 | + // check parent_id value is changed! | |
| 325 | + /*if ($this->owner->getOldAttribute($this->keyNameParentId) == $parent_id) { | |
| 326 | + return; | |
| 327 | + }*/ | |
| 328 | + | |
| 329 | + // rebuild parents entities | |
| 330 | + if ($parent_id == 0) { | |
| 331 | + $depth = 0; | |
| 332 | + $path = [intval($id)]; | |
| 333 | + } else { | |
| 334 | + $parents = $this->getParentsAL(); | |
| 335 | + $path = []; | |
| 336 | + $depth = 0; | |
| 337 | + foreach ($parents as $entity) { | |
| 338 | + $path[] = $entity->getAttribute($this->keyNameId); | |
| 339 | + $depth++; | |
| 340 | + } | |
| 341 | + $path[] = intval($id); | |
| 342 | + } | |
| 343 | + | |
| 344 | + $path = '{'. implode(',', $path) .'}'; | |
| 345 | + | |
| 346 | + // rebuild children entities (recurcive) | |
| 347 | +// $this->_rebuildChildren([ | |
| 348 | +// $this->keyNamePath => $path | |
| 349 | +// ]); | |
| 350 | + | |
| 351 | + $this->owner->setAttribute('path_int', $path); | |
| 352 | +// $this->owner->setAttribute($this->keyNamePath, $path); | |
| 353 | + $this->owner->setAttribute($this->keyNameDepth, $depth); | |
| 354 | + } | |
| 355 | + | |
| 356 | + public function _recursiveRebuildChildren() { | |
| 357 | + $children = $this->getChildrenAL()->all(); | |
| 358 | + $root_path = explode(',', $this->owner->getAttribute($this->keyNamePath)); | |
| 359 | + $root_depth = $this->owner->getAttribute($this->keyNameDepth); | |
| 360 | + | |
| 361 | + /** @var $child ActiveRecord */ | |
| 362 | + foreach ($children as $child) { | |
| 363 | + $path = $root_path; | |
| 364 | + $path[] = $child->getAttribute($this->keyNameId); | |
| 365 | + $depth = $root_depth + 1; | |
| 366 | + | |
| 367 | + $child->_recursiveRebuildChildren(); | |
| 368 | + } | |
| 369 | + } | |
| 370 | +} | |
| 0 | 371 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/components/artboxtree/ArtboxTreeHelper.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree; | |
| 4 | + | |
| 5 | +use yii\base\Object; | |
| 6 | +use yii\helpers\ArrayHelper; | |
| 7 | + | |
| 8 | +class ArtboxTreeHelper extends Object { | |
| 9 | + public static function treeMap($tree, $from, $to, $symbol = '.') | |
| 10 | + { | |
| 11 | + $result = []; | |
| 12 | + | |
| 13 | + self::_recursiveTreeMap($result, $tree, $from, $to, $symbol); | |
| 14 | + | |
| 15 | + return $result; | |
| 16 | + } | |
| 17 | + | |
| 18 | + protected static function _recursiveTreeMap(&$result, $tree, $from, $to, $symbol = '–') { | |
| 19 | + foreach ($tree as $item) { | |
| 20 | + $element = $item['item']; | |
| 21 | + $key = ArrayHelper::getValue($element, $from); | |
| 22 | + $value = ArrayHelper::getValue($element, $to); | |
| 23 | + $row = str_repeat($symbol, $element->depth+1) . $value; | |
| 24 | + $result[$key] = $row; | |
| 25 | + if (!empty($item['children'])) { | |
| 26 | + self::_recursiveTreeMap($result, $item['children'], $from, $to, $symbol); | |
| 27 | + } | |
| 28 | + } | |
| 29 | + } | |
| 30 | +} | |
| 0 | 31 | \ No newline at end of file | ... | ... |
common/components/artboxtree/ArtboxTreeQueryTrait.php
0 → 100644
| 1 | +++ a/common/components/artboxtree/ArtboxTreeQueryTrait.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree; | |
| 4 | + | |
| 5 | +use common\components\artboxtree\ArtboxTreeHelper; | |
| 6 | + | |
| 7 | +trait ArtboxTreeQueryTrait { | |
| 8 | + | |
| 9 | + static public $cache_tree = []; | |
| 10 | + | |
| 11 | + /** @var \yii\db\ActiveQuery $this */ | |
| 12 | + static $model; | |
| 13 | + | |
| 14 | + /* | |
| 15 | + * @return \yii\db\ActiveQuery | |
| 16 | + */ | |
| 17 | + private function getModel() | |
| 18 | + { | |
| 19 | + if (empty(self::$model)) { | |
| 20 | + $class = $this->modelClass; | |
| 21 | + self::$model = new $class; | |
| 22 | + } | |
| 23 | + return self::$model; | |
| 24 | + } | |
| 25 | + | |
| 26 | + public function getTree($group, $cached = true) { | |
| 27 | + if ($cached && isset(self::$cache_tree[$group])) | |
| 28 | + return self::$cache_tree[$group]; | |
| 29 | + | |
| 30 | + $model = $this->getModel(); | |
| 31 | + $data = $this->andWhere([$model->keyNameGroup => $group])->all(); | |
| 32 | + if (empty($data)) | |
| 33 | + return []; | |
| 34 | + | |
| 35 | + self::$cache_tree[$group] = $this->buildTree($data); | |
| 36 | + | |
| 37 | + return self::$cache_tree[$group]; | |
| 38 | + } | |
| 39 | + | |
| 40 | + private function _recursiveRebuild($tree, $parentPath = null, $depth = 0) { | |
| 41 | + $model = $this->getModel(); | |
| 42 | + | |
| 43 | + foreach ($tree as $row) { | |
| 44 | + $path = (is_null($parentPath) ? '' : $parentPath . $model->delimiter) . $row['item']->getAttribute($model->keyNameId); | |
| 45 | + $row['item']->setAttribute($model->keyNamePath, $path); | |
| 46 | + $row['item']->setAttribute($model->keyNameDepth, $depth); | |
| 47 | + $row['item']->save(); | |
| 48 | + if (!empty($row['children'])) { | |
| 49 | + $this->_recursiveRebuild($row['children'], $path, $depth+1); | |
| 50 | + } | |
| 51 | + } | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * @param int $group | |
| 56 | + */ | |
| 57 | + public function rebuildMP($group) { | |
| 58 | + $tree = $this->getTree($group); | |
| 59 | + | |
| 60 | + $this->_recursiveRebuild($tree); | |
| 61 | + } | |
| 62 | + | |
| 63 | + protected function buildTree(array $data, $parentId = 0) { | |
| 64 | + $model = $this->getModel(); | |
| 65 | + | |
| 66 | + $result = []; | |
| 67 | + foreach ($data as $element) { | |
| 68 | + if ($element[$model->keyNameParentId] == $parentId) { | |
| 69 | + $children = $this->buildTree($data, $element[$model->keyNameId]); | |
| 70 | + $result[] = [ | |
| 71 | + 'item' => $element, | |
| 72 | + 'children' => $children | |
| 73 | + ]; | |
| 74 | + } | |
| 75 | + } | |
| 76 | + return $result; | |
| 77 | + } | |
| 78 | + | |
| 79 | + public function normalizeTreeData(array $data, $parentId = null) | |
| 80 | + { | |
| 81 | + $model = $this->getModel(); | |
| 82 | + | |
| 83 | + $result = []; | |
| 84 | + foreach ($data as $element) { | |
| 85 | + if ($element[$model->keyNameParentId] == $parentId) { | |
| 86 | + $result[] = $element; | |
| 87 | + $children = $this->normalizeTreeData($data, $element[$model->keyNameId]); | |
| 88 | + if ($children) { | |
| 89 | + $result = array_merge($result, $children); | |
| 90 | + } | |
| 91 | + } | |
| 92 | + } | |
| 93 | + return $result; | |
| 94 | + } | |
| 95 | +} | |
| 0 | 96 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/components/artboxtree/ArtboxTreeWidget.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree; | |
| 4 | + | |
| 5 | +use Yii; | |
| 6 | +use yii\base\Widget; | |
| 7 | +use yii\i18n\Formatter; | |
| 8 | +use yii\base\InvalidConfigException; | |
| 9 | + | |
| 10 | +class ArtboxTreeWidget extends Widget | |
| 11 | +{ | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * @var \yii\data\DataProviderInterface the data provider for the view. This property is required. | |
| 15 | + */ | |
| 16 | + public $dataProvider; | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * @var string | |
| 20 | + */ | |
| 21 | + public $keyNameId = 'id'; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * @var string | |
| 25 | + */ | |
| 26 | + public $keyNameParentId = 'parent_id'; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * @var integer or null | |
| 30 | + */ | |
| 31 | + public $maxLevel = null; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * @var integer | |
| 35 | + */ | |
| 36 | + public $rootParentId = 0; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * @var string | |
| 40 | + */ | |
| 41 | + public $emptyResult; | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * @var boolean include the CSS and JS files. Default is true. | |
| 45 | + * If this is set false, you are responsible to explicitly include the necessary CSS and JS files in your page. | |
| 46 | + */ | |
| 47 | + public $assetBundle; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * @var array|Formatter the formatter used to format model attribute values into displayable texts. | |
| 51 | + * This can be either an instance of [[Formatter]] or an configuration array for creating the [[Formatter]] | |
| 52 | + * instance. If this property is not set, the "formatter" application component will be used. | |
| 53 | + */ | |
| 54 | + public $formatter; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * Init the widget object. | |
| 58 | + */ | |
| 59 | + public function init() | |
| 60 | + { | |
| 61 | + parent::init(); | |
| 62 | + if ($this->dataProvider === null) { | |
| 63 | + throw new InvalidConfigException('The "dataProvider" property must be set.'); | |
| 64 | + } | |
| 65 | + if ($this->keyNameId === null) { | |
| 66 | + throw new InvalidConfigException('The "keyNameId" property must be set.'); | |
| 67 | + } | |
| 68 | + if ($this->formatter == null) { | |
| 69 | + $this->formatter = Yii::$app->getFormatter(); | |
| 70 | + } elseif (is_array($this->formatter)) { | |
| 71 | + $this->formatter = Yii::createObject($this->formatter); | |
| 72 | + } | |
| 73 | + if (!$this->formatter instanceof Formatter) { | |
| 74 | + throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.'); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Runs the widget. | |
| 80 | + */ | |
| 81 | + public function run() | |
| 82 | + { | |
| 83 | + if (!empty($this->assetBundle) && class_exists($this->assetBundle)) { | |
| 84 | + $view = $this->getView(); | |
| 85 | + $assetBundle = $this->assetBundle; | |
| 86 | + $assetBundle::register($view); | |
| 87 | + } | |
| 88 | + if ($this->dataProvider->getCount() == 0) { | |
| 89 | + return $this->renderEmptyResult(); | |
| 90 | + } | |
| 91 | + | |
| 92 | + parent::run(); | |
| 93 | + } | |
| 94 | + | |
| 95 | + protected function renderEmptyResult() { | |
| 96 | + return empty($this->emptyResult) ? Yii::t('artbox', 'TreeViewEmptyResult') : Yii::t('artbox', $this->emptyResult); | |
| 97 | + } | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Normalize tree data | |
| 101 | + * @param array $data | |
| 102 | + * @param string $parentId | |
| 103 | + * @return array | |
| 104 | + */ | |
| 105 | + protected function _normalizeTreeData(array $data, $parentId = null) { | |
| 106 | + $result = []; | |
| 107 | + foreach ($data as $element) { | |
| 108 | + if ($element[$this->keyNameParentId] == $parentId) { | |
| 109 | + $result[] = $element; | |
| 110 | + $children = $this->_normalizeTreeData($data, $element[$this->keyNameId]); | |
| 111 | + if ($children) { | |
| 112 | + $result = array_merge($result, $children); | |
| 113 | + } | |
| 114 | + } | |
| 115 | + } | |
| 116 | + return $result; | |
| 117 | + } | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * Hierarchy tree data | |
| 121 | + * @param array $data | |
| 122 | + * @param string $parentId | |
| 123 | + * @return array | |
| 124 | + */ | |
| 125 | + protected function _hierarchyTreeData(array $data, $parentId = null) { | |
| 126 | + $result = []; | |
| 127 | + foreach ($data as $element) { | |
| 128 | + if ($element[$this->keyNameParentId] == $parentId) { | |
| 129 | + $children = $this->_hierarchyTreeData($data, $element[$this->keyNameId]); | |
| 130 | + $result[] = [ | |
| 131 | + 'item' => $element, | |
| 132 | + 'children' => $children | |
| 133 | + ]; | |
| 134 | + } | |
| 135 | + } | |
| 136 | + return $result; | |
| 137 | + } | |
| 138 | +} | |
| 0 | 139 | \ No newline at end of file | ... | ... |
common/components/artboxtree/treegrid/TreeGridColumn.php
0 → 100644
| 1 | +++ a/common/components/artboxtree/treegrid/TreeGridColumn.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree\treegrid; | |
| 4 | + | |
| 5 | +use Closure; | |
| 6 | +use Yii; | |
| 7 | +use yii\base\Model; | |
| 8 | +use yii\base\Object; | |
| 9 | +use yii\data\ActiveDataProvider; | |
| 10 | +use yii\db\ActiveQueryInterface; | |
| 11 | +use yii\helpers\ArrayHelper; | |
| 12 | +use yii\helpers\Html; | |
| 13 | +use yii\helpers\Inflector; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * Column is the base class of all [[TreeGrid]] column classes. | |
| 17 | + * The code was based in: https://github.com/yiisoft/yii2/blob/master/framework/grid/DataColumn.php | |
| 18 | + * | |
| 19 | + * @author Leandro Gehlen <leandrogehlen@gmail.com> | |
| 20 | + */ | |
| 21 | +class TreeGridColumn extends Object { | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * @var TreeGrid the grid view object that owns this column. | |
| 25 | + */ | |
| 26 | + public $grid; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * @var string the header cell content. Note that it will not be HTML-encoded. | |
| 30 | + */ | |
| 31 | + public $header; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * @var string the footer cell content. Note that it will not be HTML-encoded. | |
| 35 | + */ | |
| 36 | + public $footer; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * @var callable This is a callable that will be used to generate the content of each cell. | |
| 40 | + * The signature of the function should be the following: `function ($model, $key, $index, $column)`. | |
| 41 | + * Where `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being rendered | |
| 42 | + * and `$column` is a reference to the [[TreeColumn]] object. | |
| 43 | + */ | |
| 44 | + public $content; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * @var boolean whether this column is visible. Defaults to true. | |
| 48 | + */ | |
| 49 | + public $visible = true; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * @var array the HTML attributes for the column group tag. | |
| 53 | + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. | |
| 54 | + */ | |
| 55 | + public $options = []; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * @var array the HTML attributes for the header cell tag. | |
| 59 | + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. | |
| 60 | + */ | |
| 61 | + public $headerOptions = []; | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * @var array|\Closure the HTML attributes for the data cell tag. This can either be an array of | |
| 65 | + * attributes or an anonymous function ([[Closure]]) that returns such an array. | |
| 66 | + * The signature of the function should be the following: `function ($model, $key, $index, $column)`. | |
| 67 | + * Where `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being rendered | |
| 68 | + * and `$column` is a reference to the [[Column]] object. | |
| 69 | + * A function may be used to assign different attributes to different rows based on the data in that row. | |
| 70 | + * | |
| 71 | + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. | |
| 72 | + */ | |
| 73 | + public $contentOptions = []; | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * @var array the HTML attributes for the footer cell tag. | |
| 77 | + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. | |
| 78 | + */ | |
| 79 | + public $footerOptions = []; | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * @var string the attribute name associated with this column. When neither [[content]] nor [[value]] | |
| 83 | + * is specified, the value of the specified attribute will be retrieved from each data model and displayed. | |
| 84 | + * | |
| 85 | + * Also, if [[label]] is not specified, the label associated with the attribute will be displayed. | |
| 86 | + */ | |
| 87 | + public $attribute; | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * @var string label to be displayed in the [[header|header cell]] and also to be used as the sorting | |
| 91 | + * link label when sorting is enabled for this column. | |
| 92 | + * If it is not set and the models provided by the GridViews data provider are instances | |
| 93 | + * of [[\yii\db\ActiveRecord]], the label will be determined using [[\yii\db\ActiveRecord::getAttributeLabel()]]. | |
| 94 | + * Otherwise [[\yii\helpers\Inflector::camel2words()]] will be used to get a label. | |
| 95 | + */ | |
| 96 | + public $label; | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * @var boolean whether the header label should be HTML-encoded. | |
| 100 | + * @see label | |
| 101 | + */ | |
| 102 | + public $encodeLabel = true; | |
| 103 | + | |
| 104 | + /** | |
| 105 | + * @var string|\Closure an anonymous function or a string that is used to determine the value to display in the current column. | |
| 106 | + * | |
| 107 | + * If this is an anonymous function, it will be called for each row and the return value will be used as the value to | |
| 108 | + * display for every data model. The signature of this function should be: `function ($model, $key, $index, $column)`. | |
| 109 | + * Where `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being rendered | |
| 110 | + * and `$column` is a reference to the [[DataColumn]] object. | |
| 111 | + * | |
| 112 | + * You may also set this property to a string representing the attribute name to be displayed in this column. | |
| 113 | + * This can be used when the attribute to be displayed is different from the [[attribute]] that is used for | |
| 114 | + * sorting and filtering. | |
| 115 | + * | |
| 116 | + * If this is not set, `$model[$attribute]` will be used to obtain the value, where `$attribute` is the value of [[attribute]]. | |
| 117 | + */ | |
| 118 | + public $value; | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * @var string|array in which format should the value of each data model be displayed as (e.g. `"raw"`, `"text"`, `"html"`, | |
| 122 | + * `['date', 'php:Y-m-d']`). Supported formats are determined by the [[GridView::formatter|formatter]] used by | |
| 123 | + * the [[GridView]]. Default format is "text" which will format the value as an HTML-encoded plain text when | |
| 124 | + * [[\yii\i18n\Formatter]] is used as the [[GridView::$formatter|formatter]] of the GridView. | |
| 125 | + */ | |
| 126 | + public $format = 'text'; | |
| 127 | + | |
| 128 | + /** | |
| 129 | + * Renders the header cell. | |
| 130 | + */ | |
| 131 | + public function renderHeaderCell() | |
| 132 | + { | |
| 133 | + return Html::tag('th', $this->renderHeaderCellContent(), $this->headerOptions); | |
| 134 | + } | |
| 135 | + | |
| 136 | + /** | |
| 137 | + * Renders the footer cell. | |
| 138 | + */ | |
| 139 | + public function renderFooterCell() | |
| 140 | + { | |
| 141 | + return Html::tag('td', $this->renderFooterCellContent(), $this->footerOptions); | |
| 142 | + } | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Renders a data cell. | |
| 146 | + * @param mixed $model the data model being rendered | |
| 147 | + * @param mixed $key the key associated with the data model | |
| 148 | + * @param integer $index the zero-based index of the data item among the item array returned by [[GridView::dataProvider]]. | |
| 149 | + * @return string the rendering result | |
| 150 | + */ | |
| 151 | + public function renderDataCell($model, $key, $index, $is_first = false, $symbol = '–') | |
| 152 | + { | |
| 153 | + if ($this->contentOptions instanceof Closure) { | |
| 154 | + $options = call_user_func($this->contentOptions, $model, $key, $index, $this); | |
| 155 | + } else { | |
| 156 | + $options = $this->contentOptions; | |
| 157 | + } | |
| 158 | + return Html::tag('td', ($is_first ? str_repeat($symbol, $model->depth) : '') . $this->renderDataCellContent($model, $key, $index), $options); | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Renders the header cell content. | |
| 163 | + * The default implementation simply renders [[header]]. | |
| 164 | + * This method may be overridden to customize the rendering of the header cell. | |
| 165 | + * @return string the rendering result | |
| 166 | + */ | |
| 167 | + protected function renderHeaderCellContent() | |
| 168 | + { | |
| 169 | + if ($this->header !== null || $this->label === null && $this->attribute === null) { | |
| 170 | + return trim($this->header) !== '' ? $this->header : $this->grid->emptyCell; | |
| 171 | + } | |
| 172 | + | |
| 173 | + $provider = $this->grid->dataProvider; | |
| 174 | + | |
| 175 | + if ($this->label === null) { | |
| 176 | + if ($provider instanceof ActiveDataProvider && $provider->query instanceof ActiveQueryInterface) { | |
| 177 | + /* @var $model Model */ | |
| 178 | + $model = new $provider->query->modelClass; | |
| 179 | + $label = $model->getAttributeLabel($this->attribute); | |
| 180 | + } else { | |
| 181 | + $models = $provider->getModels(); | |
| 182 | + if (($model = reset($models)) instanceof Model) { | |
| 183 | + /* @var $model Model */ | |
| 184 | + $label = $model->getAttributeLabel($this->attribute); | |
| 185 | + } else { | |
| 186 | + $label = Inflector::camel2words($this->attribute); | |
| 187 | + } | |
| 188 | + } | |
| 189 | + } else { | |
| 190 | + $label = $this->label; | |
| 191 | + } | |
| 192 | + | |
| 193 | + return $this->encodeLabel ? Html::encode($label) : $label; | |
| 194 | + } | |
| 195 | + | |
| 196 | + /** | |
| 197 | + * Renders the footer cell content. | |
| 198 | + * The default implementation simply renders [[footer]]. | |
| 199 | + * This method may be overridden to customize the rendering of the footer cell. | |
| 200 | + * @return string the rendering result | |
| 201 | + */ | |
| 202 | + protected function renderFooterCellContent() | |
| 203 | + { | |
| 204 | + return trim($this->footer) !== '' ? $this->footer : $this->grid->emptyCell; | |
| 205 | + } | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * Renders the data cell content. | |
| 209 | + * @param mixed $model the data model | |
| 210 | + * @param mixed $key the key associated with the data model | |
| 211 | + * @param integer $index the zero-based index of the data model among the models array returned by [[GridView::dataProvider]]. | |
| 212 | + * @return string the rendering result | |
| 213 | + */ | |
| 214 | + protected function renderDataCellContent($model, $key, $index) | |
| 215 | + { | |
| 216 | + if ($this->content === null) { | |
| 217 | + return $this->grid->formatter->format($this->getDataCellValue($model, $key, $index), $this->format); | |
| 218 | + } else { | |
| 219 | + if ($this->content !== null) { | |
| 220 | + return call_user_func($this->content, $model, $key, $index, $this); | |
| 221 | + } else { | |
| 222 | + return $this->grid->emptyCell; | |
| 223 | + } | |
| 224 | + } | |
| 225 | + | |
| 226 | + | |
| 227 | + } | |
| 228 | + | |
| 229 | + /** | |
| 230 | + * Returns the data cell value. | |
| 231 | + * @param mixed $model the data model | |
| 232 | + * @param mixed $key the key associated with the data model | |
| 233 | + * @param integer $index the zero-based index of the data model among the models array returned by [[GridView::dataProvider]]. | |
| 234 | + * @return string the data cell value | |
| 235 | + */ | |
| 236 | + public function getDataCellValue($model, $key, $index) | |
| 237 | + { | |
| 238 | + if ($this->value !== null) { | |
| 239 | + if (is_string($this->value)) { | |
| 240 | + return ArrayHelper::getValue($model, $this->value); | |
| 241 | + } else { | |
| 242 | + return call_user_func($this->value, $model, $key, $index, $this); | |
| 243 | + } | |
| 244 | + } elseif ($this->attribute !== null) { | |
| 245 | + return ArrayHelper::getValue($model, $this->attribute); | |
| 246 | + } | |
| 247 | + return null; | |
| 248 | + } | |
| 249 | + | |
| 250 | +} | |
| 0 | 251 | \ No newline at end of file | ... | ... |
common/components/artboxtree/treegrid/TreeGridWidget.php
0 → 100644
| 1 | +++ a/common/components/artboxtree/treegrid/TreeGridWidget.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree\treegrid; | |
| 4 | + | |
| 5 | +use common\modules\rubrication\models\TaxOption; | |
| 6 | +use Yii; | |
| 7 | +use yii\helpers\Html; | |
| 8 | +use yii\helpers\ArrayHelper; | |
| 9 | + | |
| 10 | +class TreeGridWidget extends \common\components\artboxtree\ArtboxTreeWidget { | |
| 11 | + | |
| 12 | + /** | |
| 13 | + * @var array grid column configuration. Each array element represents the configuration | |
| 14 | + * for one particular grid column. | |
| 15 | + * @see \yii\grid::$columns for details. | |
| 16 | + */ | |
| 17 | + public $columns = []; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * @var string the default data column class if the class name is not explicitly specified when configuring a data column. | |
| 21 | + * Defaults to 'leandrogehlen\treegrid\TreeGridColumn'. | |
| 22 | + */ | |
| 23 | + public $dataColumnClass; | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * @var array the HTML attributes for the container tag of the grid view. | |
| 27 | + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. | |
| 28 | + */ | |
| 29 | + public $options = ['class' => 'table table-striped table-bordered']; | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * @var array The plugin options | |
| 33 | + */ | |
| 34 | + public $pluginOptions = []; | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * @var boolean whether to show the grid view if [[dataProvider]] returns no data. | |
| 38 | + */ | |
| 39 | + public $showOnEmpty = true; | |
| 40 | + | |
| 41 | + public $rowOptions = []; | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * @var Closure an anonymous function that is called once BEFORE rendering each data model. | |
| 45 | + * It should have the similar signature as [[rowOptions]]. The return result of the function | |
| 46 | + * will be rendered directly. | |
| 47 | + */ | |
| 48 | + public $beforeRow; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * @var Closure an anonymous function that is called once AFTER rendering each data model. | |
| 52 | + * It should have the similar signature as [[rowOptions]]. The return result of the function | |
| 53 | + * will be rendered directly. | |
| 54 | + */ | |
| 55 | + public $afterRow; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * @var boolean whether to show the header section of the grid table. | |
| 59 | + */ | |
| 60 | + public $showHeader = true; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * @var array the HTML attributes for the table header row. | |
| 64 | + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. | |
| 65 | + */ | |
| 66 | + public $headerRowOptions = []; | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * @var boolean whether to show the footer section of the grid table. | |
| 70 | + */ | |
| 71 | + public $showFooter = false; | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * @var string the HTML display when the content of a cell is empty | |
| 75 | + */ | |
| 76 | + public $emptyCell = ' '; | |
| 77 | + | |
| 78 | + public $levelSymbol = '–'; | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Init the widget object. | |
| 82 | + */ | |
| 83 | + public function init() { | |
| 84 | + parent::init(); | |
| 85 | + | |
| 86 | + $this->initColumns(); | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * Runs the widget. | |
| 91 | + */ | |
| 92 | + public function run() { | |
| 93 | + $run = parent::run(); | |
| 94 | + if (!is_null($run)) | |
| 95 | + return $run; | |
| 96 | + | |
| 97 | + if ($this->showOnEmpty || $this->dataProvider->getCount() > 0) { | |
| 98 | + $pagination = $this->dataProvider->getPagination(); | |
| 99 | + $pagination->setPageSize($this->dataProvider->getTotalCount()); | |
| 100 | + | |
| 101 | + $header = $this->showHeader ? $this->renderTableHeader() : false; | |
| 102 | + $body = $this->renderItems(); | |
| 103 | + $footer = $this->showFooter ? $this->renderTableFooter() : false; | |
| 104 | + | |
| 105 | + $content = array_filter([ | |
| 106 | + $header, | |
| 107 | + $body, | |
| 108 | + $footer | |
| 109 | + ]); | |
| 110 | + | |
| 111 | + return Html::tag('table', implode("\n", $content), $this->options); | |
| 112 | + } else { | |
| 113 | + return $this->renderEmptyResult(); | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + /** | |
| 118 | + * Renders the table header. | |
| 119 | + * @return string the rendering result. | |
| 120 | + */ | |
| 121 | + public function renderTableHeader() | |
| 122 | + { | |
| 123 | + $cells = []; | |
| 124 | + foreach ($this->columns as $column) { | |
| 125 | + /* @var $column TreeGridColumn */ | |
| 126 | + $cells[] = $column->renderHeaderCell(); | |
| 127 | + } | |
| 128 | + $content = Html::tag('tr', implode('', $cells), $this->headerRowOptions); | |
| 129 | + return "<thead>\n" . $content . "\n</thead>"; | |
| 130 | + } | |
| 131 | + | |
| 132 | + /** | |
| 133 | + * Renders the table footer. | |
| 134 | + * @return string the rendering result. | |
| 135 | + */ | |
| 136 | + public function renderTableFooter() | |
| 137 | + { | |
| 138 | + $cells = []; | |
| 139 | + foreach ($this->columns as $column) { | |
| 140 | + /* @var $column TreeGridColumn */ | |
| 141 | + $cells[] = $column->renderFooterCell(); | |
| 142 | + } | |
| 143 | + $content = Html::tag('tr', implode('', $cells), $this->footerRowOptions); | |
| 144 | + return "<tfoot>\n" . $content . "\n</tfoot>"; | |
| 145 | + } | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * Renders the data models for the grid view. | |
| 149 | + */ | |
| 150 | + public function renderItems() | |
| 151 | + { | |
| 152 | + $rows = []; | |
| 153 | + $models = array_values($this->dataProvider->getModels()); | |
| 154 | + $keys = $this->dataProvider->getKeys(); | |
| 155 | + $models = TaxOption::find()->normalizeTreeData($models, $this->rootParentId); | |
| 156 | + foreach ($models as $index => $model) { | |
| 157 | + $key = $keys[$index]; | |
| 158 | + if ($this->beforeRow !== null) { | |
| 159 | + $row = call_user_func($this->beforeRow, $model, $key, $index, $this); | |
| 160 | + if (!empty($row)) { | |
| 161 | + $rows[] = $row; | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 165 | + $rows[] = $this->renderTableRow($model, $key, $index); | |
| 166 | + | |
| 167 | + if ($this->afterRow !== null) { | |
| 168 | + $row = call_user_func($this->afterRow, $model, $key, $index, $this); | |
| 169 | + if (!empty($row)) { | |
| 170 | + $rows[] = $row; | |
| 171 | + } | |
| 172 | + } | |
| 173 | + } | |
| 174 | + | |
| 175 | + if (empty($rows)) { | |
| 176 | + $colspan = count($this->columns); | |
| 177 | + return "<tr><td colspan=\"$colspan\">" . $this->renderEmpty() . "</td></tr>"; | |
| 178 | + } else { | |
| 179 | + return implode("\n", $rows); | |
| 180 | + } | |
| 181 | + } | |
| 182 | + | |
| 183 | + /** | |
| 184 | + * Renders a table row with the given data model and key. | |
| 185 | + * @param mixed $model the data model to be rendered | |
| 186 | + * @param mixed $key the key associated with the data model | |
| 187 | + * @param integer $index the zero-based index of the data model among the model array returned by [[dataProvider]]. | |
| 188 | + * @return string the rendering result | |
| 189 | + */ | |
| 190 | + public function renderTableRow($model, $key, $index) | |
| 191 | + { | |
| 192 | + $cells = []; | |
| 193 | + /* @var $column TreeGridColumn */ | |
| 194 | + $i = 0; | |
| 195 | + foreach ($this->columns as $column) { | |
| 196 | + $cells[] = $column->renderDataCell($model, $key, $index, $i == 0, $this->levelSymbol); | |
| 197 | + $i++; | |
| 198 | + } | |
| 199 | + if ($this->rowOptions instanceof Closure) { | |
| 200 | + $options = call_user_func($this->rowOptions, $model, $key, $index, $this); | |
| 201 | + } else { | |
| 202 | + $options = $this->rowOptions; | |
| 203 | + } | |
| 204 | + $options['data-key'] = is_array($key) ? json_encode($key) : (string) $key; | |
| 205 | + | |
| 206 | + $id = ArrayHelper::getValue($model, $this->keyNameId); | |
| 207 | + Html::addCssClass($options, "treegrid-$id"); | |
| 208 | + | |
| 209 | + $parentId = ArrayHelper::getValue($model, $this->keyNameParentId); | |
| 210 | + if ($parentId) { | |
| 211 | + Html::addCssClass($options, "treegrid-parent-$parentId"); | |
| 212 | + } | |
| 213 | + | |
| 214 | + return Html::tag('tr', implode('', $cells), $options); | |
| 215 | + } | |
| 216 | + | |
| 217 | + /** | |
| 218 | + * Creates column objects and initializes them. | |
| 219 | + */ | |
| 220 | + protected function initColumns() | |
| 221 | + { | |
| 222 | + if (empty($this->columns)) { | |
| 223 | + $this->guessColumns(); | |
| 224 | + } | |
| 225 | + foreach ($this->columns as $i => $column) { | |
| 226 | + if (is_string($column)) { | |
| 227 | + $column = $this->createDataColumn($column); | |
| 228 | + } else { | |
| 229 | + $column = Yii::createObject(array_merge([ | |
| 230 | + 'class' => $this->dataColumnClass ? : TreeGridColumn::className(), | |
| 231 | + 'grid' => $this, | |
| 232 | + ], $column)); | |
| 233 | + } | |
| 234 | + if (!$column->visible) { | |
| 235 | + unset($this->columns[$i]); | |
| 236 | + continue; | |
| 237 | + } | |
| 238 | + $this->columns[$i] = $column; | |
| 239 | + } | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * Creates a [[DataColumn]] object based on a string in the format of "attribute:format:label". | |
| 244 | + * @param string $text the column specification string | |
| 245 | + * @return DataColumn the column instance | |
| 246 | + * @throws InvalidConfigException if the column specification is invalid | |
| 247 | + */ | |
| 248 | + protected function createDataColumn($text) | |
| 249 | + { | |
| 250 | + if (!preg_match('/^([^:]+)(:(\w*))?(:(.*))?$/', $text, $matches)) { | |
| 251 | + throw new InvalidConfigException('The column must be specified in the format of "attribute", "attribute:format" or "attribute:format:label"'); | |
| 252 | + } | |
| 253 | + | |
| 254 | + return Yii::createObject([ | |
| 255 | + 'class' => $this->dataColumnClass ? : TreeGridColumn::className(), | |
| 256 | + 'grid' => $this, | |
| 257 | + 'attribute' => $matches[1], | |
| 258 | + 'format' => isset($matches[3]) ? $matches[3] : 'text', | |
| 259 | + 'label' => isset($matches[5]) ? $matches[5] : null, | |
| 260 | + ]); | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * This function tries to guess the columns to show from the given data | |
| 265 | + * if [[columns]] are not explicitly specified. | |
| 266 | + */ | |
| 267 | + protected function guessColumns() | |
| 268 | + { | |
| 269 | + $models = $this->dataProvider->getModels(); | |
| 270 | + $model = reset($models); | |
| 271 | + if (is_array($model) || is_object($model)) { | |
| 272 | + foreach ($model as $name => $value) { | |
| 273 | + $this->columns[] = $name; | |
| 274 | + } | |
| 275 | + } | |
| 276 | + } | |
| 277 | +} | |
| 0 | 278 | \ No newline at end of file | ... | ... |
common/components/artboxtree/treelist/TreeListWidget.php
0 → 100644
| 1 | +++ a/common/components/artboxtree/treelist/TreeListWidget.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree\treelist; | |
| 4 | + | |
| 5 | +use Yii; | |
| 6 | +use yii\helpers\Html; | |
| 7 | +use yii\helpers\ArrayHelper; | |
| 8 | + | |
| 9 | +class TreeListWidget extends \common\components\artboxtree\ArtboxTreeWidget { | |
| 10 | + | |
| 11 | + public $displayField = 'name'; | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * Init the widget object. | |
| 15 | + */ | |
| 16 | + public function init() { | |
| 17 | + parent::init(); | |
| 18 | + } | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * Runs the widget. | |
| 22 | + */ | |
| 23 | + public function run() { | |
| 24 | + $run = parent::run(); | |
| 25 | + if (!is_null($run)) | |
| 26 | + return $run; | |
| 27 | + | |
| 28 | + $models = $this->_hierarchyTreeData(array_values($this->dataProvider->getModels()), $this->rootParentId); | |
| 29 | + return $this->renderTreelist($models); | |
| 30 | + } | |
| 31 | + | |
| 32 | + protected function renderTreelist($models) { | |
| 33 | + foreach ($models as $index => $model) { | |
| 34 | + $row = $this->renderTreelistItem($model['item']); | |
| 35 | + $children = empty($model['children']) ? '' : $this->renderTreelist($model['children']); | |
| 36 | + $output[] = '<li>'. $row . $children .'</li>'; | |
| 37 | + } | |
| 38 | + | |
| 39 | + if (!empty($output)) | |
| 40 | + return '<ul>'. implode("\n", $output) .'</ul>'; | |
| 41 | + } | |
| 42 | + | |
| 43 | + protected function renderTreelistItem($model) | |
| 44 | + { | |
| 45 | + $options = []; | |
| 46 | + $id = ArrayHelper::getValue($model, $this->keyNameId); | |
| 47 | + Html::addCssClass($options, "treelistitem-$id"); | |
| 48 | + | |
| 49 | + $parent_id = ArrayHelper::getValue($model, $this->keyNameParentId); | |
| 50 | + if ($parent_id) { | |
| 51 | + Html::addCssClass($options, "treelistitem-parent-$parent_id"); | |
| 52 | + } | |
| 53 | + | |
| 54 | +// if (is_string($this->value)) { | |
| 55 | +// return ArrayHelper::getValue($model, $this->value); | |
| 56 | +// } else { | |
| 57 | +// return call_user_func($this->value, $model, $key, $index, $this); | |
| 58 | +// } | |
| 59 | + | |
| 60 | + return Html::tag('span', ArrayHelper::getValue($model, $this->displayField), $options); | |
| 61 | + } | |
| 62 | +} | |
| 0 | 63 | \ No newline at end of file | ... | ... |
common/components/artboxtree/treemenu/TreeMenuWidget.php
0 → 100644
| 1 | +++ a/common/components/artboxtree/treemenu/TreeMenuWidget.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\components\artboxtree\treemenu; | |
| 4 | + | |
| 5 | +use Yii; | |
| 6 | +use yii\helpers\Html; | |
| 7 | +use yii\helpers\ArrayHelper; | |
| 8 | + | |
| 9 | +class TreeMenuWidget extends \common\components\artboxtree\ArtboxTreeWidget { | |
| 10 | + | |
| 11 | + public $displayField = 'name'; | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * Init the widget object. | |
| 15 | + */ | |
| 16 | + public function init() { | |
| 17 | + parent::init(); | |
| 18 | + } | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * Runs the widget. | |
| 22 | + */ | |
| 23 | + public function run() { | |
| 24 | + $run = parent::run(); | |
| 25 | + if (!is_null($run)) | |
| 26 | + return $run; | |
| 27 | + | |
| 28 | + $models = $this->_hierarchyTreeData(array_values($this->dataProvider->getModels()), $this->rootParentId); | |
| 29 | + return $this->renderTreelist($models); | |
| 30 | + } | |
| 31 | + | |
| 32 | + protected function renderTreelist($models) { | |
| 33 | + foreach ($models as $index => $model) { | |
| 34 | + $row = $this->renderTreelistItem($model['item']); | |
| 35 | + $children = empty($model['children']) ? '' : $this->renderTreelist($model['children']); | |
| 36 | + $output[] = '<li>'. $row . $children .'</li>'; | |
| 37 | + } | |
| 38 | + | |
| 39 | + if (!empty($output)) | |
| 40 | + return '<ul>'. implode("\n", $output) .'</ul>'; | |
| 41 | + } | |
| 42 | + | |
| 43 | + protected function renderTreelistItem($model) | |
| 44 | + { | |
| 45 | + $options = []; | |
| 46 | + $id = ArrayHelper::getValue($model, $this->keyNameId); | |
| 47 | + Html::addCssClass($options, "treelistitem-$id"); | |
| 48 | + | |
| 49 | + $parent_id = ArrayHelper::getValue($model, $this->keyNameParentId); | |
| 50 | + if ($parent_id) { | |
| 51 | + Html::addCssClass($options, "treelistitem-parent-$parent_id"); | |
| 52 | + } | |
| 53 | + | |
| 54 | +// if (is_string($this->value)) { | |
| 55 | +// return ArrayHelper::getValue($model, $this->value); | |
| 56 | +// } else { | |
| 57 | +// return call_user_func($this->value, $model, $key, $index, $this); | |
| 58 | +// } | |
| 59 | + | |
| 60 | + return Html::tag('span', ArrayHelper::getValue($model, $this->displayField), $options); | |
| 61 | + } | |
| 62 | +} | |
| 0 | 63 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/config/bootstrap.php | |
| 1 | +<?php | |
| 2 | +Yii::setAlias('@common', dirname(__DIR__)); | |
| 3 | +Yii::setAlias('@frontend', dirname(dirname(__DIR__)) . '/frontend'); | |
| 4 | +Yii::setAlias('@backend', dirname(dirname(__DIR__)) . '/backend'); | |
| 5 | +Yii::setAlias('@console', dirname(dirname(__DIR__)) . '/console'); | |
| 6 | +Yii::setAlias('storage', dirname(dirname(__DIR__)) . '/storage'); | ... | ... |
| 1 | +++ a/common/config/main.php | |
| 1 | +<?php | |
| 2 | +return [ | |
| 3 | + 'language' => 'ru-RU', | |
| 4 | + 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', | |
| 5 | + 'controllerMap' => [ | |
| 6 | + 'elfinder' => [ | |
| 7 | + 'class' => 'mihaildev\elfinder\Controller', | |
| 8 | + 'access' => ['@'], //глобальный доступ к фаил менеджеру @ - для авторизорованных , ? - для гостей , чтоб открыть всем ['@', '?'] | |
| 9 | + 'disabledCommands' => ['netmount'], //отключение ненужных команд https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#commands | |
| 10 | + 'roots' => [ | |
| 11 | + [ | |
| 12 | + 'class' => 'mihaildev\elfinder\UserPath', | |
| 13 | + 'path' => '../../storage/user_{id}', | |
| 14 | + 'name' => 'My Documents' | |
| 15 | + ], | |
| 16 | + ], | |
| 17 | + 'watermark' => [ | |
| 18 | + 'source' => __DIR__.'/logo.png', // Path to Water mark image | |
| 19 | + 'marginRight' => 5, // Margin right pixel | |
| 20 | + 'marginBottom' => 5, // Margin bottom pixel | |
| 21 | + 'quality' => 95, // JPEG image save quality | |
| 22 | + 'transparency' => 70, // Water mark image transparency ( other than PNG ) | |
| 23 | + 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field ) | |
| 24 | + 'targetMinPixel' => 200 // Target image minimum pixel size | |
| 25 | + ] | |
| 26 | + ], | |
| 27 | + 'artbox-comment' => [ | |
| 28 | + 'class' => \common\modules\comment\Controller::className(), | |
| 29 | + ], | |
| 30 | + ], | |
| 31 | + 'components' => [ | |
| 32 | + 'assetManager' => [ | |
| 33 | + 'bundles' => [ | |
| 34 | + 'yii\web\JqueryAsset' =>[ | |
| 35 | + 'jsOptions' => ['position' => \yii\web\View::POS_HEAD] | |
| 36 | + ] | |
| 37 | + ], | |
| 38 | + ], | |
| 39 | + 'cache' => [ | |
| 40 | + 'class' => 'yii\caching\FileCache', | |
| 41 | + ], | |
| 42 | + 'urlManager' => [ | |
| 43 | + 'enablePrettyUrl' => true, | |
| 44 | + 'showScriptName' => false, | |
| 45 | + 'rules' => [ | |
| 46 | + 'module/<module:\w+>/<controller:\w+>/<action:\w+>' => '<module>/<controller>/<action>', | |
| 47 | + ] | |
| 48 | + ], | |
| 49 | + 'i18n' => [ | |
| 50 | + 'translations' => [ | |
| 51 | + '*' => [ | |
| 52 | + 'class' => 'yii\i18n\PhpMessageSource', | |
| 53 | + 'basePath' => '@common/translation', | |
| 54 | + 'fileMap' => [ | |
| 55 | + 'app' => 'app.php', | |
| 56 | + 'app/error' => 'error.php', | |
| 57 | + ], | |
| 58 | + ], | |
| 59 | + 'app' => [ | |
| 60 | + 'class' => 'yii\i18n\PhpMessageSource', | |
| 61 | + 'basePath' => '@common/translation', | |
| 62 | + 'fileMap' => [ | |
| 63 | + 'app' => 'app.php', | |
| 64 | + 'app/error' => 'error.php', | |
| 65 | + ], | |
| 66 | + ], | |
| 67 | + ], | |
| 68 | + ], | |
| 69 | + ], | |
| 70 | + | |
| 71 | + 'modules' => [ | |
| 72 | + 'file' => [ | |
| 73 | + 'class' => 'common\modules\file\Module', | |
| 74 | + ], | |
| 75 | + 'relation' => [ | |
| 76 | + 'class' => 'common\modules\relation\Module', | |
| 77 | + 'relations' => [ | |
| 78 | + 'product_categories' => [ | |
| 79 | + 'name' => Yii::t('product', 'Categories'), | |
| 80 | + 'field' => 'categories', | |
| 81 | + 'entity1' => [ | |
| 82 | + 'model' => '\common\modules\product\models\Product', | |
| 83 | + 'label' => 'Product', | |
| 84 | + 'listField' => 'fullname', | |
| 85 | + 'key' => 'product_id', | |
| 86 | + 'linked_key' => 'product_id', | |
| 87 | + ], | |
| 88 | + 'entity2' => [ | |
| 89 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
| 90 | + 'label' => 'Category', | |
| 91 | + 'listField' => 'ValueRenderFlash', | |
| 92 | + 'key' => 'tax_option_id', | |
| 93 | + 'linked_key' => 'category_id', | |
| 94 | + 'where' => [ | |
| 95 | + 'tax_group_id' => 1 | |
| 96 | + ], | |
| 97 | + 'hierarchy' => [ | |
| 98 | + 'key' => 'tax_option_id', | |
| 99 | + 'parentKey' => 'parent_id', | |
| 100 | + ] | |
| 101 | + ], | |
| 102 | + 'via' => [ | |
| 103 | + 'model' => '\common\modules\product\models\ProductCategory', | |
| 104 | + ] | |
| 105 | + ], | |
| 106 | + 'relation_categories' => [ | |
| 107 | + 'name' => Yii::t('relation', 'Relation categories'), | |
| 108 | + 'field' => 'categories', | |
| 109 | + 'entity1' => [ | |
| 110 | + 'model' => '\common\modules\product\models\Product', | |
| 111 | + 'label' => 'Product', | |
| 112 | + 'listField' => 'fullname', | |
| 113 | + 'key' => 'product_id', | |
| 114 | + 'linked_key' => 'product_id', | |
| 115 | + ], | |
| 116 | + 'entity2' => [ | |
| 117 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
| 118 | + 'label' => 'Category', | |
| 119 | + 'listField' => 'ValueRenderFlash', | |
| 120 | + 'key' => 'tax_option_id', | |
| 121 | + 'linked_key' => 'category_id', | |
| 122 | + 'where' => [ | |
| 123 | + 'tax_group_id' => 1 | |
| 124 | + ] | |
| 125 | + ], | |
| 126 | + 'via' => [ | |
| 127 | + 'model' => '\common\modules\relation\models\Relation', | |
| 128 | + 'alias' => 'alias', | |
| 129 | + ] | |
| 130 | + ], | |
| 131 | + 'tax_option_to_group' => [ | |
| 132 | + 'name' => 'Options-Groups', | |
| 133 | + 'field' => 'tax_option_to_group', | |
| 134 | + 'linked_table' => 'tax_option_to_group', | |
| 135 | + 'entity1' => [ | |
| 136 | + 'label' => 'Option', | |
| 137 | + 'listField' => 'ValueRenderFlash', | |
| 138 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
| 139 | + 'key' => 'tax_option_id', | |
| 140 | + 'linked_key' => 'tax_option_id', | |
| 141 | + ], | |
| 142 | + 'entity2' => [ | |
| 143 | + 'label' => 'Group', | |
| 144 | + 'listField' => 'name', | |
| 145 | + 'model' => '\common\modules\rubrication\models\TaxGroup', | |
| 146 | + 'key' => 'tax_group_id', | |
| 147 | + 'linked_key' => 'tax_group_id', | |
| 148 | + ], | |
| 149 | + 'via' => [ | |
| 150 | + 'model' => 'common\modules\rubrication\models\TaxOptionToGroup', | |
| 151 | + 'alias' => 'alias', | |
| 152 | + ] | |
| 153 | + ], | |
| 154 | + 'tax_option_to_option' => [ | |
| 155 | + 'name' => 'Options-Options', | |
| 156 | + 'field' => 'tax_option_to_option', | |
| 157 | + 'entity1' => [ | |
| 158 | + 'label' => 'Option', | |
| 159 | + 'listField' => 'ValueRenderFlash', | |
| 160 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
| 161 | + 'key' => 'tax_option_id', | |
| 162 | + 'linked_key' => 'tax_option1_id', | |
| 163 | + ], | |
| 164 | + 'entity2' => [ | |
| 165 | + 'label' => 'Option', | |
| 166 | + 'listField' => 'ValueRenderFlash', | |
| 167 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
| 168 | + 'key' => 'tax_option_id', | |
| 169 | + 'linked_key' => 'tax_option2_id', | |
| 170 | + ], | |
| 171 | + 'via' => [ | |
| 172 | + 'model' => 'common\modules\rubrication\models\TaxOptionRelation', | |
| 173 | + 'alias' => 'alias', | |
| 174 | + ] | |
| 175 | + ], | |
| 176 | + 'brand_cats' => [ | |
| 177 | + 'name' => 'Категории производителей', | |
| 178 | + 'field' => 'tax_option_to_option', | |
| 179 | + 'entity1' => [ | |
| 180 | + 'label' => 'Бренд', | |
| 181 | + 'listField' => 'ValueRenderFlash', | |
| 182 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
| 183 | + 'key' => 'tax_option_id', | |
| 184 | + 'linked_key' => 'tax_option1_id', | |
| 185 | + ], | |
| 186 | + 'entity2' => [ | |
| 187 | + 'label' => 'Категория', | |
| 188 | + 'listField' => 'ValueRenderFlash', | |
| 189 | + 'model' => '\common\modules\rubrication\models\TaxOption', | |
| 190 | + 'key' => 'tax_option_id', | |
| 191 | + 'linked_key' => 'tax_option2_id', | |
| 192 | + ], | |
| 193 | + 'via' => [ | |
| 194 | + 'model' => 'common\modules\rubrication\models\TaxOptionRelation', | |
| 195 | + 'alias' => 'alias', | |
| 196 | + ] | |
| 197 | + ] | |
| 198 | + ] | |
| 199 | + ], | |
| 200 | + 'comment' => [ | |
| 201 | + 'class' => 'common\modules\comment\Module', | |
| 202 | + 'useRbac' => true, | |
| 203 | + 'rbac' => [ | |
| 204 | + 'rules' => [ | |
| 205 | + \common\modules\comment\rbac\ArtboxCommentCreateRule::className(), | |
| 206 | + \common\modules\comment\rbac\ArtboxCommentDeleteRule::className(), | |
| 207 | + \common\modules\comment\rbac\ArtboxCommentUpdateRule::className(), | |
| 208 | + \common\modules\comment\rbac\ArtboxCommentUpdateOwnRule::className(), | |
| 209 | + \common\modules\comment\rbac\ArtboxCommentDeleteOwnRule::className(), | |
| 210 | + ], | |
| 211 | + 'permissions' => [ | |
| 212 | + [ | |
| 213 | + 'name' => common\modules\comment\Permissions::CREATE, | |
| 214 | + 'description' => 'Can create comments', | |
| 215 | + 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentCreateRule())->name, | |
| 216 | + ], | |
| 217 | + [ | |
| 218 | + 'name' => common\modules\comment\Permissions::UPDATE, | |
| 219 | + 'description' => 'Can update comments', | |
| 220 | + 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentUpdateRule())->name, | |
| 221 | + ], | |
| 222 | + [ | |
| 223 | + 'name' => common\modules\comment\Permissions::DELETE, | |
| 224 | + 'description' => 'Can delete comments', | |
| 225 | + 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentDeleteRule())->name, | |
| 226 | + ], | |
| 227 | + [ | |
| 228 | + 'name' => common\modules\comment\Permissions::UPDATE_OWN, | |
| 229 | + 'description' => 'Can update own comments', | |
| 230 | + 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentUpdateOwnRule())->name, | |
| 231 | + ], | |
| 232 | + [ | |
| 233 | + 'name' => common\modules\comment\Permissions::DELETE_OWN, | |
| 234 | + 'description' => 'Can delete own comments', | |
| 235 | + 'ruleName' =>(new \common\modules\comment\rbac\ArtboxCommentDeleteOwnRule())->name, | |
| 236 | + ], | |
| 237 | + ], | |
| 238 | + ], | |
| 239 | + | |
| 240 | + ], | |
| 241 | + ], | |
| 242 | + 'language' => 'ru-RU' | |
| 243 | +]; | ... | ... |
| 1 | +++ a/common/mail/layouts/html.php | |
| 1 | +<?php | |
| 2 | +use yii\helpers\Html; | |
| 3 | + | |
| 4 | +/* @var $this \yii\web\View view component instance */ | |
| 5 | +/* @var $message \yii\mail\MessageInterface the message being composed */ | |
| 6 | +/* @var $content string main view render result */ | |
| 7 | +?> | |
| 8 | +<?php $this->beginPage() ?> | |
| 9 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
| 10 | +<html xmlns="http://www.w3.org/1999/xhtml"> | |
| 11 | +<head> | |
| 12 | + <meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" /> | |
| 13 | + <title><?= Html::encode($this->title) ?></title> | |
| 14 | + <?php $this->head() ?> | |
| 15 | +</head> | |
| 16 | +<body> | |
| 17 | + <?php $this->beginBody() ?> | |
| 18 | + <?= $content ?> | |
| 19 | + <?php $this->endBody() ?> | |
| 20 | +</body> | |
| 21 | +</html> | |
| 22 | +<?php $this->endPage() ?> | ... | ... |
| 1 | +++ a/common/mail/layouts/text.php | |
| 1 | +<?php | |
| 2 | +use yii\helpers\Html; | |
| 3 | + | |
| 4 | +/* @var $this \yii\web\View view component instance */ | |
| 5 | +/* @var $message \yii\mail\MessageInterface the message being composed */ | |
| 6 | +/* @var $content string main view render result */ | |
| 7 | +?> | |
| 8 | +<?php $this->beginPage() ?> | |
| 9 | +<?php $this->beginBody() ?> | |
| 10 | +<?= $content ?> | |
| 11 | +<?php $this->endBody() ?> | |
| 12 | +<?php $this->endPage() ?> | ... | ... |
| 1 | +++ a/common/mail/passwordResetToken-html.php | |
| 1 | +<?php | |
| 2 | +use yii\helpers\Html; | |
| 3 | + | |
| 4 | +/* @var $this yii\web\View */ | |
| 5 | +/* @var $user common\models\User */ | |
| 6 | + | |
| 7 | +$resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); | |
| 8 | +?> | |
| 9 | +<div class="password-reset"> | |
| 10 | + <p>Hello <?= Html::encode($user->username) ?>,</p> | |
| 11 | + | |
| 12 | + <p>Follow the link below to reset your password:</p> | |
| 13 | + | |
| 14 | + <p><?= Html::a(Html::encode($resetLink), $resetLink) ?></p> | |
| 15 | +</div> | ... | ... |
| 1 | +++ a/common/mail/passwordResetToken-text.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/* @var $this yii\web\View */ | |
| 4 | +/* @var $user common\models\User */ | |
| 5 | + | |
| 6 | +$resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); | |
| 7 | +?> | |
| 8 | +Hello <?= $user->username ?>, | |
| 9 | + | |
| 10 | +Follow the link below to reset your password: | |
| 11 | + | |
| 12 | +<?= $resetLink ?> | ... | ... |
| 1 | +++ a/common/models/Blog.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | + namespace common\models; | |
| 4 | + | |
| 5 | + use Yii; | |
| 6 | + use yii\behaviors\BlameableBehavior; | |
| 7 | + use yii\behaviors\TimestampBehavior; | |
| 8 | + use yii\db\Expression; | |
| 9 | + | |
| 10 | + /** | |
| 11 | + * This is the model class for table "blog". | |
| 12 | + * @property integer $blog_id | |
| 13 | + * @property integer $user_id | |
| 14 | + * @property string $name | |
| 15 | + * @property string $link | |
| 16 | + * @property string $date_add | |
| 17 | + * @property integer $user_add_id | |
| 18 | + * @property integer $view_count | |
| 19 | + * @property string $description | |
| 20 | + * @property string $cover | |
| 21 | + */ | |
| 22 | + class Blog extends \yii\db\ActiveRecord | |
| 23 | + { | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * @inheritdoc | |
| 27 | + */ | |
| 28 | + public static function tableName() | |
| 29 | + { | |
| 30 | + return 'blog'; | |
| 31 | + } | |
| 32 | + | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * @inheritdoc | |
| 36 | + */ | |
| 37 | + public function behaviors() | |
| 38 | + { | |
| 39 | + return [ | |
| 40 | + [ | |
| 41 | + 'class' => BlameableBehavior::className(), | |
| 42 | + 'createdByAttribute' => 'user_id', | |
| 43 | + 'updatedByAttribute' => false, | |
| 44 | + ], | |
| 45 | + [ | |
| 46 | + 'class' => TimestampBehavior::className(), | |
| 47 | + 'createdAtAttribute' => 'date_add', | |
| 48 | + 'updatedAtAttribute' => false, | |
| 49 | + 'value' => new Expression('NOW()'), | |
| 50 | + ], | |
| 51 | + 'slug' => [ | |
| 52 | + 'class' => 'common\behaviors\Slug', | |
| 53 | + 'in_attribute' => 'name', | |
| 54 | + 'out_attribute' => 'link', | |
| 55 | + 'translit' => true | |
| 56 | + ] | |
| 57 | + ]; | |
| 58 | + } | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * @inheritdoc | |
| 62 | + */ | |
| 63 | + public function rules() | |
| 64 | + { | |
| 65 | + return [ | |
| 66 | + [ | |
| 67 | + [ 'name', 'description' ], | |
| 68 | + 'required', | |
| 69 | + ], | |
| 70 | + [ | |
| 71 | + [ 'description' ], | |
| 72 | + 'string', | |
| 73 | + ], | |
| 74 | + [ | |
| 75 | + [ | |
| 76 | + 'name', | |
| 77 | + 'link', | |
| 78 | + 'cover', | |
| 79 | + ], | |
| 80 | + 'string', | |
| 81 | + 'max' => 255, | |
| 82 | + ], | |
| 83 | + ]; | |
| 84 | + } | |
| 85 | + | |
| 86 | + public function getDateCreate(){ | |
| 87 | + return date('Y-m-d',strtotime($this->date_add)); | |
| 88 | + } | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * @inheritdoc | |
| 92 | + */ | |
| 93 | + public function attributeLabels() | |
| 94 | + { | |
| 95 | + return [ | |
| 96 | + 'blog_id' => Yii::t('app', 'Blog ID'), | |
| 97 | + 'user_id' => Yii::t('app', 'User ID'), | |
| 98 | + 'name' => Yii::t('app', 'Название'), | |
| 99 | + 'link' => Yii::t('app', 'URL'), | |
| 100 | + 'date_add' => Yii::t('app', 'Дата добавления'), | |
| 101 | + 'user_add_id' => Yii::t('app', 'User Add ID'), | |
| 102 | + 'view_count' => Yii::t('app', 'Количество просмотров'), | |
| 103 | + 'description' => Yii::t('app', 'Описание'), | |
| 104 | + 'cover' => Yii::t('app', 'Фото главное'), | |
| 105 | + ]; | |
| 106 | + } | |
| 107 | + } | ... | ... |
| 1 | +++ a/common/models/BlogSearch.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | + namespace common\models; | |
| 4 | + | |
| 5 | + use Yii; | |
| 6 | + use yii\base\Model; | |
| 7 | + use yii\bootstrap\ActiveForm; | |
| 8 | + use yii\data\ActiveDataProvider; | |
| 9 | + use common\models\Blog; | |
| 10 | + use yii\db\ActiveQuery; | |
| 11 | + use yii\db\ActiveRecord; | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * BlogSearch represents the model behind the search form about `common\models\Blog`. | |
| 15 | + */ | |
| 16 | + class BlogSearch extends Blog | |
| 17 | + { | |
| 18 | + | |
| 19 | + public $date_add_from; | |
| 20 | + public $date_add_to; | |
| 21 | + /** | |
| 22 | + * @inheritdoc | |
| 23 | + */ | |
| 24 | + public function rules() | |
| 25 | + { | |
| 26 | + return [ | |
| 27 | + [ | |
| 28 | + [ | |
| 29 | + 'blog_id', | |
| 30 | + 'user_id', | |
| 31 | + 'user_add_id', | |
| 32 | + 'view_count', | |
| 33 | + ], | |
| 34 | + 'integer', | |
| 35 | + ], | |
| 36 | + [ | |
| 37 | + [ | |
| 38 | + 'name', | |
| 39 | + 'link', | |
| 40 | + 'date_add', | |
| 41 | + 'description', | |
| 42 | + 'cover', | |
| 43 | + 'date_add_from', | |
| 44 | + 'date_add_to', | |
| 45 | + ], | |
| 46 | + 'safe', | |
| 47 | + ], | |
| 48 | + [ | |
| 49 | + [ | |
| 50 | + 'date_add_from', | |
| 51 | + ], | |
| 52 | + 'default', | |
| 53 | + 'value' => date('Y-m-d', 0), | |
| 54 | + ], | |
| 55 | + [ | |
| 56 | + [ | |
| 57 | + 'date_add_to', | |
| 58 | + ], | |
| 59 | + 'default', | |
| 60 | + 'value' => date('Y-m-d'), | |
| 61 | + ], | |
| 62 | + ]; | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * @inheritdoc | |
| 67 | + */ | |
| 68 | + public function scenarios() | |
| 69 | + { | |
| 70 | + // bypass scenarios() implementation in the parent class | |
| 71 | + return Model::scenarios(); | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * Creates data provider instance with search query applied | |
| 76 | + * | |
| 77 | + * @param array $params | |
| 78 | + * | |
| 79 | + * @return ActiveDataProvider | |
| 80 | + */ | |
| 81 | + public function search($params) | |
| 82 | + { | |
| 83 | + $query = Blog::find(); | |
| 84 | + | |
| 85 | + // add conditions that should always apply here | |
| 86 | + | |
| 87 | + $dataProvider = new ActiveDataProvider([ | |
| 88 | + 'query' => $query, | |
| 89 | + ]); | |
| 90 | + | |
| 91 | + $this->load($params); | |
| 92 | + | |
| 93 | + if(!$this->validate()) { | |
| 94 | + // uncomment the following line if you do not want to return any records when validation fails | |
| 95 | + // $query->where('0=1'); | |
| 96 | + return $dataProvider; | |
| 97 | + } | |
| 98 | + | |
| 99 | + $query->andWhere([ 'user_id' => \Yii::$app->user->getId() ]); | |
| 100 | + | |
| 101 | + // grid filtering conditions | |
| 102 | + $query->andFilterWhere([ | |
| 103 | + 'blog_id' => $this->blog_id, | |
| 104 | + 'date_add' => $this->date_add, | |
| 105 | + 'user_add_id' => $this->user_add_id, | |
| 106 | + 'view_count' => $this->view_count, | |
| 107 | + ]); | |
| 108 | + | |
| 109 | + $query->andFilterWhere([ | |
| 110 | + 'between', | |
| 111 | + 'date_add', | |
| 112 | + $this->date_add_from, | |
| 113 | + (new \DateTime($this->date_add_to))->modify('+1 day')->format('Y-m-d') | |
| 114 | + ]); | |
| 115 | + | |
| 116 | + $query->andFilterWhere([ | |
| 117 | + 'like', | |
| 118 | + 'name', | |
| 119 | + $this->name, | |
| 120 | + ]) | |
| 121 | + ->andFilterWhere([ | |
| 122 | + 'like', | |
| 123 | + 'description', | |
| 124 | + $this->description, | |
| 125 | + ]) | |
| 126 | + ->andFilterWhere([ | |
| 127 | + 'like', | |
| 128 | + 'cover', | |
| 129 | + $this->cover, | |
| 130 | + ]); | |
| 131 | + | |
| 132 | + return $dataProvider; | |
| 133 | + } | |
| 134 | + | |
| 135 | + } | ... | ... |
| 1 | +++ a/common/models/Fields.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\models; | |
| 4 | + | |
| 5 | +use Yii; | |
| 6 | +use yii\helpers\ArrayHelper; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * This is the model class for table "{{%fields}}". | |
| 10 | + * | |
| 11 | + * @property integer $id | |
| 12 | + * @property string $table_name | |
| 13 | + * @property integer $table_id | |
| 14 | + * @property string $value | |
| 15 | + * @property string $field_name | |
| 16 | + * @property string $field_type | |
| 17 | + * @property string $language | |
| 18 | + * @property string $parent_key | |
| 19 | + * @property string $key | |
| 20 | + */ | |
| 21 | +class Fields extends \yii\db\ActiveRecord | |
| 22 | +{ | |
| 23 | + /** | |
| 24 | + * @inheritdoc | |
| 25 | + */ | |
| 26 | + public static function tableName() | |
| 27 | + { | |
| 28 | + return '{{%fields}}'; | |
| 29 | + } | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * @inheritdoc | |
| 33 | + */ | |
| 34 | + public function rules() | |
| 35 | + { | |
| 36 | + return [ | |
| 37 | + [['table_name', 'table_id',], 'required'], | |
| 38 | + [['table_id','parent_key','key'], 'integer'], | |
| 39 | + [['table_name', 'value', 'field_name','field_type','language'], 'string', 'max' => 255] | |
| 40 | + ]; | |
| 41 | + } | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * @inheritdoc | |
| 45 | + */ | |
| 46 | + public function attributeLabels() | |
| 47 | + { | |
| 48 | + return [ | |
| 49 | + 'id' => 'ID', | |
| 50 | + 'table_name' => 'Model Name', | |
| 51 | + 'table_id' => 'Model ID', | |
| 52 | + 'value' => 'Value', | |
| 53 | + 'field_name' => 'Field Name', | |
| 54 | + 'language' => 'Language', | |
| 55 | + ]; | |
| 56 | + } | |
| 57 | + | |
| 58 | + public static function getData($id, $model, $type){ | |
| 59 | + $data = ArrayHelper::toArray(self::find()->where(['table_id'=>$id, 'table_name'=>$model, 'field_type'=>$type])->all()); | |
| 60 | + $result = []; | |
| 61 | + for($i=0; $i < count($data); $i ++){ | |
| 62 | + $result[$data[$i]['parent_key']][$data[$i]['field_name']] = $data[$i]['value']; | |
| 63 | + } | |
| 64 | + | |
| 65 | + return $result; | |
| 66 | + } | |
| 67 | + | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * @param $post - array with field data | |
| 71 | + * @param $table_id - row id in model table | |
| 72 | + * @param $table_name - madel table name | |
| 73 | + * @param $language - language id | |
| 74 | + */ | |
| 75 | + | |
| 76 | + public static function saveFieldData($post,$table_id,$table_name, $language){ | |
| 77 | + | |
| 78 | + self::deleteAll(['table_id'=>$table_id, 'table_name'=>$table_name, 'language' => $language, 'field_type' => array_keys($post)]); | |
| 79 | + | |
| 80 | + if($post){ | |
| 81 | + | |
| 82 | + | |
| 83 | + foreach($post as $k => $field){ | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + foreach($field as $parent_key => $row){ | |
| 88 | + | |
| 89 | + foreach($row as $key => $value){ | |
| 90 | + | |
| 91 | + $field_model = new Fields(); | |
| 92 | + $field_model->field_name = array_keys($value)[0]; | |
| 93 | + $field_model->value = $value[array_keys($value)[0]]; | |
| 94 | + $field_model->table_name = $table_name; | |
| 95 | + $field_model->table_id = $table_id; | |
| 96 | + $field_model->field_type = $k; | |
| 97 | + $field_model->language = 'ru'; | |
| 98 | + $field_model->parent_key = $parent_key; | |
| 99 | + $field_model->key = $key; | |
| 100 | + $field_model->save(); | |
| 101 | + } | |
| 102 | + | |
| 103 | + } | |
| 104 | + } | |
| 105 | + } | |
| 106 | + } | |
| 107 | + | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * @param $post - array with field data | |
| 111 | + * @param $table_id - row id in model table | |
| 112 | + * @param $table_name - madel table name | |
| 113 | + * @param $language - language id | |
| 114 | + */ | |
| 115 | + | |
| 116 | + public static function saveFieldVideoData($post,$table_id,$table_name, $language){ | |
| 117 | + | |
| 118 | + self::deleteAll(['table_id'=>$table_id, 'table_name'=>$table_name, 'language' => $language, 'field_type' => array_keys($post)]); | |
| 119 | + | |
| 120 | + if($post){ | |
| 121 | + | |
| 122 | + | |
| 123 | + foreach($post as $k => $field){ | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + foreach($field as $parent_key => $row){ | |
| 128 | + | |
| 129 | + foreach($row as $key => $value){ | |
| 130 | + | |
| 131 | + preg_match('/src=\"(.[^"]*)\"/', $value[array_keys($value)[0]], $video_url); | |
| 132 | + | |
| 133 | + if(isset($video_url[1]) && !empty($video_url[1])){ | |
| 134 | + | |
| 135 | + $field_model = new Fields(); | |
| 136 | + $field_model->field_name = array_keys($value)[0]; | |
| 137 | + $field_model->value = $video_url[1].'?showinfo=0&autoplay=0'; | |
| 138 | + $field_model->table_name = $table_name; | |
| 139 | + $field_model->table_id = $table_id; | |
| 140 | + $field_model->field_type = $k; | |
| 141 | + $field_model->language = 'ru'; | |
| 142 | + $field_model->parent_key = $parent_key; | |
| 143 | + $field_model->key = $key; | |
| 144 | + $field_model->save(); | |
| 145 | + | |
| 146 | + } | |
| 147 | + | |
| 148 | + | |
| 149 | + } | |
| 150 | + | |
| 151 | + } | |
| 152 | + } | |
| 153 | + } | |
| 154 | + } | |
| 155 | +} | ... | ... |
| 1 | +++ a/common/models/LoginForm.php | |
| 1 | +<?php | |
| 2 | +namespace common\models; | |
| 3 | + | |
| 4 | +use Yii; | |
| 5 | +use yii\base\Model; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Login form | |
| 9 | + */ | |
| 10 | +class LoginForm extends Model | |
| 11 | +{ | |
| 12 | + public $username; | |
| 13 | + public $password; | |
| 14 | + public $rememberMe = true; | |
| 15 | + | |
| 16 | + private $_user; | |
| 17 | + | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * @inheritdoc | |
| 21 | + */ | |
| 22 | + public function rules() | |
| 23 | + { | |
| 24 | + return [ | |
| 25 | + // username and password are both required | |
| 26 | + [['username', 'password'], 'required'], | |
| 27 | + // rememberMe must be a boolean value | |
| 28 | + ['rememberMe', 'boolean'], | |
| 29 | + // password is validated by validatePassword() | |
| 30 | + ['password', 'validatePassword'], | |
| 31 | + ]; | |
| 32 | + } | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * Validates the password. | |
| 36 | + * This method serves as the inline validation for password. | |
| 37 | + * | |
| 38 | + * @param string $attribute the attribute currently being validated | |
| 39 | + * @param array $params the additional name-value pairs given in the rule | |
| 40 | + */ | |
| 41 | + public function validatePassword($attribute, $params) | |
| 42 | + { | |
| 43 | + if (!$this->hasErrors()) { | |
| 44 | + $user = $this->getUser(); | |
| 45 | + if (!$user || !$user->validatePassword($this->password)) { | |
| 46 | + $this->addError($attribute, 'Incorrect username or password.'); | |
| 47 | + } | |
| 48 | + } | |
| 49 | + } | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * Logs in a user using the provided username and password. | |
| 53 | + * | |
| 54 | + * @return boolean whether the user is logged in successfully | |
| 55 | + */ | |
| 56 | + public function login() | |
| 57 | + { | |
| 58 | + if ($this->validate()) { | |
| 59 | + return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0); | |
| 60 | + } else { | |
| 61 | + return false; | |
| 62 | + } | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Finds user by [[username]] | |
| 67 | + * | |
| 68 | + * @return User|null | |
| 69 | + */ | |
| 70 | + protected function getUser() | |
| 71 | + { | |
| 72 | + if ($this->_user === null) { | |
| 73 | + $this->_user = User::findByUsername($this->username); | |
| 74 | + } | |
| 75 | + | |
| 76 | + return $this->_user; | |
| 77 | + } | |
| 78 | +} | ... | ... |
| 1 | +++ a/common/models/User.php | |
| 1 | +<?php | |
| 2 | +namespace common\models; | |
| 3 | + | |
| 4 | +use Yii; | |
| 5 | +use yii\base\NotSupportedException; | |
| 6 | +use yii\behaviors\TimestampBehavior; | |
| 7 | +use yii\db\ActiveRecord; | |
| 8 | +use yii\web\IdentityInterface; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * User model | |
| 12 | + * | |
| 13 | + * @property integer $id | |
| 14 | + * @property string $username | |
| 15 | + * @property string $password_hash | |
| 16 | + * @property string $password_reset_token | |
| 17 | + * @property string $email | |
| 18 | + * @property string $auth_key | |
| 19 | + * @property integer $status | |
| 20 | + * @property integer $created_at | |
| 21 | + * @property integer $updated_at | |
| 22 | + * @property string $password write-only password | |
| 23 | + */ | |
| 24 | +class User extends ActiveRecord implements IdentityInterface | |
| 25 | +{ | |
| 26 | + const STATUS_DELETED = 0; | |
| 27 | + const STATUS_ACTIVE = 10; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * @inheritdoc | |
| 31 | + */ | |
| 32 | + public static function tableName() | |
| 33 | + { | |
| 34 | + return '{{%user}}'; | |
| 35 | + } | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * @inheritdoc | |
| 39 | + */ | |
| 40 | + public function behaviors() | |
| 41 | + { | |
| 42 | + return [ | |
| 43 | + TimestampBehavior::className(), | |
| 44 | + ]; | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * @inheritdoc | |
| 49 | + */ | |
| 50 | + public function rules() | |
| 51 | + { | |
| 52 | + return [ | |
| 53 | + ['status', 'default', 'value' => self::STATUS_ACTIVE], | |
| 54 | + ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], | |
| 55 | + ]; | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * @inheritdoc | |
| 60 | + */ | |
| 61 | + public static function findIdentity($id) | |
| 62 | + { | |
| 63 | + return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * @inheritdoc | |
| 68 | + */ | |
| 69 | + public static function findIdentityByAccessToken($token, $type = null) | |
| 70 | + { | |
| 71 | + throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * Finds user by username | |
| 76 | + * | |
| 77 | + * @param string $username | |
| 78 | + * @return static|null | |
| 79 | + */ | |
| 80 | + public static function findByUsername($username) | |
| 81 | + { | |
| 82 | + return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]); | |
| 83 | + } | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * Finds user by password reset token | |
| 87 | + * | |
| 88 | + * @param string $token password reset token | |
| 89 | + * @return static|null | |
| 90 | + */ | |
| 91 | + public static function findByPasswordResetToken($token) | |
| 92 | + { | |
| 93 | + if (!static::isPasswordResetTokenValid($token)) { | |
| 94 | + return null; | |
| 95 | + } | |
| 96 | + | |
| 97 | + return static::findOne([ | |
| 98 | + 'password_reset_token' => $token, | |
| 99 | + 'status' => self::STATUS_ACTIVE, | |
| 100 | + ]); | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Finds out if password reset token is valid | |
| 105 | + * | |
| 106 | + * @param string $token password reset token | |
| 107 | + * @return boolean | |
| 108 | + */ | |
| 109 | + public static function isPasswordResetTokenValid($token) | |
| 110 | + { | |
| 111 | + if (empty($token)) { | |
| 112 | + return false; | |
| 113 | + } | |
| 114 | + | |
| 115 | + $timestamp = (int) substr($token, strrpos($token, '_') + 1); | |
| 116 | + $expire = Yii::$app->params['user.passwordResetTokenExpire']; | |
| 117 | + return $timestamp + $expire >= time(); | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * @inheritdoc | |
| 122 | + */ | |
| 123 | + public function getId() | |
| 124 | + { | |
| 125 | + return $this->getPrimaryKey(); | |
| 126 | + } | |
| 127 | + | |
| 128 | + /** | |
| 129 | + * @inheritdoc | |
| 130 | + */ | |
| 131 | + public function getAuthKey() | |
| 132 | + { | |
| 133 | + return $this->auth_key; | |
| 134 | + } | |
| 135 | + | |
| 136 | + /** | |
| 137 | + * @inheritdoc | |
| 138 | + */ | |
| 139 | + public function validateAuthKey($authKey) | |
| 140 | + { | |
| 141 | + return $this->getAuthKey() === $authKey; | |
| 142 | + } | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Validates password | |
| 146 | + * | |
| 147 | + * @param string $password password to validate | |
| 148 | + * @return boolean if password provided is valid for current user | |
| 149 | + */ | |
| 150 | + public function validatePassword($password) | |
| 151 | + { | |
| 152 | + return Yii::$app->security->validatePassword($password, $this->password_hash); | |
| 153 | + } | |
| 154 | + | |
| 155 | + /** | |
| 156 | + * Generates password hash from password and sets it to the model | |
| 157 | + * | |
| 158 | + * @param string $password | |
| 159 | + */ | |
| 160 | + public function setPassword($password) | |
| 161 | + { | |
| 162 | + $this->password_hash = Yii::$app->security->generatePasswordHash($password); | |
| 163 | + } | |
| 164 | + | |
| 165 | + /** | |
| 166 | + * Generates "remember me" authentication key | |
| 167 | + */ | |
| 168 | + public function generateAuthKey() | |
| 169 | + { | |
| 170 | + $this->auth_key = Yii::$app->security->generateRandomString(); | |
| 171 | + } | |
| 172 | + | |
| 173 | + /** | |
| 174 | + * Generates new password reset token | |
| 175 | + */ | |
| 176 | + public function generatePasswordResetToken() | |
| 177 | + { | |
| 178 | + $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); | |
| 179 | + } | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Removes password reset token | |
| 183 | + */ | |
| 184 | + public function removePasswordResetToken() | |
| 185 | + { | |
| 186 | + $this->password_reset_token = null; | |
| 187 | + } | |
| 188 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/Module.php | |
| 1 | +<?php | |
| 2 | +namespace common\modules\blog; | |
| 3 | + | |
| 4 | +use yii\base\BootstrapInterface; | |
| 5 | + | |
| 6 | +class Module extends \yii\base\Module | |
| 7 | +{ | |
| 8 | + public function init() | |
| 9 | + { | |
| 10 | + parent::init(); | |
| 11 | + | |
| 12 | + \Yii::configure($this, require(__DIR__.'/config.php')); | |
| 13 | + } | |
| 14 | + | |
| 15 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/behaviors/Autocomplete.php | |
| 1 | +<?php | |
| 2 | +namespace common\modules\blog\behaviors; | |
| 3 | + | |
| 4 | +use common\models\Tools; | |
| 5 | +use yii\db\ActiveRecord; | |
| 6 | +use yii\base\Behavior; | |
| 7 | +use yii\helpers\StringHelper; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * Класс для автозаполнения полей некими данными или их форматирования | |
| 11 | + * | |
| 12 | + * Клас предназначен для заполнения полей данными или форматирования данных | |
| 13 | + * | |
| 14 | + */ | |
| 15 | + | |
| 16 | +class Autocomplete extends Behavior | |
| 17 | +{ | |
| 18 | + /** | |
| 19 | + * Атрибуты для обработки | |
| 20 | + * | |
| 21 | + * Атрибуты считываются автоматически с настроек поведения в конкретном обьекте. | |
| 22 | + * Имеет вид ассоциативного массива, где ключ - метод автозаполнения, а значение - массив, каждій єлемент | |
| 23 | + * которого - свойство обьекта для обработки, может включать массив - первый єлемент которого свойство, | |
| 24 | + * а дальнейшие конфигурации. | |
| 25 | + * | |
| 26 | + * @var array Ассоциативны массив [key(метод заполнения) => [[0 => property(свойство обьекта), ... дополнительные | |
| 27 | + * настройки]], ...[]] | |
| 28 | + * | |
| 29 | + */ | |
| 30 | + public $attributes; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * События | |
| 34 | + * | |
| 35 | + * События на которые должно срабатывать поведение. Задается ассоциативный массив, в котором ключ - событие | |
| 36 | + * связанного обьекта, а значение - метод, который вызывается при этом событии | |
| 37 | + * | |
| 38 | + * @return array [key(event) => val(method)] | |
| 39 | + * | |
| 40 | + */ | |
| 41 | + public function events() | |
| 42 | + { | |
| 43 | + return [ | |
| 44 | + ActiveRecord::EVENT_BEFORE_INSERT => 'autocomplete', | |
| 45 | + ActiveRecord::EVENT_BEFORE_UPDATE => 'autocomplete', | |
| 46 | + ]; | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * События | |
| 51 | + * | |
| 52 | + * События на которые должно срабатывать поведение. Задается ассоциативный массив, в котором ключ - событие | |
| 53 | + * связанного обьекта, а значение - метод, который вызывается при этом событии | |
| 54 | + * Доступные автозаполнения: | |
| 55 | + * ['translit' => ['prop1', ... 'prop2']], | |
| 56 | + * где prop - свойство подлежащее транслитерации | |
| 57 | + * ['repeat' => [[string 'prop1', string 'target1', boolean 'skipFilled', int 'count', boolean 'truncate', string 'suffix'], ...[]], | |
| 58 | + * где prop - свойство для преобразования, | |
| 59 | + * target - свойство с которого взять данные, | |
| 60 | + * count - число для преобразования, | |
| 61 | + * skipFilled - пропустить непустые, | |
| 62 | + * truncate - true - обрезать по словам, false - по символам, | |
| 63 | + * suffix - суффикс, который добавить после обрезки | |
| 64 | + * | |
| 65 | + * @param mixed $event Yii обьект свойста https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/concept-events.md | |
| 66 | + * | |
| 67 | + */ | |
| 68 | + public function autocomplete($event) | |
| 69 | + { | |
| 70 | + if(!empty($this->attributes['translit'])) { | |
| 71 | + foreach($this->attributes['translit'] as $translit) { | |
| 72 | + if($this->owner->hasAttribute($translit)) { | |
| 73 | + $this->owner->$translit = Tools::translit($this->owner->$translit); | |
| 74 | + } | |
| 75 | + } | |
| 76 | + } | |
| 77 | + if(!empty($this->attributes['repeat'])) { | |
| 78 | + foreach($this->attributes['repeat'] as $repeat) { | |
| 79 | + if(is_array($repeat) && $this->owner->hasAttribute($repeat[0]) && $this->owner->hasAttribute($repeat[1]) && is_int($repeat[3]) && (empty($this->owner->$repeat[0]) || $repeat[2])) { | |
| 80 | + $suffix = $repeat[5]?:''; | |
| 81 | + $truncate = $repeat[4]?'truncateWords':'truncate'; | |
| 82 | + $this->owner->$repeat[0] = StringHelper::$truncate($this->owner->$repeat[1], $repeat[3], $suffix); | |
| 83 | + } | |
| 84 | + } | |
| 85 | + } | |
| 86 | + } | |
| 87 | +} | |
| 0 | 88 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/blog/controllers/AjaxController.php | |
| 1 | +<?php | |
| 2 | +namespace common\modules\blog\controllers; | |
| 3 | + | |
| 4 | +use common\models\Language; | |
| 5 | +use common\modules\blog\models\ArticleCategory; | |
| 6 | +use common\modules\blog\models\ArticleCategoryLang; | |
| 7 | +use common\modules\blog\models\ArticleCategoryMedia; | |
| 8 | +use common\modules\blog\models\ArticleLang; | |
| 9 | +use common\modules\blog\models\ArticleMedia; | |
| 10 | +use yii\base\InvalidParamException; | |
| 11 | +use yii\web\Controller; | |
| 12 | +use yii\web\ForbiddenHttpException; | |
| 13 | +use yii\web\NotFoundHttpException; | |
| 14 | + | |
| 15 | +class AjaxController extends Controller | |
| 16 | +{ | |
| 17 | + public function beforeAction($action) | |
| 18 | + { | |
| 19 | + if(!\Yii::$app->request->getIsAjax()) { | |
| 20 | + //throw new ForbiddenHttpException('Permission denied'); | |
| 21 | + } | |
| 22 | + | |
| 23 | + if(!parent::beforeAction($action)) { | |
| 24 | + return false; | |
| 25 | + } | |
| 26 | + | |
| 27 | + return true; | |
| 28 | + } | |
| 29 | + | |
| 30 | + public function actionCategoryForm($language_id, $widget_id) | |
| 31 | + { | |
| 32 | + $model = Language::find()->where(['>=', 'language_id', 1])->andWhere(['status' => 1, 'language_id' => $language_id])->one(); | |
| 33 | + if(!$model) { | |
| 34 | + throw new NotFoundHttpException('Language not found'); | |
| 35 | + } | |
| 36 | + $category_lang = new ArticleCategoryLang(); | |
| 37 | + return $this->renderAjax('_category_form', ['model' => $model, 'category_lang' => $category_lang, 'widget_id' => $widget_id]); | |
| 38 | + } | |
| 39 | + | |
| 40 | + public function actionArticleForm($language_id, $widget_id) | |
| 41 | + { | |
| 42 | + $model = Language::find()->where(['>=', 'language_id', 1])->andWhere(['status' => 1, 'language_id' => $language_id])->one(); | |
| 43 | + if(!$model) { | |
| 44 | + throw new NotFoundHttpException('Language not found'); | |
| 45 | + } | |
| 46 | + $article_lang = new ArticleLang(); | |
| 47 | + return $this->renderAjax('_article_form', ['model' => $model, 'article_lang' => $article_lang, 'widget_id' => $widget_id]); | |
| 48 | + } | |
| 49 | + | |
| 50 | + public function actionArticleMediaForm($language_id, $widget_id, $type) | |
| 51 | + { | |
| 52 | + $model = Language::find()->where(['>=', 'language_id', 1])->andWhere(['status' => 1, 'language_id' => $language_id])->one(); | |
| 53 | + if(!$model) { | |
| 54 | + throw new NotFoundHttpException('Language not found'); | |
| 55 | + } | |
| 56 | + if(!in_array($type, ['full', 'preview'])) { | |
| 57 | + throw new InvalidParamException('Type must only be full/preview'); | |
| 58 | + } | |
| 59 | + $article_lang = new ArticleMedia(); | |
| 60 | + return $this->renderAjax('_article_media_form', ['model' => $model, 'article_lang' => $article_lang, 'widget_id' => $widget_id, 'type' => $type]); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public function actionArticleCategoryMediaForm($language_id, $widget_id, $type) | |
| 64 | + { | |
| 65 | + $model = Language::find()->where(['>=', 'language_id', 1])->andWhere(['status' => 1, 'language_id' => $language_id])->one(); | |
| 66 | + if(!$model) { | |
| 67 | + throw new NotFoundHttpException('Language not found'); | |
| 68 | + } | |
| 69 | + if(!in_array($type, ['full', 'preview'])) { | |
| 70 | + throw new InvalidParamException('Type must only be full/preview'); | |
| 71 | + } | |
| 72 | + $article_lang = new ArticleCategoryMedia(); | |
| 73 | + return $this->renderAjax('_article_media_form', ['model' => $model, 'article_lang' => $article_lang, 'widget_id' => $widget_id, 'type' => $type]); | |
| 74 | + } | |
| 75 | + | |
| 76 | + public function actionRemoveImage() | |
| 77 | + { | |
| 78 | + $post = \Yii::$app->request->post(); | |
| 79 | + if(!empty($post['article_media_id'])) { | |
| 80 | + $article_media = ArticleMedia::findOne($post['article_media_id']); | |
| 81 | + if($post['remove_media']) { | |
| 82 | + $media = $article_media->media->delete(); | |
| 83 | + } | |
| 84 | + if(!empty($article_media)) { | |
| 85 | + $article_media->delete(); | |
| 86 | + } | |
| 87 | + return true; | |
| 88 | + } else { | |
| 89 | + return false; | |
| 90 | + } | |
| 91 | + } | |
| 92 | + | |
| 93 | + public function actionRemoveCategoryImage() | |
| 94 | + { | |
| 95 | + $post = \Yii::$app->request->post(); | |
| 96 | + if(!empty($post['category_media_id'])) { | |
| 97 | + $category_media = ArticleCategoryMedia::findOne($post['category_media_id']); | |
| 98 | + if($post['remove_media']) { | |
| 99 | + $media = $category_media->media->delete(); | |
| 100 | + } | |
| 101 | + if(!empty($category_media)) { | |
| 102 | + $category_media->delete(); | |
| 103 | + } | |
| 104 | + return true; | |
| 105 | + } else { | |
| 106 | + return false; | |
| 107 | + } | |
| 108 | + } | |
| 109 | + | |
| 110 | + public function actionRemoveImageCategory() | |
| 111 | + { | |
| 112 | + $post = \Yii::$app->request->post(); | |
| 113 | + if(!empty($post['category_media_id'])) { | |
| 114 | + $category_media = ArticleCategoryMedia::findOne($post['category_media_id']); | |
| 115 | + if($post['remove_media']) { | |
| 116 | + $media = $category_media->media->delete(); | |
| 117 | + } | |
| 118 | + if(!empty($category_media)) { | |
| 119 | + $category_media->delete(); | |
| 120 | + } | |
| 121 | + return true; | |
| 122 | + } else { | |
| 123 | + return false; | |
| 124 | + } | |
| 125 | + } | |
| 126 | + | |
| 127 | + public function actionMultilangForm($model, $ajaxView, $widget_id, $language_id = NULL) | |
| 128 | + { | |
| 129 | + $model = new $model(['language_id' => $language_id]); | |
| 130 | + return $this->renderAjax($ajaxView, ['model' => $model, 'widget_id' => $widget_id]); | |
| 131 | + } | |
| 132 | + | |
| 133 | +} | ... | ... |
common/modules/blog/controllers/ArticleController.php
0 → 100644
| 1 | +++ a/common/modules/blog/controllers/ArticleController.php | |
| 1 | +<?php | |
| 2 | +namespace common\modules\blog\controllers; | |
| 3 | + | |
| 4 | +use common\components\rules\CommentRule; | |
| 5 | +use common\components\rules\DeleteRule; | |
| 6 | +use common\components\rules\UpdateRule; | |
| 7 | +use common\components\rules\ViewRule; | |
| 8 | +use common\models\Language; | |
| 9 | +use common\modules\blog\models\Article; | |
| 10 | +use common\modules\blog\models\ArticleLang; | |
| 11 | +use common\modules\blog\models\ArticleMedia; | |
| 12 | +use common\modules\blog\models\ArticleToCategory; | |
| 13 | +use yii\data\ActiveDataProvider; | |
| 14 | +use yii\rbac\DbManager; | |
| 15 | +use yii\web\Controller; | |
| 16 | +use yii\web\UploadedFile; | |
| 17 | + | |
| 18 | +class ArticleController extends Controller | |
| 19 | +{ | |
| 20 | + | |
| 21 | + public function actionIndex() | |
| 22 | + { | |
| 23 | + $dataProvider = new ActiveDataProvider([ | |
| 24 | + 'query' => Article::find(), | |
| 25 | + 'pagination' => [ | |
| 26 | + 'pageSize' => 1, | |
| 27 | + ], | |
| 28 | + ]); | |
| 29 | + return $this->render('index', ['dataProvider' => $dataProvider]); | |
| 30 | + } | |
| 31 | + | |
| 32 | + public function actionCreate() | |
| 33 | + { | |
| 34 | + $article_langs = array(); | |
| 35 | + $article = new Article(); | |
| 36 | + $default_lang = Language::getDefaultLang(); | |
| 37 | + $images = array(); | |
| 38 | + $images[$default_lang->language_id]['full'] = new ArticleMedia(['scenario' => ArticleMedia::SCENARIO_FULL]); | |
| 39 | + $images[$default_lang->language_id]['preview'] = new ArticleMedia(['scenario' => ArticleMedia::SCENARIO_PREVIEW]); | |
| 40 | + $images[0]['additional'] = new ArticleMedia(['scenario' => ArticleMedia::SCENARIO_ADDITIONAL]); | |
| 41 | + $article->loadDefaultValues(); | |
| 42 | + $langs = Language::getActiveLanguages(); | |
| 43 | + $isValid = false; | |
| 44 | + if(!empty(\Yii::$app->request->post())) { | |
| 45 | + $isValid = true; | |
| 46 | + $article->load(\Yii::$app->request->post()); | |
| 47 | + $article->user_id = \Yii::$app->user->getId(); | |
| 48 | + $isValid = $article->validate(); | |
| 49 | + foreach(\Yii::$app->request->post()['ArticleMedia'] as $lang => $value) { | |
| 50 | + foreach($value as $type => $fields) { | |
| 51 | + $images[$lang][$type] = new ArticleMedia(['scenario' => $type]); | |
| 52 | + $images[$lang][$type]->type = $type; | |
| 53 | + $images[$lang][$type]->language_id = $lang; | |
| 54 | + $images[$lang][$type]->imageFile = UploadedFile::getInstance($images[$lang][$type], "[{$lang}][{$type}]imageFile"); | |
| 55 | + $isValid = $images[$lang][$type]->validate(['imageFile']) && $isValid; | |
| 56 | + } | |
| 57 | + } | |
| 58 | + $images[0]['additional']->language_id = 0; | |
| 59 | + $images[0]['additional']->type = 'additional'; | |
| 60 | + $images[0]['additional']->imageFile = UploadedFile::getInstances($images[0]['additional'], "[0][additional]imageFile"); | |
| 61 | + if(empty(\Yii::$app->request->post()['ArticleLang'])) { | |
| 62 | + $article_langs[$default_lang->language_id] = new ArticleLang(); | |
| 63 | + $isValid = ArticleLang::validateMultiple($article_langs) && $isValid; | |
| 64 | + } else { | |
| 65 | + foreach(\Yii::$app->request->post()['ArticleLang'] as $index => $article_lang) { | |
| 66 | + $article_langs[$index] = new ArticleLang(); | |
| 67 | + } | |
| 68 | + ArticleLang::loadMultiple($article_langs, \Yii::$app->request->post()); | |
| 69 | + $isValid = ArticleLang::validateMultiple($article_langs) && $isValid; | |
| 70 | + } | |
| 71 | + } else { | |
| 72 | + $article_langs[$default_lang->language_id] = new ArticleLang(); | |
| 73 | + } | |
| 74 | + if($isValid) { | |
| 75 | + $article->save(false); | |
| 76 | + $article_categories = \Yii::$app->request->post('Article')['articleCategoriesArray']; | |
| 77 | + if(!empty($article_categories)) { | |
| 78 | + foreach($article_categories as $article_category) { | |
| 79 | + $articletocategory[$article_category] = new ArticleToCategory(); | |
| 80 | + $articletocategory[$article_category]->article_category_id = $article_category; | |
| 81 | + $articletocategory[$article_category]->link('article', $article); | |
| 82 | + } | |
| 83 | + } | |
| 84 | + $first = 1; | |
| 85 | + foreach($images as $lang => $value) { | |
| 86 | + foreach($value as $type => $fields) { | |
| 87 | + $images[$lang][$type]->upload($article->article_id); | |
| 88 | + if($first && $type != 'additional') { | |
| 89 | + $media_clone = clone $images[$lang][$type]; | |
| 90 | + $media_clone->setIsNewRecord(true); | |
| 91 | + unset($media_clone->article_media_id); | |
| 92 | + $media_clone->language_id = 0; | |
| 93 | + $media_clone->upload($article->article_id); | |
| 94 | + unset($media_clone); | |
| 95 | + $first = 0; | |
| 96 | + } | |
| 97 | + } | |
| 98 | + } | |
| 99 | + $first = 1; | |
| 100 | + foreach($article_langs as $article_lang) { | |
| 101 | + if($first) { | |
| 102 | + $article_lang_clone = clone $article_lang; | |
| 103 | + $article_lang_clone->language_id = 0; | |
| 104 | + $article_lang_clone->link('article', $article); | |
| 105 | + unset($article_lang_clone); | |
| 106 | + } | |
| 107 | + $article_lang->link('article', $article); | |
| 108 | + $first = 0; | |
| 109 | + } | |
| 110 | + echo "ok"; | |
| 111 | + //$this->redirect('index'); | |
| 112 | + } else { | |
| 113 | + return $this->render('create', [ | |
| 114 | + 'article_langs' => $article_langs, | |
| 115 | + 'article' => $article, | |
| 116 | + 'langs' => $langs, | |
| 117 | + 'images' => $images | |
| 118 | + ]); | |
| 119 | + } | |
| 120 | + } | |
| 121 | + | |
| 122 | + public function actionUpdate($id) | |
| 123 | + { | |
| 124 | + $article = Article::findOne($id); | |
| 125 | + $imagestack = $article->getArticleMedia()->all(); | |
| 126 | + $images = []; | |
| 127 | + $images[0]['additional'][0] = new ArticleMedia(['scenario' => ArticleMedia::SCENARIO_ADDITIONAL]); | |
| 128 | + $images[0]['additional'][0]->type = 'additional'; | |
| 129 | + $images[0]['additional'][0]->language_id = 0; | |
| 130 | + foreach($imagestack as $image) { | |
| 131 | + if(in_array($image->type, ['full', 'preview'])) { | |
| 132 | + $images[$image->language_id][$image->type] = $image; | |
| 133 | + $images[$image->language_id][$image->type]->scenario = $image->type; | |
| 134 | + } else { | |
| 135 | + $images[$image->language_id][$image->type][$image->article_media_id] = $image; | |
| 136 | + $images[$image->language_id][$image->type][$image->article_media_id]->scenario = $image->type; | |
| 137 | + } | |
| 138 | + } | |
| 139 | + foreach($images as $lang => $value) { | |
| 140 | + $images[$lang]['additional'][0] = new ArticleMedia(['scenario' => ArticleMedia::SCENARIO_ADDITIONAL]); | |
| 141 | + } | |
| 142 | + $article_langs = $article->getArticleLangs()->where(['>=', 'language_id', '1'])->indexBy('language_id')->all(); | |
| 143 | + $langs = Language::getActiveLanguages(); | |
| 144 | + $default_lang = Language::getDefaultLang(); | |
| 145 | + $isValid = false; | |
| 146 | + if(!empty(\Yii::$app->request->post())) { | |
| 147 | + $isValid = true; | |
| 148 | + $article->load(\Yii::$app->request->post()); | |
| 149 | + ArticleToCategory::deleteAll(['article_id' => $article->article_id]); | |
| 150 | + $article_categories = \Yii::$app->request->post('Article')['articleCategoriesArray']; | |
| 151 | + if(!empty($article_categories)) { | |
| 152 | + foreach($article_categories as $article_category) { | |
| 153 | + $articletocategory[$article_category] = new ArticleToCategory(); | |
| 154 | + $articletocategory[$article_category]->article_category_id = $article_category; | |
| 155 | + $articletocategory[$article_category]->link('article', $article); | |
| 156 | + } | |
| 157 | + } | |
| 158 | + $isValid = $article->validate(); | |
| 159 | + $images[0]['additional'][0]->type = 'additional'; | |
| 160 | + $images[0]['additional'][0]->language_id = 0; | |
| 161 | + $images[0]['additional'][0]->imageFile = UploadedFile::getInstances($images[0]['additional'][0], "[0][additional]imageFile"); | |
| 162 | + $isValid = $images[0]['additional'][0]->validate(['imageFile']) && $isValid; | |
| 163 | + foreach(\Yii::$app->request->post()['ArticleMedia'] as $lang => $value) { | |
| 164 | + foreach($value as $type => $fields) { | |
| 165 | + if(!in_array($type, ['full', 'preview'])) continue; | |
| 166 | + $images[$lang][$type] = new ArticleMedia(['scenario' => $type]); | |
| 167 | + $images[$lang][$type]->language_id = $lang; | |
| 168 | + $images[$lang][$type]->type = $type; | |
| 169 | + $images[$lang][$type]->imageFile = UploadedFile::getInstance($images[$lang][$type], "[{$lang}][{$type}]imageFile"); | |
| 170 | + $isValid = $images[$lang][$type]->validate(['imageFile']) && $isValid; | |
| 171 | + } | |
| 172 | + } | |
| 173 | + if(empty(\Yii::$app->request->post()['ArticleLang'])) { | |
| 174 | + $isValid = ArticleLang::validateMultiple($article_langs) && $isValid; | |
| 175 | + } else { | |
| 176 | + foreach(\Yii::$app->request->post()['ArticleLang'] as $index => $article_lang) { | |
| 177 | + if (!array_key_exists($index, $article_langs)) { | |
| 178 | + $article_langs[$index] = new ArticleLang(); | |
| 179 | + $article_langs[$index]->article_id = $article->article_id; | |
| 180 | + } | |
| 181 | + } | |
| 182 | + ArticleLang::loadMultiple($article_langs, \Yii::$app->request->post()); | |
| 183 | + $isValid = ArticleLang::validateMultiple($article_langs) && $isValid; | |
| 184 | + } | |
| 185 | + } | |
| 186 | + if($isValid) { | |
| 187 | + $article->save(false); | |
| 188 | + foreach($images as $lang => $value) { | |
| 189 | + foreach($value as $type => $fields) { | |
| 190 | + if($type == 'additional') { | |
| 191 | + $images[$lang][$type][0]->upload($article->id); | |
| 192 | + } else { | |
| 193 | + if(!empty($images[$lang][$type]->imageFile)) { | |
| 194 | + $images[$lang][$type]->replace($article->article_id); | |
| 195 | + } | |
| 196 | + } | |
| 197 | + } | |
| 198 | + } | |
| 199 | + foreach($article_langs as $article_lang) { | |
| 200 | + $article_lang->save(false); | |
| 201 | + } | |
| 202 | + echo "ok"; | |
| 203 | + //$this->redirect('index'); | |
| 204 | + } else { | |
| 205 | + return $this->render('update', [ | |
| 206 | + 'article_langs' => $article_langs, | |
| 207 | + 'article' => $article, | |
| 208 | + 'langs' => $langs, | |
| 209 | + 'images' => $images | |
| 210 | + ]); | |
| 211 | + } | |
| 212 | + } | |
| 213 | + | |
| 214 | + public function actionDelete($id) | |
| 215 | + { | |
| 216 | + $this->findModel($id)->delete(); | |
| 217 | + return $this->redirect(['index']); | |
| 218 | + } | |
| 219 | + | |
| 220 | + protected function findModel($id) | |
| 221 | + { | |
| 222 | + if (($model = Article::findOne($id)) !== null) { | |
| 223 | + return $model; | |
| 224 | + } else { | |
| 225 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
| 226 | + } | |
| 227 | + } | |
| 228 | +} | ... | ... |
common/modules/blog/controllers/CategoryController.php
0 → 100644
| 1 | +++ a/common/modules/blog/controllers/CategoryController.php | |
| 1 | +<?php | |
| 2 | +namespace common\modules\blog\controllers; | |
| 3 | + | |
| 4 | +use common\models\Language; | |
| 5 | +use common\modules\blog\models\Article; | |
| 6 | +use common\modules\blog\models\ArticleCategory; | |
| 7 | +use common\modules\blog\models\ArticleCategoryLang; | |
| 8 | +use common\modules\blog\models\ArticleCategoryMedia; | |
| 9 | +use common\modules\blog\models\ArticleLang; | |
| 10 | +use yii\data\ActiveDataProvider; | |
| 11 | +use yii\filters\VerbFilter; | |
| 12 | +use yii\web\Controller; | |
| 13 | +use yii\web\NotFoundHttpException; | |
| 14 | +use yii\web\UploadedFile; | |
| 15 | + | |
| 16 | +class CategoryController extends Controller | |
| 17 | +{ | |
| 18 | + public function behaviors() | |
| 19 | + { | |
| 20 | + return [ | |
| 21 | + 'verbs' => [ | |
| 22 | + 'class' => VerbFilter::className(), | |
| 23 | + 'actions' => [ | |
| 24 | + 'delete' => ['post'] | |
| 25 | + ] | |
| 26 | + ] | |
| 27 | + ]; | |
| 28 | + } | |
| 29 | + | |
| 30 | + public function actionIndex() | |
| 31 | + { | |
| 32 | + $dataProvider = new ActiveDataProvider([ | |
| 33 | + 'query' => ArticleCategory::find(), | |
| 34 | + 'pagination' => [ | |
| 35 | + 'pageSize' => 1, | |
| 36 | + ], | |
| 37 | + ]); | |
| 38 | + return $this->render('index', ['dataProvider' => $dataProvider]); | |
| 39 | + } | |
| 40 | + | |
| 41 | + public function actionCreate() | |
| 42 | + { | |
| 43 | + $category_langs = array(); | |
| 44 | + $category = new ArticleCategory(); | |
| 45 | + $default_lang = Language::getDefaultLang(); | |
| 46 | + $images = array(); | |
| 47 | + $images[$default_lang->language_id]['full'] = new ArticleCategoryMedia(['scenario' => ArticleCategoryMedia::SCENARIO_FULL]); | |
| 48 | + $images[$default_lang->language_id]['preview'] = new ArticleCategoryMedia(['scenario' => ArticleCategoryMedia::SCENARIO_PREVIEW]); | |
| 49 | + $images[0]['additional'] = new ArticleCategoryMedia(['scenario' => ArticleCategoryMedia::SCENARIO_ADDITIONAL]); | |
| 50 | + $category->loadDefaultValues(); | |
| 51 | + $langs = Language::getActiveLanguages(); | |
| 52 | + $isValid = false; | |
| 53 | + if(!empty(\Yii::$app->request->post())) { | |
| 54 | + $isValid = true; | |
| 55 | + $category->load(\Yii::$app->request->post()); | |
| 56 | + $isValid = $category->validate(); | |
| 57 | + foreach(\Yii::$app->request->post()['ArticleCategoryMedia'] as $lang => $value) { | |
| 58 | + foreach($value as $type => $fields) { | |
| 59 | + $images[$lang][$type] = new ArticleCategoryMedia(['scenario' => $type]); | |
| 60 | + $images[$lang][$type]->type = $type; | |
| 61 | + $images[$lang][$type]->language_id = $lang; | |
| 62 | + $images[$lang][$type]->imageFile = UploadedFile::getInstance($images[$lang][$type], "[{$lang}][{$type}]imageFile"); | |
| 63 | + $isValid = $images[$lang][$type]->validate(['imageFile']) && $isValid; | |
| 64 | + } | |
| 65 | + } | |
| 66 | + $images[0]['additional']->language_id = 0; | |
| 67 | + $images[0]['additional']->type = 'additional'; | |
| 68 | + $images[0]['additional']->imageFile = UploadedFile::getInstances($images[0]['additional'], "[0][additional]imageFile"); | |
| 69 | + if(empty(\Yii::$app->request->post()['ArticleCategoryLang'])) { | |
| 70 | + $category_langs[$default_lang->language_id] = new ArticleCategoryLang(); | |
| 71 | + $isValid = ArticleCategoryLang::validateMultiple($category_langs) && $isValid; | |
| 72 | + } else { | |
| 73 | + foreach(\Yii::$app->request->post()['ArticleCategoryLang'] as $index => $category_lang) { | |
| 74 | + $category_langs[$index] = new ArticleCategoryLang(); | |
| 75 | + } | |
| 76 | + ArticleCategoryLang::loadMultiple($category_langs, \Yii::$app->request->post()); | |
| 77 | + $isValid = ArticleCategoryLang::validateMultiple($category_langs) && $isValid; | |
| 78 | + } | |
| 79 | + } else { | |
| 80 | + $category_langs[$default_lang->language_id] = new ArticleCategoryLang(); | |
| 81 | + } | |
| 82 | + if($isValid) { | |
| 83 | + $category->save(false); | |
| 84 | + $first = 1; | |
| 85 | + foreach($images as $lang => $value) { | |
| 86 | + foreach($value as $type => $fields) { | |
| 87 | + $images[$lang][$type]->upload($category->article_category_id); | |
| 88 | + if($first && $type != 'additional') { | |
| 89 | + $media_clone = clone $images[$lang][$type]; | |
| 90 | + $media_clone->setIsNewRecord(true); | |
| 91 | + unset($media_clone->article_category_media_id); | |
| 92 | + $media_clone->language_id = 0; | |
| 93 | + $media_clone->upload($category->article_category_id); | |
| 94 | + unset($media_clone); | |
| 95 | + $first = 0; | |
| 96 | + } | |
| 97 | + } | |
| 98 | + } | |
| 99 | + $first = 1; | |
| 100 | + foreach($category_langs as $category_lang) { | |
| 101 | + if($first) { | |
| 102 | + $category_lang_clone = clone $category_lang; | |
| 103 | + $category_lang_clone->language_id = 0; | |
| 104 | + $category_lang_clone->link('category', $category); | |
| 105 | + unset($category_lang_clone); | |
| 106 | + } | |
| 107 | + $category_lang->link('category', $category); | |
| 108 | + $first = 0; | |
| 109 | + } | |
| 110 | + echo "ok"; | |
| 111 | + //$this->redirect('index'); | |
| 112 | + } else { | |
| 113 | + return $this->render('create', [ | |
| 114 | + 'category_langs' => $category_langs, | |
| 115 | + 'category' => $category, | |
| 116 | + 'langs' => $langs, | |
| 117 | + 'images' => $images | |
| 118 | + ]); | |
| 119 | + } | |
| 120 | + } | |
| 121 | + | |
| 122 | + public function actionUpdate($id) | |
| 123 | + { | |
| 124 | + $category = ArticleCategory::findOne($id); | |
| 125 | + $imagestack = $category->getArticleCategoryMedia()->all(); | |
| 126 | + $images = []; | |
| 127 | + $images[0]['additional'][0] = new ArticleCategoryMedia(['scenario' => ArticleCategoryMedia::SCENARIO_ADDITIONAL]); | |
| 128 | + $images[0]['additional'][0]->type = 'additional'; | |
| 129 | + $images[0]['additional'][0]->language_id = 0; | |
| 130 | + foreach($imagestack as $image) { | |
| 131 | + if(in_array($image->type, ['full', 'preview'])) { | |
| 132 | + $images[$image->language_id][$image->type] = $image; | |
| 133 | + $images[$image->language_id][$image->type]->scenario = $image->type; | |
| 134 | + } else { | |
| 135 | + $images[$image->language_id][$image->type][$image->article_category_media_id] = $image; | |
| 136 | + $images[$image->language_id][$image->type][$image->article_category_media_id]->scenario = $image->type; | |
| 137 | + } | |
| 138 | + } | |
| 139 | + foreach($images as $lang => $value) { | |
| 140 | + $images[$lang]['additional'][0] = new ArticleCategoryMedia(['scenario' => ArticleCategoryMedia::SCENARIO_ADDITIONAL]); | |
| 141 | + } | |
| 142 | + $category_langs = $category->getArticleCategoryLangs()->where(['>=', 'language_id', '1'])->indexBy('language_id')->all(); | |
| 143 | + $langs = Language::getActiveLanguages(); | |
| 144 | + $default_lang = Language::getDefaultLang(); | |
| 145 | + $isValid = false; | |
| 146 | + if(!empty(\Yii::$app->request->post())) { | |
| 147 | + $isValid = true; | |
| 148 | + $category->load(\Yii::$app->request->post()); | |
| 149 | + $isValid = $category->validate(); | |
| 150 | + $images[0]['additional'][0]->type = 'additional'; | |
| 151 | + $images[0]['additional'][0]->language_id = 0; | |
| 152 | + $images[0]['additional'][0]->imageFile = UploadedFile::getInstances($images[0]['additional'][0], "[0][additional]imageFile"); | |
| 153 | + $isValid = $images[0]['additional'][0]->validate(['imageFile']) && $isValid; | |
| 154 | + foreach(\Yii::$app->request->post()['ArticleCategoryMedia'] as $lang => $value) { | |
| 155 | + foreach($value as $type => $fields) { | |
| 156 | + if(!in_array($type, ['full', 'preview'])) continue; | |
| 157 | + $images[$lang][$type] = new ArticleCategoryMedia(['scenario' => $type]); | |
| 158 | + $images[$lang][$type]->language_id = $lang; | |
| 159 | + $images[$lang][$type]->type = $type; | |
| 160 | + $images[$lang][$type]->imageFile = UploadedFile::getInstance($images[$lang][$type], "[{$lang}][{$type}]imageFile"); | |
| 161 | + $isValid = $images[$lang][$type]->validate(['imageFile']) && $isValid; | |
| 162 | + } | |
| 163 | + } | |
| 164 | + if(empty(\Yii::$app->request->post()['ArticleCategoryLang'])) { | |
| 165 | + $isValid = ArticleCategoryLang::validateMultiple($category_langs) && $isValid; | |
| 166 | + } else { | |
| 167 | + foreach(\Yii::$app->request->post()['ArticleCategoryLang'] as $index => $category_lang) { | |
| 168 | + if(!array_key_exists($index, $category_langs)) { | |
| 169 | + $category_langs[$index] = new ArticleCategoryLang(); | |
| 170 | + $category_langs[$index]->article_category_id = $category->article_category_id; | |
| 171 | + } | |
| 172 | + } | |
| 173 | + ArticleCategoryLang::loadMultiple($category_langs, \Yii::$app->request->post()); | |
| 174 | + $isValid = ArticleCategoryLang::validateMultiple($category_langs) && $isValid; | |
| 175 | + } | |
| 176 | + } | |
| 177 | + if($isValid) { | |
| 178 | + $category->save(false); | |
| 179 | + foreach($images as $lang => $value) { | |
| 180 | + foreach($value as $type => $fields) { | |
| 181 | + if($type == 'additional') { | |
| 182 | + $images[$lang][$type][0]->upload($category->article_category_id); | |
| 183 | + } else { | |
| 184 | + if(!empty($images[$lang][$type]->imageFile)) { | |
| 185 | + $images[$lang][$type]->replace($category->article_category_id); | |
| 186 | + } | |
| 187 | + } | |
| 188 | + } | |
| 189 | + } | |
| 190 | + foreach($category_langs as $category_lang) { | |
| 191 | + $category_lang->save(false); | |
| 192 | + } | |
| 193 | + echo "ok"; | |
| 194 | + //$this->redirect('index'); | |
| 195 | + } else { | |
| 196 | + return $this->render('update', [ | |
| 197 | + 'category_langs' => $category_langs, | |
| 198 | + 'category' => $category, | |
| 199 | + 'langs' => $langs, | |
| 200 | + 'images' => $images | |
| 201 | + ]); | |
| 202 | + } | |
| 203 | + } | |
| 204 | + | |
| 205 | + public function actionDelete($id) | |
| 206 | + { | |
| 207 | + $this->findModel($id)->delete(); | |
| 208 | + return $this->redirect(['index']); | |
| 209 | + } | |
| 210 | + | |
| 211 | + protected function findModel($id) | |
| 212 | + { | |
| 213 | + if (($model = ArticleCategory::findOne($id)) !== null) { | |
| 214 | + return $model; | |
| 215 | + } else { | |
| 216 | + throw new NotFoundHttpException('The requested page does not exist.'); | |
| 217 | + } | |
| 218 | + } | |
| 219 | +} | ... | ... |
common/modules/blog/controllers/DefaultController.php
0 → 100644
common/modules/blog/controllers/MediaController.php
0 → 100644
| 1 | +++ a/common/modules/blog/controllers/MediaController.php | |
| 1 | +<?php | |
| 2 | +namespace common\modules\blog\controllers; | |
| 3 | + | |
| 4 | +use common\models\Media; | |
| 5 | +use common\modules\blog\models\Article; | |
| 6 | +use yii\web\Controller; | |
| 7 | +use yii\web\UploadedFile; | |
| 8 | + | |
| 9 | +class MediaController extends Controller | |
| 10 | +{ | |
| 11 | + public function actionIndex() | |
| 12 | + { | |
| 13 | + $model = new Media(); | |
| 14 | + if(\Yii::$app->request->isPost) { | |
| 15 | + $model->imageFile = UploadedFile::getInstance($model, 'imageFile'); | |
| 16 | + if($model->upload()) { | |
| 17 | + return true; | |
| 18 | + } else { | |
| 19 | + return false; | |
| 20 | + } | |
| 21 | + } | |
| 22 | + return $this->render('index', ['model' => $model]); | |
| 23 | + } | |
| 24 | + | |
| 25 | + public function actionCreate() | |
| 26 | + { | |
| 27 | + | |
| 28 | + } | |
| 29 | + | |
| 30 | + public function actionUpdate($id) | |
| 31 | + { | |
| 32 | + | |
| 33 | + } | |
| 34 | + | |
| 35 | + public function actionDelete($id) | |
| 36 | + { | |
| 37 | + $model = Media::findOne($id); | |
| 38 | + return $model->delete(); | |
| 39 | + } | |
| 40 | + | |
| 41 | + protected function findModel($id) | |
| 42 | + { | |
| 43 | + | |
| 44 | + } | |
| 45 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/controllers/TestController.php | |
| 1 | +<?php | |
| 2 | +namespace common\modules\blog\controllers; | |
| 3 | + | |
| 4 | +use common\models\Language; | |
| 5 | +use common\modules\blog\models\ArticleLang; | |
| 6 | +use yii\console\Controller; | |
| 7 | + | |
| 8 | +class TestController extends Controller | |
| 9 | +{ | |
| 10 | + public function actionIndex() | |
| 11 | + { | |
| 12 | + $default_lang = Language::getDefaultLang(); | |
| 13 | + $model[$default_lang->language_id] = new ArticleLang(); | |
| 14 | + $model[3] = new ArticleLang(); | |
| 15 | + return $this->render('index', ['model' => $model]); | |
| 16 | + } | |
| 17 | +} | |
| 0 | 18 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/blog/models/Article.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\modules\blog\models; | |
| 4 | + | |
| 5 | +use common\models\ActiveRecordRule; | |
| 6 | +use common\models\Media; | |
| 7 | +use common\models\User; | |
| 8 | +use common\modules\blog\behaviors\Autocomplete; | |
| 9 | +use Yii; | |
| 10 | +use yii\db\Query; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * This is the model class for table "article". | |
| 14 | + * | |
| 15 | + * @property integer $article_id | |
| 16 | + * @property integer $sort | |
| 17 | + * @property string $date_add | |
| 18 | + * @property string $date_update | |
| 19 | + * @property string $code | |
| 20 | + * @property integer $user_id | |
| 21 | + * @property string $tag | |
| 22 | + * @property integer $article_pid | |
| 23 | + * @property integer $status | |
| 24 | + * @property integer $comment | |
| 25 | + * @property integer $vote | |
| 26 | + * | |
| 27 | + * @property Article $parent | |
| 28 | + * @property Article[] $articles | |
| 29 | + * @property User $user | |
| 30 | + * @property ArticleLang[] $articleLangs | |
| 31 | + * @property ArticleMedia[] $articleMedia | |
| 32 | + * @property ArticleToCategory[] $articleToCategories | |
| 33 | + * @property Media[] $media | |
| 34 | + */ | |
| 35 | +class Article extends ActiveRecordRule | |
| 36 | +{ | |
| 37 | + /** | |
| 38 | + * @inheritdoc | |
| 39 | + */ | |
| 40 | + public static function tableName() | |
| 41 | + { | |
| 42 | + return 'article'; | |
| 43 | + } | |
| 44 | + | |
| 45 | + public function behaviors() | |
| 46 | + { | |
| 47 | + return [ | |
| 48 | + [ | |
| 49 | + 'class' => Autocomplete::className(), | |
| 50 | + 'attributes' => [ | |
| 51 | + 'translit' => ['code'], | |
| 52 | + ] | |
| 53 | + ] | |
| 54 | + ]; | |
| 55 | + } | |
| 56 | + /** | |
| 57 | + * @inheritdoc | |
| 58 | + */ | |
| 59 | + public function rules() | |
| 60 | + { | |
| 61 | + return [ | |
| 62 | + [['sort', 'article_pid', 'status', 'comment', 'vote'], 'integer'], | |
| 63 | + [['date_add', 'date_update'], 'safe'], | |
| 64 | + [['code'], 'required'], | |
| 65 | + [['code', 'tag'], 'string'] | |
| 66 | + ]; | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * @inheritdoc | |
| 71 | + */ | |
| 72 | + public function attributeLabels() | |
| 73 | + { | |
| 74 | + return [ | |
| 75 | + 'article_id' => Yii::t('app', 'ID'), | |
| 76 | + 'sort' => Yii::t('app', 'Sort'), | |
| 77 | + 'date_add' => Yii::t('app', 'Create At'), | |
| 78 | + 'date_update' => Yii::t('app', 'Update At'), | |
| 79 | + 'code' => Yii::t('app', 'Code'), | |
| 80 | + 'user_id' => Yii::t('app', 'Author'), | |
| 81 | + 'tag' => Yii::t('app', 'Tags'), | |
| 82 | + 'article_pid' => Yii::t('app', 'Parent ID'), | |
| 83 | + 'status' => Yii::t('app', 'Active'), | |
| 84 | + 'comment' => Yii::t('app', 'Comments'), | |
| 85 | + 'vote' => Yii::t('app', 'Voting'), | |
| 86 | + ]; | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * @return \yii\db\ActiveQuery | |
| 91 | + */ | |
| 92 | + public function getParent() | |
| 93 | + { | |
| 94 | + return $this->hasOne(Article::className(), ['article_id' => 'article_pid']); | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * @return \yii\db\ActiveQuery | |
| 99 | + */ | |
| 100 | + public function getArticles() | |
| 101 | + { | |
| 102 | + return $this->hasMany(Article::className(), ['article_pid' => 'article_id']); | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * @return \yii\db\ActiveQuery | |
| 107 | + */ | |
| 108 | + public function getUser() | |
| 109 | + { | |
| 110 | + return $this->hasOne(User::className(), ['id' => 'user_id']); | |
| 111 | + } | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * @return \yii\db\ActiveQuery | |
| 115 | + */ | |
| 116 | + public function getArticleLangs() | |
| 117 | + { | |
| 118 | + return $this->hasMany(ArticleLang::className(), ['article_id' => 'article_id']); | |
| 119 | + } | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * @return \yii\db\ActiveQuery | |
| 123 | + */ | |
| 124 | + public function getArticleMedia() | |
| 125 | + { | |
| 126 | + return $this->hasMany(ArticleMedia::className(), ['article_id' => 'article_id']); | |
| 127 | + } | |
| 128 | + | |
| 129 | + public function getMedia() | |
| 130 | + { | |
| 131 | + return $this->hasMany(Media::className(), ['article_id' => 'media_id'])->via('articleMedia'); | |
| 132 | + } | |
| 133 | + /** | |
| 134 | + * @return \yii\db\ActiveQuery | |
| 135 | + */ | |
| 136 | + public function getArticleToCategories() | |
| 137 | + { | |
| 138 | + return $this->hasMany(ArticleToCategory::className(), ['article_id' => 'article_id']); | |
| 139 | + } | |
| 140 | + | |
| 141 | + public function getArticleCategories() | |
| 142 | + { | |
| 143 | + return $this->hasMany(ArticleCategory::className(), ['article_category_id' => 'article_category_id'])->viaTable('article_to_category', ['article_id' => 'article_category_id']); | |
| 144 | + } | |
| 145 | + | |
| 146 | + public static function findArticleDropdown($id) | |
| 147 | + { | |
| 148 | + $query = new Query(); | |
| 149 | + return $query->select(['l.name', 'a.article_id']) | |
| 150 | + ->from(['article a']) | |
| 151 | + ->leftJoin(['article_lang l'], 'a.article_id = l.article_id') | |
| 152 | + ->where(['l.language_id' => 0, 'a.status' => 1]) | |
| 153 | + ->andWhere(['not', ['a.article_id' => $id]]) | |
| 154 | + ->indexBy('article_id') | |
| 155 | + ->column(); | |
| 156 | + } | |
| 157 | + | |
| 158 | + public function getArticleCategoriesArray() | |
| 159 | + { | |
| 160 | + return $this->getArticleToCategories()->select('article_category_id')->column(); | |
| 161 | + } | |
| 162 | + | |
| 163 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/models/ArticleCategory.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\modules\blog\models; | |
| 4 | + | |
| 5 | +use common\modules\blog\behaviors\Autocomplete; | |
| 6 | +use Yii; | |
| 7 | +use yii\behaviors\TimestampBehavior; | |
| 8 | +use yii\db\ActiveRecord; | |
| 9 | +use yii\db\Query; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * This is the model class for table "article_category". | |
| 13 | + * | |
| 14 | + * @property integer $article_category_id | |
| 15 | + * @property integer $status | |
| 16 | + * @property integer $sort | |
| 17 | + * @property string $code | |
| 18 | + * @property string $date_add | |
| 19 | + * @property string $date_update | |
| 20 | + * @property string $tag | |
| 21 | + * @property integer $artucle_category_pid | |
| 22 | + * | |
| 23 | + * @property Article[] $articles | |
| 24 | + * @property ArticleCategory $parent | |
| 25 | + * @property ArticleCategory[] $articleCategories | |
| 26 | + * @property ArticleCategoryLang[] $articleCategoryLangs | |
| 27 | + * @property ArticleCategoryMedia[] $articleCategoryMedia | |
| 28 | + */ | |
| 29 | +class ArticleCategory extends ActiveRecord | |
| 30 | +{ | |
| 31 | + /** | |
| 32 | + * @inheritdoc | |
| 33 | + */ | |
| 34 | + public static function tableName() | |
| 35 | + { | |
| 36 | + return 'article_category'; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public function behaviors() | |
| 40 | + { | |
| 41 | + return [ | |
| 42 | + [ | |
| 43 | + 'class' => Autocomplete::className(), | |
| 44 | + 'attributes' => [ | |
| 45 | + 'translit' => ['code'], | |
| 46 | + ] | |
| 47 | + ] | |
| 48 | + ]; | |
| 49 | + } | |
| 50 | + /** | |
| 51 | + * @inheritdoc | |
| 52 | + */ | |
| 53 | + public function rules() | |
| 54 | + { | |
| 55 | + return [ | |
| 56 | + [['status', 'sort', 'article_category_pid'], 'integer'], | |
| 57 | + [['code'], 'required'], | |
| 58 | + [['code', 'tag'], 'string'], | |
| 59 | + [['date_add', 'date_update'], 'safe'], | |
| 60 | + [['status'], 'boolean'], | |
| 61 | + ]; | |
| 62 | + } | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * @inheritdoc | |
| 66 | + */ | |
| 67 | + public function attributeLabels() | |
| 68 | + { | |
| 69 | + return [ | |
| 70 | + 'article_category_id' => Yii::t('app', 'ID'), | |
| 71 | + 'status' => Yii::t('app', 'Active'), | |
| 72 | + 'sort' => Yii::t('app', 'Sort'), | |
| 73 | + 'code' => Yii::t('app', 'Code'), | |
| 74 | + 'date_add' => Yii::t('app', 'Created At'), | |
| 75 | + 'date_update' => Yii::t('app', 'Updated At'), | |
| 76 | + 'tag' => Yii::t('app', 'Tags'), | |
| 77 | + 'article_category_pid' => Yii::t('app', 'Parent ID'), | |
| 78 | + ]; | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * @return \yii\db\ActiveQuery | |
| 83 | + */ | |
| 84 | + public function getArticles() | |
| 85 | + { | |
| 86 | + return $this->hasMany(Article::className(), ['article_id' => 'article_id'])->viaTable('article_to_category', ['article_category_id' => 'article_category_id']) ; | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * @return \yii\db\ActiveQuery | |
| 91 | + */ | |
| 92 | + public function getParent() | |
| 93 | + { | |
| 94 | + return $this->hasOne(ArticleCategory::className(), ['article_category_id' => 'article_category_pid']); | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * @return \yii\db\ActiveQuery | |
| 99 | + */ | |
| 100 | + public function getArticleCategories() | |
| 101 | + { | |
| 102 | + return $this->hasMany(ArticleCategory::className(), ['article_category_pid' => 'article_category_id']); | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * @return \yii\db\ActiveQuery | |
| 107 | + */ | |
| 108 | + public function getArticleCategoryLangs() | |
| 109 | + { | |
| 110 | + return $this->hasMany(ArticleCategoryLang::className(), ['article_category_id' => 'article_category_id']); | |
| 111 | + } | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * @return \yii\db\ActiveQuery | |
| 115 | + */ | |
| 116 | + public function getArticleCategoryMedia() | |
| 117 | + { | |
| 118 | + return $this->hasMany(ArticleCategoryMedia::className(), ['article_category_id' => 'article_category_id']); | |
| 119 | + } | |
| 120 | + | |
| 121 | + public static function findArticleCategoryDropdown($id) | |
| 122 | + { | |
| 123 | + $query = new Query(); | |
| 124 | + return $query->select(['l.name', 'c.article_category_id']) | |
| 125 | + ->from(['article_category c']) | |
| 126 | + ->leftJoin(['article_category_lang l'], 'c.article_category_id = l.article_category_id') | |
| 127 | + ->where(['l.language_id' => 0, 'c.status' => 1]) | |
| 128 | + ->andWhere(['not', ['c.article_category_id' => $id]]) | |
| 129 | + ->indexBy('article_category_id') | |
| 130 | + ->column(); | |
| 131 | + } | |
| 132 | + | |
| 133 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/models/ArticleCategoryLang.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\modules\blog\models; | |
| 4 | + | |
| 5 | +use common\modules\blog\behaviors\Autocomplete; | |
| 6 | +use Yii; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * This is the model class for table "article_category_lang". | |
| 10 | + * | |
| 11 | + * @property integer $article_category_language_id | |
| 12 | + * @property integer $language_id | |
| 13 | + * @property integer $article_category_id | |
| 14 | + * @property string $text | |
| 15 | + * @property string $preview | |
| 16 | + * @property string $seo_url | |
| 17 | + * @property string $name | |
| 18 | + * @property string $meta_title | |
| 19 | + * @property string $meta_descr | |
| 20 | + * @property string $meta_keyword | |
| 21 | + * @property string $h1_tag | |
| 22 | + * @property string $tag | |
| 23 | + * | |
| 24 | + * @property ArticleCategory $category | |
| 25 | + * @property Language $lang | |
| 26 | + */ | |
| 27 | +class ArticleCategoryLang extends \yii\db\ActiveRecord | |
| 28 | +{ | |
| 29 | + /** | |
| 30 | + * @inheritdoc | |
| 31 | + */ | |
| 32 | + public static function tableName() | |
| 33 | + { | |
| 34 | + return 'article_category_lang'; | |
| 35 | + } | |
| 36 | + | |
| 37 | + public function behaviors() | |
| 38 | + { | |
| 39 | + return [ | |
| 40 | + [ | |
| 41 | + 'class' => Autocomplete::className(), | |
| 42 | + 'attributes' => [ | |
| 43 | + 'repeat' => [['preview', 'text', false, 5, true, '...']], | |
| 44 | + ] | |
| 45 | + ] | |
| 46 | + ]; | |
| 47 | + } | |
| 48 | + /** | |
| 49 | + * @inheritdoc | |
| 50 | + */ | |
| 51 | + public function rules() | |
| 52 | + { | |
| 53 | + return [ | |
| 54 | + [['language_id', 'article_category_id'], 'integer'], | |
| 55 | + [['text', 'name'], 'required'], | |
| 56 | + [['text', 'preview', 'seo_url', 'name', 'meta_title', 'meta_descr', 'meta_keyword', 'h1_tag', 'tag'], 'string'], | |
| 57 | + ['seo_url', function($attribute, $params) { | |
| 58 | + $pattern = "/^[a-zA-Z\d_-]+$/"; | |
| 59 | + if(!preg_match($pattern, $this->$attribute)) { | |
| 60 | + $this->addError($attribute, Yii::t('app', "Pattern doesn't match.")); | |
| 61 | + } | |
| 62 | + }] | |
| 63 | + ]; | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * @inheritdoc | |
| 68 | + */ | |
| 69 | + public function attributeLabels() | |
| 70 | + { | |
| 71 | + return [ | |
| 72 | + 'article_category_language_id' => Yii::t('app', 'ID'), | |
| 73 | + 'language_id' => Yii::t('app', 'Lang ID'), | |
| 74 | + 'article_category_id' => Yii::t('app', 'Category ID'), | |
| 75 | + 'text' => Yii::t('app', 'Text'), | |
| 76 | + 'preview' => Yii::t('app', 'Preview'), | |
| 77 | + 'seo_url' => Yii::t('app', 'Seo Url'), | |
| 78 | + 'name' => Yii::t('app', 'Name'), | |
| 79 | + 'meta_title' => Yii::t('app', 'Meta Title'), | |
| 80 | + 'meta_descr' => Yii::t('app', 'Meta Descr'), | |
| 81 | + 'meta_keyword' => Yii::t('app', 'Meta Keywords'), | |
| 82 | + 'h1_tag' => Yii::t('app', 'H1 Tag'), | |
| 83 | + 'tag' => Yii::t('app', 'Tags'), | |
| 84 | + ]; | |
| 85 | + } | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * @return \yii\db\ActiveQuery | |
| 89 | + */ | |
| 90 | + public function getCategory() | |
| 91 | + { | |
| 92 | + return $this->hasOne(ArticleCategory::className(), ['article_category_id' => 'article_category_id']); | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * @return \yii\db\ActiveQuery | |
| 97 | + */ | |
| 98 | + public function getLang() | |
| 99 | + { | |
| 100 | + return $this->hasOne(Language::className(), ['language_id' => 'language_id']); | |
| 101 | + } | |
| 102 | +} | ... | ... |
common/modules/blog/models/ArticleCategoryMedia.php
0 → 100644
| 1 | +++ a/common/modules/blog/models/ArticleCategoryMedia.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\modules\blog\models; | |
| 4 | + | |
| 5 | +use common\models\Media; | |
| 6 | +use Yii; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * This is the model class for table "article_category_media". | |
| 10 | + * | |
| 11 | + * @property integer $article_category_media_id | |
| 12 | + * @property integer $article_category_id | |
| 13 | + * @property integer $media_id | |
| 14 | + * @property string $media_alt | |
| 15 | + * @property string $media_title | |
| 16 | + * @property string $media_caption | |
| 17 | + * @property string $type | |
| 18 | + * @property string $language_id | |
| 19 | + * | |
| 20 | + * @property ArticleCategory $category | |
| 21 | + * @property Media $media | |
| 22 | + * @property Language $lang | |
| 23 | + */ | |
| 24 | +class ArticleCategoryMedia extends \yii\db\ActiveRecord | |
| 25 | +{ | |
| 26 | + const SCENARIO_FULL = 'full'; | |
| 27 | + const SCENARIO_PREVIEW = 'preview'; | |
| 28 | + const SCENARIO_ADDITIONAL = 'additional'; | |
| 29 | + public $imageFile; | |
| 30 | + /** | |
| 31 | + * @inheritdoc | |
| 32 | + */ | |
| 33 | + public static function tableName() | |
| 34 | + { | |
| 35 | + return 'article_category_media'; | |
| 36 | + } | |
| 37 | + | |
| 38 | + public function scenarios() | |
| 39 | + { | |
| 40 | + $scenarios = parent::scenarios(); | |
| 41 | + $scenarios[self::SCENARIO_FULL] = ['article_category_media_id', 'article_category_id', 'media_id', 'type', 'media_alt', 'media_title', 'media_caption', 'imageFile']; | |
| 42 | + $scenarios[self::SCENARIO_PREVIEW] = ['article_category_media_id', 'article_category_id', 'media_id', 'type', 'media_alt', 'media_title', 'media_caption', 'imageFile']; | |
| 43 | + $scenarios[self::SCENARIO_ADDITIONAL] = ['article_category_media_id', 'article_category_id', 'media_id', 'type', 'imageFile']; | |
| 44 | + return $scenarios; | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * @inheritdoc | |
| 49 | + */ | |
| 50 | + public function rules() | |
| 51 | + { | |
| 52 | + return [ | |
| 53 | + [['article_category_id', 'media_id'], 'required'], | |
| 54 | + [['article_category_id', 'media_id'], 'integer'], | |
| 55 | + [['media_alt', 'media_title', 'media_caption'], 'string'], | |
| 56 | + [['type'], 'string', 'max' => 10], | |
| 57 | + [['imageFile'], 'file', 'extensions' => 'png, gif, jpg, jpeg', 'skipOnEmpty' => true, 'on' => self::SCENARIO_FULL], | |
| 58 | + [['imageFile'], 'file', 'extensions' => 'png, gif, jpg, jpeg', 'skipOnEmpty' => true, 'on' => self::SCENARIO_PREVIEW], | |
| 59 | + [['imageFile'], 'file', 'extensions' => 'png, gif, jpg, jpeg', 'skipOnEmpty' => true, 'maxFiles' => 10, 'on' => self::SCENARIO_ADDITIONAL] | |
| 60 | + ]; | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * @inheritdoc | |
| 65 | + */ | |
| 66 | + public function attributeLabels() | |
| 67 | + { | |
| 68 | + return [ | |
| 69 | + 'article_category_media_id' => Yii::t('app', 'ID'), | |
| 70 | + 'article_category_id' => Yii::t('app', 'Category ID'), | |
| 71 | + 'media_id' => Yii::t('app', 'Media ID'), | |
| 72 | + 'media_alt' => Yii::t('app', 'Media Alt'), | |
| 73 | + 'media_title' => Yii::t('app', 'Media Title'), | |
| 74 | + 'media_caption' => Yii::t('app', 'Media Caption'), | |
| 75 | + 'type' => Yii::t('app', 'Type'), | |
| 76 | + 'imageFile' => Yii::t('app', 'Image File'), | |
| 77 | + 'language_id' => Yii::t('app', 'Language ID'), | |
| 78 | + ]; | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * @return \yii\db\ActiveQuery | |
| 83 | + */ | |
| 84 | + public function getCategory() | |
| 85 | + { | |
| 86 | + return $this->hasOne(ArticleCategory::className(), ['article_category_id' => 'article_category_id']); | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * @return \yii\db\ActiveQuery | |
| 91 | + */ | |
| 92 | + public function getMedia() | |
| 93 | + { | |
| 94 | + return $this->hasOne(Media::className(), ['media_id' => 'media_id']); | |
| 95 | + } | |
| 96 | + | |
| 97 | + public function upload($category_id) | |
| 98 | + { | |
| 99 | + $this->article_category_id = $category_id; | |
| 100 | + if(is_array($this->imageFile)) { | |
| 101 | + $ok = true; | |
| 102 | + foreach($this->imageFile as $image) { | |
| 103 | + $media_category = clone $this; | |
| 104 | + $media = new Media(); | |
| 105 | + $media->imageFile = $image; | |
| 106 | + $media->upload(); | |
| 107 | + $media_category->media_id = $media->media_id; | |
| 108 | + $ok = $media_category->save() && $ok; | |
| 109 | + unset($media_category); | |
| 110 | + } | |
| 111 | + return $ok; | |
| 112 | + } elseif(!empty($this->imageFile)) { | |
| 113 | + $media = new Media(); | |
| 114 | + $media->imageFile = $this->imageFile; | |
| 115 | + $media->upload(); | |
| 116 | + $this->media_id = $media->media_id; | |
| 117 | + return $this->save(); | |
| 118 | + } | |
| 119 | + } | |
| 120 | + | |
| 121 | + public function replace($category_id, $removeMedia = false) | |
| 122 | + { | |
| 123 | + $this->article_category_id = $category_id; | |
| 124 | + if($removeMedia) { | |
| 125 | + $category_media = ArticleCategoryMedia::find()->select('media_id')->where(['article_category_id' => $this->article_category_id, 'type' => $this->type])->column(); | |
| 126 | + $media = array(); | |
| 127 | + foreach($category_media as $media_id) { | |
| 128 | + $media[] = Media::findOne(['media_id' => $media_id]); | |
| 129 | + } | |
| 130 | + $media = array_unique($media); | |
| 131 | + foreach($media as $one_media) { | |
| 132 | + if($one_media instanceof Media) { | |
| 133 | + $one_media->delete(); | |
| 134 | + } | |
| 135 | + } | |
| 136 | + unset($media); | |
| 137 | + unset($category_media); | |
| 138 | + } | |
| 139 | + if(is_array($this->imageFile)) { | |
| 140 | + $ok = true; | |
| 141 | + foreach($this->imageFile as $image) { | |
| 142 | + $media_category = clone $this; | |
| 143 | + $media = new Media(); | |
| 144 | + $media->imageFile = $image; | |
| 145 | + $media->upload(); | |
| 146 | + $media_category->media_id = $media->media_id; | |
| 147 | + $ok = $media_category->save() && $ok; | |
| 148 | + unset($media_category); | |
| 149 | + } | |
| 150 | + return $ok; | |
| 151 | + } elseif(!empty($this->imageFile)) { | |
| 152 | + ArticleCategoryMedia::deleteAll(['category_id' => $this->article_category_id, 'type' => $this->type]); | |
| 153 | + $media = new Media(); | |
| 154 | + $media->imageFile = $this->imageFile; | |
| 155 | + $media->upload(); | |
| 156 | + $this->media_id = $media->media_id; | |
| 157 | + $this->setIsNewRecord(true); | |
| 158 | + return $this->save(); | |
| 159 | + } | |
| 160 | + } | |
| 161 | + | |
| 162 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/models/ArticleLang.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\modules\blog\models; | |
| 4 | + | |
| 5 | +use Yii; | |
| 6 | +use common\models\Language; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * This is the model class for table "article_lang". | |
| 10 | + * | |
| 11 | + * @property integer $article_language_id | |
| 12 | + * @property integer $language_id | |
| 13 | + * @property integer $article_id | |
| 14 | + * @property string $text | |
| 15 | + * @property string $seo_url | |
| 16 | + * @property string $name | |
| 17 | + * @property string $preview | |
| 18 | + * @property string $meta_title | |
| 19 | + * @property string $meta_descr | |
| 20 | + * @property string $meta_keyword | |
| 21 | + * @property string $h1_tag | |
| 22 | + * @property string $tag | |
| 23 | + * | |
| 24 | + * @property Article $article | |
| 25 | + * @property Language $lang | |
| 26 | + */ | |
| 27 | +class ArticleLang extends \yii\db\ActiveRecord | |
| 28 | +{ | |
| 29 | + /** | |
| 30 | + * @inheritdoc | |
| 31 | + */ | |
| 32 | + public static function tableName() | |
| 33 | + { | |
| 34 | + return 'article_lang'; | |
| 35 | + } | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * @inheritdoc | |
| 39 | + */ | |
| 40 | + public function rules() | |
| 41 | + { | |
| 42 | + return [ | |
| 43 | + [['language_id', 'text', 'name'], 'required'], | |
| 44 | + [['language_id', 'article_id'], 'integer'], | |
| 45 | + [['text', 'seo_url', 'name', 'preview', 'meta_title', 'meta_descr', 'meta_keyword', 'h1_tag', 'tag'], 'string'] | |
| 46 | + ]; | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * @inheritdoc | |
| 51 | + */ | |
| 52 | + public function attributeLabels() | |
| 53 | + { | |
| 54 | + return [ | |
| 55 | + 'article_language_id' => Yii::t('app', 'ID'), | |
| 56 | + 'language_id' => Yii::t('app', 'Lang ID'), | |
| 57 | + 'article_id' => Yii::t('app', 'Article ID'), | |
| 58 | + 'text' => Yii::t('app', 'Text'), | |
| 59 | + 'seo_url' => Yii::t('app', 'Seo Url'), | |
| 60 | + 'name' => Yii::t('app', 'Name'), | |
| 61 | + 'preview' => Yii::t('app', 'Preview'), | |
| 62 | + 'meta_title' => Yii::t('app', 'Meta Title'), | |
| 63 | + 'meta_descr' => Yii::t('app', 'Meta Descr'), | |
| 64 | + 'meta_keyword' => Yii::t('app', 'Meta Keywords'), | |
| 65 | + 'h1_tag' => Yii::t('app', 'H1 Tag'), | |
| 66 | + 'tag' => Yii::t('app', 'Tags'), | |
| 67 | + ]; | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * @return \yii\db\ActiveQuery | |
| 72 | + */ | |
| 73 | + public function getArticle() | |
| 74 | + { | |
| 75 | + return $this->hasOne(Article::className(), ['article_id' => 'article_id']); | |
| 76 | + } | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * @return \yii\db\ActiveQuery | |
| 80 | + */ | |
| 81 | + public function getLang() | |
| 82 | + { | |
| 83 | + return $this->hasOne(Language::className(), ['language_id' => 'language_id']); | |
| 84 | + } | |
| 85 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/models/ArticleMedia.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\modules\blog\models; | |
| 4 | + | |
| 5 | +use common\models\Media; | |
| 6 | +use Yii; | |
| 7 | +use yii\web\UploadedFile; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * This is the model class for table "article_media". | |
| 11 | + * | |
| 12 | + * @property integer $article_media_id | |
| 13 | + * @property integer $article_id | |
| 14 | + * @property integer $media_id | |
| 15 | + * @property string $type | |
| 16 | + * @property string $media_alt | |
| 17 | + * @property string $media_title | |
| 18 | + * @property string $media_caption | |
| 19 | + * @property integer $language_id | |
| 20 | + * | |
| 21 | + * @property Article $article | |
| 22 | + * @property Media $media | |
| 23 | + */ | |
| 24 | +class ArticleMedia extends \yii\db\ActiveRecord | |
| 25 | +{ | |
| 26 | + const SCENARIO_FULL = 'full'; | |
| 27 | + const SCENARIO_PREVIEW = 'preview'; | |
| 28 | + const SCENARIO_ADDITIONAL = 'additional'; | |
| 29 | + public $imageFile; | |
| 30 | + /** | |
| 31 | + * @inheritdoc | |
| 32 | + */ | |
| 33 | + public static function tableName() | |
| 34 | + { | |
| 35 | + return 'article_media'; | |
| 36 | + } | |
| 37 | + | |
| 38 | + public function scenarios() | |
| 39 | + { | |
| 40 | + $scenarios = parent::scenarios(); | |
| 41 | + $scenarios[self::SCENARIO_FULL] = ['article_media_id', 'article_id', 'media_id', 'type', 'media_alt', 'media_title', 'media_caption', 'imageFile', 'language_id']; | |
| 42 | + $scenarios[self::SCENARIO_PREVIEW] = ['article_media_id', 'article_id', 'media_id', 'type', 'media_alt', 'media_title', 'media_caption', 'imageFile', 'language_id']; | |
| 43 | + $scenarios[self::SCENARIO_ADDITIONAL] = ['article_media_id', 'article_id', 'media_id', 'type', 'imageFile', 'language_id']; | |
| 44 | + return $scenarios; | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * @inheritdoc | |
| 49 | + */ | |
| 50 | + public function rules() | |
| 51 | + { | |
| 52 | + return [ | |
| 53 | + [['article_id', 'media_id'], 'required'], | |
| 54 | + [['article_id', 'media_id', 'language_id'], 'integer'], | |
| 55 | + [['media_alt', 'media_title', 'media_caption'], 'string'], | |
| 56 | + [['type'], 'string', 'max' => 10], | |
| 57 | + [['imageFile'], 'file', 'extensions' => 'png, gif, jpg, jpeg', 'skipOnEmpty' => true, 'on' => self::SCENARIO_FULL], | |
| 58 | + [['imageFile'], 'file', 'extensions' => 'png, gif, jpg, jpeg', 'skipOnEmpty' => true, 'on' => self::SCENARIO_PREVIEW], | |
| 59 | + [['imageFile'], 'file', 'extensions' => 'png, gif, jpg, jpeg', 'skipOnEmpty' => true, 'maxFiles' => 10, 'on' => self::SCENARIO_ADDITIONAL] | |
| 60 | + ]; | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * @inheritdoc | |
| 65 | + */ | |
| 66 | + public function attributeLabels() | |
| 67 | + { | |
| 68 | + return [ | |
| 69 | + 'article_media_id' => Yii::t('app', 'ID'), | |
| 70 | + 'article_id' => Yii::t('app', 'Article ID'), | |
| 71 | + 'media_id' => Yii::t('app', 'Media ID'), | |
| 72 | + 'type' => Yii::t('app', 'Type'), | |
| 73 | + 'media_alt' => Yii::t('app', 'Media Alt'), | |
| 74 | + 'media_title' => Yii::t('app', 'Media Title'), | |
| 75 | + 'media_caption' => Yii::t('app', 'Media Caption'), | |
| 76 | + 'imageFile' => Yii::t('app', 'Image File'), | |
| 77 | + ]; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * @return \yii\db\ActiveQuery | |
| 82 | + */ | |
| 83 | + public function getArticle() | |
| 84 | + { | |
| 85 | + return $this->hasOne(Article::className(), ['article_id' => 'article_id']); | |
| 86 | + } | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * @return \yii\db\ActiveQuery | |
| 90 | + */ | |
| 91 | + public function getMedia() | |
| 92 | + { | |
| 93 | + return $this->hasOne(Media::className(), ['media_id' => 'media_id']); | |
| 94 | + } | |
| 95 | + | |
| 96 | + public function upload($article_id) | |
| 97 | + { | |
| 98 | + $this->article_id = $article_id; | |
| 99 | + if(is_array($this->imageFile)) { | |
| 100 | + $ok = true; | |
| 101 | + foreach($this->imageFile as $image) { | |
| 102 | + $media_article = clone $this; | |
| 103 | + $media = new Media(); | |
| 104 | + $media->imageFile = $image; | |
| 105 | + $media->upload(); | |
| 106 | + $media_article->media_id = $media->media_id; | |
| 107 | + $ok = $media_article->save() && $ok; | |
| 108 | + unset($media_article); | |
| 109 | + } | |
| 110 | + return $ok; | |
| 111 | + } elseif(!empty($this->imageFile)) { | |
| 112 | + $media = new Media(); | |
| 113 | + $media->imageFile = $this->imageFile; | |
| 114 | + $media->upload(); | |
| 115 | + $this->media_id = $media->media_id; | |
| 116 | + return $this->save(); | |
| 117 | + } | |
| 118 | + } | |
| 119 | + | |
| 120 | + public function replace($article_id, $removeMedia = false) | |
| 121 | + { | |
| 122 | + $this->article_id = $article_id; | |
| 123 | + if($removeMedia && !$this->getIsNewRecord()) { | |
| 124 | + $article_media = ArticleMedia::find()->select('media_id')->where(['article_id' => $this->article_id, 'type' => $this->type, 'language_id' => $this->language_id])->column(); | |
| 125 | + $media = array(); | |
| 126 | + foreach($article_media as $media_id) { | |
| 127 | + $media[] = Media::findOne(['media_id' => $media_id]); | |
| 128 | + } | |
| 129 | + $media = array_unique($media); | |
| 130 | + foreach($media as $one_media) { | |
| 131 | + if($one_media instanceof Media) { | |
| 132 | + $one_media->delete(); | |
| 133 | + } | |
| 134 | + } | |
| 135 | + unset($media); | |
| 136 | + unset($article_media); | |
| 137 | + } | |
| 138 | + if(is_array($this->imageFile)) { | |
| 139 | + $ok = true; | |
| 140 | + foreach($this->imageFile as $image) { | |
| 141 | + $media_article = clone $this; | |
| 142 | + $media = new Media(); | |
| 143 | + $media->imageFile = $image; | |
| 144 | + $media->upload(); | |
| 145 | + $media_article->media_id = $media->media_id; | |
| 146 | + $ok = $media_article->save() && $ok; | |
| 147 | + unset($media_article); | |
| 148 | + } | |
| 149 | + return $ok; | |
| 150 | + } elseif(!empty($this->imageFile)) { | |
| 151 | + ArticleMedia::deleteAll(['article_id' => $this->article_id, 'type' => $this->type, 'language_id' => $this->language_id]); | |
| 152 | + $media = new Media(); | |
| 153 | + $media->imageFile = $this->imageFile; | |
| 154 | + $media->upload(); | |
| 155 | + $this->media_id = $media->media_id; | |
| 156 | + $this->setIsNewRecord(true); | |
| 157 | + return $this->save(); | |
| 158 | + } | |
| 159 | + } | |
| 160 | + | |
| 161 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/models/ArticleToCategory.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +namespace common\modules\blog\models; | |
| 4 | + | |
| 5 | +use Yii; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * This is the model class for table "article_to_category". | |
| 9 | + * | |
| 10 | + * @property integer $article_id | |
| 11 | + * @property integer $article_category_id | |
| 12 | + * | |
| 13 | + * @property Article $article | |
| 14 | + * @property ArticleCategory $category | |
| 15 | + */ | |
| 16 | +class ArticleToCategory extends \yii\db\ActiveRecord | |
| 17 | +{ | |
| 18 | + /** | |
| 19 | + * @inheritdoc | |
| 20 | + */ | |
| 21 | + public static function tableName() | |
| 22 | + { | |
| 23 | + return 'article_to_category'; | |
| 24 | + } | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * @inheritdoc | |
| 28 | + */ | |
| 29 | + public function rules() | |
| 30 | + { | |
| 31 | + return [ | |
| 32 | + [['article_id', 'article_category_id'], 'integer'] | |
| 33 | + ]; | |
| 34 | + } | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * @inheritdoc | |
| 38 | + */ | |
| 39 | + public function attributeLabels() | |
| 40 | + { | |
| 41 | + return [ | |
| 42 | + 'article_id' => Yii::t('app', 'Article ID'), | |
| 43 | + 'article_category_id' => Yii::t('app', 'Category ID'), | |
| 44 | + ]; | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * @return \yii\db\ActiveQuery | |
| 49 | + */ | |
| 50 | + public function getArticle() | |
| 51 | + { | |
| 52 | + return $this->hasOne(Article::className(), ['article_id' => 'article_id']); | |
| 53 | + } | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * @return \yii\db\ActiveQuery | |
| 57 | + */ | |
| 58 | + public function getCategory() | |
| 59 | + { | |
| 60 | + return $this->hasOne(ArticleCategory::className(), ['article_category_id' => 'article_category_id']); | |
| 61 | + } | |
| 62 | +} | ... | ... |
| 1 | +++ a/common/modules/blog/views/ajax/_article_form.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\bootstrap\ActiveField; | |
| 4 | +use mihaildev\ckeditor\CKEditor; | |
| 5 | + | |
| 6 | +if(empty($form)) { | |
| 7 | + $new_form = true; | |
| 8 | + $form = \yii\bootstrap\ActiveForm::begin(); | |
| 9 | +} | |
| 10 | +?> | |
| 11 | +<div role="" class="tab-pane active ajax-loaded" id="<?=$widget_id?>-<?=$model->language_id?>"> | |
| 12 | + | |
| 13 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]language_id"]))->label(false)->hiddenInput(['value' => $model->language_id]) ?> | |
| 14 | + | |
| 15 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]text", 'form' => $form]))->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ]]); ?> | |
| 16 | + | |
| 17 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]preview", 'form' => $form]))->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ]]); ?> | |
| 18 | + | |
| 19 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]seo_url"]))->textInput() ?> | |
| 20 | + | |
| 21 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]name"]))->textInput() ?> | |
| 22 | + | |
| 23 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]meta_title"]))->textInput() ?> | |
| 24 | + | |
| 25 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]meta_descr"]))->textarea() ?> | |
| 26 | + | |
| 27 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]meta_keyword"]))->textInput() ?> | |
| 28 | + | |
| 29 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]h1_tag"]))->textInput() ?> | |
| 30 | + | |
| 31 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]tag"]))->textInput() ?> | |
| 32 | + | |
| 33 | +</div> | |
| 34 | +<?php | |
| 35 | + if($new_form) { | |
| 36 | + $form->end(); | |
| 37 | + } | |
| 38 | +?> | ... | ... |
common/modules/blog/views/ajax/_article_form_test.php
0 → 100644
| 1 | +++ a/common/modules/blog/views/ajax/_article_form_test.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\bootstrap\ActiveField; | |
| 4 | +use mihaildev\ckeditor\CKEditor; | |
| 5 | + //Если это не AJAX запрос, то переменная $form будет определена и нам не придется генерировать форму. | |
| 6 | +if(empty($form)) { | |
| 7 | + $new_form = true; | |
| 8 | + $form = \yii\bootstrap\ActiveForm::begin(); | |
| 9 | +} | |
| 10 | +?> | |
| 11 | +<div role="" class="tab-pane active ajax-loaded" id="<?=$widget_id?>-<?=$model->language_id?>"> | |
| 12 | + | |
| 13 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]language_id"]))->label(false)->hiddenInput(['value' => $model->language_id]) ?> | |
| 14 | + | |
| 15 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]text", 'form' => $form]))->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ]]); ?> | |
| 16 | + | |
| 17 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]preview", 'form' => $form]))->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ]]); ?> | |
| 18 | + | |
| 19 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]seo_url"]))->textInput() ?> | |
| 20 | + | |
| 21 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]name"]))->textInput() ?> | |
| 22 | + | |
| 23 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]meta_title"]))->textInput() ?> | |
| 24 | + | |
| 25 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]meta_descr"]))->textarea() ?> | |
| 26 | + | |
| 27 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]meta_keyword"]))->textInput() ?> | |
| 28 | + | |
| 29 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]h1_tag"]))->textInput() ?> | |
| 30 | + | |
| 31 | + <?= (new ActiveField(['model' => $model, 'attribute' => "[$model->language_id]tag"]))->textInput() ?> | |
| 32 | + | |
| 33 | +</div> | |
| 34 | +<?php | |
| 35 | + if($new_form) { | |
| 36 | + $form->end(); | |
| 37 | + } | |
| 38 | +?> | ... | ... |
common/modules/blog/views/ajax/_article_media_form.php
0 → 100644
| 1 | +++ a/common/modules/blog/views/ajax/_article_media_form.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\bootstrap\ActiveField; | |
| 4 | +use mihaildev\ckeditor\CKEditor; | |
| 5 | + | |
| 6 | +$form = \yii\bootstrap\ActiveForm::begin(); | |
| 7 | +?> | |
| 8 | +<div role="" class="tab-pane active ajax-loaded" id="<?=$widget_id?>-<?=$model->language_id?>"> | |
| 9 | + | |
| 10 | + <?= (new ActiveField(['model' => $article_lang, 'attribute' => "[$model->language_id][$type]language_id"]))->label(false)->hiddenInput(['value' => $model->language_id]) ?> | |
| 11 | + | |
| 12 | + <?= (new ActiveField(['model' => $article_lang, 'attribute' => "[$model->language_id][$type]imageFile"]))->fileInput(['class' => 'image_inputs_field']) ?> | |
| 13 | + | |
| 14 | +</div> | |
| 15 | +<?php | |
| 16 | +$form->end(); | |
| 17 | +?> | ... | ... |
| 1 | +++ a/common/modules/blog/views/ajax/_category_form.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\bootstrap\ActiveField; | |
| 4 | +use mihaildev\ckeditor\CKEditor; | |
| 5 | + | |
| 6 | +$form = \yii\bootstrap\ActiveForm::begin(); | |
| 7 | +?> | |
| 8 | +<div role="" class="tab-pane active ajax-loaded" id="<?=$widget_id?>-<?=$model->language_id?>"> | |
| 9 | + | |
| 10 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]language_id"]))->label(false)->hiddenInput(['value' => $model->language_id]) ?> | |
| 11 | + | |
| 12 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]text", 'form' => $form]))->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ]]); ?> | |
| 13 | + | |
| 14 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]preview", 'form' => $form]))->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ]]); ?> | |
| 15 | + | |
| 16 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]seo_url"]))->textInput() ?> | |
| 17 | + | |
| 18 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]name"]))->textInput() ?> | |
| 19 | + | |
| 20 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]meta_title"]))->textInput() ?> | |
| 21 | + | |
| 22 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]meta_descr"]))->textarea() ?> | |
| 23 | + | |
| 24 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]meta_keyword"]))->textInput() ?> | |
| 25 | + | |
| 26 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]h1_tag"]))->textInput() ?> | |
| 27 | + | |
| 28 | + <?= (new ActiveField(['model' => $category_lang, 'attribute' => "[$model->language_id]tag"]))->textInput() ?> | |
| 29 | + | |
| 30 | +</div> | |
| 31 | +<?php | |
| 32 | +$form->end(); | |
| 33 | +?> | ... | ... |
| 1 | +++ a/common/modules/blog/views/article/_form.php | |
| 1 | +<?php | |
| 2 | +use common\modules\blog\models\ArticleCategory; | |
| 3 | +use common\modules\blog\models\ArticleMedia; | |
| 4 | +use common\widgets\Multilang; | |
| 5 | + use common\widgets\Multilanguage; | |
| 6 | + use yii\bootstrap\ActiveForm; | |
| 7 | +use common\modules\blog\models\Article; | |
| 8 | +use yii\bootstrap\Html; | |
| 9 | +use mihaildev\ckeditor\CKEditor; | |
| 10 | +use yii\helpers\Json; | |
| 11 | +use yii\helpers\Url; | |
| 12 | +use yii\widgets\Pjax; | |
| 13 | + | |
| 14 | +$def_lang = array_keys($langs)[0]; | |
| 15 | +$uploaddir = \Yii::getAlias('@saveImageDir'); | |
| 16 | +?> | |
| 17 | +<div class="article-form"> | |
| 18 | + | |
| 19 | + <?php $form = \yii\bootstrap\ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?> | |
| 20 | + | |
| 21 | + <?= $form->field($article, 'code')->hint(Yii::t('app', 'Insensitive latin non-space'))->textInput() ?> | |
| 22 | + | |
| 23 | + <?= $form->field($article, 'tag')->hint(Yii::t('app', 'Comma-separated'))->textInput() ?> | |
| 24 | + | |
| 25 | + <?= $form->field($article, 'sort')->input('number') ?> | |
| 26 | + | |
| 27 | + <?= $form->field($article, 'article_pid') | |
| 28 | + ->dropDownList(Article::findArticleDropdown($article->article_id), ['prompt' => Yii::t('app', 'Select parent')]) ?> | |
| 29 | + | |
| 30 | + <?= $form->field($article, 'articleCategoriesArray') | |
| 31 | + ->dropDownList(ArticleCategory::findArticleCategoryDropdown(NULL), ['multiple' => 'multiple'])->label(\Yii::t('app', 'Article Categories Array')); ?> | |
| 32 | + | |
| 33 | + <?= $form->field($article, 'status')->checkbox() ?> | |
| 34 | + | |
| 35 | + <ul class="nav nav-tabs" id="image-tabs" role="tablist"> | |
| 36 | + <li role="image_inputs" class="active" data-type="full"><a href="#image-full" aria-controls="image-full" role="tab" data-toggle="tab"><span><?= \Yii::t('app', 'full')?></span></a></li> | |
| 37 | + <li role="image_inputs" class="" data-type="preview"><a href="#image-preview" aria-controls="image-preview" role="tab" data-toggle="tab"><span><?= \Yii::t('app', 'preview')?></span></a></li> | |
| 38 | + <li role="image_inputs" class="" data-type="additional"><a href="#image-additional" aria-controls="image-additional" role="tab" data-toggle="tab"><span><?= \Yii::t('app', 'additional')?></span></a></li> | |
| 39 | + </ul> | |
| 40 | + <div class="tab-content image-tab-content"> | |
| 41 | + <div role="" class="tab-pane active main-tab" id="image-full"> | |
| 42 | + <?php | |
| 43 | + $imagelang = Multilang::begin([ | |
| 44 | + 'ajaxpath' => Url::to(['/blog/ajax/article-media-form?type=full']), | |
| 45 | + 'form' => $form, | |
| 46 | + 'data_langs' => $article->getIsNewRecord()?$images:ArticleMedia::find()->where(['article_id' => $article->article_id, 'type' => 'full'])->indexBy('language_id')->all() | |
| 47 | + ]); | |
| 48 | + $first = 1; | |
| 49 | + foreach($images as $lang => $value) { | |
| 50 | + if(!array_key_exists('full', $value)) continue; | |
| 51 | + ?> | |
| 52 | + <div role="" class="tab-pane <?php if($first) { echo 'active main-tab'; } ?>" id="<?=$imagelang->id?>-<?=$lang?>"> | |
| 53 | + <?php | |
| 54 | + echo $form->field($images[$lang]['full'], "[{$lang}][full]language_id")->label(false)->hiddenInput(['value' => $lang]); | |
| 55 | + echo $form->field($images[$lang]['full'], "[{$lang}][full]imageFile")->fileInput(['class' => 'image_inputs_field']); | |
| 56 | + if(!empty($images[$lang]['full']->article_media_id)) { | |
| 57 | + echo "<img src='/images/upload/{$images[$lang]['full']->media->hash}/original.{$images[$lang]['full']->media->extension}' width='100' class='image_inputs_prev'>"; | |
| 58 | + } | |
| 59 | + ?> | |
| 60 | + </div> | |
| 61 | + <?php | |
| 62 | + $first = 0; | |
| 63 | + } | |
| 64 | + $imagelang->end(); | |
| 65 | + ?> | |
| 66 | + </div> | |
| 67 | + <div role="" class="tab-pane" id="image-preview"> | |
| 68 | + <?php | |
| 69 | + $imagelang = Multilang::begin([ | |
| 70 | + 'ajaxpath' => Url::to(['/blog/ajax/article-media-form?type=preview']), | |
| 71 | + 'form' => $form, | |
| 72 | + 'data_langs' => $article->getIsNewRecord()?$images:ArticleMedia::find()->where(['article_id' => $article->article_id, 'type' => 'preview'])->indexBy('language_id')->all() | |
| 73 | + ]); | |
| 74 | + $first = 1; | |
| 75 | + foreach($images as $lang => $value) { | |
| 76 | + if(!array_key_exists('preview', $value)) continue; | |
| 77 | + ?> | |
| 78 | + <div role="" class="tab-pane <?php if($first) { echo 'active main-tab'; } ?>" id="<?=$imagelang->id?>-<?=$lang?>"> | |
| 79 | + <?php | |
| 80 | + echo $form->field($images[$lang]['preview'], "[{$lang}][preview]language_id")->label(false)->hiddenInput(['value' => $lang]); | |
| 81 | + echo $form->field($images[$lang]['preview'], "[{$lang}][preview]imageFile")->fileInput(['class' => 'image_inputs_field']); | |
| 82 | + if(!empty($images[$lang]['preview']->article_media_id)) { | |
| 83 | + echo "<img src='/images/upload/{$images[$lang]['preview']->media->hash}/original.{$images[$lang]['preview']->media->extension}' width='100' class='image_inputs_prev'>"; | |
| 84 | + } | |
| 85 | + ?> | |
| 86 | + </div> | |
| 87 | + <?php | |
| 88 | + $first = 0; | |
| 89 | + } | |
| 90 | + $imagelang->end(); | |
| 91 | + ?> | |
| 92 | + </div> | |
| 93 | + <div role="" class="tab-pane" id="image-additional"> | |
| 94 | + <?php | |
| 95 | + echo $form->field(is_array($images[0]['additional'])?$images[0]['additional'][0]:$images[0]['additional'], "[0][additional]imageFile[]")->fileInput(['multiple' => 'multiple', 'class' => 'image_inputs_field']); | |
| 96 | + if(is_array($images[0]['additional']) && count($images[0]['additional']) > 1) { | |
| 97 | + foreach($images[0]['additional'] as $onefield => $oneimage) { | |
| 98 | + if($onefield) { | |
| 99 | + ?> | |
| 100 | + <div class="additional_image_container"> | |
| 101 | + <img src='/images/upload/<?= $oneimage->media->hash ?>/original.<?= $oneimage->media->extension ?>' width='100'> | |
| 102 | + <a | |
| 103 | + href="<?= Url::to(['ajax/remove-image']) ?>" | |
| 104 | + class="remove_image glyphicon glyphicon-remove-circle" | |
| 105 | + data-params='<?= Json::encode(['article_media_id' => $oneimage->article_media_id, 'remove_media' => true]) ?>', | |
| 106 | + ></a> | |
| 107 | + </div> | |
| 108 | + <?php | |
| 109 | + } | |
| 110 | + } | |
| 111 | + } | |
| 112 | + ?> | |
| 113 | + </div> | |
| 114 | + </div> | |
| 115 | + | |
| 116 | + <hr> | |
| 117 | + | |
| 118 | + <?php | |
| 119 | + echo Multilanguage::widget([ | |
| 120 | + 'data' => $article_langs, | |
| 121 | + 'form' => $form, | |
| 122 | + 'ajaxView' => '@common/modules/blog/views/ajax/_article_form', | |
| 123 | + ]); | |
| 124 | + /* | |
| 125 | + $multilang = Multilang::begin(['ajaxpath' => Url::to(['/blog/ajax/article-form']), 'form' => $form, 'data_langs' => $article_langs]); | |
| 126 | + ?> | |
| 127 | + <?php | |
| 128 | + $first = 1; | |
| 129 | + foreach($article_langs as $index => $article_lang) { | |
| 130 | + ?> | |
| 131 | + <div role="" class="tab-pane <?php if($first) { echo 'active main-tab'; } ?>" id="<?=$multilang->id?>-<?=$index?>"> | |
| 132 | + | |
| 133 | + <?= $form->field($article_langs[$index], "[$index]language_id")->label(false)->hiddenInput(['value' => $index]) ?> | |
| 134 | + | |
| 135 | + <?= $form->field($article_langs[$index], "[$index]text")->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?> | |
| 136 | + | |
| 137 | + <?= $form->field($article_langs[$index], "[$index]preview")->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?> | |
| 138 | + | |
| 139 | + <?= $form->field($article_langs[$index], "[$index]seo_url")->textInput() ?> | |
| 140 | + | |
| 141 | + <?= $form->field($article_langs[$index], "[$index]name")->textInput() ?> | |
| 142 | + | |
| 143 | + <?= $form->field($article_langs[$index], "[$index]meta_title")->textInput() ?> | |
| 144 | + | |
| 145 | + <?= $form->field($article_langs[$index], "[$index]meta_descr")->textarea(); ?> | |
| 146 | + | |
| 147 | + <?= $form->field($article_langs[$index], "[$index]meta_keywords")->textInput() ?> | |
| 148 | + | |
| 149 | + <?= $form->field($article_langs[$index], "[$index]h1_tag")->textInput() ?> | |
| 150 | + | |
| 151 | + <?= $form->field($article_langs[$index], "[$index]tags")->textInput() ?> | |
| 152 | + | |
| 153 | + </div> | |
| 154 | + <?php | |
| 155 | + $first = 0; | |
| 156 | + } | |
| 157 | + ?> | |
| 158 | + <?php | |
| 159 | + $multilang->end(); | |
| 160 | + */ | |
| 161 | + ?> | |
| 162 | + | |
| 163 | + <div class="form-group"> | |
| 164 | + <?= Html::submitButton($article->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $article->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> | |
| 165 | + </div> | |
| 166 | + | |
| 167 | + <?php ActiveForm::end(); ?> | |
| 168 | + | |
| 169 | +</div> | |
| 170 | +<script> | |
| 171 | + var confirm_message = '<?= \Yii::t('app', 'Remove image?') ?>'; | |
| 172 | +</script> | |
| 0 | 173 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/blog/views/article/create.php | |
| 1 | +<?php | |
| 2 | +use yii\helpers\Html; | |
| 3 | + | |
| 4 | +$this->title = Yii::t('app', 'Article create'); | |
| 5 | +$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Articles'), 'url' => ['index']]; | |
| 6 | +$this->params['breadcrumbs'][] = $this->title; | |
| 7 | +?> | |
| 8 | +<div class="article-create"> | |
| 9 | + | |
| 10 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 11 | + | |
| 12 | + <?= $this->render('_form', [ | |
| 13 | + 'article_langs' => $article_langs, | |
| 14 | + 'article' => $article, | |
| 15 | + 'langs' => $langs, | |
| 16 | + 'images' => $images | |
| 17 | + ]) ?> | |
| 18 | + | |
| 19 | +</div> | ... | ... |
| 1 | +++ a/common/modules/blog/views/article/index.php | |
| 1 | +<?php | |
| 2 | +use yii\grid\ActionColumn; | |
| 3 | +use yii\grid\Column; | |
| 4 | +use yii\grid\GridView; | |
| 5 | +use common\modules\blog\models\Article; | |
| 6 | +use common\models\Language; | |
| 7 | + | |
| 8 | +echo GridView::widget([ | |
| 9 | + 'dataProvider' => $dataProvider, | |
| 10 | + 'columns' => [ | |
| 11 | + 'article_id', | |
| 12 | + 'code', | |
| 13 | + 'date_add', | |
| 14 | + [ | |
| 15 | + 'value' => function($data) { | |
| 16 | + return $data->user->firstname.' '.$data->user->lastname; | |
| 17 | + }, | |
| 18 | + 'header' => Yii::t('app', 'Author') | |
| 19 | + ], | |
| 20 | + [ | |
| 21 | + 'class' => Column::className(), | |
| 22 | + 'header' => Yii::t('app', 'Name'), | |
| 23 | + 'content' => function($model, $key, $index, $column) { | |
| 24 | + return $model->getArticleLangs()->where(['language_id' => Language::getDefaultLang()->language_id])->one()->name; | |
| 25 | + } | |
| 26 | + ], | |
| 27 | + [ | |
| 28 | + 'class' => ActionColumn::className(), | |
| 29 | + 'template' => '{update} {delete}' | |
| 30 | + ] | |
| 31 | + ] | |
| 32 | +]); | |
| 0 | 33 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/blog/views/article/update.php | |
| 1 | +<?php | |
| 2 | +use yii\helpers\Html; | |
| 3 | + | |
| 4 | +$this->title = Yii::t('app', 'Article update'); | |
| 5 | +$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Articles'), 'url' => ['index']]; | |
| 6 | +$this->params['breadcrumbs'][] = $this->title; | |
| 7 | +?> | |
| 8 | +<div class="article-create"> | |
| 9 | + | |
| 10 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 11 | + <?= $this->render('_form', [ | |
| 12 | + 'article_langs' => $article_langs, | |
| 13 | + 'article' => $article, | |
| 14 | + 'langs' => $langs, | |
| 15 | + 'images' => $images | |
| 16 | + ]) ?> | |
| 17 | + | |
| 18 | +</div> | ... | ... |
| 1 | +++ a/common/modules/blog/views/category/_form.php | |
| 1 | +<?php | |
| 2 | +use common\modules\blog\models\ArticleCategoryMedia; | |
| 3 | +use common\widgets\Multilang; | |
| 4 | +use yii\bootstrap\ActiveForm; | |
| 5 | +use common\modules\blog\models\ArticleCategory; | |
| 6 | +use yii\bootstrap\Html; | |
| 7 | +use mihaildev\ckeditor\CKEditor; | |
| 8 | +use yii\helpers\Json; | |
| 9 | +use yii\helpers\Url; | |
| 10 | + | |
| 11 | +$def_lang = array_keys($langs)[0]; | |
| 12 | +$uploaddir = \Yii::getAlias('@saveImageDir'); | |
| 13 | +?> | |
| 14 | +<div class="category-form"> | |
| 15 | + | |
| 16 | + <?php $form = \yii\bootstrap\ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?> | |
| 17 | + | |
| 18 | + <?= $form->field($category, 'code')->hint(Yii::t('app', 'Insensitive latin non-space'))->textInput() ?> | |
| 19 | + | |
| 20 | + <?= $form->field($category, 'tag')->hint(Yii::t('app', 'Comma-separated'))->textInput() ?> | |
| 21 | + | |
| 22 | + <?= $form->field($category, 'sort')->input('number') ?> | |
| 23 | + | |
| 24 | + <?= $form->field($category, 'article_category_pid') | |
| 25 | + ->dropDownList(ArticleCategory::findArticleCategoryDropdown($category->article_category_id), ['prompt' => Yii::t('app', 'Select parent')]) ?> | |
| 26 | + | |
| 27 | + <?= $form->field($category, 'status')->checkbox() ?> | |
| 28 | + | |
| 29 | + <ul class="nav nav-tabs" id="image-tabs" role="tablist"> | |
| 30 | + <li role="image_inputs" class="active" data-type="full"><a href="#image-full" aria-controls="image-full" role="tab" data-toggle="tab"><span><?= \Yii::t('app', 'full')?></span></a></li> | |
| 31 | + <li role="image_inputs" class="" data-type="preview"><a href="#image-preview" aria-controls="image-preview" role="tab" data-toggle="tab"><span><?= \Yii::t('app', 'preview')?></span></a></li> | |
| 32 | + <li role="image_inputs" class="" data-type="additional"><a href="#image-additional" aria-controls="image-additional" role="tab" data-toggle="tab"><span><?= \Yii::t('app', 'additional')?></span></a></li> | |
| 33 | + </ul> | |
| 34 | + <div class="tab-content image-tab-content"> | |
| 35 | + <div role="" class="tab-pane active main-tab" id="image-full"> | |
| 36 | + <?php | |
| 37 | + $imagelang = Multilang::begin([ | |
| 38 | + 'ajaxpath' => Url::to(['/blog/ajax/article-category-media-form?type=full']), | |
| 39 | + 'form' => $form, | |
| 40 | + 'data_langs' => $category->getIsNewRecord()?$images:ArticleCategoryMedia::find()->where(['article_category_id' => $category->article_category_id, 'type' => 'full'])->indexBy('language_id')->all() | |
| 41 | + ]); | |
| 42 | + $first = 1; | |
| 43 | + foreach($images as $lang => $value) { | |
| 44 | + if(!array_key_exists('full', $value)) continue; | |
| 45 | + ?> | |
| 46 | + <div role="" class="tab-pane <?php if($first) { echo 'active main-tab'; } ?>" id="<?=$imagelang->id?>-<?=$lang?>"> | |
| 47 | + <?php | |
| 48 | + echo $form->field($images[$lang]['full'], "[{$lang}][full]language_id")->label(false)->hiddenInput(['value' => $lang]); | |
| 49 | + echo $form->field($images[$lang]['full'], "[{$lang}][full]imageFile")->fileInput(['class' => 'image_inputs_field']); | |
| 50 | + if(!empty($images[$lang]['full']->article_category_media_id)) { | |
| 51 | + echo "<img src='/images/upload/{$images[$lang]['full']->media->hash}/original.{$images[$lang]['full']->media->extension}' width='100' class='image_inputs_prev'>"; | |
| 52 | + } | |
| 53 | + ?> | |
| 54 | + </div> | |
| 55 | + <?php | |
| 56 | + $first = 0; | |
| 57 | + } | |
| 58 | + $imagelang->end(); | |
| 59 | + ?> | |
| 60 | + </div> | |
| 61 | + <div role="" class="tab-pane" id="image-preview"> | |
| 62 | + <?php | |
| 63 | + $imagelang = Multilang::begin([ | |
| 64 | + 'ajaxpath' => Url::to(['/blog/ajax/article-category-media-form?type=preview']), | |
| 65 | + 'form' => $form, | |
| 66 | + 'data_langs' => $category->getIsNewRecord()?$images:ArticleCategoryMedia::find()->where(['article_category_id' => $category->article_category_id, 'type' => 'preview'])->indexBy('language_id')->all() | |
| 67 | + ]); | |
| 68 | + $first = 1; | |
| 69 | + foreach($images as $lang => $value) { | |
| 70 | + if(!array_key_exists('preview', $value)) continue; | |
| 71 | + ?> | |
| 72 | + <div role="" class="tab-pane <?php if($first) { echo 'active main-tab'; } ?>" id="<?=$imagelang->id?>-<?=$lang?>"> | |
| 73 | + <?php | |
| 74 | + echo $form->field($images[$lang]['preview'], "[{$lang}][preview]language_id")->label(false)->hiddenInput(['value' => $lang]); | |
| 75 | + echo $form->field($images[$lang]['preview'], "[{$lang}][preview]imageFile")->fileInput(['class' => 'image_inputs_field']); | |
| 76 | + if(!empty($images[$lang]['preview']->article_category_media_id)) { | |
| 77 | + echo "<img src='/images/upload/{$images[$lang]['preview']->media->hash}/original.{$images[$lang]['preview']->media->extension}' width='100' class='image_inputs_prev'>"; | |
| 78 | + } | |
| 79 | + ?> | |
| 80 | + </div> | |
| 81 | + <?php | |
| 82 | + $first = 0; | |
| 83 | + } | |
| 84 | + $imagelang->end(); | |
| 85 | + ?> | |
| 86 | + </div> | |
| 87 | + <div role="" class="tab-pane" id="image-additional"> | |
| 88 | + <?php | |
| 89 | + echo $form->field(is_array($images[0]['additional'])?$images[0]['additional'][0]:$images[0]['additional'], "[0][additional]imageFile[]")->fileInput(['multiple' => 'multiple', 'class' => 'image_inputs_field']); | |
| 90 | + if(is_array($images[0]['additional']) && count($images[0]['additional']) > 1) { | |
| 91 | + foreach($images[0]['additional'] as $onefield => $oneimage) { | |
| 92 | + if($onefield) { | |
| 93 | + ?> | |
| 94 | + <div class="additional_image_container"> | |
| 95 | + <img src='/images/upload/<?= $oneimage->media->hash ?>/original.<?= $oneimage->media->extension ?>' width='100'> | |
| 96 | + <a | |
| 97 | + href="<?= Url::to(['ajax/remove-image']) ?>" | |
| 98 | + class="remove_image glyphicon glyphicon-remove-circle" | |
| 99 | + data-params='<?= Json::encode(['article_category_media_id' => $oneimage->article_category_media_id, 'remove_media' => true]) ?>', | |
| 100 | + ></a> | |
| 101 | + </div> | |
| 102 | + <?php | |
| 103 | + } | |
| 104 | + } | |
| 105 | + } | |
| 106 | + ?> | |
| 107 | + </div> | |
| 108 | + </div> | |
| 109 | + | |
| 110 | + <hr> | |
| 111 | + | |
| 112 | + <?php | |
| 113 | + $multilang = Multilang::begin(['ajaxpath' => Url::to(['/blog/ajax/category-form']), 'form' => $form, 'data_langs' => $category_langs]) | |
| 114 | + ?> | |
| 115 | + <?php | |
| 116 | + $first = 1; | |
| 117 | + foreach($category_langs as $index => $category_lang) { | |
| 118 | + ?> | |
| 119 | + <div role="" class="tab-pane <?php if($first) { echo 'active main-tab'; } ?>" id="lang-<?=$index?>"> | |
| 120 | + <?= $form->field($category_langs[$index], "[$index]language_id")->label(false)->hiddenInput(['value' => $index]) ?> | |
| 121 | + | |
| 122 | + <?= $form->field($category_langs[$index], "[$index]text")->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?> | |
| 123 | + | |
| 124 | + <?= $form->field($category_langs[$index], "[$index]preview")->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?> | |
| 125 | + | |
| 126 | + <?= $form->field($category_langs[$index], "[$index]seo_url")->textInput() ?> | |
| 127 | + | |
| 128 | + <?= $form->field($category_langs[$index], "[$index]name")->textInput() ?> | |
| 129 | + | |
| 130 | + <?= $form->field($category_langs[$index], "[$index]meta_title")->textInput() ?> | |
| 131 | + | |
| 132 | + <?= $form->field($category_langs[$index], "[$index]meta_descr")->textarea(); ?> | |
| 133 | + | |
| 134 | + <?= $form->field($category_langs[$index], "[$index]meta_keyword")->textInput() ?> | |
| 135 | + | |
| 136 | + <?= $form->field($category_langs[$index], "[$index]h1_tag")->textInput() ?> | |
| 137 | + | |
| 138 | + <?= $form->field($category_langs[$index], "[$index]tag")->textInput() ?> | |
| 139 | + | |
| 140 | + </div> | |
| 141 | + <?php | |
| 142 | + $first = 0; | |
| 143 | + } | |
| 144 | + ?> | |
| 145 | + <?php | |
| 146 | + $multilang->end(); | |
| 147 | + ?> | |
| 148 | + | |
| 149 | + <div class="form-group"> | |
| 150 | + <?= Html::submitButton($category->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $category->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> | |
| 151 | + </div> | |
| 152 | + | |
| 153 | + <?php ActiveForm::end(); ?> | |
| 154 | + | |
| 155 | +</div> | |
| 156 | +<script> | |
| 157 | + var confirm_message = '<?= \Yii::t('app', 'Remove image?') ?>'; | |
| 158 | +</script> | |
| 0 | 159 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/blog/views/category/create.php | |
| 1 | +<?php | |
| 2 | +use yii\helpers\Html; | |
| 3 | + | |
| 4 | +$this->title = Yii::t('app', 'Category create'); | |
| 5 | +$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Categories'), 'url' => ['index']]; | |
| 6 | +$this->params['breadcrumbs'][] = $this->title; | |
| 7 | +?> | |
| 8 | +<div class="category-create"> | |
| 9 | + | |
| 10 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 11 | + | |
| 12 | + <?= $this->render('_form', [ | |
| 13 | + 'category_langs' => $category_langs, | |
| 14 | + 'category' => $category, | |
| 15 | + 'langs' => $langs, | |
| 16 | + 'images' => $images | |
| 17 | + ]) ?> | |
| 18 | + | |
| 19 | +</div> | ... | ... |
| 1 | +++ a/common/modules/blog/views/category/index.php | |
| 1 | +<?php | |
| 2 | +use yii\grid\ActionColumn; | |
| 3 | +use yii\grid\Column; | |
| 4 | +use yii\grid\GridView; | |
| 5 | +use common\modules\blog\models\Article; | |
| 6 | +use common\models\Language; | |
| 7 | +echo GridView::widget([ | |
| 8 | + 'dataProvider' => $dataProvider, | |
| 9 | + 'columns' => [ | |
| 10 | + 'article_category_id', | |
| 11 | + 'code', | |
| 12 | + 'date_add', | |
| 13 | + 'date_update', | |
| 14 | + [ | |
| 15 | + 'class' => Column::className(), | |
| 16 | + 'header' => Yii::t('app', 'Name'), | |
| 17 | + 'content' => function($model, $key, $index, $column) { | |
| 18 | + return $model->getArticleCategoryLangs()->orderBy(['language_id' => 'ASC'])->one()->name; | |
| 19 | + } | |
| 20 | + ], | |
| 21 | + [ | |
| 22 | + 'class' => ActionColumn::className(), | |
| 23 | + 'template' => '{update} {delete}' | |
| 24 | + ] | |
| 25 | + ] | |
| 26 | +]); | |
| 0 | 27 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/blog/views/category/update.php | |
| 1 | +<?php | |
| 2 | +use yii\helpers\Html; | |
| 3 | + | |
| 4 | +$this->title = Yii::t('app', 'Update category'); | |
| 5 | +$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Categories'), 'url' => ['index']]; | |
| 6 | +$this->params['breadcrumbs'][] = $this->title; | |
| 7 | +?> | |
| 8 | +<div class="category-create"> | |
| 9 | + | |
| 10 | + <h1><?= Html::encode($this->title) ?></h1> | |
| 11 | + <?= $this->render('_form', [ | |
| 12 | + 'category_langs' => $category_langs, | |
| 13 | + 'category' => $category, | |
| 14 | + 'langs' => $langs, | |
| 15 | + 'images' => $images | |
| 16 | + ]) ?> | |
| 17 | + | |
| 18 | +</div> | ... | ... |
| 1 | +++ a/common/modules/blog/views/media/index.php | |
| 1 | +<?php | |
| 2 | + | |
| 3 | +use yii\bootstrap\ActiveForm; | |
| 4 | +use yii\bootstrap\Html; | |
| 5 | + | |
| 6 | +$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); | |
| 7 | + | |
| 8 | +echo $form->field($model, 'imageFile')->fileInput(['multiple' => 'multiple']); | |
| 9 | + | |
| 10 | +?> | |
| 11 | + <img id="blah" src="#" alt="your image"> | |
| 12 | +<div class="form-group"> | |
| 13 | + <?= Html::submitButton(Yii::t('app', 'Create'), ['class' => 'btn btn-success']) ?> | |
| 14 | +</div> | |
| 15 | +<?php | |
| 16 | +ActiveForm::end(); | |
| 17 | +?> | |
| 18 | +<script> | |
| 19 | + function readURL(input) { | |
| 20 | + if (input.files && input.files[1]) { | |
| 21 | + var reader = new FileReader(); | |
| 22 | + | |
| 23 | + reader.onload = function (e) { | |
| 24 | + $('#blah') | |
| 25 | + .attr('src', e.target.result) | |
| 26 | + .width(150); | |
| 27 | + }; | |
| 28 | + | |
| 29 | + reader.readAsDataURL(input.files[1]); | |
| 30 | + } | |
| 31 | + } | |
| 32 | + $(function() { | |
| 33 | + $(document).on('change', 'input[type=file]', function() { | |
| 34 | + readURL(this); | |
| 35 | + }); | |
| 36 | + }); | |
| 37 | +</script> | ... | ... |
| 1 | +++ a/common/modules/blog/views/test/index.php | |
| 1 | +<?php | |
| 2 | + use common\widgets\Multilanguage; | |
| 3 | + use yii\bootstrap\ActiveForm; | |
| 4 | + | |
| 5 | +$form = ActiveForm::begin(); | |
| 6 | +echo Multilanguage::widget([ | |
| 7 | + 'data' => $model, | |
| 8 | + 'form' => $form, | |
| 9 | + 'ajaxView' => '@common/modules/blog/views/ajax/_article_form_test', | |
| 10 | +]); | |
| 11 | +$form->end(); | |
| 0 | 12 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/comment/Controller.php | |
| 1 | +<?php | |
| 2 | + namespace common\modules\comment; | |
| 3 | + | |
| 4 | + class Controller extends \yii\web\Controller | |
| 5 | + { | |
| 6 | + public function behaviors() | |
| 7 | + { | |
| 8 | + return [ | |
| 9 | + 'verbs' => [ | |
| 10 | + 'class' => \yii\filters\VerbFilter::className(), | |
| 11 | + 'actions' => [ | |
| 12 | + '*' => ['post'], | |
| 13 | + ], | |
| 14 | + ], | |
| 15 | + ]; | |
| 16 | + } | |
| 17 | + | |
| 18 | + public function actionDelete() | |
| 19 | + { | |
| 20 | + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |
| 21 | + $post = \Yii::$app->request->post('Comment'); | |
| 22 | + if(!empty($post['comment_id'])) { | |
| 23 | + if($model = \common\modules\comment\models\Comment::findOne($post['comment_id'])) { | |
| 24 | + /** | |
| 25 | + * @var \common\modules\comment\models\Comment $model | |
| 26 | + */ | |
| 27 | + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST; | |
| 28 | + if($model->deleteComment()) { | |
| 29 | + \Yii::$app->response->data = ['text' => 'Comment marked as deleted and will be check by administrators']; | |
| 30 | + } else { | |
| 31 | + \Yii::$app->response->data = ['error' => $model->hasErrors('comment_id')?$model->getFirstError('comment_id'):'Cannot delete message']; | |
| 32 | + } | |
| 33 | + }else { | |
| 34 | + \Yii::$app->response->data = ['error' => 'Comment not found']; | |
| 35 | + }; | |
| 36 | + } else { | |
| 37 | + \Yii::$app->response->data = ['error' => 'Missing comment_id']; | |
| 38 | + } | |
| 39 | + \Yii::$app->response->send(); | |
| 40 | + } | |
| 41 | + | |
| 42 | + public function actionUpdate() | |
| 43 | + { | |
| 44 | + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |
| 45 | + $post = \Yii::$app->request->post(); | |
| 46 | + if(!empty($post['Comment']['comment_id'])) { | |
| 47 | + if($model = \common\modules\comment\models\Comment::findOne($post['Comment']['comment_id'])) { | |
| 48 | + /** | |
| 49 | + * @var \common\modules\comment\models\Comment $model | |
| 50 | + */ | |
| 51 | + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST; | |
| 52 | + $model->load($post); | |
| 53 | + if(empty($post['Comment']['comment_pid'])) { | |
| 54 | + $model->comment_pid = null; | |
| 55 | + } | |
| 56 | + if($model->updateComment()) { | |
| 57 | + \Yii::$app->response->data = ['text' => 'Comment successfully updated']; | |
| 58 | + } else { | |
| 59 | + \Yii::$app->response->data = ['error' => $model->hasErrors()?$model->getFirstErrors():'Cannot update message']; | |
| 60 | + } | |
| 61 | + }else { | |
| 62 | + \Yii::$app->response->data = ['error' => 'Comment not found']; | |
| 63 | + }; | |
| 64 | + } else { | |
| 65 | + \Yii::$app->response->data = ['error' => 'Missing comment_id']; | |
| 66 | + } | |
| 67 | + \Yii::$app->response->send(); | |
| 68 | + } | |
| 69 | + | |
| 70 | + public function actionForm() | |
| 71 | + { | |
| 72 | + $post = \Yii::$app->request->post('Comment'); | |
| 73 | + if(!empty($post['comment_id'])) { | |
| 74 | + $model = \common\modules\comment\models\Comment::find()->where(['comment_id' => $post['comment_id']])->with('parent', 'author')->one(); | |
| 75 | + if($model) { | |
| 76 | + /** | |
| 77 | + * @var \common\modules\comment\models\Comment $model | |
| 78 | + */ | |
| 79 | + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST; | |
| 80 | + if($model->checkUpdate()) { | |
| 81 | + return $this->renderAjax('@common/modules/comment/views/comment_form', [ | |
| 82 | + 'model' => $model, | |
| 83 | + ]); | |
| 84 | + } else { | |
| 85 | + \Yii::$app->response->data = ['error' => 'You are not able to update this comment']; | |
| 86 | + } | |
| 87 | + }else { | |
| 88 | + \Yii::$app->response->data = ['error' => 'Comment not found']; | |
| 89 | + }; | |
| 90 | + } else { | |
| 91 | + \Yii::$app->response->data = ['error' => 'Missing comment_id']; | |
| 92 | + } | |
| 93 | + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |
| 94 | + \Yii::$app->response->send(); | |
| 95 | + } | |
| 96 | + } | |
| 0 | 97 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/comment/Module.php | |
| 1 | +<?php | |
| 2 | + namespace common\modules\comment; | |
| 3 | + | |
| 4 | + /** | |
| 5 | + * Class Module | |
| 6 | + * @package common\modules\comment | |
| 7 | + */ | |
| 8 | + class Module extends \yii\base\Module | |
| 9 | + { | |
| 10 | + | |
| 11 | + /** | |
| 12 | + * @var string Module name | |
| 13 | + */ | |
| 14 | + public static $moduleName = 'artbox_comment'; | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * @var bool Wheather to use Rbac system | |
| 18 | + * @link http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#rbac | |
| 19 | + * @see \yii\rbac\ManagerInterface | |
| 20 | + */ | |
| 21 | + public $useRbac = false; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * Array of RBAC rules and permissions that can be used by install command. | |
| 25 | + * | |
| 26 | + * Currently supports associative array, of such view: | |
| 27 | + * | |
| 28 | + * <code> | |
| 29 | + * [ | |
| 30 | + * 'rules' => [ | |
| 31 | + * \full\namapaced\ClassName, | |
| 32 | + * \another\one\ClassName, | |
| 33 | + * ], | |
| 34 | + * 'permissions' => [ | |
| 35 | + * [ | |
| 36 | + * 'name' => stringName, | |
| 37 | + * 'description' => descriptionText, | |
| 38 | + * 'ruleName' => (new \full\namespaced\ClassName())->name (optional) | |
| 39 | + * ], | |
| 40 | + * [ | |
| 41 | + * 'name' => stringName2, | |
| 42 | + * 'description' => descriptionText2, | |
| 43 | + * 'ruleName' => (new \another\one\ClassName())->name (optional) | |
| 44 | + * ], | |
| 45 | + * ] | |
| 46 | + * ] | |
| 47 | + * </code> | |
| 48 | + * | |
| 49 | + * @var array | |
| 50 | + * @see \common\modules\comment\commands\RbacController | |
| 51 | + */ | |
| 52 | + public $rbac = []; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * @var \yii\db\Connection Connection to the db | |
| 56 | + */ | |
| 57 | + public $db = null; | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * @inheritdoc | |
| 61 | + */ | |
| 62 | + public function init() | |
| 63 | + { | |
| 64 | + parent::init(); | |
| 65 | + if(\Yii::$app instanceof \yii\console\Application) { | |
| 66 | + $this->controllerNamespace = 'common\modules\comment\commands'; | |
| 67 | + } | |
| 68 | + if($this->db === null) { | |
| 69 | + $this->db = \Yii::$app->db; | |
| 70 | + } elseif(!$this->db instanceof \yii\db\Connection) { | |
| 71 | + throw new \yii\base\InvalidConfigException('Конфиг db обязан наследоваться от'.\yii\db\Connection::className()); | |
| 72 | + } | |
| 73 | + } | |
| 74 | + } | |
| 0 | 75 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/comment/Permissions.php | |
| 1 | +<?php | |
| 2 | + namespace common\modules\comment; | |
| 3 | + | |
| 4 | + class Permissions | |
| 5 | + { | |
| 6 | + | |
| 7 | + const CREATE = 'artbox_comment.create'; | |
| 8 | + const UPDATE = 'artbox_comment.update'; | |
| 9 | + const DELETE = 'artbox_comment.delete'; | |
| 10 | + const UPDATE_OWN = 'artbox_comment.update_own'; | |
| 11 | + const DELETE_OWN = 'artbox_comment.delete_own'; | |
| 12 | + } | |
| 0 | 13 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/comment/assets/CommentAsset.php | |
| 1 | +<?php | |
| 2 | + namespace common\modules\comment\assets; | |
| 3 | + | |
| 4 | + class CommentAsset extends \yii\web\AssetBundle | |
| 5 | + { | |
| 6 | + public $sourcePath = '@common/modules/comment/resources'; | |
| 7 | + | |
| 8 | + public $css = [ | |
| 9 | + 'comment.css', | |
| 10 | + ]; | |
| 11 | + | |
| 12 | + public $js = [ | |
| 13 | + 'comment.js', | |
| 14 | + ]; | |
| 15 | + | |
| 16 | + public $depends = [ | |
| 17 | + '\yii\web\YiiAsset', | |
| 18 | + '\yii\web\JqueryAsset', | |
| 19 | + ]; | |
| 20 | + | |
| 21 | + } | |
| 0 | 22 | \ No newline at end of file | ... | ... |
| 1 | +++ a/common/modules/comment/commands/RbacController.php | |
| 1 | +<?php | |
| 2 | + namespace common\modules\comment\commands; | |
| 3 | + | |
| 4 | + class RbacController extends \yii\console\Controller | |
| 5 | + { | |
| 6 | + | |
| 7 | + public function actionInstall() | |
| 8 | + { | |
| 9 | + /** | |
| 10 | + * @var \common\modules\comment\Module $module | |
| 11 | + */ | |
| 12 | + $module = \Yii::$app->controller->module; | |
| 13 | + if(!$module->useRbac) { | |
| 14 | + throw new \yii\base\InvalidConfigException('Please set useRbac config to TRUE in your module configs'); | |
| 15 | + } | |
| 16 | + $auth = \Yii::$app->getAuthManager(); | |
| 17 | + if(!$auth instanceof \yii\rbac\ManagerInterface) { | |
| 18 | + throw new \yii\base\InvalidConfigException('ManagerInterface is not configured'); | |
| 19 | + } | |
| 20 | + if(!empty($module->rbac['rules'])) { | |
| 21 | + foreach($module->rbac['rules'] as $rule) { | |
| 22 | + $rule_model = new $rule(); | |
| 23 | + echo "Creating rule: ".$rule_model->name."\n"; | |
| 24 | + if($auth->add($rule_model)) { | |
| 25 | + echo "Successful\n"; | |
| 26 | + } else { | |
| 27 | + echo "Failed\n"; | |
| 28 | + } | |
| 29 | + unset($rule_model); | |
| 30 | + } | |
| 31 | + } | |
| 32 | + if(!empty($module->rbac['permissions'])) { | |
| 33 | + foreach($module->rbac['permissions'] as $permission) { | |
| 34 | + echo "Creating permission: ".$permission['name']."\n"; | |
| 35 | + if($auth->add(new \yii\rbac\Permission($permission))) { | |
| 36 | + echo "Successful\n"; | |
| 37 | + } else { | |
| 38 | + echo "Failed\n"; | |
| 39 | + } | |
| 40 | + } | |
| 41 | + } | |
| 42 | + } | |
| 43 | + | |
| 44 | + public function actionUninstall() | |
| 45 | + { | |
| 46 | + /** | |
| 47 | + * @var \common\modules\comment\Module $module | |
| 48 | + */ | |
| 49 | + $module = \Yii::$app->controller->module; | |
| 50 | + if(!$module->useRbac) { | |
| 51 | + throw new \yii\base\InvalidConfigException('Please set useRbac config to TRUE in your module configs'); | |
| 52 | + } | |
| 53 | + $auth = \Yii::$app->getAuthManager(); | |
| 54 | + if(!$auth instanceof \yii\rbac\ManagerInterface) { | |
| 55 | + throw new \yii\base\InvalidConfigException('ManagerInterface is not configured'); | |
| 56 | + } | |
| 57 | + if(!empty($module->rbac['rules'])) { | |
| 58 | + foreach($module->rbac['rules'] as $rule) { | |
| 59 | + $rule_model = new $rule(); | |
| 60 | + echo "Removing rule: ".$rule_model->name."\n"; | |
| 61 | + if($auth->remove($rule_model)) { | |
| 62 | + echo "Successful\n"; | |
| 63 | + } else { | |
| 64 | + echo "Failed\n"; | |
| 65 | + } | |
| 66 | + unset($rule_model); | |
| 67 | + } | |
| 68 | + } | |
| 69 | + if(!empty($module->rbac['permissions'])) { | |
| 70 | + foreach($module->rbac['permissions'] as $permission) { | |
| 71 | + echo "Removing permission: ".$permission['name']."\n"; | |
| 72 | + if($auth->remove(new \yii\rbac\Permission($permission))) { | |
| 73 | + echo "Successful\n"; | |
| 74 | + } else { | |
| 75 | + echo "Failed\n"; | |
| 76 | + } | |
| 77 | + } | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + } | |
| 0 | 82 | \ No newline at end of file | ... | ... |
common/modules/comment/interfaces/CommentInterface.php
0 → 100644
| 1 | +++ a/common/modules/comment/interfaces/CommentInterface.php | |
| 1 | +<?php | |
| 2 | + namespace common\modules\comment\interfaces; | |
| 3 | + | |
| 4 | + interface CommentInterface { | |
| 5 | + public function load($data, $formName = null); | |
| 6 | + public function formName(); | |
| 7 | + public function getComments($model, $model_id); | |
| 8 | + public function postComment(); | |
| 9 | + public function deleteComment(); | |
| 10 | + public function updateComment(); | |
| 11 | + } | ... | ... |
| 1 | +++ a/common/modules/comment/models/Comment.php | |
| 1 | +<?php | |
| 2 | + namespace common\modules\comment\models; | |
| 3 | + | |
| 4 | + use yii\db\ActiveQuery; | |
| 5 | + | |
| 6 | + /** | |
| 7 | + * Class Comment | |
| 8 | + * @property bool $guestComment | |
| 9 | + * @property integer $comment_id | |
| 10 | + * @property string $text | |
| 11 | + * @property int $user_id | |
| 12 | + * @property string $user_name | |
| 13 | + * @property string $user_email | |
| 14 | + * @property int $comment_pid | |
| 15 | + * @property int $status | |
| 16 | + * @property string $date_add | |
| 17 | + * @property string $date_update | |
| 18 | + * @property string $date_delete | |
| 19 | + * @property string $model | |
| 20 | + * @property int $model_id | |
| 21 | + * @package common\modules\comment\models | |
| 22 | + */ | |
| 23 | + class Comment extends \yii\db\ActiveRecord | |
| 24 | + implements \common\modules\comment\interfaces\CommentInterface | |
| 25 | + { | |
| 26 | + | |
| 27 | + const STATUS_HIDDEN = 0; | |
| 28 | + const STATUS_DELETED = 2; | |
| 29 | + const STATUS_ACTIVE = 1; | |
| 30 | + const STATUS_PERSONAL = 3; | |
| 31 | + | |
| 32 | + const SCENARIO_USER = 'user'; | |
| 33 | + const SCENARIO_GUEST = 'guest'; | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * @var bool | |
| 37 | + */ | |
| 38 | + public $guestComment = true; | |
| 39 | + | |
| 40 | + public function rules() | |
| 41 | + { | |
| 42 | + return [ | |
| 43 | + [ | |
| 44 | + [ | |
| 45 | + 'text', | |
| 46 | + 'user_name', | |
| 47 | + 'user_email', | |
| 48 | + ], | |
| 49 | + 'required', | |
| 50 | + ], | |
| 51 | + [ | |
| 52 | + [ | |
| 53 | + 'rating', | |
| 54 | + ], | |
| 55 | + 'safe', | |
| 56 | + ], | |
| 57 | + [ | |
| 58 | + [ 'user_email' ], | |
| 59 | + 'email', | |
| 60 | + ], | |
| 61 | + [ | |
| 62 | + [ 'user_name' ], | |
| 63 | + 'string', | |
| 64 | + ], | |
| 65 | + [ | |
| 66 | + [ | |
| 67 | + 'comment_id', | |
| 68 | + 'comment_pid', | |
| 69 | + ], | |
| 70 | + 'integer', | |
| 71 | + ], | |
| 72 | + [ | |
| 73 | + [ 'status' ], | |
| 74 | + 'default', | |
| 75 | + 'value' => 1, | |
| 76 | + ], | |
| 77 | + [ | |
| 78 | + [ 'comment_pid' ], | |
| 79 | + 'exist', | |
| 80 | + 'targetAttribute' => 'comment_id', | |
| 81 | + 'filter' => [ | |
| 82 | + 'model' => $this->model, | |
| 83 | + 'model_id' => $this->model_id, | |
| 84 | + ], | |
| 85 | + ], | |
| 86 | + ]; | |
| 87 | + } | |
| 88 | + | |
| 89 | + public function scenarios() | |
| 90 | + { | |
| 91 | + return [ | |
| 92 | + self::SCENARIO_GUEST => [ | |
| 93 | + 'user_name', | |
| 94 | + 'user_email', | |
| 95 | + 'text', | |
| 96 | + 'comment_pid', | |
| 97 | + ], | |
| 98 | + self::SCENARIO_USER => [ | |
| 99 | + 'text', | |
| 100 | + 'comment_pid', | |
| 101 | + ], | |
| 102 | + ]; | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * @inheritdoc | |
| 107 | + */ | |
| 108 | + public function behaviors() | |
| 109 | + { | |
| 110 | + return [ | |
| 111 | + [ | |
| 112 | + 'class' => \yii\behaviors\TimestampBehavior::className(), | |
| 113 | + 'createdAtAttribute' => 'date_add', | |
| 114 | + 'updatedAtAttribute' => 'date_update', | |
| 115 | + 'value' => new \yii\db\Expression('NOW()'), | |
| 116 | + ], | |
| 117 | + ]; | |
| 118 | + } | |
| 119 | + | |
| 120 | + public static function tableName() | |
| 121 | + { | |
| 122 | + return '{{%comment}}'; | |
| 123 | + } | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * @inheritdoc | |
| 127 | + */ | |
| 128 | + public function attributeLabels() | |
| 129 | + { | |
| 130 | + return [ | |
| 131 | + 'text' => \Yii::t('app', 'Комментарий'), | |
| 132 | + 'user_name' => \Yii::t('app', 'Имя'), | |
| 133 | + 'user_email' => \Yii::t('app', 'Email'), | |
| 134 | + ]; | |
| 135 | + } | |
| 136 | + | |
| 137 | + public function getGuestComment() | |
| 138 | + { | |
| 139 | + return $this->guestComment; | |
| 140 | + } | |
| 141 | + | |
| 142 | + public function setGuestComment($value) | |
| 143 | + { | |
| 144 | + $this->guestComment = $value; | |
| 145 | + } | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * @param string $model | |
| 149 | + * @param integer $model_id | |
| 150 | + * | |
| 151 | + * @return ActiveQuery | |
| 152 | + */ | |
| 153 | + public function getComments($model, $model_id) | |
| 154 | + { | |
| 155 | + return $this->find() | |
| 156 | + ->where([ | |
| 157 | + 'comment.model' => $model, | |
| 158 | + 'comment.model_id' => $model_id, | |
| 159 | + 'comment.status' => 1, | |
| 160 | + ]); | |
| 161 | + } | |
| 162 | + | |
| 163 | + public function postComment() | |
| 164 | + { | |
| 165 | + if($this->checkCreate()) { | |
| 166 | + if($this->insert()) { | |
| 167 | + $this->clearSafe(); | |
| 168 | + return true; | |
| 169 | + } else { | |
| 170 | + return false; | |
| 171 | + } | |
| 172 | + } else { | |
| 173 | + $this->addError('comment_id', 'You can`t post comment here'); | |
| 174 | + return false; | |
| 175 | + } | |
| 176 | + } | |
| 177 | + | |
| 178 | + public function updateComment() | |
| 179 | + { | |
| 180 | + if($this->checkUpdate()) { | |
| 181 | + if(empty( $this->comment_id )) { | |
| 182 | + $this->addError('comment_id', 'Comment ID not found'); | |
| 183 | + return false; | |
| 184 | + } else { | |
| 185 | + if($this->update()) { | |
| 186 | + $this->clearSafe(); | |
| 187 | + return true; | |
| 188 | + } else { | |
| 189 | + return false; | |
| 190 | + } | |
| 191 | + } | |
| 192 | + } else { | |
| 193 | + $this->addError('comment_id', 'You can`t update this post'); | |
| 194 | + return false; | |
| 195 | + } | |
| 196 | + } | |
| 197 | + | |
| 198 | + public function deleteComment() | |
| 199 | + { | |
| 200 | + if($this->checkDelete()) { | |
| 201 | + if(empty( $this->comment_id )) { | |
| 202 | + $this->addError('comment_id', 'Comment ID not found'); | |
| 203 | + return false; | |
| 204 | + } else { | |
| 205 | + if($this->status == self::STATUS_DELETED) { | |
| 206 | + return false; | |
| 207 | + } | |
| 208 | + $this->status = self::STATUS_DELETED; | |
| 209 | + if($this->update()) { | |
| 210 | + $this->clearSafe(); | |
| 211 | + return true; | |
| 212 | + } else { | |
| 213 | + return false; | |
| 214 | + } | |
| 215 | + } | |
| 216 | + } else { | |
| 217 | + $this->addError('comment_id', 'You can`t delete this post'); | |
| 218 | + return false; | |
| 219 | + } | |
| 220 | + } | |
| 221 | + | |
| 222 | + public function checkCreate() | |
| 223 | + { | |
| 224 | + if($this->getGuestComment()) { | |
| 225 | + return true; | |
| 226 | + } else { | |
| 227 | + return \Yii::$app->user->can(\common\modules\comment\Permissions::CREATE, [ | |
| 228 | + 'model' => $this->model, | |
| 229 | + 'model_id' => $this->model_id, | |
| 230 | + ]); | |
| 231 | + } | |
| 232 | + } | |
| 233 | + | |
| 234 | + public function checkUpdate() | |
| 235 | + { | |
| 236 | + if($this->scenario == self::SCENARIO_GUEST) { | |
| 237 | + return false; | |
| 238 | + } else { | |
| 239 | + return \Yii::$app->user->can(\common\modules\comment\Permissions::UPDATE, [ | |
| 240 | + 'model' => $this->model, | |
| 241 | + 'model_id' => $this->model_id, | |
| 242 | + ]) || \Yii::$app->user->can(\common\modules\comment\Permissions::UPDATE_OWN, [ | |
| 243 | + 'model' => $this->model, | |
| 244 | + 'model_id' => $this->model_id, | |
| 245 | + ]); | |
| 246 | + } | |
| 247 | + } | |
| 248 | + | |
| 249 | + public function checkDelete() | |
| 250 | + { | |
| 251 | + if($this->scenario == self::SCENARIO_GUEST) { | |
| 252 | + return false; | |
| 253 | + } else { | |
| 254 | + return \Yii::$app->user->can(\common\modules\comment\Permissions::DELETE, [ | |
| 255 | + 'model' => $this->model, | |
| 256 | + 'model_id' => $this->model_id, | |
| 257 | + ]) || \Yii::$app->user->can(\common\modules\comment\Permissions::DELETE_OWN, [ | |
| 258 | + 'model' => $this->model, | |
| 259 | + 'model_id' => $this->model_id, | |
| 260 | + ]); | |
| 261 | + } | |
| 262 | + } | |
| 263 | + | |
| 264 | + protected function clearSafe($setNew = true) | |
| 265 | + { | |
| 266 | + $safe = $this->safeAttributes(); | |
| 267 | + $count = count($safe); | |
| 268 | + $values = array_fill(0, $count, NULL); | |
| 269 | + $result = array_combine($safe, $values); | |
| 270 | + $this->setAttributes($result); | |
| 271 | + $this->setIsNewRecord($setNew); | |
| 272 | + } | |
| 273 | + | |
| 274 | + public function getParent() | |
| 275 | + { | |
| 276 | + return $this->hasOne(self::className(), [ 'comment_id' => 'comment_pid' ]); | |
| 277 | + } | |
| 278 | + | |
| 279 | + public function getAuthor() | |
| 280 | + { | |
| 281 | + // if($this->user_id != NULL) { | |
| 282 | + return $this->hasOne(\common\models\User::className(), [ 'id' => 'user_id' ]); | |
| 283 | + // } else { | |
| 284 | + // return ['firstname' => $this->user_name, 'email' => $this->user_email]; | |
| 285 | + // } | |
| 286 | + } | |
| 287 | + | |
| 288 | + public function checkRating() | |
| 289 | + { | |
| 290 | + $rating = $this->hasOne(\common\modules\comment\models\Rating::className(), [ | |
| 291 | + 'model_id' => 'comment_id', | |
| 292 | + ]) | |
| 293 | + ->andWhere([ | |
| 294 | + 'model' => $this->className(), | |
| 295 | + ]) | |
| 296 | + ->one(); | |
| 297 | + if(!$rating instanceof \common\modules\comment\models\Rating) { | |
| 298 | + $rating = new \common\modules\comment\models\Rating([ | |
| 299 | + 'model' => $this->className(), | |
| 300 | + 'model_id' => $this->comment_id, | |
| 301 | + 'user_id' => $this->user_id, | |
| 302 | + ]); | |
| 303 | + $rating->save(); | |
| 304 | + } | |
| 305 | + } | |
| 306 | + | |
| 307 | + public function getRating() | |
| 308 | + { | |
| 309 | + $this->checkRating(); | |
| 310 | + return $this->hasOne(\common\modules\comment\models\Rating::className(), [ | |
| 311 | + 'model_id' => 'comment_id', | |
| 312 | + ]) | |
| 313 | + ->andWhere([ 'model' => $this->className() ]); | |
| 314 | + } | |
| 315 | + | |
| 316 | + public function hasRating($return = true) | |
| 317 | + { | |
| 318 | + $rating = $this->hasOne(\common\modules\comment\models\Rating::className(), [ | |
| 319 | + 'model_id' => 'comment_id', | |
| 320 | + ]) | |
| 321 | + ->andWhere([ 'model' => $this->className() ]) | |
| 322 | + ->andWhere([ | |
| 323 | + 'not', | |
| 324 | + [ 'value' => NULL ], | |
| 325 | + ]) | |
| 326 | + ->one(); | |
| 327 | + if($return) { | |
| 328 | + return $rating; | |
| 329 | + } else { | |
| 330 | + return $rating ? true : false; | |
| 331 | + } | |
| 332 | + } | |
| 333 | + | |
| 334 | + } | ... | ... |