public
Description: JavaScript Application Framework - JS library only
Home | Edit | New

Setting up SproutCore with a PHP backend

You can write your own PHP backend of course (and this tutorial will show you the basics), but you could also use the open source OrionDB PHP backend for SC.RestServer, written by Maurits Lamers. This backend written in PHP5 provides a generic front end to your SQL database (MySQL fully supported and PostgreSQL support under development). Check it out at its homepage .

Intro

This tutorial is part one of a series of tutorials on how to set up Sproutcore with a PHP backend. The focus of this part is mainly at how to connect SproutCore and PHP and their communication. For a more specific look at how things can be done on the PHP side, please take a look at the second part of the tutorial (after you have done this one, of course).

Note: This tutorial is a follow up from the Tutorial series Sproutcore’s Modern Model Layer and the Using the built-in REST API tutorial. If you did not read these tutorials, please do first.

There are many ways to create a link with a PHP backend, for example by using custom Ajax requests. This tutorial just uses the built-in functionality of SC.Server and its live copy, the application server set up in the core.js file of your client.

Essentials

There are a few elements that are critical to a successful link between PHP and SproutCore (called SC for the rest of this tutorial):
  • models
  • App.server
  • PHP5 objects in JSON
  • collection controllers

Proxy

In development mode, you also need a proper proxy setting to your PHP back end. This proxy setting is set in the sc-config.rb file in the root folder of your application. Let’s assume your php files are on http://localhost/phpfiles. The optimal setting would be to forward an entire folder and the tree below it. This is very easy to do:

 proxy '/phpfiles', :to => 'localhost', :cookie_domain => 'localhost'

as last line in your sc-config.rb file will do the job.

Note: If the method described aboved did not work for you, please check out this article: Name Based Virtual Hosting with Apache and the Proxy Setting in the sc-config file.

PHP

First start with the PHP output for a GET action. As is mentioned in the REST API tutorial, the layout of the JSON response needs to be:

 {"records": [], "ids" : [] }

In PHP, this can be achieved by first creating two arrays $records and $ids. The $records array contains all actual data objects and the $ids array contain the database ids of the records in the same order as the actual data objects. As it is customary to have a id property in an object, it should be easy to construct these arrays. These arrays need to be non-associative and not contain an index, which can be achieved by doing:

 //It is assumed all records are in $previous_assembled_records
$records = array();
$ids = array();
foreach($previous_assembled_records as $key=>$currentrecord){
   $records[] = $currentrecord; // assign the current record to the next available position in the $records array
   $ids[] = $currentrecord->id; // assign the id of the current record to the $ids array
}
// now all records and ids are ready
// create an object to contain it all
$jsonobject = new stdObject();
$jsonobject->records = $records;
$jsonobject->ids = $ids;
// object assembled, so send
echo json_encode($data);

Please note that, in order to let SC understand your data, every GET or POST action can only contain one type of data. So, if you are writing a web application for a store, per request you can only send products, or only send costumers.

By implementing the code above, you already can send some data to your SC application. We will leave the POSTing of data for later.

Models

The model is one of the basic concepts of MVC programming, so it is also a fundamental part in the SC approach of the application. The model in SC contains the make up of your data, together with computed properties and a link to your data resource. Let’s have a look at a typical model:

 myApp.Model = SC.Record.extend(
/** @scope Model.prototype */ {

  // TODO: Add your own code here.  

  resourceURL: 'resourceURL',     

  // this list of properties will be used when talking to the server 
  // backend. If you don't define this only 'guid' will be used. 
  properties: ['id','prop1','prop2','prop3'], 

}) ;

The following properties need to be set:

resourceURL

This is the URL part of the URI to your php file. So, if your file is hosted at http://host.com/somefolder/somefile.php, the resourceURL would be “somefolder/somefile.php”. (Do not start the resourceURL with a ’/’ unless you set the urlFormat property to something different than the default! More on that below.) Never try to include a host name in a resourceURL. SC does not support it, resulting in a actual GET URL like “http://localhost/http://host.com/somefolder/somefile.php”. Moreover, if SC would support it, your browser won’t, as JavaScript requests to any other host than the host the JavaScript file was downloaded from, is blocked.

