dvdfreitas's avatar

whereRelation with an array?

Hi,

Is there a way to use the whereRelation to write a cleaner code (without the anonymous function)?

        $this->documents = Document::whereHas(
                'categories', fn($q) => $q->whereIn('slug', $categories)
            )->get(); 

The following code doesn't work, but is to give an example of what I'd like to have.

$this->documents = 
            Document::whereRelation('categories', 'slug', $categories)
            ->get();
0 likes
12 replies
Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

There isn't a whereRelationIn sadly, but you could add it yourself as a macro. Eloquent is macroable :)

\Illuminate\Database\Eloquent\Builder::macro('whereRelationIn', function( $relation, $column, $array) {
    $this->whereHas(
                $relation, fn($q) => $q->whereIn($column, $array)
            );
)};
     
2 likes
anuzpandey's avatar

@str In boot() method of AppServiceProvider.php or create your own Provider, MacroableServiceProvider and add your macros there.

// AppServiceProvider || MacroableServiceProvider
use Illuminate\Database\Eloquent\Builder;

public function boot()
{
    Builder::macro('whereRelationIn', function ($relation, $column, $array) {
        $this->whereHas(
            $relation, fn($q) => $q->whereIn($column, $array)
        );
    });
}
1 like
str's avatar

@anuzpandey I placed it in the AppServiceProvider::register() as I'm "registering" the macro to be used later.

thedocrow0124's avatar

@anuzpandey I'm trying to apply this to my code to return all the prices that match the array of designs, however this is returning "Call to a member function get() on null" when I try to use it.

Price::whereRelationIn('style_versions.styles', 'designs_id', $styles)->get()

I've put the macro in AppServiceProvider.php

    public function boot()
    {
        Builder::macro('whereRelationIn', function ($relation, $column, $array) {
            $this->whereHas(
                $relation, fn($q) => $q->whereIn($column, $array)
            );
        });
    }

Do you have any ideas?

kokoshneta's avatar

@thedocrow0124 Did you just copy-paste the code into your AppServiceProvider? If so, remember that you have to qualify Builder, otherwise it won’t recognise the class. Do you have a use Illuminate\Database\Query\Builder statement at the top of the file?

Edit: Also, there’s a return statement missing in the macro. Should be:

public function boot() {
	Builder::macro('whereRelationIn', function ($relation, $column, $array) {
		return $this->whereHas(
			$relation, fn($q) => $q->whereIn($column, $array)
		);
	});
}

Without the return statement, running the macro will return nothing, and then you end up trying to call ->get() on nothing.

2 likes
Sinnbeck's avatar

@dvdfreitas if the question is answered you can set the thread as solved by marking a best answer

Please or to participate in this conversation.