hey everyone I'm trying to make my laravel app faster and what I see in debug bar is so many duplicated queries
and why this happens? because I'm calculating discount in the product model and when I'm getting products in my foreach I use $product->discount() and let's see what's happening in the Product model and discount function, there it is
public function discount(){
$seller = ProductSeller::orderBy('price','asc')-where('product_id',$this->id)->first();
$sellerDiscount = Discount::where('seller_id',$seller->seller_id)-latest('created_at')->first();
$brandDiscount = Discount::where('brand_id',$this->brand_id)-latest('created_at')->first();
$categoryDiscount = Discount::whereIn('category_id',$cateName)-latest('created_at')->first();
}
these are the queries that are duplicating in my category pages in a foreach any idea to prevent the duplicating of each query?
Yes it happens, because you are calling function($product->discount()) instead of getting data from that. Try to use eager load to fix this.
And then get data like this,
$product->seller
You can do this from Your main query and put condition in that.
Related
I have a function in controller which fetches all products based on Auth::id:
$products = DB::table('products')
->where('created_by_id', Auth::id())
->get();
Then has a for each loop as follows which inserts and update:
foreach($products as $key => $product){
$previous_product = Product::create((array) $product);
$previous_product->save();
$previous_product->update(['created_by_id' => $reseller_id->reseller_id]);
}
Which work perfectly, but the problem I am facing is products are duplicated twice instead of duplicated once. as shown on below image:
What I have tried to do is to use replicate() method instead of create() but I got null on replicate and the problem still persists.
Any help given to resolve my issue will be greatly appreciated.
Try to use insertOrIgnore method with query builder It will fix your issue.
DB::table('products')->insertOrIgnore($arrayOfProducts);
I would give replicate another shot:
$products = Product::where('created_by_id', Auth::id())->get();
foreach ($products as $product) {
$product->replicate()
->fill(['created_by_id' => $reseller_id->reseller_id])
->save();
}
The code you have doesn't appear that it would cause 2 new records to be inserted, though the save call you have is unneeded since create creates the record (saves it) and update calls save.
You can also updateOrCreate() method for the operation so that way you're sure to be only updating if the record exists or create. Here's a link https://laravel-news.com/firstornew-firstorcreate-firstor-updateorcreate
To do pagination in laravel, the easiest way is by:
$items = ModelOfItem::orderBy('my_order_field', 'asc')->paginate(10);
However, in this pagination, I need to relate data from another table to this page. Currently, I do it by:
$item_ids = ModelOfItem::orderBy('my_order_field', 'asc')->take(10)->list('id');
$related_items = ModelOfRelatedItem::whereIn($item_ids)->get();
However, it needs to query database twice on data that I already have in hand, and it is painful to handle page after first page. Is there a way I can get a list of id from the pagination result so I can use to directly query on the second table?
P.S. It is an old project so it is still using Laravel 4.2.
Why don't you use joins? You can join the tables & call ->paginate(10) as the end method. if you still want this approach for whatsoever reason.. You can call ->lists('id') on paginator object as well.. like this:
$items = ModelOfItem::orderBy('my_order_field', 'asc')->paginate(10);
$item_ids = $items->lists('id');
$related_items = ModelOfRelatedItem::whereIn($item_ids)->get();
I'm having a little problem with laravel that may be easily solved. To be short, the situation is: I have two tables, one for the users and the other one for products that has a column 'user_id' so I can identify the associated user.
In Laravel, I can use
$user = Sentry::getUser(); //Or Auth::user() if you're not using Sentry
$products = DB::table('table2')->where('user_id',$user->id);
And that should give me every product that user has. Good.
Now I want to show the products individually on screen, but unfortunately that doesn't work. It seems I can't echo this information in a string because it's made of multiple rows. I get
Object of class Illuminate\Database\Query\Builder could not be converted to string
For the solution, since the maximum associated products I allowed in the system is 3, I came up with the idea of getting each row separately and echoing them. For the first one, it's simple: $products->first(); but I have no idea on how to get the other two.
And maybe I'm being a newbie here, but I don't think I can use the products' id info since $products->id returns an error.
Can anyone help me?
Thanks in advance!
You want to use take, limit the number of results to three and then print out every one with a foreach loop. Docs: Laravel Queries, see skip and take.
$products = DB::table('table2')->where('user_id',$user->id)->take(3)->get()
Then, inside your view, you can just iterate through this data:
#foreach($products as $p)
Alternatively, in your PHP you can iterate through this data using something like:
foreach ($products as $product) { var_dump($product); }
(You are getting that error because you are trying to output a result object as a whole, and not the data it contains. Using the loop actually fetches the data from the result object so you can then use the loop variable ($product) normally.)
To get data from database you can use one one those methods: all, get, or first.
Using all:
$products = DB::table('table2')->all();
you are getting all the products.
Using first you can use conditions but you will get only first record that fulfil conditions:
$products = DB::table('table2')->where('user_id',$user->id)->first();
Using get you can use conditions and you will get all the records that fulfil those conditions:
$products = DB::table('table2')->where('user_id',$user->id)->get();
So in your case you want to use get to get data from database.
When you are using
$products = DB::table('table2')->where('user_id',$user->id);
Then $products is an array and you do not have to echo an array.
To display the products you need to use a foreach loop like below
foreach ( $products as $key => $product ) {
var_dump( $product );
}
If you want to show only three products, then you can use for loop inside foreach.
You can learn more about foreach from below link
http://php.net/manual/en/control-structures.foreach.php
Hiho everybody! I hope you'll give me a clue about this because I'm still noob with Magento.
I try to display a list of products I get in an array. In Mage/Catalog/Block/Product/List.php, I created a new Varien_Data_Collection() in which I pushed my products objects (with ->addItem($product)).
Then I return my custom collection and List.php class does his work with it to display the list of products.
When I call the page in my browser, I had the right number of displayed products and when I click on it to see the product page, I get the right page.
However, all the data (like the product name, the price, etc) are empty. I guess that the methods used by List class to catch these data fail with my Varien_Data_Collection object.
To illustrate, here is my code sample :
// getting a particular product
$mainProduct = Mage::getModel('catalog/category')->load($currentCat->getId());
$mainProduct = $mainProduct->getProductCollection();
$mainProduct = $mainProduct->addAttributeToFilter('product_id', $_GET['cat_id']);
// creating a custom collection
$myCollection = new Varien_Data_Collection();
foreach ($mainProduct as $product) {
// getting my particular product's related products in an array
$related = $product->getRelatedProductIds();
if ($this->array_contains($related, $_GET['cat_id'])) {
// if it suits me, add it in my custom collection
$myCollection->addItem($product);
}
}
return $myCollection;
And this is what I get in my list page :
When I var_dump($myCollection), I can see that ['name'], ['price'], etc fields are not referenced. Only ['product_id'] and many other fields I don't care about.
My very ultimate question is : how can I return a collection containing these products data to my List class ? I know that it is poorly explained but my English is very limited and I try to do my best :(
Calling ->getProductCollection() against a category only returns skeleton data for each product in the created collection. If you want full data for each of the products, you need to then load them, so in your foreach loop you would have:
$product = Mage::getModel('catalog/product')->load($product->getId());
However the way in which you are building the collection is not the best working practice - you should never have to create your own Varien_Data_Collection object, instead you should be creating a product collection as follows:
$collection = Mage::getModel('catalog/product')->getCollection();
Then before you load the collecion (which the foreach loop or calling ->load() against the collection will do as 2 examples), you can filter the collection according to your requirements. You can either do this using native Magento methods, one of which you are already using (addAttributeToFilter()) or I prefer to pull the select object from the collection and apply filtering this way:
$select = $collection->getSelect();
You can then run all of the Zend_Db_Select class methods against this select object to filter the collection.
http://framework.zend.com/manual/1.12/en/zend.db.select.html
When the collection has been loaded, the products inside it will then contain full product data.
first of all pelase do not use $_GET variable, use Mage::app()->getRequest()->getParams();
second why not try to build your collection correctly from the start?
here is what your code does:
$mainProduct = Mage::getModel('catalog/category')->load($currentCat->getId());
$mainProduct = $mainProduct->getProductCollection();
$mainProduct = $mainProduct->addAttributeToFilter('product_id', $_GET['cat_id']);
get one product, I mean you load a category then load a product collection, then filter by product id.. why not:
$mainProduct = Mage::getModel('catalog/product')->load($yourSearchedId);
I aslo do not see why you filter products by $_GET['cat_id'] which looks like a category id...
To conclude you can get more help if you explain exactly what you are trying to find. It looks like you are trying to find all products that have a given product as related. So why not set for that given product the related product correctly and get the related products collection.
$_product->getRelatedProductCollection();
UPDATE:
now that you cleared your request try this:
$relatedIds = $product->getRelatedProductIds();
$myCollection = Mage::getModel('catalog/category')
->load($currentCat->getId())
->getProductCollection();
$myCollection->addAttributeToFilter('product_id', array("in",$relatedIds));
//also addAttributeToSelect all attributes you may need like name etc
$myCollection->load(); //maybe you don't actualy need to load here
Please bear in mind I did not test this code it was written from teh top of my head, test it. But I hope you got the idea.
I'm wondering if Yii has an efficient method for grouping items by type.
Let's say I have the following model:
Tag
------
id
name
type_id
And let's say there are 5 different types of Tags. I want to be able to display in my index all tags in sections by type_id. Is there a Yii-way of accomplishing this?
Outside a framework I would write a function such that results fetched from the DB were stored like this:
$tags[$typeID][] = $tag;
Then in each section I could do something like:
foreach( $tags[$typeID] as $tag )
{
// Here are all tags for one $typeID
}
But I'm having difficulty figuring out how to do this in Yii without:
A) looping through the entire result set first and rewriting it or,
B) running 5 different queries.
When using ActiveRecord simply specify the "index" in the DBCriteria. So in a query do:
ActiveRecordClass::model()->findAll(array('index'=>'type_id'));
That will return an assoc array that your after. TBF it probably executes exactly the same code, but this is obviously easier to use that performing it everywhere.
Assuming that your active record class is called MyActiveRecordClass, the simplest approach should be sufficient:
$models = MyActiveRecordClass::model()->findAll();
$groupedModels = array();
foreach ($models as $model) {
$groupedModels[$model->typeID][] = $model;
}
If you give more specific information about how you intend to display the grouped results it might be that a better approach can be worked out.