Designing and Developing Websites with MAMP and MODx

by Susan Ottwell — Feb 21, 2008

Having a local development environment is an excellent idea. It is not at all difficult these days to install a xAMP stack. By this I mean an Apache web server, a MySQL database, and PHP/Perl. There is XAMPP for Windows and Mac, LAMP for Linux, and MAMP. My preferred development environment is OS X and MAMP.

The MAMP Package

You can download this complete, self-enclosed web development environment from the MAMP website.

After downloading and opening the MAMP .dmg file, simply drag and drop the MAMP folder to your Applications folder. If you like, drag and drop the MAMP dashboard widget into your Library/Widgets folder. No command line, no installation required.

Run the Mamp.app application, and configure the servers to your liking. I always set the Apache and the MySQL port to their defaults rather than the MAMP default. I've already made sure that Personal Web Sharing is turned off in my System Preferences. But if you like, you can have both available by using the MAMP defaults for the Apache and MySQL ports. You'll need to make sure to use those ports in your URLs and your database connections, though.

You can also choose where to have your htdocs folder (your site root) if you don't want it in /Applications/MAMP/htdocs. You could have it in your own user folder if you like. I just leave it where it is, and in the Finder drag the htdocs folder into the left sidebar for quick access.

You can also choose which version of PHP you want to develop for. That is one advanteage to the Dashboard widget; you can quickly switch PHP from 5 to 4 for testing purposes.

Of course, the Pro version has a lot more options, but I find the free version quite sufficient for development purposes.

The MODx CMS

For a few years now my preferred content management system has been the MODx CMS/CMF. For my intermediate level of PHP programming and HTML/CSS design skills it has proven to be a perfect match. I'm not going into installation and configuration of MODx, since it has extensive documentation as well as a Wiki and a very helpful forum community.

The biggest advantage of MODx to the web designer is its simple templating system. Actually, it's not really even a system. You simply use the HTML code for the look you want, as in any flat HTML file, then replace content text and dynamic data (such as menus) with simple tags. Each document is processed to replace those tags within the HTML template with material relevant to that page as the page is requested.

The advantage to the PHP programmer who wants to develop custom dynamic content is the separation of the presentation from the layout using simple tags to include the final return value of your code.

Put together, this makes MODx a perfect framework for Web 20 and AJAX applications. And that brings us to the meat of this article.

Using the Extjs Library

The next version of MODx will be a complete rewrite of the existing application. The back-end management makes extensive use of the Extjs javascript library. I've worked with Javascript and AJAX from raw XMLHttp functions through Prototype, Mootools and JQuery. But I thought that, given my favorite CMS will be using ext, it would be a good idea to get familiar with that library. So when I needed to do a redesign of a client's site that had a plain PHP data view grid, I decided to turn that into a fancy AJAX paging grid with column ordering and a simple search field.

The requirements were that when a user logs in to the site, he is sent automatically to the data viewing page. This is a built-in function of the MODx user validation system, so that was no problem. Second, the data viewed must be filtered by the username of the logged-in user. Third, the data must initially be sorted by an arbitrary field. Then the user must be able to sort the data by the column of his choice. Fourth, the data grid must enable paging, since many of the viewers will have several hundred records of data to view. Fifth, the user must be able to enter a simple word or phrase and view all rows where any of the fields contain that word or phrase.

A basic ext paging grid fulfills three out of the remaining four requirements, with the addition of the initial filtering parameter being so simple that it almost qualifies anyway. I'm no Javascript guru, in fact I frequently wonder why I have anything to do with it at all, but this project turned out to be not so bad.

For the most part, I simply copied the sample paging grid. I only needed to adjust a few things to customize it for my situation. It took a bit of searching through the documentation, and a bit of trial-and-error, but in the end a really nice grid was set up.

Hacking the Paging Grid

There really wasn't much to do to modify the demo Paging Grid to suit my purposes. I simply removed the parts that I obviously would not be using and modified those that I would. The hardest part was digging through the ext API documentation to figure out what parameters were passed to the back-end processing script by the ext AJAX request mechanism.

