Laravel - Failing to get results of collection with 'when' - laravel

Trying to optimise my code and not have a bunch of if statements and converting to using 'when'.
Old code was as follows (worked fine):
$bursary_administrator = BursaryAdministrator::findOrFail(\Auth::user()->userable_id);
$search = $request->search;
if($search == ''){
$students = $bursary_administrator->students()
->select('students.id',DB::raw("CONCAT(student_name,' ',student_middle_names,' ',student_surname) AS `student_complete_name`"))
->orderby('student_complete_name','asc')->get();
}else{
$students = $bursary_administrator->students()
->select('students.id',DB::raw("CONCAT(student_name,' ',student_middle_names,' ',student_surname) AS `student_complete_name`"))
->whereraw("CONCAT(student_name,' ',student_middle_names,' ',student_surname) like ?",['%'.$search.'%'])
->orderby('student_complete_name','asc')->get();
}
Then I converted to using 'when' and also added an extra condition (active):
$bursary_administrator = BursaryAdministrator::findOrFail(\Auth::user()->userable_id);
$students = $bursary_administrator->students()->select('students.id',DB::raw("CONCAT(student_name,' ',student_middle_names,' ',student_surname) AS `student_complete_name`"));
$students->when(request('search') != '', function ($q) {
return $q->whereraw("CONCAT(student_name,' ',student_middle_names,' ',student_surname) like ?",['%'.request('search').'%']);
})->when(request('active') == true, function ($q) {
return $q->whereIn('status',[1,4,6,7]);
});
$students->orderby('student_complete_name','asc')->get();
$response = array();
foreach($students as $student){
$response[] = array(
"id"=>$student->id,
"text"=>$student->student_complete_name
);
}
However, getting errors (the below is from tinker testing):
PHP Notice: Trying to get property 'id' of non-object in Psy Shell code on line 2
PHP Notice: Trying to get property 'student_complete_name' of non-object in Psy Shell code on line 2
What have I done wrong? I was folowing https://laraveldaily.com/less-know-way-conditional-queries/ and the difference is that there they were using a query, and I used it 'directly' on the model?

Ok, your problem is you are trying to loop an QueryBuilder and not the results of it. Which you do not assign to anything.
$students->orderby('student_complete_name','asc')->get();
To fix it.
$students = $students->orderby('student_complete_name','asc')->get();
But wait, there is more. I think you can make this a little more clear.
In your when boolean statements, not equal empty string, is equivalent to just checking the string as (bool) $string. Way more readable secondly, PHP's type juggling will convert a lot of cases to true. So if active is any string unless 0, it will return true.
Instead of making a transformation array, let Laravel handle the transformation. Make your calculated name, as an accessor and add it to the response with appends. Therefor in your Student.php model. Add the following.
class Student {
protected $appends = ['name'];
public function getNameAttribute(): string
{
return $this->attributes['student_complete_name'] ?? '';
}
}
Now you whole code can be as simple as.
$bursary_administrator = BursaryAdministrator::findOrFail(\Auth::user()->userable_id);
$students = $bursary_administrator->students()->select('students.id',DB::raw("CONCAT(student_name,' ',student_middle_names,' ',student_surname) AS `student_complete_name`"));
$students->when(request('search'), function ($q) {
return $q->whereraw("CONCAT(student_name,' ',student_middle_names,' ',student_surname) like ?",['%'.request('search').'%']);
})->when(request('active') === '1', function ($q) {
return $q->whereIn('status',[1,4,6,7]);
});
return $students->orderby('student_complete_name','asc')->get();

Related

Codeigniter get_where() function some of conditions are not working

In the get_all_staff(), I would like to get the company's staffs list based on the cnditions i have defined, but for example 'role !='=>'Management Office', is not working , and if I change its place in the code , it would works but the other condition will not work, what I am trying to say is all the syntax are correct, but all the conditions are not working in the same tiem.
public function get_all_staff($company_name)
{
// $query = $this->db->get_where('user_login', array('company_name' => $company_name,'role !='=>'Manager','delete_flag'=>0,'role !='=>'Management Office' , 'role !='=>'Admin'));
$query = $this->db->get_where('user_login', array('company_name' => $company_name,'role !='=>'Management Office','role !='=>'Manager','delete_flag'=>0 ,'role!='=>'Admin'));
return $query->result();
}
try like this.
public function get_all_staff($company_name)
{
$this->db->where('company_name', $company_name);
$this->db->where('role !=', 'Management Office');
$this->db->where('role !=', 'Manage');
$this->db->where('role !=', 'Admin');
$this->db->where('delete_flag', '0');
return $this->db->get('user_login')->result_array();
//if there is only one row then do it
// return $this->db->get('user_login')->row_array();
}

Laravel and algolia, ignore array if null

