Laravel sort Relationship - php

How can I sort my result with related tables?
I have this tables: Clients and Managers (users table)
Client.php
<?php
class Client extends Eloquent {
protected $table = 'clients';
public function Manager(){
return $this->belongsTo('User','manager','id');
}
public function Transaction(){
return $this->hasMany('ClientTransaction','client','id');
}
}
Users.php (default Laravel's model)
My question is how can I query table clients to be sorted by Manager's name.
Here is my code so far:
public function getClients() {
// Sorting preparations
$allowed = array('name','contact','money');
$sort = in_array(Input::get('sort'), $allowed) ? Input::get('sort') : 'name';
$order = Input::get('order') === 'desc' ? 'desc' : 'asc';
// Get Clients from DB
if($sort == 'contact'){
$clients = Client::with(array('Manager' => function($query) use ($order) {
$query->orderBy('name', $order);
}));
} else {
$clients = Client::orderBy($sort, $order)->with('Manager');
}
// Filters
$cname = null;
if(Input::has('cname')){
$clients = $clients->where('name', Input::get('cname'));
$cname = '$cname='.Input::get('cname');
}
// Pagination
$clients = $clients->paginate(25);
// Return View
return View::make('pages.platform.clients')
->with('clients', $clients);
}
If I try to sort by Name it sorts OK by Clients name but if I try to sort by contact it needs to sort by User's (Manager's) name.

Try this.
$clients = Client::join('users as manager', 'manager.id','=','clients.manager')
->orderBy('manager.name', $order)
->select('clients.*') // avoid fetching anything from joined table
->with('Manager'); // if you need managers data anyway
Put this into your if statement if($sort == 'contact'){ /***/ }

Related

Convert MYSQL query to Laravel way

I have to convert these queries to Laravel way.
$tqry = "select app_process,end_time,((end_time-".time().")/86400)as remain_day from BYAPPS_apps_data where mem_id='$valu[mem_id]' limit 1";
$tresult = $_DB->query($tqry);
$tmp=$tresult->fetchRow();
if($tmp[app_process]){
$status=$app_process[$tmp[app_process]];
if($tmp[app_process]==7&&($tmp[end_time]&&$tmp[remain_day]<=0)) $type="Expired";
}else {
$tqry = "select app_process from BYAPPS_apps_order_data where mem_id='$valu[mem_id]' order by idx desc limit 1";
$tresult = $_DB->query($tqry);
$tmp=$tresult->fetchRow();
if($tmp[app_process]) $status=$ord_process[$tmp[app_process]];
else $status="Not Customer";
}
I set the relation through the models like this.
UserInfo model
public function order()
{
return $this->hasMany('App\AppsOrderData', 'mem_id');
}
public function apps()
{
return $this->hasMany('App\AppsData', 'mem_id');
}
AppsOrderData model (=> Using 'BYAPPS_apps_order_data' table)
public function userinfo()
{
return $this->belongsTo('App\UserInfo', 'mem_id');
}
AppsData model (=> Using 'BYAPPS_apps_data' table)
public function payments()
{
return $this->hasMany('App\AppsPaymentData','mem_id');
}
Then, I tried to convert the original query in UserInfoController.php like below.
public function getUserInfoListData()
{
$userInfoListData = UserInfo::select('idx',
'mem_id',
'mem_nick',
'mem_name',
'cellno',
'ip',
'reg_date')
->with('order')
->with('apps');
$orderProcess = array('Cancel','Order', 'Confirm Order',
'Developing', 'App Uploaded', 'Service end',
'Service expired', '', '', 'Waiting');
$appsOrderData = AppsOrderData::select('app_process', 'mem_id', 'end_time');
return Datatables::of($userInfoListData)
->setRowId(function($userInfoListData) {
return $userInfoListData->idx;
})
->editColumn('type', function($eloquent) use ($appsOrderData, $orderProcess) {
if ($appsOrderData->app_process == 7 && $appsOrderData->end_time <= 0) {
return "Expired";
} else {
return "No Customer";
}
})
->editColumn('term', function($eloquent) {
return " (".$eloquent->launch_date." ~ ".now().")";
})
->orderColumn('reg_date', 'reg_date $1')
->make(true);
}
However, it doesn't return as I expected, all type data return just 'No Customer'.
How can I convert this query as laravel way?
Did I wrong make the relation?
I think there are some mistakes that you have done in your code,
AppData model doesn't have a user Relationship.
If you get() method to get data , You can do it in this way,
$userInfoListData= UserInfo ::
select('idx','mem_id','mem_nick','mem_name','cellno','ip','reg_date')
->with('order')
->with('apps')
->get();
For further reference you can use this:
Get Specific Columns Using “With()” Function in Laravel Eloquent
I hope this will help you to solve your issue- thanks!

