JSON View, JS/AJAX Client

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

JSON View, JS/AJAX Client

Post by VladSun »

From viewtopic.php?f=19&t=93782&start=0
arborint wrote:
VladSun wrote:My PHP projects don't use any HTML (except for the BODY tag and a few SCRIPT tags) - only JSON server-side views and ExtJS client side :)
I would be great if you would start a new thread on JSON server-side views and ExtJS client side. I'd be interested in learning more...
I'll describe an example of users CRUD interface and implementation.
I use CI and ExtJS

Model:

Code: Select all

class User_List_Model extends Model 
{
    private $user_collection = null;
    
    public function __construct()
    {
        parent::__construct();
        $this->user_collection = new User_Collection_Object();
    }
    
    public function load()
    {
        $this->user_collection->load();
    }
    
    public function get()
    {
        return $this->user_collection->get();
    }
    
    public function save()
    {
        $fields['data']     = '';
        $this->validation->set_fields($fields);
 
        if (!($users = json_decode($this->validation->data)))
            Error::register('Empty data');
            
        $this->db->trans_start();
        $this->user_collection->add($users->added);
        $this->user_collection->update($users->updated);
        $this->user_collection->delete($users->removed);
        $this->db->trans_complete();
        
        if ($this->db->trans_status() === FALSE)
            Error::register('SQL transaction error.');
    }
}
Controller:

Code: Select all

class User extends Controller {
 
    function __construct()
    {
        parent::__construct();
 
        $this->load->model('user_list_model', 'user_list');
    }
    
    public function view()
    {
        $this->user_list->load();
        
        $this->load->view('common/json_format', array(
            'data' => $this->user_list->get(),  
        )); 
    }
 
    public function save()
    {
        $this->load->library('validation');
        $this->user_list->save();
        $this->load->view('common/json');
    }
}
Views:
json_format

Code: Select all

echo json_encode($data);
json

Code: Select all

ExtResponse::pack();
Where ExtResponse is:

Code: Select all

class ExtResponse 
{
    public static function send($config)
    {
        $temp = new StdClass();
        foreach ($config as $field => $value)
            $temp->{$field} = $value;
        echo json_encode($temp);
    }
    
    public static function pack()
    {
        self::send(array(
            'success'       => !Error::has(),
            'errorMessages' => Error::getErrorMessages(),
            'data'      => Data::get(),
        ));
    } 
}
and Error is:

Code: Select all

class Error 
{
    private static $errorMessages   = null;
    
    public static function register($msg)
    {
        self::$errorMessages[] = $msg;
        if (__DEBUG) error_log($msg);
    }
    
    public static function has()
    {
        return (boolean)(count(self::$errorMessages) > 0);
    }   
    
    public static function getErrorMessages()
    {
        return self::$errorMessages;
    }
}
Client side:

UserCRUD.js
[js]var userModel = Ext.data.Record.create([    {name: 'id',        type: 'int',    defaultValue: 0},    {name: 'username',  type: 'string', defaultValue: ''},    {name: 'fullname',  type: 'string', defaultValue: ''},]); var userDataStore = new Ext.extended.JsonStore({    proxy: new Ext.data.HttpProxy({        url     : '/user/view',        method  : 'POST'    }),    updateURL   : '/user/save',    postFieldName: 'data',     recordModel : userModel,    fields      :    [        {name:  'id'},        {name:  'username'},        {name:  'fullname'},    ],    sortInfo    : {field: 'username', direction: 'ASC'},    remoteSort  : false}); var filters = new Ext.ux.grid.GridFilters({    filters:    [        {type: 'string',    dataIndex: 'username'},        {type: 'string',    dataIndex: 'fullname'}    ],    local:  true}); var userColumnModel = new Ext.grid.ColumnModel({    columns:    [        {            dataIndex   : 'username',            header      : this.getTranslation('user_view', 'username_header_text'),            editor      : new Ext.form.TextField(            {                allowBlank  : false            })        },        {            dataIndex   : 'fullname',            header      : this.getTranslation('user_view', 'fullname_header_text'),            editor      : new Ext.form.TextField(            {                allowBlank  : false            })        },    ]});userColumnModel.defaultSortable = true; var userGrid = new Ext.extended.EditorGridPanel({    store           : userDataStore,    colModel        : userColumnModel,     clicksToEdit    : 2,    enableColLock   : false,     plugins         : filters,     title           : this.getTranslation('user_view', 'user_list_title'),    autoExpandColumn: 'username'}); userGrid.load();[/js]

