What is the correct way to generate a Json Response from a Controller Action?
For example the following action is in a controller which returns Json.
function listAction()
{
...
$results = array();
foreach ($orders[ 'results' ] AS $i => $row) {
$results[ $i ] = [
'order_name' => $row[ 'order' ]['name'],
'shop_name' => $row[ 'order']['shop'][ 'name' ],
'product_name' => $row[ 'product' ][ 'name' ],
'url_shop_show' => $this->generateUrl('Shop_Show', array(
'shop_id' => $row[ 'order' ][ 'shop' ][ 'id' ],
'shop_slug' => $row[ 'order' ][ 'shop' ][ 'slug' ],
)),
'url_product_show' => $this->generateUrl('Product_Show', array(
'product_id' => $row[ 'product' ][ 'id' ],
)),
];
}
return new JsonResponse(
[
'draw' => $draw,
'data' => $results,
'recordsTotal' => $orders[ 'total_items' ],
'recordsFiltered' => $orders[ 'total_items' ],
]);
}
GenerateUrl calls:
$this->container->get('router')->generate($route, $parameters, $referenceType)
The orders array is converted to a results array and urls generated. This very much feels like presentation and therefore should be moved out of the controller.
Would it be best thing to get a template engine (Twig) to generate the output? Or create a service for Json creation?
What is the best practice?
Technically you could build a .json.twig layout but and transform the "generateUrl" method in a Twig extension.
But that requires for you to manually build your JSON in the layout and that's definitely not suggested.
Creating a JSONResponse seems a good enough solution to me.
Related
I have following data :
Array
(
[category] => Array
(
[0] => d
[1] => 100
[2] => 100
[3] => 100
)
[volume] => Array
(
[0] => 100
[1] => 100
[2] => 100
)
[urgency] => Array
(
[0] => 100
[1] => 100
[2] => 100
)
[importance] => Array
(
[0] => 100
[1] => 100
[2] => 100
)
)
And I created DynamicModel for it with rules "each value should be integer" (added in 2.0.4).
$view_model = DynamicModel::validateData(compact('category', 'volume', 'urgency', 'importance'), [
[['category', 'volume', 'urgency', 'importance'], 'each', 'rule' => ['integer']],
]);
In view I have:
<?= $form->field($model, 'category[0]')->textInput() ?>
<?= $form->field($model, 'category[1]')->textInput() ?>
<?= $form->field($model, 'category[2]')->textInput() ?>
...
<?= $form->field($model, 'importance[2]')->textInput() ?>
Problem is, when I submit form with "d" in first input, I have errors on each "category" input:
What I do wrong?
You can use Each validator
Info: This validator has been available since version 2.0.4.
[
// checks if every category ID is an integer
['categoryIDs', 'each', 'rule' => ['integer']],
]
This validator only works with an array attribute. It validates if every element of the array can be successfully validated by a specified validation rule. In the above example, the categoryIDs attribute must take an array value and each array element will be validated by the integer validation rule.
rule: an array specifying a validation rule. The first element in the array specifies the class name or the alias of the validator. The rest of the name-value pairs in the array are used to configure the validator object.
allowMessageFromRule: whether to use the error message returned by the embedded validation rule. Defaults to true. If false, it will use message as the error message.
Note: If the attribute value is not an array, it is considered validation fails and the message will be returned as the error message.
This answer is applicable to ajax request scenarios
In your controller
use yii\base\Model;
use yii\widgets\ActiveForm;
use yii\web\Response;
public function actionCreate()
{
$models = [
'model1' => new Category,
'model2' => new Category,
];
if (Yii::$app->request->isAjax && Model::loadMultiple($models, Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
$validate = [];
$validate = array_merge(ActiveForm::validateMultiple($models), $validate);
// If you need to validate another models, put below.
// $validate = array_merge(ActiveForm::validate($anotherModel), $validate);
return $validate;
}
if (Model::loadMultiple($models, Yii::$app->request->post())) {
foreach($models as $key => $model) {
$model->save();
}
}
return $this->render('create', [
'models' => $models,
]);
}
In your view
<?php
$form = ActiveForm::begin([
'enableClientValidation' => false,
'enableAjaxValidation' => true,
]);
?>
<?= $form->field($models['model1'], '[model1]name')->textInput(); ?>
<?= $form->field($models['model2'], '[model2]name')->textInput(); ?>
<?= Html::submitButton('Create') ?>
<?php ActiveForm::end(); ?>
Here is the sample code from Yii2 checkboxList, I want to add custom class for each Item in checkboxList but I don't know how and where can I add that!
Could you please help me please ..
$list = [0 => 'PHP', 1 => 'MySQL', 2 => 'Javascript'];
$list2 = [0,2];
echo Html::checkboxList('CuisineId',$list2,$list,array('class' => 'test' ));
Thanks in advance.
If you want to add the same class, you should use itemOptions :
echo Html::checkboxList('CuisineId', $list2, $list, ['itemOptions'=>['class' => 'test']]);
Or if you want a custom class for each item, you should use item callback :
echo Html::checkboxList('CuisineId', $list2, $list, ['item'=>function ($index, $label, $name, $checked, $value){
return Html::checkbox($name, $checked, [
'value' => $value,
'label' => $label,
'class' => 'any class',
]);
}]);
Read more : http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#checkboxList()-detail
EDIT : add example
Just in case you only need to change the label options:
<?= Html::checkboxList('CuisineId', $list, $items, [
'itemOptions' => [
'labelOptions' => [
'style' => 'font-weight: normal',
'class' => 'some-custom-class',
],
],
]) ?>
Note: Everything you put inside itemOptions will be passed to Html::checkbox() as its own options when creating each checkbox. It means you can pass class, style, label, labelOptions, etc.
I am using WP_Query and json_encode to return the WordPress post data in a JSON array so that I can use Angular.js as a front end. Everything works, except that I am not able to include the featured image in the JSON file.
Here is my code:
<?php
function test_ajax()
{
header( "content-type: applications/json" );
$query = new WP_Query( array(
'numberposts' => 10,
'order'=> 'DESC',
'orderby' => 'title',
'post_type' => 'post',
'meta_query' => array(
array( 'key' => '_thumbnail_id')
) ) );
echo json_encode($query->get_posts());
die();
}
add_action("wp_ajax_nopriv_test_ajax", "test_ajax");
add_action("wp_ajax_test_ajax", "test_ajax");
Here is the json that is outputted:
[{
"ID":133,
"post_author":"1",
"post_date":"2014-08-19 05:54:03",
"post_date_gmt":"2014-08-19 05:54:03",
"post_content":"\"Woman",
"post_title":"Woman on the Banks of the Seine, After Courbet, 1950",
"post_excerpt":"",
"post_status":"publish",
"comment_status":"open",
"ping_status":"open",
"post_password":"",
"post_name":"woman-on-the-banks-of-the-seine-after-courbet-1950",
"to_ping":"",
"pinged":"",
"post_modified":"2014-08-19 05:54:03",
"post_modified_gmt":"2014-08-19 05:54:03",
"post_content_filtered":"",
"post_parent":0,
"guid":"http:\/\/localhost\/mabs\/?p=133",
"menu_order":0,
"post_type":"post",
"post_mime_type":"",
"comment_count":"0",
"filter":"raw"
}]
i have coded a crawler in perl to to get the url, title of the site and put it into a hash as following
$VAR1 = {
'address1' => {
'url' => 'dthree',
'title' => 'done'
},
'address2' => {
'url' => 'dthree',
'title' => 'done'
}
};
then how can i convert it into json format .. im using MOJO::Json
The first four lines in Mojo::JSON's SYNOPSIS will tell you.
use Mojo::JSON;
my $json = Mojo::JSON->new->encode( $VAR1 );
As you can use a index value inside the view when using a listview widget I wanted to change this index value as I use the same view on different places, so not every element that I use have the same index on the pages.
somepage.php
echo ListView::widget([
'summary' => false,
'viewParams' => [
'url' => '',
],
'index' => 'index + 4',//the idea
'options' => [
'class' => 'xxxx',
],
'itemOptions'=> [
'class' => 'xxxx',
],
'itemView' => '#frontend/views/product/_item_product_small',
'dataProvider' => $provider,
]);
frontend/views/product/_item_product_small.php
<div data-index="<?=$index?>">
// content
</div>
You need to create intermediate view for such cases:
somepage.php
echo ListView::widget([
// ...
'itemView' => '_view',
]);
_view.php
$this->render('#frontend/views/product/_item_product_small', ['index' => $index + 4]);