Efficient way to populate drop-down dynamically in laravel

I have multiple database tables which each one of them populates a dropdown, The point is each dropdown effects next dropdown.
I mean if I select an item from the first dropdown, the next dropdown values change on the selected item, which means they are related and they populate dynamically on each dropdown item change.
I know this is not efficient and need refactoring so I'd be glad to point me out to the right way of populating those dropdowns.
This is the controller code:
<?php
use App\Http\Controllers\Controller;
use App\Models\County;
use App\Models\OutDoorMedia;
use App\Models\Province;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class FiltersController extends Controller
{
protected static $StatusCode = 0;
protected static $Msg = '';
protected static $Flag = false;
public function index(Request $request)
{
try {
$validator = Validator::make($request->all(), [
'province_id' => 'exists:province,id',
'county_id' => 'exists:county,id',
'media_type' => Rule::in([MEDIA_TYPE_BILLBOARD, MEDIA_TYPE_OUTDOOR_MONITOR, MEDIA_TYPE_INDOOR_MONITOR, MEDIA_TYPE_STAND, MEDIA_TYPE_STRABOARD, MEDIA_TYPE_BRAND_BOARD]),
'media_status' => Rule::in([MEDIA_STATUS_AVAILABLE, MEDIA_STATUS_NEGOTIATING, MEDIA_STATUS_ASSIGNED, MEDIA_STATUS_ARCHIVE]),
'category_id' => 'exists:category_list,id',
]);
if ($validator->fails()) {
abort(400, $validator->errors()->first());
} else {
//############################# Input Filters ####################################
$province_id = $request->has('province_id') ? $request->province_id : null;
$county_id = $request->has('county_id') ? $request->county_id : null;
$media_type = $request->has('media_type') ? $request->media_type : null;
$location = $request->has('location') ? $request->location : null;
$media_status = $request->has('media_status') ? $request->media_status : null;
$category_id = $request->has('category_id') ? $request->category_id : null;
//this flag is for detecting if user is requesting from "advertiser my order" to ignore some concitions
$advertiser_my_orders = ($request->has('my_orders') && $request->my_orders == 'true') ? true : false;
$province_ids = [];
$county_ids = [];
//############################# Media Owner Filters ####################################
//offline section filters
if (!is_null($province_id) && Province::whereId($request->province_id)->exists()) {
//check correction of county id
if (!is_null($county_id) && County::whereId($county_id)->whereProvinceId($province_id)->exists()) {
$media_owner_ODM_Provinces = Province::whereHas('media')->get()->toArray();
$media_owner_ODM_Provinces_Counties = County::whereProvinceId($province_id)
->whereHas('county_media')->get()->toArray();
foreach ($media_owner_ODM_Provinces as $key => $province) {
if ($province['id'] == $province_id) {
$media_owner_ODM_Provinces[$key]['county'] = $media_owner_ODM_Provinces_Counties;
}
}
$media_owner_ODM_locations = OutDoorMedia::whereProvinceId($province_id)->whereCountyId($county_id)->groupBy('location')->pluck('location')->toArray();
$media_owner_ODM_media_types = OutDoorMedia::whereProvinceId($province_id)->whereCountyId($county_id)->whereIn('location', $media_owner_ODM_locations)->groupBy('media_type')->pluck('media_type')->toArray();
$media_owner_ODM_media_Status = OutDoorMedia::whereProvinceId($province_id)->whereCountyId($county_id)->whereIn('media_type', $media_owner_ODM_media_types)->groupBy('status')->pluck('status')->toArray();
} else {
$media_owner_ODM_Provinces = Province::whereHas('media')->with(['county' => function ($query) {
$query->whereHas('county_media');
}])->get()->toArray();
$media_owner_ODM_locations = OutDoorMedia::whereProvinceId($province_id)->groupBy('location')->pluck('location')->toArray();
$media_owner_ODM_media_types = OutDoorMedia::whereProvinceId($province_id)->whereIn('location', $media_owner_ODM_locations)->groupBy('media_type')->pluck('media_type')->toArray();
$media_owner_ODM_media_Status = OutDoorMedia::whereProvinceId($province_id)->whereIn('media_type', $media_owner_ODM_media_types)->groupBy('status')->pluck('status')->toArray();
}
} else {
$media_owner_ODM_Provinces = Province::whereHas('media')->with(['county' => function ($query) {
$query->whereHas('county_media');
}])->get()->toArray();
foreach ($media_owner_ODM_Provinces as $province) {
$province_ids[] = $province['id'];
foreach ($province['county'] as $county) {
$county_ids[] = $county['id'];
}
}
$media_owner_ODM_locations = OutDoorMedia::whereIn('province_id', $province_ids)->whereIn('county_id', $county_ids)->groupBy('location')->pluck('location')->toArray();
$media_owner_ODM_media_types = OutDoorMedia::whereIn('province_id', $province_ids)->whereIn('county_id', $county_ids)->whereIn('location', $media_owner_ODM_locations)->groupBy('media_type')->pluck('media_type')->toArray();
$media_owner_ODM_media_Status = OutDoorMedia::whereIn('province_id', $province_ids)->whereIn('county_id', $county_ids)->whereIn('media_type', $media_owner_ODM_media_types)->groupBy('status')->pluck('status')->toArray();
}
$media_owner_offline = [
'provinces' => $media_owner_ODM_Provinces,
'media_status' => $media_owner_ODM_media_Status,
'location' => $media_owner_ODM_locations,
'media_type' => $media_owner_ODM_media_types,
];
$filters['media_owner']['offline'] = $media_owner_offline;
self::$StatusCode = 200;
self::$Msg = $filters;
self::$Flag = true;
}
} catch (\Exception $e) {
//=========== Get Error Exception Message ============
self::$StatusCode = 400;
self::$Msg = $e->getMessage();
self::$Flag = false;
return $this->CustomeJsonResponse(self::$Flag, self::$StatusCode, self::$Msg);
//=========== Get Error Exception Message ============
} finally {
return $this->CustomeJsonResponse(self::$Flag, self::$StatusCode, self::$Msg);
}
}
}
FYI: I'm using laravel 5.3 framework.
Here are something that you should be aware of them.
first of all, if you validate province_id, so there is no need to double check it in your code. so you should remove
Province::whereId($request->province_id)->exists()
Second one is, Laravel has ->when eloquent method that helps you reduce if else statements for null values, if we have a null value for given parameter, it will not effect the query.
https://laravel.com/docs/5.8/queries#conditional-clauses
Third one, I suggest you to use Laravel Resources in order to transform your fetched data from database in API.
https://laravel.com/docs/5.8/eloquent-resources
This is better version of small portion of your code, I think with suggested tips and this code, you can refactor it:
class TestController extends Controller
{
const DEFAULT_COUNTRY_ID = '10';
public $request;
public function something(Request $request)
{
// Put Validations ...
$this->request = $request;
OutDoorMedia::when('province_id', function ($query) {
return $query->where('province_id', $this->request->province_id);
})
->when('country_id', function ($query) {
// if country_id exists
return $query->where('country_id', $this->request->country_id);
}, function ($query) {
// else of above if (country_id is null ...)
return $query->where('country_id', self::DEFAULT_COUNTRY_ID);
})
->get();
}
}
This is just a sample, You can use this way to refactor your code base.

