Download the source for this entire series here!

Create the administrative complement

Next we’ll create the administration controller and configuration to achieve the https://127.0.0.1/magento/index.php/twits/admin reservation. This took me a long time to figure out how to do nicely.

  1. We’ll begin by updating the adding 2 new files (controller and helper) for the purpose of the Hello world in the admin site
    app/
      etc/
        modules/
          - SavantDegrees_All.xml (Or what ever your company name might be)
      code/
        local/
          SavantDegrees/ (Or what ever your company name might be)
            Twits/ (Or whatever your module name might be)
              Block/
                - HelloWorld.php
              controllers/
                - AdminController.php
                - IndexController.php
              etc/
                - config.xml
              Helper/
                - Data.php
  2. Then we obviously create the adminController.php
    We’ll make the admin page reuse the same Hello world block that we’ve created in Phase 1.

    <?php
    class SavantDegrees_Twits_AdminController extends Mage_Adminhtml_Controller_Action
    {
        public function indexAction()
        {
    		$this->loadLayout()
    			->_addContent($this->getLayout()->createBlock('twits/helloWorld'))
    			->renderLayout();
        }
    }

    Note that this controller extends Mage_Adminhtml_Controller_Action instead. This enforces security and loads the admin layout for this controller instead of the frontend version. With this done, you can now visit https://127.0.0.1/magento/index.php/twits/admin to see the page in action. Again, this produces our ubiquitous Hello world. You’d probably figured out by now that /twits refers to our frontend controller reservation by our config.xml and then /admin refers to the adminController that we’ve just created. Now you can try https://127.0.0.1/magento/index.php/twits/admin/index to see the indexAction method being called. Try it with other action names!

  3. Next we’ll do the config.xml magic that allows us to use https://127.0.0.1/magento/index.php/admin/twits for the administration.
    <?xml version="1.0"?>
    <config>
        <modules>
            <SavantDegrees_Twits>
                <version>0.1.0</version>
            </SavantDegrees_Twits>
        </modules>
        <global>
             <helpers>
                <twits><class>SavantDegrees_Twits_Helper</class></twits>
            </helpers>
    	<blocks>
                <twits>
                    <class>SavantDegrees_Twits_Block</class>
                </twits>
            </blocks>
        </global>
        <adminhtml>
            <menu>
                <twits translate="title" module="twits">
                    <title>Twits</title>
                    <sort_order>100</sort_order>
                    <action>twits/admin</action>
                </twits>
            </menu>
        </adminhtml>
        <frontend>
            <routers>
                <SavantDegrees_Twits>
                    <use>standard</use>
                    <args>
                        <module>SavantDegrees_Twits</module>
                        <frontName>twits</frontName>
                    </args>
                </SavantDegrees_Twits>
            </routers>
        </frontend>
    </config>

    What’ changed?

    • The global > helper > [module] fragment defines the helper class that will help our future translation. We’ll be seeing the code for that shortly.
    • The adminhtml > menu > [module] fragment allows us to create the menu to access the twits/admin page. This is vital for version 1.3 onwards as the menu generates the necessary url key to access the page.
  4. And finally the helper Data.php file
    <?php
    class SavantDegrees_Twits_Helper_Data extends Mage_Core_Helper_Abstract
    {
    }

    Why bother? Its a quirk of Magento to try to translate the menu. So we NEED this helper. Otherwise Magento goes looking for a Mage_Twits_Helper_Data class. Which obviously doesnt exist! You could use the helper from existing Magento classes, but then you could use ALOT of stuff from Magento classes. And if you’re reading this tutorial, you’re obviously arent ready.

  5. When you’re done, go flush the cache by accessing System > Cache Management > Flush Magento Cache in the admin system. Then check out the new Twit menu item in the administration menu bar!

» Moving along … Part 3 – Database

Magento needs no explaning, but it does need a shitload of proper developers education. So much that our team spent a good amount of time trying to learn how to develop on the damn thing. So heres a synthesized description of our efforts. We’re breaking up this HOWTO into a few segments into increasing orders of complexity and integration.

Download the source for this entire series here!

Let us begin …

Setup Module Environment and Helloworld

