Prevent debug info from messing with your AJAX responses

Update (05/21/2010): Well, looks like it has been removed from the core completely (good riddance).

Just a little tidbit of code that can help you when doing any AJAX communication…

Generally you’ll notice that cake inserts a timestamp with each response, unless debug = 0 (i.e. production mode).
This, of course, is not a desirable thing if you wish to return a proper JSON object, for example.
At least in 1.3 the SQL debug is moved into a separate element so it does not interfere with the output (you’ll need a little more adjustment for 1.2).

Now, we have to fix-up app/webroot/index.php to avoid timestamp output whenever we have an AJAX response.

Towards the end of the file make the following update:

if (Configure::read() > 0) {
  if (!env('HTTP_X_REQUESTED_WITH') === "XMLHttpRequest") {
    echo "<!-- " . round(getMicrotime() - $TIME_START, 4) . "s -->";
  }
}	

Problem solved, enjoy ;)

Bye-bye $cakeDebug…

The infamous $cakeDebug variable, which has been around for a long time and managed to annoy a few people in the process, has been replaced in the recent builds of CakePHP 1.3 with an element.

See the ticket here:
http://cakephp.lighthouseapp.com/projects/42648/tickets/35-the-implementation-of-dbo_sourcephp-logging-needs-changed

The two points to take away are:

  1. Automatic SQL dumps have been removed from DboSource
  2. If you wish to display SQL dumps, as before… replace any occurrence of $cakeDebug in your layouts with echo $this->element('sql_dump');

One of the obvious benefits, is that you no longer have to tweak the core to take control of the SQL debug. As always, simply place sql_dump.ctp in your own app (i.e. app/views/elements) and do what you wish with the output.

Just to test things out let’s throw the SQL debug into the Firebug console, rather than directly into the view.

We’ll need to modify the sql_dump.ctp (which now has been copied into our own app), just a little bit.

Around line 35, let’s replace the default output for SQL dump, for something like this:

//unchanged part of the sql_dump.ctp above this line

//here we are outputting the queries into the Firebug console
foreach($logs as $source => $logInfo) {
  foreach($logInfo['log'] as $key => $query) {    
    echo $this->Html->scriptBlock('console.log("' . $query['query'] . '")');  
  }   
}

For the real world example, this may not be a reasonable thing to do by any means… but it does show how easy it is now to output the SQL debug wherever you need it (logging, debugging, stylizing, parsing, sending to some remote destination… up to your imagination really).

Improved form handling in CakePHP 1.3

Here is a typical, simple form done with cake’s form helpers:

echo $this->Form->create('Article', array('action' => 'test'));

echo $this->Form->input('Article.title');
echo $this->Form->input('Article.body');
echo $this->Form->input('Article.user_id', array('type' => 'hidden'));

echo $this->Form->end('Add Aricle with Tags and Comment');

Which outputs the following HTML:

<form id="ArticleTestForm" method="post" action="/articles/test" accept-charset="utf-8">
    <fieldset style="display:none;">
        <input type="hidden" name="_method" value="POST" />
    </fieldset>
    <div class="input text">
        <label for="ArticleTitle">
            Title
        </label>
        <input name="data[Article][title]" type="text" maxlength="50" value="" id="ArticleTitle" />
    </div>
    <div class="input textarea">
        <label for="ArticleBody">
            Body
        </label>
        <textarea name="data[Article][body]" cols="30" rows="6" id="ArticleBody">
        </textarea>
    </div>
    <input type="hidden" name="data[Article][user_id]" value="" id="ArticleUserId" />
    <div class="submit">
        <input type="submit" value="Add Aricle with Tags and Comment" />
    </div>
</form>

This is fine and all, but one thing worth noting is that default behavior is wrapping each element in a div, and in some cases this may not be desirable. Either a legacy CSS or a front-end developer preference, might require the form to be structured (wrapped) differently.

Let’s see how we can set some defaults for our form with CakePHP 1.3., while simplifying the code a little at the same time by using the inputs() method…

 echo $this->Form->create('Article', array('action' => 'test', 
                                              'inputDefaults' => array(
                                                'div' => array('tag' => 'p'),
                                                'before' => '-- goes before the label --',
                                                'after' => '-- goes after the input --')));    
    
