P
P
Pavel2019-09-10 23:18:57
Yii
Pavel, 2019-09-10 23:18:57

Yii2 How to add condition in query in related data?

Good day to all!
Please help, because I have already broken my head, trying to figure out why the sample contains "extra" data. Why redundant? Look here.
There are 2 tables (MariaDB):

CREATE TABLE `email` (
  `email_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `subject` varchar(512) NOT NULL,
  `body` longtext NOT NULL,
  `status` tinyint(1) unsigned DEFAULT '0',
  `created_by` int(10) unsigned NOT NULL,
  `created_at` int(10) unsigned NOT NULL,
  `updated_at` int(10) unsigned DEFAULT '0',
  PRIMARY KEY (`email_id`),
  KEY `email_status_IDX` (`status`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='Таблица для хранения email для отправки';

and
CREATE TABLE `email_recipient` (
  `email_id` int(10) unsigned NOT NULL,
  `email_to` varchar(512) NOT NULL,
  `status` tinyint(3) unsigned DEFAULT '0',
  KEY `email_recipient_email_id_IDX` (`email_id`,`email_to`(255)) USING BTREE,
  CONSTRAINT `email_recipient_fk` FOREIGN KEY (`email_id`) REFERENCES `email` (`email_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Таблица с получателями';

The first one stores general information about the sent letter, the second one stores the recipients (connection by `email_id`).
The test data is:
MariaDB [service]> select * From email where email_id = 3;
+----------+----------+----------+--------+------------+------------+------------+
| email_id | subject  | body     | status | created_by | created_at | updated_at |
+----------+----------+----------+--------+------------+------------+------------+
|        3 | тест     | тест     |      0 |          2 | 1568143024 |          0 |
+----------+----------+----------+--------+------------+------------+------------+

and correspondingly
+----------+---------------+--------+
| email_id | email_to      | status |
+----------+---------------+--------+
|        3 | [email protected] |      0 |
|        3 | [email protected]  |      1 |
+----------+---------------+--------+

Yii2 version: 2.0.11.2 (I know that I need to upgrade, but I can't yet).
I will not give a complete output of models for them, because. I think this is not required yet, I will only give a relation from the Email model:
/**
       * @return \yii\db\ActiveQuery
       */
      public function getEmailRecipients()
      {
          return $this->hasMany(EmailRecipient::className(), ['email_id' => 'email_id']);
      }

Further there is a console application which is engaged in sending. Naturally, you need to send only to those addresses whose status is 0 (1 - sending has already been).
Actually, I get data like this:
$emails = Email::find()
        ->joinWith('emailRecipients')
        ->where(['email.status' => Email::EMAIL_STATUS_NEW])
        ->andWhere(['email_recipient.status' => EmailRecipient::EMAIL_RECIPIENT_STATUS_NEW])
        ->asArray()
        ->all();

I was 100500% sure that I would only receive emails that were ready to be sent (`email`.`status` = 0) and a list of recipients who had not yet received an email for one reason or another (`email_recipient`.`status` = 0) . But either I made a big mistake somewhere or something went wrong - an array is returned to me with the full number of recipients:
array(1) {
  [0]=>
  array(8) {
    ["email_id"]=>
    string(1) "3"
    ["subject"]=>
    string(8) "тест"
    ["body"]=>
    string(8) "тест"
    ["status"]=>
    string(1) "0"
    ["created_by"]=>
    string(1) "2"
    ["created_at"]=>
    string(10) "1568143024"
    ["updated_at"]=>
    string(1) "0"
    ["emailRecipients"]=>
    array(2) {
      [0]=>
      array(3) {
        ["email_id"]=>
        string(1) "3"
        ["email_to"]=>
        string(12) "[email protected]"
        ["status"]=>
        string(1) "1"
      }
      [1]=>
      array(3) {
        ["email_id"]=>
        string(1) "3"
        ["email_to"]=>
        string(13) "[email protected]"
        ["status"]=>
        string(1) "0"
      }
    }
  }
}

I decided to debug and get a request that gets the data:
SELECT * 
FROM `email` 
    LEFT JOIN `email_recipient` ON `email`.`email_id` = `email_recipient`.`email_id` 
WHERE (`email`.`status`=0) 
    AND (`email_recipient`.`status`=0);

It does not matter:
+----------+----------+----------+--------+------------+------------+------------+----------+---------------+--------+
| email_id | subject  | body     | status | created_by | created_at | updated_at | email_id | email_to      | status |
+----------+----------+----------+--------+------------+------------+------------+----------+---------------+--------+
|        3 | тест     | тест     |      0 |          2 | 1568143024 |          0 |        3 | [email protected] |      0 |
+----------+----------+----------+--------+------------+------------+------------+----------+---------------+--------+
1 row in set (0.00 sec)

Didn't write anything special. Models were created using gii.
Can you please tell me what I missed or misunderstood in the work of links in Yii2?
Thank you all in advance!

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Maxim, 2019-09-10
@DarthPavel

$emails = Email::find()
    ->joinWith(['emailRecipients' => static function (ActiveQuery $query) {
        $query->andWhere(['email_recipient.status' => EmailRecipient::EMAIL_RECIPIENT_STATUS_NEW]);
    }])
    ->where(['email.status' => Email::EMAIL_STATUS_NEW])
    ->asArray()
    ->all();

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question