Многие ко многим(удаление)

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Многие ко многим(удаление)

Сообщение edvardpotter »

Здравствуйте!
Как сделать удаление, при использовании связи многие ко многим.
Есть квартира:

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

/**
     * @return \yii\db\ActiveQuery
     */
    public function getApartmentImages()
    {
        return $this->hasMany(ApartmentImages::className(), ['apartment_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getImages()
    {
        return $this->hasMany(Images::className(), ['id' => 'image_id'])
            ->via('apartmentImages');
    }
    
есть изображение

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

/**
     * @return \yii\db\ActiveQuery
     */
    public function getApartmentImages()
    {
        return $this->hasMany(ApartmentImages::className(), ['image_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getApartments()
    {
        return $this->hasMany(Apartment::className(), ['id' => 'apartment_id'])
            ->via('apartmentImages');
    }
и связующая модель

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

/**
     * @return \yii\db\ActiveQuery
     */
    public function getImage()
    {
        return $this->hasOne(Images::className(), ['id' => 'image_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getApartment()
    {
        return $this->hasOne(Apartment::className(), ['id' => 'apartment_id']);
    }
При удалении квартиры, удаляются записи из связующей таблицы(apartment_images), но из images естественно не удаляются.
Каким образом сделать удаление?
Я хотел сделать в beforeDelete квартиры, удаление всех изображений которые связаны с ней, но возможно есть вариант проще и лаконичнее?
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Многие ко многим(удаление)

Сообщение edvardpotter »

trueorfalse писал(а): 2017.08.20, 12:42 Путь до файл и http://php.net/manual/ru/function.unlink.php
Нет, я же написал что нужно удаление не файла, а записи из таблицы images.
В методе beforeDelete попробовал сделать такой вариант:

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

public function beforeDelete()
{        
    foreach ($this->documents as $document){
        $document->delete();
    }
    return parent::beforeDelete();
}
Но как выяснилось позже, если запрашиваю любые hasMany связи, то всегда возвращает null.
Вот что отображается в дебаге при удалении:
Изображение
Смущает отмеченный стрелкой запрос, с условием 0=1.
Если получать эти данные в другие моменты, то все связанные данные дергаются нормально.
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Многие ко многим(удаление)

Сообщение edvardpotter »

Сделал таким образом:

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

public function delete()
    {
        foreach ($this->documents as $document){
            $document->delete();
        }
        return parent::delete(); // TODO: Change the autogenerated stub
    }
Все работает, все связанные документы удаляются, но мне это кажется странным. По сути это должно быть в beforeDelete(), но почему там связи не возвращаются и соответственно не удаляются, так и должно быть или это недоработка фреймворка?
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Многие ко многим(удаление)

Сообщение Dominus »

В гайде по созданию блога, удаление из связанной таблицы организованно следующим образом:

app\models\Post

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

public function beforeDelete()
    {
        parent::beforeDelete();
        TagPost::deleteAll(['post_id' => $this->id]);        
        return true;
    }
По идее у вас должно работать так же.
При удалении модели Post, удаляются все связанные с ней данные из таблицы модели TagPost
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Многие ко многим(удаление)

Сообщение edvardpotter »

Dominus писал(а): 2017.08.21, 16:30 В гайде по созданию блога, удаление из связанной таблицы организованно следующим образом:

app\models\Post

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

public function beforeDelete()
    {
        parent::beforeDelete();
        TagPost::deleteAll(['post_id' => $this->id]);        
        return true;
    }
По идее у вас должно работать так же.
При удалении модели Post, удаляются все связанные с ней данные из таблицы модели TagPost
Так данные из этой таблицы так и так удалятся, нужно удалять данные не из TagPost, а из Tags. Вашим способом этого не получится достичь.
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Многие ко многим(удаление)

Сообщение Dominus »

Ну в общем получилось следующее, на моём же примере:

app\models\TagPost

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

public function getTag()
    {
        return $this->hasOne(Tags::className(), ['id' => 'tag_id']);
    }
app\models\Post

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

public function getTagPosts()
    {
        return $this->hasMany(TagPost::className(), ['post_id' => 'id']);
    }

public function beforeDelete()
    {
        parent::beforeDelete(); 
        /** @var  $item \app\models\TagPost */
        foreach($this->getTagPosts()->all() as $item) {
            $item->getTag()->one()->delete(); // Удаляем тег
        }
        TagPost::deleteAll(['post_id' => $this->id]);// Удаляем связи из промежуточной таблицы      
        return true;
    }
Результат: при удалении поста, так же удаляются все привязанные к посту теги.
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
Аватара пользователя
Йож
Сообщения: 574
Зарегистрирован: 2015.08.26, 03:05

Re: Многие ко многим(удаление)

Сообщение Йож »

Видится одна проблема - все это в транзакцию бы обернуть..
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Многие ко многим(удаление)

Сообщение Dominus »

Йож писал(а): 2017.08.22, 03:16 Видится одна проблема - все это в транзакцию бы обернуть..
Можно как то так:

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

foreach ($this->getTagPosts()->all() as $item) {   
   if ($item->getTag()->one()->delete()) {                    
         TagPost::deleteAll(['tag_id' => $item->tag_id]);
   } else {
   	return false;
   }
}
//TagPost::deleteAll(['post_id' => $this->id]);
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Многие ко многим(удаление)

Сообщение edvardpotter »

Dominus писал(а): 2017.08.22, 01:40 Ну в общем получилось следующее, на моём же примере:

app\models\TagPost

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

public function getTag()
    {
        return $this->hasOne(Tags::className(), ['id' => 'tag_id']);
    }
app\models\Post

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

public function getTagPosts()
    {
        return $this->hasMany(TagPost::className(), ['post_id' => 'id']);
    }

public function beforeDelete()
    {
        parent::beforeDelete(); 
        /** @var  $item \app\models\TagPost */
        foreach($this->getTagPosts()->all() as $item) {
            $item->getTag()->one()->delete(); // Удаляем тег
        }
        TagPost::deleteAll(['post_id' => $this->id]);// Удаляем связи из промежуточной таблицы      
        return true;
    }
Результат: при удалении поста, так же удаляются все привязанные к посту теги.
Возможно у меня проблема возникала из за того что я родительский beforeDelete вызывал в конце метода, а не в начале.
Ответить