Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cakephp3: How can I return json data?

Tags:

json

cakephp

I am having a ajax post call to a cakePhp Controller:

$.ajax({
                type: "POST",
                url: 'locations/add',
                data: {
                  abbreviation: $(jqInputs[0]).val(),
                  description: $(jqInputs[1]).val()
                },
                success: function (response) {
                    if(response.status === "success") {
                        // do something with response.message or whatever other data on success
                        console.log('success');
                    } else if(response.status === "error") {
                        // do something with response.message or whatever other data on error
                        console.log('error');
                    }
                }
            });

When I try this I get the following error message:

Controller actions can only return Cake\Network\Response or null.

Within the AppController I have this

$this->loadComponent('RequestHandler');

enabled.

the Controller function looks like this:

public function add()
{
    $this->autoRender = false; // avoid to render view

    $location = $this->Locations->newEntity();
    if ($this->request->is('post')) {
        $location = $this->Locations->patchEntity($location, $this->request->data);
        if ($this->Locations->save($location)) {
            //$this->Flash->success(__('The location has been saved.'));
            //return $this->redirect(['action' => 'index']);
            return json_encode(array('result' => 'success'));
        } else {
            //$this->Flash->error(__('The location could not be saved. Please, try again.'));
            return json_encode(array('result' => 'error'));
        }
    }
    $this->set(compact('location'));
    $this->set('_serialize', ['location']);
}

What do I miss here? Is there any additional settings needed?

like image 733
user1555112 Avatar asked Dec 08 '16 14:12

user1555112


People also ask

How do I return a JSON response?

To return JSON from the server, you must include the JSON data in the body of the HTTP response message and provide a "Content-Type: application/json" response header. The Content-Type response header allows the client to interpret the data in the response body correctly.

How do I return JSON to Ajax call?

On document ready state send an AJAX GET request to 'ajaxfile. php' . Loop through all response values and append a new row to <table id='userTable'> on AJAX successfully callback. Note – For handling JSON response you have to set dataType: 'JSON' while sending AJAX request.

How do I return JSON in HTML?

If you want to return JSON, you need to have the JSON string as the only text returned. This is not possible using client side JavaScript for the reason you've seen. You should amend your JSON feed to be a server-side resource.

What is JSON return type?

The JSON return tag delivers data directly to a first-party page in JSON format. Real-time parsing or targeting can pull data out of the DOM at the time the page is rendered.


4 Answers

Instead of returning the json_encode result, set the response body with that result and return it back.

public function add()
{
    $this->autoRender = false; // avoid to render view

    $location = $this->Locations->newEntity();
    if ($this->request->is('post')) {
        $location = $this->Locations->patchEntity($location, $this->request->data);
        if ($this->Locations->save($location)) {
            //$this->Flash->success(__('The location has been saved.'));
            //return $this->redirect(['action' => 'index']);
            $resultJ = json_encode(array('result' => 'success'));
            $this->response->type('json');
            $this->response->body($resultJ);
            return $this->response;
        } else {
            //$this->Flash->error(__('The location could not be saved. Please, try again.'));
            $resultJ = json_encode(array('result' => 'error', 'errors' => $location->errors()));

            $this->response->type('json');
            $this->response->body($resultJ);
            return $this->response;
        }
    }
    $this->set(compact('location'));
    $this->set('_serialize', ['location']);
}

Edit (credit to @Warren Sergent)

Since CakePHP 3.4, we should use

return $this->response->withType("application/json")->withStringBody(json_encode($result));

Instead of :

$this->response->type('json');
$this->response->body($resultJ);
return $this->response;

CakePHP Documentation

like image 163
beta-developper Avatar answered Sep 22 '22 04:09

beta-developper


Most answers I've seen here are either outdated, overloaded with unnecessary information, or rely on withBody(), which feels workaround-ish and not a CakePHP way.

Here's what worked for me instead:

$my_results = ['foo'=>'bar'];

$this->set([
    'my_response' => $my_results,
    '_serialize' => 'my_response',
]);
$this->RequestHandler->renderAs($this, 'json');

More info on RequestHandler. Seemingly it's not getting deprecated anytime soon.

UPDATE: CakePHP 4

$this->set(['my_response' => $my_results]);
$this->viewBuilder()->setOption('serialize', true);
$this->RequestHandler->renderAs($this, 'json');

More info

like image 31
mehov Avatar answered Sep 19 '22 04:09

mehov


there are few things to return JSON response:

  1. load RequestHandler component
  2. set rendering mode as json
  3. set content type
  4. set required data
  5. define _serialize value

for example you can move first 3 steps to some method in parent controller class:

protected function setJsonResponse(){
    $this->loadComponent('RequestHandler');
    $this->RequestHandler->renderAs($this, 'json');
    $this->response->type('application/json');
}

later in your controller you should call that method, and set required data;

if ($this->request->is('post')) {
    $location = $this->Locations->patchEntity($location, $this->request->data);

    $success = $this->Locations->save($location);

    $result = [ 'result' => $success ? 'success' : 'error' ];

    $this->setJsonResponse();
    $this->set(['result' => $result, '_serialize' => 'result']);
}

also it looks like you should also check for request->is('ajax); I'm not sure about returning json in case of GET request, so setJsonResponse method is called within if-post block;

in your ajax-call success handler you should check result field value:

success: function (response) {
             if(response.result == "success") {
                 console.log('success');
             } 
             else if(response.result === "error") {
                    console.log('error');
             }
         }
like image 41
teran Avatar answered Sep 20 '22 04:09

teran


In the latest version of CakePHP $this->response->type() and $this->response->body() are deprecated.

Instead you should use $this->response->withType() and $this->response->withStringBody()

E.g:

(this was pinched from the accepted answer)

if ($this->request->is('post')) {
    $location = $this->Locations->patchEntity($location, $this->request->data);
    if ($this->Locations->save($location)) {
        //$this->Flash->success(__('The location has been saved.'));
        //return $this->redirect(['action' => 'index']);
        $resultJ = json_encode(array('result' => 'success'));

        $this->response = $this->response
            ->withType('application/json') // Here
            ->withStringBody($resultJ)     // and here

        return $this->response;
    }
}

Relevant Documentation

like image 20
Aidan Haddon-Wright Avatar answered Sep 21 '22 04:09

Aidan Haddon-Wright