Reusing a Yii2 query - php

Am trying to reuse a query but it fails.
In my method I have:
public function getPacked($from, $to){
$initquery = RealTimeTblTrucks::find()
->leftJoin('tbl_truck_history','tbl_truck_history.truck_id=tbl_trucks.id')
->where(["between","tbl_truck_history.created_at",$from,$to])
->andWhere(["tbl_truck_history.status"=>20]);
$data = [];
$data[SELF] =$initquery
->andWhere(["tbl_trucks.truck_category"=>28])
->count();
$data[NORMAL] = $initquery->andWhere(["tbl_trucks.truck_category"=>27])
->count();
$data[BULKER] = $initquery->andWhere(['in', 'tbl_trucks.truck_category', [26,34]])
->count();
return $data;
}
Now the first ($data[SELF]) returns the correct information but the next ones NORMAL and BULKER didn't return the correct information.
When I check on the raw query I can see that the last two are affected by the first one such that the new query at $data[NORMAL] contains a check for truck_category = 20 which should only be executed on the first array item (SELF).
How to refactor this to make it work?

Advantage of clone over creation a new object, is that, all properties will be copied into the new object instead of resetting them. This is quite useful when you use query builder.
public function getPacked($from, $to) {
$initquery = RealTimeTblTrucks::find()
->leftJoin('tbl_truck_history','tbl_truck_history.truck_id=tbl_trucks.id')
->where(["between","tbl_truck_history.created_at",$from,$to])
->andWhere(["tbl_truck_history.status"=>20]);
$data = [];
$querySelf = clone $initquery;
$data[SELF] = $querySelf
->andWhere(["tbl_trucks.truck_category"=>28])
->count();
$queryNormal = clone $initquery;
$data[NORMAL] = $queryNormal->andWhere(["tbl_trucks.truck_category"=>27])
->count();
$queryBulker = clone $initquery;
$data[BULKER] = $queryBulker->andWhere(['in', 'tbl_trucks.truck_category', [26,34]])
->count();
return $data;
}
Refer Yii2 clone detail

Related

Laravel Problem: Please check why this code behave like this?

$sallery_min = 4000;
$sallery_max = 30000;
$job = Job::where('status', 1);
if ($sallery_min && $sallery_max) {
$job->whereIn('salary_level', $sallery_level);
}
$data = $job->orderBy('id', 'desc')->get();
dd($data);
when use above mention code then i got 7 result its working fine. But when i change in this code like this then 11 result come from database.can i do not do code like this. what happen when Job::where('status', 1); change into $job = new Job(); $job->where('status', 1);. why result come diffrent
$sallery_min = 4000;
$sallery_max = 30000;
$job = new Job();
$job->where('status', 1);
if ($sallery_min && $sallery_max) {
$job->whereIn('salary_level', $sallery_level);
}
$data=$job->orderBy('id', 'desc')->get();
dd($data);
in your code you are getting the result where status is 1 1 from your database by using this query
$job = Job::where('status', 1);
but you are not retriving the objects because you dont use get() or first().WHer first() is use for retrieving single row and get() is use for multipe row. So for retrieving teh expected result you have to use get() method like this.
$jobs = Job::where('status', 1)->get();
If you want to query the database with a new Job object, you should use the method chaining, like:
$job = new Job();
$jobs = $job->where('status', 1)
->when($sallery_min && $sallery_max, function ($q) use ($sallery_min, $sallery_max) {
return $q->whereBetween('salary_level', [$sallery_min, $sallery_max]);
})->get();
dd($jobs);
However, Eloquent provides the static method for convenience. Use it unless you have a specific reason to stick on with the new Object word around.
Extra Note:
The above code uses Conditional Where Clauses which avoids if ... else ... statements.

The wrong record in my database is getting updated

im using laravel eloquent to update a record in a database table. Im passing in a parameter of 52 which is the id of the record I want to update (primary key).
I am printing the query to check which record its finding and its printing the record with the id of 13 and then when i check the table, id 13 has been updated.
protected $connection = 'sqlsrv';
protected $table = 'todo';
public $timestamps = false;
public static function complete($todoId, $userId)
{
$now = new DateTime();
$query = Self::join('todoTypes', 'todo.typeId', 'todoTypes.id')
->where('todoTypes.canComplete', 1)
->whereNull('todo.completedDate')
->find(52);
$query->where(function ($query) use ($now)
{
$query->whereNull('cancelDate')
->orWhere('cancelDate', '>', $now);
});
if ($query)
{
$query->completedDate = $now;
$query->save();
}
}
How about trying like this?
The query after using find did not make any sense since find returns the first object not a query builder instance.
public static function complete($todoId, $userId)
{
$now = new DateTime();
$object = Self::join('todoTypes', 'todo.typeId', 'todoTypes.id')
->where('todoTypes.canComplete', 1)
->whereNull('todo.completedDate')
->where(function ($query) use ($now) {
$query->whereNull('cancelDate')
->orWhere('cancelDate', '>', $now);
})->find(52);
if ($object) {
$object->completedDate = $now;
$object->save();
}
}
I have managed to fix this by just adding a select at the start
select('todo.id', 'todo.completedDate')
It seems it was getting the right row, but displaying the id as something else.
When I took out the join and the joins where clause, it worked. I suspect it was using the id of the joint row from the todoTypes table as that was 13.