Compare laravel query results

Inside the $get_user and $get_code queries they both have a group_id.
I have dd(); them Both and made 100% sure.
the $get_user query has multiple group_id's and the $get_code only has one group_id which is equal to one of the $get_user group_id's.
The goal at the moment is to create a group_id match query.
Get the code that has a group ID equal to one of the $get_user group_id's
public function getCodesViewQr($code_id)
{
$userid = Auth::id();
$get_user = GroupUser::all()->where('user_id',$userid);
$get_code = Code::all()->where('id',$code_id);
$group_match = GroupUser::where('group_id', $get_code->group_id);
$view['get_users'] = $get_user;
$view['get_codes'] = $get_code;
$view['group_matchs'] = $group_match;
return view('codes.view_qr_code', $view);
}
The group match query does not work. $get_code->group_id does not get the code group_id.
If there is a match then set $match equal to rue. else $match is False
$group_match = GroupUser::where('group_id', $get_code->group_id);
I'm using two Models Code and GroupUser
My Code table is like this :
-id
-group_id (This is the only on important right now)
-code_type
My GroupUser table is like this :
-id
-group_id (This is the only on important right now)
-user_id
-user_role
I have linked the Models
Inside my Code Model I have the relationship to GroupUser
public function group_user()
{
return $this->belongsto('App\GroupUser');
}
And Inside my GroupUser Model I have the relationship to Code
public function code()
{
return $this->belongsto('App\Code');
}
Inside My Code controller I have included my models.
use App\Code;
use App\GroupUser;
Hi guys so I had some help from a guy I work with and this is the solution he came up with. We made a few adjustments. all the Databases and results stayed the same. we just changed the method we used to get the results.
I really appreciate all the help from #linktoahref
public function view_code($random)
{
$code = Code::where('random', $random)->first();
$view['code'] = $code;
if ($code->code_type == 1)
{
// Its a coupon
if (!empty(Auth::user()))
{
// Someones is logged in
$user = Auth::user();
$view['user'] = $user;
$user_groups = GroupUser::where('user_id',$user->id)->pluck('group_id')->toArray();
if (in_array($code->group_id, $user_groups))
{
// The user is an admin of this code
return view('view_codes.coupon_admin', $view);
}else
{
// Save the code to that users account
return view('view_codes.generic_code', $view);
}
}else
{
// Anon
return view('view_codes.coupon_anon', $view);
}
}elseif ($code->code_type == 2)
{
// Voucher..
}else
{
// We don't know how to deal with that code type
}
}
$get_code = Code::find($code_id);
// Check if the code isn't null, else give a fallback to group_id
$group_id = 0;
if (! is_null($get_code)) {
$group_id = $get_code->group_id;
}
$group_match = GroupUser::where('group_id', $group_id)
->get();
$match = FALSE;
if ($group_match->count()) {
$match = TRUE;
}

