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

$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.

Related

Reusing a Yii2 query

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

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;

Why do Laravel relationships prevent calls to query builder methods?

I want to find all patients that belong to a user where id = 1
This works:
$data = Patient::where('user_id', '=', 1)
->with('method', 'images')->get()->toJson();
This doesn't work:
$data = User::find(1)->patients->with('method', 'images')->get()->toJson();
It says:
Call to undefined method Illuminate\Database\Eloquent\Collection::with()
Why is it wrong? Could it be corrected?
The reason your code doesn't work is all Eloquent relationship declaration returns different result depending on whether you are trying to access the relationship as property or as method (with () or without ()).
// Return you chainable queries
$query = User::find(1)->patients()->...
// Return you collection of patients
$patientsCollection = User::find(1)->patients;
Try
User::find(1)->patients()->with('method', 'images')->get()->toJson();
Try this
$patient = New Patient;
$data = $patient->where('user_id','=',1)->with('method','images')->get()->toJson();

Only query "Where" if there is a value in Laravel eloquent

I have a search query that needs to be done. However, a search doesn't always have all values set, like in this case.
$aEvents = DB::table('events')
->where('client_id', '=', $client_id);
The question is, how can I make this where statement depend on the value of $client_id. So if the value is empty I don't want the Where statement to occur.
Also, I do not want to write several complete queries with if statements in PHP. To many variables. Ideally I'd like something like this:
$aEvents = DB::table('events')
->(($client_id != "") ? where('client_id', '=', $client_id) : "");
Using eloquent is (really!) nice and save, but I'm not yet up to speed with if statements in std Class objects I guess. Any help is appreciated.
You may try something like this:
$query = DB::table('events');
if(!empty($client_id)) {
$query->where('client_id', $client_id);
}
$aEvents = $query->get(); // Call this at last to get the result
If you are passing client_id to the server via a form/query string(user input) then you may try something like this:
if($client_id = Input::get('client_id')) {
$query->where('client_id', $client_id);
}
Update: For pagination try this:
$aEvents = $query->paginate(10); // For 10 per page
So you may call links() method in your view if you pass it like this:
return View::make('viewName')->with('aEvents', $aEvents);
In the view for pagination links:
$aEvents->links()
You can also use query scopes in the model for this purpose. Scopes allow you to easily re-use query logic in your models. In the model Event, you can add the following query scope:
public function scopeClientID($query, $client_id)
{
if ($client_id != '') {
return $query->where('client_id', '=', $client_id);
} else {
return $query;
}
}
Then from your controller or wherever you're calling it from, you can do the following:
$aEvents = Event::clientID($client_id);
If you want to get all the results, then you can do:
$aEvents = Event::clientID($client_id)->get();
Or if you want pagination, you can do:
$aEvents = Event::clientID($client_id)->paginate();
You can also chain it with other methods like you'd do in a eloquent query.
You can read more about model query scopes at http://laravel.com/docs/eloquent#query-scopes

How to merge Laravel objects in controller

I have a controller where I want to combine data from multiple tables with parallel structures. What I want to end up with in the end is one object I can return from the controller so I can parse it in Backbone.
I want to do something like this:
public function index()
{
$mc = MainContact::where('verified', '=', '1')->get();
$sm = SendMessage::where('verified', '=', '1')->get();
$obj = (object) array_merge((array) $mc, (array) $sm);
return $obj;
}
I'm told by another post on StackOverflow that this works in PHP 5.3+. However, this returns the following error in Laravel:
UnexpectedValueException: The Response content must be a string or object implementing
__toString(), "object" given.
How do I implement this method in Laravel? Both $mc and sm return valid objects in Laravel.
Nowadays you can use
$new_collection = $collection->merge($other_collection).
This works in Laravel 4 and seems to handle both arrays and collections.
What you can do here is merge the arrays of the two query result and then use the Response with json output like shown below.
$array = array_merge($mc->toArray(), $sm->toArray());
return Response::json($array);
We can use collection as below
$admins = User::where('type', '=', 'admin')->get();
$authors = User::where('type', '=', 'author')->get();
$admin_author_collection = $admins->merge($authors);
Also, Please refer the various collection methods to below link
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Collection.html
Route::get('test', function(){
$rank = Rank::get();
$policy = Policy::get();
$obj = (object)array_merge_recursive((array)$rank , (array)$policy);
var_dump($obj);
});
This is working for me. Instead of array_merge use array_merge_recursive().
You could simply use array_merge(firstObject,secondObject) function.
$obj = array_merge($mc, $sm);
return $obj;

Categories