Laravel eloquent: Multiply two columns of two different tables and display - laravel

Carts table columns :
'id',
'user_id',
'sp_id',
'service_id',
'dryclean',
'q_Shirt',
'q_Pant',
'q_Tie'
Pricing table column :
'id'
'sp_id'
'Shirt'
'Pant'
'Tie'
Both table do not have any relationship defined.
In cart controller
public function cart($sp_id, $service_id)
{
$prices = DB::table('pricings')->where('pricings.sp_id', '=', $sp_id)->get();
$cart = DB::table('carts')->where('carts.service_id', '=' , $service_id)->where('carts.sp_id','=', $sp_id)->where('user_id', '=' , auth()->id())->orderBy('id', 'desc')->take(1)->get();
return view('user.cart')->with('prices', $prices)->with('cart', $cart);
}
How do I calculate total amount of order?
If column dryclean has value of none then total is 0.
else total will be
(
carts->q_Shirt*prices->Shirt +
carts->q_Pant*prices->Pant +
carts->q_Tie*prices->Tie
)
This code is just for understanding of how I am calculating total
Please help me write code in laravel controller to calculate total and how to display it in view.

I don't think to understand you well, but you can try this to have some idea.
$prices = DB::table('pricings')
->where('pricings.sp_id', '=', $sp_id)
->get();
$cart = DB::table('carts')
->where('carts.service_id', '=' , $service_id)
->where('carts.sp_id','=', $sp_id)
->where('user_id', '=' , auth()->id())
->orderBy('id', 'desc')->take(1)
->get();
$total = 0;
$prices->reduce(function($acc, $current) use ($cart, &$total) {
return $total += ($current->Shirt + $cart->q_Shirt) +
($current->Pant + $cart->q_Pant) +
($current->Tie + $cart->q_Tie);
});

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 count two column with the third column in another table?

The idea is I have a table events:
The column Mark_id has a relationship with another table called mark_events :
The relation in model Event :
public function markevent()
{
return $this->belongsTo('App\MarkEvent', 'mark_id', 'id');
}
What I need is count these columns ( status , diabetes , number_mark_event ) and save the total of these number in sum column
Code of Controller:
$form = [
'mark_id' => $request->mark_id,
'status' => $z,
'diabetes' => $request->diabetes,
];
$event = Event::update($form);
Join the tables and count the columns. This works as you only retrieve the counted columns, joins can provide side effect if returning ambiguous columns.
$eventCounts = Event::leftJoin('mark_events', 'events.mark_id', '=', 'mark_events.id')
->select(DB::raw('count(status) as status_count'), DB::raw('count(diabetes) as diabetes_count'), DB::raw('cout(number_mark_event) as number_mark_event_count'))
->get();
$eventCounts->status_count;
$eventCounts->diabetes _count;
$eventCounts->number_mark_event_count;
I write this solution for the example you posted
In update method in Controller:
public function update(Request $request){
$event = Event::where('mark_id',$request->mark_id)->firstOrFail();
$sum = $event->status + $event->diabetes + $event->markevent->number_mark_event;
$event->update([
'sum' => $sum
]);

How to sorting by current login user first in Laravel?

Below code is to divide list view by permission in the Job table.
public function index(Request $request)
{
$user_name = Auth::user()->name;
$jobs = Job::orderBy('created_at', 'desc') //#default
->where('is_trash', '==', 0)
->paginate(15);
if(!Auth::user()->hasPermissionTo('Admin')){ //check by permission
$jobs = Job::orderBy('created_at', 'desc')
->where('user_name', '=', $user_name)
->where('is_trash', '==', 0)
->orderby('updated_at', 'desc')
->orderBy('deleted_at', 'desc')
->paginate(15);
}
return view('jobs.index')
->with('jobs', $jobs);
}
For example, current login user name is C and there has A, B, D users.
Then I wish to show list as
------------------------------
C
A
B
D
------------------------------
How do I sort the currently logged in users first in the list?
Thank you in advance.:)
To place a row above all other rows and then order the remaining rows in ascending / descending order you need to do something like this SELECT * FROM table ORDER BY field = value ASC
So for your query something like this should work
$user_name = Auth::user()->name;
$jobs = Job::orderByRaw("user_name = ':name' ASC", ['name' => $user_name])
->orderBy('created_at', 'desc')
->where('is_trash', '==', 0)
->paginate(15);
I'm not entirely sure which query you wish to order and by which field but this example should give you enough to adapt on. It is untested but if :name isn't working as per the example try wrapping the query in \DB::raw() to add the binding $user_name.
You could use collections for that. Just tested, works perfectly:
list($user, $collection) = $collection->partition(function($user) {
return $user->id === auth()->id();
});
$collection = $user->merge($collection);

Laravel database query – select inside foreach

I've got a problem with a query in Laravel 5.3. I've got tables
attendees->attendee_tag<-tags (M:N relation)
and I would like to get attendees ordered by multiple tags, so I wrote this:
$query = Attendee::where('attendees.event_id', '=', $event_id);
$i = 1;
foreach($order_by as $column) {
$tag = $this->tagService->findTagById($column['tag_id']);
$sort_value = $tag->value_type == 'string' ? 'value_string_'.$i : 'value_int_'.$i;
$query->join('attendee_tag as at_'.$i, function ($join) use ($tag, $i) {
$join->on('attendees.id', '=', 'at_'.$i.'.attendee_id')
->where('at_'.$i.'.tag_id', '=', $tag->id);})
->select('at_'.$i.'.id as relationId_'.$i, 'at_'.$i.'.value_string as value_string_'.$i, 'at_'.$i.'.value_int as value_int_'.$i, 'attendees.id as id')
->orderBy($sort_value, $column['order']);
$i++;
}
$attendees = $query->get();
But I'm getting following sql error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'value_string_1' in 'order clause' (SQL: select `at_2`.`id` as `relationId_2`, `at_2`.`value_string` as `value_string_2`, `at_2`.`value_int` as `value_int_2`, `attendees`.`id` as `id` from `attendees` inner join `attendee_tag` as `at_1` on `attendees`.`id` = `at_1`.`attendee_id` and `at_1`.`tag_id` = 3 inner join `attendee_tag` as `at_2` on `attendees`.`id` = `at_2`.`attendee_id` and `at_2`.`tag_id` = 4 where `attendees`.`event_id` = 1 order by `value_string_1` asc, `value_string_2` asc limit 1000 offset 0)
It seems, that laravel has some optimalization and passes the select on $join function only once, in last iteration (second iteration in my opinion, I got 2 tags in request)
I'm assuming that you have tags() relation within Attendee model!
I tested it and it's working fine
$attendees = Attendee::join('attendee_tag', 'attendee_tag.attendee_id', '=', 'attendees.id')
->join('tags', 'attendee_tag.tag_id', '=', 'tags.id')->where('event_id', $event_id);
$i = 1;
foreach ($order_by as $column) {
$tag = $this->tagService->findTagById($column['tag_id']);
$sort_value = $tag->value_type == 'string' ? 'value_string_' . $i : 'value_int_' . $i;
$attendees->orderBy('tags.' . $sort_value, $column['order']);
$i++;
}
$attendees->get();
PS: I don't know that $order_by is all about but I took the value of it from your code above, it should work just fine :) and I'm ready to tweak it for you if you want

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

Resources