Paginate Data from scope - php

I'm using a scope to get data from a BelongstoMany relation, is it possible to paginate data from this scope ?
User Model
public function scopeWithAndWhereHas($query, $relation, $constraint){
return $query->whereHas($relation, $constraint)
->with([$relation => $constraint]);
}
I'm accessing the scope in a controller like this
$transactions = User::withAndWhereHas('drinks', function($query) use ($status){
$query->where('status', '1');
})->paginate(2);
The paginate() helper doesn't seem to work.

Related

laravel eloquent pass variables to with()

is it possible to use variables in a with()?
for example:
groep::find(1)->with(['belongsToManyAgent'])
belongsToManyAgent looks like:
public function belongsToManyAgent($ignoreVariables=true, $columns=['*'], $showBoth=false, $showRemoved=false) {
return $this->belongsToMany(
'App\Models\Agent', // doel model
'agent_groep', // pivot tabel
'groep_id', // local key
'agent_id' // foreign key
)
->when(!filter_var($ignoreVariables, FILTER_VALIDATE_BOOLEAN), function($query) use ($showRemoved) {
$query->select($columns)
->when(!filter_var($showBoth, FILTER_VALIDATE_BOOLEAN), function($query) use ($showRemoved) {
$query->where('verwijderd',$showRemoved);
})
->when(filter_var($showBoth, FILTER_VALIDATE_BOOLEAN), function($query) use ($showRemoved) {
$query->when(!filter_var($showRemoved, FILTER_VALIDATE_BOOLEAN), function($query){
$query->where('verwijderd','0');
});
});
});
}
can I access the variables in the function via with() so that I can put $showRemoved on true for example?
There are some options to further narrow down a relationship you have, like so:
$users = User::with(['posts' => function ($query) {
$query->where('title', 'like', '%code%');
}])->get();
See https://laravel.com/docs/9.x/eloquent-relationships#constraining-eager-loads . I don't think it is possible to actually pass an array of variables to your relation function since it is called internally without parameters.
Also you probably want to simplify that function name to just public function agents(...).

parameter passed to relationship from controller to model in laravel but not working

in my controller parameter passed to posts function in user model with construct method .
class MyController extends Controller
{
private $user;
public function __construct(User $getuser)
{
$this->user = $getuser;
}
public function index($id = 2)
{
$posts = $this->user->posts($id);
$user = User::FindOrFail($id);
return $user->posts;
}
}
in my user model parameter accessed and passed to relationship .
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
function posts($id)
{
return $this->hasMany('App\Post')->where('id',$id);
}
}
it works when use like this
"return $this->hasMany('App\Post')->where('id',1);"
but not working with passed parameter. getting this error
"Symfony\Component\Debug\Exception\FatalThrowableError Too few
arguments to function App\User::posts(), 0 passed in
C:\xampp\htdocs\blog\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasAttributes.php
on line 415 and exactly 1 expected"
Check your controller method you should be returning. ie: return $posts instead of return $user->posts as this is seeking to find posts without passing in the id as you do with $posts = $this->user->posts($id);
That's why you are getting a symphony error of too few arguments as you pass no arguments in return $user->posts
User Model
function posts($id)
{
return $this->hasMany('App\Post');
}
You could access the post with the given condition by using where on the relation method.
Querying relations
https://laravel.com/docs/7.x/eloquent-relationships#querying-relations
$post = $user->posts()->where('id', $id)->first();
You could use get() or first() according to your requirement.
$posts = $user->posts()->where('id', $id)->get();
If you want a user who has a post that satisfies the criteria.
$user = User::whereHas('posts', function($query) use($id){
$query->where('id', $id);
// You may add several other conditions as well.
})
->with(['posts' => function($query) use($id){
$query->where('id', $id);
}
])
->first();
Now,
$user->posts
will give a collection of only ONE post Model Instance that satisfied the condition

Eloquent scope method gives different results

