Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save data using AJAX and CakePHP

I've spent today researching how to save data using an ajax request in cakephp and have got now where, the documentation on the cakephp website seems a bit lacking for this particular topic.

I have several sortable lists and I need to save the position of each list item when one is sorted. I have an ajax request set up as follows that is triggered when an item is moved:

$.ajax({                    
        url: "/orders/save_column_order",
        type:"POST",                                        
        data:"data="+data
       });

and the referenced function in the controller is:

function save_column_order(){
    if($this->RequestHandler->isAjax()){

             SAVE STUFF...

        }
  }

I have the helpers etc. set up:

var $helpers = array('Html','Form','Js');
var $components = array('Session','Email','RequestHandler');

And its not working...

So my questions are:

1) What is the current url for sending an ajax request to an action in a controller? Is it simply /controller/action?

2) What else do I need to do to the controller to access the ajax data?

BONUS:

3) Is there a way to include a custom php file in the CakePHP framework that references the database settings so I can manually update my mysql database?

like image 834
Alex Avatar asked Jun 08 '11 20:06

Alex


1 Answers

You were very close.

1.) URL is simply /controller/action. Data is passed in $this->data and is magically available in the action. **Since you list 'Js' in your helpers instead of 'Javascript', I'm presuming you're using Cake 1.3.x and jQuery, because jQuery is the default with Cake 1.3 and Js replaced Javascript / Ajax.

-- Fix your helpers:

var $helpers = array('Html', 'Form', 'Js'=>array("Jquery"));

-- Fix your jQuery:

$.ajax({
    url:'/orders/save_column_order',
    type:'POST',
    data:data
});

2.) Use Cake's magic:

function save_column_order() {
    if ($this->data != null) {
        $this->Model->save($this->data);
    // whatever else needs doing...
    }
}

-- Since you're doing ajax, you probably do NOT want Cake's default view-rendering behavior (just a guess.) If you want to render any view at all, it's probably just a snip of markup for an ajax callback, so you probably want to place it in an element rather than a full-blown view:

function save_column_order() {
    // ...
    /* arg 1 - you can specify any view or element you like. 
       arg 2 - enforces your preferred request handling and layout */
    $this->set(compact('vars', 'for', 'view'));
    $this->render('/elements/new_column_order', 'ajax'); 
}

-- Otherwise, just suppress rendering:

function save_column_order() {
    ...     
    $this->autoRender = false;
}

-- If your save isn't working, make sure the structure of $this->data is Cake-save-friendly. If you need to view the contents of $this->data, Cake's built-in debugging (from anywhere in your app) will help you get straightened out:

debug($this->data);

3.) Wait, what?

Not sure I understand what you're asking correctly, so if this does not cover your question, please clarify what you're trying to do?

If you mean, will Cake allow you to manually update records in a table/s, yes? Although I'm not sure why you would want to. Cake's extremely powerful built-in ORM is half the point of the framework, and its extremely comprehensive magic is the other half.

You can scribble off straight SQL with the Model::sql() method, although this is discouraged it's not very OOP or reusable.

When you define associations in your model, you can set the foreign key to false and specify conditions that work like a nested select in Cake's auto joins.

If you need to force join/s, Cake's $options['joins'] give you completely granular control; you can designate any type of JOIN if the default LEFT isn't good enough for what you need to do.

You can make and break model bindings on the fly with $this->Model->bind() / unbind(). You can specify the level of recursion, apply Containable behavior, specify the fields to select and all conditions.

If you need a subquery and Cake just can't get it right, $dbo->buildStatement() will construct your SQL statement and $dbo->expression() will fire it:

function intricate() {
    $dbo = $this->Rate->Status->getDataSource();
    $subquery = $dbo->buildStatement(
        array(
            'fields' => array('`Status`.`id`'),
            'table' => $dbo->fullTableName($this->Rate->Status),
            'alias' => 'Status',
            'limit' => null,
            'offset' => null,
            'joins' => array(),
            'conditions' => $subqueryConditions,
            'order' => null,
            'group' => null
            ),
        $this->Rate->Status
        );
    $subquery = "Status.id = (".$subquery.")";
    $status = $dbo->expression($subquery);
    $options['fields']=
        array(
            "Rate.id", "Rate.plan_id", "Rate.status_id","Rate.rate", "Plan.id", 
            "Plan.company_id", "Plan.name", "Company.id", "Company.name"
        );
    $options['conditions']=
        array(
            $status, 
            "Geographical.name LIKE '%{$this->zip}%'"
        );
    $rates = $this->Rate->find('all', $options);
    $this->set(compact('rates'));
    }

-- If you mean - will Cake allow you to swap out database configurations on the fly, yes. However, doing so can get pretty hardcore, especially when Cake's magic is part of the situation.

You can add multiple db configs in /app/config/database.php -

class DATABASE_CONFIG {
    var $default = array(
        'driver' => 'mysql',
        'persistent' => false,
        'host'=>'localhost',
        'login' => 'cake',
    'password' => 'icing',
        'database' => 'dev'
);
    var $offsite = array(
        'driver' => 'mysql',
        'persistent' => false,
        'host' => '11.22.33.44', // or whatever
        'login' => 'cake',
        'password' => 'frosting',
        'database' => 'live'
);
}

-- Switching between them in your controller / model is where things get a little intense, depending on the complexity of your situation:

// Model::getDataSource()->configKeyName holds whichever db config you're using
if ($this->Model->getDataSource()->configKeyName != 'default') {
    // do something, for example, change models, tables, reload schema, etc.
    $this->loadModel('Special')
    $this->Model->table = 'extras';
    $this->Model->schema(true);
} else {
    // predictably, Model::setDataSource($configKey) changes configs
    $this->Model->setDataSource('offsite');
}

-- If this is what you meant, I can paste a chunk of code I wrote a couple weeks ago requiring I save an ajax form submission (at 2 stages of form completion) to 3 tables in 2 databases (one serving my Cake application, the other serving a legacy CodeIgniter application) showing all this fancy footwork in action along with some good old-fashioned Cake magic join-through save/update shortcuts. (I also had to generate selective emails and finally, fire off a REST request passing the id/s of the newly inserted records to the CI application to trigger it's processing. Whew!)

Anyway, HTH. :)

like image 93
OpenSorceress Avatar answered Nov 11 '22 09:11

OpenSorceress