Eloquent oderby using ( with ) - laravel

client Model
protected $table = 'client';
protected $fillable = [
'client_name',
'supplier_id'
];
public function supplier()
{
return $this->belongsTo(Supplier::class, 'supplier_id', 'id');
}
Supplier table
id | supplier
1 | john
2 | ace
3 | bravo
ClientController
$Client = new Client();
$Client = $Client ->with(
'supplier'
);
$Client = $Client->orderBy('supplier', 'DESC');
Error
Column not found: 1054 Unknown column 'supplier' in 'order clause' (SQL: select * from `client` order by `supplier` desc limit 20 offset 0)
i need to order by supplier from with relationship

Depending on your laravel version you can try:
$Client = new Client();
return $Client ->with([
'supplier' => function ($q){
$q->orderBy('supplier');
}
]);

If you want to order the supplier inside the Client, see this.
If you want to order the Client based on its supplier, see this.

So, From what I have understood is that you want to orderBy your data based on a relationship's column.
If so, I am not sure if it's easy to do this with Eloquent.
Though you can use Query Build as following:
$clientQuery = Client::query();
$clientQuery->selectRaw("clients.*, (SELECT MAX(created_at) from suppliers WHERE clients.supplier_id=suppliers.id) as orderBySupplier")
->orderBy("orderBySupplier", "DESC");

Related

Laravel order by eagerly loaded column

I am using laravel eager loading to load data on the jquery datatables. My code looks like:
$columns = array(
0 => 'company_name',
1 => 'property_name',
2 => 'amenity_review',
3 => 'pricing_review',
4 => 'sqft_offset_review',
5 => 'created_at',
6 => 'last_uploaded_at'
);
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company','notices']);
$company_search = $request->columns[0]['search']['value'];
if(!empty($company_search)){
$query->whereHas('company', function ($query) use($company_search) {
$query->where('name','like',$company_search.'%');
});
}
$property_search = $request->columns[1]['search']['value'];
if(!empty($property_search)){
$query->where('properties.property_name','like',$property_search.'%');
}
if(!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id',Auth::user()->company_id);
}
$query->orderBy($order,$dir);
if($limit != '-1'){
$records = $query->offset($start)->limit($limit);
}
$records = $query->get();
With this method I received error: Column not found: 1054 Unknown column 'company_name' in 'order clause' .
Next, I tried with following order condition:
if($order == 'company_name'){
$query->orderBy('company.name',$dir);
}else{
$query->orderBy($order,$dir);
}
However, it also returns similar error: Column not found: 1054 Unknown column 'company.name' in 'order clause'
Next, I tried with whereHas condition:
if($order == 'company_name'){
$order = 'name';
$query->whereHas('company', function ($query) use($order,$dir) {
$query->orderBy($order,$dir);
});
}else{
$query->orderBy($order,$dir);
}
But, in this case also, same issue.
For other table, I have handled this type of situation using DB query, however, in this particular case I need the notices as the nested results because I have looped it on the frontend. So, I need to go through eloquent.
Also, I have seen other's answer where people have suggested to order directly in model like:
public function company()
{
return $this->belongsTo('App\Models\Company')->orderBy('name');
}
But, I don't want to order direclty on model because I don't want it to be ordered by name everytime. I want to leave it to default.
Also, on some other scenario, I saw people using join combining with, but I am not really impressed with using both join and with to load the same model.
What is the best way to solve my problem?
I have table like: companies: id, name, properties: id, property_name, company_id, notices: title, slug, body, property_id
The issue here is that the Property::with(['company','notices']); will not join the companies or notices tables, but only fetch the data and attach it to the resulting Collection. Therefore, neither of the tables are part of the SQL query issued and so you cannot order it by any field in those tables.
What Property::with(['company', 'notices'])->get() does is basically issue three queries (depending on your relation setup and scopes, it might be different queries):
SELECT * FROM properties ...
SELECT * FROM companies WHERE properties.id in (...)
SELECT * FROM notices WHERE properties.id in (...)
What you tried in the sample code above is to add an ORDER BY company_name or later an ORDER BY companies.name to the first query. The query scope knows no company_name column within the properties table of course and no companies table to look for the name column. company.name will not work either because there is no company table, and even if there was one, it would not have been joined in the first query either.
The best solution for you from my point of view would be to sort the result Collection instead of ordering via SQL by replacing $records = $query->get(); with $records = $query->get()->sortBy($order, $dir);, which is the most flexible way for your task.
For that to work, you would have to replace 'company_name' with 'company.name' in your $columns array.
The only other option I see is to ->join('companies', 'companies.id', 'properties.company_id'), which will join the companies table to the first query.
Putting it all together
So, given that the rest of your code works as it should, this should do it:
$columns = [
'company.name',
'property_name',
'amenity_review',
'pricing_review',
'sqft_offset_review',
'created_at',
'last_uploaded_at',
];
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company', 'notices']);
$company_search = $request->columns[0]['search']['value'];
$property_search = $request->columns[1]['search']['value'];
if (!empty($company_search)) {
$query->whereHas(
'company', function ($query) use ($company_search) {
$query->where('name', 'like', $company_search . '%');
});
}
if (!empty($property_search)) {
$query->where('properties.property_name', 'like', $property_search . '%');
}
if (!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id', Auth::user()->company_id);
}
if ($limit != '-1') {
$records = $query->offset($start)->limit($limit);
}
$records = $query->get()->sortBy($order, $dir);

How to catch 1 colomn (id) on table in edit form

I have 1 table data . and I have function edit on this table . in this edit form I have select dropdown to show pluck from database .
I have 3 table . this name is aduan, ipsrs , teknisi
struckture aduan table
id
user_id
ipsrs_id
teknisi_id
aduan
etc.....
ipsrs table
id
nama_bagian
etc....
teknisi table
id
ipsrs_id
nama_teknisi
etc...
This is my controller :
public function index(Request $request)
{
$ipsrs = DB::table('ipsrs')->pluck('nama_bagian','id');
$belum_kerjakan = Aduan::with('users')->where('status','Belum Dikerjakan')->get();
$teknisi = Teknisi::where('ipsrs_id' , 1)->pluck('nama_teknisi', 'id');
$dalam_proses = Aduan::with('users')->where('status','Sedang Dikerjakan')->get();
$selesai = Aduan::with('users')->where('status','Selesai')->get();
return view('admin.admin_dashboard',[
'belum_dikerjakan' => $belum_kerjakan,
'dalam_proses' => $dalam_proses,
'selesai' => $selesai,
'ipsrs' => $ipsrs,
'teknisi' => $teknisi,
]);
}
Example this variable $belum_dikerjakan is showing table data and I have fucntion edit on this table ( in modal) .
But this I don't know how to catch data (ipsrs_id) to set where clause in the pluck . I want to change 1 to ipsrs_id form table , but how ?
If I understood the problem then here is the answer
pull only the ids from ipsrs table and pass to Teknisi table whereIn method
$ipsrsIds = DB::table('ipsrs')->pluck('id')->toArray();
$teknisi = Teknisi::whereIn('ipsrs_id' , $ipsrsIds)->pluck('nama_teknisi', 'id');
public function edit($id)
{
$category =Category::findOfFail($id);
return view('admin.category.edit',compact('category'));
}
public function update(Request $request, $id)
{
$this->validate($request,[
'name' => 'required|unique:categories'
]);
$category = Category::find($id);
$category->name = $request->name;
$category->slug = str_slug($request->name);
$category->save();
Toastr::success('Category Successfully Updated','Success');
return redirect()->route('admin.category.index');
}

Laravel how to get a Model by two parameters

Hi I'm new to Laravel and got stuck in a Problem.
I have a model Contact
class Contact extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'contacts';
}
The table have these fields:
user_id (int)
contact_id (int)
...
these two fields represent the primary key.
In the ContactsController I have the function store in wich I create or update the database:
public function store()
{
switch (Input::get('type')){
case 'make_contact_request':
$user = User::where('email', '=', Input::get('login'));
$request_self = new Contact;
$request_contact = new Contact;
$request_self->user_id = Auth::user()->id;
$request_self->contact_id = $user->id;
$request_self->status = 2;
$request_self->message = Input::get('message');
$request_contact->user_id = $user->id;
$request_contact->contact_id = Auth::user()->id;
$request_contact->status = 1;
$request_contact->message = Input::get('message');
$request_self->save();
$request_contact->save();
break;
case 'answer_contact_request':
$request_self = Contact::where('user_id', '=',Input::get('contact_id'))->where('contact_id', '=', Auth::user()->id)->first();
//$request_self = Contact::whereRaw('user_id = '.Input::get('contact_id').' AND contact_id = '.Auth::user()->id.' ');
$request_contact = Contact::whereRaw('user_id = '.Auth::user()->id.' AND contact_id = '.Input::get('contact_id').' ');
$request_self->status = 3;
$request_contact->status = 3;
$request_self->save();
$request_contact->save();
break;
}
}
I tried two different ways to get the Contact Object for the request_self Object and I get the following error:
message: "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'id' in 'where clause' (SQL: update `contacts` set `status` = 3, `updated_at` = 2014-08-02 16:16:56 where `id` is null)"
for the request_contact Object it throws a fatal error (don't get the description) and close the session.
At the end I am at the beginning of laravel so I hope the solution is pretty easy to find :) but I dont even really know for what to search.
Update:
At the end I fixed the Problem with the update function.
case 'answer_contact_request':
$request_self = Contact::where('user_id', '=',Input::get('contact_id'))->where('contact_id', '=', Auth::user()->id)->update(array('status' => 3));
$request_contact = Contact::where('user_id', '=', Auth::user()->id)->where('contact_id', '=', Input::get('contact_id'))->update(array('status' => 3));
break;
I think you can add
public function scopeComposite($query, $user_id, $contact_id)
{
return $query->where('user_id', '=', $user_id)->where('contact_id', '=', $contact_id);
}
and then you can get the contact with:
$request_self = Contact::composite(Input::get('contact_id'), Auth::user()->id)->get();
source: http://laravel.com/docs/eloquent#query-scopes
I'm not sure you can make it like this.
There is a way to make sure it works:
add a column id ( auto increment, primary ) and make the group ( contact_id, user_id ) unique and you can use query scopes and id based

Laravel how do I get the row number of an object using Eloquent?

