I have a query as:
$Category = DB::table('food')
->select('food.Food_id','food.FoodName','categories.CategoryName')
->join('categories','categories.Category_id','=','food.Category_id')
->where('categories.CategoryName', '=','Breakfast')
->get();
But I want query based on if condition,meaning that if Category is Breakfast then only food items related to Breakfast are shown or IF Category is Lunch then only food items related to that category are shown.I am using laravel 5.2
Try something like this. You don't have to make a query all at once. You can combine it through several steps. Until you perform get(), find() or something similar in the end, it won't return query results, but only kind of query builder object if I'm not wrong.
// You should probably send this as a method parameter so you can determine if you should get one, or the other category
$cat = 1;
$Category = DB::table('food')
->select('food.Food_id','food.FoodName','categories.CategoryName')
->join('categories','categories.Category_id','=','food.Category_id');
if($cat == 0){
$Category = $Category->where('categories.CategoryName', '=','Breakfast');
}
if($cat == 1){
$Category = $Category->where('categories.CategoryName', '=','Lunch');
}
$Category = $Category->get();
Related
Let's say I have Category model with hasMany relation to Product model. Product has color column.
I want to return all categories with all colors that exists in this category, so I tried:
return Category::with(['products' => function ($query) {
$query->distinct('color');
}])->get();
Thanks to this I could later foreach or pluck category->products to get unique colors list. I know I can just get all products in every category, and then filter unique colors, but by doing this I would have to query for example 1000 products per category, instead just 5, which is unnecessary resource heavy. That's why I'm trying to do this on SQL level not PHP.
But this code does not work. There are no errors, it just still returns all products with duplicated colors. Why?
Edit:
Not sure why but my code works if I add select() with used columns before discrinct, and then distinct is making unique rows by all choosed columns. No "color" param required in distinct. Not sure why it works that way, need to dive deeper into SQL docs.
Have you tried this code? Somehow, this will reduce your unnecessary query.
$categories = Category::with([
'products'=> fn($q) => $q->select(['category_id', 'color'])->distinct('color')
])
->select('id') // select required column in categories table
->whereHas('products')
->get();
$colors = $categories->map(function($category) {
return $category->products->pluck('color');
})->toArray();
$color = [];
for ($i=0; $i < count($colors); $i++) {
$color = array_merge($color, $colors[$i]);
}
$uniqueColor = array_unique($color);
return $categories;
I want to get 2 result from a filter query in Laravel version 6. I want to get product table information that user can change item exist in page by a select box with name of pageitemcount and can search by a field with name of select. when user select pageitemcount and also search for an name, submit a form and below query is run . When user search anything, available filter of category must be limited to available categories. I want to show distinct product category in additional to product list.
public function productIndex(Request $request)
{
$take = 10;
$query = Product::query();
if ($request->has('pageitem')){
$take = $request->input("pageitem");
}
// Search
if ($request->has('search')){
$query = $query->where('name', $request->input("search"));
}
$availableCategoriesQuery= $query;
// Get product unique product category to show them to user
// that exist in prodcut list that show to user
$availableCategories = $availableCategoriesQuery->select("category_id")->distinct()->get();
// Get product list by pagination
$productList = $query->paginate($take);
return view('admin.manage_product', ['productList' => $productList, 'availableCategories' => $availableCategories]);
}
but when $availableCategories is executed, affected $query variable, and i cant get right result from next line, i get result of $availableCategories in $productList variable. i do'nt want to repeat my code again, how can i deal with?
the result of $availableCategories is completely true, but result of productList is $availableCategories that is paginated.
OK, I think I see the problem. You are trying to reuse the $query variable. You probably want something like this:
I assume that product_categories is the table for your product categories. You can also use the model if you want.
Also, Since the DB has no intrinsic order, you should specify an OrderBy() as well.
$take = $request->input("pageitem", 10);
$productList = Product::paginate($take)->get();
$availableCategories = DB::table('product_categories')->distinct()->get("category_id");
My product can have many categories. In one part of the object however, I need to get a specific Category. So instead of getting all the categories and then in a for loop search for specific one, I need to get only this specific category. For that I am using query builder.
public function findProduct($id) {
$qb = $this->createQueryBuilder('p')
->addSelect(array('p', 'cat')) // many to many table
->addSelect(array('p', 'category')) // the category entity
->leftJoin('p.category', 'cat')
->leftJoin('cat.category', 'category')
->andWhere("category.id = 15") // error here
->SetParameter('id', $id);
return $qb->getQuery()->getOneOrNullResult();
}
With this query I am easily able to do $product->getCategory[0]([] since array) and get only the category that I need(in this example category with id=15)
THE PROBLEM:
However if the product doesnt have a category with a specific id.. It returns whole product null..
So If i do:
$product = $em->getRepository('MpShopBundle:Product')->findProduct($id); = null
But instead it should be like this:
$product = $em->getRepository('MpShopBundle:Product')->findProduct($id); = object
$product->getCategory() = null
How can I make this work in query builder? Is that even possible?
This should work. Instead of constraining your whole query (which is what that does) just constrain the join).
leftJoin('cat.category', 'category', 'WITH', 'category.id = 15')
This way you should get your product always & category only if id == 15.
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();
I made the following method in custom Magento controller to retrieve all the manufacturers in the specified category. The module is made as a service to get the data for ajax calls.
I made a number of methods like this and all are executed on my local server in the range of 5-7 seconds. This one takes 14 seconds to execute on local server.
Can you help me to find a bottleneck here:
public function subcategoryAction() {
$storeId = Mage::app()->getStore()->getStoreId();
// Subcategory ID passed with a GET method
$sub = $this->getRequest()->getParam('subcategory');
if ($sub) {
// Querying to get all product ID's in the specified subcategory
$product_ids = Mage::getResourceModel('catalog/product_collection')
->setStoreId($storeId)
->addAttributeToFilter('status', array('eq' => '1'))
->addAttributeToFilter('visibility', 4)
->addCategoryFilter(Mage::getModel('catalog/category')
->load($sub))->getAllIds();
$product = Mage::getModel('catalog/product');
// Load all the product models by their ID's
foreach ($product_ids as $id) {
$product->load($id);
$manufacturers[] = $product->getAttributeText('manufacturer');
}
// Getting unique values of manufacurers, just like array_unique
$manufacturers[$product->getAttributeText('manufacturer')] = $product->getAttributeText('manufacturer');
// Echoing default option value
echo "<option value='all'>BRAND/MAKE</option>";
// Echoing and formatting manufacturers for a dropdown
foreach ($manufacturers as $manufacturer) {
if ($manufacturer != "") {
echo "<option value='" . $manufacturer . "'>" . $manufacturer . "</option>";
}
}
}
}
Accepted #Mischa Leiss suggestion, changed this messy unique values code:
$manufacturers=array_flip(array_flip(array_reverse($manufacturers,true)));
to his code:
$manufacturers[$product->getAttributeText('manufacturer')] = $product->getAttributeText('manufacturer');
SOLUTION
This is the quickest solution, all thanks to #Mischa
$products = Mage::getResourceModel('catalog/product_collection')
->setStoreId($storeId)
->addAttributeToSelect('manufacturer')
->addAttributeToFilter('status', array('eq' => '1'))
->addAttributeToFilter('visibility', 4)
->addCategoryFilter(Mage::getModel('catalog/category')
->load($sub));
Takes only about 2 seconds.
A. the bottleneck is that you explicitly load each model instead of fetching the data straight from the collection itself - dont get the ids but a collection of products and iterate over it.
B. next thing is, why dont you just add the manufacturer attribute id as array key, so you dont need to array flip.
$manufacturers[$product->getManufacturer()] =
$product->getAttributeText('manufacturer');
C. even better would be to build some custom source model to simply do a smarter sql query.
I assembled a little join series (used color attribute) to get the label/value pair via a product collection:
$collection = Mage::getModel('catalog/product')->getCollection();
//get the color attribute joined
$collection->addAttributeToSelect('color', 'left');
//join the label from the attribute option table
$collection->joinField('color_label', 'eav_attribute_option_value', 'value', 'option_id=color');
//group for uniqueness reset the columns and fetch what we want
$collection->getSelect()->group(array('color_label'));
$collection->getSelect()->reset(Zend_Db_Select::COLUMNS);
$collection->getSelect()->columns(array('color_label' => 'at_color_label.value', 'color_id' => 'at_color_label.option_id'));
Good luck!