I'm using Laravel 5.4
Working code
$cityWithEvents = City::with(['events' => function ($q) {
$q->whereDate('start_time', Carbon::today('America/Montreal'))->orwhereBetween('start_time', [Carbon::today('America/Montreal'), Carbon::tomorrow('America/Montreal')->addHours(4)]);
}])->where('active', 1)->get()->keyBy('id');
Not working code
$cityWithEvents = City::with('todayEventsWithAfterHoursIncluded')
->where('active', 1)
->get()
->keyBy('id');
City model
public function events() {
return $this->hasManyThrough('App\Event', 'App\Venue');
}
public function todayEventsWithAfterHoursIncluded () {
return $this->events()
->whereDate('start_time', Carbon::today('America/Montreal'))
->orwhereBetween('start_time', [
Carbon::today('America/Montreal'),
Carbon::tomorrow('America/Montreal')->addHours(4)
]);
}
Questions
When trying to create a scope method the query gives me different result. I can't see why and what should I change
I've only used scopes a few times, but never within a ->with() clause. On your City model, create a new scope:
public function scopeTodayEventsWithAfterHoursIncluded($query){
return $query->with(["events" => function($subQuery){
$subQuery->whereDate('start_time', Carbon::today('America/Montreal'))->orWhereBetween('start_time', [Carbon::today('America/Montreal'), Carbon::tomorrow('America/Montreal')->addHours(4)]);
});
}
Then, on your City query, add it as a scope function:
$cityWithEvents = City->where('active', 1)
->todayEventsWithAfterHoursIncluded()
->get();
I think the way you are using it requires that your Event model has the scope on it, as you're technically calling with("events") on your base query and your scoped one.
Let me know if this changes you results.
If you do the query, you should do it like this:
$cityWithEvents = City::withTodayEventsWithAfterHoursIncluded()
->where('active', 1)
->get()
->keyBy('id');
You scope in you model should look like this:
public function scopeWithTodayEventsWithAfterHoursIncluded ($query)
{
return $query
->with(['events' => function ($q) {$q
->whereDate('start_time', Carbon::today('America/Montreal'))
->orwhereBetween('start_time', [
Carbon::today('America/Montreal'),
Carbon::tomorrow('America/Montreal')->addHours(4)
]);
}]);
}
Now it should be equal.

Eloquent Query Scope on Relationships

I have two models, App\Song (belongsTo App\Host) and App\Host (hasMany App\Song).
I have the following query in my Controller:
$songs = Song::whereHas('host', function($query) {
$query->where('skip_threshold', '>', \DB::raw('songs.attempts'))
->where('active', 1);
})
->whereNull('downloaded')
->get();
For reusability I would like to turn into a query scope(s).
I'm quite new to Eloquent so I'm not sure this is the correct way to do this being that its two Models as its not returning any results (where there should be).
Song.php
public function scopeEligable($query)
{
$query->where('skip_threshold', '>', \DB::raw('songs.attempts'));
}
public function scopeActiveHost($query)
{
$query->where('active', 1);
}
public function scopeInDownloadQueue($query)
{
$query->whereNull('downloaded');
}
You should put scopes into Models they belong to. Looking at your initial query scopes scopeEligable and scopeActiveHost belongs to Host model, so you should move them into Host model and then you'll be able to use your query using scopes like this:
$songs = Song::whereHas('host', function($query) {
$query->eligable()->activeHost();
})->inDownloadedQueue()->get();
and as already pointed in comment you should add return to each scope so they could be used as they intended.
EDIT
If you would like to make using it shorter, you could create new relationship in Song model:
public function activeHost()
{
return $this->belongsTo(Host:class)->eligable()->activeHost();
}
so now, you could write:
$songs = Song::whereHas('activeHost')->inDownloadedQueue()->get();
I think you're mistaken about 2 models. I think this should work
Song.php
public function scopeEligable($query, $active) {
return $query->whereHas('host', function($q) {
$q->where('skip_threshold', '>', \DB::raw('songs.attempts'))->where('active', $active);
})
}
public function scopeInDownloadQueue($query)
{
$query->whereNull('downloaded');
}
Usage
$songs = Song::eligable(true)->inDownloadQueue()->get();

Passing parameters from Controller to Model in Laravel 5

I am having trouble passing parameters from my Controller to my Model in Laravel 5.
My Model:
class Widget extends Model {
protected $fillable = array('type');
public function widget_fields_with_data($id)
{
return DB::table('widget_fields')
->join('banner_data', function($join) {
$join->on('banner_data.widget_field_id', '=', 'widget_fields.id')
->where('banner_data.banner_id', '=', $id);
})
->select('widget_fields.*', 'banner_data.value');
}}
In My Controller
$widget->widget_fields_with_data('54')->get();
This seems to return an Undefined variable: id error and I can't figure out why.
If i hardcode the value in the Model everything works okay.
Use use() statement:
function($join) use($id)
Here is your answer. You haven't passed the $id in inner function.
public function widget_fields_with_data($id)
{
return DB::table('widget_fields')
->join('banner_data', function($join) use($id) { // pass $id here
$join->on('banner_data.widget_field_id', '=', 'widget_fields.id')
->where('banner_data.banner_id', '=', $id);
})
->select('widget_fields.*', 'banner_data.value');
}}

Categories