return html in rest api yii2 - json

I have a table country
CREATE TABLE `country` (
`code` CHAR(2) NOT NULL PRIMARY KEY,
`name` CHAR(52) NOT NULL,
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Country` VALUES ('AU','Australia',18886000);
INSERT INTO `Country` VALUES ('BR','Brazil',170115000);
INSERT INTO `Country` VALUES ('CA','Canada',1147000);
my model:
namespace app\models;
use yii\db\ActiveRecord;
class Country extends ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'country';
}
/**
* #inheritdoc
*/
public static function primaryKey()
{
return ['code'];
}
/**
* Define rules for validation
*/
public function rules()
{
return [
[['code', 'name', 'population'], 'required']
];
}
}
My controller:
<?php
namespace app\controllers;
use yii\rest\ActiveController;
class CountryController extends ActiveController
{
public $modelClass = 'app\models\Country';
}
?>
and this is my config in urlManager
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'country',
'tokens' => [
'{id}' => '<id:\\w+>'
]
]
],
],
the webservice works perfectly but I need return a html with this dates.
For example, using Postman http://localhost/basic/web/countries/AU
actually return
{
"code": "AU",
"name": "Australia",
"population": 24016400
}
But I want that return html in the json content, for example:
{
"content": "<html>
<body>
<h1>AU</h1>
<p>Name: Australia</p>
<p>Population: 24016400</p>
</body>
</html>"
}
Is possible?
Thank you

Related

TYPO3 Extbase - Manipulate/Change returning json

How can I manipulate/change the returning json from:
[{
"name": "Audi",
"owner": "Peter",
"price": 0,
"color": "Blue",
"pid": 0,
"uid": 1
}, {
"name": "BMW",
"owner": "Wolfgang",
"price": 0,
"color": "Black",
"pid": 0,
"uid": 2
}]
to e.g.:
{
"data": [{
"DT_RowId": "row_1",
"name": "Audi",
"owner": "Peter"
}, {
"DT_RowId": "row_2",
"name": "BMW",
"owner": "Wolfgang"
}],
"options": [],
"files": [],
"draw": 1,
"recordsTotal": "2",
"recordsFiltered": "16"
}
I tried this in my controller, but it's not even filtering for name & owner:
/**
* #var string
*/
protected $defaultViewObjectName = 'TYPO3\CMS\Extbase\Mvc\View\JsonView';
public function jsonRequestAction() {
$this->view->setVariablesToRender(array('records'));
$this->view->setConfiguration(array(
'records' => array(
'only' => array('name', 'owner')
)
)
);
$this->view->assign('records', $this->leiRepository->jsonRequest());
}
I still get all the fields in the standard json.
That's the function from the repository:
public function jsonRequest() {
$query = $this->createQuery();
$result = $query->setLimit(1000)->execute();
//$result = $query->execute();
return $result;
}
Use your own JsonView in Controller:
/**
* JsonController
*/
class JsonController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* view
*
* #var \TYPO3\CMS\Extbase\Mvc\View\JsonView
*/
protected $view;
/**
* defaultViewObjectName
*
* #var string
*/
protected $defaultViewObjectName = \Vendor\Extension\View\JsonView::class;
/**
* action list
*
* #return void
*/
public function listAction() {
$response = [
'draw' => $draw,
'start' => $start,
'length' => $length,
'recordsTotal' => $allProducts->count(),
'recordsFiltered' => $allProducts->count(),
'order' => $order,
'search' => $search,
'columns' => $columns,
'data' => $filteredProducts
];
$this->view->setVariablesToRender(['response']);
$this->view->assign('response', $response);
}
}
Be aware to biuld the entire $repsonse in controller as like as the DataTables expects it (last lines above). And here is the JsonView:
/**
* JsonView
*/
class JsonView extends \TYPO3\CMS\Extbase\Mvc\View\JsonView {
/**
* #var array
*/
protected $configuration = [
'response' => [
//'_only' => ['draw', 'start', 'length', 'order', 'columns', 'recordsTotal', 'recordsFiltered', 'data'],
'data' => [
'_descend' => [
'product' => [
'_only' => ['uid'],
],
'orderType' => [
'_only' => ['uid'],
],
],
'_descendAll' => [
//'_exclude' => ['title'],
'_descend' => [
'maturity' => [],
'currency' => [
'_only' => ['title'],
],
'updated' => [],
'customer' => [
'_only' => ['title', 'title_short', 'titleShort'],
],
],
],
],
],
];
/**
* Always transforming ObjectStorages to Arrays for the JSON view
*
* #param mixed $value
* #param array $configuration
* #return array
*/
protected function transformValue($value, array $configuration) {
if ($value instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
$value = $value->toArray();
}
return parent::transformValue($value, $configuration);
}
}
The JsonView configuration is only capable of filtering/reducing data - this cannot be used to add additional computed properties like like requested in the initial question. Besides that, the keyword is _only instead of only.
You don't need to to use json_encode() and still can use JsonView. However the data payload has to be computed in your controller individually - thus, to contain e.g. recordsTotal and DT_RowId properties.

Custom action in Action with id in Rest ActiveController Yii2

Trying to implement a GET method in Rest API, to query the user status e.g. GET user/:id/status
So getting the status of user id #1 would call /user/1/status
In config I have:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => [
'v1/user'
],
'extraPatterns' => [
'GET status' => 'status',
],
'tokens' => [
'{id}' => '<id:\\w+>'
],
],
],
User Model:
namespace api\modules\v1\models;
use \yii\db\ActiveRecord;
class User extends ActiveRecord {
/**
* #inheritdoc
*/
public static function tableName() {
return 'user';
}
/**
* #inheritdoc
*/
public static function primaryKey() {
return [ 'id' ];
}
}
User Controller:
namespace api\modules\v1\controllers;
use yii\rest\ActiveController;
class UserController extends ActiveController {
public $modelClass = 'api\modules\v1\models\User';
public function actions() {
$actions = parent::actions();
unset(
$actions[ 'index' ],
$actions[ 'view' ],
$actions[ 'create' ],
$actions[ 'update' ],
$actions[ 'delete' ],
$actions[ 'options' ]
);
return $actions;
}
protected function verbs() {
return [
'status' => [ 'GET' ],
];
}
public function actionStatus( $id ) {
return 1;
}
}
But now I'm not sure on how to actually return the data for the call.
$user = User::findOne($id);
if ($user)
return Json::encode(['success'=>true, 'data'=>$user->status]);
else
return Json::encode(['success'=>false, 'message'=>"Can't find user"]);

Yii2 findOne() exceeding execution time

I have a action that is doing a simple findOne($id) query and returning the one row from the database. This is exceeding maximum execution time. This method is being inherited by multiple classes where is works perfectly fine. I am not overriding any find() or afterFind() methods in the relevant Model.
public function actionGetone($id)
{
$classname = $this->model;
$model = new $classname;
return $model::findOne($id);
}
I don't get any errors and works as expected if I override the method with:
public function actionGetone($id){
$items = Job::find()->where(['id' => $id])->all();
return $items;
}
but as soon as I change it to return return $items[0]; id dies again with same Exceeded error.
Not sure if this is linked but I'm getting a Maximum execution time of 30 seconds exceeded error when the action is not mentioned in the behaviours() method and when it is added to access rule like below. But it gives me a Call to a member function checkAccess() on null error when i change access role to ['*']. I don't have authManager setup.
public function behaviors()
{
return [
'contentNegotiator' => [
'class' => \yii\filters\ContentNegotiator::className(),
'formats' => [
'application/json' => yii\web\Response::FORMAT_JSON,
],
],
'authenticator' => [
'class' => \yii\filters\auth\HttpBearerAuth::className(),
'only' => [ 'delete','patch','getone'],
],
'access' => [
'class' => \yii\filters\AccessControl::className(),
'only' => ['delete','patch','getone'],
'rules' => [
[
'actions' => ['delete','patch','getone'],
'allow' => true,
'roles' => ['#'],
],
],
]
];
}
I'd appreciate any ideas :)
Update
$items = Job::find()->where(['id' => $id]);
return $items;
Gives:
{
"sql": null,
"on": null,
"joinWith": null,
"select": null,
"selectOption": null,
"distinct": null,
"from": null,
"groupBy": null,
"join": null,
"having": null,
"union": null,
"params": [],
"where": {
"id": "3"
},
"limit": null,
"offset": null,
"orderBy": null,
"indexBy": null,
"modelClass": "common\models\Job",
"with": null,
"asArray": null,
"multiple": null,
"primaryModel": null,
"link": null,
"via": null,
"inverseOf": null
}
Found the problem, its to do with the recursive flag in the model's toArray() method. In my case, a user has jobs and a job has users specified in the model's fields() methods. Which is resulting in an infinite loop.
Add this to the relation's model to avoid the infinite loop:
public function toArray(array $fields = [], array $expand = [], $recursive = true)
{
return parent::toArray($fields, $expand, false);
}

Yii2 View DateTime Format (d-m-Y H:i:s) But When Save/update in DB Change format to Y-m-d H:i:s

I'm Using Kartik DateTimePicker Extension
<?= $form->field($model, 'Created')->widget(DateTimePicker::classname(),[
'model' => $model,
'attribute' => 'Created',
'name' => 'Created',
'options' => ['placeholder' => 'Select Created'],
'pluginOptions' => [
'format' => 'dd-mm-yyyy hh:ii:ss',
'todayHighlight' => true
]
])
?>
User fill the Create Date the format is
d-m-Y H:i:s (like 24-09-2015 11:21:10)
But when record save to database then Create Date Format change to
Y-m-d H:i:s (like 2015-09-24 11:21:10)
How can I change the date format on save/update of record
Need to just add this code before save/update model in controller.
like,
// ICU format
$model->Created = Yii::$app->formatter->asDate($_POST['modelName']['Created'], 'yyyy-MM-dd HH:mm:ss'); // 2014-10-06 15:22:34
OR
// PHP date()-format
$model->Created = Yii::$app->formatter->asDate($_POST['modelName']['Created'], 'php:Y-m-d H:i:s'); // 2014-10-06 15:22:34
For more information refer this link
Finally I found the answer using AttributeBehavior.
In my model class I've write the behaviors code:
public function behaviors()
{
return [
[
'class' => AttributeBehavior::className(),
'attributes' => [
// update 1 attribute 'created' OR multiple attribute ['created','updated']
ActiveRecord::EVENT_BEFORE_INSERT => ['created','updated'],
ActiveRecord::EVENT_BEFORE_UPDATE => 'updated',
],
'value' => function ($event) {
return date('Y-m-d H:i:s', strtotime($this->Created));
},
],
];
}
My Model Class
namespace frontend\models;
use Yii;
use yii\db\ActiveRecord;
use yii\behaviors\AttributeBehavior;
/**
* This is the model class for table "product".
*
* #property integer $id
* #property integer $product_id
* #property string $product_name
* #property string $created
* #property string $updated
*/
class Product extends ActiveRecord
{
public $csv_file;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'product';
}
public function behaviors()
{
return [
[
'class' => AttributeBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created','updated'], // update 1 attribute 'created' OR multiple attribute ['created','updated']
ActiveRecord::EVENT_BEFORE_UPDATE => 'updated', // update 1 attribute 'created' OR multiple attribute ['created','updated']
],
'value' => function ($event) {
return date('Y-m-d H:i:s', strtotime($this->LastUpdated));
},
],
];
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id', 'product_id', 'product_name', created, updated], 'required'],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'product_id' => 'Product ID',
'product_name' => 'Product Name',
'created' => 'Created',
'updated' => 'Updated',
];
}
}
If input format is d/m/Y then you need to replace the "/" by "-"
like: input date(created): 10/09/2015
date('Y-m-d H:i:s', strtotime(str_replace("/","-",$this->created)));
use in active form
'clientOptions' => ['alias' => 'dd-mm-yyyy'],
use in active form
echo MaskedInput::widget([
'name' => 'input-31',
'clientOptions' => ['alias' => 'date']]);
use class
Class yii\widgets\MaskedInput
Example
<?= $form->field($model, 'date_of_birth')->widget(\yii\widgets\MaskedInput::className(), [
'name' => 'input-31',
'clientOptions' => ['alias' => 'dd-mm-yyyy'], ]) ?>
I have simple code,
in behavior:
public function behaviors() {
return [
[ 'class' => \yii\behaviors\TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at'],
],
// if you're using datetime instead of UNIX timestamp:
'value' => new Expression('NOW()'),
]
];
}
for rules:
public function behaviors() {
return [
[ 'class' => \yii\behaviors\TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at'],
],
// if you're using datetime instead of UNIX timestamp:
'value' => new Expression('NOW()'),
]
];
}
public function behaviors() {
return [
[
'class' => BlameableBehavior::className(),
],
[
'class' => TimestampBehavior::className(),
'value' => date('Y-m-d H:i:s')
],
];
}

Yii2-admin example in basic app

Does anyone have a working example of this extension.
I'm talking about:
https://github.com/mdmsoft/yii2-admin
I'm looking for Yii app basic.
I installed and working properly, but I don't know how to configure "Roles" and "Rules"
At Yii 1.xxx I used http://www.yiiframework.com/extension/authbooster/ but this not working in Yii2.xx
Create a custom model AccessRules.php
<?php
namespace app\models;
class AccessRules extends \yii\filters\AccessRule
{
/**
* #inheritdoc
*/
protected function matchRole($user)
{
if (empty($this->roles)) {
return true;
}
foreach ($this->roles as $role) {
if ($role === '?') {
if ($user->getIsGuest()) {
return true;
}
} elseif ($role === '#') {
if (!$user->getIsGuest()) {
return true;
}
// Check if the user is logged in, and the roles match
} elseif (!$user->getIsGuest() && (int)$role === $user->identity->user_role) {
return true;
}
}
return false;
}
}
?>
Now in your Site Controller add the roles:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
// We will override the default rule config with the new AccessRule class
'ruleConfig' => [
'class' => AccessRules::className(),
],
'only' => ['create', 'update', 'delete','index'],
'rules' => [
[
'actions' => ['create', 'update', 'delete','index'],
'allow' => true,
// Allow admin to create
'roles' => [
'1'
],
]
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}