Skip to content

Commit 1758dd1

Browse files
committed
Initial commit
0 parents  commit 1758dd1

File tree

11 files changed

+603
-0
lines changed

11 files changed

+603
-0
lines changed

LICENSE.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Yii 2 Tree extension for Yii 2 framework is free software.
2+
It is released under the terms of the following BSD License.
3+
4+
Copyright © 2015, Alexey Rogachev (https://github.com/arogachev)
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice, this
11+
list of conditions and the following disclaimer.
12+
13+
* Redistributions in binary form must reproduce the above copyright notice,
14+
this list of conditions and the following disclaimer in the documentation
15+
and/or other materials provided with the distribution.
16+
17+
* Neither the name of test nor the names of its
18+
contributors may be used to endorse or promote products derived from
19+
this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Yii 2 Tree
2+
3+
Database tree structures management for Yii 2 framework

composer.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "arogachev/yii2-tree",
3+
"description": "Database tree structures management for Yii 2 framework",
4+
"keywords": [
5+
"yii2",
6+
"tree",
7+
"nested set",
8+
"nested sets",
9+
"widget",
10+
"active record"
11+
],
12+
"homepage": "https://github.com/arogachev/yii2-tree",
13+
"type": "yii2-extension",
14+
"license": "BSD-3-Clause",
15+
"authors": [
16+
{
17+
"name": "Alexey Rogachev",
18+
"email": "arogachev90@gmail.com"
19+
}
20+
],
21+
"require": {
22+
"yiisoft/yii2": "*",
23+
"bower-asset/jstree": "*"
24+
},
25+
"autoload": {
26+
"psr-4": {
27+
"arogachev\\tree\\": "src"
28+
}
29+
}
30+
}

src/assets/JsTreeAsset.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace arogachev\tree\assets;
4+
5+
use yii\web\AssetBundle;
6+
7+
class JsTreeAsset extends AssetBundle
8+
{
9+
/**
10+
* @inheritdoc
11+
*/
12+
public $sourcePath = '@bower/jstree/dist';
13+
14+
/**
15+
* @inheritdoc
16+
*/
17+
public $js = [
18+
'jstree.min.js',
19+
];
20+
21+
/**
22+
* @inheritdoc
23+
*/
24+
public $css = [
25+
'themes/default/style.min.css',
26+
];
27+
28+
/**
29+
* @inheritdoc
30+
*/
31+
public $depends = [
32+
'yii\web\JqueryAsset',
33+
];
34+
}

src/assets/TreeAsset.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace arogachev\tree\assets;
4+
5+
use yii\web\AssetBundle;
6+
7+
class TreeAsset extends AssetBundle
8+
{
9+
/**
10+
* @inheritdoc
11+
*/
12+
public $sourcePath = '@vendor/arogachev/yii2-tree/src/assets/src';
13+
14+
/**
15+
* @inheritdoc
16+
*/
17+
public $publishOptions = [
18+
'forceCopy' => YII_DEBUG,
19+
];
20+
21+
/**
22+
* @inheritdoc
23+
*/
24+
public $js = [
25+
'tree.js',
26+
];
27+
28+
/**
29+
* @inheritdoc
30+
*/
31+
public $depends = [
32+
'yii\web\YiiAsset',
33+
'arogachev\assets\JsTreeAsset',
34+
];
35+
}

src/assets/src/tree.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
yii.tree = (function($) {
2+
var pub = {
3+
modelClass: undefined,
4+
5+
createNode: function(event, target) {
6+
$.post(
7+
'/tree/append-to',
8+
{
9+
modelClass: pub.modelClass,
10+
parentPk: target.parent
11+
},
12+
function(data) {
13+
$(event.target).jstree('set_id', target.node, data.pk);
14+
}
15+
);
16+
},
17+
18+
renameNode: function(event, target) {
19+
if (target.text != target.old) {
20+
$.post(
21+
'/tree/rename',
22+
{
23+
modelClass: pub.modelClass,
24+
modelPk: target.node.id,
25+
name: target.text
26+
}
27+
);
28+
}
29+
},
30+
31+
moveNode: function(event, target) {
32+
var tree = $(event.target);
33+
var prevPk = tree.jstree('get_prev_dom', target.node).attr('id');
34+
var nextPk = tree.jstree('get_next_dom', target.node).attr('id');
35+
36+
if (target.old_parent != target.parent) {
37+
$.post(
38+
'/tree/append-to',
39+
{
40+
modelClass: pub.modelClass,
41+
parentPk: target.parent,
42+
modelPk: target.node.id
43+
}
44+
);
45+
46+
return;
47+
}
48+
49+
if (prevPk) {
50+
$.post(
51+
'/tree/insert-after',
52+
{
53+
modelClass: pub.modelClass,
54+
modelPk: target.node.id,
55+
prevModelPk: prevPk
56+
}
57+
);
58+
} else if (nextPk) {
59+
$.post(
60+
'/tree/insert-before',
61+
{
62+
modelClass: pub.modelClass,
63+
modelPk: target.node.id,
64+
nextModelPk: nextPk
65+
}
66+
);
67+
}
68+
},
69+
70+
deleteNode: function(event, target) {
71+
$.post(
72+
'/tree/delete',
73+
{
74+
modelClass: pub.modelClass,
75+
modelPk: target.node.id
76+
}
77+
);
78+
}
79+
};
80+
81+
return pub;
82+
})(jQuery);

