Symfony Doctrine Предотвращение удаления записи конкретного объекта - PullRequest
6 голосов
/ 09 апреля 2020

представьте, что у меня есть doctrine объект, и у меня может быть несколько записей об этом объекте в базе данных, которые я не хочу удалять, но я хочу, чтобы они были видны.

В общем, у меня могут быть объекты, для которых у меня есть записи по умолчанию, которые должны оставаться там - их нельзя удалять, но они должны быть видны.

Или, например, я хочу иметь специальную учетную запись пользователя только для операций CRON. Я хочу, чтобы эта учетная запись была видна в списке пользователей, но не должна быть удалена - очевидно.

Я искал, и лучшее, что я получил, было SoftDeletable https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/doc/softdeleteable.md Это предотвращает физическое / реальное удаление из БД, но также делает его невидимым на передней панели приложения. Это хороший подход - сделать столбец в соответствующем столбце таблицы сущности - флаг 1/0 - который будет отмечать то, что не может быть удалено. Я также хотел бы, чтобы это так, потому что он может быть использован в качестве Черты в нескольких сущностях. Я думаю, что это было бы хорошим кандидатом для другого расширения в вышеупомянутом расширении Atlantic18 / DoctrineExtensions. Если вы считаете, что это хорошая идея (Doctrine filter), как лучше всего это сделать?

Вопрос в том, единственный ли это путь? У вас есть лучшее решение? Каков общий способ решения этой проблемы?

РЕДАКТИРОВАТЬ: 1. Итак, мы знаем, что нам нужен дополнительный столбец в базе данных - это легко сделать чертой для него чтобы сделать его многоразовым Но 2. Чтобы не иметь никакого дополнительного кода в каждом репозитории, как выполнить sh лог c из «если столбец истинен, предотвратить удаление» с помощью аннотации? Как и в приведенном выше примере SoftDeletable.

Заранее спасибо.

Ответы [ 3 ]

7 голосов
/ 13 апреля 2020

Вы можете сделать это на уровне базы данных. Просто создайте таблицу с именем, например, protected_users с внешним ключом users и установите ключ ON DELETE RESTRICT. Создайте запись в этой таблице для каждого пользователя, которого вы не хотите удалять. Таким образом, любая попытка удалить запись потерпит неудачу как на Doctrine, так и на уровне дб (при любом ручном вмешательстве в дб). Нет необходимости редактировать users сущность, и она защищена даже без Doctrine. Конечно, вы можете создать сущность для этой таблицы protected_users.

Вы также можете создать метод для сущности пользователя, например isProtected(), который будет просто проверять, существует ли связанная сущность ProtectedUser.

5 голосов
/ 13 апреля 2020

Вы должны взглянуть на события doctrine с Symfony:

Step1: Я создаю интерфейс ProtectedInterface одним методом:

public function isDeletable(): boolean

Step2: Я создаю черту ProtectionTrait, которая создает новое свойство. Это isDeletable свойство помечено @ ORM / Column. Эта черта реализует isDeletable (). Это всего лишь геттер.

Если бы у моей сущности могли быть некоторые необратимые данные, я обновляю класс. Мой класс теперь будет реализовывать мой DeleteProtectedInterface и использовать мой ProtectionTrait.

Step3: Я создаю исключение, которое будет выдаваться каждый раз, когда кто-то пытается удалить неосуществляемую сущность.

Step4: Вот советы: Я создаю слушателя , как softdeletable . В этом слушателе я добавляю тест условия, когда моя сущность реализует ProtectedInterface, я вызываю метод получения isDeleteable():

final class ProtectedDeletableSubscriber implements EventSubscriber
{
    public function onFlush(OnFlushEventArgs $onFlushEventArgs): void
    {
        $entityManager = $onFlushEventArgs->getEntityManager();
        $unitOfWork = $entityManager->getUnitOfWork();

        foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) {
            if ($entity instanceof ProtectedInterface && !$entity->isDeletable()) {
                throw new EntityNotDeletableException();
            }
        }
    }
}

Я думаю, что этот код можно оптимизировать, потому что он вызывается каждый раз, когда я удаляю сущность. В моем приложении пользователи не удаляют много данных. Если вы используете компонент SoftDeletable, вы должны заменить его смесью между этим и оригинальным, чтобы избежать большого количества испытаний. Например, вы можете сделать это:

final class ProtectedSoftDeletableSubscriber implements EventSubscriber
{
    public function onFlush(OnFlushEventArgs $onFlushEventArgs): void
    {
        $entityManager = $onFlushEventArgs->getEntityManager();
        $unitOfWork = $entityManager->getUnitOfWork();

        foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) {
            if ($entity instanceof ProtectedInterface && !$entity->isDeletable()) {
                throw new EntityNotDeletableException();
            }

            if (!$entity instance SoftDeletableInterface) {
                 return
            }

            //paste the code of the softdeletable subscriber
        }
    }
}
0 голосов
/ 09 апреля 2020

Что ж, лучший способ добиться этого - иметь еще один столбец в базе данных, например, boolean canBeDeleted и установить для него значение true, если запись не должна быть удалена. Затем в методе удаления в вашем репозитории вы можете проверить, можно ли удалить удаляемую запись, и выбросить исключение или обработать ситуацию другим способом. Вы можете добавить это поле в черту и добавить его к любому объекту всего одной строкой. Мягкое удаление - это когда вы хотите пометить запись как удаленную, но хотите, чтобы она оставалась в базе данных.

...