CakePHP уникален для 2 полей?
У меня есть форма регистрации, в которой пользователи могут заполнить два адреса электронной почты (email1 и email2). Маркетинговое требование состоит в том, что они должны быть уникальными (уникальными, как если бы у нас было 10 пользователей, тогда было бы 10*2=20 уникальных адресов электронной почты).
Система уже построена на CakePHP, так что я хотел бы знать, есть ли что-то похожее на функцию isUnique (уникальную в одной области), которая может сделать это прямо из коробки? Или я обречен сам кодировать это? Заранее спасибо.
РЕДАКТИРОВАТЬ: построен на примере Ричарда, это работает для меня:
function checkUnique($data, $fields) {
if (!is_array($fields)) {
$fields = array($fields);
}
foreach($data as $key) {
$checks = $key;
}
if (empty($checks)) {
return true; //allow null
}
foreach($fields as $key) {
$tmp[$key] = $checks;
}
if (isset($this->data[$this->name][$this->primaryKey])) {
$tmp[$this->primaryKey] = "<>".$this->data[$this->name][$this->primaryKey];
}
return $this->isUnique($tmp);
}
6 ответов
Я опубликовал решение этой проблемы в CakePHP Google Group:
Добавьте следующее в вашу AppModel:
/**
* checks is the field value is unqiue in the table
* note: we are overriding the default cakephp isUnique test as the
original appears to be broken
*
* @param string $data Unused ($this->data is used instead)
* @param mnixed $fields field name (or array of field names) to
validate
* @return boolean true if combination of fields is unique
*/
function checkUnique($data, $fields) {
if (!is_array($fields)) {
$fields = array($fields);
}
foreach($fields as $key) {
$tmp[$key] = $this->data[$this->name][$key];
}
if (isset($this->data[$this->name][$this->primaryKey])) {
$tmp[$this->primaryKey] = "<>".$this->data[$this->name][$this-
>primaryKey];
}
return $this->isUnique($tmp, false);
}
}
и используется в вашей модели validate:
var $validate = array(
"name"=>array(
"unique"=>array(
"rule"=>array("checkUnique", array("name", "institution_id")),
"message"=>"A contact with that name already exists for that
institution"
)
)
);
checkUnique
можно просто написать как обертку для isUnique
,
class AppModel extends Model {
public function checkUnique($ignoredData, $fields, $or = true) {
return $this->isUnique($fields, $or);
}
}
и используется в вашей модели validate:
public $validate = array(
'name' => array(
'unique' => array(
'rule' => array('checkUnique', array('name', 'institution_id'), false),
'message' => 'A contact with that name already exists for that
institution'
)
)
);
Вы можете проверить, что набор полей уникален, предоставив несколько полей и установив $ или в false:
public $validate = array(
'email' => array(
'rule' => array('isUnique', array('email', 'username'), false),
'message' => 'This username & email combination has already been used.'
)
);
Не забудьте включить исходное поле в список полей при создании уникального правила для нескольких полей.
Если указанное поле не включено в данные модели, оно рассматривается как нулевое значение. Вы можете пометить перечисленные поля как обязательные.
И да и нет.
Да, вам придется кодировать его самостоятельно, но в рамках компонента проверки CakePHP.
Компонент проверки имеет механизм, позволяющий настраивать правила проверки. По сути, вы помещаете имя функции в $ validate (как обычно). Вы должны определить функцию; в этом случае все довольно просто (просто примените ваше двойное требование isUnique).
Риск быть избитым по голове и плечам за предложение решения, отличного от CakePHP, позвольте мне представить следующее.
Создайте уникальный индекс в вашей базе данных на сколько угодно столбцов.
Стандартный синтаксис SQL для этого:
create unique index {IndexName} on {Table} ({Column}, {Column}, ...)
Поместите команду "$this->Model->save()" внутри блока "try/catch". В блоке "catch" проверьте исключение для кода ошибки. В MySQL единственным нарушением ключа является код ошибки 23000, но вы должны быть готовы и к другим возможным ошибкам.
Это быстро и просто и не требует подсчета скобок.
В любом случае вы всегда должны размещать код доступа к базе данных внутри блока try / catch. Часть вашей обработки исключений должна включать регистрацию любых неожиданных сообщений об ошибках. Вы не можете ожидать, что CakePHP сделает все за вас.
Насколько я помню, вы должны к такому виду принуждения, используя beforeSave
метод в модели. У меня было требование, чтобы у объекта был установлен хотя бы один из N fks, и я мог сделать это только так.
Изменить: попробуйте эту тему, чтобы увидеть, если что-то там решает вашу проблему.