4

I'm trying to make an unobtrusive action for deleting bookmarks in CakePHP. Allthough it's working just fine, I suspect there must be a better way to do this. Could someone please point me in the right direction?

function delete($id = null) {
  $ok = $this->Bookmark->delete($id);

  if($this->RequestHandler->isAjax()) {
    $this->autoRender = false;
    $this->autoLayout = false;
    $response = array('status' => 0, 'message' => 'Could not delete bookmark');

    if($ok) {
        $response = array('status' => 1, 'message' => 'Bookmark deleted');
    }

    $this->header('Content-Type: application/json');
    echo json_encode($response);
    exit();
  }
  // Request isn't AJAX, redirect.
  $this->redirect(array('action' => 'index'));
}
fortysixandtwo
  • 485
  • 5
  • 12
  • 1
    I assume this is a controller method? If so, what is it that you don't like? The `$response` bits seem a little "clunky" to me and I might just go with response codes only, but I certainly don't see anything egregiously inelegant in this. – Rob Wilkerson Mar 24 '10 at 23:27
  • Hi! First of all i'm not sure if it's best practice to handle the response in the controller or a view. I think echoing in a controller is inelegant, and to use a view for this is overkill. Any thoughts? – fortysixandtwo Mar 25 '10 at 12:44
  • 1
    Yep. :-) In my own stuff, I choose inelegant (your word, not mine) over overkill. I hate file system clutter. If the response is simple and laconic (as yours is), I see no reason to create a view file file for it. Yours is also a system response which I think is quite valid in a controller. – Rob Wilkerson Mar 25 '10 at 18:20

1 Answers1

3

If you're planning to use AJAX action calls more extensively, it may be worthwhile to go the "overkill" route, rather than the "inelegant" route. The following method configures your application to handle AJAX requests quite gracefully.

In routes.php, add:

Router::parseExtensions('json');

Create a new directory json in app/views/layouts/, and a new layout default.ctp in the new directory:

<?php
    header("Pragma: no-cache");
    header("Cache-Control: no-store, no-cache, max-age=0, must-revalidate");
    header('Content-Type: text/x-json');
    header("X-JSON: ".$content_for_layout);

    echo $content_for_layout;
?>

Create a new directory json in app/views/bookmarks/, and a new view delete.ctp in the new directory:

<?php
    $response = $ok
        ? array( 'status'=>1, 'message'=>__('Bookmark deleted',true))
        : array( 'status'=>0, 'message'=>__('Could not delete bookmark',true));

    echo $javascript->object($response); // Converts an array into a JSON object.
?>

Controller:

class BookmarksController extends AppController()
{
    var $components = array('RequestHandler');

    function beforeFilter()
    {
        parent::beforeFilter();
        $this->RequestHandler->setContent('json', 'text/x-json');
    }
    function delete( $id )
    {
        $ok = $this->Bookmark->del($id);
        $this->set( compact($ok));

        if (! $this->RequestHandler->isAjax())
            $this->redirect(array('action'=>'index'),303,true);
    }
}

On the pages from which the AJAX is called, you'd change the AJAX requests from /bookmarks/delete/1234 to /bookmarks/delete/1234.json.

This also make available to you the option of handling non-AJAX calls to /bookmarks/delete/1234 with an app/views/bookmarks/delete.ctp view.

Any further actions that you want to handle via AJAX and JSON, you'd add views in the app/views/bookmarks/json/ directory.

Daniel Wright
  • 4,584
  • 2
  • 27
  • 28