echo $this->Form->inputs(array('Article.title', 
                                               'Article.body', 
                                               'Article.user_id' => array('type' => 'hidden')), 
                                      array('legend' => 'Article submit'));

echo $this->Form->end('Add Aricle');

Which produces:

<form id="ArticleTestForm" method="post" action="/articles/test" accept-charset="utf-8">
    <fieldset style="display:none;">
        <input type="hidden" name="_method" value="POST" />
    </fieldset>
    <fieldset>
        <legend>
            New Article
        </legend>
        <p class="input text">
            -- goes before the label --
            <label for="ArticleTitle">
                Title
            </label>
            <input name="data[Article][title]" type="text" maxlength="50" value="" id="ArticleTitle" />
           -- goes after the input --
        </p>
        <p class="input textarea">
            -- goes before the label --
            <label for="ArticleBody">
                Body
            </label>
            <textarea name="data[Article][body]" cols="30" rows="6" id="ArticleBody">
            </textarea>
           -- goes after the input --
        </p>
        <input type="hidden" name="data[Article][user_id]" value="" id="ArticleUserId" />
    </fieldset>
    <div class="submit">
        <input type="submit" value="Add Aricle" />
    </div>
</form>

Of course for a simple form this may not be a very significant improvement, but having the ability to set defaults for the entire form and relying on some automagic for the rest, certainly makes one’s life easier.

CakePHP 1.3 helps with team-based development workflow…

I do have to say that in 1.2 some of the features described here are available as well, however CakePHP 1.3 takes it slightly to the next level to make team-based development even easier… With SVN or Git it is already easy enough to make team-based development readily accessible, that being said DB (schema and data) management during development process has always been a little bit painful.

Without too much dwelling let’s consider the following scenario. We have our favorite developers Joe and Bob.
(By the way, we are not going to cover any specific version control system here).

Bob starts up the project.
1. He creates the relevant Database with tables, adds a few models, controllers, actions, views.
2. He writes some code and populates the DB in the process with some dummy data.

So far, this should be familiar to most. Generally speaking, once Bob is done with the initial logical point of setup, he would commit all his work into some version control system.

Here’s where the pain of the past came into play…

While Joe can easily grab the application files, which are needed for the project, he is missing the DB structure and some data to continue working on the project.
Since early versions of CakePHP we’ve had a few built-in and third-party tools to help with that process, but they were lacking something… in one way or another. Not to say they didn’t get the job done, just the overall package wasn’t quite there.

Let’s see what to do in cake 1.3..

Bob fires up the command line and…

#cake schema generate

… which creates a php-based, cake-like schema.php file, which holds the information about the table structure.

Next, Bob types…

#cake bake fixture all -records -count 15

(Thanks Mark Story!)

This will bake all fixtures based on the current DB structure… and populate them with maximum of 15 records, which are currently in the database tables.
Fixtures are “nice little things”, but as far as we are concerned here, they simply hold our test data, so that Joe can have easy access to it.

OK, now that Bob was nice enough to do all of the above. He can happily commit all of the application code (including our newly baked schema and fixtures).

Moving on, at this point Joe is ready to get started on the project. He checks out the initial code from the version control repository.

Once the code is on his local development machine, Joe runs:

#cake schema create

Which, as you might have guessed, crates all the tables based on the schema developed and committed by Bob.
(It goes without saying that appropriate CakePHP and ultimately database configuration should already be in place on Joe’s development box).

Now that the tables are created Joe can begin his work, and while it is important to remember the “empty state” of an application, more often than not, some data is needed to get things rolling.

Well, all Joe needs to do at this point is:

#cake fixtures

Which, loads all the data from the fixtures into the newly created tables in Joe’s local database. Nice, eh?
At this point both development environments are fully in-sync and the progress can continue.
The above feature is currently in development and will not be available (or might change) depending on when you are reading this post.

A few things to note…

  1. I rarely find it useful to attempt to alter my schema. If the latest check-in has the required data and updated schema, I can safely drop all the tables, recreate them and insert new data
  2. To address the point above, all of my schema files are in the version control system, so if for whatever reason I need to go back, I simply check out the required revision and rebuild the schema (and add data if needed).
  3. This process can be followed back and forth for as many iterations as necessary.
  4. Human connection is necessary. If there is conflict in the code or schema… check with your fellow developer Bob or Joe and come to an agreement over a beer.

