Multiple like conditions in Codeigniter 4 - codeigniter

Please help me to use multiple conditions in Codeigniter 4?
I have used the following codes but it doesn't work, threw an error, with one like its working fine.
$users = $model->like('title', $this->request->getVar('search'))->like('name', $this->request->getVar('search'))->get();
$db = \Config\Database::connect();
$user = $db->table('staff');
$user = $db->like('title', $this->request->getVar('search'));
$user = $db->or_like('name', $this->request->getVar('search'));
$query = $user->get();

Your second code is using or_like but in Codeigniter 4 you should use orLike:
https://codeigniter4.github.io/userguide/database/query_builder.html
I don't know what type of error it throws (you should have posted it) and which of the two codes is the correct, but your code shoul look like this:
$db = \Config\Database::connect();
$builder = $db->table('staff');
$users = $builder->like('title', $this->request->getVar('search'))->orLike('name', $this->request->getVar('search'))->get();

This my own approach.
namespace App\Models;
use CodeIgniter\Model;
class SearchData extends Model
{
protected $table = 'Staff';
/**
* An array of search result
*
* #var $Keyword string
*
* #return array
*/
public function FindStaffMember($Keyword){
$ResponseData="No Record Found!";
//::You could past third parameter
//$this->like('title', 'match', 'before'); // Produces: WHERE `title` LIKE '%match' ESCAPE '!'
//$this->like('title', 'match', 'after'); // Produces: WHERE `title` LIKE 'match%' ESCAPE '!'
//$this->like('title', 'match', 'both'); // Produces: WHERE `title` LIKE '%match%' ESCAPE '!'
$this->like("Staff_Name", $Keyword);
$this->orLike("Staff_Id", $Keyword);
$this->limit(10);
$this->orderBy("Staff_Name", "ASC");
//:::::
$query = $this->get();
//$RecordCounted=count($query->getResultArray()); //:::
if($query->getResultArray()){
$ResponseData=$query->getResultArray();
}
return $ResponseData;
}
}

Related

Laravel: pass an argument to the relationship function (not the query callback function) when using whereHas