properties

This array determines what properties are recognised by SC and imported into a record. (There is some discussion whether this is still valid, but include it for the time being)

How to actually get the records into your application

core.js

We have now set up everything needed for a successful GET action. First, make sure there is a server in your application (which should normally be the case if you set up your application using sc-gen) by looking up core.js and looking up the line containing something like:

 server: SC.Server.create({ prefix: ['myApp'] }),

There can also be a property called urlFormat, but leave it to the standard value of "/%@/%@". It can be used to alter the way the actual call to the server will look like, but we will have a look at that later.

Collection controllers

To be able to use a set of records properly, you need collection controllers. A collection controller is just a container which provides certain actions for your collection of records. It is a sort of inbetween between a set of records in a collection and a collection view. The most used properties of a collection controller are arrangedObjects, content and selection.

When declaring the collection controller, you can set it up with a specific behaviour:

 myApp.modelCollectionController = SC.CollectionController.create(
/** @scope myApp.modelCollectionController */ {

  // TODO: Add your own code here.
  allowsEmptySelection: true,
  allowsMultipleSelection: false,
}) ;

Look up the properties in the SC documentation.

main.js

Now we go to your main.js to setup the actual collections and set up the GET action. After the line that reads:

myApp.server.preload(myApp.FIXTURES) ;

we include the following code:

// first create a collection of our Model data type
var myApp.modelCollection = myApp.Model.collection(); 
// set up the collection controller with our newly created collection
myApp.modelCollectionController.set('content',myApp.modelCollection);
// perform the server request for our data type
myApp.server.listFor(myApp.modelCollection);

These lines can also be executed on the command line (using FireBug or Safari). After the line with listFor you should see a GET action being performed. Any collection view attached to the arrangedObjects property of the modelCollectionController should immediately show the loaded records.

Posting

Note: At the moment, POSTing using JSON partly works (introduced in 0.9.14), but there are two issues.
  • It will work only on the commitRecords() function (a bug)
  • It will only work properly for records previously fetched from the server back end. It will not work for freshly created records directly. For a work around, please go to http://sproutit.lighthouseapp.com/projects/11697/tickets/98-get-attributes-only-available-on-records-from-server.

To enable POSTing using JSON, you have to add a line to your server init in the core.js file of your project:

server: SC.Server.create({ prefix: ['myApp'], urlFormat: "/%@/%@", postFormat: SC.JSON_FORMAT, escapeJSON: true})

Note: If you are experiencing errors when using non-ASCII or special characters, please try to switch the escapeJSON property to off (it is on by default).

The basic line for committing a bunch of records is:

myApp.server.commitRecords(collection_of_records);

where collection_of_records needs to be an array of records (an array of SC.Record-deriven objects). It can not be a collection. The most easy method of entering records is by selecting them directly in SC.Store by using the SC.Store.findRecords function. It has the following syntax:

SC.Store.findRecords( hash_of_conditions, record_type);

hash_of_conditions

hash_of_conditions is a JavaScript object in which key-value pairs are defined. An example could be: { 'guid' : '21', 'otherproperty':'value_of_otherproperty' }

hash_of_conditions is optional and can be left out when all records of a specific type are to be returned.

record_type

record_type is the same as a model type. In the case of the application described in this tutorial, this would be myApp.Model.

In case you want to create new records on the server, you would use:

myApp.createRecords( collection_of_records);

REST or not to REST

Although you can use SproutCore with any kind of backend, SC was originally used with applications that used a RESTful server interface, whereas PHP usually connects to the server by calling php files directly.

Note: If you are unfamiliar with REST, go to http://rest.blueoxen.net/cgi-bin/wiki.pl or http://en.wikipedia.org/wiki/Representational_State_Transfer to read about it, or use Google:”http://www.google.com”. If you are in a hurry: the main difference is that REST uses the URL to point at resources rather than files on a server.

