Implement Search from hasMany relation

Hello, i’m making, a globalSearch for my Client’s model. But i’ve made another table “Telephone” that contains all the phone numbers for my Client. So i created a hasMany relation between them in Client’s Model.

/**
 * @return \yii\db\ActiveQuery
 */
public function getTelephones()
{
    return $this->hasMany(Telephone::className(), ['client_id' => 'client_id']);
}

Now i need to search for my Clients in Client’s index with GridView by these telephone numbers from table ‘Telephone’. I’ve searched in google for 2 days and cannot find the solution with using ->orFilterWhere function. Can someone please help me do that here is my ClientSearch model.

<?php namespace app\models;

use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Client;

/**
 * ClientSearch represents the model behind the search form of `app\models\Client`.
 */
class ClientSearch extends Client
{
public $globalSearch;
/**
 * {@inheritdoc}
 */
public function rules()
{
    return [
        [['globalSearch'], 'safe'],
    ];
}


/**
 * {@inheritdoc}
 */
public function scenarios()
{
    // bypass scenarios() implementation in the parent class
    return Model::scenarios();
}

/**
 * Creates data provider instance with search query applied
 *
 * @param array $params
 *
 * @return ActiveDataProvider
 */
public function search($params)
{
    $query = Client::find();


     // will eagerly load the related models

    // add conditions that should always apply here

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
        'sort'=> [
          'attributes' => ['first_name', 'last_name', 'email'],
          'defaultOrder' => ['first_name'=>SORT_ASC, 'last_name'=>SORT_ASC]
        ]
    ]);

    $this->load($params);


    if (!$this->validate()) {
        // uncomment the following line if you do not want to return any records when validation fails
        // $query->where('0=1');
        return $dataProvider;
    }

    // grid filtering conditions
    $query->andFilterWhere([
        'client_id' => $this->client_id,
    ]);

    $query->orFilterWhere(['like', 'Concat(first_name," ", last_name)', $this->globalSearch])
        ->orFilterWhere(['like', 'first_name', $this->globalSearch])
        ->orFilterWhere(['like', 'last_name', $this->globalSearch])
        ->orFilterWhere(['like', 'email', $this->globalSearch])
        ->orFilterWhere(['like', 'address', $this->globalSearch])
        ->orFilterWhere(['like', 'client_id', $this->globalSearch]);

    return $dataProvider;

}
}

Please help me when i search for any of the numbers related to the Client to show me the Client in the GridView.

Telephone model have - ID, client_id and telephone as attributes.

Hi @BomFunK, welcome to the forum.

You could include telephone table in the query using joinWith.

    public function search($params)
    {
        $query = Client::find()->joinWith('telephones');
        ...
        $query->orFilterWhere(['like', 'Concat(first_name," ", last_name)', $this->globalSearch])
        ...
        ->orFilterWhere(['like', 'telephone.number', $this->globalSearch]);

https://www.yiiframework.com/wiki/780/drills-search-by-a-hasmany-relation-in-yii-2-0

1 Like

Hey @softark, thanks for the welcome!

I did that and when i try to search for a number i got the following error:

    Integrity constraint violation – yii\db\IntegrityException
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'client_id' in where clause is ambiguous
The SQL being executed was: SELECT COUNT(*) FROM `client` LEFT JOIN `telephone` ON `client`.`client_id` = `telephone`.`client_id` WHERE ((((((((Concat(first_name," ", last_name) LIKE '%0885%') OR (Concat(first_name," ", Concat(second_name," ", last_name)) LIKE '%0885%')) OR (`first_name` LIKE '%0885%')) OR (`second_name` LIKE '%0885%')) OR (`last_name` LIKE '%0885%')) OR (`email` LIKE '%0885%')) OR (`address` LIKE '%0885%')) OR (`client_id` LIKE '%0885%')) OR (`telephone`.`telephone` LIKE '%0885%')
Error Info: Array
(
    [0] => 23000
    [1] => 1052
    [2] => Column 'client_id' in where clause is ambiguous
)
↵
Caused by: PDOException
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'client_id' in where clause is ambiguous
in /home/pcwozv8q/dash.pcworkshop.bg/basic/vendor/yiisoft/yii2/db/Command.php at line 1293

I have no idea how to fix that problem also I’ve already read the Drills Search topic and didn’t make it work from there. Can u help me fixing this error?
This is my edit i made to get the error.

<?php

namespace app\models;

use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Client;

/**
 * ClientSearch represents the model behind the search form of `app\models\Client`.
 */
class ClientSearch extends Client
{
    public $globalSearch;
    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [['globalSearch'], 'safe'],
        ];
    }


    /**
     * {@inheritdoc}
     */
    public function scenarios()
    {
        // bypass scenarios() implementation in the parent class
        return Model::scenarios();
    }

    /**
     * Creates data provider instance with search query applied
     *
     * @param array $params
     *
     * @return ActiveDataProvider
     */
    public function search($params)
    {
        $query = Client::find()->joinWith('telephones');


         // will eagerly load the related models

        // add conditions that should always apply here

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'sort'=> [
              'attributes' => ['first_name', 'last_name', 'email'],
              'defaultOrder' => ['first_name'=>SORT_ASC, 'last_name'=>SORT_ASC]
            ]
        ]);

        $this->load($params);


        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

        // grid filtering conditions
        $query->andFilterWhere([
            'client_id' => $this->client_id,
        ]);

        $query->orFilterWhere(['like', 'Concat(first_name," ", last_name)', $this->globalSearch])
            ->orFilterWhere(['like', 'Concat(first_name," ", Concat(second_name," ", last_name))', $this->globalSearch])
            ->orFilterWhere(['like', 'first_name', $this->globalSearch])
            ->orFilterWhere(['like', 'second_name', $this->globalSearch])
            ->orFilterWhere(['like', 'last_name', $this->globalSearch])
            ->orFilterWhere(['like', 'email', $this->globalSearch])
            ->orFilterWhere(['like', 'address', $this->globalSearch])
            ->orFilterWhere(['like', 'client_id', $this->globalSearch])
            ->orFilterWhere(['like', 'telephone.telephone', $this->globalSearch]);

        return $dataProvider;

    }
}

I’m sorry, I didn’t notice that both client and telephone have client_id column.

The following will do the job.

        // ->orFilterWhere(['like', 'client_id', $this->globalSearch])
        ->orFilterWhere(['like', 'client.client_id', $this->globalSearch])
        ->orFilterWhere(['like', 'telephone.telephone', $this->globalSearch]);
1 Like

Thanks it worked perfectly!