Putting orderby from highest to lowest in database query

1.I've a confusion on how to add sort orderby(highest to lowest) in my database query for the age.I've tried some few codes but it generates an error.Any help here is much appreciated.
public function ListOrgaScholar($ship_id){
$ship = Scholarship::find($ship_id);
$ship_age_from = $ship->ship_age_from;
$ship_age_to = $ship->ship_age_to;
$scholars = (new Scholar)->newQuery()->select('*');
$scholars->whereBetween(DB::raw('TIMESTAMPDIFF(YEAR,scholars.scholar_birthday,CURDATE())'),array($ship_age_from,$ship_age_to));
$scholars = $scholars->get();
}
2.Same us here.How to add orderby(highest to lowest) since it is two different where clause.The $ship_gpa_from and $ship_gpa_to are inputs of grade.
public function ListOrgaScholar($ship_id){
$ship = Scholarship::find($ship_id);
$ship_gpa_from = $ship->ship_gpa_from;
$ship_gpa_to = $ship->ship_gpa_to;
$scholars = (new Scholar)->newQuery()->select('*');
if($ship_gpa_from)
$scholars->where('scholar_GPA', '>=', $ship_gpa_from);
if($ship_gpa_to)
$scholars->where('scholar_GPA', '<=', $ship_gpa_to);
$scholars = $scholars->get();
}
Have you tried returning the results as collection and then applying collection functions on them? The code would look somewhat like this:
$scholarship = Scholarship::find($id);
$scholars = Scholar::all();
$selectedScholars = $scholars->filter(function ($item, $key) {
$scholarAge = Carbon::now() - $item->scholar_birthday //this depends on the value of scholar_birthday;
return ($scholarAge >= $scholarship->ship_age_from && $scholarAge <= $scholarship->ship_age_from);
})->sortBy("scholar_birthday");

Not able to pass a variable in laravel

In the controller below, if I return $friendPosts (which has the post ids), the ids are shown in the view without problems.
But when I try to return the $sharedPosts (which has the whole row), nothing shows up in the view.
Controller
public function getProfile($email)
{
$myFriends = Auth::user()->friends()->lists('id');
$friendShares = Share::where('user_id',$myFriends)->get();
$friendPosts = $friendShares->lists('post_id');
$sharedPosts = Post::where('id', $friendPosts)->get();
return view('profile.index')
->with ('friendShares', $sharedPosts);
}
View
#foreach ($friendShares as $friendShares)
<p> {{$friendShares}}</p>
#endforeach
$myFriends = Auth::user()->friends()->lists('id');
$friendShares = Share::where('user_id',$myFriends)->get();
$friendPosts = $friendShares->lists('post_id');
$sharedPosts = Post::where('id', $friendPosts)->get();
should be
$myFriends = Auth::user()->friends()->lists('id');
$friendShares = Share::whereIn('user_id',$myFriends)->get();
$friendPosts = $friendShares->lists('post_id');
$sharedPosts = Post::whereIn('id', $friendPosts)->get();
You are working with more ids, not just one, so you have to use whereIn() which looks trough an array of values.
Next time it would be useful if you tell us what you actually wanted/tried to do with your code.

Laravel 5.2 - filtering on a custom attribute and then paginating

So I know how to paginate using paginate() and I know how to filter based on an Accessor (a where() on the collection). However, paginate takes in a query builder and where() on a collection returns a collection.
So if I want to get a bunch of items / filter by a custom attribute and then paginate the result set....how do i do that??
Accessor:
public function getRequiredToReportAttribute()
{
// return boolean based off of complicated business logic
}
index method:
public function index()
{
//what im doing (redacted)
$employers = (new App\Employers')->paginate($this->perPage);
// what I would like to be doing
$employers = (new App\Employers)->where('required_to_report', '=', true)->paginate($this->perPage);
return $this->sendResponse($employers);
}
In the case that you want to work with accesors, you could by iterating the collection after you get your query, something like this:
$result = Model::get()->filter(function($item) {
return $item->require_to_report === true;
});
Here you have all records of your model and then you could create a manual paginator:
$paginator = new Illuminate\Pagination\Paginator($result, 10);
you have with this approach a weakness when you have too many records, the performance could be affected.
Based off of Jose Rojas answer and this post I built a LengthAwarePaginator for a collection filtering on an attribute accessor. Here's an example of how to do it:
$collection = Model::all();
//Filter your collection
$filteredItems = $collection->filter(function($col) {
return $col->require_to_report === true;
});
// Setup necessary information for LengthAwarePaginator
$currentPage = LengthAwarePaginator::resolveCurrentPage();
$pageLimit = 20;
// slice the current page items
$currentItems = $filteredItems->slice(pageLimit * ($currentPage - 1), pageLimit)->values();
// you may not need the $path here but might be helpful..
$path = "/api/v1/employers";
// Build the new paginator
$paginator = new LengthAwarePaginator($currentItems, count($filteredItems), $pageLimit, $currentPage, ['path' => $path]);
return $paginator;

Categories