From this point on, there are two possible routes: use REST or not use REST. When you want to use REST, a few actions have to be performed to get the web server and PHP working together to get the call correctly forwarded. If you don’t want to use REST, it will involve some tinkering with the urlFormat property of SC.Server to get things working. If you are not sure what to use, I would suggest to go with REST as I think it will work more efficiently with SC and will scale better in the long term.

urlFormat The urlFormat property is a string describing two parts of the GET or POST process: the resourceURL and the verb. The verb is the actual action to be performed, like “list” or “update” and depends on the action performed (listFor provides “list” and commitRecords provides “update”). The resourceURL property has been introduced earlier in this tutorial.

The contents of the urlFormat defaults to "/%@/%@". This string is translated to form the end URL of the call, where the first "%@" is replaced by the resourceURL property of your model and the second "%@" is replaced by the verb and in some cases some extra parameters. If your resourceURL on your model is ‘dbaccess.php?do=getproduct’, your urlFormat is "/%@&action=%@" and the function call is MyApp.server.listFor(), the URL will end up looking like http://host:4020/dbaccess.php?do=getproduct&action=list"

It may be tempting for “old-school” PHP programmers to jump right in and get to work hooking SC up to their existing frameworks. However, you might encounter some unusual things, as SC.Server seems not to be built for this way of talking to the server back end. (One of the unusual things will be that POSTed data always is sent as an array called records.)

Moreover, there are a few advantages of doing it the REST way.

PHP revisited

One of these advantages is that because of the nature of resources, it is very easy to scale a RESTful interface as it is just calling a different resource. There are two ways of doing a RESTful interface, as there are two possible URL schemes.

Non Rails URL Scheme The first URL scheme resembles the example above, but with a little twist. Instead of setting resourceURL to “access.php”, you could set resourceURL to “product.php”, set the urlFormat to "/%@?action=%@" to get a URL like http://host:4020/product.php?action=list". This will of course work, but you will have to create different PHP files for every type of data.

Rails URL Scheme The second URL scheme resembles the Rails URL scheme and it has some advantages over the first URL scheme. It requires some tinkering with web server configuration, but it will allow you to make things much more template based and prevents having to manually write large amounts of PHP code and create many different files, or one large file.

The basic concept that makes this work is the ability to tell the webserver to forward a complete URL to a specific file without altering the actual URL or the way it looks like for the user or the application. This enables translating a resource file directly to a database table.

With Apache, this forwarding is done using .htaccess files. However, the server needs to be configured to accept this kind of local overrides so you need to check for this first. There are multiple sources on the web to find out how to configure the server to do this.

When you want the REST interface to be in http://host/resources, and you want to send every request below this directory (say http://host/resources/product) to http://host/resources/index.php, your .htaccess file will probably look like this:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*$ /resources/index.php

Using $_SERVER["REQUEST_URI"] and $_SERVER["REQUEST_METHOD"] you can access the original request and method. If your request was http://host/resources/products/list?order=id $_SERVER['REQUEST_URI"] will return "/resources/products/list?order=id" even though the call was forwarded to http://host/resources/index.php .

You can now start writing your own REST API, but you could also use one of the PHP REST APIs that are already available (such as [http://phprestsql.sourceforge.net/], from which the rewrite rules above originate).

You are now ready (I hope) to connect your SC application to PHP. If you want to know more about the PHP side of the SproutCore-PHP connection, please read on in part 2 of this tutorial:

Setting up SproutCore with a PHP backend part 2

If you have any comments, please add them below!

Comments

Corrected some errors and added a note on top about the focus of this tutorial. Special thanks to gskluzacek on pointing out some errors! – Maurits

Converted a couple article references in the top note section to links, mainly to see how to edit this wiki – bedward

Last edited by mauritslamers, Wed Jan 14 14:10:24 -0800 2009
Home | Edit | New
Versions: