Skip to content

March 14, 2011


Extending ExtJS CRUD operations on id and baseParams

by Joe Kuan

There are couple things I would like to extend the ExtJS CRUD operations for my application.

  1. If the baseParams property is specified inside a Store object, the HttpProxy will pass the content of baseParams as part of the JSON string. However, the server side Php’s CRUD operations ignores it, ie none of the data in baseParams can be found in Request->$params
  2. The syntax for id field in Restful URL is too restricted for only [0-9]+

Here is an example of my code of Store object:

      this.graphNavStore = new{
        autoDestroy: true,
        autoSave: false,
        // Restful to make the URL update as /controller/action/id
        restful: true,
        baseParams: { display_type: config.display_type,
                      series_id: config.filters.series_id,
                      user_id: AppQoS.user.get_userid() },
        proxy: new{
          api: {
            read: '/CRUD.php/graphclicks/view',
            create: '/CRUD.php/graphclicks/create',
            update: '/CRUD.php/graphclicks/update',
            destroy: '/CRUD.php/graphclicks/destroy'

When the Store’s record value is modified and the save operation is called, the CRUD update action is forwarded to the server with the following Http request:

All the baseParams and the modified record value are passed to the server in JSON string (See above, Request Payload). The record value and the id are encapsulated inside the ‘data’ object. According to ExtJS CRUD source code in lib/request.php, only the ‘data’ field of the JSON string is stored in the Request->params, everything else are ignored.

Hence, I have modified the code, so that all the attributes in baseParams apart from ‘data’ are preserved inside the Request->params->baseParams field. The syntax for the ids is also extended.

Here is the code

restful = (isset($params["restful"])) ? $params["restful"] : false;
        $this->method = $_SERVER["REQUEST_METHOD"];
    public function isRestful() {
        return $this->restful;
    protected function parseRequest() {
        if ($this->method == 'PUT') {
            $raw  = '';
            $httpContent = fopen('php://input', 'r');
            while ($kb = fread($httpContent, 1024)) {
                $raw .= $kb;
            $params = array();
            parse_str($raw, $params);

            if (isset($params['data'])) {
                $this->params =  json_decode(stripslashes($params['data']));
            } else {
                $params = json_decode(stripslashes($raw));
                $this->params = $params->data;
        } else {
            // grab JSON data if there...
            $this->params = (isset($_REQUEST['data'])) ? json_decode(stripslashes($_REQUEST['data'])) : null;

            if (isset($_REQUEST['data'])) {
                $this->params =  json_decode(stripslashes($_REQUEST['data']));
            } else {
                $raw  = '';
                $httpContent = fopen('php://input', 'r');
                while ($kb = fread($httpContent, 1024)) {
                    $raw .= $kb;
                $params = json_decode(stripslashes($raw));
                $this->params = $params->data;

        // Pack everything else in $params (except data) to Request->params->baseParams 
        // Under update and create actions, $this->params is an object because the 
        // action can contain multiple values
        // The destroy action, $this->params contain a single value - id which is also
        // assigned to $this->id. 
        if (is_scalar($this->params)) {
          $this->params = new stdClass();
        $this->params->baseParams = new stdClass();
        foreach ((array) get_object_vars($params) as $name => $value) {
          if ($name == 'data')
          $this->params->baseParams->$name = $value;

        // Quickndirty PATH_INFO parser
        if (isset($_SERVER["PATH_INFO"])){
            $cai = '/^\/([a-z]+\w)\/([a-z]+\w)\/([0-9,a-z]+)$/';  // /controller/action/id
            $ca =  '/^\/([a-z]+\w)\/([a-z]+)$/';              // /controller/action
            $ci = '/^\/([a-z]+\w)\/([0-9,a-z]+)$/';               // /controller/id
            $c =  '/^\/([a-z]+\w)$/';                             // /controller
            $i =  '/^\/([0-9,a-z]+)$/';                             // /id
            $matches = array();
            if (preg_match($cai, $_SERVER["PATH_INFO"], $matches)) {
                $this->controller = $matches[1];
                $this->action = $matches[2];
                $this->id = $matches[3];
            } else if (preg_match($ca, $_SERVER["PATH_INFO"], $matches)) {
                $this->controller = $matches[1];
                $this->action = $matches[2];
            } else if (preg_match($ci, $_SERVER["PATH_INFO"], $matches)) {
                $this->controller = $matches[1];
                $this->id = $matches[2];
            } else if (preg_match($c, $_SERVER["PATH_INFO"], $matches)) {
                $this->controller = $matches[1];
            } else if (preg_match($i, $_SERVER["PATH_INFO"], $matches)) {
                $this->id = $matches[1];

Alternatively, you can download the code from

1 Comment Post a comment
  1. Tadeo
    Nov 6 2011

    Hi, i’m doing a practice with ExtJs4.x+PHP+MYsql, but i do not know what happens with my code, i think is not working, do you have some code example with ExtJs4.x+PHP+MYsql? Thanks, here is part of my code:

    //0.-Nuevo mandato en Ext4.x llamamos las partes que conformaran a cada Objeto y solo lo que necesitamos


    //1.-Definimos el Modelo de Datos, con el Array de datos que viene desde la Consulta PHP
    extend: ‘’,
    fields: [
    {name: ‘Titulo’, type: ‘string’},
    {name: ‘Interprete’, type: ‘string’},
    {name: ‘Anio’,type: ‘string’}

    var Status=0; // 1 Se esta Insertando

    // 2.-Creamos el Data Store
    var store = Ext.create(‘’, {
    model: ‘CompactDisc’,//Llamamos el Modelo Antes Creado
    autoLoad: true,
    proxy: {
    type: ‘ajax’,
    api: {
    read : “/CursosExjs/Cursos4x/Grids/Php/TCd.php”,
    create : “/CursosExjs/Cursos4x/Grids/Php/GrdRawAdd.php”,
    //update : tridPAX.BASE_PATH + ‘Admin/Grid/Update’,
    // destroy : tridPAX.BASE_PATH + ‘Admin/Grid/Destroy’
    autoSave : true //<— hace las peticiones al servidor automáticamente
    reader: {
    type: 'json',
    successProperty: 'success',//<— el successproperty indica la propiedad que define si se ha insertado/actualizado o borrado con éxito
    idProperty : 'id',
    root:'data' //Json_encode root:Datos del Servidor desde desde TCD.php

    encode: false,
    writeAllFields : true,//decide si se manda al servidor solamente los campos modificados o todo
    type: 'json',
    root: 'data'// Le enviamos los datos al Servidor de lo que se agrego o Actualizo


    listeners: {
    exception: function(proxy, response, operation){{
    title: 'ERROR',
    msg: operation.getError(),
    icon: Ext.MessageBox.ERROR,
    buttons: Ext.Msg.OK

    //3.-Llamamos el Plugin para el Raw editor
    var MyRowEditing = Ext.create('Ext.grid.plugin.RowEditing',
    clicksToEdit: 2 //Con Doble Click Editamos la Linea


    //3.1.- Esta linea sirve para Cambiar el texto de los botones que viene por default en el RawEditor
    Ext.grid.RowEditor.prototype.cancelBtnText = "Cancelar";
    Ext.grid.RowEditor.prototype.saveBtnText = "Guardar";
    //Ext.grid.RowEditor = new Ext.grid.RowEditor();

    //4.-Creamos el Grid,Tambien se puede crear de esta forma:var Mygrid =new Ext.grid.Panel({
    var MyGridRawEditor = Ext.create('Ext.grid.Panel', {
    store: store,
    plugins: [MyRowEditing],//Anexamos el Pluggin para el RawEditor
    columns: [
    {text: "Id",width: 10, dataIndex: 'Id', sortable: true,hidden:true, field: {
    xtype: 'numberfield'
    {text: "Titulo",width: 220, dataIndex: 'Titulo', sortable: true, field: {
    xtype: 'textfield'
    {text: "Interprete", width: 180, dataIndex: 'Interprete', sortable: true, field: {
    xtype: 'textfield'
    {text: "Anio", width: 50, dataIndex: 'Anio', sortable: true, field: {
    xtype: 'numberfield'
    title: 'Grid Con RawEditor',
    dockedItems: [{
    xtype: 'toolbar',
    items: [{
    text: 'Agregar',
    iconCls: 'add',
    handler: function(){
    // empty record
    store.insert(0, new CompactDisc());
    MyRowEditing.startEdit(0, 1);

    }, '-', {
    itemId: 'delete',
    text: 'Borrar',
    iconCls: 'delete',
    disabled: true,
    handler: function(){
    var selection = MyGridRawEditor.getView().getSelectionModel().getSelection()[0];
    if (selection) {


    MyGridRawEditor.getSelectionModel().on('selectionchange', function(selModel, selections){
    MyGridRawEditor.down('#delete').setDisabled(selections.length === 0);

    //5.-Creamos la Ventana
    var MyWindowGridRawEditor=Ext.create('Ext.window.Window', {
    title: 'Lista de Discos',
    width: 700,
    height: 510,
    layout: 'fit',
    closable: true,
    items:MyGridRawEditor //Grid Creado anteriormente


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

%d bloggers like this: