Webylon 3.1 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • auth
  • Booking
  • cart
    • shipping
    • steppedcheckout
  • Catalog
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • AjaxUniqueTextField
  • AutocompleteTextField
  • ConfirmedPasswordField
  • CreditCardField
  • CurrencyField
  • CurrencyField_Disabled
  • CurrencyField_Readonly
  • EmailField
  • HtmlEditorConfig
  • HtmlEditorField
  • HtmlEditorField_Readonly
  • HtmlEditorField_Toolbar
  • NumericField
  • PasswordField
  • PhoneNumberField
  • UniqueRestrictedTextField
  • UniqueTextField
  1 <?php
  2 /**
  3  * Shows two password-fields, and checks for matching passwords.
  4  * Optionally hides the fields by default and shows
  5  * a link to toggle their visibility.
  6  * 
  7  * @package forms
  8  * @subpackage fields-formattedinput
  9  */
 10 class ConfirmedPasswordField extends FormField {
 11     
 12     /**
 13      * Minimum character length of the password.
 14      *
 15      * @var int
 16      */
 17     public $minLength = null;
 18     
 19     /**
 20      * Maximum character length of the password.
 21      *
 22      * @var int
 23      */
 24     public $maxLength = null;
 25     
 26     /**
 27      * Enforces at least one digit and one alphanumeric
 28      * character (in addition to {$minLength} and {$maxLength}
 29      *
 30      * @var boolean
 31      */
 32     public $requireStrongPassword = false;
 33     
 34     /**
 35      * Allow empty fields in serverside validation
 36      *
 37      * @var boolean
 38      */
 39     public $canBeEmpty = false;
 40     
 41     /**
 42      * If set to TRUE, the "password" and "confirm password"
 43      * formfields will be hidden via CSS and JavaScript by default,
 44      * and triggered by a link. An additional hidden field
 45      * determines if showing the fields has been triggered,
 46      * and just validates/saves the input in this case.
 47      * This behaviour works unobtrusively, without JavaScript enabled
 48      * the fields show, validate and save by default.
 49      * 
 50      * @param boolean $showOnClick
 51      */
 52     protected $showOnClick = false;
 53     
 54     /**
 55      * Title for the link that triggers
 56      * the visibility of password fields.
 57      *
 58      * @var string
 59      */
 60     public $showOnClickTitle;
 61     
 62     /**
 63      * @param string $name
 64      * @param string $title
 65      * @param mixed $value
 66      * @param Form $form
 67      * @param boolean $showOnClick
 68      * @param string $titleConfirmField Alternate title (not localizeable)
 69      */
 70     function __construct($name, $title = null, $value = "", $form = null, $showOnClick = false, $titleConfirmField = null) {
 71         // naming with underscores to prevent values from actually being saved somewhere
 72         $this->children = new FieldSet(
 73             new PasswordField(
 74                 "{$name}[_Password]", 
 75                 (isset($title)) ? $title : _t('Member.PASSWORD')),
 76             new PasswordField(
 77                 "{$name}[_ConfirmPassword]",
 78                 (isset($titleConfirmField)) ? $titleConfirmField : _t('Member.CONFIRMPASSWORD', 'Confirm Password')
 79             )
 80         );
 81         
 82         // has to be called in constructor because Field() isn't triggered upon saving the instance
 83         if($showOnClick) {
 84             $this->children->push(new HiddenField("{$name}[_PasswordFieldVisible]"));
 85         }
 86         $this->showOnClick = $showOnClick;
 87         
 88         // we have labels for the subfields
 89         $title = false;
 90         
 91         parent::__construct($name, $title, null, $form);
 92         $this->setValue($value);
 93     }
 94     
 95     function Field() {
 96         Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/prototype/prototype.js');
 97         Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/behaviour/behaviour.js');
 98         Requirements::javascript(SAPPHIRE_DIR . '/javascript/prototype_improvements.js');
 99         Requirements::javascript(SAPPHIRE_DIR . '/javascript/ConfirmedPasswordField.js');
100         
101         $content = '';
102         
103         if($this->showOnClick) {
104             if($this->showOnClickTitle) {
105                 $title = $this->showOnClickTitle;
106             } else {
107                 $title = _t(
108                     'ConfirmedPasswordField.SHOWONCLICKTITLE', 
109                     'Change Password', 
110                     PR_MEDIUM, 
111                     'Label of the link which triggers display of the "change password" formfields'
112                 );
113             }
114             
115             $content .= "<div class=\"showOnClick\">\n";
116             $content .= "<a href=\"#\"" . $this->getTabIndexHTML() . ">{$title}</a>\n";
117             $content .= "<div class=\"showOnClickContainer\">";
118         }
119 
120         foreach($this->children as $field) {
121             $field->setDisabled($this->isDisabled()); 
122             $field->setReadonly($this->isReadonly());
123             $content .= $field->FieldHolder();
124         }
125 
126         if($this->showOnClick) {
127             $content .= "</div>\n";
128             $content .= "</div>\n";
129         }
130         
131         return $content;
132     }
133     
134     /**
135      * Can be empty is a flag that turns on/off empty field checking.
136      * For example, set this to false (the default) when creating a user account,
137      * and true 
138      */
139     function setCanBeEmpty($value) {
140         $this->canBeEmpty = (bool)$value;
141     }
142     
143     /**
144      * The title on the link which triggers display of the
145      * "password" and "confirm password" formfields.
146      * Only used if {@link setShowOnClick()} is set to TRUE.
147      * 
148      * @param $title
149      */
150     public function setShowOnClickTitle($title) {
151         $this->showOnClickTitle = $title;
152     }
153     
154     /**
155      * @return string
156      */
157     public function getShowOnClickTitle() {
158         return $this->showOnClickTitle;
159     }
160     
161     function setRightTitle($title) {
162         foreach($this->children as $field) {
163             $field->setRightTitle($title);
164         }
165     }
166     
167     /**
168      * @param array: 2 entrie array with the customised title for each of the 2 children.
169      */
170     function setChildrenTitles($titles) {
171         if(is_array($titles)&&count($titles)==2){
172             foreach($this->children as $field) {
173                 if(isset($titles[0])){
174                     $field->setTitle($titles[0]);
175                     array_shift($titles);       
176                 }
177             }
178         }
179     }
180     
181     /**
182      * Value is sometimes an array, and sometimes a single value, so we need to handle both cases
183      */
184     function setValue($value) {
185         if(is_array($value)) {
186             if($value['_Password'] || (!$value['_Password'] && !$this->canBeEmpty)) {
187                 $this->value = $value['_Password'];
188             }
189             if(isset($value['_PasswordFieldVisible'])){
190                 $this->children->fieldByName($this->Name() . '[_PasswordFieldVisible]')->setValue($value['_PasswordFieldVisible']);
191             }
192         } else {
193             if($value || (!$value && !$this->canBeEmpty)) {
194                 $this->value = $value;
195             }
196         }
197         $this->children->fieldByName($this->Name() . '[_Password]')->setValue($this->value);
198         $this->children->fieldByName($this->Name() . '[_ConfirmPassword]')->setValue($this->value);
199     }
200     
201     function jsValidation() {
202         $formID = $this->form->FormName();
203         $jsTests = '';
204         
205         $jsTests .= "
206             // if fields are hidden, reset values and don't validate
207             var containers = $$('.showOnClickContainer', $('#'+fieldName));
208             if(containers.length && !Element.visible(containers[0])) {
209                 passEl.value = null;
210                 confEl.value = null;
211                 return true;
212             }
213         ";
214 
215         $error1 = _t('ConfirmedPasswordField.HAVETOMATCH', 'Passwords have to match.');
216         $jsTests .= "
217             if(passEl.value != confEl.value) {
218                 validationError(confEl, \"$error1\", \"error\");
219                 return false;
220             }
221         ";
222         
223         $error2 = _t('ConfirmedPasswordField.NOEMPTY', 'Passwords can\'t be empty.');
224         if(!$this->canBeEmpty) {
225             $jsTests .= "
226                 if(!passEl.value || !confEl.value) {
227                     validationError(confEl, \"$error2\", \"error\");
228                     return false;
229                 }
230             ";
231         }
232         
233         if(($this->minLength || $this->maxLength)) {
234             if($this->minLength && $this->maxLength) {
235                 $limit = "{{$this->minLength},{$this->maxLength}}";
236                 $errorMsg = sprintf(_t('ConfirmedPasswordField.BETWEEN', 'Passwords must be %s to %s characters long.'), $this->minLength, $this->maxLength);
237             } elseif($this->minLength) {
238                 $limit = "{{$this->minLength}}.*";
239                 $errorMsg = sprintf(_t('ConfirmedPasswordField.ATLEAST', 'Passwords must be at least %s characters long.'), $this->minLength);
240             } elseif($this->maxLength) {
241                 $limit = "{0,{$this->maxLength}}";
242                 $errorMsg = sprintf(_t('ConfirmedPasswordField.MAXIMUM', 'Passwords must be at most %s characters long.'), $this->maxLength);
243             }
244             $limitRegex = '/^.' . $limit . '$/';
245             $jsTests .= "
246             if(passEl.value && !passEl.value.match({$limitRegex})) {
247                 validationError(confEl, \"{$errorMsg}\", \"error\");
248                 return false;
249             }
250             ";
251         }
252         
253         $error3 = _t('ConfirmedPasswordField.LEASTONE', 'Passwords must have at least one digit and one alphanumeric character.');
254         if($this->requireStrongPassword) {
255             $jsTests .= "
256                 if(!passEl.value.match(/^(([a-zA-Z]+\d+)|(\d+[a-zA-Z]+))[a-zA-Z0-9]*$/)) {
257                     validationError(
258                         confEl, 
259                         \"$error3\", 
260                         \"error\"
261                     );
262                     return false;
263                 }
264             ";
265         }
266         
267         $jsFunc =<<<JS
268 Behaviour.register({
269     "#$formID": {
270         validateConfirmedPassword: function(fieldName) {
271             var passEl = _CURRENT_FORM.elements['Password[_Password]'];
272             var confEl = _CURRENT_FORM.elements['Password[_ConfirmPassword]'];
273             $jsTests
274             return true;
275         }
276     }
277 });
278 JS;
279         Requirements :: customScript($jsFunc, 'func_validateConfirmedPassword_' . $formID);
280         
281         //return "\$('$formID').validateConfirmedPassword('$this->name');";
282         return <<<JS
283 if(typeof fromAnOnBlur != 'undefined'){
284     if(fromAnOnBlur.name == '$this->name')
285         $('$formID').validateConfirmedPassword('$this->name');
286 }else{
287     $('$formID').validateConfirmedPassword('$this->name');
288 }
289 JS;
290     }
291 
292     /**
293      * Determines if the field was actually
294      * shown on the clientside - if not,
295      * we don't validate or save it.
296      * 
297      * @return bool
298      */
299     function isSaveable() {
300         $isVisible = $this->children->fieldByName($this->Name() . '[_PasswordFieldVisible]');
301         return (!$this->showOnClick || ($this->showOnClick && $isVisible && $isVisible->Value()));
302     }
303     
304     function validate() {
305         $validator = $this->form->getValidator();
306         $name = $this->name;
307         
308         // if field isn't visible, don't validate
309         if(!$this->isSaveable()) return true; 
310         
311         $passwordField = $this->children->fieldByName($name.'[_Password]');
312         $passwordConfirmField = $this->children->fieldByName($name.'[_ConfirmPassword]');
313         $passwordField->setValue($_POST[$name]['_Password']);
314         $passwordConfirmField->setValue($_POST[$name]['_ConfirmPassword']);
315         
316         $value = $passwordField->Value();
317         
318         // both password-fields should be the same
319         if($value != $passwordConfirmField->Value()) {
320             $validator->validationError($name, _t('Form.VALIDATIONPASSWORDSDONTMATCH',"Passwords don't match"), "validation", false);
321             return false;
322         }
323 
324         if(!$this->canBeEmpty) {
325             // both password-fields shouldn't be empty
326             if(!$value || !$passwordConfirmField->Value()) {
327                 $validator->validationError($name, _t('Form.VALIDATIONPASSWORDSNOTEMPTY', "Passwords can't be empty"), "validation", false);
328                 return false;
329             }
330         }
331             
332         // lengths
333         if(($this->minLength || $this->maxLength)) {
334             if($this->minLength && $this->maxLength) {
335                 $limit = "{{$this->minLength},{$this->maxLength}}";
336                 $errorMsg = sprintf(_t('ConfirmedPasswordField.BETWEEN', 'Passwords must be %s to %s characters long.'), $this->minLength, $this->maxLength);
337             } elseif($this->minLength) {
338                 $limit = "{{$this->minLength}}.*";
339                 $errorMsg = sprintf(_t('ConfirmedPasswordField.ATLEAST', 'Passwords must be at least %s characters long.'), $this->minLength);
340             } elseif($this->maxLength) {
341                 $limit = "{0,{$this->maxLength}}";
342                 $errorMsg = sprintf(_t('ConfirmedPasswordField.MAXIMUM', 'Passwords must be at most %s characters long.'), $this->maxLength);
343             }
344             $limitRegex = '/^.' . $limit . '$/';
345             if(!empty($value) && !preg_match($limitRegex,$value)) {
346                 $validator->validationError('Password', $errorMsg, 
347                     "validation", 
348                     false
349                 );
350             }
351         }
352         
353         if($this->requireStrongPassword) {
354             if(!preg_match('/^(([a-zA-Z]+\d+)|(\d+[a-zA-Z]+))[a-zA-Z0-9]*$/',$value)) {
355                 $validator->validationError(
356                     'Password', 
357                     _t('Form.VALIDATIONSTRONGPASSWORD', "Passwords must have at least one digit and one alphanumeric character."), 
358                     "validation", 
359                     false
360                 );
361                 return false;
362             }
363         }
364         return true;
365     }
366     
367     /**
368      * Only save if field was shown on the client,
369      * and is not empty.
370      *
371      * @param DataObject $record
372      * @return bool
373      */
374     function saveInto(DataObject $record) {
375         if(!$this->isSaveable()) return false;
376         
377         if(!($this->canBeEmpty && !$this->value)) {
378             parent::saveInto($record);
379         }
380     }
381     
382     /**
383      * Makes a pretty readonly field with some stars in it
384      */
385     function performReadonlyTransformation() {
386         $stars = '*****';
387 
388         $field = new ReadonlyField($this->name, $this->title ? $this->title : _t('Member.PASSWORD'), $stars);
389         $field->setForm($this->form);
390         return $field;
391     }
392 }
393 
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.1 API Docs API documentation generated by ApiGen 2.8.0