0

In CakePHP 2.4, what is the correct syntax to foreach through my data in order to customize the contents and structure of JSON output from my controller?

I currently have the following method, which creates a .json that directly mirrors Cake's internal array of all my posts:

public function points() {
$this->autoRender = false; // We don't render a view in this example
$this->Post->recursive = -1; //Don't return stuff we don't need

return json_encode($this->Post->find('all'));
}

This creates JSON that looks like this, with each post's data the child of its own Post object (prettified with carriage returns so you can read it):

[{"Post":{"id":"1",
          "user_id":"1",
          "organism_id":"0",
          "title":"Title Text",
          "lat":"44.54401744186992",
          "lng":"-68.26070404052734",
          "body":"Body Text",
          "created":"2014-01-19 07:13:29",
          "modified":"2014-01-19 07:13:29"}
 },
 {"Post":{"id":"2",
          "user_id":"1",
          "organism_id":"0",
          "title":"Title Text",
          "lat":"44.54401744186992",
          "lng":"-68.26070404052734",
          "body":"Body Text",
          "created":"2014-01-19 07:13:29",
          "modified":"2014-01-19 07:13:29"}
 }]

This is a problem, because (A) For performance reasons, I might not want to dump all the data for each post into the JSON, and (B) for output to Google Maps, I need to output each post's data as child objects of one Posts object, like so:

{"Posts":[
    {"id":"1",
    "user_id":"1",
    "organism_id":"0",
    "title":"Title Text",
    "lat":"44.54401744186992",
    "lng":"-68.26070404052734",
    "body":"Body Text",
    "created":"2014-01-19 07:13:29",
    "modified":"2014-01-19 07:13:29"
},
    {"id":"2",
    "user_id":"1",
    "organism_id":"0",
    "title":"Title Text",
    "lat":"44.54401744186992",
    "lng":"-68.26070404052734",
    "body":"Body Text",
    "created":"2014-01-19 07:13:29",
    "modified":"2014-01-19 07:13:29"}]}

I know I somehow need to foreach through the data and build an array. How does this work? foreach ($posts as $post): doesn't work inside the controller.

3
  • 1
    Read this - it explains why you should request this via .json extension. and not just like any normal http request. Then foreach() your data and create a final array you can set() to the view for serialization. Commented Feb 17, 2014 at 23:36
  • Thanks Mark- I read that first before posting. When I go into production I'll use $this->request->onlyAllow('ajax');, but first I need to read my JSON to figure out why my Javascript doesn't like it! Commented Feb 17, 2014 at 23:41
  • How do I foreach the data in the controller? I know how to do it in a view but CakePHP doesn't seem to like the same syntax: foreach ($posts as $post) { $marker = array( 'id' => $post['Post']['id'], 'lat' => $post['Post']['lat'], 'lng' => $post['Post']['lng'], 'title' => $post['Post']['title'], 'body' = $post['Post']['body']); $markers[] = $marker; } Commented Feb 18, 2014 at 0:09

3 Answers 3

1

Try this......

$data = array();
foreach ($posts as $post) {
      $data[] = $post['Posts'];
}

$postdata['Posts'] = $data;

 echo json_encode($postdata); 
Sign up to request clarification or add additional context in comments.

4 Comments

I tried almost exactly that and Cake threw a wall of errors, including 'undefined index' and 'maximum depth reached'- your code did the same thing. Thank you though, because your code let me know I can use $markers[] = array( inside a foreach loop, instead of making a new marker array and adding it to markers each time! That should cut down on my overhead a bit.
Can you please paste the array return from the query, may I help you more.
Notice (8): Undefined index: Posts [APP/View/Posts/json/points.ctp, line 5], repeated 65x, once for each item in the controller, then $data = array( (int) 0 => null, (int) 1 => null, (int) 2 => null, (int) 3 => null,, up to 64, then a stack trace. I have a solution that works just fine, though- check the other answer.
can you please paste the code in view file? If possible paste the array print too.
0

I found the solution!

In the controller:

public function points() {
    $this->request->onlyAllow('ajax'); //Don't respond to non-AJAX requests
    $this->Post->recursive = -1; //don't return info from other controllers
    $this->set('posts', $this->Post->find('all'));
}

In /view/posts/json/points.ctp:

foreach ($posts as $post) {
$markers[] = array(
    'id' => $post['Post']['id'],
    'lat' => $post['Post']['lat'],
    'lng' => $post['Post']['lng']
    ); //make an array of the contents of each post I want to include

}

$data = array(
'Posts' => $markers); //Make everything the child of a 'Posts' object

 echo json_encode($data); //Turn it into JSON!

Comments

0

You can also use the Hash Utility:

    $posts = $this->Post->find('all');
    $posts = array('Posts' => Hash::extract($posts, '{n}.Post'));
    $this->set('posts', posts);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.