How to POST backbone model data to DB through Slim php and Paris

jmk2142 picture jmk2142 · Jan 29, 2012 · Viewed 20k times · Source

I'm trying to get an understanding of how Backbone.js, Slim PHP and Paris/Idiorm might work together and I'm having trouble completing the flow, starting with model attribute data, all the way to the database. PROBLEM: What exactly gets sent to my server when I do model.save() ?

Client-side: Backbone.js

var Donut = Backbone.Model.extend({
    defaults: {
        name: null,
        sparkles: false,
        creamFilled: false
    },
    url: function() {
        return '/donut';
    }
});

var bostonCream = new Donut({
    name: 'Bawston Cream',
    sparkles: true,
    creamFilled: true
});

bostonCreme.save();  // <-- Problem: Not sure what & format this is sending

I think the above is my main problem. My understanding is that backbone will by default, know to send POST data since it's new. It sends it to /donut which is routed, but the question I have is WHAT does it send? And in what format? The outcome I want is to save those donut attributes to my DB. I can pass this server-side code a json like this using jQuery $.post()...

var myDonut = {"name":"Jelly Filled", "sparkles":false, "creamFilled":true};
$.post('http://localhost/donut', myDonut);

...and it happily takes it, saves it to my database. But with the current setup trying to send my backbone donut data, I get POST 500 Internal Server Error. Below I have some server-side code.

Server-side: Slim PHP w/ Paris

class Donut extends Model {}

$app->post('/donut', function() use ($app) {  // Slim framework routes my POST...

    $donuts = Model::factory('Donut')->create();  // Paris stuff...

    $donuts->name = $app->request()->post('name');  // Slim request parameters...
    $donuts->sparkles = $app->request()->post('sparkles');
    $donuts->creamFilled = $app->request()->post('creamFilled');

    $donuts->save();   // Paris... Save name, sparkles, and creamFilled to my DB
});

I have a feeling the answer is out there, but every example I've looked at seems to be missing one piece of the puzzle or another and I can't get that "A-hA!" moment. I thank you in advance and apologize if this is a really ignorant question. :-P

FOLLOWUP/EDIT: 1

Can you paste the error messages?

I get a POST http://localhost:8888/donut 500 (Internal Server Error) in the current state. I can get more information with the following code.

bostonCream.save({}, {  // REPLACE bostonCream.save();
    success: function(model, response) {
        console.log('SUCCESS:');
        console.log(response);
    },
    error: function(model, response) {
        console.log('FAIL:');
        console.log(response);
    }
});

Now when I run backbone's save(), I still get the 500 Error but also XMLHttpRequest as my FAIL response. The only remarkable clue from the XMLHttpRequest is responseText = SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null.

So my guess is that either 1) I'm messing something up with the save() in that it isn't capturing my attributes correctly, 2) It is currently sending my attributes in a format that my server isn't recognizing with the standard $app->request()->post() Slim methods (Doesn't seem to do much when I try accessing directly with $_POST either), 3) My server isn't setup correctly to take the kind of data that is being sent.

Another thing I noticed although I don't know what to make of it is that when I add

echo $_POST;

It returns to me an empty array. Still gives me the FAIL. If I do THIS however...

echo json_encode($_POST);

It gives me a SUCCESS and the response is a [ ]. Nothing in there. Clearly my POST data is still wonky.

Answer

jmk2142 picture jmk2142 · Jan 30, 2012

I came up with a solution to completing the problem: how to get data from client to server using the default backbone save() and .sync - passed over to the Slim php framework and going through Paris/Idiorm to my DB.

I am including my working updated code below:

Client-side: Backbone.js

var Donut = Backbone.Model.extend({
    defaults: {
        name: null,
        sparkles: false,
        creamFilled: false
    },
    url: function() {
        return '/donut';
    }
});

var bostonCream = new Donut({
    name: 'Bawston Cream',
    sparkles: true,
    creamFilled: true
});

bostonCream.save();

/***** If you want to check out the response to save() ? ***
bostonCream.save({}, {
    success: function(model, response) {
        console.log('SUCCESS:');
        console.log(response);
    },
    error: function(model, response) {
        console.log('FAIL:');
        console.log(response);
    }
});
************************************************************/

Sever-side: Slim PHP w/ Paris/Idorm

class Donut extends Model {}

$app->post('/donut', function() use ($app) {

    $donuts = Model::factory('Donut')->create();

    /* EDIT: Works... but not the Slim way
    $parameters = json_decode(file_get_contents('php://input'), true);
    $donuts->name = $parameters['name'];
    $donuts->sparkles = $parameters['sparkles'];
    $donuts->creamFilled = $parameters['creamFilled']; */

    /* SLIM: Using Slim Request Object */
    $requestBody = $app->request()->getBody();  // <- getBody() of http request
    $json_a = json_decode($requestBody, true);
    $donuts->name = $json_a['name'];
    $donuts->sparkles = $json_a['sparkles'];
    $donuts->creamFilled = $json_a['creamFilled'];

    $donuts->save();

    // echo json_encode($parameters); // Prove you've captured POST data, send it back
}

Now my code is happily using the default settings of Backbone.js (no changes to sync) and sending proper model attribute information to my server which seems to be successfully accepting the data and saving it to my DB.

The key here seems to be this line...

/* $parameters = json_decode(file_get_contents('php://input'), true); */
// EDITED: getBody() method not documented in Develop Doc, only Stable @ time of post

$requestBody = $app->request()->getBody();