1

每个人都知道SoftDeleteable是一个 Doctrine Extension:

这允许行为“软删除”对象,在 SELECT 时间通过将它们标记为时间戳来过滤它们,但不会从数据库中显式删除它们。

现在考虑这一点,当在表中插入新行并将上述标记为已删除但实际存在时,这将是一致的逻辑吗?

关键是我最近被迫在应用程序中使用此行为,但是当我插入新记录时,从逻辑上讲,当一个记录存在时,我收到如下错误:

执行“INSERT INTO fos_user (username, username_canonical, email, email_canonical, enabled, salt, password, last_login, locked, expired, expires_at, confirm_token, password_requested_at, roles, credentials_expired, credentials_expire_at, deletedAt, createdAt, updatedAt) VALUES ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) 'with params ["admin1" "admin1" "admin ", "admin", 1, "8ycal2x0eewwg0gw0o0gcw884ooossg", "886mLvLTi1yPdSBTR9Cfi + + a3lvideQ4pw89ZHDOWVz86kJqXjx7C1 1ZIwTvzET7N1Fk \ / yHsw10z3Cjm9k + m \ / g ==", null, 'a, 2: { null, null, null, 'a: 2 0;s:16:\"ROLE_PROFILE_ONE\"i:1,s:16:\"ROLE_PROFILE_TWO\";}",0,null,null,"09/12/2014 18:16:01""9/12 /2014 18:16:01"]:

SQLSTATE [23000]:完整性约束违规:1062 键 'UNIQ_957A647992FC23A8' 的重复条目 'admin1'

我的问题是,您如何处理SoftdDeleteable以输入新记录?你所做的或更少的想法的一个例子会对我很好并且会有所帮助。

4

1 回答 1

2

如果您想保留原件,那么您需要找到某种方式来确保之前没有使用过唯一字段。我认为最简单的方法是为您的用户字段使用自定义存储库并在搜索之前禁用 softdeleteable 过滤器。

默认情况下,UniqueEntity 使用 findBy 和为该类设置的存储库,但在默认情况下禁用过滤器创建您自己的方法是有意义的,以避免在保持常规方法完好无损的情况下弄乱约束。

当您使用 FOSUserBundle 时(或者从表名看来fos_user),您可以在映射中设置 repositoryClass(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 约束中同时指定 email 和 name 字段,那么它将强制组合值唯一(例如,两个用户可以拥有相同的电子邮件,只要他们不具有相同的名称) )。

如果您需要两个字段分别唯一(例如,一个唯一的电子邮件和一个唯一的用户名),您可以使用两个 UniqueEntity 条目,每个条目都有一个字段。

于 2014-09-17T11:23:57.683 回答