Refactor Query Builder Laravel - laravel

I want to do repetitive get data and foreach on several tables (see example below). Is there a way to write the code in a cleaner way instead of repeating the same code for all the tables?
$xs = DB::table('table1')->where('text', 'like', '%string')->get();
foreach ($xs as $x) {
..
}
$ys = DB::table('table2')->where('text', 'like', '%string')->get();
foreach ($ys as $y) {
..
}```

My approach is using array and foreach
$tables = ['table1', 'table2'];
results = [];
foreach($tables as $table) {
$data = DB::table($table)->where('text', 'like', '%string')->get();
foreach($data as $d) {
// your logic here
}
$results[] = ; // return a value from each query to array
}

You can write a base function and pass tableName to it and execute certain action
public function getData($tableName) {
$query = DB::table($tableName)->where('text', 'like', '%string')->get();
foreach ($query as $row) {
...
}
// return result;
}
$tables = ['table1', 'table2', 'table3'];
$queryResponse = [];
foreach($tables as $tableName) {
$queryResponse[$tableName] = $this->getData($tableName);
}

Related

How to use regex or any other operator with whereIn clause

Is there any way we can use operator or regex as we normally do with the whereIn() clause.
I want to use something like this
$query->whereIN(name,'like','%test%');
I'm getting multiple data in an array. It should return data if name contains any of the keywords.
For eg. $searchArray = ['test','case'];
So it should return data with name containing values in $searchArray
Is it possible?
The whereIn method verifies that a given column's value is contained within the given array:
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();
https://laravel.com/docs/9.x/queries#additional-where-clauses
Try this:
where('title', 'like', '%' . $keyword . '%')
UPDATE:
$query->where(function ($query) use ($keyword, $columns) {
foreach ($columns as $key => $column) {
$clause = $key == 0 ? 'where' : 'orWhere';
$query->$clause($column, "LIKE", "%$keyword%");
if (!empty($relativeTables)) {
$this->filterByRelationship($query, $keyword,
$relativeTables);
}
}
});
I Had the same problem. The only way i was able do solve, was with mongodb native query aggregation. Let me show how i did.
I made a function to use in all of my system
public function matchLikeIn($match, $field, $value,$option = 'i')
{
try {
$or = array();
foreach($value as $v){
$or['$or'][] = [
$field => [
'$regex' => $v,
'$options' => $option
]
];
}
$match['$and'][] = $or;
return $match;
} catch (Exception $e) {
}
}
A exemple using it
$match = array();
$names = ["name1","name2"];
$match = $this->matchLikeIn($match, "name", $names, 'i');
$aggregate[] = ['$match' => $match];
$query = Model::raw(function ($collection) use ($aggregate) {
return $collection->aggregate($aggregate);
})->toArray();

Laravel query groubBy condition

I have a dB query where I would like to groupBy() only when conditions are met without using union because of pagination.
Unfortunately groupBy() seems to only work when called on the entire query outside of the loop.
This was made for dynamic filtering from $filterArr. Depending on the array I need to select from different columns of the table.
When the $key=='pattern' I would need the distinct results from its column.
the query looks something like this
select `col_1`, `col_2`, `col_3`
from `mytable`
where (`color` LIKE ? or `pattern` LIKE ? or `style` LIKE ?)
group by `col_2` //<< i need this only for 'pattern' above and not the entire query
Heres the model:
// $filterArr example
// Array ( [color] => grey [pattern] => stripe )
$query = DB::table('mytable');
$query = $query->select(array('col_1', 'col_2', 'col_3'), DB::raw('count(*) as total'));
$query = $query->where(function($query) use ($filterArr){
$ii = 0;
foreach ($filterArr as $key => $value) {
if ($key=='color'){
$column = 'color';
}else if ($key=='style'){
$column = 'style';
}else if ($key=='pattern'){
$column = 'pattern';
$query = $query->groupBy('col_2'); // << !! does not work
}
if($ii==0){
$query = $query->where($column, 'LIKE', '%'.$value.'%');
}
else{
$query = $query->orWhere($column, 'LIKE', '%'.$value.'%');
}
$ii++;
}
});
$query = $query->orderBy('col_2', 'asc')->simplePaginate(30);
I think you can simplify your code a bit:
$query = DB::table('mytable');
$query = $query->select(array('col_1', 'col_2', 'col_3'), DB::raw('count(*) as total'));
$query = $query->where(
collect($filterArr)
->only(['color','style','pattern'])
->map(function ($value, $key) {
return [ $key, 'like', '%'.$value.'%', 'OR' ];
})->all()
)->when(array_key_exists('pattern', $filterArr), function ($query) {
return $query->groupBy('col_2');
});
$query = $query->orderBy('col_2', 'asc')->simplePaginate(30);

Laravel - passing array of columns in 'where' clause

I have a search query like this:
$data = User::where('first_name', 'like', '%'.$query.'%')
->orWhere('last_name', 'like', '%'.$query.'%')
->get();
Now, I have many models, each with different column names. Instead of defining a search() function into every controller, I want to do this:
// User
public static function searchableFields()
{
return ['first_name', 'last_name'];
}
// Some other model
public static function searchableFields()
{
return ['name', 'description'];
}
And put the search logic in a shared controller, something like this:
$data = $classname::
where($classname::searchableFields(), 'like', '%'.$query.'%')
->get();
How can I achieve this?
Thanks a lot.
You can loop over the fields and add them to your Eloquent query one by one.
$data = $classname::where(function ($query) use ($classname) {
foreach ($classname::searchableFields() as $field)
$query->orWhere($field, 'like', '%' . $query . '%');
})->get();
I would use scope for that.
You can create base model that all the models should extend (and this model should extend Eloquent model) and in this model you should add such method:
public function scopeMatchingSearch($query, $string)
{
$query->where(function($q) use ($string) {
foreach (static::searchableFields() as $field) {
$q->orWhere($field, 'LIKE', '%'.$string.'%');
}
});
}
Now you can make a search like this:
$data = User::matchingSearch($query)->get();
Just to avoid confusion - $query parameter passed to matchingSearch becomes $string parameter in this method.
You can try something like this.
// Controller
function getIndex(Request $request)
{
$this->data['users'] = User::orderBy('first_name','asc')->get();
if ($request->has('keyword')) {
$results = User::search($request->keyword);
$this->data['users'] = collect([$results])->collapse()->sortBy('first_name');
}
}
// Model
function search($keyword)
{
$results = [];
$search_list = ['first_name','last_name'];
foreach ($search_list as $value)
{
$search_data = User::where($value,'LIKE','%'.$keyword.'%')->get();
foreach ($search_data as $search_value) {
$exist = 0;
if (count($results)) {
foreach ($results as $v) {
if ($search_value->id == $v->id) {
$exist++;
}
}
if ($exist == 0) {
$results[] = $search_value;
}
} else{
$results[] = $search_value;
}
}
}
return $results;
}

Showing the lowest pid / parent id number first

I have this function below which get the pid numbers from my database. The pid is parent id.
public function test() {
$arr = array();
foreach ($this->make_parent_list() as $result) {
$arr[] = $result;
}
print_r(implode(',', $arr));
}
The out put is as follows 4, 1
But I need it to print the lowest number first. 1, 4
Question How can I make sure when i view the parent id / pid that it
will show the lowest number first I have tried
$this->db->order_by('pid', 'desc'); and $this->db->order_by('pid',
'asc');
public function make_parent_list() {
$this->db->where('fid', '5');
$query = $this->db->get('forum');
$return = array();
foreach ($query->result() as $category)
{
$this->db->where('fid', $category->pid);
$this->db->order_by('pid', 'desc');
$query = $this->db->get('forum');
$return[$category->pid] = $category->pid;
foreach ($query->result() as $category)
{
$return[$category->pid] = $category->pid;
}
}
return $return;
}
Solved
I had to created a $results variable and then wrap in sort() outside foreach loop
$arr = array();
$results = $this->make_parent_list();
sort($results);
foreach ($results as $result) {
$arr[] = $result;
}
echo implode(',', $arr);
Now out put 1,4
I think you got a bit lost... The order_by asc,desc does work. Your function has order_by desc and an unnecessary foreach etc.
Assumptions: The forum table has at least the two columns pid and fid. I created a table with
fid , pid
5 1
5 4
If you simplify your function to...
// Given the fid, return an array of pid values in ascending order
public function make_parent_list() {
$this->db->where('fid', '5'); // Hardcoded for testing.
$this->db->order_by('pid', 'asc');
$query = $this->db->get('forum');
$pid_list = array();
foreach ($query->result() as $category) {
$pid_list[] = $category->pid;
}
return $pid_list;
}
Then you only need
$results = $this->make_parent_list();
echo implode(',', $results);
That will give you a result of 1,4.
If you change asc to desc in the order_by in the function then you will get 4,1.

Laravel foreach "where" with eloquent

I have certain fields and data values which cannot be hardcoded into the query. I'm trying to get something like this:
return Listing::where('id', $id)
->where(function($query) use ($input) {
->where('field_1', 'foo_1')
->where('field_2', 'foo_2')
->where('field_3', 'foo_3')
}
->get();
**Here's what I have **
return Listing::where('id', $id)
->where(function($query) use ($input) {
$i = 0;
foreach ($input as $key => $value) {
$i++;
// ->where('field_1', red_1); // Desired output
->where("where(field_{$i},".$value."_1)");
// $query = $query."where(field_{$i},".$value."_1)"."<br>";
// return $query prints out the following
/*
field_1 red_1,
field_2 foo_1,
field_3 bar_3
*/
}
})
->get();
Something like this should work:
$listing = Listing::where('id', $id);
foreach ($input as $key => $value) {
$i++;
// ->where('field_1', red_1); // Desired output
$listing->where("where(field_{$i},".$value."_1)");
}
$results = $listing->get();
$query = Listing::where('id', $id);
$i = 0;
foreach ($input as $key => $value) {
$i++;
$query->where('field_'.$i,$value.'_'.$i);
}
return $query->get();
One you're not chaining correctly and two you are mis-using the querybuilder closure. If you want to execute logic like a loop then you have to break down the query. Furthermore using a where closure is like writing a parenthesis around your where conditions.
Something like:
$query->where('bacon', $foo)
$query->where(function ($query) use ($bar, $baz){
$query->where('apple', $bar);
$query->orWhere('orange', $baz)
});
Would roughly translate to:
WHERE bacon = $foo AND (apple = $bar OR orange = $baz)

Resources