Wednesday, November 30, 2011

Magento: Exception printing is disabled by default for security reasons

When I go to any product detail page, I get the following error:-
    There has been an error processing your request
    Exception printing is disabled by default for security reasons.

I don’t get the detailed information about the error as I used to get in previous versions of Magento.
Solution:
In your magento root, there is a folder called errors.
Go inside the errors folder.
There is a file named local.xml.sample.
Rename it to local.xml
Hence, the problem is solved. Now, I am able to see detailed error information.

Thursday, November 24, 2011

Custom Module


List of created files:
app/etc/modules/Flexsin_Helloworld.xml
app/code/local/Flexsin/Helloworld/Block/Helloworld.php
app/code/local/Flexsin/Helloworld/controllers/IndexController.php
app/code/local/Flexsin/Helloworld/etc/config.xml
app/code/local/Flexsin/Helloworld/Model/Helloworld.php
app/code/local/Flexsin/Helloworld/Model/Mysql4/Helloworld.php
app/code/local/Flexsin/Helloworld/Model/Mysql4/Helloworld/Collection.php
app/code/local/Flexsin/Helloworld/Model/Status.php
app/code/local/Flexsin/Helloworld/sql/helloworld_setup/mysql4-install-0.1.0.php
app/design/frontend/flexsin/default/layout/helloworld.xml
app/design/frontend/flexsin/default/template/helloworld/helloworld.phtml
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Grid.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit/Form.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit/Tabs.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit/Tab/Form.php
app/code/local/Flexsin/Helloworld/controllers/Adminhtml/HelloworldController.php
app/code/local/Flexsin/Helloworld/Helper/Data.php
app/design/adminhtml/flexsin/default/layout/helloworld.xml

Wednesday, November 23, 2011

Magento Files and Folders Structure


The files and folders included in the main directory are as follows:
.htaccess - contains mod_rewrite rules, which are essential for the Search Engine Friendly URLs. There you can also find standard web server and php directives that can improve your web site performance.

.htaccess.sample - this is a backup of the .htaccess file. If you modify .htaccess it can be used in order to get the default settings.

404 (directory) - The folder stores the default 404 template and skin for Magento.

app (directory) - This folder contains the modules, themes, configuration and translation files. Also there are the template files for the default administration
theme and the installation.

cron.php - a Cron Job should be set for this file. Executing of the file on a defined time period will ensure that the complicated Magento caching system will not affect the web site performance.

downloader (directory) - This is the storage of the web downloader files. They are used for the installation and upgrade of Magento through your browser.

favicon.ico - the default favicon for Magento. A small icon that is shown in the browser's tool bar once your web site is loaded.

index.php - the main index file for Magento.

index.php.sample - A backup of the default index file. It can be used to revert the changes in a case of a index.php modification.

js (directory) - Contains the pre-compiled libraries of the JavaScript code included in Magento.

lib (directory) - The Magento core code is located in this folder. It contains the software's PHP libraries.

LICENSE_AFL.txt - The Academic Free License under which the Magento software is distributed.

LICENSE.txt - The Open Software License under which the Magento software is distributed.

media (directory) - This is the storage of the Magento media files - images out of the box, generated thumbnails, uploaded products images. It is also used as a container for importing images through the mass import/export tools.

pear - The file controls the automatic update through the downloader script and SSH. It handles the update of each individual Magento module.

php.ini.sample - This file contains sample php directives that can be used in order to modify your PHP setup. If you want to alter the default setup edit the file and then rename it to php.ini.

pkginfo (directory) - Contains files with information regarding the modules upgrades' changes.

report (directory) - This folder contains the skin of the Magento errors reports.

skin (directory) - There are located the themes files - images, JavaScript files, CSS files, Flash files. Also there can be found the skin files for the installation of skins and administration templates.

var (directory) - Cache, sessions, database backups, data exports and cached error reports can be found in this directory.

If you want to modify an existing template or set a new one you should know that the template files are separated in 3 folders:
/app/design/frontend/default/YOUR_TEMPLATE_NAME/layout/ - Contains the .xml files that define which modules should be called by the template files and loaded in defined areas on the site.
/app/design/frontend/default/YOUR_TEMPLATE_NAME/template/ - Contains files and subfolders that structure the final output for the users using the functions located in the layout/ folder.
/skin/frontend/default/YOUR_TEMPLATE_NAME/ - Contains the CSS, images, JavaScript and Flash files related to the template.