An intro look at jQuery Tools, enhancement for setFlash() and CakePHP 1.3

Actually the main focus of this post will be how to creatively use JavaScript and Session::setFlash() to make your app a little more sexy.
(Slightly tweaked to use CakePHP 1.3, although there is nothing special here that you couldn’t do with other versions of cake).

First, I wanted to point out an awesome little library, called jQuery Tools, which comes with a set of really nice widgets, a whopping 5KB in size and its own CDN for easy loading.

To proceed further let’s consider an Articles Controller, where we are adding a new article.

This is something that you should’ve seen at least a few hundred times…

<?php
class ArticlesController extends AppController {    
 public function add() {
    if (!empty($this->data)) {
        if($this->Article->save($this->data)) {
          $this->Session->setFlash('Article saved!', 'modal', array('class' => 'modal success'));
        } else {
          $this->Session->setFlash('Article was not saved!', 'modal', array('class' => 'modal problem'));
        }
     }
  }
}
?>

Here we are using a pretty standard approach to write a message to the session by using $this->Session->setFlash().
What usually happens then, is a redirect to some other place where the message is displayed.
In our case the message will be displayed in the same view, using a nice-looking modal/dialog.
Another point to note, is that once the message is displayed to the user, we’ll automatically hide it (let’s say after three seconds).
To further extend the app you might consider disabling (or converting to plain-text) the form fields, and possibly displaying an “Edit” link… though these features are brewing in my app, I thought it would be too much to cover in one example.

Alright, now that we are looking at our familiar add() action, let’s see what tweaks we should do achieve the desired goals listed above.

In our layout, we’ll need to load both the jQuery and jQuery Tools libraries.

This is a snippet to do so using the existing CDN’s (and in CakePHP 1.3 style):

<?php echo $this->Html->script(array('https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js', 
                                         'http://cdn.jquerytools.org/1.1.2/jquery.tools.min.js')); ?>

$this->Html->script() replaced CakePHP 1.2 approach of using $javascript->link(), the rest should be pretty obvious.

Next, let’s consider the view for our add() action:

<?php $this->Session->flash(); ?>

<?php
    echo $this->Form->create();
    
    echo $this->Form->input('Article.title');
    echo $this->Form->input('Article.body');
       
    echo $this->Form->end('Add Aricle');

?>

One thing you’ll notice is the way helpers are referenced in CakePHP 1.3… while $form->input() still works, the approach above is “safer” and more consistent. (Take a look here for more details).

Let’s get back to this line of code for a second…

$this->Session->setFlash('Article saved!', 'modal', array('class' => 'modal success'));

The main difference in CakePHP 1.3, is that modal, the second param, represents an element (unlike a layout in previous versions).
Therefore for this setup to work properly you’ll need to create app/views/elements/modal.ctp

Let’s see what it looks like:

<div id="flash-message" class="<?php echo $class; ?>"> <?php echo $message; ?> </div>

$message is replaced by whatever we place in the first argument to the setFlash() method (which happens to be “Article saved!”, in our case).
As you’ve probably guessed $class gets replaced with the appropriate value from the array of passed params.

Now, if we have successfully saved the article the add.ctp view gets re-displayed with our message showing up and the element rendered. (This all happens automagically by using $this->Session->flash()).
This could be already fine in itself, but it’s just not sexy enough… so we add a little jQuery and jQuery Tools magic to make things a little more fun.

$(document).ready(function() { 
 
   //with this approach you can assign the jQuery Tools API to be used later
  //otherwise you could use a standard one-liner:
  //$('#flash-message').expose().load();
   var flashMessage = $('#flash-message').expose({api: true}); 
    
   //now that we have a direct access to the API through the "flashMessage" object
   //we can call the jQuery Tools methods
   //such as load(), which is required to show/expose our modal
   flashMessage.load();
   
   //now that the modal is displayed we can create a simple way to automatically 
   //remove it after 3 seconds
   flashMessage.onLoad(function() {
     setTimeout(function() {
          flashMessage.close();
          $('#flash-message').slideUp(500);        
      }, 3000);
   });
 
});