I would like to know how to pass an argument to a model relationship function. Just to be clear, I'm NOT talking about the query callback.
Consider a model like so:
class UserRelationships extends Model
{
// other stuff
// dynamic scope:
/**
* Scope a query to only include users of a given type.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #param mixed $type
* #return \Illuminate\Database\Eloquent\Builder
*/
// $relationships = UserRelationships::at( Carbon::parse('2022-10-10') )->get();
public function scopeAt($query, Carbon $date)
{
return $query->where('superseded_at', '>', $date )
->where('created_at', '<=', $date );
}
}
And a related model featuring the following relationships:
class User extends Authenticatable
{
public function progenial_relation(Carbon $date=null) // returns this user record in the userRelationships table, which can be used to retrieve this users parent (directly lookup the sponsor_id)
// when eager loading, this is useful for getting all users whose parent is x, hence the name
{
return $this->hasOne(UserRelationships::class, 'user_id', 'id')
->at( #$date ?: Carbon::now() ) // local dynamic scope in userRelationships
->orderByDesc('created_at')
->limit(1);
}
public function parental_relation(Carbon $date=null) // returns records from the userRelationships table, of all the users which refer to this user as their sponsor
// when eager loading, this is useful for getting the user whose child is x, hence the name
{
return $this->hasMany(UserRelationships::class, 'sponsor_id', 'id')
->at( #$date ?: Carbon::now() ); // local dynamic scope in userRelationships
}
}
As you can see my relationships accept an argument (the date).
Now, if you wanted to use those relationships straightforwardly like so, there's no issues:
$date = Carbon\Carbon::parse('2022-06-01');
$relations_at_date = User::find(1)->parental_relation( $date )->get();
But what happens if you need to use eager-loading methods such as has(), whereHas(), doesntHave(), whereDoesntHave()?
How do you pass an argument to the relationship? For example, I wanted to add other relationships to my User model.
public function children(Carbon $date=null)
{
$date = #$date ?: Carbon::now();
return self::whereHas('progenial_relation', function($q) {
$q->where('sponsor_id', $this->id);
}, $date); // not working
}
I tried with these syntax, but it doesn't work:
whereHas( 'relationship_name', $callback, $argument )
whereHas( 'relationship_name', $argument, $callback )
whereHas( 'relationship_name', [$argument], $callback )
whereHas( 'relationship_name', $callback, [$argument] )
Is it somehow possible?
Are there any alternatives?
For completeness I'm going to add what happens if I use a normal closure:
public function children(Carbon $date=null)
{
$date = #$date ?: Carbon::now();
return self::whereHas('progenial_relation', function($q) use ($date) {
$q->at($date)->where('sponsor_id', $this->id);
});
}
This is the resulting SQL. As you can see the constraints are applied twice. Once by the query callback and once by the relationship. But since I cannot pass the correct argument to the relationship, it gets the default one. The 2 constraints collide and the query does not work.
"select * from `users`
where exists (
select *
from `user_relationships`
where `users`.`id` = `user_relationships`.`user_id`
and `user_relationships`.`superseded_at` > ?
and `user_relationships`.`created_at` <= ?
and `sponsor_id` = ?
and `user_relationships`.`superseded_at` > ?
and `user_relationships`.`created_at` <= ?
)
and `users`.`deleted_at` is null"
I don't think that its possible to pass variables to relationship methods when eager-loading like this.
But you can apply a sub-query to the wherehas:
$date = #$date ?: Carbon::now();
return self::whereHas('progenial_relation', function($q) use ($date) {
$q
->where('sponsor_id', $this->id)
->at( #$date ?: Carbon::now() );
}, $date);
Although I'm not sure what the ->at method/scope you added does.

Laravel 8 Paginate Collection (sortBy)

I try to paginate a sorted collection in Laravel 8, maybee any one have an idea?
That's my code:
$where = Business::where('name', 'LIKE', '%' . $what . '%');
$businesses = $where->get()->sortByDesc(function($business) {
return $business->totalReviews;
})->paginate(10); // <--- not working.. Collection::paginate not exists
Paginate can only be called on a builder instance (it makes no sense to call it on a collection as you already have all the data). But you are doing some logic based on the review count that requires a model method which must can only be called after fetching the data.
So you must refactor the ordering so that it gets called on the builder instance so that the ordering happens on SQL before the pagination logic happens.
withCount('relation') is perfect for this as it will append on a count of a specific relation onto your query which you can then sort by on SQL.
For example you can try this where reviews is a relation on the Business model that you have many of (likely either belongsToMany or hasMany):
Business::withCount('reviews')
->where('name', 'LIKE', '%' . $what . '%')
->orderBy('reviews_count', 'desc')
->paginate(10);
Where inside your Business model you have:
public function reviews()
{
return $this->hasMany(Review::class);
}
Remove the get:
$businesses = $where->sortByDesc(function($business) {
return $business->totalReviews;
})->paginate(10);
I fixed it on this way
$businesses = $where->get()->sortByDesc(function($business) {
return $business->getTotalReviews();
});
$businesses = ViewHelper::paginate($businesses, 10);
ViewHelper.class
<?php
namespace App\Classes;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Database\Eloquent\Collection;
class ViewHelper
{
/**
* Gera a paginação dos itens de um array ou collection.
*
* #param array|Collection $items
* #param int $perPage
* #param int $page
* #param array $options
*
* #return LengthAwarePaginator
*/
public static function paginate($items, $perPage = 15, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
}

How can i decode json data if i saved in array laravel?

I have 2 two tables: one is an admission and the other is a class table. I am saving class id in admission class field of admission table by json_encode method.
My controller
public function store(Request $request)
{
$inputs = $request->all();
$admission = new Admission;
$admission->school_id = Auth::User()->id;
$admission->admission_classes=json_encode($inputs['admission_classes']);
$admission->save();
}
My index function
public function index(Request $request) {
$school_id= Auth::user()->id;
$admissions= Admission::where('school_id',$school_id)->orderBy('id','desc')->paginate(10);
return view('frontend.index',compact('admissions','active_class'));
}
My view
#foreach($admissions as $i => $admission)
{{ $admission->admission_classes }}
#endforeach
I am getting data in this way:-
["1","2","4","5","6","7","8","9"]
But I want to get in this format:
Nursery,Class 1, Class2, Class3 etc
My class controller
class Classes extends Authenticatable
{
use EntrustUserTrait;
use Billable;
use Messagable;
protected $fillable = [
'name','status'
];
}
You need to save integer value in as json array and do the following code
$integerIDs = array_map('intval', $inputs['admission_classes']);
$admission->admission_classes= json_encode($integerIDs);
public function index(Request $request){
$admissions = DB::select('SELECT a.*, GROUP_CONCAT(c.name) as classes FROM academy as a LEFT JOIN class c ON JSON_CONTAINS(a.classes, CAST(c.id as JSON), '$') WHERE a.school_id =2 GROUP BY a.id');
$admissions = $this->arrayPaginator($admissions, $request);
return view('frontend.index',compact('admissions','active_class'));
}
public function arrayPaginator($array, $request)
{
$page = Input::get('page', 1);
$perPage = 10;
$offset = ($page * $perPage) - $perPage;
return new LengthAwarePaginator(array_slice($array, $offset,
$perPage, true), count($array), $perPage, $page,
['path' => $request->url(), 'query' => $request->query()]);
}
I have not checked the code hope this will help u to continue.......
The best way to achieve this would be to have a one-to-many relationship with App\Classes.
However, since you already have something up and running, I would probably do it like this.
First, I would cast admission_classes to an array. This makes sure that admission_classes will always be casted to an array whenever it is fetched. It makes it easier for us to work with it.
protected $casts = [
'admission_classes' => 'array'
];
Finally, while fetching your admission records, you would also need to map over it and hydrate the Classes from its ids. This is how I'd try to achieve it.
$admissions = Admission::where('school_id',$school_id)
->orderBy('id','desc')
->paginate(10)
->map(function($admission) {
return array_map(function($class) {
$class = Classes::find($class);
return isset($class) ? $class->name : '';
}, $admission->admission_classes);
});
You will notice that I wrapped the Classes::find() method into the optional() helper. This is because, in case, a record is not found, it will not fail.
Finally, to print your class names in your blade, you would do something like this:
implode(',', $admission->admission_classes);

Laravel Eloquent get() indexed by primary key id

I often find it very useful to index my results by the primary key id.
Example:
$out = [];
$users = User::where('created_at', '>=', '2015-01-01')->get();
foreach ($users as $user) {
$out[$user->id] = $user;
}
return $out;
Is there anyway to do this in one shot with Eloquent? It's not useful to use the 0...n index.
You can accomplish this by using getDictionary() on your collection.
Like so:
$users = User::where('created_at', '>=', '2015-01-01')->get()->getDictionary();
Note: in newer version of Laravel (5.2+), getDictionary() was removed; keyBy() can be used instead:
$users = User::where('created_at', '>=', '2015-01-01')->get()->keyBy('id');
I created my own solution by having a super Model that extends Eloquent.
Full solution:
https://gist.github.com/yadakhov/741173ae893c1042973b
/**
* Where In Hashed by primary key
*
* #param array $ids
* #return array
*/
public static function whereInHash(array $ids, $column = 'primaryKey')
{
$modelName = get_called_class();
$primaryKey = static::getPrimaryKey();
if ($column === 'primaryKey') {
$column = $primaryKey;
}
$rows = $modelName::whereIn($column, $ids)->get();
$out = [];
foreach ($rows as $row) {
$out[$row->$primaryKey] = $row;
}
return $out;
}
Not with eloquent but this is potentially nicer option than looping through all the results.
$users = Users::all();
return array_combine($users->modelKeys(), $users);
You can use keyBy()
$users = User::where('created_at', '>=', '2015-01-01')->get()->keyBy('id')->toArray();

Eloquent - where not equal to

I'm currently using the latest Laravel version.
I've tried the following queries:
Code::where('to_be_used_by_user_id', '<>' , 2)->get()
Code::whereNotIn('to_be_used_by_user_id', [2])->get()
Code::where('to_be_used_by_user_id', 'NOT IN', 2)->get()
Ideally, it should return all records except user_id = 2, but it returns blank array. How do I tackle this?
Code::all()
This returns all 4 records.
Code model:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Code extends Model
{
protected $fillable = ['value', 'registration_id', 'generated_for_user_id', 'to_be_used_by_user_id', 'code_type_id', 'is_used'];
public function code_type()
{
return $this->belongsTo('App\CodeType');
}
}
Use where with a != operator in combination with whereNull
Code::where('to_be_used_by_user_id', '!=' , 2)->orWhereNull('to_be_used_by_user_id')->get()
For where field not empty this worked for me:
->where('table_name.field_name', '<>', '')
While this seems to work
Code::query()
->where('to_be_used_by_user_id', '!=' , 2)
->orWhereNull('to_be_used_by_user_id')
->get();
you should not use it for big tables, because as a general rule "or" in your where clause is stopping query to use index. You are going from "Key lookup" to "full table scan"
Instead, try Union
$first = Code::whereNull('to_be_used_by_user_id');
$code = Code::where('to_be_used_by_user_id', '!=' , 2)
->union($first)
->get();
Or like this:
Code::whereNotIn('to_be_used_by_user_id', [2])->get();
Fetching data with either null and value on where conditions are very tricky. Even if you are using straight Where and OrWhereNotNull condition then for every rows you will fetch both items ignoring other where conditions if applied. For example if you have more where conditions it will mask out those and still return with either null or value items because you used orWhere condition
The best way so far I found is as follows. This works as where (whereIn Or WhereNotNull)
Code::where(function ($query) {
$query->where('to_be_used_by_user_id', '!=' , 2)->orWhereNull('to_be_used_by_user_id');
})->get();
Here's a useful scope method that you can add to your model and use it for different columns.
/**
* #param Builder $query
* #param string $field
* #param $value
* #return Builder
*/
public function scopeWhereNot(Builder $query, string $field, $value): Builder
{
return $value === null
? $query->whereNotNull($field)
: $query->where(function ($q) use ($field, $value) {
return $q->where($field, '<>', $value)
->orWhereNull($field);
});
}
and use it as follows
Code::whereNot('to_be_used_by_user_id', 2)->get()

Resources