Eloquent Parent-Child relationship on same model
You would have to recursively get the children if you have an unknown depth like that.
Another option is to use the nested sets model instead of the adjacency list model. You can use something like baum/baum
package for Laravel for nested sets.
"A nested set is a smart way to implement an ordered tree that allows for fast, non-recursive queries." - https://github.com/etrepat/baum
With this package you have methods like getDescendants
to get all children and nested children and toHierarchy
to get a complete tree hierarchy.
Wikipedia - Nested Set Model
Baum - Nested Set pattern for Laravel's Eloquent ORM
Managing Hierarchical Data in MySQL
Laravel parent / child relationship on the same model
Calling the relationship function (->children()
) will return an instance of the relation class. You either need to call then get()
or just use the property:
$children = $category->children()->get();
// or
$children = $category->children;
Further explanation
Actually children()
and children
are something pretty different. children()
just calls the method you defined for your relationship. The method returns an object of HasMany
. You can use this to apply further query methods. For example:
$category->children()->orderBy('firstname')->get();
Now accessing the property children
works differently. You never defined it, so Laravel does some magic in the background.
Let's have a look at Illuminate\Database\Eloquent\Model
:
public function __get($key)
{
return $this->getAttribute($key);
}
The __get
function is called when you try to access a property on a PHP object that doesn't actually exist.
public function getAttribute($key)
{
$inAttributes = array_key_exists($key, $this->attributes);
// If the key references an attribute, we can just go ahead and return the
// plain attribute value from the model. This allows every attribute to
// be dynamically accessed through the _get method without accessors.
if ($inAttributes || $this->hasGetMutator($key))
{
return $this->getAttributeValue($key);
}
// If the key already exists in the relationships array, it just means the
// relationship has already been loaded, so we'll just return it out of
// here because there is no need to query within the relations twice.
if (array_key_exists($key, $this->relations))
{
return $this->relations[$key];
}
// If the "attribute" exists as a method on the model, we will just assume
// it is a relationship and will load and return results from the query
// and hydrate the relationship's value on the "relationships" array.
$camelKey = camel_case($key);
if (method_exists($this, $camelKey))
{
return $this->getRelationshipFromMethod($key, $camelKey);
}
}
Then in getAttribute
first is some code that checks for "normal" attributes and returns then. And finally, at the end of the method, if there's a relation method defined getRelationshipFromMethod
is called.
It will then retrieve the result of the relationship and return that.
Eloquent relationship between two models that belong to the same model
public function parents()
{
return $this->hasManyThrough(Parent::class, Family::class, 'id', 'family_id', 'family_id', 'id');
}
Laravel - Getting parent data depending on child association
Run doesn't have a user_id column, and I believe a whereHas is what you want here as you are trying to only get runs where a certain user has a time not all runs with only the times for that user
$runs = Run::whereHas('times', function ($builder) use ($user) {
$query->where('user_id', $user->id);
})->get();
Additionally if you want to eager load the times for that user and that user only you can add a constrainted with
$runs = Run::whereHas('times', function ($builder) use ($user) {
$query->where('user_id', $user->id);
})->with(['times' => function ($query) use ($user) {
$query->where('user_id', $user->id);
}])->get();
edit:
The relationship between Runs and Users is effectively a many to many relationship with Times acting as a pivot model. Laravel supports this type of arrangement so let's set that up.
use Illuminate\Database\Eloquent\Relations\Pivot;
class Time extends Pivot
{
public function run()
{
return $this->belongsTo('\App\Run');
}
public function user()
{
return $this->belongsTo('\App\User');
}
}
class User extends Model
{
public function times()
{
return $this->hasMany('\App\Time');
}
public function runs()
{
return $this->belongsToMany('\App\Run')->using('\App\Time');
}
}
class Run extends Model
{
public function times()
{
return $this->hasMany('\App\Time');
}
public function users()
{
return $this->belongsToMany('\App\User')->using('\App\Time');
}
}
So now you can query all the runs for a specific user, and because it's using Time as a pivot table you know that the user will have a time for all the runs it returns
User::find(1)->runs();
All users who participated in a run
Run::find(1)->users();
belongsToMany with parent-child relationship in Laravel 5
Extend your models:
class Category {
public function children() {
return $this->hasMany(Category::class, 'parent_id');
}
}
class Game {
public function getAllCategoriesAttribute() {
$result = collect();
$children = function($categories) use(&$result, &$children) {
if($categories->isEmpty()) return;
$result = $result->merge($categories);
$children($categories->pluck('children')->collapse());
};
$children($this->categories);
return $result;
}
}
Then you can access the categories like this:
Game::find($id)->allCategories;
How to create a parent / children relationship in laravel?
I was selecting the columns like this
CategoryModel::select('id', 'name')->with('parent')->get();
I did not know that I also should select the parent_id.
Now It's working fine with this
public function parent()
{
return $this->hasOne(CategoryModel::class, 'id', 'parent_id');
}
Laravel parent/children relationship on it's own model
This issue has been reported and fixed in 5.0 https://github.com/laravel/framework/pull/8193
Unfortunately there is no back port for the version 4.
However if you want to apply the fix yourself you can see the list of modifications here : https://github.com/laravel/framework/pull/8193/files
Be carefull, modifying the framework's code base is at risk but there will be no more bug fixes on Laravel 4.x version, only security fixes for a few more month.
Related Topics
Openssl Not Working on Windows, Errors 0X02001003 0X2006D080 0X0E064002
Codeigniter Model Error: Undefined Property
How to Maintain Session in Curl in PHP
Using If(!Empty) with Multiple Variables Not in an Array
How to Set Session Timeout in Laravel
Laravel and View Caching in Development -- Can't See Changes Right Away
How to Prefix a Positive Number with Plus Sign in PHP
PHP Directory List from Remote Server
PHP Strtotime +1 Month Adding an Extra Month
How to Round to Nearest Thousand
How to Find Array/Dictionary Value Using Key
Soapfault Exception: Could Not Connect to Host
How to Use C++ Binaries from PHP
Prevent Direct Access to a PHP Page
What Is a Good Method to Sanitize the Whole $_Post Array in PHP
Require_Once :Failed to Open Stream: No Such File or Directory
Python Format Datetime with "St", "Nd", "Rd", "Th" (English Ordinal Suffix) Like PHP's "S"