ronylicha's avatar

Global Scope through Relationship, HOw TO?

Hello, i'm triyng to do a Global scope, but i have to go through a relationship and i get this error:

Method Illuminate\Database\Eloquent\Collection::getRelated does not exist.

Here the Builder Macro i wrote and use:

Builder::macro('providersViaCourses', function ($relationName1, $relationName2, $relationAttributeToDisplay2, $arrayOfData) {
            return $this->whereHas(
                $relationName1, fn($q) => $q->whereHas(
                    $relationName2, fn($q) => $q->whereIn($relationAttributeToDisplay2, $arrayOfData)
            )
            );
        });

It's a Laravel problem (i have last 10 version) how do you globalScope in this case?

This macro work fine evrywhere else

Just to be clear i use it in a ModelScope.php that i call from my model : static::addGlobalScope(new ModelScope());

0 likes
4 replies
LaryAI's avatar
Level 58

It seems like you're trying to create a global scope that applies a condition through a nested relationship. The error you're encountering suggests that you're trying to call a method on a collection that doesn't exist. This is likely because you're trying to use the getRelated method on a collection result instead of on the relationship itself.

To define a global scope that involves nested relationships, you should define the scope within a class that implements the Scope interface and then apply it to your model. Here's an example of how you can define and apply a global scope that filters models based on a nested relationship:

First, define the global scope:

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class ProvidersViaCoursesScope implements Scope
{
    protected $relationName1;
    protected $relationName2;
    protected $relationAttributeToDisplay2;
    protected $arrayOfData;

    public function __construct($relationName1, $relationName2, $relationAttributeToDisplay2, $arrayOfData)
    {
        $this->relationName1 = $relationName1;
        $this->relationName2 = $relationName2;
        $this->relationAttributeToDisplay2 = $relationAttributeToDisplay2;
        $this->arrayOfData = $arrayOfData;
    }

    public function apply(Builder $builder, Model $model)
    {
        $builder->whereHas($this->relationName1, function ($query) {
            $query->whereHas($this->relationName2, function ($query) {
                $query->whereIn($this->relationAttributeToDisplay2, $this->arrayOfData);
            });
        });
    }
}

Then, apply the scope to your model:

class YourModel extends Model
{
    protected static function booted()
    {
        static::addGlobalScope(new ProvidersViaCoursesScope(
            'relationName1', 'relationName2', 'relationAttributeToDisplay2', ['array', 'of', 'data']
        ));
    }
}

Replace 'relationName1', 'relationName2', 'relationAttributeToDisplay2', and ['array', 'of', 'data'] with the actual names and values you want to use for your relationships and conditions.

This way, the global scope will be applied to all queries for YourModel, and it will filter the results based on the conditions defined through the nested relationships.

Thunderson's avatar

I think you not understand global scope's principle, write global scope in the first relationship's model only .

// in first model file
protected static function booted():void
{
    static::addGlobalScope(new TrougthRelationScope) ;
}
public function secondRelationName() {
  // code here ...
}

// in second Model File 
public function lastRelationName() {
   // code here ...
}

// in TrougthRelationScope file
class TrougthRelationScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        $arrayOfData = getArrayOfDataFirst();
        $builder->whereHas('secondRelationName',  fn($q) => $q->whereIn('lastRelationName', 
             $arrayOfData));
    }
}
//  use first model anywhere and the scope will be automaticly call
public function AnyControllerMethod() 
{
   $data = FirstModel::get();
}
ronylicha's avatar

Indeed i didnt see anywhere in the doc that precision, so i have to use local scope. fine thx

Please or to participate in this conversation.