Thursday, May 20, 2010

how to find methods in Magento

Problem: http://www.magentocommerce.com/boards/viewthread/193422/
Here is how I've learned.
Let's say you have in a phtml file this line of code.
$object->method();
($object can be anything including $this).
And you don't know what type is $object.
put this line above the method call.
echo get_class($object);
Clear the cache (contents of var/cache) and reload the page. You should see the name of the class. For example Mage_Catalog_Model_Category. now all you have to do is to find the class.
Because Magento is based on Zend Framework it uses the the same convention for class naming.
So class Abc_Def_Ghi will be in the file Abc/Def/Ghi.php (for the example above the file is Mage/Catalog/Model/Category.php)
All the classes are placed in app/code/core or app/code/local/ or app/code/community or lib/ and after that follow the path like explained above.

If you don't find a method in that specific class look in one of the parents. Check the class that the current class extends.

You will not find all the methods in Magento. For example some of the methods that start with get, set, has, uns is possible that the methods are missing.
For this take a look in Varien_Object class (that is the base class for most of the objects) lib/Varien/Object.php file (remember the convention above?) and look in the 'magic' method __call().

Monday, May 17, 2010

Import products update

This is an update for http://marius-strajeru.blogspot.com/2009/11/import-simple-products-for-barrmy.html

Starting version 1.4 you can only perform product updates 'programmatic' only if Magento thinks you are in the admin panel.

If you try to do this from a non-admin page make sure you put this

Mage::app()->setCurrentStore(Mage::getModel('core/store')->load(Mage_Core_Model_App::ADMIN_STORE_ID));
before you call
$product->save();

Thursday, May 6, 2010

How to add product skus (or payment method) to the orders grid

[UPDATE] The solution provided here works only for Magento 1.4.0.0 or lower. Starting Magento 1.4.0.1 the order tables are not EAV anymore. I think (but I'm not sure) the logic is still OK but you have to try it by adding a new column to sales_flat_order and sales_flat_order_grid tables instead of adding a new attribute. [/UPDATE] I've tried in different ways to add articles skus (or payment method) to the orders grid in admin. I've tried 'left joining' different tables, performing different actions after applying _prepareCollection() method. All of them worked in some way, but the website started working slow when it reached 10000-12000 orders. And when I say slow I mean over 2 minutes to render the orders grid in admin. This was because of the slow queries which also resulted in slow loading of the frontend pages.
I found an easier solution, it's somehow redundant but it works and it's pretty fast.
I added a new varchar attribute for the order object.
EDIT: This only works in versions < 1.4
INSERT INTO `eav_attribute` (`attribute_id`, `entity_type_id`, `attribute_code`, `attribute_model`, `backend_model`, `backend_type`, `backend_table`, `frontend_model`, `frontend_input`, `frontend_label`, `frontend_class`, `source_model`, `is_required`, `is_user_defined`, `default_value`, `is_unique`, `note`) VALUES
(NULL, 11, 'product_skus', NULL, NULL, 'varchar', NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, 0, '');

Clear the cache (contents of the folder var/cache)
Override the Mage_Sales_Model_Order class and in the _beforeSave() method add this:
if (!$this->getProductSkus()) {
$skus = array();
foreach ($this->getAllItems() as $item) {
$skus[] = $item->getSku();
}
$this->setProductSkus(implode(",", $skus));
}
This will add a string with all the skus separated by comma to the order model.
Now all you have to do is to show the string in the orders grid.
Override the Mage_Adminhtml_Block_Sales_Order_Grid block and in the _prepareColumns() method add a new column like this:
$this->addColumn('product_skus', array(
'header' => Mage::helper('sales')->__('Products'),
'index' => 'product_skus',
));
Added it where ever you want.
If you don't know how to overwrite a model or a class this is a good tutorial:
http://magedev.com/2009/06/03/magento-overriding-model-block-or-helper/

The only problem is that these changes will take effect only for the orders you make from now on.

You can add the skus for every order like this.
Create a new php file, let's call it orders.php and place it in the root of the application (same level as index.php) with this code:
<?php
$mageFilename = 'app/Mage.php';

require_once $mageFilename;

Varien_Profiler::enable();

Mage::setIsDeveloperMode(true);

ini_set('display_errors', 1);

umask(0);
Mage::app('default');
Mage::register('isSecureArea', 1);

$orders = Mage::getModel('sales/order')->getCollection()->addAttributeToSelect("*");
foreach ($orders as $order){
$order->save();
}
?>

and call it in the browser (http://yourwebsite.com/orders.php)

If you have many orders it will take some time to run but eventually ... you get my point.

If you want to do this with the payment method the system is the same. Add a new attribute:
INSERT INTO `eav_attribute` (`attribute_id`, `entity_type_id`, `attribute_code`, `attribute_model`, `backend_model`, `backend_type`, `backend_table`, `frontend_model`, `frontend_input`, `frontend_label`, `frontend_class`, `source_model`, `is_required`, `is_user_defined`, `default_value`, `is_unique`, `note`) VALUES
(NULL, 11, 'order_payment_method', NULL, NULL, 'varchar', NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, 0, '');
Clear the cache.
In the _beforeSave() method add this:
if (!$this->getOrderPaymentMethod()) {
$this->setOrderPaymentMethod($this->getPayment()->getMethodInstance()->getTitle()); //if you want the payment method's name (Check / money order)
//$this->setOrderPaymentMethod($this->getPayment()->getMethod());//if you want the payment method's code (checkmo)
}

In the Mage_Adminhtml_Block_Sales_Order_Grid block _prepareColumns() method add this:
$this->addColumn('order_payment_method', array(
'header' => Mage::helper('sales')->__('Payment'),
'index' => 'order_payment_method',
));

Same as for the product skus, this will now work for previous orders, but you can run the same script as above to update all the old orders.

That's it. Let me know how it turns out.