CakePHP 3允许空重复的多个isUnique

5

我在BlockedTable.php中有以下规则:

public function buildRules(RulesChecker $rules)
{
    $rules->add($rules->isUnique(['date', 'time']),
        ['message' => 'unique error']);

    return $rules;
}

到目前为止,这个功能一直很好用 - 如果我尝试保存一个已经存在的日期和时间的新记录,它会阻止我保存。

然而,如果我的时间是NULL,就像下面的条目一样;

╔════╦══════════════╦═══════╗
║ ID ║  Date        ║ Time  ║
╠════╬══════════════╬═══════╣
║  1 ║ 22/08/1985   ║ NULL  ║
╚════╩══════════════╩═══════╝

规则仍允许我使用相同的数据保存新条目。因此,如果我尝试保存$date = 22/08/1985$time = NULL,它会成功保存,并且我的数据库中会有重复记录。我原本期望由于上述规则而失败?
为什么会发生这种情况?如何防止在NULL值上出现重复条目?
感谢您的帮助。

如果CakePHP 5是您的选择,那么它现在已默认启用。https://github.com/cakephp/cakephp/issues/15734 - Peter VARGA
2个回答

2
使用普通比较运算符(即column = NULL,这是唯一规则所做的)与NULL进行比较时,应始终返回NULL(据我所知,至少在MySQL和Postgres中是这样),因此无法找到任何内容,并且只要涉及NULL值,唯一检查就会通过。
如果您想防止这种行为,您将需要使用自定义规则,因为内置规则根本不支持它。我认为这是值得改进的问题,因此您可能需要在GitHub上开启一个工单。
以下是一个重写的IsUnique规则类的基本示例,它基本上只是向条件键添加了一个IS运算符,以便NULL检查最终变成column IS NULL
public function __invoke(EntityInterface $entity, array $options)
{
    if (!$entity->extract($this->_fields, true)) {
        return true;
    }

    $alias = $options['repository']->alias();
    $conditions = $this->_alias($alias, $entity->extract($this->_fields));
    if ($entity->isNew() === false) {
        $keys = (array)$options['repository']->primaryKey();
        $keys = $this->_alias($alias, $entity->extract($keys));
        if (array_filter($keys, 'strlen')) {
            $conditions['NOT'] = $keys;
        }
    }

    // handle null values
    foreach ($conditions as $key => $value) {
        if ($value === null) {
            $conditions[$key . ' IS'] = $value;
            unset($conditions[$key]);
        }
    }

    return !$options['repository']->exists($conditions);
}

理论上来说,您也可以在重载的 IsUnique::_alias() 方法中完成这个操作,这样就不需要重新实现原始规则类中的代码,但这并不是正确的地方。

https://github.com/cakephp/cakephp/blob/3.2.5/src/ORM/Rule/IsUnique.php

另请参阅


感谢您提供深入的答案,我会考虑我的选择,并同时创建一个增强工单。 - JayIsTooCommon
刚刚完成了自定义规则,而且完美地运行了。再次感谢。 - JayIsTooCommon

1

我知道这是一个旧帖子,但是由于我不得不花很多时间搜索来解决这个问题,所以我认为我应该在这里发布我是如何做到的。

在cakePHP 3.6中,您可以通过将isUnique类中的allowMultipleNulls属性更改为false来解决此问题。

问候。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接