Zend Framework JSON Output - php

In controller I am generating a special form by ID, passed from AJAX. Form output is JSON. Form creates finely. But my problem is to show this JSON in view. How?
Thank you.

In controller (http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.json):
$this->getHelper('json')->sendJson(array(
'param1' => 'v1'
'param2' => 'v2'
));
In view (http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.json):
<?php
echo $this->json(array(
'param1' => 'v1'
'param2' => 'v2'
));
?>

json is a encoded string containing vars in js style if you need to access the member in this string you need to json_decode the string so
$result = json_decode($jsonString);
but note that json treat php associative array like php object ... so if you pass an array you can access it as $result->memberReference not $result['memberReference'];

The easiest way is to stop view from being executed:
function jsonAction () {
....
print $json;
exit;
}
Also see check http://pl.php.net/json_encode if you don't have JSON string already.

You can use Zend class
$sData = Zend_Json::encode($aArray);
Or you can use advanced scenario like:
$data = array(
'onClick' => new Zend_Json_Expr('function() {'
. 'alert("I am a valid javascript callback '
. 'created by Zend_Json"); }'),
'other' => 'no expression',
);
$jsonObjectWithExpression = Zend_Json::encode($data,false,
array('enableJsonExprFinder' => true)
);

The best way todo this in my opinion is to assign one controller as your json output, then you can do this:
class Api_IndexController extends Zend_Controller_Action {
public function init() {
$this->data = array();
}
public function preDispatch() {
$this->variables = $this->_getAllParams();
}
public function postDispatch() {
$this->_helper->json($this->data);
}
public function __call($name, $args) {
return;
}
public function forumAction () {
$this->mapper = new ORM_Model_Mapper_Forum();
$this->model = new ORM_Model_Forum();
$this->dbTable = new ORM_Model_DbTable_Forum();
if (isset($this->variables['id']) && is_numeric($this->variables['id'])) {
$output = $this->model->find($this->variables['id']);
if ($output->id == null) {
return $this->_setError(404);
}
} else {
$output = $this->mapper->fetchAllToArray();
}
$this->data = $output;
}
private function _setError($code=500) {
$this->data = array('error' => $code);
}
}

Related

Undefined variable answers eventhough variable is defined

<?php
class Question_model extends CI_Model {
public $answers;
public function filter_answers($value){
if(is_string($value))
{
if(strpos($value,"option") !== false){
$this->$answers[] = str_replace("option","",$value);
}
}
}
public function create_question($data){
$data = array(
'explanation' => $data['exp'],
'name' => $data['name']
);
$this->db->insert('question', $data);
array_filter($data,array($this,"filter_answers"));
echo $this->$answers;
}
}
I am using codeigniter framework and i am getting this in model as you can see that variable is actually defined and not the other way around. I am calling model from codeigniter controller.
You must be call answer property with $this->answers, not by $this->$answers.
<?php
class Question_model extends CI_Model {
public $answers;
public function filter_answers($value){
if(is_string($value))
{
if(strpos($value,"option") !== false){
$this->answers[] = str_replace("option","",$value);
}
}
}
public function create_question($data){
$data = array(
'explanation' => $data['exp'],
'name' => $data['name']
);
$this->db->insert('question', $data);
array_filter($data,array($this,"filter_answers"));
echo $this->answers;
}
}
The double arrow operator, “=>”, is used as an access mechanism for
arrays. This means that what is on the left side of it will have a
corresponding value of what is on the right side of it in array
context. This can be used to set values of any acceptable type into a
corresponding index of an array. The index can be associative (string
based) or numeric.
<?php
$myArray = array(
0 => 'Big',
1 => 'Small',
2 => 'Up',
3 => 'Down'
);
?>
The object operator, “->”, is used in object scope to access methods
and properties of an object. It’s meaning is to say that what is on
the right of the operator is a member of the object instantiated into
the variable on the left side of the operator. Instantiated is the key
term here.
<?php
$obj = new MyObject(); // Create a new instance of MyObject into $obj
$obj->thisProperty = 'Fred'; // Set a property in the $obj object called thisProperty
$obj->getProperty(); // Call a method of the $obj object named getProperty
?>
Example
<?php
class Question_model extends CI_Model {
public $answers;
public function filter_answers($value){
if(is_string($value))
{
if(strpos($value,"option") !== false){
$this->answers[] = str_replace("option","",$value);
}
}
}
public function create_question($data){
$data = array(
'explanation' => $data['exp'],
'name' => $data['name']
);
$this->db->insert('question', $data);
array_filter($data,array($this,"filter_answers"));
echo $this->answers;
}
}

Slim framework unable to encode to json with protected variables

Basically I was encoding a response with json and couldn't figure out why it kept returning the right number of array members but they were empty.
$app->get('/api/server_list', function ($request, $response, $args) {
$serverlist = new ServerListing($this->db);
$servers = $serverlist->getServers();
$newResponse = $response->withJson($servers);
return $newResponse;
});
This is the output of the above with an added print_r($servers)
[{},{}]Array
(
[0] => ServerEntity Object
(
[id:protected] => 1
[serverName:protected] => dc1.domain.com
)
[1] => ServerEntity Object
(
[id:protected] => 2
[serverName:protected] => dc2.domain.com
)
)
Here is the class code for ServerListing:
<?php
class ServerListing extends Listing
{
public function getServers() {
$sql = "SELECT * from servers";
$stmt = $this->db->query($sql);
$results = [];
while($row = $stmt->fetch()) {
$results[] = new ServerEntity($row);
}
return $results;
}
}
Here is ServerEntity:
<?php
class ServerEntity
{
public $id;
public $serverName;
public function __construct(array $data) {
if(isset($data['id'])) {
$this->id = $data['id'];
}
$this->serverName = $data['name'];
}
public function getId() {
return $this->id;
}
public function getServerName() {
return $this->serverName;
}
}
Only way it works is with public.
I understand public/private/protected. Though this is my first time with a framework and Object Oriented php.
Using the same database call in another route I can then pass the server list to a view and it works fine.
So I guess two questions.
Why does the json encode fail?
Am I doing something fundamentally wrong/ is there a better way to do this?
Slim's Response::withJson() doesn't do anything magic. It relies on the PHP function json_encode() to do the encoding. json_encode() also doesn't know any special trick. If you pass an object to it to encode it gets all the data it can get from it. And that means only its public properties because, well, this is how OOP works.
However, if you implement the JsonSerializable interface in a class then you can control what data is available to json_encode() when it comes to encode an object of that class.
For example:
class ServerEntity implements JsonSerializable
{
private $id;
private $serverName;
// ... your existing code here
public function jsonSerialize()
{
return array(
'id' => $this->id,
'name' => $this->serverName,
);
}
}
Some test code:
echo(json_encode(new ServerEntity(array('id' => 7, 'name' => 'foo'))));
The output is:
{"id":7,"name":"foo"}
In short, an object can be converted into an array.
The object's public properties will be used as $key => $value pairs in the array.
Since the properties are protected, the values are not included.
While it would seem logical that the array actually be empty, the process in which PHP converts the object to an array is not really documented well enough.
In practice what I would recommend is you create a public method that converts the Object to an array.
class ServerEntity {
//...
public function toArray() {
return array("id" => $this->id, "name" => $this->name);
}
//...
}
Then you may simply do...
$app->get('/api/server_list', function ($request, $response, $args) {
$serverlist = new ServerListing($this->db);
$servers = $serverlist->getServers();
$objects = array();
foreach ($servers as $server) {
$objects[] = $server->toArray();
}
$newResponse = $response->withJson($objects);
return $newResponse;
});

How to call a class member as a closure?

I'm trying to make the following example works. It looks like PHP thinks $this->getData2 as a member variable. How do I make it so that PHP thinks it as a method?
class Test {
public function getData()
{
return array(
'data1'=>array('name'=>'david'),
'data2'=>$this->getData2
);
}
public function getData2()
{
return "hello"
}
}
$test = new Test;
$data = $test->getData();
$data = $data['data2']();
I've tried the following, but looks like..I can't use $this in this case
function() use($this) {
return $This->getData2();
}
class Test {
public function getData(){
return array(
'data1'=>array('name'=>'david'),
'data2'=>'getData2'
);
}
public function getData2() {
return "hello";
}
}
$test = new Test;
$data = $test->getData();
$data = $test->$data['data2']();
echo $data;
Wasn't working without the $test-> on the $data = $test->$data['data2'](); line
And because I love fiddles: http://phpfiddle.org/main/code/4f5-v37
A callable to a method is an array with the object as a first member, and the method name as a second one.
So:
class Test {
public function getData()
{
return array(
'data1'=>array('name'=>'david'),
'data2'=>array($this, 'getData2')
);
}
public function getData2()
{
return "hello";
}
}
$test = new Test;
$data = $test->getData();
$data = $data['data2']();
Try:
class Test {
public function getData(){
return array('data1' => array('name' => 'david'), 'data2' => 'getData2');
}
public function getData2(){
return 'hello';
}
}
$test = new Test; $data = $test->getData(); echo $test->$data['data2']();
Easiest way would just be to do the calculation in a variable outside of the array and then just put the variable into the array

save() function Zend Framework

