laravel-nestedset icon indicating copy to clipboard operation
laravel-nestedset copied to clipboard

Creating new node fails when using $parent attribute.

Open Nertskull opened this issue 7 years ago • 14 comments

I am using the following to create a new node.

$add = new mCategory;                                                                                                            

$parent = mCategory::findOrFail(4);                                                                                              

$add->category_name     = $request->category_name;                                                                               
$add->notes             = $request->notes;                                                                                       
$add->parent_id         = $parent->category_id;   #### This is line 114 referenced in the error below

$add->save();

But I get a ModelNotFoundException in Builder.php line 196 error, here is part of the error:

in Builder.php line 196
at Builder->findOrFail('4') in NodeTrait.php line 822
at fnCategory->setParentIdAttribute('4') in Model.php line 2922
at Model->setAttribute('parent_id', '4') in Model.php line 3465
at Model->__set('parent_id', '4') in fnCategoryController.php line 114
at fnCategoryController->store(object(Request))
at call_user_func_array(array(object(fnCategoryController), 'store'), array(object(Request))) in Controller.php line 76
at Controller->callAction('store', array(object(Request))) in ControllerDispatcher.php line 146
at ControllerDispatcher->call(object(fnCategoryController), object(Route), 'store') in ControllerDispatcher.php line 94
at ControllerDispatcher->Illuminate\Routing\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
at Pipeline->Illuminate\Routing\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 96
at ControllerDispatcher->callWithinStack(object(fnCategoryController), object(Route), object(Request), 'store') in ControllerDispatcher.php line 54
at ControllerDispatcher->dispatch(object(Route), object(Request), 'App\Http\Controllers\Finance\fnCategoryController', 'store') in Route.php line 174
at Route->runController(object(Request)) in Route.php line 140
at Route->run(object(Request)) in Router.php line 703

From the docs/readme page it says you can do this:

// #6 Using the parent attribute
$node->parent_id = $parent->id;
$node->save();

If however I do this instead:

$add = new mCategory;                                                                                                            

$parent = mCategory::findOrFail(4);                                                                                              

$add->category_name     = $request->category_name;                                                                               
$add->notes             = $request->notes;                                                                                       
###$add->parent_id         = $parent->category_id;   # Remove this attribute.

$add->appendToNode($parent)->save();

Then it works, and it adds the node to the correct parent of the tree.

I would prefer to use the first way. Am I doing something wrong there?

Thanks!

Nertskull avatar Apr 24 '17 17:04 Nertskull

in Builder.php line 196
at Builder->findOrFail('4') in NodeTrait.php line 822
at fnCategory->setParentIdAttribute('4') in Model.php line 2922

this means that model with an id of 4 is not found

lazychaser avatar Apr 25 '17 17:04 lazychaser

Yes, but it does exist.

And the model with id 4 IS found when doing the appendToNode($parent) method.

I can also do

return dd($parent->category_id);

And I get a result for that.

But when I assign that to the new $add->parent_id attribute.

$add->parent_id         = $parent->category_id;

It fails.

The model exists and is found. Shouldn't I be able to assign it to the $add->parent_id attribute?

Nertskull avatar Apr 25 '17 17:04 Nertskull

Seems like you're using category_id as a primary key and you didn't specify it in Eloquent model

lazychaser avatar Apr 25 '17 17:04 lazychaser

I have the following set in my eloquent model. I think that it is correct.

