How to load related entities in custom functions


(Modaei) #1

I have two related entities. "ad" and "building"

my ad model:


public function getBuilding()

    {

        return $this->hasOne(Building::className(), ['id' => 'building_id']);

    }

building model:


public function getAds()

    {

        return $this->hasMany(Ad::className(), ['building_id' => 'id']);

    }

I have added the extra fields to the ad model so when I access "localhost/REST/api/ads?expand=building" I have ads data with related buildings data together.


public function extraFields() {

        return ['building'];

    }

Is this done by eager loading or lazy loading?

I have also added a search action to the controller:


public function actionSearcharea($lat1, $long1, $lat2, $long2){

        $ads = Ad::find()

                ->joinWith('building')

                ->where(['>','building.latitude',$lat1])

                ->andWhere(['>','building.longitude',$long1])

                ->andWhere(['<','building.latitude',$lat2])

                ->andWhere(['<','building.longitude',$long2])

                ->all();

        return $ads;

    }

How can I have the ads results with the related buildings data? like the expand functionality above.


(Mzimin) #2




// yii2/db/ActiveQuery.php


public $this joinWith ( $with, $eagerLoading = true, $joinType = 'LEFT JOIN' )




So it’s eager loading by default, but you can change it to lazy loading.

http://www.yiiframework.com/doc-2.0/yii-db-activequery.html#joinWith()-detail

The simpliest way - add asArray():





$ads = Ad::find()

  ->joinWith('building')

  ->where(['>','building.latitude',$lat1])

  ->andWhere(['>','building.longitude',$long1])

  ->andWhere(['<','building.latitude',$lat2])

  ->andWhere(['<','building.longitude',$long2])

  ->asArray()

  ->all();




But better return ActiveDataProvider in REST index actions:





$query = Ad::find()

  ->joinWith('building')

  ->where(['>','building.latitude',$lat1])

  ->andWhere(['>','building.longitude',$long1])

  ->andWhere(['<','building.latitude',$lat2])

  ->andWhere(['<','building.longitude',$long2]);


return new ActiveDataProvider([

  'query': $query

]);




And in this way you can add building to json response by adding expand=building in GET params.

By the way, if you always need to return ‘building’ with ad - you can add it to fields() method of Ad model.


(Modaei) #3

Thanks a lot mikezimin for your response. It was very helpfull.

If I add building to the ad’s model’s fields() method, is it using joinWith and threfore eager loading too?


(Mzimin) #4

I don’t think that framework should decide to produce eager loading when some relative field specified in fields() method.

If you want to eager loading some relation ‘by default’ - you can override find() method of your model:





    public static function find()

    {

        return parent::find()->with('building');

    }


    // or any other query


    public static function find()

    {

        return parent::find()->where('deleted' => false)->orderBy('title');

    }