How to add subqueries in eloquent db of laravel 5? - laravel

I am building an api in laravel 5.3 using eloquent if I use /api/location/event_name/event_status then I am getting results.
But when I use /api/location/event_name or /api/location/ nothing comes.
How to write the query so that all my link show result?
class events_api extends Controller
{
public function events($location = "",$event_name="",$event_status="")
{
$events = DB::table('event_table')
->join('event_details', 'event_table.event_id', '=', 'event_details.event_id')
->join('venue', 'event_details.venue_id', '=', 'venue.venue_id')
->where('venue.venue_city','=',$location)
->where('event_table.event_name','=','$event_name')
->where('event_table.event_status','=','$event_status')
->where('event_table.event_post_status','=','publish')
->select('event_table.event_title','event_details.event_start_ts','event_details.event_views','venue.venue_name','venue.venue_city','venue.venue_location')
->get();
echo $events;
}
}``

If you would like to make a subQuery try using toSql method:
class events_api extends Controller
{
public function events($location = "",$event_name="",$event_status="")
{
$subQuery = DB::table('event_table')
->join('event_details', 'event_table.event_id', '=', 'event_details.event_id')
->join('venue', 'event_details.venue_id', '=', 'venue.venue_id')
->where('venue.venue_city','=',$location)
->where('event_table.event_name','=','$event_name')
->where('event_table.event_status','=','$event_status')
->where('event_table.event_post_status','=','publish')
->select('event_table.event_title','event_details.event_start_ts','event_details.event_views','venue.venue_name','venue.venue_city','venue.venue_location');
DB::table(DB::raw("{$subQuery->toSql()} as main_query"))
->mergeBindings($subQuery->getBindings())
// build your query here
->get()
}
}
You'll also need to mergeBindings if you use any bindings in subquery

Related

Laravel Query Builder Method addSelect does not exist

I tried to pass data from the database to view. Now I have to write some SQL code in the controller. Is it possible to do more queries from two Query Builder instances? Like my code, obviously, it didn't work; it throws an error.
Method Illuminate\Support\Collection::addselect does not exist.
Has anyone a better idea?
class StatisticsController extends Controller
{
public function statistic()
{
$right = DB::table('answers')
->select('questions.question_title', 'questions.chapters_id',
DB::raw('count(*) as rightanswers'))
->join('questions', 'questions.id', '=', 'answers.questions_id')
->where('answers.is_correct', 1)
->groupBy('questions.question_title', 'questions.chapters_id')
->get();
$wrong = DB::table('answers')
->select('questions.question_title', 'questions.chapters_id',
DB::raw('count(*) as wronganswers'))
->join('questions', 'questions.id', '=', 'answers.questions_id')
->where('answers.is_correct', 0)
->groupBy('questions.question_title', 'questions.chapters_id')
->get();
$data = $right->addselect('questions.title', 'chapters_id',
'rightanswers/(rightanswers+wronganswers) as rightigeRate')
->join('wrong', 'right.questions.title', '=', 'wrong.questions.title')
->get();
return view('/statistics', compact('data'));
}
}

Joining 2 scopes laravel

I've been trying to solve this for quite a while now. I want to join these two scopes from my Match Model:
public function scopeMainMatches($query)
{
return $query->where('type', 'main');
}
public function scopeDotaMatches($query)
{
return $query->join('leagues', function ($join) {
$join->on('matches.league_id', '=', 'leagues.id')
->select('matches.*')
->where('leagues.type', '=', 'dota2')
->where('matches.type', '=', 'main');
});
}
so basically, when I put in into join eloquent relationship it will be the same like this:
$query = DB::table('matches')
->join('leagues', 'leagues.id', '=', 'matches.league_id')
->select('matches.*')
->where('leagues.type', '=', 'dota2')
->get();
it works fine during the terminal check. but I need to connect 2 scopes for the Controller which looks like this:
$_matches = \App\Match::mainMatches()
->get()
->load('teamA', 'teamB')
->sortByDesc('schedule');
so when I try to connect mainMatches and dotaMatches, it doesn't show up on the matches. although when i run php artisan tinker, it returns the correct output, but it won't show up on the matches table.
$_matches = \App\Match::mainMatches()
->dotaMatches()
->get()
->load('teamA', 'teamB')
->sortByDesc('schedule');
any Ideas how to work on this? TYIA!
I've managed to join two tables in just one scope here is the code:
public function scopeMainMatches($query) {
return $query->join('leagues','leagues.id','=','matches.league_id')->select('matches.*')->where('matches.type', 'main');
}

non trivial relationship in eloquent

i get:
Relationship method must return an object of type
Illuminate\Database\Eloquent\Relations\Relation
code of model:
class Order extends Model{
public function order_status(){
$q = self::GetQueryWithCurrentOrderStatus();
return $q->where('order.id', '=', $this->id)->get();
}
private static function GetQueryWithCurrentOrderStatus(){
$rawSql = OrderOrderStatus::selectRaw('order_order_status.order_id as id, max(created_at)')->groupBy('order_order_status.order_id')->toSql();
$query = OrderStatus::join('order_order_status', 'order_order_status.order_status_id', '=', 'order_status.id')
->join('order', 'order.id', '=', 'order_order_status.order_id')
->join(DB::raw('( ' . $rawSql . ') CurrentOrderStatus'), function ($join) {
$join->on('order_order_status.id', '=', 'CurrentOrderStatus.id');
});
return $query;
}
}
db structure is written in the answer here:
https://dba.stackexchange.com/questions/151193/good-database-structure-for-scenario-with-orders-that-have-a-state-and-the-state/151195#151195
order_status_history is order_order_status
now i could write in the blade file just:
$order->order_status() instead of $order->order_status ... but why? is there a solution?
If you're trying to call a method, call a method. order_status isn't a property.
If you access it as a property, it requires an Eloquent relationship (like it says) which are created through the hasOne, hasMany, belongsTo, belongsToMany methods: https://laravel.com/docs/master/eloquent-relationships

Laravel query scope combination

I'm using Laravel 4.2 Query Scopes but encountered a problem.
My Model:
class SomeModel extends Eloquent {
public function scopeS1($query) {
return $query->where('field1', '=', 'S1');
}
public function scopeS2($query) {
return $query->where('field2', '=', 'S2');
}
}
Now when I do SomeModel::s1()->s2()->get(); it returns all results and doesn't filter by S1 AND S2. Note also that I have no problem when I do
SomeModel::where('field1', '=', 'S1')->where('field2', '=', 'S2')->get()
So why is query scoping and doing anything here??
Since your real scopes contain OR conditions you should use a nested where to make sure they get interpreted correctly. Laravel will wrap parentheses around.
public function scopeS1($query) {
return $query->where(function($q){
$q->where('field1', '=', 'S1')
->orWhere('foo', '=', 'bar');
});
}
// and the same for scopeS2...

Where NOT in pivot table

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();

Resources