Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Scope by pivot data values

Say I want to store various bits of data about customers, so I have two models linked by a pivot table, storing the customer's values for each datafield type on the pivot table:

Customer {
    public function datafields()
    {
        return $this->belongsToMany('Datafield')->withPivot('value');
    }
}

and

Datafield {
    public function customers()
    {
        return $this->belongsToMany('Customer')->withPivot('value');
    }

So my tables are customers, customer_datafield, datafields.

How can I set up a query scope in the customer to find all customers that have a value of x for a specfic datafield?

Something along the lines of

Customer {
    public function datafields()
    {
        return $this->belongsToMany('Datafield')->withPivot('value');
    }
    public function scopeSearch($query, $searchfor)
    {
        return $query->datafields()->pivot()
            ->where('value', $searchfor)
            ->where('datafield_id', 123);
    }
}

I've tried a few methods but not having any luck geting one to work. Any suggestions much appreciated!

like image 968
Rob Avatar asked Sep 27 '14 10:09

Rob


People also ask

How do I find the pivot value?

Click anywhere on the PivotTable, and then select PivotTable > Field List. You can also right-click the PivotTable and then select Show Field List. In the PivotTable Fields list, under Values, click the arrow next to the value field. Click Value Field Settings.

What is pivot attribute in Laravel?

In laravel, When working in a many-many relationship, the user has to choose the intermediate table and it is called a pivot table in terms of Laravel. The pivot attribute communicates with this intermediate table in controllers or models in Laravel. The admin in laravel has to define the role of every other user.

How do I create a pivot table model in Laravel?

To create a pivot table we can create a simple migration with artisan make:migration or use Jeffrey Way's package Laravel 5 Generators Extended where we have a command artisan make:migration:pivot.


2 Answers

Eloquent way for a single fixed pivot field:

public function scopeDataValue($query, $search)
{
    $pivot = $this->datafields()->getTable();

    $query->whereHas('datafields', function ($q) use ($search, $pivot) {
        $q->where("{$pivot}.value", $search);
    });
}

// usage
Model::

This gives you more power and flexibility:

public function scopeDataValues($query, array $search, $bool = 'and')
{
    $pivot = $this->datafields()->getTable();

    $query->whereHas('categories', function ($q) use ($search, $pivot, $bool) {
        $q->where(function ($q) use ($search, $pivot, $bool) {
            foreach ($search as $field => $value)
            {
                $q->where("{$pivot}.{$field}", '=', $value, $bool);
            }
        });
    });
}

// usage
Model::dataValues(['value' => 'findMe', 'otherField' => 'findMeToo'])->get();

Model::dataValues(['value' => 'findMe', 'otherField' => 'orFindMe'], 'or')->get();

You might be tempted to use where with array of values instead of foreach in the second closure, however it might not work as expected, for fields won't be prefixed with table name.


Another solution is to use simple join:

public function scopeDataValue($query, $search)
{
    $pivot = $this->datafields()->getTable();

    // first get array of already joined table
    $base = $query->getQuery();
    $joins = array_fetch((array) $base->joins, 'table');

    $foreignKey = $this->categories()->getForeignKey();

    // if table has not been joined, let's do it
    if ( ! in_array($pivot, $joins))
    {
        $query->join($pivot, $this->getQualifiedKeyName(), '=', $foreignKey);
    }

    $query->where("{$pivot}.correct", $search);
}

// usage
Model::dataValue(2)->take(..)->where(..)->dataValue(5)->get();

You can alter it the same way as 2nd example above.

like image 61
Jarek Tkaczyk Avatar answered Oct 31 '22 09:10

Jarek Tkaczyk


Note: on Laravel 5 you can simply use this:

$query->wherePivot('pivotcolumn','=', $search);
like image 3
Felice Ostuni Avatar answered Oct 31 '22 09:10

Felice Ostuni