Browse Source

SluggableRelationBehavior

Module manifest permissions
master
Egorka 6 years ago
parent
commit
bce5a6ed17
  1. 6
      backend/views/module/list.php
  2. 2
      common/modules/languages/forms/LanguageForm.php
  3. 1
      common/modules/languages/messages/ru/languages.php
  4. 1
      common/modules/languages/services/LanguageManageService.php
  5. 10
      common/modules/languages/views/manage/language/_form.php
  6. 5
      common/modules/languages/views/manage/language/index.php
  7. 11
      common/modules/languages/views/manage/language/view.php
  8. 4
      common/modules/pages/controllers/PageController.php
  9. 4
      common/modules/pages/controllers/manage/PageController.php
  10. 15
      common/modules/pages/entities/Page.php
  11. 3
      common/modules/pages/entities/queries/PageQuery.php
  12. 5
      common/modules/pages/manifest.php
  13. 4
      common/modules/pages/repositories/read/PageReadRepository.php
  14. 30
      common/modules/pages/views/manage/page/_form.php
  15. 137
      core/behaviors/SluggableRelationBehavior.php
  16. 40
      core/services/ModuleService.php
  17. 9
      core/services/PermissionManager.php

6
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;
?>
<div class="col-md-4">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title"><i class="fa fa-power-off" aria-hidden="true" style="color: <?= $color ?>"></i> <?= Yii::t($module->name, $module->name) ?></h3>
<h3 class="box-title"><i class="fa fa-power-off" aria-hidden="true" style="color: <?= $color ?>"></i> <?= $module_name ?></h3>
</div>
<div class="box-body">
<?= Yii::t($module->name, $module->description) ?>
<?= $module_description ?>
</div>
<div class="box-footer" style="text-align: right">
<?php if ($module->isEnabled()): ?>

2
common/modules/languages/forms/LanguageForm.php

@ -20,6 +20,8 @@ class LanguageForm extends Model
$this->name = $language->name;
$this->title = $language->title;
$this->status = $language->status;
$this->_language = $language;
}
parent::__construct($config);
}

1
common/modules/languages/messages/ru/languages.php

@ -14,4 +14,5 @@ return [
'Draft' => 'Отключен',
'Publish' => 'Публикация',
'Are you sure you want to set this language as default?' => 'Вы действительно хотите сделать этот язык основным?',
'Status for default language is active always' => 'Статус для основного языка: всегда включен',
];

1
common/modules/languages/services/LanguageManageService.php

@ -49,6 +49,7 @@ class LanguageManageService
{
$this->repository->clearDefaults();
$language->default = Language::DEFAULT_TRUE;
$language->status = Language::STATUS_ACTIVE;
$this->repository->save($language);
}
}

10
common/modules/languages/views/manage/language/_form.php

@ -58,8 +58,14 @@ $this->registerJs($js2);
<div class="box-header with-border"><?= Yii::t('languages', 'Publish') ?></div>
<div class="box-body">
<?= $form->field($model, 'status')->radioList(LanguageHelper::statusList()) ?>
<?php if (!$model->_language->default): ?>
<?= $form->field($model, 'status')->radioList(LanguageHelper::statusList()) ?>
<?php else: ?>
<div class="callout callout-danger">
<p><?= Yii::t('languages', 'Status for default language is active always') ?></p>
</div>
<?php endif; ?>
</div>
</div>
</div>

5
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'],
],

11
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'
],
]) ?>
</div>

4
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.');
}

4
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());

15
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,
],
];
}

3
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([

5
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'
],
],
];

4
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();
}
}

30
common/modules/pages/views/manage/page/_form.php

@ -81,13 +81,29 @@ $this->registerJs($js2);
<div class="box box-default">
<div class="box-header with-border"><?= Yii::t('pages', 'Publish') ?></div>
<div class="box-body">
<?= Html::submitButton(Yii::t('pages', 'Preview on site'), [
'class' => 'btn btn-info',
'value'=>'preview',
'name'=>'submit_preview',
'formaction' => \yii\helpers\Url::to(['/pages/manage/page/create-preview']),
'formtarget' => '_blank',
]) ?>
<div class="btn-group">
<button type="button" class="btn btn-info"><?= Yii::t('pages', 'Preview on site') ?></button>
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<?php foreach (Yii::$app->params['translatedLanguages'] as $language => $language_name): ?>
<li>
<?= Html::submitButton($language_name, [
'class' => 'btn btn-block btn-flat bg-white',
'value'=>'preview',
'name'=>'submit_preview',
'formaction' => \yii\helpers\Url::to(['/pages/manage/page/create-preview', 'language' => $language == Yii::$app->params['defaultLanguage'] ? '' : $language]),
'formtarget' => '_blank',
'style' => 'border:0; background-color:#ffffff;',
]) ?>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
</div>

137
core/behaviors/SluggableRelationBehavior.php

@ -0,0 +1,137 @@
<?php
/**
* Created by Error202
* Date: 28.08.2018
*/
namespace core\behaviors;
use yii\base\Behavior;
use yii\db\ActiveRecord;
use yii\validators\UniqueValidator;
use yii\helpers\Inflector;
use Yii;
class SluggableRelationBehavior extends Behavior
{
/**
* Source attribute for generate slug
* @var string
*/
public $attribute;
/**
* Field name for slug
* @var string
*/
public $slugAttribute = 'slug';
/**
* Relation name, if attribute from relative table
* @var string
*/
public $relation;
/**
* Generate slug if slugAttribute is empty
* @var bool
*/
public $slugIfEmpty = true;
public function events()
{
return [
ActiveRecord::EVENT_AFTER_UPDATE => '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();
}
}

40
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

9
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');

Loading…
Cancel
Save