I'd like to know the position of a user based on its creation date. How do I do that using Eloquent?
I'd like to be able to do something like this:
User::getRowNumber($user_obj);
I suppose you want MySQL solution, so you can do this:
DB::statement(DB::raw('set #row:=0'));
User::selectRaw('*, #row:=#row+1 as row')->get();
// returns all users with ordinal 'row'
So you could implement something like this:
public function scopeWithRowNumber($query, $column = 'created_at', $order = 'asc')
{
DB::statement(DB::raw('set #row=0'));
$sub = static::selectRaw('*, #row:=#row+1 as row')
->orderBy($column, $order)->toSql();
$query->remember(1)->from(DB::raw("({$sub}) as sub"));
}
public function getRowNumber($column = 'created_at', $order = 'asc')
{
$order = ($order == 'asc') ? 'asc' : 'desc';
$key = "userRow.{$this->id}.{$column}.{$order}";
if (Cache::get($key)) return Cache::get($key);
$row = $this->withRowNumber($column, $order)
->where($column, '<=',$this->$column)
->whereId($this->id)->pluck('row');
Cache::put($key, $row);
return $row;
}
This needs to select all the rows from the table till the one you are looking for is found, then selects only that particular row number.
It will let you do this:
$user = User::find(15);
$user->getRowNumber(); // as default ordered by created_at ascending
$user->getRowNumber('username'); // check order for another column
$user->getRowNumber('updated_at', 'desc'); // different combination of column and order
// and utilizing the scope:
User::withRowNumber()->take(20)->get(); // returns collection with additional property 'row' for each user
As this scope requires raw statement setting #row to 0 everytime, we use caching for 1 minute to avoid unnecessary queries.
$query = \DB::table(\DB::raw('Products, (SELECT #row := 0) r'));
$query = $query->select(
\DB::raw('#row := #row + 1 AS SrNo'),
'ProductID',
'ProductName',
'Description',
\DB::raw('IFNULL(ProductImage,"") AS ProductImage')
);
// where clauses
if(...){
$query = $query->where('ProductID', ...));
}
// orderby clauses
// ...
// $query = $query->orderBy('..','DESC');
// count clause
$TotalRecordCount = $query->count();
$results = $query
->take(...)
->skip(...)
->get();
I believe you could use Raw Expresssions to achieve this:
$users = DB::table('users')
->select(DB::raw('ROW_NUMBER() OVER(ORDER BY ID DESC) AS Row, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
However, looking trough the source code looks like you could achieve the same when using SQLServer and offset. The sources indicates that if you something like the following:
$users = DB::table('users')->skip(10)->take(5)->get();
The generated SQL query will include the row_number over statement.
[For Postgres]
In your model
public function scopeWithRowNumber($query, $column = 'id', $order = 'asc'){
$sub = static::selectRaw('*, row_number() OVER () as row_number')
->orderBy($column, $order)
->toSql();
$query->from(DB::raw("({$sub}) as sub"));
}
In your controller
$user = User::withRowNumber()->get();

Laravel QueryBuilder where clause with user info on other model

I have a Model ImageRequest that is related to my User model like this:
public function user()
{
return $this->belongsTo('App\User');
}
An my User model like this:
public function imageRequests()
{
return $this->hasMany('App\ImageRequest');
}
Now I use this package to build my filterable query to fetch all ImageRequests:
spatie/laravel-query-builder
this is what my query looks like:
$query = QueryBuilder::for(ImageRequest::class)
->with(['requestTypes'])
->allowedIncludes('requestTypes')
->orderByRaw("FIELD(status , 'new') desc")
->orderBy('functional_id', 'asc')
->allowedFilters(
'id',
'pv_number',
'created_at',
Filter::scope('starts_between'),
'location_of_facts',
'train_nr',
'status',
'result_of_search',
Filter::custom('type', RequestTypeFilter::class)
);
I need to add a where clause for the User model something like this:
->where('zone', Auth::user->zone);
But it says:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'zone' in 'where clause' (SQL: select count(*) as aggregate from image_requests where zone = a)
Please look into this code, Here I added a whereHas instead for where. so it will take only matching records to user table for desired zone.
hope it helps..
$query = QueryBuilder::for(ImageRequest::class)
->with(['requestTypes'])
->whereHas('user'=>function($q){
$q->where('zone', Auth::user->zone);
})
->allowedIncludes('requestTypes')
->orderByRaw("FIELD(status , 'new') desc")
->orderBy('functional_id', 'asc')
->allowedFilters(
'id',
'pv_number',
'created_at',
Filter::scope('starts_between'),
'location_of_facts',
'train_nr',
'status',
'result_of_search',
Filter::custom('type', RequestTypeFilter::class));
Please have try this, used direct join query.
$query = ImageRequest::selectRaw('column1,column2')
->join('user', function($join){
$join->on('ImageRequest.user_id','=','user.id');
})
->leftJoin('request_types', function($join){
$join->on('request_types.image_request_id','=','image_request.id')
})
->where('user.zone', Auth::user->zone)
->orderByRaw("FIELD(status , 'new') desc")
->orderBy('functional_id', 'asc')
->allowedFilters(
'id',
'pv_number',
'created_at',
Filter::scope('starts_between'),
'location_of_facts',
'train_nr',
'status',
'result_of_search',
Filter::custom('type', RequestTypeFilter::class)
);

Resources