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 24, 2009

HOWTO: Self-Signed SSL on IIS in Vista

Author: gaweee | Filed under: development, howto

Yes it can be done, no its not hard at all, no you dont have to download any weird sharewares and no it doesnt cost a cent. Lets go!

  1. Download the SelfSSL from microsoft downloads
  2. Install it, duh.
  3. Assuming you installed it where its supposed to be, go to C:\Program Files\IIS Resources\SelfSSL and run selfssl.exe
  4. Agree to it installing the certificate for you and press Y
  5. Open your IIS Manager > Sites
  6. Right click on the Default Web Site and choose Edit Bindings
  7. Add
  8. Select type as https and select the certificate you just installed.
  9. Done

Viola!

This adds the certificate for only a puny 7 days. If you’re like us, you’ll probably need a cert for a much longer period than that. No problem!
Fire up your command prompt and cd to C:\Program Files\IIS Resources\SelfSS\
type the following:

selfssl.exe /V:3650 /t

That’ll give you a nice cert for 10 years.
But wait, you’re original cert is still there! Wel’ll have to remove it.

  1. Start->Run->mmc.exe
  2. File -> Add/Remove Snap-in
  3. Certificates (on the left column)
  4. OK
  5. Navigate the tree to: Certificates -> Personal -> Certificates
  6. Delete the original SSL cert you created (see the expiration date differences)
  7. Follow the above instructions in customizing your IIS to the new cert now. =D

Note: This is used for development purposes and the certificates will be recognized as invalid for that domain. Go ahead and add the security exception in Firefox, IE, Chrome or whatever other browsers you’re using.

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

Feb 8, 2009

HOWTO: IE6 testing environment on Vista

Author: gaweee | Filed under: development, howto

Lets cut through the chase, theres no way to install IE6 on vista but you can boot it off an image (which seems to be the most popular choice anyway), even if other sites teaches you registry hacks and etc, there are still differences between the real IE6 rendering versus the emulated/hacked version. But, what you can do is to install the Virtual PC with IE6 + XP SP3 Virtual Hard Disk.

Once you’ve downloaded both and installed the Virtual PC, run it. Then:
File > New Virtual Machine Wizard

  1. Create a virtual machine
  2. Choose some location of your preference
  3. Choose Windows XP for your operating system
  4. Use the recommended RAM (of if you can spare it, adjust it more or less to your preference)
  5. Use an existing Virtual Hard Disk
  6. Choose the downloaded IE6 + XPSP3 .vhd image
  7. Finish

When ready, click Start on the virtual image and viola!

Note:

  • The .vhd image always expires 3 months as of download, this is to prevent ppl from just living off an image (since i gather the image can be run off other operating systems too)
  • Go to Settings > Networking and choose the active network controller to give the IE6 image networking capabilities
  • If you’ve been developing your website on localhost, then you cannot access http://localhost/project on your IE6 anymore as thats is resolved internally. Instead use your main computer’s IP. In my case, http://192.168.1.1/project

Windows XP booting via Virtual PC  IE6 running on Virtual PC

Feb 7, 2009

HOWTO: PHP image resize, centered and cropped

Author: gaweee | Filed under: development, howto

Sorry for not posting in such a long time folks, i just came back from the Pegasus galaxy. While working on a Joomla! 1.5 project, we had to develop a function to crop and resize images for obvious content management and aesthetic reasons. So i gathered around some good sources on PHP.net and wrote the following class:

class ImageHelper {
 
	static function treatFilename($filename) {
		$newfilename = strtolower($filename);
		$newfilename = str_replace(" ","_",$newfilename);
		return $newfilename;
	}
 
	static function isPotrait($srcimage) {
		if (!file_exists(realpath($srcimage)))
			return;
 
		return !ImageHelper::isLandscape($srcimage);
	}
 
	static function isLandscape($srcimage) {
		if (!file_exists(realpath($srcimage)))
			return;
 
		$size	= getimagesize( $srcimage );
		return ($size[0] > $size[1]);
	}
 
