I am facing weird issue in Yii2 I have a query which has one join with agent table and a (one to many) relation of jobs with task it works fine but issue is it returns everything in string. Below is the query:
$query = self::find()
->select("job.*, agent.first_name,agent.last_name")
->leftJoin('agent', 'job.agent_id = agent.id')
->with('tasks')
->asArray()
->all();
and the JSON encoded result:
{
"success": true,
"data": [
{
"id": "10",
"customer_id": "1",
"job_type": "normal",
"created": "2016-06-22 10:19:25",
"first_name": "Shayan",
"last_name": "",
"tasks": [
{
"id": "10",
"job_id": "10",
"title": "bring food",
"instruction": null,
"created": "2016-06-22 10:19:25",
},
{
"id": "10",
"job_id": "10",
"title": "bring pizza",
"instruction": null,
"created": "2016-06-22 10:19:25",
},
]
}
if you notice the fields like id, customer_id and job_id these all are integer but it return as string. But if I remove ->asArray() from above query it return valid type casting but issue is it skips relational and leftJoin agent table fields, it only returns job table fields here is the response after removing ->asArray() from above query.
{
"success": true,
"data": [
{
"id": 10,
"customer_id": 1,
"name": null,
"job_type": "normal",
"created": "2016-06-22 10:19:25",
},
If you notice in above response it does not have agent tables first_name, last_name and relational data tasks completely skipped but id and customer_id is in integer.
Does anyone faced same issue? your help would be highly appreciated. Thanks in advance.
I wanted to make sure that's actually the case. I have tested this myself with quite similar query and my results are quite similar:
array(2) {
[0]=>
array(5) {
["id"]=>
string(1) "1"
["name"]=>
string(5) "Admin"
// ...
}
// ...
}
In my case I also get all types as strings. So, If you're going to check for input and its type with if ($data[0]['id'] === 1)
, you will get false
result since it's string
.
But what you need to do is to add (int)
before variable to convert it into different typecast. This would be: (int) $data[0]['id']
.
Then var_dump((int) $data[0]['id']);
(in my case) will give int(1)
instead of string(1) "1"
.
You can also check in conditionals:
((int) $data[0]['id'] === 1) ? exit('Integer') : exit('Not integer');
Without writing (int)
as prefix will give Not integer
result while with prefix will yield Integer
.
If you do not want to keep writing these prefixes in each function, you can write something like:
$data[0]['id'] = (int) $data[0]['id'];
And now $data[0]['id']
will be integer
in future uses.
New solution:
This new solution will return an object with arrays instead of just arrays.
// Method that gives data back. In this case, user with ID == 10.
public static function getData()
{
$dataProvider = new ActiveDataProvider([
'query' => self::findOne(['id' => 10])->attributes
]);
return $dataProvider;
}
In Controller you (as always) pass this object:
$data = User::getData();
return $this->render('user', [
//...
'data' => $data
]);
And then in Viewer you may access values (in correct typecast) like this:
$data->query['columnName'];
So, for ID check:
($data->query['id'] === 10 ? exit('ok') : exit('nok'));
You will get response ok
(typecast: integer, value: 10).
This is expected behavior and also documented:
Note: While this method saves memory and improves performance, it is closer to the lower DB abstraction layer and you will lose most of the Active Record features. A very important distinction lies in the data type of the column values. When you return data in Active Record instances, column values will be automatically typecast according to the actual column types; on the other hand when you return data in arrays, column values will be strings (since they are the result of PDO without any processing), regardless their actual column types.
For the second issue, to retrieve the additional fields in the active record class you have to create additional properties in the class for them:
class MyRecord extends \yii\db\ActiveRecord
{
public $first_name;
public $last_name;
// ...
}
Method "asArray" will convert type of all variables to string. Therefore you should not use this.
Right solution you can find in documentation: https://www.yiiframework.com/doc/guide/2.0/en/rest-resources#overriding-extra-fields
You need use "fields" and "expand" params in URI for API requests.
For example: http://localhost/posts?fields=id,title&expand=author
At first add relation to the model:
/**
* @return \yii\db\ActiveQuery
*/
public function getAuthor()
{
return $this->hasOne(Profile::class, ['id' => 'author_id']);
}
Also you need add fields and extraFields methods to the model:
public function fields()
{
return ['id', 'title'];
}
public function extraFields()
{
return ['author'];
}
And change response:
public function actionIndex()
{
return new ActiveDataProvider([
'query' => Post::find(),
]);
}
P.S. Sorry for necroposting, but I had the same issue recently
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With