Последовательная логика использования SoftDeleteable

Всем известно, что SoftDeleteable является расширением Doctrine:

Это позволяет выполнять «обратимое удаление» объектов, фильтруя их во время SELECT, помечая их отметкой времени как, но не удаляя их явно из базы данных.

Теперь, учитывая это, что было бы последовательной логикой при вставке новых строк в таблицу и принятии вышеизложенного, помеченного как удаленное, но физически присутствующего?

Дело в том, что недавно я был вынужден использовать это поведение в приложении, но когда я вставляю новые записи и логически, когда они существуют, я получаю такую ​​​​ошибку:

Произошло исключение при выполнении «INSERT INTO fos_user (имя пользователя, имя пользователя_каноническое, электронная почта, электронная почта_каноническая, включено, соль, пароль, последний_логин, заблокировано, истекло, истекает_в, подтверждение_токен, пароль_запрошенный_ат, роли, учетные данные_истек срок действия, учетные данные_expire_at, deleteAt, createdAt, updatedAt) ЗНАЧЕНИЯ ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) 'с параметрами ["admin1" "admin1" "admin ", "admin", 1, "8ycal2x0eewwg0gw0o0gcw884ooossg", "886mLvLTi1yPdSBTR9Cfi++a3lvideQ4pw89ZHDOWVz86kJqXjx7C1 1ZIwTvzET7N1Fk\/yHsw10z3Cjm9k+m\/g==", null', 0, 0, g ==", null, 0, 0 0;s:16:\"ROLE_PROFILE_ONE\" i:1, s:16:\"ROLE_PROFILE_TWO\";}", 0, null, null," 12.09.2014 18:16:01""9/12 /2014 18:16:01"]:

SQLSTATE [23000]: нарушение ограничения целостности: 1062 Дублирующаяся запись «admin1» для ключа «UNIQ_957A647992FC23A8»

Мой вопрос: как вы обрабатываете SoftdDeleteable для ввода новых записей? Пример того, что вы делаете, или меньше идей пришли бы ко мне хорошо и помогли бы.


person ReynierPM    schedule 17.09.2014    source источник
comment
Вы хотите сохранить исходные строки с программным удалением и не допускать повторения имени пользователя или удалить оригинал и полностью заменить его?   -  person qooplmao    schedule 17.09.2014
comment
@Qoop, моя идея состоит в том, чтобы сохранить оригинал, это идея SoftDeleteable или нет?   -  person ReynierPM    schedule 17.09.2014
comment
Я не думаю, что за этим стоит какая-то конкретная идея, она может позволить вам выполнить мягкое удаление, а затем жесткое удаление или мягкое удаление и сохранить для записей. Я добавил ответ.   -  person qooplmao    schedule 17.09.2014


Ответы (1)


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

По умолчанию UniqueEntity использует findBy и репозиторий, установленный для класса, но имеет смысл создать собственный метод с отключенным фильтром по умолчанию, чтобы не возиться с ограничением, оставив обычный метод нетронутым.

Поскольку вы используете FOSUserBundle (по крайней мере, так кажется из названия таблицы fos_user), вы можете установить репозиторий Class в вашем сопоставлении (XML — это большая куча беспорядка, но вы можете видеть это здесь)...

// Annotation
@ORM\Entity(repositoryClass="Acme\StoreBundle\Entity\ProductRepository")

//YAML
Acme\UserBundle\Entity\User:
    type: entity
    repositoryClass: Acme\UserBundle\Entity\UserRepository

А затем в вашем UserRepository просто добавьте метод findIncludingSoftdeletedBy, отключающий фильтр softdeleteable, например...

namespace Acme\UserBundle\Entity;