	static function resizeImage($srcimage, $destimage, $width, $height) {
		if (!file_exists(realpath($srcimage)))
			return;
 
		$srcpathinfo 	= pathinfo($srcimage);
		$srcext 		= strtolower($srcpathinfo['extension']);
		$destpathinfo 	= pathinfo($destimage);
		$destext 		= strtolower($destpathinfo['extension']);
		$size 			= getimagesize( $srcimage );				// Get the size of the original image into an array [0]=> width, [1]=> height
		$image			= null;
		$canvas 		= imagecreatetruecolor( $width, $height );	// Prepare canvas
 
		// Create a new image in the memory from the file 
		switch ($srcext) { 
			case 'wbmp':
			case 'bmp':
				$image = imagecreatefromwbmp($srcimage);
				break;
			case 'jpg':
			case 'jpeg':
				$image = imagecreatefromjpeg($srcimage);
				break;
			case 'png':
				$image = imagecreatefrompng($srcimage);
				break;
			case 'gif':
				$image = imagecreatefromgif($srcimage);
				break;
			case 'xpm':
				$image = imagecreatefromxpm($srcimage);
				break;
			default:
				return;
		}
 
		// Calculate dimensions
		$widthratio		= $size[0]/$width;
		$heightratio	= $size[1]/$height;
		$dimensions 	= array(
						'ratio' 			=> $widthratio,
						'source_cropwidth' 	=> 0,
						'source_cropheight' => 0,
						'source_offsetx' 	=> 0,
						'source_offsety' 	=> 0
						);
 
		if ($heightratio < $widthratio)
			$dimensions['ratio'] 			= $heightratio;
 
		// let say image is 1200*800, then:
		// widthratio = 1200/400 = 3
		// heightratio = 800/300 = 2.66
		// since there is less height than width, the max scale we can do is 2.66, then
		// the targetwidth to crop = 400 * 2.66
		// the targetheight to crop = 300 * 2.66
		// the offset width = (1200 - (2.66 * 400))/2 = 68
		// the offset height = (800 - (2.66 * 300))/2 = 1
 
		$dimensions['source_width'] 		= $size[0];
		$dimensions['source_height'] 		= $size[1];
		$dimensions['source_cropwidth'] 	= $width * $dimensions['ratio'];
		$dimensions['source_cropheight'] 	= $height * $dimensions['ratio'];
		$dimensions['source_offsetx'] 		= ($size[0] - $dimensions['source_cropwidth']) / 2;
		$dimensions['source_offsety'] 		= ($size[1] - $dimensions['source_cropheight']) / 2;
 
		imagecopyresampled($canvas, $image, 0, 0, $dimensions['source_offsetx'], $dimensions['source_offsety'], $width, $height, $dimensions['source_cropwidth'], $dimensions['source_cropheight']);
 
		switch ($destext) {
			case 'jpg':
			case 'jpeg':
				imagejpeg( $canvas, $destimage );
				break;
			case 'png':
				imagepng( $canvas, $destimage );
				break;
			case 'gif':
				imagegif( $canvas, $destimage );
				break;
			case 'wbmp':
			case 'bmp':
				imagewbmp( $canvas, $destimage );
				break;
		}
 
		imagedestroy( $canvas );
		imagedestroy( $image );
 
		return true;
	}
}
use treatFilename to remove those pesky spaces, then use isPotrait or isLandscape to determine the orientation of the picture, then perform your resize accordingly. If your uploaded file input was called ulimage, then the code to resize your image would be:

	$width 		= 150;
	$height 		= 150;
	if (is_uploaded_file(@$_FILES['ulimage']['tmp_name'])){
		$targetfilename	= ImageHelper::treatFilename(uniqid() . "_" . $_FILES['ulimage']['name']);
		move_uploaded_file($_FILES['ulimage']['tmp_name'], dirname(__FILE__) . "/tmp/" . $_FILES['ulimage']['name']);
		ImageHelper::resizeImage(dirname(__FILE__) . "/tmp/" . @$_FILES['ulimage']['name'], dirname(__FILE__) . "/tmp/" . $targetfilename, $width, $height);
	}

The reason you need to save the file first is for the imageResize function to infer the image type off its extension. I hadnt bothered to create an image type override. :D

Get the source here: ImageHelper.php
or view the demo here
Sep 1, 2008

EXTJS themed file input field

Author: gaweee | Filed under: Uncategorized

Theming a file input field has always been notoriously hard. Thanks to the guys who wrote the Ext UploadDialog script, theres now a better and more aesthetically pleasing way to create a file upload. I tried using their script wholesale but ran into some problems with the layout. So i kinda hacked and extracted their Ext.ux.BrowseButton code.

So now you can use it simply with:

	new Ext.ux.BrowseButton({
		input_name: "uploadfile1",
		text: "Select a file"
		onInputFileChange: function() {
			alert("you chose " + this.getInputFile().dom.value);
		}
	})
 
	new Ext.ux.TBBrowseButton({
		input_name: "uploadfile2",
		text: "Select another file"
	})

The first chunk of code creates a Browse Button (File Input) control as with the name uploadfile1. and the second chunk of codes creates a ToolBar Browse Button with the name uploadfile2.

Hypothetically you should be able to add a ToolBar button but i havent quite gotten a ToolBar Browse Button to fit aesthetically well inside a form. Let me know if you all come up with any examples that do!

Meanwhile, 3 cheers for the guys who wrote the Ext UploadDialog script!!!

Download the jQuery progressbar here: EXT Browse Button
or view the demo here

Jun 23, 2008

HOWTO: struts 2 i18n

Author: gaweee | Filed under: development, howto

i18n in struts is really flexible if set up correctly. Unfortunately searching for a document to learn the ‘hidden’ tricks of it is really frustrating… So in revenge, i’m writing my own! I hope someone out there finds this useful…

Step 1: Edit your struts.properties file – Add/Edit the following line:

