diff --git a/.editorconfig b/.editorconfig index b58baa8..d705472 100644 --- a/.editorconfig +++ b/.editorconfig @@ -45,7 +45,7 @@ indent_size=2 indent_style=space indent_size=2 -[{*.yml,*.yaml}] +[{*.yml,*.yaml,*.xml}] indent_style=space indent_size=2 diff --git a/README.md b/README.md index 6acca0f..9e364e6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@

- - - -

Yii 2 Advanced Project Template

+

ZxCMS - Yii2 site management system


@@ -17,10 +14,6 @@ deploying the application in different environments. Documentation is at [docs/guide/README.md](docs/guide/README.md). -[![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2-app-advanced/v/stable.png)](https://packagist.org/packages/yiisoft/yii2-app-advanced) -[![Total Downloads](https://poser.pugx.org/yiisoft/yii2-app-advanced/downloads.png)](https://packagist.org/packages/yiisoft/yii2-app-advanced) -[![Build Status](https://travis-ci.org/yiisoft/yii2-app-advanced.svg?branch=master)](https://travis-ci.org/yiisoft/yii2-app-advanced) - DIRECTORY STRUCTURE ------------------- diff --git a/backend/bootstrap/SetUp.php b/backend/bootstrap/SetUp.php index 9a1c71e..872eb09 100644 --- a/backend/bootstrap/SetUp.php +++ b/backend/bootstrap/SetUp.php @@ -2,9 +2,11 @@ namespace backend\bootstrap; +use core\entities\Settings; use mihaildev\ckeditor\CKEditor; use mihaildev\elfinder\ElFinder; use yii\base\BootstrapInterface; +use yii\helpers\ArrayHelper; class SetUp implements BootstrapInterface { @@ -14,5 +16,19 @@ class SetUp implements BootstrapInterface $container->set(CKEditor::class, [ 'editorOptions' => ElFinder::ckeditorOptions('elfinder', []), ]); + + // load settings + $settings = ArrayHelper::map(Settings::find()->andWhere(['active' => 1])->all(), 'key', 'value', 'section'); + $app->params['settings'] = $settings; + + // Connect backend modules + + // Add finish UrlRules + $app->getUrlManager()->addRules([ + '<_c:[\w\-]+>' => '<_c>/index', + '<_c:[\w\-]+>/' => '<_c>/view', + '<_c:[\w\-]+>/<_a:[\w-]+>' => '<_c>/<_a>', + '<_c:[\w\-]+>//<_a:[\w\-]+>' => '<_c>/<_a>', + ]); } } \ No newline at end of file diff --git a/backend/components/ToggleAction.php b/backend/components/ToggleAction.php new file mode 100644 index 0000000..4c4a191 --- /dev/null +++ b/backend/components/ToggleAction.php @@ -0,0 +1,113 @@ +request->getIsPost()) { + throw new MethodNotAllowedHttpException(); + } + $id = (int)$id; + $result = null; + if (empty($this->modelClass) || !class_exists($this->modelClass)) { + throw new InvalidConfigException("Model class doesn't exist"); + } + /* @var $modelClass \yii\db\ActiveRecord */ + $modelClass = $this->modelClass; + $attribute = $this->attribute; + $model = $modelClass::find()->where([$this->primaryKey => $id]); + if (!empty($this->andWhere)) { + $model->andWhere($this->andWhere); + } + $model = $model->one(); + if (!is_null($this->scenario)) { + $model->scenario = $this->scenario; + } + if (!$model->hasAttribute($this->attribute)) { + throw new InvalidConfigException("Attribute doesn't exist"); + } + if ($model->$attribute == $this->onValue) { + $model->$attribute = $this->offValue; + } elseif ($this->onValue instanceof Expression && $model->$attribute != $this->offValue) { + $model->$attribute = $this->offValue; + } else { + $model->$attribute = $this->onValue; + } + if ($model->save()) { + if ($this->setFlash) { + Yii::$app->session->setFlash('success', $this->flashSuccess); + } + } else { + if ($this->setFlash) { + Yii::$app->session->setFlash('error', $this->flashError); + } + } + if (Yii::$app->request->getIsAjax()) { + Yii::$app->end(); + } + /* @var $controller \yii\web\Controller */ + $controller = $this->controller; + if (!empty($this->redirect)) { + return $controller->redirect($this->redirect); + } + return $controller->redirect(Yii::$app->request->getReferrer()); + } +} \ No newline at end of file diff --git a/backend/components/ToggleColumn.php b/backend/components/ToggleColumn.php new file mode 100644 index 0000000..0a2823c --- /dev/null +++ b/backend/components/ToggleColumn.php @@ -0,0 +1,143 @@ +onText === null) { + $this->onText = Yii::t('main', 'On'); + } + if ($this->offText === null) { + $this->offText = Yii::t('main', 'Off'); + } + if ($this->onValueText === null) { + $this->onValueText = Yii::t('main', 'Active'); + } + if ($this->offValueText === null) { + $this->offValueText = Yii::t('main', 'Inactive'); + } + if ($this->enableAjax) { + $this->registerJs(); + } + } + + /** + * @inheritdoc + */ + protected function renderDataCellContent($model, $key, $index) + { + $url = [$this->action, 'id' => $model->{$this->primaryKey}]; + + $attribute = $this->attribute; + $value = $model->$attribute; + + if ($value === null || $value == true) { + $icon = $this->iconOn; + $title = $this->offText; + $valueText = $this->onValueText; + $color = 'green'; + } else { + $icon = $this->iconOff; + $title = $this->onText; + $valueText = $this->offValueText; + $color = 'red'; + } + return Html::a( + '', + $url, + [ + 'title' => $title, + 'class' => 'toggle-column', + 'style' => 'color:' . $color, + 'data-method' => 'post', + 'data-pjax' => '0', + ] + ) . ( $this->displayValueText ? " {$valueText}" : "" ); + } + + /** + * Registers the ajax JS + */ + public function registerJs() + { + if(Yii::$app->request->isAjax) { + return; + } + $js = <<<'JS' +$(document.body).on("click", "a.toggle-column", function(e) { + e.preventDefault(); + $.post($(this).attr("href"), function(data) { + var pjaxId = $(e.target).closest("[data-pjax-container]").attr("id"); + $.pjax.reload({container:"#" + pjaxId}); + }); + return false; +}); +JS; + $this->grid->view->registerJs($js, View::POS_READY, 'zx-toggle-column'); + } +} \ No newline at end of file diff --git a/backend/config/urlManager.php b/backend/config/urlManager.php index 30a648e..4d4641d 100644 --- a/backend/config/urlManager.php +++ b/backend/config/urlManager.php @@ -12,9 +12,10 @@ return [ '' => 'site/index', '<_a:login|logout>' => 'auth/<_a>', + /* Moved to end of bootstrap - SetUp.php '<_c:[\w\-]+>' => '<_c>/index', '<_c:[\w\-]+>/' => '<_c>/view', '<_c:[\w\-]+>/<_a:[\w-]+>' => '<_c>/<_a>', - '<_c:[\w\-]+>//<_a:[\w\-]+>' => '<_c>/<_a>', + '<_c:[\w\-]+>//<_a:[\w\-]+>' => '<_c>/<_a>',*/ ], ]; diff --git a/backend/controllers/SettingsController.php b/backend/controllers/SettingsController.php new file mode 100644 index 0000000..25b7b2b --- /dev/null +++ b/backend/controllers/SettingsController.php @@ -0,0 +1,150 @@ +service = $service; + } + + public function behaviors() + { + return [ + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + 'access' => [ + 'class' => AccessControl::className(), + 'rules' => [ + [ + 'actions' => ['create','view','index', 'update', 'delete', 'toggle'], + 'allow' => true, + 'roles' => ['SettingsManagement'], + ], + [ // all the action are accessible to admin + 'allow' => true, + 'roles' => ['admin'], + ], + ], + ], + ]; + } + + public function actions() + { + return [ + 'toggle' => [ + 'class' => ToggleAction::className(), + 'modelClass' => Settings::class, + //'setFlash' => true, + ] + ]; + } + + public function actionIndex() + { + $searchModel = new SettingsSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + return $this->render( + 'index', + [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ] + ); + } + + public function actionView($id) + { + return $this->render( + 'view', + [ + 'model' => $this->findModel($id), + ] + ); + } + + public function actionCreate() + { + $form = new SettingsForm(); + if ($form->load(Yii::$app->request->post()) && $form->validate()) { + try { + $settings = $this->service->create($form); + return $this->redirect(['view', 'id' => $settings->id]); + } catch (\DomainException $e) { + Yii::$app->errorHandler->logException($e); + Yii::$app->session->setFlash('error', $e->getMessage()); + } + } + else { + $form->active = 1; + } + return $this->render( + 'create', + [ + 'model' => $form, + ] + ); + } + + public function actionUpdate($id) + { + $settings = $this->findModel($id); + + $form = new SettingsForm($settings); + if ($form->load(Yii::$app->request->post()) && $form->validate()) { + try { + $this->service->edit($settings->id, $form); + return $this->redirect(['view', 'id' => $settings->id]); + } catch (\DomainException $e) { + Yii::$app->errorHandler->logException($e); + Yii::$app->session->setFlash('error', $e->getMessage()); + } + } + return $this->render( + 'update', + [ + 'model' => $form, + 'settings' => $settings, + ] + ); + } + + public function actionDelete($id) + { + $this->service->remove($id); + return $this->redirect(['index']); + } + + protected function findModel($id) + { + if (($model = Settings::findOne($id)) !== null) { + return $model; + } else { + throw new NotFoundHttpException('The requested page does not exist.'); + } + } +} \ No newline at end of file diff --git a/backend/forms/SettingsSearch.php b/backend/forms/SettingsSearch.php new file mode 100644 index 0000000..42f101f --- /dev/null +++ b/backend/forms/SettingsSearch.php @@ -0,0 +1,66 @@ + $query, + ] + ); + if (!($this->load($params) && $this->validate())) { + return $dataProvider; + } + $query->andFilterWhere( + [ + 'id' => $this->id, + 'active' => $this->active, + 'section' => $this->section, + ] + ); + $query->andFilterWhere(['like', 'key', $this->key]) + ->andFilterWhere(['like', 'value', $this->value]); + return $dataProvider; + } + +} \ No newline at end of file diff --git a/backend/messages/ru/buttons.php b/backend/messages/ru/buttons.php index 8038f70..657a957 100644 --- a/backend/messages/ru/buttons.php +++ b/backend/messages/ru/buttons.php @@ -7,4 +7,6 @@ return [ 'Delete' => 'Удалить', 'Edit' => 'Изменить', 'Editing' => 'Редактирование', + 'All Settings' => 'Все настройки', + 'Create Setting' => 'Новый параметр', ]; \ No newline at end of file diff --git a/backend/messages/ru/main.php b/backend/messages/ru/main.php index 0071bde..f5e1cd7 100644 --- a/backend/messages/ru/main.php +++ b/backend/messages/ru/main.php @@ -8,4 +8,20 @@ return [ 'Profile' => 'Профиль', 'Error' => 'Ошибка', 'Return to back or login page please.' => 'Вернитесь назад или авторизуйтесь снова.', + '{attribute} "{value}" already exists for this section.' => '{attribute} "{value}" уже есть в этом разделе.', + '"{attribute}" must be a valid JSON object' => '"{attribute}" должен быть в формате Json', + 'Please select correct type' => 'Укажите правильный тип', + 'Settings' => 'Настройки', + 'Type' => 'Тип', + 'Section' => 'Раздел', + 'Key' => 'Ключ', + 'Value' => 'Значение', + 'Active' => 'Активная', + 'Created At' => 'Создано', + 'Updated At' => 'Обновлено', + 'On' => 'Включить', + 'Off' => 'Выключить', + 'Updating Setting' => 'Редактирование параметра', + 'Editing' => 'Редактирование', + 'Change at your own risk' => 'Редактируйте на свой страх и риск', ]; \ No newline at end of file diff --git a/backend/views/layouts/header.php b/backend/views/layouts/header.php index 9fc4146..24c9ab3 100644 --- a/backend/views/layouts/header.php +++ b/backend/views/layouts/header.php @@ -1,13 +1,16 @@
- APP' . Yii::$app->name . '', Yii::$app->homeUrl, ['class' => 'logo']) ?> + '.(isset(Yii::$app->params['settings']['site']['short_name']) ? Yii::$app->params['settings']['site']['short_name'] : 'APP').'' . (isset(Yii::$app->params['settings']['site']['name']) ? Yii::$app->params['settings']['site']['name'] : Yii::$app->name) . '', Yii::$app->homeUrl, ['class' => 'logo']) ?>