Source of file CustomConfirmedPasswordField.php
Size: 13,407 Bytes - Last Modified: 2021-12-24T06:39:20+00:00
/var/www/docs.ssmods.com/process/src/code/CustomConfirmedPasswordField.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 | <?php /** * this allows you to add individual placeholders to the confirm password fields * * @author patrick chitovoro * @copyright (c) 2015, Chito Systems */ class CustomConfirmedPasswordField extends FormField { /** * Minimum character length of the password. * * @var int */ public $minLength = null; /** * Maximum character length of the password. * * @var int */ public $maxLength = null; /** * Enforces at least one digit and one alphanumeric * character (in addition to {$minLength} and {$maxLength} * * @var boolean */ public $requireStrongPassword = false; /** * Allow empty fields in serverside validation * * @var boolean */ public $canBeEmpty = false; /** * If set to TRUE, the "password" and "confirm password" form fields 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 */ protected $showOnClick = false; /** * A place to temporarly store the confirm password value * @var string */ protected $confirmValue; /** * Title for the link that triggers the visibility of password fields. * * @var string */ public $showOnClickTitle; /** * Child fields (_Password, _ConfirmPassword) * * @var FieldList */ public $children; /** * @param string $name * @param string $title * @param mixed $value * @param Form $form * @param boolean $showOnClick * @param string $titleConfirmField Alternate title (not localizeable) */ public function __construct($name, $title = null, $value = "", $form = null, $showOnClick = false, $titleConfirmField = null) { // naming with underscores to prevent values from actually being saved somewhere $this->children = new FieldList( new BootstrapConfirmPasswordField( "{$name}[_Password]", (isset($title)) ? $title : _t('Member.PASSWORD', 'Password') ), new BootstrapConfirmPasswordField( "{$name}[_ConfirmPassword]", (isset($titleConfirmField)) ? $titleConfirmField : _t('Member.CONFIRMPASSWORD', 'Confirm Password') ) ); // has to be called in constructor because Field() isn't triggered upon saving the instance if($showOnClick) { $this->children->push(new HiddenField("{$name}[_PasswordFieldVisible]")); } // disable auto complete foreach($this->children as $child) { $child->setAttribute('autocomplete', 'off'); } $this->showOnClick = $showOnClick; // we have labels for the subfields $title = false; parent::__construct($name, $title, null, $form); $this->setValue($value); } /** * @param array $properties * * @return string */ public function Field($properties = array()) { Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery/jquery.js'); Requirements::javascript(FRAMEWORK_DIR . '/javascript/ConfirmedPasswordField.js'); Requirements::css(FRAMEWORK_DIR . '/css/ConfirmedPasswordField.css'); $content = ''; if($this->showOnClick) { if($this->showOnClickTitle) { $title = $this->showOnClickTitle; } else { $title = _t( 'ConfirmedPasswordField.SHOWONCLICKTITLE', 'Change Password', 'Label of the link which triggers display of the "change password" formfields' ); } $content .= "<div class=\"showOnClick\">\n"; $content .= "<a href=\"#\">{$title}</a>\n"; $content .= "<div class=\"showOnClickContainer\">"; } foreach($this->children as $field) { $field->setDisabled($this->isDisabled()); $field->setReadonly($this->isReadonly()); if(count($this->attributes)) { foreach($this->attributes as $name => $value) { $field->setAttribute($name, $value); } } $content .= $field->FieldHolder(); } if($this->showOnClick) { $content .= "</div>\n"; $content .= "</div>\n"; } 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 when displaying on an edit form. * * @param boolean $value * * @return ConfirmedPasswordField */ public function setCanBeEmpty($value) { $this->canBeEmpty = (bool)$value; return $this; } /** * 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 string $title * * @return ConfirmedPasswordField */ public function setShowOnClickTitle($title) { $this->showOnClickTitle = $title; return $this; } /** * @return string $title */ public function getShowOnClickTitle() { return $this->showOnClickTitle; } /** * @param string $title * * @return ConfirmedPasswordField */ public function setRightTitle($title) { foreach($this->children as $field) { $field->setRightTitle($title); } return $this; } /** * @param array $titles 2 entry array with the customized title for each * of the 2 children. * * @return ConfirmedPasswordField */ public function setChildrenTitles($titles) { if(is_array($titles) && count($titles) == 2) { foreach($this->children as $field) { if(isset($titles[0])) { $field->setTitle($titles[0]); array_shift($titles); } } } return $this; } /** * Value is sometimes an array, and sometimes a single value, so we need * to handle both cases. * * @param mixed $value * * @return ConfirmedPasswordField */ public function setValue($value, $data = null) { // If $data is a DataObject, don't use the value, since it's a hashed value if ($data && $data instanceof DataObject) $value = ''; //store this for later $oldValue = $this->value; if(is_array($value)) { $this->value = $value['_Password']; $this->confirmValue = $value['_ConfirmPassword']; if($this->showOnClick && isset($value['_PasswordFieldVisible'])) { $this->children->fieldByName($this->getName() . '[_PasswordFieldVisible]') ->setValue($value['_PasswordFieldVisible']); } } else { if($value || (!$value && $this->canBeEmpty)) { $this->value = $value; } } //looking up field by name is expensive, so lets check it needs to change if ($oldValue != $this->value) { $this->children->fieldByName($this->getName() . '[_Password]') ->setValue($this->value); $this->children->fieldByName($this->getName() . '[_ConfirmPassword]') ->setValue($this->value); } return $this; } /** * Update the names of the child fields when updating name of field. * * @param string $name new name to give to the field. */ public function setName($name) { $this->children->fieldByName($this->getName() . '[_Password]') ->setName($name . '[_Password]'); $this->children->fieldByName($this->getName() . '[_ConfirmPassword]') ->setName($name . '[_ConfirmPassword]'); return parent::setName($name); } /** * Determines if the field was actually shown on the client side - if not, * we don't validate or save it. * * @return boolean */ public function isSaveable() { $isVisible = $this->children->fieldByName($this->getName() . '[_PasswordFieldVisible]'); return (!$this->showOnClick || ($this->showOnClick && $isVisible && $isVisible->Value())); } /** * @param Validator $validator * * @return boolean */ public function validate($validator) { $name = $this->name; // if field isn't visible, don't validate if(!$this->isSaveable()) { return true; } $passwordField = $this->children->fieldByName($name.'[_Password]'); $passwordConfirmField = $this->children->fieldByName($name.'[_ConfirmPassword]'); $passwordField->setValue($this->value); $passwordConfirmField->setValue($this->confirmValue); $value = $passwordField->Value(); // both password-fields should be the same if($value != $passwordConfirmField->Value()) { $validator->validationError( $name, _t('Form.VALIDATIONPASSWORDSDONTMATCH',"Passwords don't match"), "validation", false ); return false; } if(!$this->canBeEmpty) { // both password-fields shouldn't be empty if(!$value || !$passwordConfirmField->Value()) { $validator->validationError( $name, _t('Form.VALIDATIONPASSWORDSNOTEMPTY', "Passwords can't be empty"), "validation", false ); return false; } } // lengths if(($this->minLength || $this->maxLength)) { if($this->minLength && $this->maxLength) { $limit = "{{$this->minLength},{$this->maxLength}}"; $errorMsg = _t( 'ConfirmedPasswordField.BETWEEN', 'Passwords must be {min} to {max} characters long.', array('min' => $this->minLength, 'max' => $this->maxLength) ); } elseif($this->minLength) { $limit = "{{$this->minLength}}.*"; $errorMsg = _t( 'ConfirmedPasswordField.ATLEAST', 'Passwords must be at least {min} characters long.', array('min' => $this->minLength) ); } elseif($this->maxLength) { $limit = "{0,{$this->maxLength}}"; $errorMsg = _t( 'ConfirmedPasswordField.MAXIMUM', 'Passwords must be at most {max} characters long.', array('max' => $this->maxLength) ); } $limitRegex = '/^.' . $limit . '$/'; if(!empty($value) && !preg_match($limitRegex,$value)) { $validator->validationError( $name, $errorMsg, "validation", false ); } } if($this->requireStrongPassword) { if(!preg_match('/^(([a-zA-Z]+\d+)|(\d+[a-zA-Z]+))[a-zA-Z0-9]*$/',$value)) { $validator->validationError( $name, _t('Form.VALIDATIONSTRONGPASSWORD', "Passwords must have at least one digit and one alphanumeric character"), "validation", false ); return false; } } return true; } /** * Only save if field was shown on the client, and is not empty. * * @param DataObjectInterface $record * * @return boolean */ public function saveInto(DataObjectInterface $record) { if(!$this->isSaveable()) { return false; } if(!($this->canBeEmpty && !$this->value)) { parent::saveInto($record); } } /** * Makes a read only field with some stars in it to replace the password * * @return ReadonlyField */ public function performReadonlyTransformation() { $field = $this->castedCopy('ReadonlyField') ->setTitle($this->title ? $this->title : _t('Member.PASSWORD')) ->setValue('*****'); return $field; } /** * @param $titles * @return $this */ public function setChildrenPlaceholders($titles) { if (is_array($titles) && count($titles) == 2) { foreach ($this->children as $field) { if (isset($titles[0])) { $field->setAttribute('placeholder', $titles[0]); array_shift($titles); } } } return $this; } } |