src/controllers/TreeController.php

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
3+
namespace arogachev\tree\controllers;
4+
5+
use arogachev\tree\helpers\NestedSetsHelper;
6+
use Yii;
7+
use yii\db\ActiveRecord;
8+
use yii\filters\ContentNegotiator;
9+
use yii\web\BadRequestHttpException;
10+
use yii\web\Controller;
11+
use yii\web\ForbiddenHttpException;
12+
use yii\web\NotFoundHttpException;
13+
use yii\web\Response;
14+
15+
class TreeController extends Controller
16+
{
17+
/**
18+
* @inheritdoc
19+
*/
20+
public function behaviors()
21+
{
22+
return [
23+
[
24+
'class' => ContentNegotiator::className(),
25+
'formats' => [
26+
'application/json' => Response::FORMAT_JSON,
27+
],
28+
],
29+
];
30+
}
31+
32+
/**
33+
* @inheritdoc
34+
*/
35+
public function beforeAction($action)
36+
{
37+
if (!parent::beforeAction($action)) {
38+
return false;
39+
}
40+
41+
if (!Yii::$app->request->isAjax) {
42+
throw new ForbiddenHttpException('This page is not allowed for view.');
43+
}
44+
45+
return true;
46+
}
47+
48+
/**
49+
* @return array
50+
*/
51+
public function actionGetTree()
52+
{
53+
return NestedSetsHelper::getHierarchicalArray(Yii::$app->request->get('modelClass'));
54+
}
55+
56+
/**
57+
* @return array
58+
* @throws BadRequestHttpException
59+
* @throws NotFoundHttpException
60+
*/
61+
public function actionAppendTo()
62+
{
63+
$parent = $this->getModel('parentPk');
64+
$model = $this->getModel(null, true);
65+
$model->appendTo($parent);
66+
67+
return ['pk' => $model->primaryKey];
68+
}
69+
70+
/**
71+
* @throws BadRequestHttpException
72+
* @throws NotFoundHttpException
73+
*/
74+
public function actionRename()
75+
{
76+
$model = $this->getModel();
77+
$model->name = Yii::$app->request->post('name');
78+
$model->save(false);
79+
}
80+
81+
/**
82+
* @throws BadRequestHttpException
83+
* @throws NotFoundHttpException
84+
* @throws \Exception
85+
*/
86+
public function actionDelete()
87+
{
88+
$this->getModel()->deleteWithChildren();
89+
}
90+
91+
/**
92+
* @throws BadRequestHttpException
93+
* @throws NotFoundHttpException
94+
*/
95+
public function actionInsertBefore()
96+
{
97+
$model = $this->getModel();
98+
$prevModel = $this->getModel('nextModelPk');
99+
$model->insertBefore($prevModel);
100+
}
101+
102+
/**
103+
* @throws BadRequestHttpException
104+
* @throws NotFoundHttpException
105+
*/
106+
public function actionInsertAfter()
107+
{
108+
$model = $this->getModel();
109+
$nextModel = $this->getModel('prevModelPk');
110+
$model->insertAfter($nextModel);
111+
}
112+
113+
/**
114+
* @param null|string $paramName
115+
* @param boolean $createIfNotFound
116+
* @return \yii\db\ActiveRecord|\creocoder\nestedsets\NestedSetsBehavior
117+
* @throws BadRequestHttpException
118+
* @throws NotFoundHttpException
119+
*/
120+
protected function getModel($paramName = null, $createIfNotFound = false)
121+
{
122+
$modelClass = Yii::$app->request->post('modelClass');
123+
if (!$modelClass) {
124+
throw new BadRequestHttpException('Model class must be specified in order to find model.');
125+
}
126+
127+
$pk = Yii::$app->request->post($paramName ?: 'modelPk');
128+
if (!$pk && !$createIfNotFound) {
129+
throw new BadRequestHttpException('Model primary key must be specified in order to find model.');
130+
}
131+
132+
if (!$createIfNotFound) {
133+
$model = $modelClass::findOne($pk);
134+
if (!$model) {
135+
throw new NotFoundHttpException('Model not found.');
136+
}
137+
} else {
138+
$model = new $modelClass;
139+
}
140+
141+
if (!($model instanceof ActiveRecord)) {
142+
throw new BadRequestHttpException('Valid ActiveRecord model class must be specified.');
143+
}
144+
145+
return $model;
146+
}
147+
}

0 commit comments

Comments
 (0)