We’re trying to achieve a proof of concept here to describe how the file structure, namespaces and config files interplay to achieve a Hello world message

  1. Create your directory structure! Our NEW company name is Savant Degrees! and our module shall be called….. Twits (for a lack of an imagination). The whole module (well, almost) should rest in the /app/code/local> folder. So lets first create the following folder structure. For a hello world module, you only need a config file, a controller and a block. Ergo…
    app/
      etc/
        modules/
          - SavantDegrees_All.xml (Or what ever your company name might be)
      code/
        local/
          SavantDegrees/ (Or what ever your company name might be)
            Twits/ (Or whatever your module name might be)
              Block/
                - HelloWorld.php
              controllers/
                - IndexController.php
              etc/
                - config.xml
  2. Create your config.xml file. Thats the crux of the whole module.
    <?xml version="1.0"?>
    <config>
        <modules>
            <SavantDegrees_Twits>
                <version>0.1.0</version>
            </SavantDegrees_Twits>
        </modules>
        <global>
            <blocks>
                <twits>
                    <class>SavantDegrees_Twits_Block</class>
                </twits>
            </blocks>
        </global>
        <frontend>
            <routers>
                <SavantDegrees_Twits>
                    <use>standard</use>
                    <args>
                        <module>SavantDegrees_Twits</module>
                        <frontName>twits</frontName>
                    </args>
                </SavantDegrees_Twits>
            </routers>
        </frontend>
    </config>

    Let me explain this step a little…

    The modules > [module] > version number allows Magento to track when your module is upgraded. We’ll be seeing a version of that shortly.
    The global > blocks > [module] define the Block resources that are available under your package. We’ll be using this to generate a Hello world shortly
    The frontend > routers fragment define how the module can be access. The current code allows the block to be access via https://127.0.0.1/magento/index.php/twits

  3. Create your IndexController.php file. Its as simple as:
    class SavantDegrees_Twits_IndexController extends Mage_Core_Controller_Front_Action
    {
     
        public function indexAction()
        {
    	$this->loadLayout();
    	$this->getLayout()
    		->getBlock('content')->append(
    			$this->getLayout()->createBlock('twits/helloWorld')
        	);
            $this->renderLayout();
        }
    }

    More Explanation: The twits/index refers to the index block inside the Twits module, which is defined in the config file above. We’re trying to put its contents inside the layout.

  4. Lastly, we’ll create the Index.php Block:
    class SavantDegrees_Twits_Block_HelloWorld extends Mage_Core_Block_Template
    {
    	protected function _toHtml()
    	{
    		return 'Hello world';
    	}
    }

    You DO understand SOME PHP don’t you?

  5. Finally, we activate the module by creating the file SavantDegrees_All.xml file
    <?xml version="1.0"?>
    <config>
        <modules>
            <SavantDegrees_Twits>
                <active>true</active>
                <codePool>local</codePool>
            </SavantDegrees_Twits>
        </modules>
    </config>
  6. Wake up the Magento installer by logging into the admin backend, System > Configuration > Advanced > Advanced. Click on Save Config. Clear your cache at /var/cache too just to be sure.

Tada! Navigate to https://127.0.0.1/magento/index.php/twits to see your well deserved Hello World!

» Next … Part 2 – Admin Controller

Feb 11, 2009

JQuery Progress Bar 1.2

Author: gaweee | Filed under: development, howto
jQuery progressBar screenshot

Thanks for all the comments and feedback! By popular request i’ve added the multi-colored progress bar and fixed some bugs. The new multi-colored bar changes from red to orange and then to green at configurable intervals. Check out the demo!

Since the last update this endeavour has seen comments claiming that it works and sometimes that it doesnt. I’ve tested the demo across Safari, Opera, IE6/7, Firefox and Chrome. Havent found any problem. For those of you who have problems, please do email me the problem.

Download the new jQuery progressbar here: jQuery progressbar
or view the demo here

Jun 18, 2008

HOWTO: Scheduled Remote MySQL Backups

Author: gaweee | Filed under: development, howto

If you have more access to more than 1 server, a good idea would be to schedule remote backups using a small script and crontab. This way, if 1 server goes down at least SOME data still resides on another. (a friend’s hosting service got prematurely terminted recently because someone else sharing a hosting plan was serving illegal content and the whole system was confiscated by the police in that country!)

