Configuring LESS on Mac OS X and PhpStorm 6.0

LESS is a neat library that extends CSS with dynamic behaviour. It is not the only tool of its type but I like it as it is fairly quick to configure. I tend to build HTML projects as a quick front end to some code. LESS gives me a quick way of making changes to style. PhpStorm 6.0 provides file watchers that run LESS in the background and compiles CSS while you work. This very brief tutorial will help you get things going on Mac OS X Mountain Lion.

Configuring Node.js

If you have LESS installed, skip this section. You need node.js installed, including the node package manager (npm). Download and run the installer package. Accept the default options. If you have installed Xcode in the past then your development environment will have already configured your shell to contain the correct paths. The installer package will prompt you if you need to update your shell path to include the location of npm. By default, at the time of writing, npm is installed at /usr/local/bin/npm. Confirm this by running the which command:

$ which npm
/usr/local/bin/npm

Once npm is installed, open a terminal window and run the following command to install LESS.

$ npm install less -g

If you experience problems during the installation, my security options required sudo to be used and that allowed the installation to proceed, it may be the case for you too. Once the installation has completed, confirm the presence of lessc using which.

$ which lessc
/usr/local/bin/lessc

Try it out by passing a simple .less file through the compiler.

$ lessc example.less > example.css

You should be good to go with LESS.

Configuring PhpStorm / WebStorm

File watchers are a great feature in the JetBrains web IDEs. As you edit LESS files, Php/WebStorm will automatically compile them and produce CSS files in your project. You may get prompted to add a file watcher when editing a LESS file. Responding affirmatively is the simplest way of enabling the file watcher. If you missed it, select Preferences from the application menu. Select File Watcher from the ‘Project Settings’ section.

Configuring a File Watcher using PhpStorm 6.0
Configuring a File Watcher using PhpStorm 6.0

If you responded to the auto-detect LESS prompt, there will be a file watcher already listed, as shown in the screen shot. If you are configuring for the first time, select the + icon and choose LESS.

Editing file watcher settings using PhpStorm 6.0.
Editing file watcher settings using PhpStorm 6.0.

PhpStorm should detect the installation of lessc automatically. Additionally, there are some useful settings in the dialog. The ability to track root files only is great when working with Twitter Bootstrap projects; when you only desire bootstrap.less to be compiled in response to changes in variables.less. A full description of the options is available in the JetBrains documentation.

That is all there is to it. Any time you edit a LESS file, the IDE will compile it using the settings configured in the file watcher.

Further Reading

Models without Tables in CakePHP

CakePHP provides a lot of functionality. If you follow its naming conventions and practices as outlined in The Book, you get the functionality without having to write a lot of plumbing code. The worked examples walk you through the basics of creating a CRUD application. The problem I have with CRUD applications is I am not convinced that they exist. I have never been tasked with creating an application that merely creates, updates and deletes data. There is always a reason to collect the data and often this reason will result in some processing, which may be reports, operations, monitoring etc.

Linking models to tables and establishing their relationships is useful and, as already mentioned, quite powerful. In this article I suggest that you have all of those models in place and have them implement any methods that are required, but supplementing those models with table-less models when an operation involves multiple modes and contextually different validation rules. I think this approach presents a few benefits, chiefly:

  • Methods that act on data are situated in the model layer.
  • Validation rules that are specific to an operation can be separate from the associated table model.
  • Controllers remain skinny.
  • Take advantage of CakePHP view form and validation mechanisms without involving the controller.

Define The Model

The first step is to create a new file to define your model, ensuring that it inherits AppModel. For the purpose of this tutorial, I have appended Operation to the class name for table-less models. You will most likely have your own naming convention/company style. The useTable member of the class should also be initialised to false. This stops some of the CakePHP functionality from activating, scanning your database and declaring a schema. You will do this manually.

class ContactOperation extends AppModel {
	public $useTable = false;
}

You will then need to declare a schema member (inherited from base class). You will define it with your own ‘table’ definition. This is a regular CakePHP array (string keys of arrays). You can use this to create fields that will represent the aggregate data that you wish to collect. This data depends on your scenario. For example, if your program managed windshield repairs, you may have models for operatives, customers, vehicles, stock and appointments. A wind shield repair gathers information, from your CRUD generated features, and does something with it. An operative will fix the windshield on a given appointment, which takes place at a particular place. These operations may trigger historical event logging, stock allocation and other activities – all things pertaining to the relevant models. However, the fix windshield operation may only need to collect a set of information consisting of key fields from other models, a date/time and other notes. It does not get saved to the database directly, it is used to execute lots of other activities. The scenario could also be much simpler, like a contact form. The contact form does not have a model directly related, but it will still validate email addresses, possibly check for rogue IP addresses or some white/blacklist mechanism. All these scenarios present an opportunity to wrap them up into a model, instead of fragmenting the context over several. For the purpose of this article, the contact form is the scenario of choice. Define the schema within the class as shown:

public $_schema = array(
        'name' => array(
            'type' => 'string',
            'length' => 200,
            'null' => false,
        ),
        'email' => array(
            'type' => 'string',
            'length' => 150,
            'null' => false,
        ),
        'category_id' => array(
            'type' => 'integer',
            'null' => false,
        ),
        'message' => array(
            'type' => 'text',
            'null' => false,
        ),
    );

With a schema and known fields in place, you are already on your way to being able to use the form helper to generate input for this model automatically in your views. To this end, we shall now add some validation rules. The validation rules are defined as another associated array, just like a regular model. You can use a combination of built-in CakePHP rules or use your own custom rules.

public $validate = array(
    'name' => array(
        'validName' => array(
            'rule' => array('between', 2, 200),
            'message' => 'Name must be %s-%s in length.',
            'allowEmpty' => false,
            'required' => true,
        ),
    ),
    'email' => array(
        'validEmail' => array(
            'rule' => array('email'),
            'message' => 'Must be a properly formatted e-mail address.',
            'allowEmpty' => false,
            'required' => true,
        ),
    ),
    'category_id' => array(
        'validCategory' => array(
            'rule' => array('validateCategory'),
            'message' => 'Must represent a valid category.',
            'allowEmpty' => false,
            'required' => true,
        ),
    ),
    'message' => array(
        'validation' => array(
            'rule' => array('notempty'),
            'message' => 'Message cannot be empty.',
            'allowEmpty' => false,
            'required' => true,
        ),
    ),
);

I have provided the validation rules in long form. It is something I tend to do when developing with CakePHP for my own code consistency. The only custom validation rule is that of category ID. In this simple example, the categories will be a static array list provided by the model being defined. A real application would likely retrieve these categories from a specific data provider. That being said, the validation method and a get list method are presented below, add them to your ‘ContactOperation’ model definition.

public function getCategoriesList() {
        // this could be a find 'list' from
        // another model
        return array(
            1 => 'Sales',
            2 => 'Support',
            3 => 'Query',
        );
}

public function validateCategory($check) {
        // would likely check for a real
        // record id
        $selected = reset($check);
        return is_numeric($selected) &&
            $selected < 4 && $selected > 0;
}

Additional rules can be added according to your preference. You may have a banned list of e-mail address, in which case a validation rule could verify the existence of the address on this list and behave accordingly. This list may be external to your application. The methods shown here are illustrative of the framework in operation. I am certainly not suggesting you adopt it as ‘good practice’.

Defining the Controller

You have choices when defining the controller. You could provide a specific controller for the purpose of contact form operations. You could create a method in an existing controller and create a route for it. I shall use the example given in DerEuroMark’s blog post on the Contact Form Plugin. Define a new controller called ‘ContactController’ and have it extend ‘AppController’. E.g.

<?php
App::uses('AppController', 'Controller');

class ContactController extends AppController {

    public $useModel = false;
}

The ContactController will only have one method, index. Using this naming scheme allows for an easy browse to /contact/ without requiring specific routes to be configured. The controller is set to not use a model directly, they can be initialised at execution time as required. The definition of the index method is given as:

public function index() {

    $model = ClassRegistry::init('ContactOperation');

    if($this->request->is('post')) {
        $model->set($this->request->data);
        if($model->validates()) {
            $this->Session->setFlash(_('Thank you!'));
            // do email sending and possibly redirect
            // elsewhere for now, scrub the form
            // redirect to root '/'.
            unset($this->request->data);
            $this->redirect('/');
        } else {
            $this->Session->setFlash(_('Errors occurred.'));
            // display the form with errors.
        }
    }

    $categories = $model->getCategoriesList();

    $this->set('categories', $categories);
}

