From bce5a6ed17368341aec71a00ee99ff73d15c50bf Mon Sep 17 00:00:00 2001 From: Egorka Date: Tue, 28 Aug 2018 22:02:18 +0300 Subject: [PATCH] SluggableRelationBehavior Module manifest permissions --- backend/views/module/list.php | 6 +- common/modules/languages/forms/LanguageForm.php | 2 + common/modules/languages/messages/ru/languages.php | 1 + .../languages/services/LanguageManageService.php | 1 + .../languages/views/manage/language/_form.php | 10 +- .../languages/views/manage/language/index.php | 5 + .../languages/views/manage/language/view.php | 11 +- .../modules/pages/controllers/PageController.php | 4 +- .../pages/controllers/manage/PageController.php | 4 +- common/modules/pages/entities/Page.php | 15 ++- .../modules/pages/entities/queries/PageQuery.php | 3 + common/modules/pages/manifest.php | 5 + .../pages/repositories/read/PageReadRepository.php | 4 +- common/modules/pages/views/manage/page/_form.php | 30 +++-- core/behaviors/SluggableRelationBehavior.php | 137 +++++++++++++++++++++ core/services/ModuleService.php | 40 +++++- core/services/PermissionManager.php | 9 ++ 17 files changed, 261 insertions(+), 26 deletions(-) create mode 100644 core/behaviors/SluggableRelationBehavior.php diff --git a/backend/views/module/list.php b/backend/views/module/list.php index 6872c8d..212a715 100644 --- a/backend/views/module/list.php +++ b/backend/views/module/list.php @@ -28,16 +28,18 @@ $this->params['breadcrumbs'][] = $this->title; ModuleHelper::addModuleAdminTranslation($module->name); } + $module_name = in_array($module->name, array_keys(Yii::$app->getI18n()->translations)) ? Yii::t($module->name, $module->name) : $module->name; + $module_description = in_array($module->name, array_keys(Yii::$app->getI18n()->translations)) ? Yii::t($module->name, $module->description) : $module->description; ?>
-

name, $module->name) ?>

+