struts.custom.i18n.resources=languages_actions,languages_views

This definition instructs struts to use the files languages_actions.properties and languages_view.properties for your language definitions. When there is a new request locale, such as zh_CN (chinese), struts will find for the file languages_actions_zh_CN.properties, or if defaults to en_US (english), struts will use the file language_actions_en_US.properties.
On top of that, there can be many places where language definitions can be found. They will be searched in the following order:

  1. ActionClass.properties
  2. BaseClass.properties (all the way to Object.properties)
  3. Interface.properties (every interface and sub-interface)
  4. ModelDriven’s model (if implements ModelDriven), for the model object repeat from 1
  5. package.properties (of the directory where class is located and every parent directory all the way to the root directory)
  6. search up the i18n message key hierarchy itself
  7. global resource properties

I put my files in the main WEB-INF\classes folder where struts.properties can be found
Read here for more information on how struts 2 searches for i18n definitions.

Step 2: Writing the language file itself

user.submit.image=/images/en_US/submit.gif
user.welcome=Welcome, {0}
user.link=<a href="somelink.action?id={1}&amp;token={2}">{0}</a>' document
user.validation.token.invalid={0} does not exists in the system

the above is an example of a en_US language definition file. You can see how the image and welcome message would be different in a zh_CN language definition file. but just for the heck of it, here it is anyway

user.submit.image=/images/zh_CN/submit.gif
user.welcome={0}, 你好
user.link=<a href="somelink.action?id={1}&amp;token={2}">{0}</a> 的文件
user.validation.token.invalid={0} 不纯在于系统

The key here in flexibility is the use of # parameters for the definitions (very printf-ish). This allows the dynamic data to be reformatted to any language structure (left to right, right to left, orientation of grammer, verbs, subject, topics, etc). Really smart way to do it!

Step 3: Using the definitions:
in JSP,

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<h1><s:text name="user.welcome">
	<s:param value="user.name" />
</s:text></h1>
<s:text name="user.link">
	<s:param value="document.name" />
	<s:param value="document.id" />
	<s:param value="document.token" />
</s:text>
<form input="">
	<s:submit type="image" src="%{getText('user.submit.image')}" cssClass="submit" />
</form>

Or in Java,

public class SomeActions extends ActionSupport {
	public String someMethod() throws Exception {
		if (!token.equalsIgnoreCase("abcdefghi")) {
			String [] messageargs = { token };
			addActionError(getText("user.validation.token.invlaid", messageargs));
		}
	}
 
	private String token;
	public String getToken() 	{ return  token; }
	public void setToken(String s) 	{ token = s; }
}

The above examples goes to show how you can combine dynamic data with the i18n strings in a JSP or a Java file

Tips

  • When using a utf8 language definition file (such as for zh_CN), you have to write out your files then run it through the native2ascii program. On windows it would look like this:
    "c:\Program Files\Java\jdk1.6.0_04\bin\native2ascii.exe" -encoding UTF8 \path\to\zh_CN.locale \new\path\to\languages_actions_zh_CN.properties

    Change your jdk\bin directory to where appropriate

  • Flood HTML with s:text language definitions – If you’ve already decided to make your app internationalized, its a big step, so make sure everything is pulled off a dynamic language pack.
  • Always use the s:date taglib to represent date, save yourself all the time (and frustration) in the world
  • Set up your default language definition file first. Struts makes it such that if your definition doesn’t exists then it searches the default file for it. That is to say if your definition for user.link doesn’t exists in languages_actions_zh_CN.properties, struts will continue to find for it in languages_actions.properties so at least there will be a link there, even if its untranslated.
Jun 20, 2008

JQuery Progress Bar 1.1

Author: gaweee | Filed under: development
jQuery progressBar screenshot

This code has been downloaded quite abit so i thought i’d put in some effort to improve it. I found some free time this evening to clean up the code. The original code is a couple of months old and its my first jquery plugin. I didnt quite understand what i was doing then.I made the code less resource intensive and more configurable.

The progress bar can now be controlled externally. click on the demo link below to see what i’m talking about. I’ll know of at least 1 bug in the script if its fully tested, will try to fix this within the week. Meanwhile if you have any ideas for improvements, please leave a comment!


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

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

JQuery Progress Bar v1.0

Author: gaweee | Filed under: development
jQuery progressBar screenshot

I really liked the mootools progressbar at http://www.webappers.com/progressBar/ but i’m so against the idea of having 2-3 libraries in a single system. Since i always use jQuery, i tried to port the progressBar over. The problem is, jQuery unlike most of the other libraries doesnt quite work with objects. So its not that easy to return and manage an object to perform actions like “add 5%”, “fill to 95%”, etc. Honestly i’m not sure where else to use such a comprehensive progress bar other than a file upload utility.

So for what its worth, i made a simple progress bar in jQuery that parses a percentage string and animates the loading.

Download the jQuery progressbar here: jQuery progressbar
Or view the demo: here