I know how to limit fields when dealing with a collection, but what I'm wondering is if I can limit the selected fields when using getModel()->load($id).
My thought process is if I know the ID I use:
Mage::getModel('model')->load($id)
as opposed to:
Mage::getModel('model')->getCollection()->addFieldToFilter('id', $id)->getFirstItem();
The issue is load($id) returns everything. I know I can use addFieldToSelect on the collection. Is there an equivalent when using load()? When I google this I get the collection method.
Thanks,
GG
EDIT:
I just want to add that if the collection way is how it's done than that's fine. I just want to make sure it can't be done using load().
No, there is no alternative to use the collection except for rewriting the model code altogether which is probably not what you want to do.
The model load call can only be used to load a full entry - what you can specify is the attribute which to use for the load. For example:
Mage::getModel('catalog/product')->load($sku,'sku')
will load a product by its sku.
In fact the model load itself simply defers to it's resource by doing:
$this->_getResource()->load($this, $id, $field);
But the resource load method does also not provide the ability to filter for specific attributes, so you will always load the full pack or use the collection.
You could try loading a collection with only one item (as you are doing now), and selecting what attributes you want using:
addAttributeToSelect('you_attribute_code_here')
This will return a collection (albeit containing one item), with only the attributes you wish to have returned. Example:
$productIds = array(166);
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('description')
->addFieldToFilter('entity_id', array('in' => $productIds));
$product = $collection->getFirstItem();
Related
I have created a extension that filters product collection based on a attribute.
Below is the controllers, block and view template code.
Controller
$url = Mage::getUrl('no-route');
if(Mage::app()->getRequest()->getParam('ajax')){
echo $this->getLayout()->createBlock('catalogextensions/bestsellers_home_list')
->setTemplate('catalog/landings/bestseller.phtml')
->toHtml();
}
else{
$this->loadLayout();
$this->getLayout()->getBlock('head')->setTitle('Besesellers');
$this->renderLayout();
}
Block product collection function
$storeId = Mage::app()->getStore()->getId();
$products = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('*')
->addAttributeToFilter(array( array( 'attribute'=>'top_seller', 'eq' => '1' )));
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($products);
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($products);
Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($products);
$products->getSelect()->limit(4,$this->get_cur_page());
return $products ;
Product collection is iterated on view.phtml template.
Now, it is taking 35 seconds to get the output, below are the statistics of execution that i was able to get by making use of PHP's microtime() function
For
Block(product collection ) it taking around 0.01 second
Template Rendering its taking around 0.12 second
But for controller function it is taking around 35 second
I am not able to find what to check, because controller function just create a Block at runtime.
*Note:I am making use of a Paid full page cache Extension "Mirasvit FPC".
how can i find it what is taking time
Server configuration is
30GB Ram with 4 vCPU.
Application server : Nginx + php5-fpm.
Version: Magento CE 1.8.0.1
Thanks.
You use a bit deprecated way to call the filters. I don't know if that can really influate the time of loading but using addFieldToFilter() would limit the calls to database and can be usefull. You can use :
Magento: Filter products by Status
filtering product collection on "is_salable"
The block is maybe not cached correctly. I mean the products are load each time the page is called.
Make sure your flat product is set to on and all attributes needed for your filters are set as filter.
If a listing comes from EAv tables it might consume lots of resources thus slowing down.
Additionally apply optimization tricks.
First, are you sure you need to add all attributes to select?
You can replace the
addAttributeToSelect('*')
with
addAttributeToSelect(array('attribute_code', 'attribute_code'))
Next, what exactly is that
$this->get_cur_page()
doing? Rest of code shouldn't make disastrous performance issues.
PS
This should have been a comment, but I'm unable to comment yet.
Doing this:
Mage::getModel('catalog/product')->loadByAttribute('ordernumber', 500);
gives me an object of a product, which means everything with the custom attribute (ordernumber) is fine.
Doing this, though:
Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('ordernumber')
->addAttributeToFilter('ordernumber', 500);
returns a collection, but an empty one - without items. And they should be 3. Couple of hours ago it worked. Now it stopped working, and I haven't changed anything concerning the collection or the attribute. I have no clue what the problem might be...
The attribute is set to Yes for the Usied in Product Listing
Your code may not work if you are using it on frontend and the flat catalog is enabled.
To make it work, you have 2 possibilities:
Option 1:
Make the attribute ordernumber to be used in product listing. Edit the attribute in the backend and set the flag Used in product listing to Yes. Reindex is required.
Option 2:
Use the eav collection directly:
Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('ordernumber')
->addAttributeToFilter('ordernumber', 500);
I recommend the first approach.
Please use
$products = Mage::getModel('catalog/product')->loadByAttribute('ordernumber', '500');
ANOTHER WAY
Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('ordernumber','500')
Please Make Sure Used in Product Listing option set to yes for Attributes ordernumber.
After that clear cache. Hope this will work.
It seems like I have to set a store view before I can update an attribute on website scope – is that correct?
My code:
Mage::app('admin');
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product');
$product->load(123);
$product->setStoreId('1'); // without this line the attribute is not updated
$product->setSomeattribute("abc");
$product->save();
Yes. that's correct. This is for performance reasons on the frontend. Usually you don't save products from frontend. See a detailed explanation of why is this needed.
But you don't need to do that. I's slow and resource consuming. Try to save it like this:
Mage::getSingleton('catalog/product_action')
->updateAttributes(array(123), array('somattribute'=>'abc'), 1);
The first parameter is and array with the product ids.
The second is an array with the attribute codes and values to be updated.
The third is the store id for which the update is done.
This method is faster.
today I'm fighting with Magento again :) and I found a difference between
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $product_sku);
and
$product = Mage::getModel('catalog/product')->load($product_id);
Can anyone exaplain me a difference between these two approaches? I found that when I'm loading a product by sku then when I 'try to re-save it with changed data then I get error exception 'Varien_Exception' with message 'Invalid method Varien_Object::save in app\code\core\Mage\CatalogInventory\Model\Observer.php(153): Varien_Object->__call('save', Array) that's true because once you try to load by sku then another observer sets product's stock item as Varien_Object, that looks like pitfall or I just dont understand it enough, but
I do daily Magento development from its beginnig so I know a lot about system and this is new for me. Thanks in advance, Jaro.
Interesting. While both methods will net you a single product model instance with fully loaded EAV data (provided the third parameter of loadByAttribute() is not passed or is *), the observers which add stock-related data are different for products vs. product collections, yet both stock information objects are added to the product data key "stock_item". It's debatable, but this feels like a bug. I would think that Mage_CatalogInventory_Model_Observer::saveInventoryData() or Mage_CatalogInventory_Model_Observer::_prepareItemForSave() would handle this.
You could resolve this issue by setting the product stock item fully on your product instance using the stock_item object.
loadByAttribute is a serious misnomer in my opinion because it doesn't actually trigger a load(); rather it uses getResourceCollection():
public function loadByAttribute($attribute, $value, $additionalAttributes = '*')
{
$collection = $this->getResourceCollection()
->addAttributeToSelect($additionalAttributes)
->addAttributeToFilter($attribute, $value)
->setPage(1,1);
Because it doesn't trigger the observer events associated with load() it means the resulting product object doesn't include the full set of product data you might want. In my case I needed the "description" attribute and it wasn't included.
There are several ways to resolve this:
Use a different method to load by SKU:
$product = Mage::getModel("catalog/product");
$product->load($product->getIdBySku("whatever"));
Force the desired attribute data to be included in the default product resource data by visiting Magento Admin > Catalog > Attributes > Edit attribute > "Used in Product Listing" = "Yes" and then reindexing. You should then be able to use the attribute data (in the frontend, at least) using loadByAttribute().
See also https://magento.stackexchange.com/a/197286/18855
I m trying to learn coding a bit through Magento, and I have to admit that I'm a bit confused about this notion of object chaining in it.
In fact I don't understand when to do a load and when I can avoid it. For exemple:
$product = Mage::getModel('catalog/product')->load($item->getProductId());
I would like to get the info of product from a product ID in this case; why do I need to load it? ($item is the loop of all the products of an order)
And here I don't need to do any load:
$customer = $payment->getOrder()->getCustomer();
I'm sorry in advance for my stupid question: What does load do comparing to my second example? Thanks a lot and have a nice day,
Anselme
Behind the scenes a method like $payment->getOrder() is effectively (after checking to see if it's already loaded) doing this:
return Mage::getModel('sales/order')->load($this->getOrderId());
// $this in this context is $payment
So a load is still needed to retrieve the relevant data from the database, the getOrder() method is just a convenience. The load() method itself returns it's class instance, which is why you can assign it to $product in your first example. The getOrder() and getCustomer() methods don't return themselves, they return a different object, which is why $payment is not assigned to $customer in your second example.
The Mage::getModel() method is only responsible for determining the correct class and creating a blank instance of it. Instead of a load you could instead set it's data with a setData() call, passing a keyed array of values. All of the setters return their object, just like load() does.
$customer = $payment->getOrder()->getCustomer();
It means the id of the customer is already present in the session, so you don't need to explicitly tell magento to load the customer.
In the products case, you have to tell magento the product id of the product you want to get details of.