Creating a search form with order by fields composed of model properties and related pivot count

I'm trying to create a search form for my Laravel app. Basically a user can enter some fields (searchable model related, like the title) and sort it in different ways; title, create date, but also vote count or favorite count. The last two are results from a pivot table (many to many relations).
I've been struggling with this but I don't know how to proceed. Here's what I have so far:
public function search(SearchRequest $request)
{
$posts = Post::where('published', 1);
if (strlen($request->title) > 0) {
$posts->where('title', 'like', '%' . $request->title . '%');
}
switch($request->order_by) {
case 'title' : $orderBy = 'title'; break;
case 'createDate' : $orderBy = 'created_at'; break;
case 'favorites' : $orderBy = 'post_favorites.count(*)'; break;
case 'votes' : $orderBy = 'post_votes.count(*)'; break;
}
$posts->orderBy($orderBy, $request->order_by_direction);
$posts = $posts->get();
var_dump($posts);
}
To keep it simple I've rewritten the code to a typical blog post example. Thanks for your suggestions.
going to take a stab on it, but its not tested as got nothing to test it on etc, so bear with me, other might take it further simpler, but hope it helps.
public function search(SearchRequest $request)
{
if(count($request->get('title')) > 0){
$search_text = $request->get('title');
$order_by = $request->get('order_by');
$display_by = $request->get('order_by_direction');
$search_results = Post::where('title', 'like', '%' . $search_text . '%')->get();
if($display_by == 'asc') return this::orderSearchResults($search_results, $order_by);
return this::orderSearchResults($search_results, $order_by)->reverse();
} else {
//do something else here
}
}
private function orderSearchResults($search_results, $order_by)
{
switch ($order_by) {
case 'title' :
return $search_results->sortby('title');
break;
case 'createDate' :
return $search_results->sortby('created_at');
break;
case 'favorites' :
return $search_results->sortby(function($search){
return count($search['post_favorites']);
});
break;
case 'votes' :
return $search_results->sortby(function($search){
return count($search['post_votes']);
});
break;
default :
return $search_results;
break;
}
}
the second part is based on the resulted being returned as a collection etc.
I was in a similar situation where I had to get users with search option on different fields (search in name, email, phone... etc) and order them by number of posts or name or email... and this worked as intended. I tried to rewrite the code to match the example you have provided.
// if the user didn't fill the field, we assign default values
$searchText = $request->input('searchText') ?: null; // the terms we are looking for
$targetField = $request->input('targetField') ?: 'title'; // in which field we want to search
$orderBy = $request->input('orderBy') ?: 'id'; // field used to order the results
$order = $request->input('order') ?: 'DESC'; // order direction
// from here we start assembling our query depending on the request
$query = DB::table('posts')->select('*')->where('published', 1);
// if the user typed something in search bar, we look for those terms
$query->when($searchText, function($query) use ($searchText,$targetField) {
return $query->where($targetField,'like','%'.$searchText.'%');
});
// if the user wants to order by votes
$query->when($orderBy === 'votes', function ($query) use ($order) {
return $query->addSelect(DB::raw('(select count(post_id) from post_votes where post_votes.post_id = posts.id) AS nbvotes'))
->orderBy('nbvotes',$order));
});
// apply same logic for favorites
// if the orderBy is neither favorites or votes, by name or email for example...
$query->when($orderBy != 'favorites' && $orderBy != 'votes', function ($query) use ($orderBy,$order) {
return $query->orderBy($orderBy,$order);
});
// executing the query
$posts = $query->get();

