Thursday, January 23, 2014

Re: Little trick to return json - Code Included

A far better, more scalable way of doing it (That is actually built into the framework):

routes.php
Router::parseExtensions();
Router::setExtensions(array('json', 'xml'));
 
AppController.php
class AppController extends Controller {
    public $components = array('RequestHandler');

Any controller action that you want to JSONify:
public function index() {
    $this->set('myData', $myData); 
    $this->set('_serialize', 'myData');
} 

Or, to match your original intentions, in AppController.php
class AppController extends Controller {
    public $components = array('RequestHandler');
 
    function beforeRender() {
       $this->set('_serialize', array_keys($this->viewVars));
    }
}

And then to make a request:
$.ajax({
url: "http://localhost/aplication/users",
type: "POST",
dataType: "json" //or xml if you want xml data
});

You shouldn't be 'echo'ing anything from you controllers. Output is the realm of Views (and ViewClasses) 

On Thursday, 23 January 2014 02:09:07 UTC+2, advantage+ wrote:

I am doing something similar but broke it down to a global function for ajax.

 

AppController:

/************************************************************

* SETUP AJAX REQUESTS

* ***********************************************************

* Force the request to not render a view or layout

*

*

*

*

************************************************************/

public function _ajaxSetup($setKey = false) {

       // Turn off debug, dont want to ruin our response

       Configure::write('debug', 0);

 

       $this->layout = 'ajax';

       $this->autoLayout = false;

       $this->autoRender = false;

             

       if($setKey === true){

              $this->request->data{$this->modelClass}['key'] = $this->Session->read('Secure.key');

       }

                           

       // If not from this domain, destroy

       if ($this->request->domain($tldLength = 1) != $this->_domain) {

              $this->Session->destroy();              

       }

}

 

/************************************************************

* RETURN A JSON RESPONSE

* ***********************************************************

*

*

*

*

************************************************************/

public function _ajaxReturn($response = array(), $reGenerate = true) {

 

       $reponse['status'] = false;

             

       $this->layout = 'ajax';

       $this->autoLayout = false;

       $this->autoRender = false;

                                         

       if($reponse['status'] === false){

                    

              $errors = $this->{$this->modelClass}->validationErrors;

              $this->set('errors', $this->{$this->modelClass}->validationErrors);

                    

              if(!empty($errors['lock'])){

                     $response['html'] = $this->render('/Elements/errors/illegal')->body();

                     $response['message'] = 'Form was modified, CSFR / XSS'; //log what happened to be implemented

                     $response['illegal'] = true;

              }

       }

             

       if($reGenerate === true){

              $token = $this->_securityKey();

       } else {

              $token = $this->Session->read('Secure.key');

       }

                    

       $_response = array(

              'status' => $status,

              'errors' => $errors,

              'clear' => false,

              'token' => $token,

              'message' => $this->_securityError());

                    

       $response = array_merge($_response, $response);

      

       $this->header('Content-Type: application/json');

       echo json_encode($response);

       exit();

}

 

Then in any controller snip::

 

$this->Model->create();

if ($this->Model->save($this->request->data, true, $this->whitelist)) {

       $data = $this->Model->getRecords($this->owner_id , $this->Model->id);

       $this->set('data', $data);

       $response = array(

              'status' => true,

              'clear' => true, //clear the form or not

              'html' => $this->render('/Elements/something/view_block')->body(),

              'message' => array(

                     'title' => 'Success!',

                     'text' => 'Your info has been saved.'));

} else {

       $response = array(

              'message' => array(

                     'title' => 'Not quite there!',

                     'text' => 'Please correct the following errors and try again.'));

}

$this->_ajaxReturn($response); // will take care of errors and everything else, reset the CSFR token

 

 

Notes::

 

$this->_securityError()); is a function based off of Security::blackhole for what reason the request failed.

$this->_securityKey(); is a function like Security::csrf token for forms, this just generates / adds a hidden token like Security does to forms allowing ajax requests but also ensures form was not modified, from the server not a remote request and validate the token.

Anything data sent to the controller will be forced to have the lock, like the CSRF Security does, if the form was modified, tampered with saving will fail and trigger the illegal response.

 

Please note none of my forms use js to add fields or dynamically edit the form. Using FormHelper to create all forms and all are HTML as if rendered via HTTP request.(except the _lock field)

 

<input type="hidden" required="required" id="_lock" value="$2a$10$e6YJZevaTrTSSuURxwUHyuG2IfUEXuFGIZqAFIpNEaKd9.Hu6qune" class="form-control" name="data[Model][lock]"> // this gets regenerated on every request, js will pass $token and reset a new value on every request.  And yes I modify the form, use Security component and found a work around to allow updating the form and not setting off a trigger for Security to blackhole it. Security will still check for form field modification so it does the heavy work, I set my own CSFR token and Model validation checks all of that.

 

So the form is secure because its from your server, the form was not modified, it was from a valid user, and the token ensures from the user and for the user.

 

Hope it helps anyone. Or feel free to improve as that would be great!

 

Dave Maharaj

Freelance Designer | Developer
Description: header_logo

www.movepixels.com  |  dave@movepixels.com  |  709.800.0852

 

From: cake...@googlegroups.com [mailto:cake...@googlegroups.com] On Behalf Of euromark
Sent: Wednesday, January 22, 2014 4:47 PM
To: cake...@googlegroups.com
Subject: Re: Little trick to return json

 

You could cut down your code by almost have and drop every second line when following the documentation regarding JsonView:

No need to fight the framework and manually set response type and alike

 

Also, I highly recommend using /users.json as request url. 
This way you also trigger a lot of Cake magic as well. And you are down to none of your code above, as CakePHP would do all that for you right away.



Am Dienstag, 21. Januar 2014 16:59:11 UTC+1 schrieb Rubensvsx:

Sorry for the poor english. 

I created a piece of code that solved my problem in returning a JSON object and helped me not to re-write all views. I await your feedback pros and cons.

 

 

class AppController extends Controller {
    public $components = array('RequestHandler');

 

    function beforeRender() {
        if ($this->RequestHandler->isAjax()) {
            $this->layout = 'ajax';
            $this->RequestHandler->setContent('json', 'application/json');
            $this->viewVars = json_encode($this->viewVars);
            return false;
        }
    }
}

 

 

If an Ajax request is performed automatically be returns a JSON object with the query result.

 

$.ajax({
url: "http://localhost/aplication/users",
type: "POST",
dataType: "json"
});

--
Like Us on FaceBook https://www.facebook.com/CakePHP
Find us on Twitter http://twitter.com/CakePHP
 
---
You received this message because you are subscribed to the Google Groups "CakePHP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cake-php+u...@googlegroups.com.
To post to this group, send email to cake...@googlegroups.com.
Visit this group at http://groups.google.com/group/cake-php.
For more options, visit https://groups.google.com/groups/opt_out.

--
Like Us on FaceBook https://www.facebook.com/CakePHP
Find us on Twitter http://twitter.com/CakePHP
 
---
You received this message because you are subscribed to the Google Groups "CakePHP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cake-php+unsubscribe@googlegroups.com.
To post to this group, send email to cake-php@googlegroups.com.
Visit this group at http://groups.google.com/group/cake-php.
For more options, visit https://groups.google.com/groups/opt_out.

No comments: