Some Magento Models and Collections

This is a bit of a pastebin of code relating to Magento models and collections. No guarantee of performance or best practices here.

TO DO: figure out finer points of models and collections, add some organization and structure.



Magento's data models have three basic class types*

  • A model is what you'll most commonly use. This represents data of a particular type in a database agnostic way (product, category, CMS Page, Review, etc.)
  • A resource model is a class that, behind the scenes, does the actual fetching of data from Magento. Every model has a resource model that is used to load a single instance of a model from the database.
  • A collection is a class that loads an array like structure of multiple models based on a set of rules. Think of it like a SQL WHERE clause.

Adding to confusion is that, behind the scenes, Magento also considers a collection to be a resource model. So there's collection resource models and individual resource models.

Generally speaking, when you want to load a specific item, you use a model. When you want to load a number of items, you use a collection resource model.


* Shamelessly lifted from Alan Storm's site.


Listing Parent Classes of Magento Collections and Models

Listing Parent Classes of Magento Collections and Models.

Let us look at clooection class that retrieves product and product information

The class is called

class Mage_Catalog_Model_Resource_Product_Collection

and is located at this location

/app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php

Now let us list it's parent classes

<?php
// list parent classes

// specify path to Mage.php - only needed if this is standalone program
require_once 'C:\xampp\htdocs\magento\app\Mage.php';

// Magento boostrap - only needed if this is standalone program
Mage::app();

// put your favourite collection or model here...
$collection = Mage::getResourceModel('catalog/product_collection');

$count = 1;
echo "<pre>";
echo $count . ": Collection: " . get_class($collection) . "<br>";;
$parent = get_parent_class($collection);

while ($parent) {    
	$count++;
	echo $count . ": Parent ". $parent . "<br>";
	$parent = get_parent_class($parent);   
}

Output:

1: Collection: Mage_Catalog_Model_Resource_Product_Collection
2: Parent Mage_Catalog_Model_Resource_Collection_Abstract
3: Parent Mage_Eav_Model_Entity_Collection_Abstract
4: Parent Varien_Data_Collection_Db
5: Parent Varien_Data_Collection



Listing Magento Collections and Models Class Methods

Listing Magento Magento Collections and Models Class Methods using php get_class and get_class_methods.

<?php
// get class method for a  Magento class

// specify path to Mage.php
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();

// for catalog product
// $collection = Mage::getResourceModel('catalog/product');

// for catalog model
// $collection = Mage::getResourceModel('catalog/model');

// for catalog categories
// $collection = Mage::getResourceModel('catalog/category');

// for sales order
// $collection = Mage::getResourceModel('sales/order');

// for sales order
// $collection = Mage::getResourceModel('sales/order_invoice_collection');
  
// for catalog product
// $collection = Mage::getResourceModel('catalog/category');

// used to to get cataegories and all products
$collection = Mage::getResourceModel('catalog/product_collection');

$class_name = get_class($collection);
$methods = get_class_methods($class_name);
echo "<pre>";
echo "List Methods for class $class_name \n<br />\n";
foreach($methods as $method)
{
    var_dump($method);
}

Output:

List Methods for class Mage_Catalog_Model_Resource_Category 

List Methods for class Mage_Catalog_Model_Resource_Product_Collection 


string(11) "__construct"
string(24) "getCatalogPreparedSelect"
string(18) "getPriceExpression"
string(28) "getAdditionalPriceExpression"
string(15) "getCurrencyRate"
string(13) "getFlatHelper"
string(13) "isEnabledFlat"
string(15) "getNewEmptyItem"
string(9) "setEntity"
string(8) "setStore"
string(15) "_loadAttributes"
string(20) "addAttributeToSelect"
string(11) "addIdFilter"
string(23) "addWebsiteNamesToResult"
string(14) "addStoreFilter"
...



Listing Magento Class Properties and Methods with parent

Listing Magento Class Properties and Methods and parent Properties and Methods

<?php
// get class method for a Magento class and its parents

// specify path to Mage.php
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();

$collection = Mage::getResourceModel('catalog/product');
$count = 1;
echo "<pre>";
echo $count . ": Methods for class " . get_class($collection);
print_r(get_class_methods($collection));
$parent = get_parent_class($collection);

while ($parent) {    
	$count++;
	echo $count . ": Methods for parent ". $parent . " ";
	print_r(get_class_methods($parent));
	$parent = get_parent_class($parent);   
}