By including this script we will achieve exactly what our goals are. Display the message in a nice modal/overlay fashion, wait 3 seconds and then auto-hide the message from the user and make our page act as before again.
If you care, please take a look at the comments in the code, to see some nice features of jQuery Tools, i.e. the ability to access any tool’s API. (Please refer to jQuery Tools site for more details).
Overall, we are just relying on the jQuery goodness and overriding our boring flash() behavior, with something quite a bit more interesting.

Well, there you have it, aimed with these tools you are ready to bake sexy CakePHP 1.3 apps ;)

P.S.

Just a little CSS for the modal:

.modal {
   width: 350px; 
   padding: 60px;
   margin: 50px 50px;
  }
  
  .success {
    border: 1px solid #004000;    
  }
  
  .problem {
    border: 1px solid #800000;    
  }

Top 10 things to look forward to in CakePHP 1.3

With CakePHP 1.3 release is just about on the horizon, there are a few developments that I am particularly excited about.
There are some great summaries and previews at code.cakephp.org, but still a few things are somewhat scattered, so here’s my attempt to better highlight some goodies in 1.3. Forgive shameless copy/paste in some parts, but really it goes without saying that all the credit goes to the developers for baking yet another awesome cake.

Maybe, the proper title should be “Top 10 things I’m looking forward to”… but either way, I hope you’ll find something useful and if there are some interesting features/updates that I’ve not included, please do share them in the comments.

So, without “further dudes”…

10. Missing behaviors trigger an error

Using behaviors that do not exist, now triggers a cakeError making missing behaviors easier to find and fix.

9. GROUP BY support in the Containable behavior

Finally, we should be able to do something along the lines of:

'contain' => array(
    'Answer' => array(
        'fields' => array('Answer.value', 'COUNT(*) AS count'),
        'group' => array('Answer.value')
    )
)

Which really makes reporting across multiple models much easier and any previously required hackery is no longer needed.

8. “Missing” model methods will trigger a warning

In the past, when Model::someMethod() was not found, the method itself was attempted to be executed as a query. Now, we should see a warning that such method isn’t there. This does affect some existing code, but is a sound improvement overall.

7. Support for engine type in MySQL DB

The new schema shell will properly recognize the engine type used by your tables (for example MyISAM vs InnoDB).
This was a bit of a pain in the “old days” when running a new schema would always default to MyISAM.

6. Helpers are now referenced by $this->HelperName

This is actually a very nice improvement because it ensures that your helper object will not conflict with some random variable from your view.
For example, if you have an ImageHelper and you also had an $image variable, in the old days the collision between the two would create major problems, especially because the conflict can happen completely unknowingly to the user (consider an app with lots and lots of views). Such an error was too easy to make.

5. Updates to the Form helper

What could be better than the lovely input(s) methods of the Form helper?
How about the suggestions outlined in this ticket

To summarize, we should have greater control over the form element placement therefore having much more flexibility in the way the forms are laid out.

4. Error logging with debug at zero

This has been a long-requested feature and it is finally making it’s way into 1.3
You can use Configure::write(‘log’, $val), to control which errors are logged when debug is off. By default all errors are logged.
The $val is a standard PHP constant such as E_WARNING.

3. New fixture task

Baking fixtures is now another tasty piece of cake. One of the lovely feature is that it properly handles UUID’s.

2. Sweet prefix routing
The old admin routing is gone in the way of proper prefix routing, so if you wish to have:
http://www.example.com/user/profiles/edit
http://www.example.com/admin/users/delete
http://www.example.com/editor/articles/publish

It is now easily accomplished with a simple setup in the core.php:

Configure::write('Routing.prefixes', array('admin', 'editor', 'user));

Of course, you’ll need appropriate “prefixed” action such as editor_publish() in your relevant controllers.

1. Brand new way to handle Javascript and Ajax

This is probably the most anticipated and welcomed change in 1.3. One of the great things about CakePHP has always been the fact that it did not depend on any other libraries or what have you … (well other than PHP). In the old days that paradigm was somewhat “broken” because Ajax helper required the use of the Prototype JS library.
It wasn’t necessarily a huge problem, but for people who preferred to work with other JS frameworks… the helpers were of little help and mostly dead weight in the framework.
Not only that, the the new JS helper and improved HTML helper solve a lot of other little problems, which make CakePHP 1.3 something to really look forward to.

Well… it’s no worth repeating what’s already said at 1.3 wiki regarding the new helpers.

Go cake!