Geoff
Geoff

Reputation: 6639

Passing related attributes in yii2 to a json output

Am returning data to a rest api and i would like to return both the attributes an the related attributes

This is what i have

$query = User::find()->joinWith('role');

When i perform

var_dump($query->all())

I get an array of the form (attributes and related attributes)

  [1]=>
 object(common\models\User)#119 (10) {
  ["_attributes":"yii\db\BaseActiveRecord":private]=>
array(18) {
  ["id"]=>
  int(27)
  ["username"]=>
  string(8) "marshal2"
  ["email"]=>
  string(18) "[email protected]"
 }

["_related":"yii\db\BaseActiveRecord":private]=>
array(1) {
  ["role"]=>
  object(common\rbac\models\Role)#131 (8) {
    ["_attributes":"yii\db\BaseActiveRecord":private]=>
    array(3) {
      ["item_name"]=>
      string(23) "Tracking center officer"
      ["user_id"]=>
      int(27)

    }

  }
}

} ...

When passing the result to a json output via

return ['data' => $query->all()];

Only the attributes are passed but the related are not passed That is i get

"data": [
{
  "username": "admin",
  "email": "[email protected]",

},
{
  //also id
  "username": "marshal1",
  "email": "[email protected]",
  ..... and others

  //i expected to see a role name since there is a related attribute with user id
},

What do i need to add so that the related attributes are also passed as i expect the data also to show role item name

This is my user model

    public $role;

public function rules()
{
    return [
        [['username', 'email'], 'filter', 'filter' => 'trim'],
        [['username','expires_on', 'email', 'status'], 'required'],
        ['email', 'email'],
       // ['expires_on', 'integer'],
        [['username','first_name','last_name','firebase_pwd','picture'], 'string', 'min' => 2, 'max' => 255],

        // password field is required on 'create' scenario
        ['password', 'required', 'on' => 'create'],
        // use passwordStrengthRule() method to determine password strength
        $this->passwordStrengthRule(),

        ['username', 'unique', 'message' => 'This username has already been taken.'],
        ['email', 'unique', 'message' => 'This email address has already been taken.'],
    ];
}

   public function fields()
{
    $fields = parent::fields();

    // remove fields that contain sensitive information
    unset($fields['auth_key'], $fields['password_hash'],
        $fields['password_reset_token'],
        $fields['created_at'],
        $fields['firebase_pwd'],
        $fields['updated_at'],
        $fields['id'],
        $fields['authtoken'],
        $fields['account_activation_token']
    );

    $fields['role'] =function ($model){ //added this to see if it'll work
        return $model->role->name;
    };


   return $fields;
}

The relationship still in the user model

    public function getRole()
{
    // User has_one Role via Role.user_id -> id
    return $this->hasOne(Role::className(), ['user_id' => 'id']);
}

enter code here

Upvotes: 0

Views: 1472

Answers (4)

gud3
gud3

Reputation: 565

You can receive result to array and return same how said @topher. Or you can wrap up toArray.

ArrayHelper::toArray(User::find()->with('role')->all(), [ //or your namespace model 'common\models\User' => ArrayHelper::merge( User::attributes(), ['role' => function($model) { return $model->role; }] ) ])

With this method you've an opportunity to setting return result.

ArrayHelper::toArray(User::find()->all(), [ //or your namespace model 'common\models\User' => [ 'id', 'username' ], ])

Converting Objects to Arrays

P.S It happens because response preparing with rest serializer and it uses only one layer from model.

Upvotes: 0

Bohdan Vorona
Bohdan Vorona

Reputation: 725

All you need to do is using asArray().

Example:

$users = User::find()->with('role')->asArray()->all();

Upvotes: 0

topher
topher

Reputation: 14860

Use eager loading on the join and use asArray() to return the data as an array:

$query = User::find()->with('role')->asArray();

or

$query = User::find()->joinWith('role', true)->asArray();

Upvotes: 3

ScaisEdge
ScaisEdge

Reputation: 133370

You can set the response i JSON format

 \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
 $items = $query->all();
 return ['data' => $items];

or encode in php

$my_json = json_encode($items);

echo $my_json;

Upvotes: 0

Related Questions