First, it's important to always set the path to the single-pixel transparent image that is used to format the actual grid generation by the javascript. By default, this is set to the ext site, so you need to set it to wherever you installed your ext library files.

Ext.BLANK_IMAGE_URL = 'js/ext2/resources/images/default/s.gif';

Next, you need to set up the data store object. There are a number of parameters for this object, but most of them work just fine with the defaults for most uses. To see the full set of options for the store object, go to the api documentation, then ext->data->store in the menu on the left.

I just modified the proxy and the reader objects to suit my needs. Since my data resides on the same server as the script, I used the HttpProxy.

proxy: new Ext.data.HttpProxy({
url: 'path/to/processor/processor-script.php'
}),

For the reader, you need to adjust the incoming values to match your data fields. The elements need to match the names you give your array of database rows and the row count in your processing script. The 'id' value is the HTML tag ID that ext will use for the grid for styling and DOM traversal, so it can be whatever you like.

One issue that is not really ext-specific but caused me a few hours of grief is to watch out for the commas ending the parameters. Be very careful not to have a stray comma, especially after the last parameter in each object definition. Internet explorer takes violent exception to extra commas and won't display your grid at all. Commas aren't very big, and IE is not very helpful in its javascript error messages, so it's not always easy to figure out why IE is being so recalcitrant.

Once your data store is set up, the actual grid gets defined. First, establish the layout of your data in the grid by configuring a ColumnModel object. Again, it's not at all difficult to modify the demo grid's column model to fit your data model. The documentation for the grid and column model objects can be found at on the same API page, this time in the ext->grid section.

To make the columns of the grid sortable, you can either specify each column being sortable as you define them in the ColumnModel, or you can set the default sortable status after defining the column model object.

cm.defaultSortable = true;

Setting up the grid itself was a bit more involved. It took some study of the API documentation to understand what all of the options were for, and which ones I wanted enabled and which ones I wanted to disable. Primarily, you need to set 'el' to the HTML element you put in your page's HTML to contain the grid, 'store' to the store object you defined earlier, and 'cm' to the column model object you defined.

The bottom bar (bbar) is of key interest, since it's here that the paging and the search field would be defined. There are a number of bottom bars you can choose; fortunately the demo paging grid comes with the paging bar you want for a paging grid. The bar itself is an object, and has its own entry in the API documentation at ext->util->PagingToolbar. The object has all of the functionality of paging controls built-in, all you need to do is set the parameters, such as how many rows to show at a time, and what to display as information on the right side of the toolbar.

Adding a Search Field

This was the hardest part of the whole process. Actually, it only took me about half an hour to get the basic paging grid working with my data. Adding a button and a field for entering a search word or phrase took another two days.

It turns out to be pretty easy to add things to the bar, it was just a problem in finding out how, and a lot of trial-and-error getting it to work right. Of course, a stray comma as mentioned earlier didn't help, since it was difficult to tell whether it was my attempts to add to the bottom bar that was killing IE or something else altogether.

 

In the end, I finally figured out that all you need to do to add elements to the bottom bar is simply put what you want in the 'items' parameter. To make a long story short, I'll just show the code I ended up using.

items:[
'-',
{text: 'Search', handler:
function(){
grid.store.load({params:{start: 0, limit: 25}});
}
},
{xtype: 'field', id: 'filter', name: 'filter',
autoCreate: {tag: "input", type: "text", size: "20",
autocomplete: "off"}}
]

What this does is first put a hyphen after the paging controls. Then it inserts a default element, a button, and defines the handler function for the button's onclick event. The button's definition doesn't need to be specified as does the input field added later, since they are the default for added items to this toolbar. The handler function just reloads the grid's data store. Since the grid is not yet completely defined, the bbar object is not yet available, so you can't use its copy of the store object. That is why I used 'grid.store.load()' instead of 'bbar.store.load() in the handler function.

The input field for the search word or phrase took a bit more defining. The 'xtype' tells ext what kind of element this is. It needs an ID so its value can be gathered later to pass in the AJAX request. The autoCreate values tell ext how to generate the element; in this case it will be an HTML input tag, with the tag elements as specified.