of course backing up mysql is the only thing you can do, unless you’ve way too much disk space and way too much bandwidth… in that case please consult a professional on the actual 1001 ways to throw money at redundancy.

The script will first run remote commands on the target server over ssh to dump and gzip the database into a file. The file is then downloaded to the backup server. A final ssh command removes the dump file from the target server. Viola! And here is the shell script…

ssh root@wits.sg 'mysqldump -uroot twits> /tmp/twits.backup.sql && bzip2 -9 /tmp/twits.backup.sql'
scp root@wits.sg:/tmp/twits.backup.sql.bz2 /var/backups/twits/`date "+%Y%m%d-%H%M"`.sql.bz2
ssh root@wits.sg 'rm /tmp/twits.backup.sql.bz2'

Save this few lines to a file on the backup server and give it execute permissions! (I saved it at /root/twits_backup.sh)
Note: Passwordless logins between the 2 servers must have been setup prior to running this script. Otherwise scp and ssh commands will both be prompted for a password.

Next set up the cron job on the backup server to run the script

30 05 * * * /root/twits_backup.sh

This sets the script to run at 5:30am everyday.
Here is a good place to read up more on cron jobs.

Jun 17, 2008

HOWTO: Did you mean…

Author: gaweee | Filed under: development, howto

I always thought it was really cool to have those “Did you mean <some other spelling corrected word>”? Took me long enough to finally chance upon how it works! Basically it uses sound functions: soundex, metaphone or levenshtein distance to match words.

Different database supports different possible implementations of the functions. A sample mySQL query would look like:

SELECT `name` FROM `organizations` WHERE SOUNDEX(`name`) = SOUNDEX('dog');

I’ve also seen some mysql stored procs that hack in a levenshtein distance calculation algorithm. This allows a even more dynamic and accurate match. Unfortunately, i’ve never gotten it to work. Do let me know if anyone has succeeded.

Jun 17, 2008

HOWTO: Fix EXTJS Textarea for IE6

Author: gaweee | Filed under: development, howto

I encountered a interesting display bug when working with EXTJS recently. The following code renders well in FF 2 and above but not in IE6.

var form = new Ext.form.FormPanel({
	baseCls: 'x-plain',
	labelWidth: 140,
	url: 'abc/def.php',
	defaultType: 'textfield',
	items: [{
		fieldLabel: 'Name',
		name: 'name',
		anchor:'100%'  // anchor width by percentage
	}, {
		xtype: 'textarea',
		fieldLabel: 'Description',
		name: 'description',
		anchor: '100% -30'  // bug in IE6
	}]
});
 
var window = new Ext.Window({
	title: 'Some Window',
	width: 500, height: 300, 
	layout: 'fit',
	plain: true,
	buttonAlign: 'center',
	items: form
});
 
window.show();

brian.moeskau from the EXTJS forums was kind enough to answer this problem. The fix is a piece of code that primes the width of the controls to prevent it from overflowing out of the window/panels. The code is as follows

Ext.override(Ext.form.Field, {
    adjustWidth : function(tag, w){
        tag = tag.toLowerCase();
        if(typeof w == 'number' && !Ext.isSafari){
            if(Ext.isIE && (tag == 'input' || tag == 'textarea')){
                if(!Ext.isStrict){
                    return this.inEditor ? w : w - 3;
                }
                if(tag == 'input' && Ext.isStrict){
                    return w - (Ext.isIE6 ? 4 : 1);
                }
                if(tag == 'textarea' && Ext.isStrict){
                    return w-4;
                }
            }else if(Ext.isOpera && Ext.isStrict){
                if(tag == 'input'){
                    return w + 2;
                }
                if(tag == 'textarea'){
                    return w-2;
                }
            }
        }
        return w;
    }
});

I hope this will solve other people’s problems too!

Jun 17, 2008

HOWTO: Codeigniter, IIS and ISAPI_Rewrite

Author: gaweee | Filed under: development, howto

Pretty URLs on IIS is possible. Not so much to make it pretty but to make it convenient when testing your system. Its really simple too!

Step 1 – Install ISAPI_Rewrite from Helicon
Step 2 – Configure your ISAPI_Rewrite httpd.ini
below is my configuration for a codeigniter virtual directory called firingrange

