What does Load mean in Magento Objects? - magento

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.

Related

Magento - Limit selected fields without collection when loading a Model

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();

Magento product load - difference between loadByAttribute and load methods

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

Get simple products belonging to configurable product AFTER configurable product save

In magento, it is possible to get the simple products associated to a configurable product by using the following call:
$childProducts = Mage::getModel('catalog/product_type_configurable')->getUsedProducts(null, $product);
I am trying to call this function after the configurable product is saved, so that I can get the new list of simple products it uses. So I am making the above call from a method that is triggered by the catalog_product_save_after event. However, after the call $childProducts stores the simple products that were associated to $product BEFORE the save operation, not AFTER it.
How could I get the simple products associated to $product after the save operation?
Thanks in advance, any suggestion is appreciated.
Magento's OOP system is very good, and this goodness sometimes creates problems for those who haven't yet gone deep into its structure.
If you closely follow the method "getUsedProducts()" in the class "Mage_Catalog_Model_Product_Type_Configurable", you will see that there are some "if" logics provided, along with the usage of its properties (like "_usedProducts", "_configurableAttributes"). These obstruct you from getting the actual result, but the fault is not of Magento, instead the fault is because of the lack of Magento documentation.
Let me clear you about the first few lines of this method:-
Varien_Profiler::start('CONFIGURABLE:'.__METHOD__);
if (!$this->getProduct($product)->hasData($this->_usedProducts)) {
if (is_null($requiredAttributeIds) and is_null($this->getProduct($product)->getData($this->_configurableAttributes))) {
// If used products load before attributes, we will load attributes.
$this->getConfigurableAttributes($product);
// After attributes loading products loaded too.
Varien_Profiler::stop('CONFIGURABLE:'.__METHOD__);
return $this->getProduct($product)->getData($this->_usedProducts);
}
....
This method has 2 arguments - "$requiredAttributeIds" (Configurable Attribute IDs) & "$product" (configurable product object).
When calling this method, you are passing "null" for the parameter "$requiredAttributeIds", but you are providing the correct Configurable Product object "$product".
This class has a property "_usedProducts" (for maintaining the data of child simple products), which is set for every Configurable Product object. If this value has earlier been set, then Magento will return you the already available values to you. This is the main reason why you are getting the child products before the configurable product was updated.
So, what you can do is you can clear the full Cache Storage, along with refreshing all the Cache processes. May be then your result will work, because internally Magento stores all these used products data in cache.
Hope it helps.

How do I get the shipping method the user has chosen during checkout?

I want to get the name of the shipping method the user has chosen during checkout. Does anyone know how to retrieve that info?
This will get it to some extent but it is cached:
Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress()->getShippingDescription();
When I am on the onestep checkout and I go back to the shipping tab and change the shipping, it is still holding the old shipping method. I need to figure out how to get the current one.
Foreword
Constructed from Magento app/code/core/Mage/Checkout/Block/Onepage/Shipping/Method/Available.php and others:
app/design/frontend/base/default/template/checkout/onepage/shipping_method/available.phtml uses this code to determine which shipping method was selected:
$this->getAddressShippingMethod()
app/code/core/Mage/Checkout/Block/Onepage/Shipping/Method/Available.php expands that code to this:
return $this->getAddress()->getShippingMethod();
Let's research a bit and expand it even deeper:
$this->getQuote()->getShippingAddress()->getShippingMethod();
Parent block expands method getQuote():
return $this->getCheckout()->getQuote();
And deeper:
public function getChechout() {
return Mage::getSingleton('checkout/session');
}
Merging all that code gives us this:
Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress()->getShippingMethod()
That gives you the shipping method code. Giving that, you could manipulate it just as you wish. This data is stored within the database, so when you change shipping method, the code changes too.
Getting deeper and deeper!
If you've ever created your own shipping method, you'd know, that it has the method called collectRates().
It fills a set of shipping/rate_result_method models, stores it within the instance of shipping/rate_result model and returns it (you can get each model' instance using Mage::getModel(<model i've named>); ).
Yet, note: one could contain multiple rate_result_method instances, while the shipping method code is the same for all those instances!
Thus, in order to get the description, you need to get one of the rate_result_method instances and retrieve its methodTitle or carrierTitle.
After a small researching i've found how to retrieve all these rates:
Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress()->getShippingRatesCollection()
This will provide you with a collection of all rates for the selected shipping method. You can operate it with getItems() and get a hash. Or you could use getFirstItem() and use it as the template.
Anyway, let's assume u've retrieved some item of that collection and stored it within the $rate variable:
$rate->getCarrier(); // This will provide you with the carrier code
$rate->getCarrierTitle(); // This will give you the carrier title
$rate->getCode(); // This will give you **current shipping method** code
$rate->getMethod(); // This will provide you with the **shipping method** code
$rate->getMethodTitle(); // This will tell you current shipping method title
$rate->getMethodDescription(); // And this is the description of the current shipping method and **it could be NULL**
That's all, folks!
I am really sorry for my poor English and for my strange mind flow. Hope this will help you or someone else. Thanks!
Just in case you need it still. You can get shipping method from order by:
$order->getShippingMethod();
Of course how you get your $order depends on context.
Also you can get description by:
$order->getShippingDescription();
shipping method in magento
$methods = Mage::getSingleton('shipping/config')->getActiveCarriers();
$options = array();
foreach($methods as $_code => $_method)
{
if(!$_title = Mage::getStoreConfig("carriers/$_code/title"))
$_title = $_code;
$options[] = array('value' => $_code, 'label' => $_title . " ($_code)");
}
echo "<xmp>";
print_r($options);
echo "</xmp>";
In your checkout controller you need to add extra steps to save your quote if you want this information to be accessible to you.
I added a few '$quote->save();' entries to get this to work, however, I cannot definitively say which entry is the one that did the fix. I also cannot find the link on Magento forums, however, I hope I have given you a head start on what is going on.
You could override the saveShippingMethodAction() function in the Mage_Checkout_OnepageController, or extend upon it, and save the method into the registry by inserting:
Mage::register('blahShippingMethod', $this->getRequest()->getPost('shipping_method'));
and call upon it as you need it: Mage::registry('blahShippingMethod');
Don't forget to unset it when you no longer need it as you will run into an error if you try to reset when it's already been set.
Mage::unregister('blahShippingMethod');

Get customer object on an event

I’m trying to createan observer on the following event.:
‘sales_order_payment_pay’.
However according to magento doc
http://www.magentocommerce.com/wiki/5_-_modules_and_development/reference/magento_events
I don’t have so much parameters avalaible on this event..
Do you have any idea how I could retrieve the customer object (i would need info such as customer id and customer email)?
Thanks for your feedback and anyway I wish you a nice day,
Anselme
This event does expose the payment object, so you should be able to chain off of that to get the object you want:
public function yourObserverFunction($event) {
$payment = $event['payment'];
$customer = $payment->getOrder()->getCustomer();
// ... do something useful
}
Generally objects in Magento can be chained like this, and now your code doesn't rely on the event being triggered from a customer session (which is not a good assumption anyway).
Hope that helps!
Thanks,
Joe
Every event exposes different objects inside of the $observer object that is passed around. In Magento you can often get a lot of stuff by referring to any number of objects that are in the request or session. In this case there is a customer/session object (Mage_Customer_Model_Session) which has the customer attached.
if(Mage::getSingleton('customer/session')->isLoggedIn()){
Mage::getSingleton('customer/session')->getCustomer();
}

Resources