Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
899 views
in Technique[技术] by (71.8m points)

php - Laravel parent / child relationship on the same model

The Setup And Dummy Data

I have a simple model called Category, which has the following schema:

|----------------------------------------------|
| cat_id   | cat_name    | parent_id           |
|----------------------------------------------|
|   1      | Home        |   0                 |
|----------------------------------------------|
|   2      | Products    |   1                 |
|----------------------------------------------| 
|   3      | Services    |   1                 |
|----------------------------------------------|
|   4      | Product A   |   2                 |
|----------------------------------------------|
|   5      | Product B   |   2                 |
|----------------------------------------------|

The Desired Output

So you can see that we would get a very straight forward hierarchy as follows:

Home
  - Products
      - Product A
      - Product B
  - Services

The Issue

I'm trying to map this relationship in Laravel 4.2, so that I can query a model and get its parent (it will always have a parent), and child categories if they exist.

I've defined the relationship in the Category model using:

public function children()
{
    return $this->hasMany('Category', 'parent_id', 'cat_id');
}
public function parent()
{
    return $this->belongsTo('Category', 'parent_id');
}

The Problem

I can get the parent name working, using

$category = Category::findOrFail($id);
return $category->parent->cat_name;

However, I don't understand how to get the child objects.

I've tried:

$category = Category::findOrFail($id);
$children = $category->children();

But when I dd($children) it doesn't output what I'd expect.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 IlluminateDatabaseEloquentModel:

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...