Commit a83704822d340f1b8b9a049b889046ee095f6cc8

Authored by Alexander Karnovsky
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.

.bowerrc 0 → 100644
  1 +++ a/.bowerrc
  1 +{
  2 + "directory" : "vendor/bower"
  3 +}
... ...
.gitignore 0 → 100644
  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
... ...
.htaccess 0 → 100644
  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
... ...
LICENSE.md 0 → 100644
  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.
... ...
README.md 0 → 100644
  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 +[![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2-app-advanced/v/stable.png)](https://packagist.org/packages/yiisoft/yii2-app-advanced)
  16 +[![Total Downloads](https://poser.pugx.org/yiisoft/yii2-app-advanced/downloads.png)](https://packagist.org/packages/yiisoft/yii2-app-advanced)
  17 +[![Build Status](https://travis-ci.org/yiisoft/yii2-app-advanced.svg?branch=master)](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 +```
... ...
backend/config/.gitignore 0 → 100644
  1 +++ a/backend/config/.gitignore
  1 +main-local.php
  2 +params-local.php
0 3 \ No newline at end of file
... ...
backend/config/bootstrap.php 0 → 100644
  1 +++ a/backend/config/bootstrap.php
  1 +<?php
... ...
backend/config/main.php 0 → 100644
  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 +];
... ...
backend/config/params.php 0 → 100644
  1 +++ a/backend/config/params.php
  1 +<?php
  2 +return [
  3 + 'adminEmail' => 'admin@example.com',
  4 +];
... ...
backend/controllers/BlogController.php 0 → 100644
  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 +}
... ...
backend/controllers/SiteController.php 0 → 100644
  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 +}
... ...
backend/models/.gitkeep 0 → 100644
  1 +++ a/backend/models/.gitkeep
  1 +*
... ...
backend/runtime/.gitignore 0 → 100644
  1 +++ a/backend/runtime/.gitignore
  1 +*
  2 +!.gitignore
0 3 \ No newline at end of file
... ...
backend/views/blog/_form.php 0 → 100644
  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>
... ...
backend/views/blog/_search.php 0 → 100644
  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>
... ...
backend/views/blog/create.php 0 → 100644
  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>
... ...
backend/views/blog/index.php 0 → 100644
  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>
... ...
backend/views/blog/update.php 0 → 100644
  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>
... ...
backend/views/blog/view.php 0 → 100644
  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>
... ...
backend/views/layouts/admin.php 0 → 100644
  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
... ...
backend/views/layouts/control-sidebar.php 0 → 100644
  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
... ...
backend/views/layouts/footer.php 0 → 100644
  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 &copy; 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
... ...
backend/views/layouts/header.php 0 → 100644
  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
... ...
backend/views/layouts/main-sidebar.php 0 → 100644
  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
... ...
backend/views/layouts/main-sidebar1.php 0 → 100644
  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
... ...
backend/views/layouts/main.php 0 → 100644
  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() ?>
... ...
backend/views/layouts/none.php 0 → 100644
  1 +++ a/backend/views/layouts/none.php
  1 +<?php
  2 +/* @var $content string */
  3 +use yii\widgets\Menu;
  4 +$this->beginContent('@app/views/layouts/main.php');
  5 +?>
  6 +
  7 + <?= $content; ?>
  8 +
  9 +<?php $this->endContent() ?>
0 10 \ No newline at end of file
... ...
backend/views/site/error.php 0 → 100644
  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>
... ...
backend/views/site/index.php 0 → 100644
  1 +++ a/backend/views/site/index.php
... ...
backend/views/site/login.php 0 → 100644
  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>
... ...
backend/web/.gitignore 0 → 100644
  1 +++ a/backend/web/.gitignore
  1 +/index.php
  2 +/index-test.php
... ...
backend/web/assets/.gitignore 0 → 100644
  1 +++ a/backend/web/assets/.gitignore
  1 +*
  2 +!.gitignore
... ...
backend/web/css/site.css 0 → 100644
  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 +}
... ...
backend/web/favicon.ico 0 → 100644
No preview for this file type
backend/web/js/fieldWidget.js 0 → 100644
  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
... ...
backend/web/robots.txt 0 → 100644
  1 +++ a/backend/web/robots.txt
  1 +User-agent: *
  2 +Disallow: /
... ...
common/behaviors/ShowImage.php 0 → 100644
  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
... ...
common/behaviors/Slug.php 0 → 100644
  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
... ...
common/components/LangRequest.php 0 → 100644
  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
... ...
common/components/LangUrlManager.php 0 → 100644
  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
... ...
common/components/Request.php 0 → 100644
  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
... ...
common/components/artboxtree/ArtboxTreeHelper.php 0 → 100644
  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 = '&ndash;') {
  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
... ...
common/components/artboxtree/ArtboxTreeWidget.php 0 → 100644
  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 = '&ndash;')
  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 = '&nbsp;';
  77 +
  78 + public $levelSymbol = '&ndash;';
  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