Output:

1: Methods for class Mage_Catalog_Model_Resource_ProductArray
(
    [0] => __construct
    [1] => getWebsiteIds
    [2] => getWebsiteIdsByProductIds
    [3] => getCategoryIds
    [4] => getIdBySku
    [5] => refreshIndex
	...
	
2: Methods for parent Mage_Catalog_Model_Resource_Abstract Array
(
    [0] => getDefaultStoreId
    [1] => getAttributeRawValue
    [2] => load
    [3] => setConnection
    [4] => getReadConnection
    [5] => getWriteConnection	
	...




Class Methods vs array notation

Using catalog/category' collection. Getting data using class method where available or as array element.

<?php
// getting data using method where available or array notation
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();


$collection = Mage::getModel('catalog/category')->load($categoryId)
    ->getProductCollection()   
    ->addAttributeToSort('name', 'ASC');

echo "<pre>Get value by <br>";
foreach($collection as $product) {

    // get name as array element
    echo "by array value : " . $product['name'] . "<br>";

    // get name using getName method
    echo "by method      : " . $product->getName() . "<br><br>";
}

Output:

Get value by 
by array value : 1-Year Members Only Shopping
by method      : 1-Year Members Only Shopping

by array value : 16GB Memory Card
by method      : 16GB Memory Card

by array value : 3-Year Warranty
by method      : 3-Year Warranty

by array value : 5-Year Warranty
by method      : 5-Year Warranty

by array value : 8GB Memory Card
by method      : 8GB Memory Card

...



Iterating through Magento Stores

Iterating through Magento Stores to get store number, language, and root category.

The Admin section of Magento uses terms "Website", "Store" and "Store View". In the code the terms are "Website", "Store Group" and "Store View" and the methods used to access data are getWebsites(), getGroups(), and getStores().


<?php
//require_once 'C:\xampp\htdocs\magento\app\Mage.php';
require_once '/var/www/shop/app/Mage.php';

Mage::app();

error_reporting(E_ALL);
ini_set('display_errors', 1);

foreach (Mage::app()->getWebsites() as $website) {
    foreach ($website->getGroups() as $group) {
        $stores = $group->getStores();
        echo "<h3>Store Information<h3>";			
		echo "<pre>";		
		
		foreach ($stores as $store) {			
			echo "<pre>";		
			// print_r($store);
			echo "Website ID:" . $store['website_id'] . "<br>";
			echo "Store ID: "  . $store['store_id'] . "<br>";
			echo "Store code: " . $store['code'] . "<br>";
			echo "Store Name: " . $store['name'] . "<br>";
			echo "Store Is active: " . $store['is_active']  . "<br>";
			echo "Root Category: " . $store->getRootCategoryId()  . "<br>";
        }
    }
}

Output

Store Information

Website ID:1
Store ID: 1
Store code: en
Store Name: English
Store Is active: 1
Root Category: 113

Website ID:1
Store ID: 2
Store code: fr
Store Name: Francais
Store Is active: 1
Root Category: 113

Website ID:1
Store ID: 3
Store code: en_us
Store Name: English US
Store Is active: 0
Root Category: 113



Iterating through Collections: List Magento Categories

Use Magento Collections to get collection of Categories.

<?php

//require_once '/var/www/myStore/Mage.php';
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();

$categories = Mage::getModel('catalog/category')
                    ->getCollection()
                    ->addAttributeToSelect('*');
					

echo "<pre>";
foreach ($categories as $category){
	echo "Name = " 		. $category['name'] . '<br>';
	echo "Entity ID = " . $category['entity_id'] . '<br>';
	// can do the same with getData Property
	echo "Entity ID = " . $category->getData('entity_id') . '<br>';	
	echo "Url Path = " . $category->getData('url_path') . '<br>';		
	echo "Parent ID = " . $category['parent_id'] . '<br>';
	echo "Is Active = " . $category['is_active'] . '<br><br>';
		
	// var_dump($category);    
}

output:

Name = Root Catalog
Entity ID = 1
Entity ID = 1
Url Path = 
Parent ID = 0
Is Active = 

Name = Default Category
Entity ID = 2
Entity ID = 2
Url Path = 
Parent ID = 1
Is Active = 1

Name = Women
Entity ID = 4
Entity ID = 4
Url Path = women.html
Parent ID = 2
Is Active = 1

Name = Men
Entity ID = 5
Entity ID = 5
Url Path = men.html
Parent ID = 2
Is Active = 1

Name = Accessories
Entity ID = 6
Entity ID = 6
Url Path = accessories.html
Parent ID = 2
Is Active = 1
...



Iterating through Catalog Product Collection

Sort by name Ascending,

<?php
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();

$_productCollection = Mage::getModel('catalog/product')
                        ->getCollection()
                        ->addAttributeToSort('name', 'ASC')
                        ->addAttributeToSelect('*')
                        ->load();

foreach ($_productCollection as $_product){	
	echo ' Name => ' . $_product->getName() . '<br>';   
	echo ' Item ID => ' . $_product->getId() . '<br>';
	echo ' Price => ' .  $_product->getPrice() . '<br>';

	$stock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($_product->getId());
	
	echo ' Qty => ' .   $stock->getQty() . '</br>';
	echo ' min Qty => ' .   $stock->getMinQty() . '<br>';	
	echo ' min Sale Qty => ' .   $stock->getMinSaleQty() . '<br>';
	
	echo ' Manage Stock => ' .   $stock->getManageStock() . '<br>';
	echo ' Is in Stock => ' .   $stock->getIsInStock()  ;
	
	if ($stock->getIsInStock()) {
		echo " => product is in stock" . '<br>';
	} 
	else {
		echo " => product is not in stock" . '<br>';
	}   
	
	echo '<br>' ;
	
}



Iterating through Collections: Add count

Same as above, but we add setLoadProductCount method and filters to count active products for each category

<?php
// getting data using method where available or array notation
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();

$category_collection = Mage::getModel('catalog/category')
    ->getCollection()
    ->addAttributeToSelect('*')
    ->addAttributeToFilter('level', 2)
    ->addAttributeToSelect('is_active', 1)
    ->setLoadProductCount(true);

echo "<pre>"; 
foreach($category_collection as $item)
{
    echo ('Entity ID: ' . $item->getData('entity_id') . "\n" );	
	echo ('Name: ' . $item->getData('name') . "\n" );
	echo ('Include in Menu: ' . $item->getData('include_in_menu') . "\n" );
	echo ('IsActive: ' .$item->getData('is_active') . "\n" );
	echo ('URL: '  . $item->getData('url_path') . "\n" );	
	echo ('Product Count: '  . $item->getData('product_count') . "\n" );	
	// var_dump($item->getData());
	echo "\n"; 
}

Output:

Entity ID: 4
Name: Women
Include in Menu: 1
IsActive: 1
URL: women.html
Product Count: 51

Entity ID: 5
Name: Men
Include in Menu: 1
IsActive: 1
URL: men.html
Product Count: 70

Entity ID: 6
Name: Accessories
Include in Menu: 1
IsActive: 1
URL: accessories.html
Product Count: 58



List Magento Products using catalog/category and getProductCollection()

list products using catalog/category and getProductCollection() method, sorted by product name.

<?php

// specify path to Mage.php
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();

// listing products using catalog/category 
// and getProductCollection() method
// sorted by product name

$category_collection = Mage::getModel('catalog/category')
	->load($categoryId)
    ->getProductCollection()
    ->addAttributeToSort('name', 'ASC');
	
echo "<pre>";

foreach($category_collection as $item)
{
     echo $item->entity_id  . " - " ;	 
	 echo $item->name . "<br/>" ;
	 // dump whole array
	 // var_dump($item);
}

output:

542 - 1-Year Members Only Shopping
394 - 16GB Memory Card
441 - 3-Year Warranty
442 - 5-Year Warranty
395 - 8GB Memory Card
448 - A Tale of Two Cities
450 - Alice in Wonderland
687 - Angela Wrap Dress
...



List Magento Categories with corresponding Products

Sort by name Ascending,

<?php
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();
 
$category_collection = Mage::getModel('catalog/category')
    ->getCollection()
    ->addAttributeToSelect('*');
	
foreach($category_collection as $item){
	echo ('</br>');		
	echo ('Entity ID: ' . $item->getData('entity_id') . "</br>" );	
	echo ('Name: ' . $item->getData('name') . "</br></br>" );
	fnGetProducts($item->getData('entity_id'));	
}

function fnGetProducts($catId)
{
	$category = new Mage_Catalog_Model_Category();
	$category->load($catId);
	$collection = $category->getProductCollection();
				->addAttributeToSelect('*');	
				->joinField('qty',
                 'cataloginventory/stock_item',
                 'qty',
                 'product_id=entity_id',
                 '{{table}}.stock_id=1',
                 'left');
	
	echo '<table border="1" style="border-collapse:collapse;" width="95%" padding:"5px">'; 	
	echo '<tr>';	
	echo '<td> SKU </td>';
	echo '<td> ID </td>';
	echo '<td> Name </td>';
	echo '<td> Manage Stock </td>';	
	echo '<td> Qty in Stock </td>';
	echo '<td> Price </td>';
	echo '<td> Weight </td>';
	echo '<td> Visibility </td>';
	echo '<td> Tax Class </td>';
	echo '<td> Colour </td>';		
	echo '<td> Size </td>';		
	echo '<td>  </td>';
	echo '<td width="50%"> Description </td>';
	echo '</tr>';
		
	foreach ($collection as $product) { 
		
		echo '<pre>';		
		// var_dump($product);
		// die();
		
		echo '<tr>';		
		echo '<td>' .$product->getSku() . '</td>';
		echo '<td>' . $product->getId() . '</td>';
		echo '<td>' .$product->getName() . '</td>';

		// Stock Item - Manage Stock
		$stock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($product->getId());				
		if ($stock->getManageStock() == 1){
			echo  '<td> Yes </td>';  
		}
		else{ 
			echo '<td> No </td>' ;
		}
				
		echo '<td>' . round($product->getQty()) . '</td>';		
		echo '<td>' . $product->getPrice() . '</td>';
		echo '<td>' . $product->getWeight() . '</td>';
		
		echo '<td>' .$product->getVisibility() . '</td>';
		
		// Tax class
		$taxClassId = $product->getTaxClassId();
		$taxClassName = Mage::getModel('tax/class')->load($taxClassId)->getClassName();			
		echo '<td>' .$product->getTaxClassId() . '=' . $taxClassName . '</td>';
			
		// Color
		$colorName = $product->getResource()->getAttribute('color')->getFrontend()->getValue($product);			
    	echo '<td>' .$product->getColor() . ' = ' . $colorName . '</td>';		
		
		// Size
		$size =  $product->getResource()->getAttribute('size')->getFrontend()->getValue($product) . ' '	;
		if (trim($size) <> 'No'){
			echo  '<td>' . trim($size) . '</td>';  
		}
		else{ 
			echo '<td> </td>' ;
		}
	
		echo '<td>' .$product->getStockItem() . '</td>'; 
		echo '<td>' .$product->getDescription() . '</td>'; 
		echo '</tr>';
	
	}
	echo '</table>'; 
}
	



List Order and Payment Information using sales/order_payment collection

<?php

// specify path to Mage.php
require_once 'C:\xampp\htdocs\magento\app\Mage.php';
Mage::app();

$orders = Mage::getModel('sales/order')->getCollection();
$orders->getSelect()->join(
    array('p' => $orders->getResource()->getTable('sales/order_payment')),
    'p.parent_id = main_table.entity_id',
    array()
);
//$orders->addFieldToFilter('method','ccsave');
echo "<pre>";
foreach ($orders as  $order) {
    echo "Entity Id -> "     . $order->getEntityId() ."<br>";
	echo "Order No -> "      . $order->getIncrementId(); 
	echo "Customer Name -> " . $order->getCustomerLastname() . ", " . $order->getCustomerFirstname() . "<br>";	
	echo "Ship Status -> "   . $order->getStatus() . "<br>";
	echo "Ship Carrier -> "  . $order->getShippingDescription() . "<br>";	
	echo "Order Total -> "   . $order->getGrandTotal() . "<br><br>";	
	// var_dump($order);	
}

Output:

Entity Id -> 41
Order No -> 100000049
Customer Name -> Akizian, Mosses
Ship Status -> pending
Ship Carrier -> United Parcel Service - Ground
Order Total -> 823.4500

Entity Id -> 42
Order No -> 100000051
Customer Name -> Ngia, Robert
Ship Status -> canceled
Ship Carrier -> United Parcel Service - 3 Day Select
Order Total -> 698.3000

Entity Id -> 43
Order No -> 100000052
Customer Name -> Moorehouse, Jill
Ship Status -> canceled
Ship Carrier -> United Parcel Service - Next Day Air Early AM
Order Total -> 1148.0800

List Categories with Products to html file and email to users


<?php
require_once '/var/www/myshop/app/Mage.php';
//require_once 'C:\xampp\htdocs\magento\app\Mage.php';

Mage::app();


$category_collection = Mage::getModel('catalog/category')
    ->getCollection()
    ->addAttributeToSelect('*');

// write to file
ob_start();

     echo "<h3>This report lists all Categories in myshop.com and Categories with corresponding products";
     echo " in each category</h3>";


    echo "<h4>1. List all categories</h4>";

    fnListHierarchy();

    echo "<h4>2. List all categories and products</h4>";

foreach($category_collection as $item){
    // we are only interested in new categoies (113 and greater...)
    if  ($item->getData('entity_id') >= 113)
    {
        echo ('</br>');
        echo ('Entity ID: ' . $item->getData('entity_id') . "</br>" );
        echo ('Name: ' . $item->getData('name') . "</br></br>" );
        fnGetProducts($item->getData('entity_id'));
    }
}


// print footer
fnFooter();


// capture contents & write tofile
$content = ob_get_contents();
ob_end_clean();
file_put_contents('/home/myshop_inventory_report.html', $content);

// echo $content;


// send by email
fnSendMail();


/* --------------------------------------------------------------------------
   get products
   -------------------------------------------------------------------------- */

function fnGetProducts($catId)
{

        $category = new Mage_Catalog_Model_Category();
        $category->load($catId);
        $collection = $category->getProductCollection()
                                ->addAttributeToSelect('*')
                                ->joinField('qty',
                 'cataloginventory/stock_item','qty','product_id=entity_id',
                 '{{table}}.stock_id=1','left');

        echo '<table border="1" style="border-collapse:collapse;" width="95%" padding:"5px">';
        echo '<tr>';
        echo '<td width="10%"> SKU </td>';
        echo '<td width="5%"> ID </td>';
        echo '<td width="5%"> Status </td>';
        echo '<td width="15%"> Name </td>';
        echo '<td width="5%"> Manage Stock </td>';

        echo '<td width="10%"> Allow Backorders </td>';

        echo '<td width="5%"> Qty in Stock </td>';
        echo '<td width="5%"> Price </td>';
        echo '<td width="5%"> Weight </td>';
        echo '<td width="5%"> Visibility </td>';
        echo '<td width="5%"> Tax Class </td>';
        echo '</tr>';

        foreach ($collection as $product) {
// echo "<pre>";
// var_dump($product);

                echo '<pre>';

                echo '<tr>';
                echo '<td>' .$product->getSku() . '</td>';
                echo '<td>' . $product->getId() . '</td>';
                echo '<td>' . $product->getStatus() . '</td>';
                echo '<td>' . html_entity_decode($product->getName()) . '</td>';

                // Stock Item - Manage Stock
                $stock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($product->getId());
                if ($stock->getManageStock() == 1){
                        echo  '<td style="color:#0000A0;"> Yes </td>';
                }
                else{
                        echo '<td style="color:#008000"> No </td>' ;
                }

                echo '<td>' . ($stock->getBackorders());

               if ($stock->getBackorders() == 0) {
                  echo "= No backorders</td>";
               } elseif ($stock->getBackorders() == 1) {
                   echo "= Allow Qty below Zero</td>";
               } elseif ($stock->getBackorders() == 2) {
                   echo "<= Allow Qty below Zero and Notify Customer</td>";

               }

                echo '<td>' . round($product->getQty()) . '</td>';
                echo '<td>' . $product->getPrice() . '</td>';
                echo '<td>' . $product->getWeight() . '</td>';

                echo '<td>' . $product->getVisibility() . '</td>';

                // Tax class
                $taxClassId    = $product->getTaxClassId();
                $taxClassName  = Mage::getModel('tax/class')->load($taxClassId)->getClassName();
                echo           '<td>' .$product->getTaxClassId() . '=' . $taxClassName . '</td>';

                echo '<td>' . $product->getStockItem() . '</td>';
//              echo '<td>' . $product->getDescription() . '</td>';
                echo '</tr>';

        }
        echo '</table>';
  }

/* --------------------------------------------------------------------------
   send email
   -------------------------------------------------------------------------- */

function fnSendMail(){

  //define the receiver of the email

  //$addresses[] = array("myaddress1@example.com", "myaddress2@example.com");
  //$to = implode(", ", $addresses);
  $to = 'myaddress1@example.com';

  //define the subject of the email
  $subject = 'myshop.com inventory report';

  //create a boundary string. It must be unique
  //so we use the MD5 algorithm to generate a random hash
  $random_hash = md5(date('r', time()));

  //define the headers we want passed. Note that they are separated with \r\n
  $headers = "From: webmaster@example.com\r\nReply-To: webmaster@example.com";

  //add boundary string and mime type specification
  $headers .= "\r\nContent-Type: multipart/mixed; boundary=\"PHP-mixed-".$random_hash."\"";


  //read the atachment file contents into a string,
  //encode it with MIME base64,
  //and split it into smaller chunks

  $attachment = chunk_split(base64_encode(file_get_contents('/home/myshop_inventory_report.html')));
  //define the body of the message.
  ob_start(); //Turn on output buffering
?>
--PHP-mixed-<?php echo $random_hash; ?>
Content-Type: multipart/alternative; boundary="PHP-alt-<?php echo $random_hash; ?>"

--PHP-alt-<?php echo $random_hash; ?>
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Please find enclosed myshop.com inventory report

--PHP-alt-<?php echo $random_hash; ?>
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

<h3>myshop.com</h2>
<p>Inventory Report</p>

--PHP-alt-<?php echo $random_hash; ?>--

--PHP-mixed-<?php echo $random_hash; ?>
Content-Type: application/text; name="myshop_inventory_report.html"
Content-Transfer-Encoding: base64
Content-Disposition: attachment

<?php echo $attachment; ?>
--PHP-mixed-<?php echo $random_hash; ?>--

<?php
//copy current buffer contents into $message variable and delete current output buffer
$message = ob_get_clean();

//send the email
$mail_sent = @mail( $to, $subject, $message, $headers );

//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed"
echo $mail_sent ? "Mail sent" : "Mail failed";

}

/* --------------------------------------------------------------------------
   footer
   -------------------------------------------------------------------------- */


function fnFooter()
{

?>


   <h3>Manage Stock</h3>
   <p>Determines if you use full inventory control to manage the items in your catalog. Options include:</p>

   <p><b>Yes</b> - Activates full inventory control to keep track of the number of items currently in stock. (To change the setting, clear the Use Config Settings checkbox and select “Yes.”)</p>

   <p><b>No</b> - Does not keep track of the number of items currently in stock. (This is the default setting.)</p>

        <h3>Backorders</h3>
        <p>Determines how your store manages backorders. A backorder does not change the processing status of the order. Funds are still authorized or captured immediately when the order is placed, regardless of whether the product is in stock. When the product becomes available, it will be shipped. Options include:</p>
        <p><b>No Backorders</b> - Does not accept backorders when product is out of stock</p>
        <p><b>Allow Qty Below 0</b> - Accepts backorders when the quantity falls below zero.</p>
        <p><b>Allow Qty Below 0 and Notify Customer</b> - Accepts backorders when the quantity falls below zero, but notifies customers that orders can still be placed. </p>







<?php

}


// for getting data:
function getChildCategories($category, $isFirst = false) {

        // If this is the first invocation, we just want to iterate through the top level categories, otherwise fetch the children
        $children = $isFirst ? $category : $category->getChildren();

        // For each category, fetch its children recursively
        foreach ($children as $child) {
                $_categories[] = [ "name" => $child->getName(), "id" => $child->getId(), "children" => getChildCategories($child) ];
        }

        // Return our tree
        return $_categories;
};

// for rendering:
function renderCategoriesTree($category, $isFirst = false) {

        // If this is the first invocation, we just want to iterate through the top level categories, otherwise fetch the children
        $children = $isFirst ? $category : $category->getChildren();
        echo "<ul>";
        // For each category, fetch its children recursively
        foreach ($children as $child) {
                echo "<li>"; echo $child->getName(); echo "</li>";
                renderCategoriesTree($child);
        }
        echo "</ul>";
}

function fnListHierarchy()
{

  // Example Usage:
  $_categories = Mage::helper('catalog/category')->getStoreCategories();

  // var_dump this to see an associative array of all categories
  $categories = getChildCategories($_categories, true);

  // Run this to echo out a DOM
  renderCategoriesTree($_categories, true);

}