I have this code:
public function toSearchableArray()
{
$data = $this->toArray();
$data['_geoloc'] = $this->_geoloc->toArray();
$data['address'] = $this->address->toArray();
return $data;
}
However sometimes $data['entities'] is null therefore throwing me an error:
[Symfony\Component\Debug\Exception\FatalThrowableError]
Call to a member function toArray() on null
Is there any way to by-pass that?
You need to check elements if they exist and not null before call methods on them, like this:
public function toSearchableArray()
{
$data = $this->toArray();
$data['_geoloc'] = !empty($this->_geoloc) ? $this->_geoloc->toArray() : null;
$data['address'] = !empty($this->address) ? $this->address->toArray() : '';
return $data;
}
Also $this->toArray(); will convert the model instance to an array with all relations. So you need to load them like: $this->load('_geoloc', 'address'); and call only $data = $this->toArray();
I assume address is a relation to another table.
toArray() will convert it, if it was loaded before
public function toSearchableArray()
{
$this->address;
$data = $this->toArray();
return $data;
}
Is _geoloc also a relation to another table?
I think you can try this:
public function toSearchableArray()
{
$data = $this->toArray();
$data['_geoloc'] = $this->_geoloc->toArray();
$data['address'] = $this->address->toArray();
print('<pre style="color:red;">');
print_r($data);
print('</pre>');
exit;
return $data;
}
Hope help for you !!!

Input array loop on controller laravel 5

I have inputs array and i need to make a foreach but laravel $request->all() only return last one:
url:
http://localhost:8000/api/ofertas?filter_pais=1&filter_pais=2&filter_pais=3
controller:
public function filtroOfertas(Request $request){
return $request->all();
}
result:
{"filter_pais":"3"}
result should return 1, 2 and 3 and i need to make a foreach in filter_pais.
Any solution? Thanks
Use [] at the key of query string.
http://localhost:8000/api/ofertas?filter_pais[]=1&filter_pais[]=2&filter_pais[]=3
It will be parsed as array.
Repeated parameters make no sense and should be avoided without exception.
But looking at other solutions, there are several:
routes.php
Route::get('/api/ofertas/{r}', 'Controller#index');
Controller:
public function index($r)
{
$query = explode('&', $r);
$params = array();
foreach($query as $param)
{
list($name, $value) = explode('=', $param);
$params[urldecode($name)][] = urldecode($value);
}
// $params contains all parameters
}
Given that the URL has no question marks:
http://localhost:8000/api/ofertas/filter_pais=1&filter_pais=2&filter_pais=3

Handling non objects

I might have a controller function like so
public function index()
{
$poll = DB::table('poll')->whereNull('deleted_at')->orderBy('id', 'desc')->first();
$question = DB::table('poll_question')->whereNull('deleted_at')->where('poll_id', $poll->id)->first();
$answers = DB::table('poll_answer')->whereNull('deleted_at')->where('question_id', $question->id)->orderBy('id')->get();
return view('index', compact('poll', 'question', 'answers'));
}
This is fine if the three collections I am obtaining contain data. If they dont and I try to visit the index page, I get
ErrorException in PollResponseController.php line 20: Trying to get property of non-object
So what is the best way to handle non-object's? To bypass this, I could do
public function index()
{
$poll = DB::table('poll')->whereNull('deleted_at')->orderBy('id', 'desc')->first();
if($poll) {
$question = DB::table('poll_question')->whereNull('deleted_at')->where('poll_id', $poll->id)->first();
if($question) {
$answers = DB::table('poll_answer')->whereNull('deleted_at')->where('question_id', $question->id)->orderBy('id')->get();
return view('index', compact('poll', 'question', 'answers'));
}
}
return view('error');
}
But is that not a bit exessive? I was just wondering if there was a better approach to handling this?
Thanks
You can use simple if($question) clause or if(is_null($question)).
$question = DB::table('poll_question')->whereNull('deleted_at')->where('poll_id', $poll->id)->first();
if($question){
// The object is not empty, so I'll use it
}else{
// The object is empty
}
In a blade template it will look like #if($question) and #if(is_null($question)) respectively.
#if($question)
{{ $question->property }}
#endif
In most cases you should just bypass all variables in a template and then check each of them with #if clauses.

Laravel ORM relationship returns error when value not present in DB

I have an issue with querying relationships.
I am querying relations between Projects, Companies and Products. However, whenever a Project ID is not present in the database an fatal exception is trown:
Call to a member function companies() on a non-object
public function index($i) {
return $this->returnTop($i, Array(
'projectid' => 5,
'products' => Array(1, 2, 3)
)
);
}
public function returnTop($count = 6, $args = Array()) {
$companies = Project::find($args['projectid'])->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
}
Now, I know that project id 5 is not present in the DB, and this is likely to be the cause of this error, but I want to return a message instead of the application throwing a fatal error....
Any ideas?
Just check if find() returns null. Something like this:
$project = Project::find($args['projectid']);
if(is_null($project)){
return Response::json(['message' => 'Project not found']);
}
$companies = $project->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
An alternative would be findOrFail which throws a ModelNotFoundException. You could handle the exception globally or catch it inside the controller:
try {
$companies = Project::findOrFail($args['projectid'])->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e){
return Response::json(['message' => 'Project not found']);
}
You first have to test whether the returned object is actually not null. Blindly assuming a database query succeeds is waiting for sh*t to hit the fan.
public function returnTop($count = 6, $args = Array()) {
$project = Project::find($args['projectid']);
if($project) {
$companies = $project->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
}
else {
return; // .. your error or whatever
}
}
Also the "call to a member function on a non-object" is quite specific, it tells you that a method (member function) could not be called due to the fact that you are trying to call it on a non-object.

Resources