Tuesday, April 10, 2012

Magento Set, Retrieve and Unset Session Variables


To set a Magento session variable:
$myValue = 'Hello World';
Mage::getSingleton('core/session')->setMyValue($myValue);
To Retrieve:
$myValue = '';
$myValue=Mage::getSingleton('core/session')->getMyValue();
To Unset:
Mage::getSingleton('core/session')->unsMyValue();
Note that ‘MyValue’ can be any text you want but ‘set’, ‘get’ and ‘uns’ prefixes are required.

Saturday, April 7, 2012

The Better Way to Modify Magento Layouts

Here is the slimmed down, commented local.xml from one of our recent projects:
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
 <reference name="head">
  <!-- Magento looks in /skin/frontend/<INTERFACE>/<THEME>/js/buyprinting.js
  for this file -->
  <action method="addItem"><type>skin_js</type><name>js/buyprinting.js</name></action>
  <!-- This removes the item that was set in the page.xml file -->
  <action method="removeItem"><type>skin_js</type><name>js/iehover-fix.js</name></action>
  <!-- Magento looks in /js/prototype/element.storage.js for this file -->
  <action method="addJs"><name>prototype/element.storage.js</name></action>
  <action method="addCss">
<stylesheet>css/buyprinting.css</stylesheet></action>
 </reference>
 <reference name="header">
        <!-- This adds a CMS block that can be called from the template file
        associated with the header block. -->
  <block type="cms/block" name="cms_quick_help">
   <action method="setBlockId"><block_id>quick_help</block_id></action>
  </block>
        <!-- The remove tag removes the blocks with the specified name from the layout -->
  <remove name="top.menu"/>
  <remove name="store_language"/>
  <remove name="breadcrumbs"/>
 </reference>
 <reference name="top.nav">
  <remove name="catalog.topnav"/>
 </reference>
 <reference name="left">
  <remove name="left.newsletter"/>
  <remove name="left.permanent.callout"/>
  <remove name="catalogsearch.leftnav"/>
        <!-- When you use the remove tag, it removes any blocks with the specified name from
            the entire layout, regardless of the context. So, if I remove right.newsletter in
            the <default> context and that name is used in say the <catalog_product_view> context,
            then both blocks will be removed.  Because remove operates on the global context,
            you can only remove an element once.  Since <remove name="right.newsletter" /> is
            being called in catalogsearch.xml, we have to unset it, or else we'll get an error.

            The line below only unsets the block from the parent's context, not the global
            layout context -->
  <action method="unsetChild"><name>right.newsletter</name></action>
 </reference>
 <reference name="right">
        <!-- Some blocks have to be removed using remove, others via unsetChild.
            I've not spent the time digging into the code to figure out why -->
  <remove name="right.permanent.callout"/>
  <remove name="catalog.compare.sidebar"/>
  <remove name="left.reports.product.viewed"/>
  <action method="unsetChild"><name>sale.reorder.sidebar</name></action>
  <action method="unsetChild"><name>wishlist_sidebar</name></action>
  <action method="unsetChild"><name>right.reports.product.viewed</name></action>
  <remove name="cart_sidebar"/>
 </reference>
</default>

<!-- CATALOG PAGES -->
 <catalog_product_view><!-- 2columns-right -->
  <reference name="root">
   <action method="setTemplate"><template>page/2columns-left.phtml</template></action>
  </reference>
  <reference name="content">
   <reference name="product.info">
    <block type="cms/block" name="cms_product_info_tabs">
     <action method="setBlockId"><block_id>product_info_tabs</block_id></action>
    </block>
    <block type="catalog/product_view" name="product.clone_prices" as="prices" template="catalog/product/view/price_clone.phtml"/>
    <action method="unsetChild"><name>tierprices</name></action>
    <action method="unsetChild"><name>addto</name></action>
    <remove name="addto"/>
    <reference name="product.info.options.wrapper.bottom">
     <action method="unsetChild"><name>product.tierprices</name></action>
    </reference>
   </reference>
  </reference>
 </catalog_product_view>
</layout>

Other:
<!-- Append the cart_sidebar block into the right block -->
   <reference name="right">
      <action method="append"><block>cart_sidebar</block></append>
   </reference>

   <!-- Remove the cart_sidebar block from the left sidebar -->
   <reference name="left">
      <action method="unsetChild"><block>cart_sidebar</block></action>
   </reference>

Friday, March 23, 2012

A list of some useful code snippets for Magento developers


1. Check if customer is logged in:
if(!Mage::getSingleton('customer/session')->isLoggedIn())
{
 $this->_redirect('customer/account/login/');
}
2. Get current site url:
Mage::getUrl();
3. Get Category URL:
$categoryUrl = Mage::getModel('catalog/category')->load($categoryId)->getUrl();
4. Get product URL:
$productId = 1;
$product = Mage::getModel('catalog/product')->load($productId);
$path = Mage::getUrl().$product->getUrlPath();
5. Get Product image path:
$productId = 1;
$product = Mage::getModel('catalog/product')->load($productId);
$path = Mage::helper('catalog/image')->init($product, 'image')->resize(75, 75);
6. Format a number as price:
$this->formatPrice(10);
7. Call a .phtml explicitly:
echo $this->getLayout()->createBlock('sales/order_recent')->setTemplate('sales/order/recent.phtml')->toHtml();
8. Get Currency Code:
Mage::app()->getStore()->getCurrentCurrencyCode();
9. Get Currency Symbol:
Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())->getSymbol();
10. Get Customer Shipping/Billing Address:
$customerAddressId = Mage::getSingleton('customer/session')->getCustomer()->getDefaultShipping();
if ($customerAddressId){
       $address = Mage::getModel('customer/address')->load($customerAddressId);
}
11. Get all products in the cart:
$mageFilename = 'app/Mage.php';
require_once $mageFilename;
umask(0);
Mage::app();

// Secret Sauce - Initializes the Session for the FRONTEND
// Magento uses different sessions for 'frontend' and 'adminhtml'
Mage::getSingleton('core/session', array('name'=>'frontend'));

$session = Mage::getSingleton('checkout/session');
foreach ($session->getQuote()->getAllItems() as $item)
{
 $productid      = $item->getProductId();
 $name       = $item->getName();
 $qty       = $item->getQty();

 echo "Product Id-".$productid.', Name-'.$name. ', Quantity-'.$qty;
}
12. Find which class is loaded in current template:
<?php
    print_r(get_class_methods(get_class($this)));
?>
or
<?php
    print_r($this->debug());
?>
or
<?php
    echo Zend_Debug::dump($this);
?>
13. Get Current theme folder:
<?php echo $this->getSkinUrl('') ?>
14. Get total price of items in the cart:
<?php echo $this->helper('checkout')->formatPrice(Mage::getSingleton('checkout/cart')->getQuote()->getGrandTotal()); ?>
15. Get the current category:
<?php
    $currentCategory = Mage::registry('current_category');
?>
16. Add product to cart through querystring:
http://www.mydomain.com/checkout/cart/add?product=[id]&qty=[qty]
http://www.mydomain.com/checkout/cart/add?product=[id]&qty=[qty]&options[id]=[val

Improving PHP performance

I want to share these tips with my readers.

1. 'echo' is much faster than print. So always try echo something rather than printing it.

/*This is faster*/
echo 'This is echoed text';

/*This is slower*/
print 'This is printed text';

2. Always use the stacked form of echo instead of using concatenation. e.g

/*Faster form of echo*/
echo 'This is stacked form of ', $variable;

/*Slower form of echo*/
echo 'This is regular form of ' . $variable;

3. Use of single quotes rather than double quotes with echo can improve the performance of your code because compiler will not search for the variables inside the single quotes but in double quotes it will perform a search for possible variables.

/*Faster form of echo*/
echo 'This is single quoted string.';

/*Slower form of echo*/
echo "This is double quoted $string.";

4. Use pre-increments where possible instead of post-increments. Pre-incrementing is faster than post-increments.

/*Slower form of iteration*/
for ( $i=0; $i < 1000; $i++ ) {
echo 'Loop ',$i;
}

/*Faster form of iteration*/
for ( $i=0; $i < 1000; ++$i ) {
echo 'Loop ',$i;
}

5. Never use calculations as counters in an iteration.

/*Slower form of iteration*/
for ( $i=0; $i < count($arr); $i++ ) {
echo 'Loop ',$i;
}

/*Faster form of iteration*/
$counter = count($arr);

for ( $i=0; $i < $counter; $i++ ) {
echo 'Loop ',$i;
}

6. Always unset the variable after using those. It may save some of your resources on the server.

$counter = count($arr);

for ( $i=0; $i < $counter; $i++ ) {
$value = $arr[$i];

foo( $value );//call any function

unset($value);//unset the variable after using it.
}

7. Always initialize your variables before using those. It can sometimes prove beneficial in terms of performance.

$counter = count($arr);

$value = '';//initialize the variable before using it

for ( $i=0; $i < $counter; $i++ ) {
$value = $arr[$i];

foo( $value );//call any function

unset($value);//unset the variable after using it.
}

8. Always close the database connections after you are done with the queries.

mysql_connect('localhost', 'root', 'secret123');

mysql_select_db('test_db');

//write database queries here

mysql_close();//close the connection at the end

9. Avoid strlen() to check the length of a string. Checking the desired index in the string can also work.

/*Slower form*/
if ( strlen($str) > 100 ) {
echo 'You have crossed the limits';
}

/*Faster form*/
if ( $str[100] ) {
echo 'You have crossed the limits';
}

10. Use include() and require() instead of include_once() and require_once(). There's a lot of work involved in checking to see if a file has already been included. Sometimes it's necessary, but you should default to include() and require() in most situations.

11. Use full file paths on include/require statements. Normalizing a relative file path can be expensive; giving PHP the absolute path (or even "./file.inc") avoids the extra step.

12. Don't copy variables for no reason. Sometimes PHP novices attempt to make their code "cleaner" by copying predefined variables to variables with shorter names before working with them. What this actually results in is doubled memory consumption (when the variable is altered), and therefore, slow scripts. In the following example, if a user had inserted 512KB worth of characters into a textarea field. This implementation would result in nearly 1MB of memory being used.

/*Slower form*/
$description = strip_tags($_POST['description']);
echo $description;

/*Faster form*/
echo strip_tags($_POST['description']);

13. Avoid doing SQL queries within a loop. A common mistake is placing a SQL query inside of a loop. This results in multiple round trips to the database, and significantly slower scripts. In the example below, you can change the loop to build a single SQL query and insert all of your users at once.

foreach ($userList as $user) {
$query = 'INSERT INTO users (first_name,last_name) VALUES("' . $user['first_name'] . '", "' . $user['last_name'] . '")';
mysql_query($query);
}

Produces:

INSERT INTO users (first_name,last_name) VALUES("John", "Doe")

Instead of using a loop, you can combine the data into a single database query.

$userData = array();
foreach ($userList as $user) {
$userData[] = '("' . $user['first_name'] . '", "' . $user['last_name'] . '")';
}
$query = 'INSERT INTO users (first_name,last_name) VALUES' . implode(',', $userData);
mysql_query($query);

Produces:
INSERT INTO users (first_name,last_name) VALUES("John", "Doe"),("Jane", "Doe")...

14. Avoid OOP whenever you can. You should use OOP concepts only when these are really required. Study the situation you are working in. If you can do the things without OOP concepts, do it without hesitation. Using OOP for smaller tasks will always increase overhead rather than improving the performance. So the core concepts can help in most of the situations.'

15. Always strive for caching. Each time your request is processed by the server, the server has to reproduce the similar content repetitively. This wastes a lot of server resources just for nothing useful. So try to implement templating systems like 'Smarty'. It will always fasten your web application.

16. Using in built functions of PHP is many times faster than using custom build functions. So search the PHP manual thoroughly before writing your own function. Nearly every type of function is available in PHP.

Implementing alphabetical search in Magento

Create below mentioned files in the app/core/code/local directory with complete directory structure as in Magento core.

app\code\local\Mage\Catalog\Block\Product\List\Toolbar.php
In this file replace the setCollection function with following:

public function setCollection($collection)
    {
        $this->_collection = $collection;

        $this->_collection->setCurPage($this->getCurrentPage());

        // we need to set pagination only if passed value integer and more that 0
        $limit = (int)$this->getLimit();
  $postData = '';
        if ($limit) {
            $this->_collection->setPageSize($limit);
        }
        if ($this->getCurrentOrder()) 
  {
   /**********Alphabetic search Code Start From here**********/
   $postData = Mage::app()->getRequest()->getParam('alpha').'%';
   if(isset($postData['alpha']) && $postData['alpha']!= '' && trim($postData) !='ALL')
   {
    $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection())->addAttributeToFilter(array(
                    array('attribute'=>'name', 'like'=>$postData)
                ));
   }
   else
   {
      $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
   }
   /**********Alphabetic search Code ends here**********/
        }
        return $this;
    }
app\design\frontend\default\default\template\catalog\product\list\toolbar_bottom.phtml

Open this file an replace the code with given below:
<?php 
$search_array = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','ALL');

/*Find if the URL already contains any querystring variable or not */
if (strstr( $this->helper('core/url')->getCurrentUrl(), "&" ))
{
 $separator = '&'; 
}
else
{
    $separator = '?';
}
?>
    <div>
        <p class="view-mode-list-bot">
            <?php 
   $postData = Mage::app()->getRequest()->getParam('alpha');
   foreach ($search_array  as $search_array_value):
   
   /*Clean the URL*/
   if (strstr( $this->helper('core/url')->getCurrentUrl(), "?" ) )
   {
    $new_Url =  $this->str_replace_once('&','?',str_replace("?alpha=".trim($postData['alpha']),'',str_replace($separator."alpha=".trim($postData['alpha']),'',$this->helper('core/url')->getCurrentUrl())));
   }
   else
   {
    $new_Url = str_replace("?alpha=".trim($postData['alpha']),'',str_replace($separator."alpha=".trim($postData['alpha']),'',$this->helper('core/url')->getCurrentUrl()));
   }

   $alphaURL = $new_Url.$separator.'alpha='.$search_array_value;