I have found this function in the documentation from Zend, more specific in the Create model and Database Table section ( http://framework.zend.com/manual/1.12/en/learning.quickstart.create-model.html ).
This is in the Application_Model_GuestbookMapper:
public function save(Application_Model_Guestbook $guestbook)
{
$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'created' => date('Y-m-d H:i:s'),
);
if (null === ($id = $guestbook->getId())) {
unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id));
}
}
and now i would like to integrate this into my controller, but i have no idea how?
I created an instance of the mapper and tried to pass the info from my decoded json string to it, but I still get errors...:
public function indexAction()
{
$mapper = new Application_Model_GuestbookMapper();
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$json = file_get_contents('http://data.appsforghent.be/poi/apotheken.json');
$data = Zend_Json::decode($json);
foreach($data['apotheken'] as $row)
{
$mapper->save();
}
}
I know i have to pass the $data to the save() function but I have no idea how... The model won't fit the json-url, I just wanted to show how I retrieve and decode the json.
Can anybody help me?
What you need to pass in to the $mapper->save(); is an instance of Application_Model_Guestbook. So hopefully you have a class Application_Model_Guestbook in which you define the possibility to set a data array as its attributes, for example like this:
class Application_Model_Guestbook {
private $email,$comment,$created;
public function __construct($data) {
$this->email = $data['email'];
// etc add other variables
}
public function getEmail() {
return $this->email;
}
}
Then to call that, use:
foreach($data['apotheken'] as $row)
{
$guestbook = new Application_Model_Guestbook($row);
$mapper->save($guestbook);
}
I have not tested this specifically, but it should give you an idea of how to achieve what you want to do.

How to make an action for missing actions?

I am very new to cakePHP.
I am working on a controller like so:
class DesignersController extends AppController
{
var $name = 'Designers';
function index()
{
$data = $this->Designer->find('all');
$this->set('designers', $data);
}
function belle_etoile()
{
$this->show_designer("belle etoile");
}
function ritani()
{
$this->show_designer("ritani");
}
function swarovski()
{
$this->show_designer("swarovski");
}
function verragio()
{
$this->show_designer("verragio");
}
private function show_designer($designer)
{
$this->layout = 'first';
$data = $this->Designer->find('first', array('conditions' => array('Designer.name' => $designer)));
$this->set('data', $data);
$this->render('show_designer');
}
}
As you can see many of the "actions" are shortcuts for show_designer/param action where param is the name of the shortcut action.
Every one of these actions is a "designer" in the database. I just don't want to have to make the url designers/show_designer/ritani, I would rather it just be designers/ritani.
This works, but the problem is:
I have to create a bunch of redundant functions for every designer, and if a new designer gets added, it won't work until I add a function for it.
I would rather have a function/action that runs if the action requested is missing, and has the action that was requested as a parameter
so if I request url designers/stardust, since stardust is not defined as an action it would call the catch_all action with stardust as the parameter.
So instead of a bunch of redundant functions I could just have this:
function catch_all($action)
{
$this->show_designer($action)
}
Is there anyway to do something like this?
Use routing instead
// add this to app/config/routes.php
Router::connect('/designer/*', array('controller' => 'designers', 'action' => 'designer'));
In your controller
// and remove all actions 'belle_etoile', 'swarovski' etc
// change `show_designer` to `public designer`
class DesignersController extends AppController {
var $name = 'Designers';
function designer($name)
{
$this->layout = 'first';
$data = $this->Designer->find('first', array('conditions' => array('Designer.name' => $name)));
if(!empty($data)) {
$this->set('data', $data);
$this->render('show_designer');
} else {
$this->redirect('index');
}
}
}
have you tried adding a call method:
function __call($action,$params = array())
{
$this->show_designer($action)
}
Im not 100% shore how cake calls its methods but it should work:
Example of the usage:
finale class Test
{
function __call($action,$params = array())
{
echo $action . " called:<br />";
foreach($params as $param)
{
echo "Param: "$param . "<br />";
}
}
}
$test = new Test();
$test->SomeNonExistantmethod("param 1","param 2");
This would output:
SomeNonExistantmethod called:
param: param 1
param: param 2
your class would be like so:
class DesignersController extends AppController
{
var $name = 'Designers';
var $allowed = array(
"belle_etoile",
"ritani",
"swarovski",
"verragio"
);
function index()
{
$data = $this->Designer->find('all');
$this->set('designers', $data);
}
function __call($action,$params = array())
{
if(in_array($action,$this->allowed))
{
$this->show_designer($action);
}
}
private function show_designer($designer)
{
$this->layout = 'first';
$data = $this->Designer->find('first', array('conditions' => array('Designer.name' => $designer)));
$this->set('data', $data);
$this->render('show_designer');
}
}

Categories