Laravel 4.1 WhereIn w/ Many to Many Relation and Conditionals? - php

I am working on an application where part of it needs to search through a number of different fields on the same model with AND - AKA find age whereBetween $from and $to AND where gender is $gender. Where I am getting lost is this model has a many to many relationship with Category and I need to filter by category in the same query. I am trying to do this in one query because it needs to be pretty fast.
Here is what I have so far:
$categories = Input::get('categories');
$query = Program::with('categories')->whereIn('category', $categories)->query();
if ($ages = Input::get('ages')) {
$query->whereBetween('age',array($from,$to));
}
if ($gender = Input::get('gender')) {
$query->where('gender','like', $gender);
}
// Executes the query and fetches it's results
$programs = $query->get();
I have put this together from so many different sources that I would like to know if this even works, or if it is the most efficient method possible. There is of course a table programs, a table categories, and a table program_category with columns id, program_id, and category_id.
Thanks in advance for your help!

So, in the end figured it out:
$query = Program::whereHas('categories', function($q) use ($categories)
{
$q->whereIn('categories.id', $categories);
});
'categories' is the name of the relationship function on my Program model. $categories is my array of category ids. Thanks again for your help.

This will work if fields are available in the right table as you queried for and you may write it like this:
$categories = Input::get('categories');
$query = Program::with('categories')->whereIn('category', $categories);
// declare $from and $to if not available in the current scope
if ($ages = Input::get('ages')) $query->whereBetween('age', array($from,$to));
if ($gender = Input::get('gender')) $query->where('gender', $gender);
// Executes the query and fetches it's results
$programs = $query->get();

Related

Fetch featured product only from product table in Api

Product Table
where i want to fetch only featured product. I have defined a column in database product_type in which four types of products(hot deals, newly listed, deals of the day and featured product)strong text can be listed which is optional.
Blockquote
Here is my model|query code in codeigniter
public function featured_product()
{
$arrResult = array();
$this->db->select('*');
$this->db->from('product');
$this->db->where("product_type","featured");
$result = $this->db->get()->result_array();
if(!empty($result))
{
$arrResult['result'] = $result;
}
else
{
$arrResult['result'] = '';
}
return $arrResult ;
}
When i try to fetch whole product list in api i get the result but i want to show only featured product.
You could try and use find_in_set:
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_find-in-set
I don’t know codeigniter, but I think, this looks useful:
https://forum.codeigniter.com/thread-71337.html
I propose a different approach.
This is not an answer to your question, but I hope it will allow you to rethink your table structure.
Instead of storing all the product_types in a single column use a pivot table (also known as a junction table).
You'll want to store all the data that you currently have in product_types column in a separate table(the pivot, lets call it product_to_type) and reference the id of product_table and product_type in the pivot table.
Something like this:
Here's a nice db-fiddle to play around with if you want.
This has multiple advantages:
You have a atomic tables
You can add data to either table without causing trouble in other tables
Foreign key ensure data consistency(you can probably do a better job with that. The keys are used are decent but not great)
You can extract any sort of data with the correct use of joins
You can add indexes to make the query buttery smooth
I'm sure there are other advantages too.
As I have changed my database to separate table with product_id matching with product_type. Still I find the solution to my question with a function FIND_IN_SET().
Here is my updated modal query:
public function featured_product()
{
$arrResponse = array();
$data = 'featured';
$this->db->select('*');
$this->db->where('find_in_set("'.$data.'", product_type) <> 0');
$this->db->from('product');
$result = $this->db->get()->result_array();
if(!empty($result))
{
$arrResponse['result'] = $result;
}
else
{
$arrResponse['result'] = '';
}
return $arrResponse ;
}

Query Laravel Eloquent many to many where all id's are equal

I making a project based on Laravel and have the tables: companies, attributes, and attribute_company related as Many To Many relation when attribute_company use as a pivot table to connect companies and attributes tables.
I get an array of attribute_id's from the client and I need to get results of the companies that has the whole attributes exactly.
The only solution I found is to query whereHas combined with whereIn inside like this:
Company::whereHas('attributes', function (Builder $query) use ($atts_ids) {
$query->whereIn('attribute_id', $atts_ids);
})->get();
This query will return companies if at least one attribute_id found (which is not what I am looking for).
It would be great if anybody can make it clearer for me.
Thank you all in advance :)
One possible solution:
$company = new Company();
$company = $company->newQuery();
foreach($atts_ids as $att_id)
{
$company = $company->whereHas('attributes', function (Builder $query) use ($att_id) {
$query->where('attribute_id', $att_id);
});
}
$company = $company->get();

How to query related records only using where clause in laravel?