With the grid object finally defined, it's time to build it.

grid.render();

At this point, you'll actually get an empty grid displayed on your page.

Since my requirements included filtering the data, I need to establish the parameters that will be sent to the processing script in the AJAX request. This is accomplished by the data store's baseParams parameter. I created a handler function for the store's beforeload event.

store.on('beforeload', function() {
store.baseParams = {
client:document.getElementById('clientName').innerHTML,
filter:document.getElementById('filter').value
};
});

This gets my client's login name from a display on the page, and gets the search word or phrase from the input field I added to the bottom toolbar. Now every time the store is loaded it will send these values to the processing script.

And at last, the AJAX request is sent off, with the initial values for paging.

store.load({params:{start:0, limit:25}});

Looking at the original demo code, you'll notice that the whole thing is wrapped in one big onReady function. As soon as the page is loaded and the DOM is available, the AJAX request is sent and the first set of data will appear immediately. The paging toolbar automatically keeps track of where it's at in your data, so each subsequent request will carry the appropriate start and limit values with it.

The Processing Script

Ext doesn't care at all what scripting language you use for processing the AJAX request. It only requires that the return values be in the same form that you specified in the 'reader' parameter of your data store object. In this case, I used a json reader, so my script needs to encode the result set from my database query in json format.

The ext AJAX request will send request parameters as GET if only a default set of parameters are used. If custom parameters are added, then it uses POST. In PHP it might be safest to use the REQUEST array to be able to access both.

I had a little trouble figuring out what parameters ext sends for the column sorting feature, but finally found the relevant documentation in the ext->data->store API documentation, in the Remote Sort configuration item. It sends two parameters, 'sort', the field to sort by, and 'dir', the direction to sort (asc or desc). Armed with this information, plus that it can be seen from the demo that the paging parameters are 'start' and 'limit', and I had defined the baseParams myself as 'client' for the client name filter and 'filter' for the search field value, I was able to build my SQL queries to establish the number of records being returned, and to get the desired rows to load into an array of objects to be json encoded. The exact details are not important, as every scripting language will have its own way of dealing with building the queries and connecting to and querying the database. The database itself isn't even important here, since your request processing script can access any available database from sqlite to Oracle.

Once the data is gathered and the results json encoded, the request result are returned to the AJAX handler.

echo
$_REQUEST['callback'].'({"total":"'.$rows.'","results":'.json_encode($arr).'})';

This line in PHP invokes the callback handler with 'total' set to the number of rows returned, and 'results' a json encoded array of the rows returned by the query.

The reader object defined in the data store object's parameters can take this data and feed it to the grid, which will organize the data into the form specified in the column model object. The 'results' array will be loaded into the reader's 'root' parameter. The 'total' value is loaded into the reader's totalProperty parameter.

Although it took a bit of study, the ext data grid example proved to be an excellent starting point for a customized data display. It makes a very pretty sortable paging grid with additional custom features in the toolbar with a minimum of bother. I've always known that Javascript and AJAX could make some nice user interface tools, but as I get to know ext I can see a lot of very interesting possibilities for future applications.

About the Author

sottwell has been my alter ego for more than ten years now. It didn't come easily as I grew up in an environment where "those computer kit things would never be of any use, and girls don't do that kind of thing anyway". Married right out of high school, it was more than 20 years later before my husband finally decided that he could use a computer himself, so we would get one. A year later, I bought the parts to build my own. The shop owner didn't want to sell me the parts; he actually told me, "Go home and knit booties for your grandchild". Four days later, I faxed him from my new computer requesting a return fax of his price list. Within two minutes I had a surprised phone call from him, and a few months after that he offered me a job.

Since then, I've run two computer sales and repair businesses in two hemispheres, taught online programming courses in assembly, C++, QuickBasic and VisualBasic, worked for a high-tech startup, and now I work in freelance web development. It's been a lot of work, but it's also been a lot of fun. On the way, I've added six more grandchildren, and yes, I can knit booties for them!

You can see what I'm up to at my two sites, sottwell.com and loripsum.co.uk.

Del.icio.us Digg Technorati Blinklist Furl reddit Design Float