creocoder / yii2-nested-sets

The nested sets behavior for the Yii framework.
Other
446 stars 129 forks source link

Upgrading from yii1 to yii2 nested set behaviour #55

Closed gb5256 closed 9 years ago

gb5256 commented 9 years ago

Hello, I have an app that I move into yii2. I am already using nested set (for yii1). In your old version, tree was called root, and also my table is set up this way. I do not want to change the table, as lots of other things need the column root. I thought, that changing this would do the trick:

public function behaviors() {
    return [
        'class' => NestedSetsBehavior::className(),
              'treeAttribute' => 'root', \\ this is 'tree' by your default
            // 'leftAttribute' => 'lft',
            // 'rightAttribute' => 'rgt',
             'depthAttribute' => 'level',
    ];
}

But this throws an error: Class root does not exist

Do I have to change the attribute name some where else? thanks again, gb5256

creocoder commented 9 years ago

This change is enough. If you plan upgrade from Yii 1 version you also need update level column values to level - 1.

Class root does not exist

This can't be caused be behavior. Can you show your model dump?

gb5256 commented 9 years ago

after some testing, I found out that it happens when I then want to go like /controller/view/15. So actually for all actions that GII has created. At your extension for Yii1 there it was necessary to remove all validations from the rules. Is this necessary for this yii2 too?

creocoder commented 9 years ago

At your extension for Yii1 there it was necessary to remove all validations from the rules. Is this necessary for this yii2 too?

Currently yes, you need remove required validator from this attributes. But seems you give me idea about removing this limitations :+1:

gb5256 commented 9 years ago

Hmmm, after removed the required, it still is not working. Have you ever tried it on a Gii-generated MVC? I always get a "Class root does not exist". Even when I just try this: Node::find()->roots()->all();

creocoder commented 9 years ago

Have you ever tried it on a Gii-generated MVC?

Ofcourse, with Gii generated model.

As i said this error

Class root does not exist

Can't be caused by behavior in any case. This error of your model layer. Can you provide your model dump to investigate situation and help?

gb5256 commented 9 years ago

That is very kind of you :-) This is my model:

namespace frontend\models;

use Yii;
use frontend\components\NestedQuery;
use creocoder\nestedsets\NestedSetsBehavior;

/**
 * This is the model class for table "node".
 *
 * @property integer $id
 * @property integer $map_id
 * @property integer $root
 * @property integer $lft
 * @property integer $rgt
 * @property integer $level
 * @property integer $link_node_id
 *
 * @property Map $map
 * @property NodeValue[] $nodeValues
 */
class Node extends \yii\db\ActiveRecord {

/**
 * @inheritdoc
 */
public static function tableName() {
    return 'node';
}

/**
 * @inheritdoc
 */
public function rules() {
    return [
        [['map_id', 'root', 'lft', 'rgt', 'level', 'link_node_id'], 'integer'],
        //not needed because of nestedSet
        //[['root', 'lft', 'rgt', 'level'], 'required']
    ];
}

/**
 * @inheritdoc
 */
public function attributeLabels() {
    return [
        'id' => Yii::t('app', 'ID'),
        'map_id' => Yii::t('app', 'Map ID'),
        'root' => Yii::t('app', 'Root'),
        'lft' => Yii::t('app', 'Lft'),
        'rgt' => Yii::t('app', 'Rgt'),
        'level' => Yii::t('app', 'Level'),
        'link_node_id' => Yii::t('app', 'Link Node ID'),
    ];
}

/**
 * @return \yii\db\ActiveQuery
 */
public function getMap() {
    return $this->hasOne(Map::className(), ['id' => 'map_id']);
}

/**
 * @return \yii\db\ActiveQuery
 */
public function getNodeValues() {
    return $this->hasMany(NodeValue::className(), ['node_id' => 'id']);
}

public function behaviors() {
    return [
        'class' => NestedSetsBehavior::className(),
             'treeAttribute' => 'root',
             'leftAttribute' => 'lft',
             'rightAttribute' => 'rgt',
             'depthAttribute' => 'level',
    ];
}

public function transactions() {
    return [
        self::SCENARIO_DEFAULT => self::OP_ALL,
    ];
}

public static function find() {
    return new NestedQuery(get_called_class());
}

}
creocoder commented 9 years ago

@gb5256 Ok, all fine there. Also i need your frontend\components\NestedQuery dump. Btw usually this class place is also models and not components. Just FYI.

gb5256 commented 9 years ago

namespace frontend\components; (Well, I have put it into a components folder as i did it this way in yii1, so just a old habit...)

namespace frontend\components;
use creocoder\nestedsets\NestedSetsQueryBehavior;

class NestedQuery extends \yii\db\ActiveQuery {

public function behaviors() {
    return [
        NestedSetsQueryBehavior::className(),
    ];
}

}
creocoder commented 9 years ago

@gb5256 Are you sure you get error with description:

Class root does not exist

? It only can be caused if somewhere you have not existent call to class named root(). But there is nothing like that in your dumps. I suggest to temporary comment relations methods and try to call Node::find()->roots()->all(); again.

creocoder commented 9 years ago

@gb5256 I guess something wrong inside Map or NodeValue or controller and view. And this something probably caused by find/replace :)

creocoder commented 9 years ago

@gb5256 So try to comment relations. Create empty controller and just call Node::find()->roots()->all();. I bet everything will be fine :+1: If so than next you need to find error inside related models or controller/view which lead to this low level php error like class not exist.

gb5256 commented 9 years ago

grrrrr. I dont get it.

I have an empty controller like this:

    namespace frontend\controllers;

    use Yii;
    use frontend\models\Node;
    use frontend\models\_search\NodeSearch;
    use yii\web\Controller;
    use yii\web\NotFoundHttpException;

 class NodeController extends Controller {
   public function actionIndex() {
        $root = Node::find()->roots()->all();
   }
}

as you see I am not even calling a view, just calling the roots() I have also removed all relations from the model. Still the same. Looking at the error output, this is happening:

../vendor/creocoder/yii2-nested-sets/src/NestedSetsQueryBehavior.php – yii\base\Object::__construct() 

in line 28 it calls

$model = new $this->owner->modelClass();

This is then handed over to yii which constructs it and throws in the end a

  ReflectionException
  Class root does not exist
Mihai-P commented 9 years ago

I think we have an error in the docs. See here https://github.com/creocoder/yii2-nested-sets/issues/56

gb5256 commented 9 years ago

AHHHHHHHHHHHHHHH.

@Mihai-P : you are perfectly right. Now it works. The documentation is wrong !!!!

creocoder commented 9 years ago

@Mihai-P Thanks you! Doc fixed! :) It was really hard to understand what was wrong by looking at dumps provided by @gb5256

Mihai-P commented 9 years ago

Sorry about that, I think everybody has multiple behaviors defined so nobody saw the missing brackets.

Best regards,

Mihai Petrescu mihai@2ezweb.com.au +61 438 002 393

On Tue, Jan 27, 2015 at 10:53 AM, gb5256 notifications@github.com wrote:

AHHHHHHHHHHHHHHH.

@Mihai-P https://github.com/Mihai-P : you are perfectly right. Now it works. The documentation is wrong !!!!

— Reply to this email directly or view it on GitHub https://github.com/creocoder/yii2-nested-sets/issues/55#issuecomment-71626453 .

gb5256 commented 9 years ago

@creocoder Perhaps you can also add to the docs your comment about upgrading from yii1 to reduce all levels by -1. Anyway: thanks everybody for getting this running. Highly appreciated.