Reputation: 9230
I have a dropdown to select a parent, which is self-referencing to the Page. I want to limit the results of that dropdown, so that it won't allow me to nest a Page more than one level.
If I edit the 'Son' Page, and the 'Son' has a 'Grandson', than I shouldn't be allowed to select 'Dad' as parent for the son, since it would create a nest that is to deep
In the folllowing case, When I'm editing the Son record, I shouldn't be able to select Dad as it's parent, since the son has children.
+----+-----------+----------+
| id | parent_id | title |
+----+-----------+----------+
| 1 | NULL | Dad |
| 2 | NULL | Son |
| 3 | 2 | Grandson |
+----+-----------+----------+
Now in this case, I should be able to select Dad as the parent when I'm editing the Son record, since the Son doesn't have any children
+----+-----------+----------+
| id | parent_id | title |
+----+-----------+----------+
| 1 | NULL | Dad |
| 2 | NULL | Son |
| 3 | NULL | Grandson |
+----+-----------+----------+
I'm struggling to get my head around this, and on how to wrap this all in the query builder.
The following code works if the Son has a Child of it's own, I won't be able to select Dad, which is good. But it fails when there's no children.
It comes down to this: My parent select should also allow pages where parent_id is null to be shown, but only if the current record (Son) doesn't have any children.
Recap: Only show the record if it doesn't occur in any parent_id, so has no children, if it does however no records are to be shown.. If it doesn't, it should show the records where parent_id is null. Is this possible in one query?
$query->where('id', '<>', $page->id);
$query->where('parent_id', '<>', $page->id);
Upvotes: 3
Views: 2938
Reputation: 26490
You need to join the table on itself, as the where-clause is a per-row basis.
Join the table on itself with a left-join, where the ID matches the parent ID. Then select only the rows where the joined table's IDs are null.
$pages = DB::table('pages AS p')
->leftJoin('pages AS p1', 'p.id', '=', 'p1.parent_id')
->where('p.id', '<>', $page->id)
->whereNull('p1.id')
->select('p.*')
->get();
Upvotes: 1
Reputation: 4904
You can achieve this with query builder sub-query with whereRaw function Check the code
$result = DB::table('parents as p')
->whereRaw("parent_id is null and id not in (SELECT parent_id FROM parents WHERE parent_id is not null)")
->get();
dd($result);
The o/p looks like this
1st scenario
It may help you :)
Upvotes: 1
Reputation: 9389
You can create parent and children relationship in the Page model.
public function parent()
{
return $this->belongsTo('Page', 'parent_id');
}
public function children()
{
return $this->hasMany('Page', 'parent_id');
}
Now, you can check if Page has children or not and the pick up the records with parent id null like this:
$pages = Page::where('parent_id', null)->doesntHave('children')->get();
This will give you records with parent id null and no children. I hope you understand.
Upvotes: 1
Reputation: 1049
Hmmm... I don't think it is possible to break this to just one line because am like you will have to loop the parent_id column checking whether the current id is in the parent_id column or not:
But not to worry: a different approach would be easier: two separate tables and thus different relationship:
Pages model: has one parent
Parents model: belongs to a page
With above relationship you it is easy using eloquent to get what has no parent by just checking where has not the given relationship:
Breaking this down:
Pages model:
public function parents () {
return $this->hasOne(Parent::class, 'page_id');
}
to parents model:
Parents model:
protected $fillable = ['page_id'];
public function pages () {
return $this->belongsTo(Page::class, 'page_id');
}
Upvotes: 0