... ...
common/config/.gitignore 0 → 100644
  1 +++ a/common/config/.gitignore
  1 +main-local.php
  2 +params-local.php
... ...
common/config/bootstrap.php 0 → 100644
  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');
... ...
common/config/main.php 0 → 100644
  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 +];
... ...
common/config/params.php 0 → 100644
  1 +++ a/common/config/params.php
  1 +<?php
  2 +return [
  3 + 'adminEmail' => 'admin@example.com',
  4 + 'supportEmail' => 'support@example.com',
  5 + 'user.passwordResetTokenExpire' => 3600,
  6 +];
... ...
common/mail/layouts/html.php 0 → 100644
  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() ?>
... ...
common/mail/layouts/text.php 0 → 100644
  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() ?>
... ...
common/mail/passwordResetToken-html.php 0 → 100644
  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>
... ...
common/mail/passwordResetToken-text.php 0 → 100644
  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 ?>
... ...
common/models/Blog.php 0 → 100644
  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 + }
... ...
common/models/BlogSearch.php 0 → 100644
  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 + }
... ...
common/models/Fields.php 0 → 100644
  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 +}
... ...
common/models/LoginForm.php 0 → 100644
  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 +}
... ...
common/models/User.php 0 → 100644
  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 +}
... ...
common/modules/blog/Module.php 0 → 100644
  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 +}
... ...
common/modules/blog/behaviors/Autocomplete.php 0 → 100644
  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
... ...
common/modules/blog/config.php 0 → 100644
  1 +++ a/common/modules/blog/config.php
  1 +<?php
  2 +return [
  3 + 'components' => [
  4 +
  5 + ],
  6 + 'params' => [
  7 + 'test' => 'Hello',
  8 + ],
  9 +];
... ...
common/modules/blog/controllers/AjaxController.php 0 → 100644
  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
  1 +++ a/common/modules/blog/controllers/DefaultController.php
  1 +<?php
  2 +namespace common\modules\blog\controllers;
  3 +
  4 +use yii\web\Controller;
  5 +
  6 +class DefaultController extends Controller
  7 +{
  8 + public function actionIndex()
  9 + {
  10 + return $this->render('index');
  11 + }
  12 +}
... ...
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 +}
... ...
common/modules/blog/controllers/TestController.php 0 → 100644
  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
... ...
common/modules/blog/models/Article.php 0 → 100644
  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 +}
... ...
common/modules/blog/models/ArticleCategory.php 0 → 100644
  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 +}
... ...
common/modules/blog/models/ArticleCategoryLang.php 0 → 100644
  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 +}
... ...
common/modules/blog/models/ArticleLang.php 0 → 100644
  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 +}
... ...
common/modules/blog/models/ArticleMedia.php 0 → 100644
  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 +}
... ...
common/modules/blog/models/ArticleToCategory.php 0 → 100644
  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 +}
... ...
common/modules/blog/views/ajax/_article_form.php 0 → 100644
  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 +?>
... ...
common/modules/blog/views/ajax/_category_form.php 0 → 100644
  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 +?>
... ...
common/modules/blog/views/article/_form.php 0 → 100644
  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
... ...
common/modules/blog/views/article/create.php 0 → 100644
  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>
... ...
common/modules/blog/views/article/index.php 0 → 100644
  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
... ...
common/modules/blog/views/article/update.php 0 → 100644
  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>
... ...
common/modules/blog/views/category/_form.php 0 → 100644
  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
... ...
common/modules/blog/views/category/create.php 0 → 100644
  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>
... ...
common/modules/blog/views/category/index.php 0 → 100644
  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
... ...
common/modules/blog/views/category/update.php 0 → 100644
  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>
... ...
common/modules/blog/views/default/index.php 0 → 100644
  1 +++ a/common/modules/blog/views/default/index.php
  1 +<?php
  2 +
  3 +use yii\behaviors\BlameableBehavior;
  4 +use yii\web\Application;
  5 +
  6 +$behavior = new BlameableBehavior();
  7 +var_dump($behavior->value);
0 8 \ No newline at end of file
... ...
common/modules/blog/views/media/index.php 0 → 100644
  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>
... ...
common/modules/blog/views/test/index.php 0 → 100644
  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
... ...
common/modules/comment/Controller.php 0 → 100644
  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
... ...
common/modules/comment/Module.php 0 → 100644
  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
... ...
common/modules/comment/Permissions.php 0 → 100644
  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
... ...
common/modules/comment/assets/CommentAsset.php 0 → 100644
  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
... ...
common/modules/comment/commands/RbacController.php 0 → 100644
  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 + }
... ...
common/modules/comment/models/Comment.php 0 → 100644
  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 + }
... ...