可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a registration form in which users can fill in two email address (email1 & email2). Marketing's requirement is that they need to be unique (unique as in if we had 10 users, then there would be 10*2=20 unique email address).
The system is already built on cakephp, so what I'd like to know is, is there something similar to the isUnique feature (unique in one field) that can do this right out of the box? Or am I doomed to code this myself? Thanks in advance.
EDIT: built on Richard's example, this worked for me:
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);
}
回答1:
I posted a solution to this on the CakePHP Google Group:
http://groups.google.com/group/cake-php/browse_frm/thread/b3a1e4ae3eeb6091/e168f54bac27c163?lnk=gst&q=checkUnique#e168f54bac27c163
Add the following to your 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);
}
}
and is used in your model 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"
)
)
);
回答2:
checkUnique
could just be written as a wrapper for isUnique
.
class AppModel extends Model {
public function checkUnique($ignoredData, $fields, $or = true) {
return $this->isUnique($fields, $or);
}
}
and is used in your model 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'
)
)
);
回答3:
From cakePHP 2.0 documentation:
You can validate that a set of fields are unique by providing multiple fields and set $or to false:
public $validate = array(
'email' => array(
'rule' => array('isUnique', array('email', 'username'), false),
'message' => 'This username & email combination has already been used.'
)
);
Make sure to include the original field in the list of fields when making a unique rule across multiple fields.
If a listed field isn’t included in the model data, then it’s treated as a null value. You may consider marking the listed fields as required.
回答4:
Yes and no.
Yes, you will have to code it yourself, but within the CakePHP validation component.
The validation component has a mechanism to allow custom validation rules. Essentially, you put a function name inside $validate (like you normally would). You do have to define the function; in this case, it's pretty simple (just enforce your double isUnique requirement).
http://book.cakephp.org/2.0/en/models/data-validation.html#custom-validation-rules
回答5:
At the risk of being beaten about the head and shoulders for offering a non-CakePHP solution, let me present the following.
Create a unique index in your database over however many columns you need.
Standard SQL syntax for this is:
create unique index {IndexName} on {Table} ({Column}, {Column}, ...)
Place your "$this->Model->save()" command inside of a "try/catch" block. In the "catch" block, test the exception for the error code. In MySQL, a unique key violation is error code 23000, but you should be prepared for other possible errors as well.
It's quick and simple and doesn't involve counting array parentheses.
You should always place database access code inside a "try/catch" block anyway. Part of your exception handling should include logging any unexpected error messages. You can't expect CakePHP to do everything for you.
回答6:
As far as I remember, you have to this kind of enforcement using the beforeSave
method in the model. I had a requirement that an object have at least one of N fks set, and I could only do it this way.
Edit: try this thread to see if anything there solves your problem.