From 4d43a61605f901ef5652249c80114bd5e495e4d3 Mon Sep 17 00:00:00 2001 From: Sean Harvey Date: Wed, 28 Jan 2009 05:17:33 +0000 Subject: [PATCH] ENHANCEMENT Allow selection of the unique identifier field on Member by setting Member::set_unique_identifier_field(AnotherField). Default is "Email". git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.3@70861 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- dev/BulkLoader.php | 6 +++ security/Member.php | 118 ++++++++++++++++++++++++++------------------ 2 files changed, 75 insertions(+), 49 deletions(-) diff --git a/dev/BulkLoader.php b/dev/BulkLoader.php index 0db8cd532..ce4557025 100644 --- a/dev/BulkLoader.php +++ b/dev/BulkLoader.php @@ -95,6 +95,12 @@ abstract class BulkLoader extends ViewableData { * Alternatively the array values can contain a callback method (see example for * implementation details). The callback method should be defined on the source class. * + * NOTE: If you're trying to get a unique Member record by a particular field that + * isn't Email, you need to ensure that Member is correctly set to the unique field + * you want, as it will merge any duplicates during {@link Member::onBeforeWrite()}. + * + * {@see Member::set_unique_identifier_field()}. + * * If multiple checks are specified, the first one "wins". * * diff --git a/security/Member.php b/security/Member.php index 38d242151..ac6b34dff 100644 --- a/security/Member.php +++ b/security/Member.php @@ -68,6 +68,15 @@ class Member extends DataObject { 'Email', ); + /** + * The unique field used to identify this member. + * By default, it's "Email", but another common + * field could be Username. + * + * @var string + */ + protected static $unique_identifier_field = 'Email'; + /** * {@link PasswordValidator} object for validating user's password */ @@ -130,8 +139,30 @@ class Member extends DataObject { // This can be called via CLI during testing. if(Director::is_cli()) return; - $file = ""; $line = ""; - if (!headers_sent($file, $line)) session_regenerate_id(true); + $file = ''; + $line = ''; + + if(!headers_sent($file, $line)) session_regenerate_id(true); + } + + /** + * Get the field used for uniquely identifying a member + * in the database. {@see Member::$unique_identifier_field} + * + * @return string + */ + static function get_unique_identifier_field() { + return self::$unique_identifier_field; + } + + /** + * Set the field used for uniquely identifying a member + * in the database. {@see Member::$unique_identifier_field} + * + * @param $field The field name to set as the unique field + */ + static function set_unique_identifier_field($field) { + self::$unique_identifier_field = $field; } /** @@ -416,29 +447,18 @@ class Member extends DataObject { } } - /** - * Event handler called before writing to the database - * - * If an email's filled out look for a record with the same email and if - * found update this record to merge with that member. + * Event handler called before writing to the database. */ - function onBeforeWrite() { if($this->SetPassword) $this->Password = $this->SetPassword; - if($this->Email) { - if($this->ID) { - $idClause = "AND `Member`.ID <> $this->ID"; - } else { - $idClause = ""; - } - - $existingRecord = DataObject::get_one( - "Member", "Email = '" . addslashes($this->Email) . "' $idClause"); - - // Debug::message("Found an existing member for email $this->Email"); - + $identifierField = self::$unique_identifier_field; + if($this->$identifierField) { + $idClause = ($this->ID) ? " AND `Member`.ID <> $this->ID" : ''; + $SQL_identifierField = Convert::raw2sql($this->$identifierField); + + $existingRecord = DataObject::get_one('Member', "$identifierField = '{$SQL_identifierField}'{$idClause}"); if($existingRecord) { $newID = $existingRecord->ID; if($this->ID) { @@ -740,15 +760,13 @@ class Member extends DataObject { $groupIDList = array(); if(is_a($groups, 'DataObjectSet')) { - foreach($groups as $group) + foreach($groups as $group) { $groupIDList[] = $group->ID; + } } elseif(is_array($groups)) { $groupIDList = $groups; } - /*if( empty( $groupIDList ) ) - return Member::map(); */ - $filterClause = ($groupIDList) ? "`GroupID` IN (" . implode( ',', $groupIDList ) . ")" : ""; @@ -771,8 +789,7 @@ class Member extends DataObject { * @return array Groups in which the member is NOT in. */ public function memberNotInGroups($groupList, $memberGroups = null){ - if(!$memberGroups) - $memberGroups = $this->Groups(); + if(!$memberGroups) $memberGroups = $this->Groups(); foreach($memberGroups as $group) { if(in_array($group->Code, $groupList)) { @@ -780,6 +797,7 @@ class Member extends DataObject { unset($groupList[$index]); } } + return $groupList; } @@ -907,10 +925,6 @@ class Member extends DataObject { if($valid->valid()) { $this->AutoLoginHash = null; $this->write(); - - // Emails will be sent by Member::onBeforeWrite(). - - //$this->sendinfo('changePassword', array('CleartextPassword' => $password)); } return $valid; @@ -1343,27 +1357,36 @@ class Member_Validator extends RequiredFields { */ function php($data) { $valid = parent::php($data); + + $identifierField = Member::get_unique_identifier_field(); + + $SQL_identifierField = Convert::raw2sql($data[$identifierField]); + $member = DataObject::get_one('Member', "$identifierField = '{$SQL_identifierField}'"); - $member = DataObject::get_one('Member', - "Email = '". Convert::raw2sql($data['Email']) ."'"); - - // if we are in a complex table field popup, use ctf[childID], else use - // ID - if(isset($_REQUEST['ctf']['childID'])) + // if we are in a complex table field popup, use ctf[childID], else use ID + if(isset($_REQUEST['ctf']['childID'])) { $id = $_REQUEST['ctf']['childID']; - elseif(isset($_REQUEST['ID'])) + } elseif(isset($_REQUEST['ID'])) { $id = $_REQUEST['ID']; - else + } else { $id = null; - - if($id && is_object($member) && $member->ID != $id) { - $emailField = $this->form->dataFieldByName('Email'); - $this->validationError($emailField->id(), - _t('Member.VALIDATIONMEMBEREXISTS', "There already exists a member with this email"), - "required"); - $valid = false; } + if($id && is_object($member) && $member->ID != $id) { + $uniqueField = $this->form->dataFieldByName($identifierField); + $this->validationError( + $uniqueField->id(), + sprintf( + _t( + 'Member.VALIDATIONMEMBEREXISTS', + 'A member already exists with the same %s' + ), + strtolower($identifierField) + ), + 'required' + ); + $valid = false; + } // Execute the validators on the extensions if($this->extension_instances) { @@ -1374,7 +1397,6 @@ class Member_Validator extends RequiredFields { } } - return $valid; } @@ -1401,9 +1423,7 @@ class Member_Validator extends RequiredFields { return $js; } } - // Initialize the static DB variables to add the supported encryption // algorithms to the PasswordEncryption Enum field Member::init_db_fields(); - -?> +?> \ No newline at end of file