i am trying to query many to many relation for my get api call. i have three table as shown here but i am not using pivot table.
This is my Projects model class and this the function
public function projectRewd()
{
return $this
->belongsToMany('App\Rewards','rewards','project_id','reward_id');
}
And this is my Rewards model class and function
public function projectShip()
{
return $this->belongsToMany('App\Shipping_location','shipping_location','projects_id','rewards_id');
}
This is my api controller function
Route::get('projects/{id}', function($id) {
$proj = Projects::whereHas('projectRewd', function($q)
{
$q->where('id', $id);
});
return $proj;
});
i am using this link for api call
http://localhost:8000/api/projects/1
i want to extract rewards data and shipping_location data associate with project_id.
i am getting this error
"message": "Object of class Illuminate\\Database\\Eloquent\\Builder could not be converted to string"
i check and tried all related error from different post.
i also search and tried many technique. Cant solve my problem.
Please suggest me how to do this??
can i do this type of query in larvel without using pivot table??
You are getting Builder model because you forgot to add ->first() or ->get().
You should write:
$proj = Projects::whereHas('projectRewd', function($q){
$q->where('id', $id);
})->first();
Your closure-based controller returns your query-builder object. Not a project. You need to retrieve results from the query by fetching e.g. the first result (->first()) or all (->get()).
Route::get('projects/{id}', function($id) {
$proj = Projects::whereHas('projectRewd', function($q)
{
$q->where('id', $id);
})->first();
return $proj;
});
Referencing $id:
The reason why $id is unknown, is that the closure doesn't know about it.
You can pass it to the closure using use(...).
Route::get('projects/{id}', function($id) {
$proj = Projects::whereHas('projectRewd', function($q) use ($id)
{
...
Further:
Your whereHas query looks incorrect to me:
$q->where('id', $id);
Apparently $id is the project id. But the 'id' column in projectRewd is the primary key of projectRewd (unless you have modified the defaults).
I assume you want to query all projects that have at least one projectRewd:
Route::get('projects/{id}', function($id) {
$proj = Projects::has('projectRewd')->first();
return $proj;
});
And if you want to eager load the joined tables:
Route::get('projects/{id}', function($id) {
$proj = Projects::with('projectRewd. projectShips')->has('projectRewd')->first();
return $proj;
});
Related
Consider the following:
$posts = $this->model->newQuery()
->whereIn('user_id', $user->following) // specifically this line
->orWhere('user_id', $user->id)
->get();
The problem with the above is that there are two queries:
Get following: $user->following
Get posts: Above
This would be much more efficient with the use of a subquery, however, I cannot actually remember the correct way to do it...
I have tried all of the following:
// This was a long-shot...
...->whereIn('user_id', function ($query) use ($user) {
$query->raw($user->following()->toSql());
});
// This works but pretty sure it can be done better with eloquent...
...->whereIn('user_id', function ($query) use ($user) {
$query->select('follow_id')
->from('user_follows')
->where('user_id', $user->id);
});
Is there a way that this can be achieved by using the previously defined relationship $user->following() instead of manually defining the relationship query like the last example above?
Reference
The following relationship is defined as follows:
/**
* Get the users that the user follows.
*/
public function following()
{
return $this->belongsToMany('SomeApp\User\Models\User', 'user_follows', 'user_id', 'follow_id')
->withTimestamps();
}
Use this:
->whereIn('user_id', $user->following()->getQuery()->select('id'))
I have a little problem, I have a table with Movies and another with Genres ex: Action, Adventure etc...
Table names:
movies
movie_genre
genres
I want to fetch all the Movies with the selected Genre ex: Action
$movies = Movie::with('genres')
->when($genre, function ($query) use ($genre) {
return $query->where('genres.id', $genre->id);
})
->paginate(20);
This php code doesn't work, how can I make it work?
PS: The genre is transfered from the view by $_GET['genre'] and stocked in the variable $genre.
Edit after the answer of #Shane and #Marcin NabiaĆek :
The relationship is set in the models and when I use your code directly like this:
Movie::with('genres', 'countries', 'type')
->when($type, function ($query) use ($type) {
return $query->where('medias.type_id', $type->id);
})
->whereHas('genres', function ($query) use ($genre) {
return $query->where('genres.id', $genre->id);
})
->paginate(20);
it work perfectly, but with the when() function it dosn't. I have to use the when() to make the condition work only if there is a genre selected by the user.
You should use whereHas to get all movies that are assigned to given genre:
$movies = Movie::with('genres')
->when($genre, function ($query) use ($genre) {
$query->whereHas('genres', function($q) use ($genre) {
return $query->where('id', $genre->id);
});
})->paginate(20);
In case $genre is only id and not model, you should rather use:
return $query->where('id', $genre);
and in case it's an array (user is allowed to choose multiple genres), you should use:
return $query->whereIn('id', (array) $genre);
I'm not familiar with the when function. I use whereHas:
$movies = Movie::whereHas('genres', function ($query) use ($genre) {
$query->where('id', $genre->id);
})->with('genres')->get();
Also, is $genre the model or the ID? You mentioned it was received from $_GET which would mean it would be an ID probably.
I think a better solution would be to use your relationship function in the Genre model to get them:
$movies = Genre::find($genre_id)->movies;
In Laravel we can setup relationships like so:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Allowing us to to get all items in a pivot table for a user:
Auth::user()->items();
However what if I want to get the opposite of that. And get all items the user DOES NOT have yet. So NOT in the pivot table.
Is there a simple way to do this?
Looking at the source code of the class Illuminate\Database\Eloquent\Builder, we have two methods in Laravel that does this: whereDoesntHave (opposite of whereHas) and doesntHave (opposite of has)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
this works correctly for me!
For simple "Where not exists relationship", use this:
User::doesntHave('Role')->get();
Sorry, do not understand English. I used the google translator.
For simplicity and symmetry you could create a new method in the User model:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
To use call:
Auth::user()->availableItems();
It's not that simple but usually the most efficient way is to use a subquery.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
If this was something I did often I would add it as a scope method to the Item model.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Then use that later like this.
$items = Item::whereNotRelatedToUser($user_id)->get();
How about left join?
Assuming the tables are users, items and item_user find all items not associated with the user 123:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();
this should work for you
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);
Ended up writing a scope for this like so:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
And then call:
Items::avail()->get();
Works for now, but a bit messy. Would like to see something with a keyword like not:
Auth::user()->itemsNot();
Basically Eloquent is running the above query anyway, except with a = instead of a <>.
Maybe you can use:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Source: http://laravel.com/docs/4.2/queries#advanced-wheres
This code brings the items that have no relationship with the user.
$items = $this->item->whereDoesntHave('users')->get();
I have 3 models
User
Pick
Schedule
I'm trying to do something like the following
$picksWhereGameStarted = User::find($user->id)
->picks()
->where('week', $currentWeek)
->first()
->schedule()
->where('gameTime', '<', Carbon::now())
->get();
This code only returns one array inside a collection. I want it to return more than 1 array if there is more than 1 result.
Can I substitute ->first() with something else that will allow me to to return more than 1 results.
If not how can I set up my models relationship to allow this to work.
My models are currently set up as follow.
User model
public function picks()
{
return $this->hasMany('App\Pick');
}
Schedule model
public function picks()
{
return $this->hasMany('App\Pick');
}
Pick model
public function user()
{
return $this->belongsTo('App\User');
}
public function schedule()
{
return $this->belongsTo('App\Schedule');
}
Since you already have a User model (you used it inside you find method as $user->id), you can just load its Pick relationship and load those Picks' Schedule as follows:
EDIT:
Assuming you have a schedules table and your picks table has a schedule_id column. Try this.
$user->load(['picks' => function ($q) use ($currentWeek) {
$q->join('schedules', 'picks.schedule_id', '=', 'schedules.id')
->where('schedules.gameTime', '<', Carbon::now()) // or Carbon::now()->format('Y-m-d'). See what works.
->where('picks.week', $currentWeek);
}])->load('picks.schedule');
EDIT: The code above should return the user's picks which have a schedules.gameTime < Carbon::now()
Try it and do a dump of the $user object to see the loaded relationships. That's the Eloquent way you want.
Tip: you may want to do $user->toArray() before you dump $user to see the data better.
EDIT:
The loaded picks will be in a form of Collections so you'll have to access it using a loop. Try the following:
foreach ($user->picks as $pick) {
echo $pick->schedule->gameTime;
}
If you only want the first pick from the user you can do: $user->picks->first()->schedule->gameTime
I think a foreach loop may be what you're looking for:
$picks = User::find($user->id)->picks()->where('week', $currentWeek);
foreach ($picks as $pick){
$pickWhereGameStarted = $pick->schedule()->where('gameTime', '<', Carbon::now())->get();
}
Try this and see if it's working for you
I have a query which looks like this:
$items = Item::live()
->with('location')
->where('last_location_id', Input::get('last_location_id'))
->get();
The background of this is...
2 tables: Items & Cars.
The live scope is:
public function scopeLive($query)
{
return $query->whereHas('basic_car', function($q)
{
$q->whereNotNull('id')->where('sale_status', 'Live');
});
}
This basically checks the cars table for a matching id to that of the items 'car_id' field and will run some where clauses on the cars table.
I now however want to check another field on the cars table, but using the Input::get('last_location_id') from the original query.
$items = Item::live()
->with('location')
->where('last_location_id', Input::get('last_location_id'))
->orWhere('ROW ON THE CARS TABLE' = Input::get('last_location_id'))
->get();
This does't work, then I tried:
$items = Item::live()
->with('location')
->where('last_location_id', Input::get('last_location_id'))
->orWhere(function($query)
{
$query->where('cars.Location', Input::get('last_location_id'));
})
->get();
Which results in an unknown column 'cars.Location' error.
My next test was to create another scope:
public function scopeLiveTest($query)
{
return $query->whereHas('basic_car', function($q)
{
$q->whereNotNull('id')->where('sale_status', 'Live')->where('Location', 1); // hardcoded ID
});
}
And replacing the live() scope with that works but I dont get the affect of the orWhere in the query itself and I also cannot specify a ID from the Input.
How can I do this?
You can pass a parameter to scope like this:
$items = Item::liveAtLocation(Input::get('last_location_id'))
->orWhere(function( $query ) { // to get the OR working
$query->live()
->with('location')
->where('last_location_id', Input::get('last_location_id'));
})
->get();
And for the scope:
public function scopeLiveAtLocation($query, $location_id)
{
return $query->whereHas('basic_car', function($q) use ($location_id)
{
$q->whereNotNull('id')->where('sale_status', 'Live')->where('Location', $location_id);
});
}