I tried to search students that belong to particular User/School only using the following the query. I have created one-to-many relationship between User and Students.. Everything seems okay but when I try to search students, it gives me list of students that belong to other Users too.
public function searchStudent(Request $request)
{
$q = $request->q;
$grades = Auth::user()->grades;
$searchPupils = Student::where('user_id','=',Auth::user()->id)->where('name','LIKE','%'.$q.'%')->orWhere('email','LIKE','%'.$q.'%')->get();
if(count($searchPupils) > 0)
{
return view('add-class', compact('grades'))->withDetails($searchPupils)->withQuery($q);
}
else
{
return view ('add-class', compact('grades'))->withMessage('No Details found. Try to search again !');
}
}
I also tried doing
$searchPupils = Auth::user()->students()->where('name','LIKE','%'.$q.'%')->orWhere('email','LIKE','%'.$q.'%')->get();
Still it searches for the whole Students table . How should it be done?
the problem is in your query where conditions, use advance where clause as below.
$searchPupils =Student::where('user_id','=',Auth::user()->id)
->where(function($query)use($q){
$query->where('name','LIKE','%'.$q.'%')
->orWhere('email','LIKE','%'.$q.'%');
})->get();

Refactoring Laravel function to reduce number of database queries

I wondered if anyone could offer me some advice on refactoring the below function to reduce the number of database queries? Alternatively, there may be a completely different way of achieving this using Laravel.
I am trying to calculate the P&L for a Job, which is made up of Products, which are made up of Components:
public function jobProfitAndLoss($id)
{
$products_in_job = DB::table('job_product')
->where('job_id', $id)
->get();
$total_price = 0.0000;
$total_cost = 0.0000;
foreach ($products_in_job as $row) {
$total_price = $total_price + ($row->quantity)*($row->price);
$product_id = $row->product_id;
$components_in_product = DB::table('components')
->where('product_id', $product_id)
->get();
foreach ($components_in_product as $component) {
$total_cost = $total_cost + ($component->cost)*($row->quantity);
}
}
return $total_price-$total_cost;
}
Products have Components -
https://www.dropbox.com/s/ncnij8dnh99sb9v/Screenshot%202016-04-09%2015.22.26.png?dl=0
Components belong to Products -
https://www.dropbox.com/s/3dx6u30gbod2rv4/Screenshot%202016-04-09%2015.23.43.png?dl=0
Jobs have many Products -
https://www.dropbox.com/s/q179t0knd7y8z4k/Screenshot%202016-04-09%2015.24.11.png?dl=0
You will see here that there are some of the same queries being executed multiple times, which I am not sure how to avoid in this situation -
https://www.dropbox.com/s/xonbtx9cdqvq1wd/Screenshot%202016-04-09%2015.33.07.png?dl=0
Any help is much appreciated.
Edit: It seems that you aren't using models. If you have not done so, create models for your database entries. You will need to use the protected $table attribute for job_product as Eloquent may not be able to automatically convert your class name into the correct table name.
First of all, set up relations if you have not done so. For example, under Job.php, include the Products relation:
public function products() {
return $this->hasMany(App\Products::class); // Assuming App is the namespace
}
Now, instead of using a Fluent query for $components_in_product, you are able to directly do $components_in_product = $products_in_job->products;. However, this still leads to N+1 queries.
As a result, take a look at this: https://laravel.com/docs/5.2/eloquent-relationships#eager-loading
$books = App\Book::with('author')->get();
foreach ($books as $book) {
echo $book->author->name;
}
For this operation, only two queries will be executed:
select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)
Therefore, change $products_in_job to an Eloquent query and add ->with('products') to the query.

Laravel multiple table join saved to a variable and running a foreach against it (search function)

I presently have 3 tables: Shows, Genres and Show_Genre (associates the two). I have a search form that submits a series of checkboxes with values into an array based on what genres they selected. Presently I want to associate the Shows table and the Genres table into a variable and run a query against it once for every genre checkbox selected. Then, once the selection is filtered, I can display the resulting Show objects that matched the users parameters.
My present setup is the following
public function searchShows(SearchRequest $request)
{
//$ShowsWithGenres give a collection inside a collection which I can't seem to even access its values without doing a bunch of ugly code using count() in a for loop
$ShowsWithGenres = Show::with('genres')->get();
$genres = $request->name;
if(isset($genres))
{
foreach($genres as $genre)
{
//iterate against the selection repeatedly reducing the number of results
}
}
}
Thanks.
You should use whereHas() and whereIn.
Perhaps something like this should do it:
$shows = Show::whereHas('genres', function($q) use($genre_ids)
{
$q->whereIn('id', $genre_ids);
})->get();
EDIT
Try this, however I'm unsure about the performance.
$query= Show::query();
foreach($genre_ids as $id){
$query->whereHas('genres', function($q) use($id)
{
$q->where('id', $id);
})
}
$shows = $query->get();
Using Eloquents whereHas() function you can query results based on the relation's data. http://laravel.com/docs/5.0/eloquent#querying-relations
public function searchShows(SearchRequest $request)
{
// Start a query (but don't execute it at this point as we may want to add more)
$query = Show::with('genres');
$genreNames = (array) $request->name;
// Check there are some genre names, if theres not any it'll cause an SQL syntax error
if (count($genreNames) > 0)
{
$query->whereHas('genres', function($subQuery) use ($genreNames)
{
$subQuery->whereIn('genre_name', $genreNames);
}
}
// Finally execute the query. $shows now contains only shows with the genres that the user has searched for, if they didn't search with any genres, then it contains all the results.
$shows = $query->get();
}

Categories