ActiveRecord - How can I modify the property value after the AR object created?

Hi.

I have to fetch data from the database. The videos have thumb images. These images stored in json array.

But I want to fetch these string based array convert to php array.

I wrote this function and it works fine, but unfortunately I have no idea where or when should I call this convert function.

In the Controller’s Action I get the all Video ActiveRecord object from DB. After I tried to call in the __construct or in the init function but it seems the properties of AR is null in the construct and init functions.

Please check this code snippets with the comments.




    // Controller

    /**

     * Displays homepage.

     *

     * @return mixed

     */

    public function actionIndex()

    {

        $videos = Video::find()->all();

        // other codes.

        return ['index', ['models' => $videos]];

    }


    // Video ActiveRecord

    /**

     * {@inheritdoc}

     */

    public __construct($config) {

        // This is NULL, after or before the parent::__construct() calling, it does not matter!

        $this->thumbs = $this->convertToPHPValueArrayInt($this->thumbs);

        parent::__construct($config);

    }




    /**

     * {@inheritdoc}

     */

    public function init() {

        // single-table inheritance

        $this->source = self::TYPE;

        // This is NULL, after or before the parent::init() calling, it does not matter!

        $this->thumbs = $this->convertToPHPValueArrayInt($this->thumbs);

        parent::init();

    }

    


     // Getter function

     // There is thumbs property but If I call '$model->thumbs' it will not get the converted arrays.

     // This is work only if I call in this way: '$model->getThumbs()'

     /**

     * @return array of video tags

     */

    public function getThumbs() {

        

        return $this->convertToPHPValueArrayInt($this->thumbs);

    }




    //View

    <?php    foreach ($models as $model) : ?>

    <div class="row">

        <div class="col-md-12">

            <!--<?= $model->title ?>-->

        </div>

        <div class="col-md-12">

            <?php 

                // Still the format json format.

                // It seems the __construct and init functions not called, because I placed an echo function but it not run!

                var_dump($model->thumbs);

            ?>

        </div>

    </div>

    <?php    endforeach; ?>




Do you have any idea how I can achieve that the thumbs propery will be modified in the __construct or init function? Or somehow else?

Thanks for the answers.

Does it (or something similar) work?


public function actionIndex()

    {

        $videos = Video::find()->all();

        $videos->thumbs= $videos->convertToPHPValueArrayInt($videos->thumbs);

        // other codes.

        return ['index', ['models' => $videos]];

    }

In this case, no, becasue it is a lost ->all() returns a list.

But in the view when I iterate over the list it is work for one model of course.

AfterFind?

I have tried it too!

I placed a command echo &quot;I am here&quot; into the afterFind() but it seems it was not called!

What I figured out is that, afterFind() called if you query only one active record object, but it does not called if I query a collection of AR.

Are you sure about that? It looks like it should be calling it:




    /**

     * @inheritdoc

     */

    public function populate($rows)

    {

        if (empty($rows)) {

            return [];

        }

        $models = $this->createModels($rows);

        if (!empty($this->join) && $this->indexBy === null) {

            $models = $this->removeDuplicatedModels($models);

        }

        if (!empty($this->with)) {

            $this->findWith($this->with, $models);

        }

        if ($this->inverseOf !== null) {

            $this->addInverseRelations($models);

        }

        if (!$this->asArray) {

            foreach ($models as $model) {

                $model->afterFind();             // <-------- HERE

            }

        }

        return $models;

    }



Yeap, totally. Here my codes again :)

The view




/* @var $this yii\web\View */

/* @var models common\models\Video[] */


$this->title = 'My Yii Application';

?>

<div class="video-index">


    <?php    foreach ($models as $model) : ?>

    <div class="row">

        <div class="col-md-12">

            <?= $model->title ?>

        </div>

        <div class="col-md-12">

            <?php 

                var_dump($model->getThumbs());

            ?>

        </div>

    </div>

    <?php    endforeach; ?>

</div>



Here you can see the controller:




    /**

     * Displays homepage.

     *

     * @return mixed

     */

    public function actionIndex()

    {

        //common\modules\Video

        $videos = Video::find()->where(['status' => 1])->limit(30)->all();

        return $this->render('index', ['models' => $videos]);

    }



Here the model:




namespace common\models;


class Video extends \common\modules\VideoTube\models\Video

{

    

    public function afterFind() {

        throw new Exception("Tadam");

        echo "In afterFind method - Before parent call";

        die();

        parent::afterFind();

        echo "In afterFind method - After parent call";

        die();

    }


}




I do not see the echo arguments on the site, and the php running not died! So I will see the Video title and thumbs on the site… so I am sure the afertFind() method does not call. And the Exception not throwd.

I think the Yii2 uses another mechanism to fill out the object’s property with the values.

I don’t think you’re using the correct Video model. According to your comments




common\modules\Video


vs

 

\common\modules\VideoTube\models\Video