RewriteRule ^/firingrange/(images|css|files|js)(.*)$ /firingrange/webroot/$1$2 [L]
RewriteRule ^/firingrange/$ /firingrange/index.php [L]
RewriteRule ^/firingrange/index.php$ /firingrange/index.php [L]
RewriteRule ^/firingrange/index.php?(.*)$ /firingrange/index.php?$1 [L]
RewriteRule ^/firingrange/(\w+).php$ /firingrange/webroot/($1).php [L]
RewriteRule ^/firingrange/(.+)\?(.*)$ /firingrange/index.php?$1&amp;$2 [L]
RewriteRule ^/firingrange/(.*)$ /firingrange/index.php?$1 [L]

Just like the mod_rewrite HOWTO, I threw all my static files into webroot folder so that you can access the site via http://t.wits.g/images/myimage.jpg easily. Same goes for css and js.

Jun 15, 2008

HOWTO: Passwordless logins between servers

Author: gaweee | Filed under: development, howto
Before i get into this HOWTO, its worth noting that the use of passwordless logins can be really dangerous when it applies on an organizational level. Some organizations do not have any operating procedures in place to remove inactive employee accounts much less bother to check for ssh authorized keys. That being said, i’ve found this technique tremendously useful in creating backup server relations between one or more servers.
So if you’ve properly weighted your pros and cons, here we go…
Step 1 – generate your RSA/DSA keypair

gaweee@wits:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/gaweee/.ssh/id_rsa): [enter]
Enter passphrase (empty for no passphrase): [enter]
Enter same passphrase again: [enter]
Your identification has been saved in /home/gaweee/.ssh/id_rsa.
Your public key has been saved in /home/gaweee/.ssh/id_rsa.pub.
The key fingerprint is:
2c:1f:fb:f0:ae:2b:88:99:60:ee:eb:a5:83:3c:3c:c4 gaweee@wits

Why? Distribution of these keys is crucial to logging into the remote server without having to key in your password.
The 2 files created: /home/gaweee/.ssh/id_rsa and /home/gaweee/.ssh/id_rsa.pub are your private and public keys respectively. Keep your private key to yourself ONLY.

Step 2 – Distribute the public key to target servers

gaweee@wits:~$ scp .ssh/id_rsa.pub somenewserver:.ssh/authorized_keys
gaweee@somenewserver password: [password]

this uses scp to put the public key onto the new server’s authorized_keys.
Viola! and you’re done!

Jun 15, 2008

HOWTO: Migrate your svn repository between servers

Author: gaweee | Filed under: development, howto
Step 1 – Backup your svn data:

svnadmin dump /path/to/somerepository &lt; somerespositry.svn.backup

The resulting file can be pretty large. Its basically a file of all your snapshots. Needless to say, if you’re at revision 300, be prepared to wait.

Step 2 – Create the new respository:
login to the new server to create the repository

svnadmin create /path/to/newrespository

Double check the created directory structure where possible, many a times my svn folders arent created with the correct group write permissions. So remote commits encounters transaction errors

Step 3 – Restore the repository on the new server

svnadmin load /path/to/newrepository < somerepository.svn.backup

And you’re done! really simple wasnt it?

Jun 13, 2008

HOWTO: Codeigniter and mod_rewrite

Author: gaweee | Filed under: development, howto

I cant remember the last time i got mod_rewrite to just work. I think i know regex, i think i know how http request works, i think i know some mod_rewrite. I try. For sure it breaks. This is undeniable proof that good things ONLY come to those who sweat and strain their necks…

The following is my mod_rewrite ruleset for codeigniter

Options +FollowSymlinks
RewriteEngine on
 
RewriteCond %{REQUEST_URI} (index\.php|webroot/|images/|css/|js/|robots\.txt|favicon\.ico)
RewriteRule ^(images|css|files|js)/(.*)$ webroot/$1/$2 [L]
RewriteRule ^(favicon\.ico)$ webroot/$1 [L]
 
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

I threw all my static files into webroot folder so that you can access the site via http://t.wits.g/images/myimage.jpg easily. Same goes for css and js.
So now you can access your controllers through the preferred pretty url: http://t.wits.sg/welcome
I’ll go hack the router.php file someday when i’m free enough so that it can accept GET requests too.

Recent Comments