use Kalnoy\Nestedset\NodeTrait;
  9 
 10 class fnCategory extends Model
 11 {
 12     //
 13     use SoftDeletes;
 14     use NodeTrait;
 15 
 16 
 17     protected $table = 'fn_category';
 18     protected $primaryKey = 'category_id';
 19 
 20     protected function getScopeAttributes() {
 21         return [ 'tree_hash' ];
 22     }
....

Nertskull avatar Apr 25 '17 17:04 Nertskull

You're using scope attributes but don't set one on new model, it tries to find parent model applying scope and does not succeed.

Also, parent_id accepts numeric value, if you've already fetched the model from database, it is better to use appendToNode

lazychaser avatar Apr 25 '17 17:04 lazychaser

Ah, yes that makes sense. I am not applying the scope attribute to the new model.

Is there a way to apply the scope attribute to the new model?

If not, I will continue to use the appendToNode attribute, since it is working.

Thank you for your help.

Nertskull avatar Apr 25 '17 18:04 Nertskull

Scoping relies on attributes, you simply need to set them. In your case you can do either of following:

$model = mCategory::scoped([ 'tree_hash' => $hash ]);

or

$model = new mCategory;

$model->tree_hash = $hash;

lazychaser avatar Apr 26 '17 03:04 lazychaser

I apologize for being slow, but I still can't quite get this to work.

Adding a new node works as you suggested above.

But, then when I try the following to update a child node to a new parent node, and I still get errors.

$node = mCategory::scoped(['tree_hash' => $hash])->findOrFail(24);  // Current parent_id = 18 , want to change to 16 

$parent = mCategory::scoped(['tree_hash' => $hash])->findOrFail(16);


// None of the following work, all give 'ModelNotFoundErrors'

$node->appendToNode($parent)->save();                         
$parent->appendNode($node);                                   
$node->parent()->associate($parent)->save();

$node->parent_id = 16;
$node->save();

Nertskull avatar Apr 26 '17 15:04 Nertskull

Hi !

I encountered a similar issue. Creating a model as follow would not work and return a "not found" exception :

$data = [
    'name' => 'Some category',
    'parent_id' => '6c5deea0-87ac-11ea-87aa-0d8e79776d7a',
    'document_id' => '6b5d0250-87ac-11ea-83a9-f9f3a62e4dcf',
]

$category = Category::create($data);

The reason why it does not work is that my nested set model is scoped on document_id and this index was last in the array (or at least after parent_id) passed to create(). I do not have a handle on the order of the array elements because they come out of a request. My solution is then to reorder the array to make sure the scoped index is first (or at least before parent_id) before passing it to the create() function.

Maybe this operation could be done inside this package ?

Julien1138 avatar May 06 '20 08:05 Julien1138

@Julien1138 Hi,Julien My problem is the same as yours. Have you solved it?

@lazychaser Can you pay attention to this problem?Please

Hi !

I encountered a similar issue. Creating a model as follow would not work and return a "not found" exception :

$data = [
    'name' => 'Some category',
    'parent_id' => '6c5deea0-87ac-11ea-87aa-0d8e79776d7a',
    'document_id' => '6b5d0250-87ac-11ea-83a9-f9f3a62e4dcf',
]

$category = Category::create($data);

The reason why it does not work is that my nested set model is scoped on document_id and this index was last in the array (or at least after parent_id) passed to create(). I do not have a handle on the order of the array elements because they come out of a request. My solution is then to reorder the array to make sure the scoped index is first (or at least before parent_id) before passing it to the create() function.

Maybe this operation could be done inside this package ?

liuyong888 avatar Feb 26 '21 08:02 liuyong888

My solution is then to reorder the array to make sure the scoped index is first (or at least before parent_id) before passing it to the create() function.

@lazychaser hi, faced with that too

yarmat avatar Mar 02 '21 15:03 yarmat

I've experienced this issue again today for the umpteenth time. We have to try different workarounds each time for different projects.

stian-scholtz avatar Nov 25 '21 11:11 stian-scholtz

Having the same issue here, we have a scope property type and when setting a parent_id in the request, the check for the parent's validity doesn't correctly include the scope property:

select
  *
from
  "categories"
where
  "categories"."type" is null -- This shouldn't be null
  and "categories"."id" = '01gv64ktmc3kr054x2sf5hb4fe'
  and "categories"."organization_id" = '01GPKGCY6BTDZM5P3J6M43ARJ1'
  and "categories"."deleted_at" is null
limit
  1

LeoAdamek avatar Mar 10 '23 17:03 LeoAdamek

liuyong888

Thank You! 👍

app06 avatar Oct 16 '23 11:10 app06