use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository
{
    /**
     * Finds users by a set of criteria including sofdeleted.
     *
     * @param array      $criteria
     * @param array|null $orderBy
     * @param int|null   $limit
     * @param int|null   $offset
     *
     * @return array The objects.
     */
    public function findIncludingSoftdeletedBy(
        array $criteria, array $orderBy = null, $limit = null, $offset = null
    )
    {
        // Get array of enabled filters
        $enabledFilters = $this->em->getFilters()->getEnabledFilters();

        // If softdeleteable (or soft-deleteable depending on config) 
        // is in array of enabled filters disable it
        if (array_key_exists('softdeleteable', $endabledFilters)) {
            // disabled softdeleteable filter ($this->em being entity manager)
            $this->_em->getFilters()->disable('softdeleteable');
        }

        // return regular "findBy" including softdeleted users
        return $this->findBy($criteria, $orderBy, $limit, $offset);
    }
}

Обновить

Я забыл этот бит.

Затем вам нужно будет создать свой собственный файл проверки, который будет ссылаться на это новое ограничение проверки. (Для FOSUserBundle и в YAML (я предпочитаю YAML, XML выглядит так, будто на моем экране заболела книга по физике)).

Acme\UserBundle\Entity\User:
    constraints:
        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity:
            fields: usernameCanonical
            errorPath: username
            message: fos_user.username.already_used
            // Your method instead of the default "findBy"
            method: findIncludingSoftdeletedBy
            groups: [ Registration, Profile ]
        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity:
            fields: emailCanonical
            errorPath: email
            message: fos_user.email.already_used
            // Your method instead of the default "findBy"
            method: findIncludingSoftdeletedBy
            groups: [ Registration, Profile ]

Дополнительную информацию об ограничении UniqueEntity см. в документах, в частности..

поля
тип: массив | строка [опция по умолчанию]

Этот обязательный параметр представляет собой поле (или список полей), в котором этот объект должен быть уникальным. Например, если вы указали как поле электронной почты, так и поле имени в одном ограничении UniqueEntity, то это обеспечит уникальность значения комбинации (например, у двух пользователей может быть один и тот же адрес электронной почты, если у них нет одного и того же имени). ).

Если вам нужно, чтобы два поля были уникальными по отдельности (например, уникальный адрес электронной почты и уникальное имя пользователя), используйте две записи UniqueEntity, каждая с одним полем.

person qooplmao    schedule 17.09.2014
comment
этот подход удобен только для одного столбца, но что произойдет, если другие тоже будут УНИКАЛЬНЫМИ? Мне нужно будет повторить один и тот же код несколько раз, верно? Например, в FOSUserBundle, который я использую, как вы сказали ранее, username и email hard уникальны, но у меня есть и другие поля, поскольку мой класс User расширяется от BaseUser, тогда как работать с в этом случае? - person ReynierPM; 17.09.2014
comment
Строка ограничения UniqueEntity и массив $criteria из полей, которые вы установили, и их значения в объекте, а затем передает это вашему method, все, что вы делаете, — это совместная поддержка того, что уже есть, и добавление возможности отключения в softdeleteable фильтр. Так что просто используйте ограничение UniqueEntity обычным способом, но с установленным методом. - person qooplmao; 17.09.2014
comment
это не работает! Поскольку в вашем коде я не вижу, где определяется $em, я изменил вашу строку кода на эту: $this->getEntityManager()->getFilters()->disable('soft-deleteable');, которая возвращает это Filter 'soft-deleteable' is not enabled., поэтому что-то не работает. С другой стороны, если я прокомментирую эту строку, будет показана та же ошибка с дубликатами, какой-нибудь совет? - person ReynierPM; 18.09.2014
comment
Извините, может плохо. Это была просто копия и вставка из документов. Я не уверен, почему это не работает. Это может быть потому, что вы дважды отключаете фильтр (по одному разу для каждого звонка, но он уже отключен). Проверка того, включен ли фильтр, может помочь вам. Я обновлю. - person qooplmao; 18.09.2014
comment
Также это может быть связано с тем, что вы используете StofDoctrineExtensionsBundle, который регистрирует фильтр как softdeleteable, а не soft-deleteable, как исходные документы Gedmo. Пожалуйста, дайте мне знать, и я соответствующим образом обновлю свой ответ. - person qooplmao; 18.09.2014