4
votes

I'm trying to learn Laravel and right now I'm experimenting with Eloquent. I've got the following case that I can't solve right now:

Let's say I'm creating a webshop, so I have products (Product 1, Product 2, etc):

+-------------+------------------+------+-----+---------------------+----------------+
| Field       | Type             | Null | Key | Default             | Extra          |
+-------------+------------------+------+-----+---------------------+----------------+
| id          | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| name        | varchar(255)     | NO   |     | NULL                |                |
| slug        | varchar(255)     | NO   |     | NULL                |                |
| description | text             | NO   |     | NULL                |                |
| price       | decimal(5,2)     | NO   |     | NULL                |                |
| active      | tinyint(4)       | NO   |     | 1                   |                |
| created_at  | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| updated_at  | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
+-------------+------------------+------+-----+---------------------+----------------+

Those products are sorted into Taxonomies (Brand, Color, Department):

+-------------+------------------+------+-----+---------------------+----------------+
| Field       | Type             | Null | Key | Default             | Extra          |
+-------------+------------------+------+-----+---------------------+----------------+
| id          | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| name        | varchar(255)     | NO   |     | NULL                |                |
| slug        | varchar(255)     | NO   |     | NULL                |                |
| description | text             | NO   |     | NULL                |                |
| created_at  | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| updated_at  | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
+-------------+------------------+------+-----+---------------------+----------------+

These taxonomies have terms (Nike, Adidas, Red, Green, Boys, Girls):

+-------------+------------------+------+-----+---------------------+----------------+
| Field       | Type             | Null | Key | Default             | Extra          |
+-------------+------------------+------+-----+---------------------+----------------+
| id          | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| taxonomy_id | int(11)          | NO   |     | NULL                |                |
| name        | varchar(255)     | NO   |     | NULL                |                |
| slug        | varchar(255)     | NO   |     | NULL                |                |
| description | text             | NO   |     | NULL                |                |
| created_at  | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| updated_at  | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
+-------------+------------------+------+-----+---------------------+----------------+

And last I have a pivot table to connect the terms to the products:

+------------+------------------+------+-----+---------------------+----------------+
| Field      | Type             | Null | Key | Default             | Extra          |
+------------+------------------+------+-----+---------------------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| product_id | int(11)          | NO   |     | NULL                |                |
| term_id    | int(11)          | NO   |     | NULL                |                |
| created_at | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| updated_at | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
+------------+------------------+------+-----+---------------------+----------------+

I've created models for Product, Taxonomy and Term like this:

<?php

class Product extends Eloquent {

    public function terms()
    {
        return $this->belongsToMany('Term', 'product_terms', 'product_id', 'term_id');
    }

}

<?php

class Taxonomy extends Eloquent {

    public function terms()
    {
        return $this->hasMany('Term');
    }

}

<?php

class Term extends Eloquent {

    public function taxonomy()
    {
        return $this->belongsTo('Taxonomy');
    }

}

Now I want to do the following, I want to get all the products, loop over them and show something like the name, description and price. Well, a simple $products = Product::all(); is all I need. Then, when I loop over the products, I know I can do something like $product->terms to get all the terms. But how should a get the term of a given taxonomy. So for example something like this:

<?php
echo $product->term('brand'); // Where 'brand' is the taxonomy name of the term I want to get
echo $product->term('color'); // Where 'color' is the taxonomy name of the term I want to get

Hope someone can help me.

1

1 Answers

3
votes

Alright, I think I understand your setup. Given the relations you stated, I think you'd define your models as follows:

<?php

class Product extends Eloquent {

    public function terms()
    {
        return $this->belongsToMany('Term')->withTimestamps();
    }

}

<?php

class Taxonomy extends Eloquent {

    public function terms()
    {
        return $this->hasMany('Term');
    }

}

<?php

class Term extends Eloquent {

    public function taxonomy()
    {
        return $this->belongsTo('Taxonomy');
    }

    public function products()
    {
        return $this->belongsToMany('Product')->withTimestamps();
    }

}

Since your pivot is named and id'd correctly you shouldn't have to specify that info in the belongsToMany relationship, but if you want the timestamps to work you need the withTimestamps.

EDIT:

If you can look taxonomies up by id instead of slug, this will work:

$products = Product::all();
foreach($products as $product)
{
    $term = $product->terms()->with('taxonomy')->where('taxonomy_id', '=', 2)->first();
    echo $term->name;
}

In the scenario above you could just store the taxonomy slug in the term table since it should be a unique key. Otherwise you could look over the terms and look for the one with the taxonomy that you want:

$products = Product::all();
foreach($products as $product)
{
    $terms = $product->terms()->with('taxonomy')->get();
    foreach($terms as $term)
    {
        if($term->taxonomy->slug == 'brand')
        {
            echo $term->name."<br />";
        }
    }
}

END EDIT

I have to admit that I'm a little lost though because your last two tables seem exactly the same and I'm wondering why you associate terms with products instead of taxonomies with products. I'm suspect that my solution won't work with the way you're relating things but if you related taxonomies with products instead it would work jut fine.

<?php
$product->taxonomy()->where('slug', '=', 'brand')->term;