In this article, hopefully, you will learn how to create a module that uses its own controller, programatically creates a block based on core template and assigned via file, handles form submission and utilizes Magento notification system to output the notifications to user.
Although the module it self might look relatively simple in the end, keep in mind that these are powerful concepts that you can latter reuse for much more complex requirements.
file 1:
/app/etc/modules/Inchoo_SimpleContact.xml
content of file 1:
<?xml version="1.0"?> <config> <modules> <Inchoo_SimpleContact> <active>true</active> <codePool>local</codePool> </Inchoo_SimpleContact> </modules> </config>
file 2: app/code/local/Inchoo/SimpleContact/etc/config.xml
content of file 2:
<?xml version="1.0"?> <config> <modules> <Inchoo_SimpleContact> <version>0.1.0</version> </Inchoo_SimpleContact> </modules> <frontend> <routers> <JustSomeFreeRouterNameHereNo1> <use>standard</use> <args> <module>Inchoo_SimpleContact</module> <frontName>inchoo-simplecontact</frontName> </args> </JustSomeFreeRouterNameHereNo1> </routers> </frontend> </config>
As we dissect our module, the first thing that pops up is the “frontend” element. We can see it has lot of sub-elements of which “routers” is first. In order for something in Magento to be accessible on certain url, that something needs to have controller, like all Zend powered applications. Unlike pure Zend apps, Magento has its own way of mapping controllers, trough xml definitions.
I intentionally used “JustSomeFreeRouterNameHereNo1″ for element name making it self explanatory. You can freely assign name to a router wheres “use” and “args” are two parameters each router should have. Parametar “module” if the full name of your module and “frontName” is the actual url path trough which you acccess your controller. In example above I would access my controller indexAction() method trough url like http://shop.local/index.php/inchoo-simplecontact/index/ or http://shop.local/index.php/inchoo-simplecontact/. In case we have url rewrite set up we can even access it by omitting the “index.php” part from url.
Now we will look into the content of IndexController.php.
file 3: app/code/local/Inchoo/SimpleContact/controllers/IndexController.php
content of file 3:
<?php class Inchoo_SimpleContact_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { //Get current layout state $this->loadLayout(); $block = $this->getLayout()->createBlock( 'Mage_Core_Block_Template', 'inchoo.simple_contact', array( 'template' => 'inchoo/simple_contact.phtml' ) ); $this->getLayout()->getBlock('content')->append($block); //$this->getLayout()->getBlock('right')->insert($block, 'catalog.compare.sidebar', true); $this->_initLayoutMessages('core/session'); $this->renderLayout(); } public function sendemailAction() { //Fetch submited params $params = $this->getRequest()->getParams(); $mail = new Zend_Mail(); $mail->setBodyText($params['comment']); $mail->setFrom($params['email'], $params['name']); $mail->addTo('somebody_else@example.com', 'Some Recipient'); $mail->setSubject('Test Inchoo_SimpleContact Module for Magento'); try { $mail->send(); } catch(Exception $ex) { Mage::getSingleton('core/session')->addError('Unable to send email. Sample of a custom notification error from Inchoo_SimpleContact.'); } //Redirect back to index action of (this) inchoo-simplecontact controller $this->_redirect('inchoo-simplecontact/'); } } ?>
Above file, although simple, demonstrates two powerful concepts. First we have an example of creating a block “on the fly”. There are several ways one can add an output block to be shown in Magento, this is the “hardest” way. Most of the materials you will find on the web will show you how to do it from xml files. However, I want you to know how to do it from code.
There is one important reason why you should now how to do this from code: Simplicity! If you were to output the block from layout files then you are adding at leas one more file to your module. The more files you have in your module, bigger the chance for bugs. This is really something you should consider and keep in mind for modules who actually require controllers and are not very user centric.
When I say “not very user centric” I think in terms where designer needs to have full control of layout and the way it is arranged. However in cases where not much layout modifications will be required on custom made controller output I believe that “saving yourself” from writing another layout file is the right way to go.
Note that inside the method call createBlock i use ‘Mage_Core_Block_Template’ as one of the parameters. This is the block class. In this example core block template is used. However, you can freely use one of your own declared blocks (will be shown in latter modules). Created block is appended (inserted actualy) in existing block named “content”. Block “content” is one that is almost always present in the output.
Inside the sendemailAction method we have another important concept, the notification system example. Catch exception block triggers the “adding in the notification message” to the session storage. There are few different storage mechanism inside the Magento. Most of them simply extend core/session without any noticeable diference, therefore unles you wish to extend the existing and write your own, you can use the Mage::getSingleton(‘core/session’). You can use 4 diferent types of notification messages: error, warning, notice, success. Which you can call respectively like trough methods addError(’Custom error here’), addWarning(’Custom warning here’), addNotice(’Custom notice here’), addSuccess(’Custom success here’) as shown above.
Any notifications added to ‘core/session’ storage are outputted to frontend trough view files. For instance one such example is app/design/frontend/default/default/template/page/3columns.phtml file. Inside the file there is the < ?php echo $this->getChildHtml(‘global_messages’) ?> line of code that outputs all global notifications. Note that the “global_messages” referes to block name from within the page.xml layout file, which in turn referes to Magento “core/messages” (Mage_Core_Block_Messages) class type.
Final file for our module is the view file itself. As you might notice from the IndexController, we are using the ‘inchoo/simple_contact.phtml’ as one of the parameters passed to createBlock method. What this means is that our module is going to look for app/design/frontend/default/default/template/inchoo/simple_contact.phtml file. Note that if we were to assign diferent template then “default” to be used for our site then ‘inchoo/simple_contact.phtml’ would refer to folder and file from within that template. If that file is not find in this “other” template then the system would look for one in default template.
file 4: app/design/frontend/default/default/template/inchoo/simple_contact.phtml
content of file 4:
<div class="box simple_contact"> <form id="simple_contact_form" name="simple_contact_form" action="<?php echo $this->getUrl('inchoo-simplecontact/') ?>index/sendemail" method="post"> <fieldset class="group-select"> <h4 class="legend">Inchoo_SimpleContact module sample</h4> <ul> <li> <div class="input-box"> <label for="name">Gimme your name <span class="required">*</span></label><br /> <input name="name" id="name" title="Name" value="" class="required-entry input-text" type="text" /> </div> <div class="input-box"> <label for="email">And your email <span class="required">*</span></label><br /> <input name="email" id="email" title="Email" value="" class="required-entry input-text validate-email" type="text" /> </div> <div class="clear"></div> <div class="input-box"> <label for="comment">Some comment?</label><br /> <textarea name="comment" id="comment" title="Comment" class="required-entry input-text" style="height:100px;" cols="50" rows="3"></textarea> </div> </li> </ul> </fieldset> <div class="button-set"> <p class="required">* Required Fields</p> <button class="form-button" type="submit"><span>Submit</span></button> </div> </form> </div>
Content of above file is mostly HTML related so there is not much to talk about it.
That’s it, the end.