Laravel - Multi fields search form

I'm builind a form with laravel to search users, this form has multiple fields like
Age (which is mandatory)
Hobbies (optional)
What the user likes (optional)
And some others to come
For the age, the user can select in the list (18+, 18-23,23-30, 30+ etc...) and my problem is that i would like to know how i can do to combine these fields into one single query that i return to the view.
For now, i have something like this :
if(Input::get('like')){
$users = User::where('gender', $user->interested_by)->has('interestedBy', Input::get('like'))->get();
if(strlen(Input::get('age')) == 3){
$input = substr(Input::get('age'),0, -1);
if(Input::get('age') == '18+' || Input::get('age') == '30+' )
{
foreach ($users as $user)
{
if($user->age($user->id) >= $input){
$result[] = $user;
// On enregistre les users étant supérieur au if plus haut
}
else
$result = [];
}
return view('search.result', ['users' => $result]);
}
elseif (strlen(Input::get('age')) == 5) {
$min = substr(Input::get('age'), 0, -3);
$max = substr(Input::get('age'), -2);
$result = array();
foreach($users as $user)
{
if($user->age($user->id) >= $min && $user->age($user->id) <= $max)
$result[] = $user;
}
return view('search.result', ['users' => $result]);
}
}
else
$users = User::all();
And so the problem is that there is gonna be 2 or 3 more optional fields coming and i would like to query for each input if empty but i don't know how to do it, i kept the age at the end because it's mandatory but i don't know if it's the good thing to do.
Actually this code works for now, but if i had an other field i don't know how i can do to query for each input, i know that i have to remove the get in my where and do it at the end but i wanna add the get for the last query..
Edit: my models :
User.php
public function interestedBy()
{
return $this->belongsToMany('App\InterestedBy');
}
And the same in InterestedBy.php
class InterestedBy extends Model{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'interested_by';
public function users()
{
return $this->belongsToMany('App\User');
}
}
you can use query builer to do this as follow
$userBuilder = User::where(DB::raw('1')); //this will return builder object to continue with the optional things
// if User model object injected using ioc container $user->newQuery() will return blank builder object
$hobbies = Request::input('hobbies') // for laravel 5
if( !empty($hobbies) )
{
$userBuilder = $userBuilder->whereIn('hobbies',$hobbies) //$hobbies is array
}
//other fields so on
$users = $userBuilder->get();
//filter by age
$age = Request::input('age');
$finalRows = $users->filter(function($q) use($age){
return $q->age >= $age; //$q will be object of User
});
//$finalRows will hold the final collection which will have only ages test passed in the filter
A way you could possible do this is using query scopes (more about that here) and then check if the optional fields have inputs.
Here is an example
Inside your User Model
//Just a few simple examples to get the hang of it.
public function scopeSearchAge($query, $age)
{
return $query->where('age', '=', $age);
});
}
public function scopeSearchHobby($query, $hobby)
{
return $query->hobby()->where('hobby', '=', $hobby);
});
}
Inside your Controller
public function search()
{
$queryBuilder = User::query();
if (Input::has('age'))
{
$queryBuilder ->searchAge(Input::get('age'));
}
if (Input::has('hobby'))
{
$queryBuilder->searchHobby(Input::get('hobby'));
}
$users= $queryBuilder->get();
}

Categories