Adding and removing javascript / css when and where you need it


Adding and removing javascript and css is handled separately within Magento. CSS is added in the usual fashion, where you have a <link rel=”stylesheet”… />. However, any included javascript (unless linked to “by hand” from a theme’s skin) is pulled via a php files which reads through the “js” folder in the root directory (root/js/index.php is responsible for this).
That is all well and good for Magento. The real question is how we, as developers, add these items when we need them. How you as a developer add css or javascript is, luckily, handled the same.
In this post, we will show how to add and remove javascript and css to a CMS page (and anywhere else) that you may need.
Method 1: Layout xml.
a) For files you want to include on every page
For css or js files you want to add to every page, you edit the page. xml files located in your layout folder (app/design/frontend/default/your_theme/layout/page.xml). Within this file, at the top you will find the <default> area with the <block name=”root” … >. This block has a child named “head” which contains the included css and js elements.


<block type="page/html_head" name="head" as="head">
<action method="addJs"><script>prototype/prototype.js</script></action>
<action method="addJs" ifconfig="dev/js/deprecation"><script>prototype/deprecation.js</script></action>
<action method="addJs"><script>prototype/validation.js</script></action>
<action method="addJs"><script>scriptaculous/builder.js</script></action>

...

</block>
Here you can add your javascript and css. Note that any Js files you add are relative to the “js” folder in your root directory. The css files are included from the skin files of the current and default templates (skin/frontend/default/your_template(& default)/css).
b) Specific areas
If you want to include css or js on only certain areas (such as the checkout process or catalog pages), you can do that also. For instance, if you want it in a single product view (product view vs product list), you can open up catalog.xml, find <catalog_product_view> area (near line 168 in vs 1.2.1).  Add your code in there – notice that we are using the <reference> tag rather than <block> tags. We use the “reference” tag to reference other blocks that are in other areas of the template.


<reference name="head">
<action method="addJs"><script>varien/product.js</script></action>

<action method="addItem"><type>js_css</type><name>calendar/calendar-win2k-1.css</name><params/><!--<if/><condition>can_load_calendar_js</condition>--></action>
<action method="addItem"><type>js</type><name>calendar/calendar.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
<action method="addItem"><type>js</type><name>calendar/lang/calendar-en.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
<action method="addItem"><type>js</type><name>calendar/calendar-setup.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
</reference>

The use of can also be used in your layout XML areas in the admin backend (CMS pages, category and product designs). This can accomplish the same thing, as well as adding or removing other blocks.
Method 2: Block Code
We can accomplish all of this in code as well. These functions are defined within Mage_Page_Block_Html_Head. So, we can use this code with in a block class (not a .phtml file!):

$headBlock = $this->getLayout()->getBlock('head');
$headBlock->addJs('somefolder/yay.js');

I suggest looking over the page. xml file as long as finding the removeItem syntax ($type, $name for the method, for the xml), which will be very handy for you for adding or removing assets as and when you need them!
<action method="removeItem"><type>js</type><name>calendar/calendar.js</name</action>

$this->getLayout->getBlock('head')->removeItem('js', 'calendar/calendar.js');


Adding and removing javascript / css when and where you need it


Adding and removing javascript and css is handled separately within Magento. CSS is added in the usual fashion, where you have a <link rel=”stylesheet”… />. However, any included javascript (unless linked to “by hand” from a theme’s skin) is pulled via a php files which reads through the “js” folder in the root directory (root/js/index.php is responsible for this).
That is all well and good for Magento. The real question is how we, as developers, add these items when we need them. How you as a developer add css or javascript is, luckily, handled the same.
In this post, we will show how to add and remove javascript and css to a CMS page (and anywhere else) that you may need.
Method 1: Layout xml.
a) For files you want to include on every page
For css or js files you want to add to every page, you edit the page.xml files located in your layout folder (app/design/frontend/default/your_theme/layout/page.xml). Within this file, at the top you will find the <default> area with the <block name=”root” … >. This block has a child named “head” which contains the included css and js elements.

Saturday, November 19, 2011

web services using php as JSON format


Create a php file with following code:

$hostname="localhost";
$username="bhoopendra";
$password="";
$database="my_db";
$table='comment';
$con=mysql_connect($hostname, $username, $password) or die(mysql_error());
mysql_select_db($database, $con) or die(mysql_error());
$result=mysql_query("SELECT * FROM ".$table) or die(mysql_error());

while($row = mysql_fetch_assoc($result)) {
$data[]=$row;
 
}

$file=fopen("web.xml", "w");
if(fwrite($file,json_encode($data))){
//header('location: web.xml');
}

web services using php as xml format


Create a php file with following code:
$hostname="localhost";
$username="bhoopendra";
$password="";
$database="my_db";
$table='comment';
$con=mysql_connect($hostname, $username, $password) or die(mysql_error());
mysql_select_db($database, $con) or die(mysql_error());
$result=mysql_query("SELECT * FROM ".$table) or die(mysql_error());
$doc = new DomDocument('1.0');
$root = $doc->createElement('root');
$root = $doc->appendChild($root);

while($row = mysql_fetch_assoc($result)) {
$occ = $doc->createElement($table);
  $occ = $root->appendChild($occ);
  foreach ($row as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
 }
}
$xml_string = $doc->saveXML();
//echo $xml_string;
$file=fopen("web.xml", "w");
if(fwrite($file,$xml_string)){
header('location: web.xml');
}

Friday, November 18, 2011

Magento: Get parent id of simple product associated to configurable product


A simple product is associated with a configurable product. You have the id of the simple product. Now, you need the id of the configurable product with which the simple product is associated.
Get parent product id, i.e. get id of configurable product from a simple product.

$_product = Mage::getModel('catalog/product')->load(YOUR_SIMPLE_PRODUCT_ID);
$parentIdArray = $_product->loadParentProductIds()->getData('parent_product_ids');
print_r($parentIdArray);

Magento: Get order option of configurable and bundle product in cart


We are not allowed to order configurable and bundle products directly. We have to select product options from product detail page of configurable or bundle product. Only then we can add the product to cart.
The following code fetches the order option selected for configurable and bundle products:

// For configurable product
Mage::getModel('catalog/product_type_configurable')->getOrderOptions($this->getProduct());
 
// For bundle product
Mage::getModel('bundle/product_type')->getOrderOptions($this->getProduct());

Magento: Displaying / Adding Gift Message in Order


Gift Message facility is present in Magento by default. You can add gift message in order as a whole or in individule order items.
By default, the gift message is not enabled in Magento.

