From 9e9274207b4b24368070c20863a413ef4c400fa0 Mon Sep 17 00:00:00 2001 From: Pavel Bariev Date: Tue, 22 Jul 2014 18:50:26 +0400 Subject: [PATCH] renewed tree behavior --- ARTreeBehavior.php | 246 ++++++++++++++--------------------- PTARBehavior.php | 95 -------------- actions/TreeAction.php | 20 --- actions/TreeCreateAction.php | 15 --- actions/TreeDeleteAction.php | 19 --- actions/TreeMoveAction.php | 6 +- actions/TreeUpdateAction.php | 6 +- views/_simple.php | 2 +- 8 files changed, 108 insertions(+), 301 deletions(-) delete mode 100755 PTARBehavior.php delete mode 100755 actions/TreeAction.php delete mode 100755 actions/TreeCreateAction.php delete mode 100755 actions/TreeDeleteAction.php mode change 100755 => 100644 actions/TreeUpdateAction.php diff --git a/ARTreeBehavior.php b/ARTreeBehavior.php index 872c673..2beae67 100755 --- a/ARTreeBehavior.php +++ b/ARTreeBehavior.php @@ -1,9 +1,15 @@ 'afterSave', - ActiveRecord::EVENT_AFTER_UPDATE => 'afterSave', + ActiveRecord::EVENT_BEFORE_INSERT => 'beforeInsert', ActiveRecord::EVENT_AFTER_DELETE => 'afterDelete', ]; } - + + public function beforeInsert() + { + $this->set('rank', $this->getLastRank() + 1); + $this->createUrl(); + } + + public function afterDelete() + { + $this->treeResort($this->get('rank'), -1); + $this->owner->deleteAll($this->getDescendantCondition()); + } + + + /* MENU WIDGET */ + + public function menuWidget($view='node', $attributes=array(), $return=false) + { + $items = $this->childrenTree($attributes); + $behavior = $this; + $widget = new ARTreeMenuWidget(compact('view', 'items', 'behavior'), $return); + return $widget->run(); + } + public function nodeAttributes($model = false, $pid = '') { $uniqueKey = self::$uniqueKey++; @@ -47,92 +78,19 @@ public function nodeAttributes($model = false, $pid = '') ) ); } - - public function getJsTree() - { - $tree = $this->childrenTree(); - foreach ($tree as $key=>$data){ - $tree[$key] = $this->setJsData($data); - } - return reset($tree); - } - - private function setJsData($data) - { - $result = $this->nodeAttributes($data['model']); - foreach($data['children'] as $child){ - $result['children'][] = $this->setJsData($child); - } - return $result; - } - - public function getParent() - { - return $this->owner->findOne(array( - $this->id => $this->get('parent_id') - )); - } - - public function getParentsCriteria($addCriteria = array()) - { - $query = new CDbCriteria(); - $urls = array(); - while($this->url){ - $urls[] = $this->url = preg_replace('/(\d+)?\/$/','',$this->url); - } - $query->addInCondition('url', $urls ? $urls : array(0)); - $query->mergeWith($addCriteria); - return $query; - } - - public function getChildren($addCriteria=array()) - { - if($this->owner->isNewRecord){ - return array(); - } - $query = new CDbCriteria(); - $query->order = $this->rank; - $query->addColumnCondition(array($this->parent_id => $this->owner->primaryKey)) - ->mergeWith($addCriteria); - return $this->find($query, true); - } - - public function getDescendants($query) - { - return $query->andWhere($this->getDescendantCondition())->all(); - } - public function getDescendantCondition() - { - if(!$url = $this->get('url')){ - $url = '/'; - } - return ['like', 'url', $url]; - } - - public function menuWidget($view='node', $attributes=array(), $return=false) - { - $items = $this->childrenTree($attributes); - $behavior = $this; - $widget = new ARTreeMenuWidget(compact('view', 'items', 'behavior'), $return); - return $widget->run(); - } - - - /* TREE SERVICE */ + /* TREE BUILD */ - public function childrenTree($attributes=array()) + public function childrenTree($conditions = array()) { - $query = $this->owner->find(); - if($attributes){ - $query->andFilterWhere($attributes); - } - $items = $this->getDescendants($query); + $items = $this->owner->find()->where( + array_merge($this->getDescendantCondition(), $conditions) + )->all(); return $this->toTree($items); } - public function toTree($items) + protected function toTree($items) { $id = $this->id; $result = array(); @@ -168,90 +126,84 @@ private function rangeTree($items) return $result; } - public function cloneTo($pid) - { - $className = get_class($this->owner); - $new = new $className; - $new->attributes = $this->owner->attributes; - $this->ownerBehavior($new)->move($pid); - foreach($this->getChildren() as $child){ - $this->ownerBehavior($child)->cloneTo($new->id); - } - return true; - } - - /* SYSTEM SERVICE */ + /* TREE UPDATE */ - public function createUrl() + protected function createUrl() { - $model = $this->owner; $oldUrl = $this->get('url'); - $newUrl = (($parent = $this->getParent()) ? $this->ownerBehavior($parent)->get('url') : '/') - . $this->get('name') . "/"; + $newUrl = (($parent = $this->getParent()) ? $parent->{$this->url} : '/') . $this->get('slug') . "/"; if($newUrl == $oldUrl){ - return true; + return false; } - if($oldUrl && $this->get('parent_id')){ - \Yii::$app->db->createCommand(" - UPDATE {$model->tableName()} + if (!$this->get('parent_id')) { + return $this->set('slug', ''); + } + return ($oldUrl) + ? \Yii::$app->db->createCommand(" + UPDATE {$this->owner->tableName()} SET {$this->url} = REPLACE({$this->url}, '{$oldUrl}', '{$newUrl}') WHERE {$this->url} LIKE '{$oldUrl}%' - ")->execute(); - } - $attributes = $this->get('parent_id') - ? [$this->url => $newUrl] - : [$this->name => '']; - return $model->updateAll($attributes, ['id'=>$model->primaryKey]); + ")->execute() + : $this->set('url', $newUrl); } - public function move($pid, $position=false) + public function treeMove($pid, $rank = false) { - if($position === false){ - $position = ($lastChild = $this->owner->findOne(array( - $this->parent_id => $pid - ), array( - 'order' => 'rank DESC', - 'condition' => 'id != '.$this->get('id') * 1 - ))) ? $lastChild->rank+1 : 0; + if ($rank === false) { + $rank = $this->getLastRank() + 1; } - return $this->treeResort(-1) // resort old parent children - ->set('rank', $position) - ->set('parent_id', $pid) - ->treeResort() // resort new parent children - ->owner->save(false); + $selfShift = ($pid == $this->get('parent_id')) && ($rank > $this->get('rank')); + $this->treeResort($this->get('rank'), -1); + $this->set('parent_id', $pid)->createUrl(); + $this->treeResort($rank - ($selfShift ? 0 : 1), 1); + return $this->owner->updateAttributes([ + $this->parent_id => $pid, + $this->rank => $rank + ]); } - private function treeResort($increment = 1) + private function treeResort($rank = 0, $increment = 1) { - if(!$pid = $this->get('parent_id')){ - return $this; - }; - $condition = "{$this->parent_id} = {$pid} - AND {$this->rank} >= {$this->get('rank')}" - . (($id = $this->get('id')) ? " AND id != {$id}" : ""); - \Yii::$app->db->createCommand(" - UPDATE {$this->owner->tableName()} SET {$this->rank} = ({$this->rank}+{$increment}) - WHERE {$condition} - ")->execute(); - return $this; + return $this->owner->updateAllCounters( + ['rank' => $increment], + "{$this->parent_id} = :parent_id AND rank > :rank", + [':rank' => $rank, ':parent_id' => $this->get('parent_id')] + ); + } + + + /* GETTERS */ + + protected function getParent() + { + return $this->owner->findOne(array( + $this->id => $this->get('parent_id') + )); } - - - /* SYSTEM */ - public static function afterSave($event) + protected function getDescendantCondition() { - $behavior = self::fromEvent($event); - if($behavior->attributesChanged(array('parent_id'))){ - $behavior->createUrl(); + if(!$url = $this->get('url')){ + $url = '/'; } + return ['like', 'url', $url]; + } + + protected function get($attributeName) + { + return $this->owner->{$this->$attributeName}; + } + + protected function set($attributeName, $value) + { + $this->owner->{$this->$attributeName} = $value; + return $this; } - public static function afterDelete($event) + protected function getLastRank() { - $behavior = self::fromEvent($event); - $behavior->treeResort(-1); - $behavior->owner->deleteAll($behavior->getDescendantCondition()); + $max = $this->owner->find()->where([$this->parent_id => $this->get('parent_id')])->max($this->rank); + return is_numeric($max) ? $max : -1; } } \ No newline at end of file diff --git a/PTARBehavior.php b/PTARBehavior.php deleted file mode 100755 index 9353369..0000000 --- a/PTARBehavior.php +++ /dev/null @@ -1,95 +0,0 @@ -owner->getCommandBuilder() - ->createFindCommand($this->owner->tableSchema, $criteria) - ->$get() - : $this->owner->$get($criteria); - } - - protected function get($attributeName) - { - return $this->owner->{$this->attr($attributeName)}; - } - - protected function getAll($attributeNames) - { - $result = array(); - foreach($attributeNames as $attributeName){ - $result[$attributeName] = $this->get($attributeName); - } - return $result; - } - - protected function set($attributeName, $value) - { - $this->owner->{$this->attr($attributeName)} = $value; - return $this; - } - - public function attr($attributeName) - { - return isset($this->$attributeName) ? $this->$attributeName : $attributeName; - } - - public function attributesChanged($attributes) - { - foreach($attributes as $attribute){ - if($this->get($attribute) !== $this->owner->getOldAttribute($attribute)){ - return true; - } - } - return false; - } - /** - * gets name of the behavior, listing its owner behaviors - * and comparing ro itself - * @return string name of this behavior - */ - public function getName() - { - return array_search($this, $this->owner->getBehaviors()); - } - /** - * refreshes its attributes from owner behavior method data - * @return \ActiveRecordBehavior this - */ - public function refresh() - { - $behaviors = $this->owner->behaviors(); - $settings = $behaviors[$this->getName()]; - foreach($settings as $attribute=>$value){ - if(in_array($attribute, array('class'))){ - continue; - } - $this->$attribute = $value; - } - return $this; - } - - public static function fromEvent($event) - { - $className = get_called_class(); - $model = new $className(); - $model->attach($event->sender); - return $model; - } - - public function ownerBehavior($owner) - { - return $owner->getBehavior($this->getName()); - } -} \ No newline at end of file diff --git a/actions/TreeAction.php b/actions/TreeAction.php deleted file mode 100755 index 5b15cc7..0000000 --- a/actions/TreeAction.php +++ /dev/null @@ -1,20 +0,0 @@ -getBehavior('nodeTree')->getBranch())); - \Yii::$app->end(); - } - - protected function printTree($node) - { - header('Content-type: application/json'); - echo json_encode(array($node->getBehavior('nodeTree')->getJsTree())); - \Yii::$app->end(); - } -} \ No newline at end of file diff --git a/actions/TreeCreateAction.php b/actions/TreeCreateAction.php deleted file mode 100755 index f2647db..0000000 --- a/actions/TreeCreateAction.php +++ /dev/null @@ -1,15 +0,0 @@ -controller->findModel(); - $model->scenario = 'nodeTree'; - $post = ["Item" => \Yii::$app->request->post()['attributes']]; - if($model->load($post) && $model->getBehavior('nodeTree')->move($id)){ - echo json_encode($model->getBehavior('nodeTree')->nodeAttributes()); - } - } -} \ No newline at end of file diff --git a/actions/TreeDeleteAction.php b/actions/TreeDeleteAction.php deleted file mode 100755 index 80f271a..0000000 --- a/actions/TreeDeleteAction.php +++ /dev/null @@ -1,19 +0,0 @@ -controller->findModel($id); - if(!$model->isNewRecord && $model->delete()){ - \Yii::$app->session->setFlash('success', 'Removed.'); - } - if (!\Yii::$app->request->isAjax) { - $this->controller->redirect($pid - ? array('read', 'id'=>$pid) - : array('index') - ); - } - } -} diff --git a/actions/TreeMoveAction.php b/actions/TreeMoveAction.php index 620d041..29786c4 100755 --- a/actions/TreeMoveAction.php +++ b/actions/TreeMoveAction.php @@ -2,12 +2,14 @@ namespace bariew\nodeTree\actions; -class TreeMoveAction extends TreeAction +use yii\base\Action; + +class TreeMoveAction extends Action { public function run($id) { $model = $this->controller->findModel($id); - if(!$model->getBehavior('nodeTree')->move($_POST['pid'], $_POST['position'])){ + if(!$model->treeMove($_POST['pid'], $_POST['position'])){ throw new \yii\web\HttpException(400, "Could not save changes"); } } diff --git a/actions/TreeUpdateAction.php b/actions/TreeUpdateAction.php old mode 100755 new mode 100644 index c2a87f0..2cc31cf --- a/actions/TreeUpdateAction.php +++ b/actions/TreeUpdateAction.php @@ -2,7 +2,9 @@ namespace bariew\nodeTree\actions; -class TreeUpdateAction extends TreeAction +use yii\base\Action; + +class TreeUpdateAction extends Action { public function run($id) { @@ -10,6 +12,6 @@ public function run($id) if(($model->attributes = @$_POST['attributes']) && !$model->save()){ throw new \yii\web\HttpException(400, "Model not saved"); } - echo json_encode($model->getBehavior('nodeTree')->nodeAttributes()); + echo json_encode($model->nodeAttributes()); } } \ No newline at end of file diff --git a/views/_simple.php b/views/_simple.php index f245cd2..57909c6 100755 --- a/views/_simple.php +++ b/views/_simple.php @@ -7,7 +7,7 @@ 'data-jstree' => json_encode(array( "opened" => strpos($activeId, $id) === 0, "selected" => $activeId == $id, - "type" => 'folder' + "type" => $items ? 'folder' : 'file' )) )); echo \yii\helpers\Html::a($item, '#', ['data-id' => $id]);