and the main view (loaded by the default controller)

Code: Select all

<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); ?>
<!DOCTYPE html  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>ExtJS CTI</title>
        <link href="favicon.ico" rel="shortcut icon">
        <link rel="stylesheet" type="text/css" href="/css/ext-all.css" />
        <link rel="stylesheet" type="text/css" href="/css/examples.css" />
        <link rel="stylesheet" type="text/css" href="/css/extended.css" />
        <link rel="stylesheet" type="text/css" href="/css/Ext.ux.form.LovCombo.css" />
<?php if (__DEBUG)
{
?>
        <script type="text/javascript" src="/scripts/ext.js"></script>
        <script type="text/javascript" src="/scripts/ext-core.js"></script>
        <script type="text/javascript" src="/scripts/ext-core-debug.js"></script>
        <script type="text/javascript" src="/scripts/ext-debug.js"></script>
<?php
}
else
{
?>
        <script type="text/javascript" src="/scripts/ext.js"></script>
<?php
}
?>
        <script type="text/javascript" src="/scripts/menu/EditableItem.js"></script>
        <script type="text/javascript" src="/scripts/menu/RangeMenu.js"></script>
        
        <script type="text/javascript" src="/scripts/grid/RowExpander.js"></script>
        <script type="text/javascript" src="/scripts/ux/Ext.ux.form.LovCombo.js"></script>
 
        <script type="text/javascript" src="/scripts/grid/GridFilters.js"></script>
        <script type="text/javascript" src="/scripts/grid/filter/Filter.js"></script>
        <script type="text/javascript" src="/scripts/grid/filter/StringFilter.js"></script>
        <script type="text/javascript" src="/scripts/grid/filter/DateFilter.js"></script>
        <script type="text/javascript" src="/scripts/grid/filter/ListFilter.js"></script>
        <script type="text/javascript" src="/scripts/grid/filter/LovFilter.js"></script>
        <script type="text/javascript" src="/scripts/grid/filter/NumericFilter.js"></script>
        <script type="text/javascript" src="/scripts/grid/filter/BooleanFilter.js"></script>
    
        <script type="text/javascript" src="/scripts/extended/prototype.js"></script>
        <script type="text/javascript" src="/scripts/extended/editableGrid.js"></script>
    
        <script type="text/javascript" src="/scripts/views/UserCRUD.js"></script>
    </head>
<body>
</body>
</html>
 
It's a copy-paste from my project and I've excluded parts of my code. So, maybe there are obvious errors and missing code.
Last edited by VladSun on Thu Jan 22, 2009 6:35 am, edited 1 time in total.
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: JSON View, JS Client

Post by VladSun »

Some request-response flows:

1. View

Client request:
POST /user/view

Server response:

Code: Select all

[{"id":"1711","username":"translator","fullname":"translator"},{"id":"6600","username":"plamen","fullname":"plamen"},{"id":"6770","role_id":"4","username":"user","fullname":"name"
},{"id":"1710","username":"admin","fullname":"administrator"},{"id":"6778","username":"supervisor","fullname":"supervisor"}]

2. Save

Client request:
POST /user/save
data=

Code: Select all

{"updated":[{"id":"6778","username":"supervisord","fullname":"supervisor"}],"removed":
[{"id":"6600","username":"plamen","fullname":"plamen"},{"id":"1710","username":"admin"
,"fullname":"administrator"}],"added":[{"id":"0","username":"dadas","fullname":"dadas"
}]}
Server response:

Code: Select all

{"success":true,"errorMessages":null,"data":null}
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: JSON View, JS Client

Post by VladSun »

Ext.extended.JsonStore and Ext.extended.EditorGridPanel (my implementations) extend ExtJS Ext.data.JsonStore Ext.grid.EditorGridPanel classes.
Together they build a full read/write interface - Add/Delete record and Save/Discard changes.
I'm still refactoring them though they work pretty nice.

So ... hit me with your criticism - it will be helpful.
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: JSON View, JS/AJAX Client

Post by Eran »

Seems pretty straightforward. I use this pattern a lot in Ajax-y actions in my controllers. It works really well
Post Reply