?>
                
                    <a href="<?php echo $alphaURL; ?>" title="<?php echo $_label ?>" class="<?php echo strtolower($_code); ?> <?php if($search_array_value == $postData){ echo 'remove_under'; } ?>"><?php echo $search_array_value; ?></a>   
                
            <?php endforeach; ?>
           
        </p>
       
    </div>

Thursday, March 22, 2012

Magento : Add category attribute

There are following step
1.Create a new module under your local folder, in our case under /app/local/Bd/Customcategoryattribute.
2.Register the module in etc/modules directory Bd_Customcategoryattribute by using the following code

<?xml version="1.0"?>
<config>
  <modules>
    <Bd_Customcategoryattribute>
      <active>true</active>
      <codePool>local</codePool>
      <version>0.1.0</version>
    </Bd_Customcategoryattribute>
  </modules>
</config>
3.Create config.xml under etc directory of your module /app/local/Bd/Customcategoryattribute/etc/config.xml by using the following code

<?xml version="1.0"?>
<config>
  <modules>
    <Bd_Customcategoryattribute>
      <version>0.1.0</version>
    </Bd_Customcategoryattribute>
  </modules>
  <global>
    <helpers>
      <customcategoryattribute>
        <class>Bd_Customcategoryattribute_Helper</class>
      </customcategoryattribute>
    </helpers>
<models>
 <customcategoryattribute>
<class>Bd_Customcategoryattribute_Model</class>
<resourceModel>customcategoryattribute_mysql4</resourceModel>
 </customcategoryattribute>
</models>
<resources>
 <customcategoryattribute_setup>
<setup>
 <module>Bd_Customcategoryattribute</module>
 <class>Mage_Catalog_Model_Resource_Eav_Mysql4_Setup</class>
</setup>
<connection>
 <use>core_setup</use>
</connection>
 </customcategoryattribute_setup>
 <customcategoryattribute_write>
<connection>
 <use>core_write</use>
</connection>
 </customcategoryattribute_write>
 <customcategoryattribute_read>
<connection>
 <use>core_read</use>
</connection>
 </customcategoryattribute_read>
</resources>
  </global>
</config>
4.Create setup file mysql4-install-0.1.0 under sql directory of your module /app/local/Bd/Customcategoryattribute/sql/customcategoryattribute_setup/mysql4-install-0.1.0.php by using the following code

<?php
$installer = $this;
$installer->startSetup();
$installer->addAttribute("catalog_category", "custom_attribute",  array(
    "type"     => "varchar",
    "backend"  => "",
    "frontend" => "",
    "label"    => "Custom Attribute",
    "input"    => "text",
    "class"    => "",
    "source"   => "",
    "global"   => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
    "visible"  => true,
    "required" => false,
    "user_defined"  => false,
    "default" => "",
    "searchable" => false,
    "filterable" => false,
    "comparable" => false,
    "visible_on_front"  => false,
    "unique"     => false,
    "note"       => "Extra Attribute"
));
$installer->endSetup();
5. At last create helper Data.php under helper directory of your module /app/local/Bd/Customcategoryattribute/Helper/Data.php by using the following code
<?php class Bd_Customcategoryattribute_Helper_Data extends Mage_Core_Helper_Abstract { }  

Here, 
type:(realted to db)  varchar, text, datetime, int, etc.
input:(reated to frontend filed) text, textarea, date, select, multiselect, select, image

Please comment if u need about other properties. Thanks.


Remove Head Block From Page


You can either unset head block entirely, or just remove the script files. What you need to do is to create an observer on

controller_action_layout_render_before
event, and create this observer function:
public function removeHead()
{
 if (Mage::app()->getRequest()->getModuleName() == "lazyload") { //put your module/controller/action name here so you don't remove head for every single page
  $layout = Mage::getSingleton('core/layout');
  $layout->unsetBlock('head');

  /* second level of destruction - because this block has two lives .. like a final queen in an arcade */

  $head = $layout->getBlock('root')->getChild('head');
  if (is_object($head)) {
   $head->setData('items',array());
   $layout->getBlock('root')->setChild('head',$head);
  }

  /* third level of destruction - if the bitch respawns */
  //$layout->getBlock('root')->setChild('head', new Mage_Core_Block_Template);
 }
}