- name, $module->description) ?> +
diff --git a/common/modules/languages/views/manage/language/index.php b/common/modules/languages/views/manage/language/index.php index 290d177..d2622b0 100644 --- a/common/modules/languages/views/manage/language/index.php +++ b/common/modules/languages/views/manage/language/index.php @@ -59,6 +59,11 @@ $this->params['breadcrumbs'][] = $this->title; ], [ 'class' => ActionColumn::class, + 'visibleButtons' => [ + 'delete' => function ($model, $key, $index) { + return $model->default === 1 ? false : true; + } + ], 'options' => ['style' => 'width: 100px;'], 'contentOptions' => ['class' => 'text-center'], ], diff --git a/common/modules/languages/views/manage/language/view.php b/common/modules/languages/views/manage/language/view.php index bc8988f..238f0f5 100644 --- a/common/modules/languages/views/manage/language/view.php +++ b/common/modules/languages/views/manage/language/view.php @@ -3,6 +3,7 @@ use yii\helpers\Html; use yii\widgets\DetailView; use common\modules\languages\entities\Language; +use common\modules\languages\helpers\LanguageHelper; /* @var $this yii\web\View */ /* @var $language Language */ @@ -36,8 +37,14 @@ $this->params['breadcrumbs'][] = $this->title; 'id', 'title', 'name', - 'status', - 'default' + [ + 'attribute' => 'status', + 'format' => 'raw', + 'value' => function(Language $language) { + return LanguageHelper::statusLabel($language->status); + }, + ], + 'default:boolean' ], ]) ?>
diff --git a/common/modules/pages/controllers/PageController.php b/common/modules/pages/controllers/PageController.php index 3913662..ba4afa1 100644 --- a/common/modules/pages/controllers/PageController.php +++ b/common/modules/pages/controllers/PageController.php @@ -62,9 +62,9 @@ class PageController extends FrontendController ]); } - public function actionPreview($id) + public function actionPreview($id, $language = '') { - if (!$page = $this->pages->findPreview($id)) { + if (!$page = $this->pages->findPreview($id, $language)) { throw new NotFoundHttpException('The requested page does not exist.'); } diff --git a/common/modules/pages/controllers/manage/PageController.php b/common/modules/pages/controllers/manage/PageController.php index 8b78d84..85e7cb4 100644 --- a/common/modules/pages/controllers/manage/PageController.php +++ b/common/modules/pages/controllers/manage/PageController.php @@ -85,7 +85,7 @@ class PageController extends Controller ]); } - public function actionCreatePreview() + public function actionCreatePreview($language = '') { $this->service->removePreviews(); @@ -94,7 +94,7 @@ class PageController extends Controller if ($form->load(Yii::$app->request->post()) && $form->validate()) { try { $page = $this->service->create($form, Page::TYPE_PREVIEW); - return $this->redirect(Url::to(Yii::$app->get('frontendUrlManager')->createAbsoluteUrl(['/pages/page/preview', 'id' => $page->id]))); + return $this->redirect(Url::to(Yii::$app->get('frontendUrlManager')->createAbsoluteUrl(['/pages/page/preview', 'id' => $page->id, 'language' => $language]))); } catch (\DomainException $e) { Yii::$app->errorHandler->logException($e); Yii::$app->session->setFlash('error', $e->getMessage()); diff --git a/common/modules/pages/entities/Page.php b/common/modules/pages/entities/Page.php index 15e6851..7f0320c 100644 --- a/common/modules/pages/entities/Page.php +++ b/common/modules/pages/entities/Page.php @@ -4,6 +4,7 @@ namespace common\modules\pages\entities; use common\modules\pages\entities\queries\PageQuery; use core\behaviors\LanguageBehavior; +use core\behaviors\SluggableRelationBehavior; use paulzi\nestedsets\NestedSetsBehavior; use core\behaviors\MetaBehavior; use yii\behaviors\TimestampBehavior; @@ -92,12 +93,6 @@ class Page extends ActiveRecord TimestampBehavior::class, WidgetContentBehavior::class, [ - 'class' => SluggableBehavior::class, - 'attribute' => 'title', - 'ensureUnique' => true, - 'preserveNonEmptyValues' => true, - ], - [ 'class' => LanguageBehavior::class, 'virtualClassName' => 'PagesVirtualTranslate', 'translatedLanguages' => \Yii::$app->params['translatedLanguages'], @@ -106,6 +101,14 @@ class Page extends ActiveRecord 'attributes' => ['title', 'content', 'meta_title', 'meta_description', 'meta_keywords'], 'defaultLanguage' => \Yii::$app->params['defaultLanguage'], ], + [ + //'class' => SluggableBehavior::class, + 'class' => SluggableRelationBehavior::class, + 'attribute' => 'title', + 'relation' => 'translation', + //'ensureUnique' => true, + //'preserveNonEmptyValues' => true, + ], ]; } diff --git a/common/modules/pages/entities/queries/PageQuery.php b/common/modules/pages/entities/queries/PageQuery.php index 13f6200..96a718f 100644 --- a/common/modules/pages/entities/queries/PageQuery.php +++ b/common/modules/pages/entities/queries/PageQuery.php @@ -9,9 +9,12 @@ namespace common\modules\pages\entities\queries; use common\modules\pages\entities\Page; use yii\db\ActiveQuery; +use core\components\LanguageTranslateTrait; class PageQuery extends ActiveQuery { + use LanguageTranslateTrait; + public function typePublic($alias = null) { return $this->andWhere([ diff --git a/common/modules/pages/manifest.php b/common/modules/pages/manifest.php index f894542..a6fdf36 100644 --- a/common/modules/pages/manifest.php +++ b/common/modules/pages/manifest.php @@ -5,4 +5,9 @@ return [ 'name' => 'pages', 'description' => 'Custom pages on site with slug', 'module' => 'PagesModule', + 'permissions' => [ + 'PagesManagement' => [ + 'description' => 'Manage website pages' + ], + ], ]; \ No newline at end of file diff --git a/common/modules/pages/repositories/read/PageReadRepository.php b/common/modules/pages/repositories/read/PageReadRepository.php index d6615ab..3a0108d 100644 --- a/common/modules/pages/repositories/read/PageReadRepository.php +++ b/common/modules/pages/repositories/read/PageReadRepository.php @@ -21,8 +21,8 @@ class PageReadRepository return Page::find()->typePublic()->andWhere(['slug' => $slug])->andWhere(['>', 'depth', 0])->one(); } - public function findPreview($id): ?Page + public function findPreview($id, $language): ?Page { - return Page::find()->andWhere(['id' => $id])->one(); + return $language ? Page::find()->localized($language)->andWhere(['id' => $id])->one() : Page::find()->andWhere(['id' => $id])->one(); } } \ No newline at end of file diff --git a/common/modules/pages/views/manage/page/_form.php b/common/modules/pages/views/manage/page/_form.php index f23ed3f..ec0d36d 100644 --- a/common/modules/pages/views/manage/page/_form.php +++ b/common/modules/pages/views/manage/page/_form.php @@ -81,13 +81,29 @@ $this->registerJs($js2);
- 'btn btn-info', - 'value'=>'preview', - 'name'=>'submit_preview', - 'formaction' => \yii\helpers\Url::to(['/pages/manage/page/create-preview']), - 'formtarget' => '_blank', - ]) ?> + +
+ + + +
+
diff --git a/core/behaviors/SluggableRelationBehavior.php b/core/behaviors/SluggableRelationBehavior.php new file mode 100644 index 0000000..fc56f9d --- /dev/null +++ b/core/behaviors/SluggableRelationBehavior.php @@ -0,0 +1,137 @@ + 'afterUpdate', + ActiveRecord::EVENT_AFTER_INSERT => 'afterInsert', + ]; + } + + public function afterInsert() + { + $this->addSlug(); + } + + public function afterUpdate() + { + if (!$this->owner->{$this->slugAttribute}) { + $this->addSlug(); + } + } + + private function addSlug() + { + /** @var ActiveRecord $owner */ + $owner = $this->owner; + + if (!$this->isNewSlugNeeded()) { + $slug = $owner->{$this->slugAttribute}; + } + else { + if ($this->relation) { + $attribute = $owner->{$this->relation}->{$this->attribute}; + $slug = $this->generateSlug($attribute); + $slug = $this->makeUnique($slug); + } + else { + $attribute = $owner->{$this->attribute}; + $slug = $this->generateSlug($attribute); + $slug = $this->makeUnique($slug); + } + } + $owner->{$this->slugAttribute} = $slug; + $owner->save(); + } + + protected function generateSlug($attribute) + { + return Inflector::slug($attribute); + } + + protected function isNewSlugNeeded() + { + if (empty($this->owner->{$this->slugAttribute})) { + return true; + } + + if (!empty($this->owner->{$this->slugAttribute}) && !$this->slugIfEmpty) { + return true; + } + + return false; + } + + protected function makeUnique($slug) + { + $uniqueSlug = $slug; + $iteration = 0; + while (!$this->validateSlug($uniqueSlug)) { + $iteration++; + $uniqueSlug = $this->generateUniqueSlug($slug, $iteration); + } + return $uniqueSlug; + } + + protected function generateUniqueSlug($baseSlug, $iteration) + { + return $baseSlug . '-' . ($iteration + 1); + } + + protected function validateSlug($slug) + { + /* @var $validator UniqueValidator */ + /* @var $model ActiveRecord */ + $validator = Yii::createObject(array_merge( + [ + 'class' => UniqueValidator::class, + ] + )); + + $model = clone $this->owner; + $model->clearErrors(); + $model->{$this->slugAttribute} = $slug; + + $validator->validateAttribute($model, $this->slugAttribute); + return !$model->hasErrors(); + } +} \ No newline at end of file diff --git a/core/services/ModuleService.php b/core/services/ModuleService.php index a6a825f..d6c5de3 100644 --- a/core/services/ModuleService.php +++ b/core/services/ModuleService.php @@ -10,10 +10,12 @@ use Yii; class ModuleService { private $modules; + private $permission_manager; - public function __construct(ModuleRepository $modules) + public function __construct(ModuleRepository $modules, PermissionManager $permission_manager) { $this->modules = $modules; + $this->permission_manager = $permission_manager; } public function create($name, $class, $type = 'common', $active = ModuleRecord::STATUS_DISABLED): ModuleRecord @@ -29,6 +31,10 @@ class ModuleService public function delete(ModuleRecord $module) { + // connect manifest + $manifest = require Yii::getAlias('@common/modules/' . $module->name . '/manifest.php'); + + // down migrations $migrations = $this->getMigrationFiles($module->name); $migrations = array_reverse($migrations); foreach ($migrations as $migrationPath) { @@ -48,6 +54,12 @@ class ModuleService } } } + + // remove permissions + if (isset($manifest['permissions']) && is_array($manifest['permissions'])) { + $this->removePermissions($manifest['permissions']); + } + // delete files $modulePath = Yii::getAlias('@common/modules/' . $module->name); if (file_exists($modulePath)) { @@ -65,6 +77,9 @@ class ModuleService public function enable(ModuleRecord $module) { + // connect manifest + $manifest = require Yii::getAlias('@common/modules/' . $module->name . '/manifest.php'); + $module->active = ModuleRecord::STATUS_ENABLED; // migration if not exists @@ -88,9 +103,32 @@ class ModuleService } } + // add not exists permissions + if (isset($manifest['permissions']) && is_array($manifest['permissions'])) { + $this->assignPermissions($manifest['permissions']); + } + $this->modules->save($module); } + private function assignPermissions(array $permissions): void + { + foreach ($permissions as $permission => $description) { + if (!$this->permission_manager->permissionExists($permission)) { + $this->permission_manager->create($permission, $description); + } + } + } + + private function removePermissions(array $permissions) + { + foreach ($permissions as $permission => $description) { + if ($this->permission_manager->permissionExists($permission)) { + $this->permission_manager->delete($permission); + } + } + } + private function getMigrationFiles($module) { // migration if not exists diff --git a/core/services/PermissionManager.php b/core/services/PermissionManager.php index 170abcc..52ba320 100644 --- a/core/services/PermissionManager.php +++ b/core/services/PermissionManager.php @@ -113,6 +113,15 @@ class PermissionManager return $permission; } + public function permissionExists($name): bool + { + $am = $this->manager; + if (!$permission = $am->getPermission($name)) { + return false; + } + return true; + } + public function getPermissionsSelectArray() { $data = ArrayHelper::map($this->getPermissions(), 'name', 'description');