This method is very simple. The controller checks to see if the request is a post and attempts to validate the form. Upon successful validation, it’s time to send an email, say thanks and do whatever is required after using the contact form. Should the form not validate, it will use the view form helper to tie into the validation errors and have the displayed side by side with the input controls, the usual CakePHP affair. The model is initialised at the start of the method using the ClassRegistry static class. Before the view is rendered, the categories are assigned to the view from the model method you defined earlier. This is regular CakePHP naming convention and ties the list with the input control and remembers user selection.

Define the View

The view is a simple form, with several input controls. The form creates a ‘ContactOperation’ form, which hooks up to the model and retrieves the appropriate mark up settings. It really is very simple. Create a new directory under ‘View’ called ‘Contact’ and a file within it called ‘index.ctp’. Use the following markup/script to define your view:

<div class="contact form">
    <?php echo $this->Form->create('ContactOperation'); ?>
    <fieldset>
        <legend><?php echo __('Contact Us'); ?></legend>
        <?php
            echo $this->Form->input('name');
            echo $this->Form->input('email');
            echo $this->Form->input('category_id');
            echo $this->Form->input('message');
        ?>
    </fieldset>
    <?php echo $this->Form->end(__('Submit')); ?>
<?php
echo $this->Form->end();

Start your development server (my screen shots show MAMP running on localhost:8888) and navigate to /contact. You will see something similar to the screen shot:

CakePHP Contact Form View

If you put some data into the inputs that purposefully trip the validation methods, you can see how CakePHP has automatically hooked your model logic into your view.

CakePHP Contact Form View with Errors

Summary

The technique demonstrated in this post can be used in most business scenarios. I often find the table-less model approach to be much cleaner and less muddled than trying to pin a multi-model operation onto one model and managing the relationships. Using a table-less model, you get to define your behaviour and validation within the context of the operation, while maintaining the stand alone validation.

To extend this idea, you can then implement the save methods inherited from model, or write your own application level method. For example, the code to send an email could be presented as a method in your ContactOperation model. For something more general, such as this contact form, you may wish to produce a set of plugins and tools for use across various projects.

Further Reading

PhpStorm and CakePHP Unit Tests

I am currently crafting a brief tutorial on testing using PhpStorm, CakePHP and my recent experiences in running a project with this setup. However, running CakePHP unit tests from within the PhpStorm IDE was driving me to despair until Maarten Balliauw came to my rescue. He has made a blog post explaining how to hook the PhpStorm and CakePHP unit tests together. I can verify that it works well and I have run hundreds of tests. If you are working with CakePHP and PhpStorm, you should read Maarten’s post.

The folks at JetBrains really are a classy bunch!

Configure PHP on Mac OS X Mountain Lion

I have recently picked up a project to be created using PHP. It has been great to get back into PHP as I have not used it in a while (since PHP 4.3). For some reason, web sharing was removed from OS X Mountain Lion; removing the one click activation of Apache. PHP is still there and can be configured easily from the terminal. This post explains how to activate PHP, Pear and Xdebug using the system installation.

For convenience, I recommend using a separate stack for development, such as MAMP. I shall post about that later.

Install Xcode

If you intend to develop on your Mac then I recommend installing Xcode from the App Store. Once you have Xcode installed, launch the program and go to preferences. Click on the Downloads tab install the Command Line Tools. This will make compilers available, such as gcc, for building extensions and packages.

Xcode Preferences
Additional downloads for Xcode.

Configure PHP

Use the default initialisation file and copy it to the same directory as ‘php.ini’. You will need to provide your administrative account password for sudo commands.

$ sudo cp /private/etc/php.ini.default /private/etc/php.ini

You should now be able to execute php with the -v switch to get the current version and determine that it is installed.

Configure Pear

Execute the Pear PHP archive using the following:

$ sudo php /usr/lib/php/install-pear-nozlib.phar

Point Pear and Pecl programs to the PHP initialisation file:

$ pear config-set php_ini /private/etc/php.ini

$ pecl config-set php_ini /private/etc/php.ini

Finally, get Pear to upgrade itself and all of its packages.

$ sudo pear upgrade

Install and Configure Xdebug

From the terminal prompt, get Pecl to install Xdebug.

$ sudo pecl install xdebug

Pecl will install Xdebug as an extension and create a new line in your php.ini file referencing the extension. This will not work correctly as Xdebug needs to be loaded as Zend extension. This can be corrected with a brief and simple change to php.ini.

$ sudo pico /etc/php.ini

Change the line at the top that starts with ‘extension’ to:

zend_extension="/usr/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so"

Save php.ini and you should now have a working PHP with Xdebug using Mountain Lion.