Your Location is: Home > Php

Yii2 - Unable to parse result of hasMany()

From: Liechtenstein View: 3956 Erik 

Question

I got stuck on kinda very basic thing and can not move on. I have tables interpret and interpret_member like this (just important data here):

$this->createTable('interpret', [
    'name'      => $this->string(255)->notNull(),
    'PRIMARY KEY (name)'
]);

$this->createTable('interpret_member', [
    'name'      => $this->string(255)->notNull(),
    'interpret' => $this->string(255)->notNull(),
    'PRIMARY KEY (name, interpret)'
]);

$this->createIndex(
    'idx-interpret_member',
    'interpret_member',
    'interpret'
);

$this->addForeignKey('fk-interpret_member', 'interpret_member', 'interpret', 'interpret', 'name', 'CASCADE', 'CASCADE');

Then I have models for both tables generated by gii, so I also have method getInterpretMembers in Interpret model. First I tried to parse its output according to this manual, which gives me an error Trying to get property 'name' of non-object. So I searched here and found this thread. Following that I changed my foreach ($members as $member) to foreach ($members->InterpretMember as $member). That gave me error Getting unknown property: yii\db\ActiveQuery::InterpretMember. The last hope was this thread, but that ended on error Trying to get property 'name' of non-object. The code of last try was:

public function getInterpretMembers()
{
    $members = $this->hasMany(InterpretMember::className(), ['interpret' => 'name']);
    foreach ($members as $member) {
        $member = ArrayHelper::toArray($member, [
            'app\models\user\InterpretMember' => [
                'name',
                'interpret',
                'position'
            ]
        ]);
        echo "Member = {$member->name}<br/>";
    }
    die();
}

I used this code for all attempts, it was just modified according to the mentioned threads and manual.

Best answer

The problem is quite simple

$members = $this->hasMany(InterpretMember::className(), ['interpret' => 'name']); 

The hasMany function returns an ActiveQuery instance and not actually the data from DB, so in order to get data you need to call one() or all() function from ActiveQuery instance

$members = $this->hasMany(InterpretMember::className(), ['interpret' => 'name'])->all();

Congratulations, now you will have the data

Another answer

You are misunderstanding how relations and ActiveRecord works in Yii2.

What your models should look like.

Interpret model

class Interpret extends \yii\db\ActiveRecord
{
    /**
    * Method that defines the relation. It should
    * return instance of \yii\db\ActiveQuery
    */
    public function getInterpretMembers()
    {
        return $this->hasMany(InterpretMember::class, ['interpret' => 'name']);
    }

    //... other methods
}

InterpretMember model

class InterpretMember extends \yii\db\ActiveRecord
{
    public function getInterpret()
    {
        return $this->hasOne(Interpret::class, ['name' => 'interpret'])
    }
}

This will create property interpretMembers in your Interpret class and property interpret in your InterpretMember class.

To work with it in your controller you can do for example following:

class InterpretController extends \yii\web\Controller
{
    public function actionView()
    {
        //find interpret with name InterpretName
        $interpret = Interpret::findOne('InterpretName');
        //output all members
        foreach ($interpret->interpretMembers as $member) {
            echo "Member = {$member->name}<br/>";
        }
        die();
    }
}

Or if you want to work with members inside of Interpret class:

class Interpret extends \yii\db\ActiveRecord
{
    /**
    * Method that defines the relation. It should
    * return instance of \yii\db\ActiveQuery
    */
    public function getInterpretMembers()
    {
        return $this->hasMany(InterpretMember::class, ['interpret' => 'name']);
    }

    //... other methods

    public function doSomethingWithMembers()
    {
        foreach ($this->interpretMembers as $member) {
            echo "Member = {$member->name}<br/>";
        }
        die();
    }
}