Thursday, April 16, 2009

Integrate PHP Into JavaScript in CakePHP

Thursday, April 16, 2009 3

The Nuts And Bolts of Cakephp blog recently posted the article “Blend PHP and JavaScript in CakePHP” by Teknoid. He wrote about how to serve JavaScript files with some PHP content by using the $javascript->link() method. That is an interesting approach to PHP/JS integration. After reading his post, I started to consider some alternatives.

Basically, what it comes down to is that you can blend PHP and JavaScript by either the following:

  • Embed JavaScript directly in your view templates (maybe this doesn't mean much to you).
  • Place .js file in your app/vendors/js/ or vendors/js.
  • Use the technique explained in Teknoid's blog.

And here's another alternative, or a more standard way to output files in CakePHP. In this article I am going to explain in detailed steps the way to integrate PHP into JavaScript.

First, parseExtensions needs to be activated (app/config/routes.php).

 Router::parseExtensions('js');

Let’s assume a basic model:

<?php
class User extends AppModel {
    var $name = 'User';
}
?>

Create a table for the User Model with the following SQL:

create table users (
  id int(11) not null auto_increment,
  username varchar(32) not null,
  primary key (id)
);

insert into users (id, username) values (1, 'Jennifer');

Let's build our controller:

<?php
class UsersController extends AppController {
    var $name = 'Users';
    var $uses = array('User');
}
?>

Okay, nothing fancy so far. Let's keep going.

Include the RequestHandler Component in our $components array of either the Users Controller or App Controller:

var $components = array('RequestHandler');

Include the Javascript and Cache Helper in our $helpers array of either the Users Controller or App Controller:

var $helpers = array('Javascript', 'Cache');

As you can see above, yes we are going to use view caching with the Cache Helper. So we'll set 'Cache.check' to true (app/config/core.php).

Configure::write('Cache.check', true);

We'll add an empty action to the Users Controller, for the sake of this demonstration and load some JavaScript file:

function test() {}

Then add another action that renders a JavaScript file:

function alert($id) {
 
    if ($this->params['url']['ext'] != 'js') {
        exit;
    }

    $this->layout = 'gen';
    $this->ext = '.js';
  
    $this->set("cacheDuration", '1 hour');
  
    $data = $this->User->findById($id);
    $this->set('data', $data);
}

In the alert() method, we have changed the file extension from ctp to js so that we can benefit from the code coloring functionality on our text editor.

Now, our Users Controller looks like the following:

<?php
class UsersController extends AppController {

    var $name = 'Users';
    var $uses = array('User');
    var $components = array('RequestHandler');
    var $helpers = array('Javascript', 'Cache');

    function test() {}
 
    function alert($id) {
        if ($this->params['url']['ext'] != 'js') {
            exit;
        }

        $this->layout = 'gen';
        $this->ext = '.js';

        $this->set("cacheDuration", '1 hour');

        $data = $this->User->findById($id);
        $this->set('data', $data);
    }
}
?>

Okay. Let's move on to the view part. We need a view (views/users/test.ctp) to load a JS file:

<?php
if (isset($javascript)) {
    $javascript->link('/users/alert/1', false);
}
?>

The number in the end of the url indicates a user with id=1. So, we are going to retrieve an individual user's data record.

We'll create a layout for JavaScript output (views/layouts/js/gen.ctp):

<cake:nocache><?php header("content-type: application/x-javascript"); ?></cake:nocache><?php
echo $content_for_layout;
if (!$this->cacheAction) {
 $this->cacheAction = $cacheDuration;
}
$this->data = null;
Configure::write('debug', 0);
?>

And a basic view for the alert action (views/users/js/alert.js):

So, if you don't have a js folder in your /app/views/users, create one (this is where you place the alert view template ).

alert("<?php echo $data['User']['username']; ?>");

That's it! Now that we've got a dynamic JavaScript output with view caching, let's quickly open the page located at /users/test in our browser where the alert dialog will appear.

Wednesday, April 8, 2009

Preventing Duplicate Form Submissions in CakePHP

Wednesday, April 8, 2009 0

Forms are a necessary part of web applications and a great way to add data to your database. But somtimes this useful tool may cause problems if your visitors submit the same form information over and over again. How do you solve this with CakePHP or in Cake way? The solution is simple. CakePHP already has one built in, and it's really neat.

Using our Posts controller example, we can make use of Model::postConditions() together with Model::hasAny():

function add() {
 if (!empty($this->data)) {
  $this->Post->set($this->data);
  if($this->Post->validates()) {
   if ($this->Post->hasAny($this->postConditions($this->data))) { 
     $this->Session->setFlash(
      __("Duplicate form submissions are not acceptable.", true)
     );
   } else {
    if ($this->Post->save($this->data)) {
     $this->Session->setFlash(__("Your data has been saved.", true));
    }
   }
  }
 }
}

Hope this is helpful for some of you.

Friday, April 3, 2009

Directly Calling a Model Function from a View

Friday, April 3, 2009 2

It's always better not to call functions in the model from the view, because it breaks somehow the MVC pattern. However, there might be cases where this approach is needed.

A quick example would be:

class Post extends AppModel {

    var $name = 'Post';

    function user($id, $key = null) {
        if (empty($id)) {
            return null;
        }
        $user = ClassRegistry::init('User')->find('first', array(
            'conditions' => array('User.id' => $id),
            'recursive' => -1
        ));
        if (!$user) {
            return null;
        }
        if ($key == null) {
            return $user;
        } else {
           $user = array_pop($user);
           if (isset($user[$key])) {
               return $user[$key];
           }
           return null;
        }
    }

}

See the above example. The method user() is just a sample method that returns an entire User record for a given ID. In addition, if the second argument is given correctly, only a specific field will be retrieved from a returned row.

Now that we have a model function, we can call it in our view:

<? pr( Post::user(1) ); ?>
<? pr( Post::user(1, 'username') ); ?>
 
JamNite ◄Design by Pocket, BlogBulk Blogger Templates