@MarkLb

Как оптимально реализовать каскадное скрытие во вложенности?

Ситуация: Допустим, существует следующая вложенность в сервисе: Категория->Группы->Услуги.
Иллюстрация

kiss_9kb.1578833041.png


Задача: Необходимо организовать псевдо-удаление, то есть формально пользователь не видит категорию/группу/услугу, но фактически в БД они есть.
Т.е., чтобы флаг "is deleted" становился активным.

Но необходимо это сделать с каскадностью. Например: если "удаляется" категория - с ней вложенные в неё группы, а за группами - вложенные в них услуги.
Если только группа - значит связанные с ней услуги.
Иллюстрация

kiss_11kb.1578833367.png


Вопрос: как это оптимально реализовать?

Сейчас из вариантов вижу - реализовать события удаления для категорий, групп и по цепочке они будут "дергать" друг-друга и "удалять".
Но, возможно, это можно как-то со стороны БД "разрулить"? По-сути, до возникновения этой задачи вопрос каскадного(но физического) удаления решала именно она.
  • Вопрос задан
  • 33 просмотра
Пригласить эксперта
Ответы на вопрос 1
kimono
@kimono
Web developer
На ошибки не проверял, но думаю можно сделать примерно так:

interface SoftDeletableInterface
{
    public function softDelete() : bool;

    public function getChildren() : array;
}

abstract class SoftDeletableModel extends ActiveRecord implements SoftDeletableInterface
{
    public function getChildren() : array
    {
        return [];
    }

    final public function softDelete(bool $inTransaction = false) : bool
    {
        if ($inTransaction) {
            $this->softDeleteInternal();

            return true;
        }

        $transaction = \Yii::$app->db->beginTransaction();
        try {
            $this->softDeleteInternal();
            $transaction->commit();

            return true;
        } catch (\Exception $exception) {
            $transaction->rollBack();

            return false;
        }
    }

    private function softDeleteInternal() : void
    {
        $this->updateAttributes(['is_deleted' => true]);

        foreach ($this->getChildren() as $children) {
            foreach ((array)$children as $child) {
                $child->softDelete(true);
            }
        }
    }
}

class Category extends SoftDeletableModel
{
    public function getChildren() : array
    {
        return $this->groups;
    }

    public function getGroups()
    {
        return $this->hasMany(Group::class, ['category_id' => 'id']);
    }
}

class Group extends SoftDeletableModel
{
    public function getChildren() : array
    {
        return [$this->services, $this->users] /* array of array */;
    }

    public function getServices()
    {
        return $this->hasMany(Service::class, ['group_id' => 'id']);
    }

    public function getUsers()
    {
        return $this->hasMany(User::class, ['group_id' => 'id']);
    }
}

class Service extends SoftDeletableModel
{
}

class User extends SoftDeletableModel
{
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы