Skip to content

March 14, 2011

1

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 Ext.data.Store({
        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 Ext.data.HttpProxy({
          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"];
        $this->parseRequest();
    }
    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;
            }
            fclose($httpContent);
            $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')
            continue;
          $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 https://github.com/JoeKuan/Extended-ExtJS-CRUD-to-handle-Store-object-baseParams

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
    Ext.require([
    ‘Ext.grid.*’,
    ‘Ext.data.*’

    ]);

    //1.-Definimos el Modelo de Datos, con el Array de datos que viene desde la Consulta PHP
    Ext.define(‘CompactDisc’,{
    extend: ‘Ext.data.Model’,
    fields: [
    {name:’Id’,type:’int’},
    {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(‘Ext.data.Store’, {
    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

    },
    writer:{
    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){
    Ext.MessageBox.show({
    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) {
    store.remove(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',
    plain:true,
    modal:true,
    closable: true,
    closeAction:'close',
    items:MyGridRawEditor //Grid Creado anteriormente
    });

    Reply

Leave a comment

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

Subscribe to comments