Skip to content

Commit

Permalink
added copy pages feature, Web UI and CLI command, tests, Tree model r…
Browse files Browse the repository at this point in the history
…efactored
  • Loading branch information
Christopher Stebe committed Feb 21, 2017
1 parent 0bbc5c8 commit 6706908
Show file tree
Hide file tree
Showing 22 changed files with 618 additions and 50 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,32 @@ On a node you can attach an anchor by using *Advanced URL settings*, with `{'#':

It is recommended to create a new entry in *Tree* mode.


Copy pages
---

**Console config**

```
'controllerMap' => [
'copy-pages' => '\dmstr\modules\pages\commands\CopyController',
]
```

**CLI**

Command: `yii copy-pages/root-node --rootId --destinationLanguage`

**Web UI**

Url: `/pages/copy`

**RBAC permission**

`pages_copy`



Testing
-------

Expand Down
188 changes: 188 additions & 0 deletions commands/CopyController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
<?php
/**
* @link http://www.diemeisterei.de/
* @copyright Copyright (c) 2017 diemeisterei GmbH, Stuttgart
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace dmstr\modules\pages\commands;

use dmstr\modules\pages\models\Tree;
use yii\console\Exception;
use yii\db\Expression;

/**
* Pages module copy command
* @package dmstr\modules\pages\commands
* @author Christopher Stebe <[email protected]>
*/
class CopyController extends \yii\console\Controller
{
/**
* @const string
*/
const DESCRIPTION = "Pages module copy command";

/**
* @var integer
*/
public $rootId;

/**
* @var string
*/
public $destinationLanguage;

/**
* @param string $id
*
* @return array
*/
public function options($id)
{
return array_merge(
parent::options($id),
[
'rootId',
'destinationLanguage',
]
);
}

/**
* @inheritdoc
*/
public function init()
{
parent::init();
}

/**
* Show information about this command
*/
public function actionIndex()
{
$actions = [
$this->id . '/root-node',
];
echo "\n" . self::DESCRIPTION . "\n";
echo "----------------------------------------\n\n";
foreach ($actions as $action) {
echo "yii " . $action . "\n";
}
echo "\n\n";
}

/**
* Copy a root node to another language
*
* @param $rootId
* @param $destinationLanguage
*
* @return bool
*/
public function actionRootNode($rootId, $destinationLanguage)
{
// disable access trait
Tree::$activeAccessTrait = false;

// transaction begin
$transaction = \Yii::$app->db->beginTransaction();

// try copy root node with children
try {
/**
* Find source root node
*
* @var Tree $sourceRootNode
*/
$sourceRootNode = Tree::findOne([Tree::ATTR_ID => $rootId, Tree::ATTR_LVL => Tree::ROOT_NODE_LVL]);
if ($sourceRootNode === null) {
throw new Exception(\Yii::t('pages', 'Root node with ID={ID} not found', ['ID' => $rootId]), 404);
}

/**
* make new root in destination language
*/

// check if not already exists
$newRootNodeExists = Tree::findOne(
[Tree::ATTR_DOMAIN_ID => $sourceRootNode->domain_id, Tree::ATTR_ACCESS_DOMAIN => $destinationLanguage]
);


if ($newRootNodeExists instanceof Tree) {
throw new Exception(
\Yii::t(
'pages',
'Root node with domain_id="{DOMAIN_ID}" and access_domain="{ACCESS_DOMAIN}" already exists',
['DOMAIN_ID' => $sourceRootNode->domain_id, 'ACCESS_DOMAIN' => $destinationLanguage]
), 500
);
}

// make new root node
$newRootNode = new Tree($sourceRootNode->attributes);
$newRootNode->id = null;
$newRootNode->name = str_replace(
$sourceRootNode->access_domain,
$destinationLanguage,
$sourceRootNode->name
);
$newRootNode->access_domain = $destinationLanguage;
$newRootNode->created_at = new Expression('NOW()');
$newRootNode->updated_at = new Expression('NOW()');

// detach nested set behavior to be able to raw insert records
$newRootNode->detachBehavior('tree');
$newRootNode->save();

// set the new page id as root
$newRootNode->root = $newRootNode->id;
$newRootNode->save();


if (!empty($newRootNode->getErrors())) {
throw new Exception(implode(', ', $newRootNode->getErrors()));
}


// make new child leaves in destination language
$childLeaveQuery = Tree::find()->where([Tree::ATTR_ROOT => $sourceRootNode->id]);
$childLeaveQuery->andWhere(['NOT', [Tree::ATTR_ID => $sourceRootNode->id]]);


foreach ($childLeaveQuery->all() as $sourceChildLeave) {
/**
* make new child leave
*
* @var Tree $childLeave
*/
$newChildNode = new Tree($sourceChildLeave->attributes);
$newChildNode->id = null;
$newChildNode->root = $newRootNode->id;
$newChildNode->access_domain = $destinationLanguage;
$newChildNode->created_at = new Expression('NOW()');
$newChildNode->updated_at = new Expression('NOW()');

// detach nested set behavior to be able to raw insert records
$newChildNode->detachBehavior('tree');
$newChildNode->save();

if (!empty($newChildNode->getErrors())) {
throw new Exception(implode(', ', $newRootNode->getErrors()));
}
}

// Success
$this->stdout('"' . Tree::optsSourceRootId()[$rootId] . '" successfully copied to language "' . $destinationLanguage . '"');
$transaction->commit();
\Yii::$app->end();
} catch (Exception $e) {
$transaction->rollBack();
$this->stderr($e->getMessage());
\Yii::$app->end(1);
}
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"devgroup/yii2-jsoneditor": "1.0.*",
"dmstr/yii2-web": "~0.1",
"dmstr/yii2-db": "0.8.0-rc4 as 0.7.999",
"bedezign/yii2-audit": "^1.0"
"bedezign/yii2-audit": "^1.0",
"mikehaertl/php-shellcommand": "^1.2.4"
},
"autoload": {
"psr-4": {
Expand Down
66 changes: 66 additions & 0 deletions controllers/CopyController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* @link http://www.diemeisterei.de/
* @copyright Copyright (c) 2017 diemeisterei GmbH, Stuttgart
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace dmstr\modules\pages\controllers;

use dmstr\modules\pages\models\forms\CopyForm;
use mikehaertl\shellcommand\Command;
use rmrevin\yii\fontawesome\AssetBundle;
use yii\helpers\Url;
use yii\web\Controller;


/**
* Class CopyController
* @package dmstr\modules\pages\controllers
* @author Christopher Stebe <[email protected]>
*/
class CopyController extends Controller
{
/**
* @var string
*/
public $defaultAction = 'root-node';

/**
* @inheritdoc
*/
public function init()
{
parent::init();

// Register font-awesome asset bundle
AssetBundle::register(\Yii::$app->view);
}

/**
* @return string
*/
public function actionRootNode()
{
Url::remember();

$model = new CopyForm();
if ($model->load(\Yii::$app->request->post()) && $model->validate()) {

// RUN copy-pages cli command
$command = new Command('yii copy-pages/root-node');
$command->addArg('--rootId', $model->sourceRootId);
$command->addArg('--destinationLanguage', $model->destinationLanguage);
if ($command->execute() && empty($command->getError())) {
\Yii::$app->session->setFlash('success', $command->getOutput());
} else {
\Yii::$app->session->setFlash('danger', $command->getError());
}

return $this->refresh();
}
return $this->render('root-node', ['copyForm' => $model]);
}
}
24 changes: 24 additions & 0 deletions migrations/m170220_121800_auth_items.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

use yii\db\Migration;

class m170220_121800_auth_items extends Migration
{
public function up()
{
$auth = Yii::$app->authManager;

if ($auth) {
$permission = $auth->createPermission('pages_copy');
$permission->description = 'Pages Copy';
$auth->add($permission);
}
}

public function down()
{
echo "m170220_121800_auth_items cannot be reverted.\n";

return false;
}
}
22 changes: 15 additions & 7 deletions models/BaseTree.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ class BaseTree extends \kartik\tree\models\Tree
*/
const ATTR_ROOT = 'root';

/**
* Column attribute 'lvl'
*/
const ATTR_LVL = 'lvl';

/**
* Column attribute 'route'
*/
Expand Down Expand Up @@ -199,6 +204,11 @@ class BaseTree extends \kartik\tree\models\Tree
*/
const GLOBAL_ACCESS_PERMISSION = 'pages.globalAccess';

/**
* RBAC permission name to copy page root nodes
*/
const COPY_ACCESS_PERMISSION = 'pages_copy';

/**
* Virtual attribute generated from "domain_id"_"access_domain".
*
Expand All @@ -224,11 +234,6 @@ public function init()
if (null === $this->module = \Yii::$app->getModule(PagesModule::NAME)) {
throw new HttpException(404, 'Module "' . PagesModule::NAME . '" not found in ' . __METHOD__);
}

// add AuditTrailBehavior
if (!YII_ENV_TEST) {
$this->attachBehavior('audit', 'bedezign\yii2\audit\AuditTrailBehavior');
}
}

/**
Expand Down Expand Up @@ -273,7 +278,10 @@ public function behaviors()
return ArrayHelper::merge(
parent::behaviors(),
[
[
'audit' => [
'class' => 'bedezign\yii2\audit\AuditTrailBehavior'
],
'timestamp' =>[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
Expand All @@ -294,7 +302,7 @@ public function rules()
[
'domain_id',
'default',
'value' => function ($model) {
'value' => function () {
return uniqid();
}
],
Expand Down
Loading

0 comments on commit 6706908

Please sign in to comment.