Here is how you display gift message adding form in order/checkout:-
1) First of all, go to System -> Configuration -> Advanced -> Disable modules output and check if Mage_GiftMessage is Enabled. This should be Enabled.
2) Now, go to System -> Configuration -> SALES -> Sales -> Gift Messages.
3) Here, you will find two selection lists:-
Allow Gift Messages on Order Level: By default it is ‘No’. When you change it to ‘Yes’ then you will be able to add a single gift message to the whole order. The gift message form is displayed in ‘Shipping Method’ section of Checkout page.
Allow Gift Messages for Order Items: By default it is ‘No’. When you change it to ‘Yes’ then you will be able to add gift message separately to individual item of your shopping cart. The gift message form is displayed in ‘Shipping Method’ section of Checkout page.
4) You can also enable or disable gift messages in individual product from ‘Manage Products’. When you edit any product, you will see a selection list of Allow Gift Message. By default, it is set to Use config, i.e. it will use the value set in configuration (see #3 ‘Allow Gift Messages for Order Items’). Here, you can set ‘Yes’ or ‘No’ to display gift message adding facilty to the particular product or not.

Magento: How to enable backorders?


Difference between backorder and pre-order
A backorder is for an item that was in stock previously but is temporarily out of stock.
A pre-order is for an item that has not been released yet.
Scenario for backorder:
For example, a customer orders 3 items. One item is not in stock. Shouldn’t I be able to Invoice only the 2 items I am shipping now, and then go back in next week and Invoice for the third item when it is back in stock? How do I set this up? – Source: magentocommerce forum
Backorders simply means that the item you are going to order is out of stock and you will receive the item OR the item will be delivered to you when the item will be in stock.
By default, backorder is not enabled in magento. Hence, you cannot add items to cart when the item is out of stock. But, if you enable backorders then you can add item to cart even if it is out of stock.
To enable backorders, go to:
Admin Panel -> System -> Configuration -> Catalog Tab -> Inventory -> Product Stock Options -> Backorders = Allow Qty Below 0 and Notify Customer
Edit Product to Qty = 0 and Stock Availability = In Stock
And backorders are enabled!
When you add the particular product to cart, the product is added to cart and you will see the following message:
* This product is not available in the requested quantity. 1 of the items will be backordered.
You can order the product even if it is out of stock. The product will be delivered to you when it is in stock.

Tuesday, November 15, 2011

Magento : Adding a home link to the menu bar


There are following step:
1. Now look for the top.phtml file in app/design/frontend/YOUR_PACKAGE/
YOUR_THEME/template/catalog/navigation/ directory. In my case, the
absolute path of top.phtml file for active default theme is: /var/www/magento.
local.com/public/app/design/frontend/base/default/template/
catalog/navigation/.
2. The code should look like this:
<?php $_menu = $this->renderCategoriesMenuHtml(0,'level-top') ?>
<?php if($_menu): ?>
<div class="nav-container">
<ul id="nav">
<?php echo $_menu ?>
</ul>
</div>
<?php endif ?>
3. Next, let's add the new alternative home link now. Add the following code snippet
before the foreach loop:
<!-- NEW HOME LINK -->
<li class="home"><a href="<?php echo $this->getUrl('')?>"><?php
echo $this->__('Home') ?></a></li>
<!-- NEW HOME LINK -->
4. After the changes, now the top.phtml file should look like this:
<?php $_menu = $this->renderCategoriesMenuHtml(0,'level-top') ?>
<?php if($_menu): ?>
Chapter 2
25
<div class="nav-container">
<ul id="nav">
<!-- NEW HOME LINK -->
<li class="home"><a href="<?php echo $this-
>getUrl('')?>"><?php echo $this->__('Home') ?></a></li>
<!-- NEW HOME LINK -->
<?php echo $_menu ?>
</ul>
</div>
<?php endif ?>
5. Next, we will add some CSS style for the active state of our home link like other
menus in the top navigation bar. Find the styles.css file from the skin/
frontend/YOUR_PACKAGE/YOUR_THEME/css/ directory and open it. In my case,
the location of styles.css file is: /var/www/magento.local.com/public/
skin/frontend/default/default/css.
6. Now append the following line at the end of styles.css file:
body.cms-home #nav li.home a { color:#d96708; }
7. Reload the home page and see the changes. A new home menu will appear:

Sunday, November 13, 2011

Adding a step to the Onepage Checkout

The default Magento onepage checkout includes six steps for the customer to complete. However, sometimes you may have a requirement to create an extra checkout step. An example of this might be an option for your customer to choose a free gift as part of their order, or an extra step to collect special delivery instructions. Using delivery instructions as an example, we'll demonstrate how this can be achieved.

The first file we need to modify is app/code/core/Mage/Checkout/Block/Onepage.php. Obviously we don't want to modify the code in the core context, so copy the file to app/code/local/Mage/Checkout/Block/Onepage.php. Magento will use this file automatically.

In the getSteps() method of this class there is an array of the step codes, in order of viewing. We need to add our own step code in this array, in the relevant place. For this example, the code will be deliveryinstructions so we will change the line to be this:

$stepCodes = array('billing', 'shipping', 'shipping_method', 'deliveryinstructions', 'payment', 'review');

Next, we need to create a new file - app/code/local/Mage/Checkout/Block/Onepage/Deliveryinstructions.php. As you can see from the name, this is the block file that runs our new step. You can use this class to do any special setup work for your block, but more than likely all you'll need is this:

<?php
class Mage_Checkout_Block_Onepage_Deliveryinstructions extends Mage_Checkout_Block_Onepage_Abstract
{
    protected function _construct()
    {
        $this->getCheckout()->setStepData('deliveryinstructions', array(
            'label'     => Mage::helper('checkout')->__('Delivery Instructions'),
            'is_show'   => $this->isShow()
        ));
        parent::_construct();
    }
}

Now we need to make the actual template. The file we need is: <THEME DIRECTORY>/template/checkout/onepage/deliveryinstructions.phtml. Often the best way to create this file is to copy one of the other files, perhaps billing.phtml or shipping.phtml. Then, just modify the file to suit your needs.

With the template created, we need to tell Magento about it by editing the <THEME DIRECTORY>/layout/checkout.xml file. This will tell Magento when to load our new template file. Below the multishipping sections in this file the <checkout_onepage_index> context begins. Look through it until you find the references to the login, billing, shipping, shipping method, payment and review templates. These are all inside the content reference area. At the position between all these files that you want your step to show, you need to add a reference to your new template. It should look something like this:

<block type="checkout/onepage_deliveryinstructions" name="checkout.onepage.deliveryinstructions" as="deliveryinstructions" template="checkout/onepage/deliveryinstructions.phtml"/>

Following on from that, we need to override the onepage controller to put in our extra step. How to actually override a controller is beyond the scope of this post, however the Magento wiki article on overriding controllers should tell you everything you need to know.

There are two parts we need to work with in our overridden controller, and the first one is the save<STEP>Action method for the step before ours. In this example, I'm putting my new step between the Shipping Method step and the Payment Method step, so I'm going to override the saveShippingMethodAction method. We need to change the goto_section in the method to be our new step, so it should look like this:

$result['goto_section'] = 'deliveryinstructions';

We also need to remove the following code, as we don't need to update our delivery instructions section. We will need the code again for the next part, so keep it handy:

$result['update_section'] = array(
        'name' => 'payment-method',
        'html' => $this->_getPaymentMethodsHtml()
);

The next change to this controller should be to add a new method, called saveDeliveryinstructionsAction. This method must perform two functions; it should call the method on the Onepage Model, and also pass any data back to the browser. The following code is an example of what we need, copied and modified from the saveShippingMethodAction method:

public function saveDeliveryinstructionsAction()
{
 $this->_expireAjax();
 if ($this->getRequest()->isPost()) {
  $data = $this->getRequest()->getPost('deliveryinstructions', '');
  $result = $this->getOnepage()->saveDeliveryinstructions($data);
  /*
  $result will have error data if shipping method is empty
  */
  if(!$result) {
   Mage::dispatchEvent('checkout_controller_onepage_save_deliveryinstructions', array('request'=>$this->getRequest(), 'quote'=>$this->getOnepage()->getQuote()));
   $this->getResponse()->setBody(Zend_Json::encode($result));

   $result['goto_section'] = 'payment';
   $result['update_section'] = array(
       'name' => 'payment-method',
       'html' => $this->_getPaymentMethodsHtml()
   );

  }
  $this->getResponse()->setBody(Zend_Json::encode($result));
 }
}

In the last step we called a method that we haven't defined yet, so we'll do that now. This method is in the app/code/core/Mage/Checkout/Model/Type/Onepage.php file. Like the past few files, we are going to modify the saveShippingMethod method and also copy it to a new method. The saveShippingMethod code should be modified to look like this:

public function saveShippingMethod($shippingMethod)
{
    if (empty($shippingMethod)) {
        $res = array(
            'error' => -1,
            'message' => Mage::helper('checkout')->__('Invalid shipping method.')
        );
        return $res;
    }
    $rate = $this->getQuote()->getShippingAddress()->getShippingRateByCode($shippingMethod);
    if (!$rate) {
        $res = array(
            'error' => -1,
            'message' => Mage::helper('checkout')->__('Invalid shipping method.')
        );
        return $res;
    }
    $this->getQuote()->getShippingAddress()->setShippingMethod($shippingMethod);
    $this->getQuote()->collectTotals()->save();

    $this->getCheckout()
        ->setStepData('shipping_method', 'complete', true)
        ->setStepData('deliveryinstructions', 'allow', true);

    return array();
}

Unfortunately, there is no simple way to save the data that we collect. For example, information about a customer will be saved completely differently to shipping information like our delivery instructions; the delivery instructions will be saved differently again to how we would add a free gift to the order.

Because of this I won't show you any code for actually saving the data you've captured, though we may address this in a follow up post at a later date. The following code is the new method that does not save anything:

public function saveDeliveryinstructions($deliveryinstructions)
{
    // Save the data here

    $this->getCheckout()
        ->setStepData('deliveryinstructions', 'complete', true)
        ->setStepData('payment', 'allow', true);

    return array();
}

Next, we need to make a couple of JavaScript changes. These changes will be made in the <SKIN DIRECTORY>/js/opcheckout.js> file. In the Checkout class, we need to change the setShippingMethod method to go to the delivery information block, similar to the way we have in the files above. Then we need to make a setDeliveryinstructions method which will be exactly the same as the setShippingMethod method before we modified it.

There is a class further down in the file called ShippingMethod, inside of which is a method called nextStep. We need to change it as per the above method so that the step goes to the delivery instructions step rather than the payment step. Then, again like before, we need to copy the whole class and modify it so that it's now a DeliveryInstructions class, making sure to set the next step to be the payment step.

There is now one final requirement, which is to add in our step in the progress meter on the right side of the checkout. To do this we need to edit <THEME DIRECTORY>/template/checkout/onepage/progress.phtml. If you look at the file, you'll have a pretty good idea of how the template should be laid out and below is an example of what to add in for our example delivery instructions:

<?php if ($this->getCheckout()->getStepData('deliveryinstructions', 'is_show')): ?>
 <?php if ($this->getCheckout()->getStepData('deliveryinstructions', 'complete')): ?>
  <li>
   <h4 class="complete"><?php echo $this->__('Delivery Instructions') ?> <span class="separator">|</span> <a href="#deliveryinstructions" onclick="checkout.accordion.openSection('opc-deliveryinstructions');return false;"><?php echo $this->__('Change') ?></a></h4>
   <div class="content">
    <!-- Here write code to display the data the customer enters -->
   </div>
  </li>
 <?php else: ?>
  <li>
   <h4><?php echo $this->__('Delivery Instructions') ?></h4>
  </li>
 <?php endif; ?>
<?php endif; ?>

We have now added a new step to our checkout and made it accessible in the same way as the rest of the checkout steps. Using this as a base, you can develop the concept further to provide additional information or options to the customer during checkout. Of course, too many steps will likely turn people away, so it's a matter of balancing the need to collect extra information with the need to make the checkout as quick and easy to complete as possible.

Creating a Custom Magento Shipping Method


Explaining The Shipping Architecture

Before making our own module, we’ll look at how Magento’s existing shipping rate functionality operates. If you are already familiar with this, then you should skip to the next section.
For this walkthrough we’ll use the “Flatrate” shipping method which is available by default with Magento. This method requires two files (excluding inherited classes and so on), these are:
  • app/code/core/Mage/Shipping/Model/Carrier/Flatrate.php
  • app/code/core/Mage/Shipping/etc/config.xml

Open Flatrate.php and take a look - there are four elements of the class which are essential to the operation of this rate.
app/code/core/Mage/Shipping/Model/Carrier/Flatrate.php
protected $_code = 'flatrate';
protected $_isFixed = true;
 
public function collectRates() {}
public function getAllowedMethods() {}

The first important element is the $_code property. This is a code which must be unique to your shipping method. It’s important to note this code is specified in other places, so you need to be consistent with its naming (more on this later). The next property, $_isFixed, is telling Magento that this shipping method is a fixed, one time fee - rather than a recurring payment, which is the alternative option here.
The second file is config.xml; this file is for all Magento shipping methods and as such, it is quite large. However, we are only interested in one part of it:
app/code/core/Mage/Shipping/etc/config.xml
<carriers>
    <flatrate>
        <active>1</active>
        <sallowspecific>0</sallowspecific>
        <model>shipping/carrier_flatrate</model>
        <name>Fixed</name>
        <price>5.00</price>
        <title>Flat Rate</title>
        <type>I</type>
        <specificerrmsg>This shipping method is currently unavailable...(etc)</specificerrmsg>
        <handling_type>F</handling_type>
    </flatrate>
</carriers>

Notice how the node is called <flatrate> to match the $_code property in the Flatrate.php class we saw earlier. Most of the nodes above are easy to understand, but some will benefit from a little more explanation:
sallowspecific set to 1 to limit the countries the rate is applicable to
title the courier name
name the rate name
type an option specific to flatrate, whether the charge is per item or order
specifierrmsg a message to show if the method does not apply to this country
handling_type whether the handling charge is fixed, per item or a percentage

The <model> node in config.xml, as shown above, tells Magento which shipping class to use; in our example, that is shipping/carrier_flatrate. Magento converts shipping/carrier_flatrate to Mage_Shipping_Model_Carrier_Flatrate (found in app/code/core/Mage/Shipping/Model/Carrier/Flatrate.php). The class within Magento responsible for loading the correct rate is Mage_Shipping_Model_Shipping. It is a good idea to take a look at this class and familiarise yourself with how Magento handles this.
We can also take a deeper look at the flatrate classfile. This class extends Mage_Shipping_Model_Carrier_Abstract and implements Mage_Shipping_Model_Carrier_Interface. In fact since all shipping methods must do the same, we can work out which methods require implementation, and which are already there. In general we will be interested in implementing two methods:
  • collectRates()
  • getAllowedMethods()

All other implementation is provided in Mage_Shipping_Model_Carrier_Abstract, so these two methods are all we need to create our own shipping model.

Creating Your Own Rate

This example shows how to create a simple shipping rate, which can provide the basis of a more complicated rate should you need to adapt this for your own purposes. The first step is to make our module skeleton by creating a directory structure along these lines:
app/code/local/Foobar/
app/code/local/Foobar/Shipping/
app/code/local/Foobar/Shipping/etc/
app/code/local/Foobar/Shipping/Model/

Then we need to add a module activation file to app/etc/modules/Foobar_Shipping.xml with the following contents:
app/etc/modules/Foobar_Shipping.xml
<?xml version="1.0"?>
<config>
    <modules>
        <Foobar_Shipping>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Shipping/>
            </depends>
        </Foobar_Shipping>
    </modules>
</config>

Next we make the config file; here’s the one I used when creating this example:
app/code/local/Foobar/Shipping/etc/config.xml
<?xml version="1.0" ?>
<config>
    <modules>
        <Foobar_Shipping>
            <version>0.1.0</version>
        </Foobar_Shipping>
    </modules>
    <global>
        <models>
            <foobar_shipping>
                <class>Foobar_Shipping_Model</class>
            </foobar_shipping>
        </models>
    </global>
    <default>
        <carriers>
            <foobar_customrate>
                <active>1</active>
                <model>foobar_shipping/carrier_customrate</model>
                <title>Foobar Shipping</title>
                <name>Default Rate</name>
            </foobar_customrate>
        </carriers>
    </default>
</config>

Finally we add our custom shipping class.
app/code/local/Foobar/Shipping/Model/Carrier/Customrate.php
<?php
 
class Foobar_Shipping_Model_Carrier_Customrate
    extends Mage_Shipping_Model_Carrier_Abstract
    implements Mage_Shipping_Model_Carrier_Interface
{
    protected $_code = 'foobar_customrate';
    protected $_isFixed = true;
 
    public function collectRates(Mage_Shipping_Model_Rate_Request $request)
    {
 
        if (!$this->getConfigFlag('active')) {
            return false;
        }
 
        $result = Mage::getModel('shipping/rate_result');
 
        $method = Mage::getModel('shipping/rate_result_method');
        $method->setCarrier('foobar_customrate');
        $method->setCarrierTitle($this->getConfigData('title'));
        $method->setMethod('foobar_customrate');
        $method->setMethodTitle($this->getConfigData('name'));
        $method->setPrice(5);
        $method->setCost(2);
 
        $result->append($method);
 
        return $result;
    }
 
    public function getAllowedMethods()
    {
        return array('foobar_customrate' => $this->getConfigData('name'));
    }
}

After clearing your cache, go and ahead and add a product to your cart and go to checkout. You should see our shipping method sitting there with a charge (of 5 units of whatever currency your Magento is set up to use). Congratulations - you have a basic shipping module available for use!

Behind the Scenes

When we hit the checkout, Magento uses the collectRates() method in our class; via this method you can offer shipping rates (or not) by storing an object in $result, which is Mage_Shipping_Model_Rate_Result. Basically, you add instances of Mage_Shipping_Model_Rate_Result_Method ($method in our example) to this object via the append() method. The rate result object holds all the values such as carrier and method name, as well as the all-important price and cost. In this way it becomes easy to offer multiple rates via the collectRates() method, simply by creating more rate results and calling append() for each one, in this way:
<?php
 
$result = Mage::getModel('shipping/rate_result');
 
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('foobar_customrate');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('foobar_customrate_one');
$method->setMethodTitle('Rate 1');
$method->setPrice(5);
$method->setCost(2);
 
$result->append($method);
 
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('foobar_customrate');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('foobar_customrate_two');
$method->setMethodTitle('Rate 2');
$method->setPrice(5);
$method->setCost(2);
 
$result->append($method);
After using the code above, you will see two shipping methods available for use. Methods are grouped by carrier, and the Carrier Title and Method Title are displayed on the frontend. If your shipping method uses multiple rates then it makes little sense to use the config to specify the names attribute, which is why they are hardcoded here. In this case you are free to remove the <name> node from your config.xml, as it is not used anywhere else.

Magento: Admin Controller Override


I had to override adminhtml controller class (Mage_Adminhtml_System_ConfigController) with my module’s controller class (MyNamespace_MyModule_ConfigController).
It was really tough to find the right solution. I googled, searched in magentocommerce forum and found a lot of solutions. But they didn’t work for me.

After searching & trying more, I got some work done with the following piece of code:-
<global>
    <routers>
        <adminhtml>
           <rewrite>
               <system_config>
                   <to>MyNamespace_MyModule/config</to>
                   <override_actions>true</override_actions>
                   <actions>
                       <save>
                           <to>MyNamespace_MyModule/config/save</to>
                       </save>
                       <index>
                           <to>MyNamespace_MyModule/config/index</to>
                       </index>
                   </actions>
               </system_config>
           </rewrite>
       </adminhtml>
    </routers>
</global>
But this gave “404 Error Page not found” when I go to System->Configuration.
Finally, I did the controller override with the following code:-
<global>
    <rewrite>
        <mynamespace_mymodule_config>
            <from><![CDATA[#^/admin/system_config/#]]></from>
            <to>/mymodule/config/</to>
        </mynamespace_mymodule_config>
    </rewrite>
</global>

Magento: How to get controller, module, action and router name?


You can easily get controller name, action name, router name and module name in template file or in any class file.
IN TEMPLATE FILES

$this->getRequest() can be used in template (phtml) files.
Here is the code:
/**
 * get Controller name
 */
$this->getRequest()->getControllerName();
 
/**
 * get Action name, i.e. the function inside the controller
 */
$this->getRequest()->getActionName();
 
/**
 * get Router name
 */
$this->getRequest()->getRouteName();
 
/**
 * get module name
 */
$this->getRequest()->getModuleName();
IN CLASS FILES
$this might not work in class (php) files. In this case, you need to use Mage::app().
Here is the code:
/**
 * get Controller name
 */
Mage::app()->getRequest()->getControllerName();
 
/**
 * get Action name, i.e. the function inside the controller
 */
Mage::app()->getRequest()->getActionName();
 
/**
 * get Router name
 */
Mage::app()->getRequest()->getRouteName();
 
/**
 * get module name
 */
Mage::app()->getRequest()->getModuleName();
The above functions (getControllerName, getActionName, getRouteName, getModuleName) are present in the class Mage_Core_Model_Url.
You can explore all requests with print_r.
echo "<pre>";
    print_r(Mage::app()->getRequest());
echo "</pre>";

Friday, November 11, 2011

Magento: Very Useful Collection Functions


There are different important functions that you can implement in your Collection object. The functions are present in Varien_Data_Collection_Db class. The class file is present in lib/Varien/Data/Collection/Db.php
Here are some of the functions that you can use in your collection object:-

/**
 * Get Zend_Db_Select instance
 */
$collection->getSelect();
 
/**
 * Get collection size
 */
$collection->getSelect()->getSize();
 
/**
 * Get sql select string or object
 */
$collection->getSelect()->getSelectSql();
 
/**
 * Add select order
 */
$collection->getSelect()->setOrder($field, $direction);
 
/**
 * Add field filter to collection
 *
 * If $attribute is an array will add OR condition with following format:
 * array(
 *     array('attribute'=>'firstname', 'like'=>'test%'),
 *     array('attribute'=>'lastname', 'like'=>'test%'),
 * )
 */
$collection->getSelect()->setOrder($field, $condition);
 
/**
 * Set select distinct
 */
$collection->getSelect()->distinct($flag);
 
/**
 * Get all data array for collection
 */
$collection->getSelect()->getData();
 
/**
 * Reset loaded for collection data array
 */
$collection->getSelect()->resetData();
 
/**
 * Print and/or log query
 */
$collection->getSelect()->printLogQuery(true, true);
More functions below:-
Varien_Data_Collection_Db class extends Varien_Data_Collection class. Here are some more functions present in Varien_Data_Collection class:-
/**
 * Get current collection page
 */
$collection->getSelect()->getCurPage();
 
/**
 * Retrieve collection last page number
 */
$collection->getSelect()->getLastPageNumber();
 
/**
 * Retrieve collection page size
 */
$collection->getSelect()->getPageSize();
 
/**
 * Retrieve collection all items count
 */
$collection->getSelect()->getSize();
 
/**
 * Retrieve collection first item
 */
$collection->getSelect()->getFirstItem();
 
/**
 * Retrieve collection last item
 */
$collection->getSelect()->getLastItem();
 
/**
 * Retrieve collection items
 */
$collection->getSelect()->getItems();
 
/**
 * Clear collection
 */
$collection->getSelect()->clear();
You can also use the select functions as present in Zend_Db_Select class. This class file is present in lib/Zend/Db/Select.php