Сложный запрос hasOne

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
svil
Сообщения: 538
Зарегистрирован: 2018.02.12, 22:41

Сложный запрос hasOne

Сообщение svil » 2019.04.25, 12:34

Есть три таблицы :
Companies : id, name
Contracts : id, id_company
Acts: id, id_contract
Acts связан c Companies через Contracts.
Соответственно в модели Companies

Код: Выделить всё

public function getContracts()
    {
        return $this->hasMany(Contracts::className(), ['id_company' => 'id']);
    }

В модели Contracts

Код: Выделить всё

  public function getCompanies()
    {
        return $this->hasOne(Companies::className(), ['id' => 'id_company']);
    }
В модели Acts, чтобы вытащить наименование компании я пытаюсь реализовать запрос

Код: Выделить всё

SELECT `companies`.* FROM `companies` 
LEFT JOIN `contracts` ON `companies`.`id` = `contracts`.`id_company` 
LEFT JOIN `acts` ON `contracts`.`id` = `acts`.`id_contract` WHERE (contracts.id_company = companies.id) AND (acts.id_contract = contracts.id)
Но как получить одну компанию по ее id, связанной с id_company в Contracts, которая связана по своему id с id_contract в Acts?
Пыталась неудачно так

Код: Выделить всё

 public function getCompanies()
    {
       
        $query = hasOne(Companies::className()); // Вот в этом месте туплю!!!
        $query->joinWith(['contracts' => function ($q) {
            $q->where(['contracts.id_company' => 'companies.id']);
            $q->joinWith(['acts' => function ($qi) {
                $qi->where(['acts.id_contract' => 'contracts.id']);
            }]);

        }]);
Как средставами фреймворка прописать запрос, чтобы потом в дальнейшем
получать из модели данные о компании типа $model->Companies->name, если в модели Acts будет метод:

Код: Выделить всё

 public function getCompaniesName() {
        return $this->Companies->name;
    }

Аватара пользователя
svil
Сообщения: 538
Зарегистрирован: 2018.02.12, 22:41

Re: Сложный запрос hasOne

Сообщение svil » 2019.04.25, 13:36

Имеем связку Companies - Contracts-Acts
Нужно получить из Acts данные о Companies
В модели Companies

Код: Выделить всё

 public function getActs() {

        return $this->hasMany(Acts::className(), ['id' => 'id_contract'])
            ->viaTable(
                'Contracts',
                ['id_company' => 'companies.id'],
                function ($query) {
                    $query->andWhere(['acts.id_contract' => 'contracts.id']);
                });
    }
В модели Acts не получается:

Код: Выделить всё

public function getCompanies()
    {
        return $this->hasOne(Companies::className(), ['id' => 'id_company'])
            ->viaTable(
                'Contracts',
                ['id_company' => 'companies.id'],
                function ($query) {
                    $query->andWhere(['acts.id_contract' => 'contracts.id']);
                });
    }
Ошибка

Код: Выделить всё

Getting unknown property: app\models\Acts::companies.id

Аватара пользователя
svil
Сообщения: 538
Зарегистрирован: 2018.02.12, 22:41

Re: Сложный запрос hasOne

Сообщение svil » 2019.04.25, 13:46

Исправила id

Код: Выделить всё

return $this->hasOne(Companies::className(), ['id' => 'contracts.id_company'])
            ->viaTable(
                'contracts',
                ['contracts.id_company' => 'id'],
                function ($query) {
                    $query->andWhere(['acts.id_contract' => 'contracts.id']);
                });
Ошибка

Код: Выделить всё

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'acts.id_contract' in 'where clause'
The SQL being executed was: SELECT * FROM `contracts` WHERE (`acts`.`id_contract`='contracts.id') AND (`contracts`.`id_company`=1)
Error Info: Array
(
    [0] => 42S22
    [1] => 1054
    [2] => Unknown column 'acts.id_contract' in 'where clause'
)
↵
Caused by: PDOException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'acts.id_contract' in 'where clause'
in /Users/svetlanailina/Sites/mytest/vendor/yiisoft/yii2/db/Command.php at line 1290

Аватара пользователя
proctoleha
Сообщения: 260
Зарегистрирован: 2016.07.10, 19:00

Re: Сложный запрос hasOne

Сообщение proctoleha » 2019.04.25, 14:24

Вот если без кода на пальцах.

У отдельно взятой компании есть много контрактов, и каждому контракту соответствует один?несколько? актов. В любом случае один акт соответствует одному контракту. Я правильно понял?

Для простоты не будем использовать viaTable, в актах у нас стандартная связь hasOne() по отношению к контрактам, getContract()

Вытаскиваем данные компании по act_id

Act::find()->joinWhis('contract.company')->where(['act.id' => $act_id])->one();
Или
Company::find()->joinWhis('contract.act')->where(['act.id' => $act_id])->one();

Вроде все просто? Или я чего то не понимаю? Смысл городить огород, чтобы сразу вытащить имя?
Вот за что я не люблю линукс, так это за свои кривые, временами, руки

Аватара пользователя
svil
Сообщения: 538
Зарегистрирован: 2018.02.12, 22:41

Re: Сложный запрос hasOne

Сообщение svil » 2019.04.25, 14:29

Спасибо. Попробую. Но у меня получилось с помощью жадной загрузки
В модели Acts

Код: Выделить всё

 public function getContracts()
    {
        return $this->hasOne(Contracts::className(), ['id' => 'id_contract'])->with(['companies']);
    }
Потом только вывожу

Код: Выделить всё

echo $model->contracts->companies->name;

Аватара пользователя
proctoleha
Сообщения: 260
Зарегистрирован: 2016.07.10, 19:00

Re: Сложный запрос hasOne

Сообщение proctoleha » 2019.04.25, 14:41

Так у меня тоже самое написано, только явно. И тоже жадная загрузка. И точно также надо выводить. Отличие только одно: связь getContracts() отвечает только за контракты. По моему скромному мнению вытаскивать каждый раз вместе с контрактами данные компании не комильфо. А если потребуются только акты и контракты?
Вот за что я не люблю линукс, так это за свои кривые, временами, руки

Аватара пользователя
svil
Сообщения: 538
Зарегистрирован: 2018.02.12, 22:41

Re: Сложный запрос hasOne

Сообщение svil » 2019.04.25, 15:03

Это как раз в виде, когда надо акты контракты компании

Аватара пользователя
leonenco
Сообщения: 122
Зарегистрирован: 2017.01.30, 22:42

Re: Сложный запрос hasOne

Сообщение leonenco » 2019.04.26, 06:57

можно в модели Acts реализовать метод getCompanies этим образом, через связаную таблицу,

Код: Выделить всё

public function getCompanies()
    {
        return $this->hasOne(Companies::className(), ['id' => 'id_company'])->viaTable('contacts', ['id' => 'contracts_id']);
    }

Ответить