3.5. Customizing the UI

The first thing you'll probably notice about the generated code is that the input types aren't ideal for our application. Let's make a few improvements.

Changing UI Widgets

The first change we want to make is to have the blog post itself to be in HTML. To do this, simply edit the edit.yaml file, updating the class of the post object to WFHTMLArea.

Note

On Mac OS X, you can use PHOCOA Builder.app to make these edits to the UI setup.

Once that change is made, just reload the page and you will see the HTML Editor (thanks, FCKEditor!).

Note

Technically, PHOCOA classifies all UI objects into two major classes: Views and Widgets. Views are read-only UI objects used for layout. Widgets, which are subclasses of views, add support for accepting input and writing data back to bound data objects. View classes can read data via bindings, but they cannot accept input or push data back to bound objects.

Controlling Widget Visibility

Next, we want to hide the Post date field for new entries as it will be added automatically.

To do this, we will add a hidden binding to the post_dts setup in the edit.yaml file:

    postDts:
      class: 'WFTextField'
      bindings:
        value:
          instanceID: 'Blog'
          controllerKey: 'selection'
          modelKeyPath: 'postDts'
        hidden:
          instanceID: 'Blog'
          controllerKey: 'selection'
          modelKeyPath: 'isNew'

If you reload now, you'll notice that the Post dts field is now missing when editing a new post. However, the field label is still there. PHOCOA has a handy smarty block element to help you eliminate extra layout markup around hidden widgets. Edit the edit.tpl file as shown:

    {WFViewHiddenHelper id="postDts"} 
    <div>
        <label for="postDts">Post Dts:</label>
        {WFView id="postDts"}{WFShowErrors id="postDts"}
    </div>
    {/WFViewHiddenHelper}

You will now see that the field and supporting labels and markup are automatically hidden.

Go ahead and enter in a sample title and post, and create the blog post.

Formatters

Once you have created the new post, the form switches to edit mode by hiding the "Create Post" button and adding in "Save" and "Delete" buttons. Also, you will now see that our "Post Dts" field is visible since the object is no longer new.

However, you'll notice that the "Post Dts" is blank. That's because we aren't setting up a default value for this field, due to a limitation of the current version of Propel. Without getting into the details, suffice it to say that you can't set default dates with Propel at this time that work properly. So, we'll just fix this in our Blog class (classes/blog/Blog.php) by overriding the save method. While we're at it, we'll fix up the getPostDts method to return a UNIX date, which we also need:

class Blog extends BaseBlog {
    public function save(PDO $con = null)
    {
        if ($this->isNew())
        {
            $this->setPostDts( "now" );
        }
        return parent::save($con); 
    }
    public function getPostDts()
    {
        $dt = parent::getPostDts();
        if ($dt)
        {       
            return $dt->format('U');
        }       
        return NULL;
    }
} // Blog

If you go back now and add another Blog entry, you'll see that the "Post Dts" is now filled in.

However, you'll probably notice that the format of the timestamp is very generic. We'll fix that using PHOCOA's formatters, which are small classes that automatically convert between human-readable forms and their machine counterparts.

To add a formatter, we must declare it as a shared instance in the module via shared.yaml:

postDtsFormatter:
  class: WFUNIXDateFormatter
  properties:
    formatString: 'D, M j H:m:s'

Now, we attach our formatter to our "Post Dts" field in edit.yaml:

    postDts:  
      class: 'WFTextField'
      properties:
        formatter: '#module#postDtsFormatter'
      bindings: 
        value: 
          instanceID: 'Blog'
          controllerKey: 'selection'
          modelKeyPath: 'postDts'
        hidden:
          instanceID: 'Blog'
          controllerKey: 'selection'
          modelKeyPath: 'isNew'

Note

Notice the #module# preceding the shared instance ID in the formatter; since you can use the YAML mechanism to set up values such as strings, integers, booleans, and doubles, we needed a special flag to indicate that you want to link it to the value of an instance variable of the module, which is what shared instances are.

Reload, and you'll see the new date format. A few neat things to notice about formatters; the formatters try to take any human-readable value and convert it to something useful. For instance, try entering and saving a "Post Dts" of "tomorrow", or "next tuesday". Also, try entering garbage, and you will see that formatters automatically detect error and display error conditions.