2007-09-11 02:26:55 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Shows two password-fields, and checks for matching passwords.
|
2007-12-19 02:45:22 +01:00
|
|
|
* Optionally hides the fields by default and shows
|
|
|
|
* a link to toggle their visibility.
|
2008-04-05 01:15:42 +02:00
|
|
|
*
|
2008-01-09 05:18:36 +01:00
|
|
|
* @package forms
|
|
|
|
* @subpackage fields-formattedinput
|
2007-09-11 02:26:55 +02:00
|
|
|
*/
|
|
|
|
class ConfirmedPasswordField extends FormField {
|
|
|
|
|
2007-12-19 02:45:22 +01:00
|
|
|
/**
|
|
|
|
* Minimum character length of the password.
|
|
|
|
*
|
|
|
|
* @var int
|
|
|
|
*/
|
2008-04-26 08:35:50 +02:00
|
|
|
public $minLength = null;
|
2007-09-11 02:26:55 +02:00
|
|
|
|
2007-12-19 02:45:22 +01:00
|
|
|
/**
|
|
|
|
* Maximum character length of the password.
|
|
|
|
*
|
|
|
|
* @var int
|
|
|
|
*/
|
2008-04-26 08:35:50 +02:00
|
|
|
public $maxLength = null;
|
2007-09-11 02:26:55 +02:00
|
|
|
|
2007-12-19 02:45:22 +01:00
|
|
|
/**
|
|
|
|
* Enforces at least one digit and one alphanumeric
|
|
|
|
* character (in addition to {$minLength} and {$maxLength}
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
*/
|
2007-09-11 02:26:55 +02:00
|
|
|
public $requireStrongPassword = false;
|
|
|
|
|
2007-12-19 02:45:22 +01:00
|
|
|
/**
|
|
|
|
* Allow empty fields in serverside validation
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
*/
|
2007-09-11 02:26:55 +02:00
|
|
|
public $canBeEmpty = false;
|
|
|
|
|
2007-12-19 02:45:22 +01:00
|
|
|
/**
|
2008-11-22 04:33:00 +01:00
|
|
|
* If set to TRUE, the "password" and "confirm password"
|
|
|
|
* formfields will be hidden via CSS and JavaScript by default,
|
|
|
|
* and triggered by a link. An additional hidden field
|
|
|
|
* determines if showing the fields has been triggered,
|
|
|
|
* and just validates/saves the input in this case.
|
|
|
|
* This behaviour works unobtrusively, without JavaScript enabled
|
|
|
|
* the fields show, validate and save by default.
|
|
|
|
*
|
|
|
|
* @param boolean $showOnClick
|
2007-12-19 02:45:22 +01:00
|
|
|
*/
|
|
|
|
protected $showOnClick = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Title for the link that triggers
|
|
|
|
* the visibility of password fields.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
2008-11-22 04:33:00 +01:00
|
|
|
public $showOnClickTitle;
|
2007-12-19 02:45:22 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $name
|
|
|
|
* @param string $title
|
|
|
|
* @param mixed $value
|
|
|
|
* @param Form $form
|
|
|
|
* @param boolean $showOnClick
|
2008-04-09 13:29:29 +02:00
|
|
|
* @param string $titleConfirmField Alternate title (not localizeable)
|
2007-12-19 02:45:22 +01:00
|
|
|
*/
|
2008-04-09 13:29:29 +02:00
|
|
|
function __construct($name, $title = null, $value = "", $form = null, $showOnClick = false, $titleConfirmField = null) {
|
2007-09-11 02:26:55 +02:00
|
|
|
// naming with underscores to prevent values from actually being saved somewhere
|
2011-05-11 09:51:54 +02:00
|
|
|
$this->children = new FieldList(
|
2008-04-09 13:29:29 +02:00
|
|
|
new PasswordField(
|
|
|
|
"{$name}[_Password]",
|
2010-12-08 23:07:37 +01:00
|
|
|
(isset($title)) ? $title : _t('Member.PASSWORD', 'Password')
|
|
|
|
),
|
2008-04-09 13:29:29 +02:00
|
|
|
new PasswordField(
|
|
|
|
"{$name}[_ConfirmPassword]",
|
|
|
|
(isset($titleConfirmField)) ? $titleConfirmField : _t('Member.CONFIRMPASSWORD', 'Confirm Password')
|
|
|
|
)
|
2007-09-11 02:26:55 +02:00
|
|
|
);
|
2008-11-22 04:33:00 +01:00
|
|
|
|
|
|
|
// has to be called in constructor because Field() isn't triggered upon saving the instance
|
|
|
|
if($showOnClick) {
|
2007-12-19 02:45:22 +01:00
|
|
|
$this->children->push(new HiddenField("{$name}[_PasswordFieldVisible]"));
|
|
|
|
}
|
2008-11-22 04:33:00 +01:00
|
|
|
$this->showOnClick = $showOnClick;
|
2007-12-19 02:45:22 +01:00
|
|
|
|
|
|
|
// we have labels for the subfields
|
|
|
|
$title = false;
|
2007-09-11 02:26:55 +02:00
|
|
|
|
2009-06-27 06:00:10 +02:00
|
|
|
parent::__construct($name, $title, null, $form);
|
|
|
|
$this->setValue($value);
|
2007-09-11 02:26:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function Field() {
|
2011-02-25 05:01:46 +01:00
|
|
|
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery/jquery.js');
|
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
|
|
|
Requirements::javascript(SAPPHIRE_DIR . '/javascript/ConfirmedPasswordField.js');
|
2011-02-25 05:01:46 +01:00
|
|
|
Requirements::css(SAPPHIRE_DIR . '/css/ConfirmedPasswordField.css');
|
2007-12-19 02:45:22 +01:00
|
|
|
|
2007-09-11 02:26:55 +02:00
|
|
|
$content = '';
|
2007-12-19 02:45:22 +01:00
|
|
|
|
|
|
|
if($this->showOnClick) {
|
2008-11-22 04:33:00 +01:00
|
|
|
if($this->showOnClickTitle) {
|
|
|
|
$title = $this->showOnClickTitle;
|
|
|
|
} else {
|
|
|
|
$title = _t(
|
|
|
|
'ConfirmedPasswordField.SHOWONCLICKTITLE',
|
|
|
|
'Change Password',
|
|
|
|
PR_MEDIUM,
|
|
|
|
'Label of the link which triggers display of the "change password" formfields'
|
|
|
|
);
|
|
|
|
}
|
2007-12-19 02:45:22 +01:00
|
|
|
|
|
|
|
$content .= "<div class=\"showOnClick\">\n";
|
2012-03-07 17:45:14 +01:00
|
|
|
$content .= "<a href=\"#\">{$title}</a>\n";
|
2007-12-19 02:45:22 +01:00
|
|
|
$content .= "<div class=\"showOnClickContainer\">";
|
|
|
|
}
|
2008-11-22 04:33:00 +01:00
|
|
|
|
2007-09-11 02:26:55 +02:00
|
|
|
foreach($this->children as $field) {
|
2009-04-29 01:55:53 +02:00
|
|
|
$field->setDisabled($this->isDisabled());
|
|
|
|
$field->setReadonly($this->isReadonly());
|
2007-12-19 02:45:22 +01:00
|
|
|
$content .= $field->FieldHolder();
|
|
|
|
}
|
|
|
|
|
|
|
|
if($this->showOnClick) {
|
|
|
|
$content .= "</div>\n";
|
|
|
|
$content .= "</div>\n";
|
2007-09-11 02:26:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $content;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Can be empty is a flag that turns on/off empty field checking.
|
|
|
|
* For example, set this to false (the default) when creating a user account,
|
|
|
|
* and true
|
|
|
|
*/
|
|
|
|
function setCanBeEmpty($value) {
|
|
|
|
$this->canBeEmpty = (bool)$value;
|
2012-02-17 13:35:26 +01:00
|
|
|
return $this;
|
2007-09-11 02:26:55 +02:00
|
|
|
}
|
|
|
|
|
2008-11-22 04:33:00 +01:00
|
|
|
/**
|
|
|
|
* The title on the link which triggers display of the
|
|
|
|
* "password" and "confirm password" formfields.
|
|
|
|
* Only used if {@link setShowOnClick()} is set to TRUE.
|
|
|
|
*
|
|
|
|
* @param $title
|
|
|
|
*/
|
|
|
|
public function setShowOnClickTitle($title) {
|
|
|
|
$this->showOnClickTitle = $title;
|
2012-02-17 13:35:26 +01:00
|
|
|
return $this;
|
2008-11-22 04:33:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getShowOnClickTitle() {
|
|
|
|
return $this->showOnClickTitle;
|
|
|
|
}
|
|
|
|
|
2007-09-11 02:26:55 +02:00
|
|
|
function setRightTitle($title) {
|
|
|
|
foreach($this->children as $field) {
|
|
|
|
$field->setRightTitle($title);
|
|
|
|
}
|
2012-02-17 13:35:26 +01:00
|
|
|
return $this;
|
2007-09-11 02:26:55 +02:00
|
|
|
}
|
|
|
|
|
2009-06-23 09:47:45 +02:00
|
|
|
/**
|
|
|
|
* @param array: 2 entrie array with the customised title for each of the 2 children.
|
|
|
|
*/
|
2009-06-23 09:46:12 +02:00
|
|
|
function setChildrenTitles($titles) {
|
2009-06-23 09:47:45 +02:00
|
|
|
if(is_array($titles)&&count($titles)==2){
|
2009-06-23 09:46:12 +02:00
|
|
|
foreach($this->children as $field) {
|
|
|
|
if(isset($titles[0])){
|
|
|
|
$field->setTitle($titles[0]);
|
|
|
|
array_shift($titles);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-17 13:35:26 +01:00
|
|
|
return $this;
|
2009-06-23 09:46:12 +02:00
|
|
|
}
|
|
|
|
|
2007-09-11 02:26:55 +02:00
|
|
|
/**
|
|
|
|
* Value is sometimes an array, and sometimes a single value, so we need to handle both cases
|
|
|
|
*/
|
|
|
|
function setValue($value) {
|
|
|
|
if(is_array($value)) {
|
|
|
|
if($value['_Password'] || (!$value['_Password'] && !$this->canBeEmpty)) {
|
|
|
|
$this->value = $value['_Password'];
|
|
|
|
}
|
2011-04-25 12:44:54 +02:00
|
|
|
if($this->showOnClick && isset($value['_PasswordFieldVisible'])){
|
2011-10-29 06:01:52 +02:00
|
|
|
$this->children->fieldByName($this->getName() . '[_PasswordFieldVisible]')->setValue($value['_PasswordFieldVisible']);
|
2008-05-24 03:22:27 +02:00
|
|
|
}
|
2007-09-11 02:26:55 +02:00
|
|
|
} else {
|
2011-03-18 23:10:34 +01:00
|
|
|
if($value || (!$value && $this->canBeEmpty)) {
|
2007-09-11 02:26:55 +02:00
|
|
|
$this->value = $value;
|
|
|
|
}
|
|
|
|
}
|
2011-10-29 06:01:52 +02:00
|
|
|
$this->children->fieldByName($this->getName() . '[_Password]')->setValue($this->value);
|
|
|
|
$this->children->fieldByName($this->getName() . '[_ConfirmPassword]')->setValue($this->value);
|
2012-02-17 13:35:26 +01:00
|
|
|
|
|
|
|
return $this;
|
2007-09-11 02:26:55 +02:00
|
|
|
}
|
|
|
|
|
2007-12-19 02:45:22 +01:00
|
|
|
/**
|
|
|
|
* Determines if the field was actually
|
|
|
|
* shown on the clientside - if not,
|
|
|
|
* we don't validate or save it.
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
function isSaveable() {
|
2011-10-29 06:01:52 +02:00
|
|
|
$isVisible = $this->children->fieldByName($this->getName() . '[_PasswordFieldVisible]');
|
2007-12-19 02:45:22 +01:00
|
|
|
return (!$this->showOnClick || ($this->showOnClick && $isVisible && $isVisible->Value()));
|
|
|
|
}
|
|
|
|
|
2007-09-11 02:26:55 +02:00
|
|
|
function validate() {
|
|
|
|
$validator = $this->form->getValidator();
|
|
|
|
$name = $this->name;
|
2007-12-19 02:45:22 +01:00
|
|
|
|
|
|
|
// if field isn't visible, don't validate
|
|
|
|
if(!$this->isSaveable()) return true;
|
|
|
|
|
2007-09-11 02:26:55 +02:00
|
|
|
$passwordField = $this->children->fieldByName($name.'[_Password]');
|
|
|
|
$passwordConfirmField = $this->children->fieldByName($name.'[_ConfirmPassword]');
|
|
|
|
$passwordField->setValue($_POST[$name]['_Password']);
|
|
|
|
$passwordConfirmField->setValue($_POST[$name]['_ConfirmPassword']);
|
2007-12-19 02:45:22 +01:00
|
|
|
|
|
|
|
$value = $passwordField->Value();
|
|
|
|
|
2007-09-11 02:26:55 +02:00
|
|
|
// both password-fields should be the same
|
2007-12-19 02:45:22 +01:00
|
|
|
if($value != $passwordConfirmField->Value()) {
|
2007-10-25 04:47:45 +02:00
|
|
|
$validator->validationError($name, _t('Form.VALIDATIONPASSWORDSDONTMATCH',"Passwords don't match"), "validation", false);
|
2007-09-11 02:26:55 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$this->canBeEmpty) {
|
|
|
|
// both password-fields shouldn't be empty
|
2007-12-19 02:52:11 +01:00
|
|
|
if(!$value || !$passwordConfirmField->Value()) {
|
2007-10-25 04:47:45 +02:00
|
|
|
$validator->validationError($name, _t('Form.VALIDATIONPASSWORDSNOTEMPTY', "Passwords can't be empty"), "validation", false);
|
2007-09-11 02:26:55 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// lengths
|
2007-12-19 02:45:22 +01:00
|
|
|
if(($this->minLength || $this->maxLength)) {
|
2007-09-11 02:26:55 +02:00
|
|
|
if($this->minLength && $this->maxLength) {
|
2008-09-12 07:40:55 +02:00
|
|
|
$limit = "{{$this->minLength},{$this->maxLength}}";
|
2008-01-10 04:28:13 +01:00
|
|
|
$errorMsg = sprintf(_t('ConfirmedPasswordField.BETWEEN', 'Passwords must be %s to %s characters long.'), $this->minLength, $this->maxLength);
|
2007-09-11 02:26:55 +02:00
|
|
|
} elseif($this->minLength) {
|
2008-09-12 07:40:55 +02:00
|
|
|
$limit = "{{$this->minLength}}.*";
|
2008-01-10 04:28:13 +01:00
|
|
|
$errorMsg = sprintf(_t('ConfirmedPasswordField.ATLEAST', 'Passwords must be at least %s characters long.'), $this->minLength);
|
2007-09-11 02:26:55 +02:00
|
|
|
} elseif($this->maxLength) {
|
2008-09-12 07:40:55 +02:00
|
|
|
$limit = "{0,{$this->maxLength}}";
|
2008-01-10 04:28:13 +01:00
|
|
|
$errorMsg = sprintf(_t('ConfirmedPasswordField.MAXIMUM', 'Passwords must be at most %s characters long.'), $this->maxLength);
|
2007-09-11 02:26:55 +02:00
|
|
|
}
|
2008-09-12 07:40:55 +02:00
|
|
|
$limitRegex = '/^.' . $limit . '$/';
|
2007-12-19 02:45:22 +01:00
|
|
|
if(!empty($value) && !preg_match($limitRegex,$value)) {
|
2007-09-11 02:26:55 +02:00
|
|
|
$validator->validationError('Password', $errorMsg,
|
|
|
|
"validation",
|
|
|
|
false
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if($this->requireStrongPassword) {
|
2007-12-19 02:45:22 +01:00
|
|
|
if(!preg_match('/^(([a-zA-Z]+\d+)|(\d+[a-zA-Z]+))[a-zA-Z0-9]*$/',$value)) {
|
2007-09-11 02:26:55 +02:00
|
|
|
$validator->validationError(
|
|
|
|
'Password',
|
2007-10-25 04:47:45 +02:00
|
|
|
_t('Form.VALIDATIONSTRONGPASSWORD', "Passwords must have at least one digit and one alphanumeric character."),
|
2007-09-11 02:26:55 +02:00
|
|
|
"validation",
|
|
|
|
false
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2007-11-12 03:58:27 +01:00
|
|
|
|
2007-12-19 02:45:22 +01:00
|
|
|
/**
|
|
|
|
* Only save if field was shown on the client,
|
|
|
|
* and is not empty.
|
|
|
|
*
|
|
|
|
* @param DataObject $record
|
|
|
|
* @return bool
|
|
|
|
*/
|
2007-11-12 03:58:27 +01:00
|
|
|
function saveInto(DataObject $record) {
|
2007-12-19 02:45:22 +01:00
|
|
|
if(!$this->isSaveable()) return false;
|
|
|
|
|
2007-11-12 03:58:27 +01:00
|
|
|
if(!($this->canBeEmpty && !$this->value)) {
|
|
|
|
parent::saveInto($record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Makes a pretty readonly field with some stars in it
|
|
|
|
*/
|
|
|
|
function performReadonlyTransformation() {
|
|
|
|
$stars = '*****';
|
|
|
|
|
|
|
|
$field = new ReadonlyField($this->name, $this->title ? $this->title : _t('Member.PASSWORD'), $stars);
|
|
|
|
$field->setForm($this->form);
|
|
|
|
return $field;
|
|
|
|
}
|
|
|
|
}
|