Drupal 8 optional in drupal_process_states doesn't work - forms

I've defined few conditional fields with drupal_process_states that should only be displayed and validated if radio button has value 'post'. It works for 'invisible' and 'disabled' properties, but it does not work for 'optional' property. It allows to submit a form, but it fails on backend validation saying that those fields are required. Here is my code in form alter hook:
$states_when_delivery_is_post = array(
'disabled' => array(
':input[name="field_delivery_way"]' => array('value' => 'email'),
),
'optional' => array(
':input[name="field_delivery_way"]' => array('value' => 'email'),
),
'invisible' => array(
':input[name="field_delivery_way"]' => array('value' => 'email'),
),
);
if (isset($form['field_country'])) {
$form['field_country']['#states'] = $states_when_delivery_is_post;
}
Any ideas?

Apparently, states only provide front-end functionality, so you should implement backend rules by yourself. For example I don't need address fields to be required if delivery way is email, so I'm clearing those address fields errors:
function module_name_form_name_validation(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
if ($form_state->getValue('field_delivery_way')[0]['value'] == 'email') {
$errors = $form_state->getErrors();
$conditional_fields = ['field_city][0][value', 'field_house_number][0][value', 'field_postcode][0][value', 'field_street][0][value', 'field_country'];
$form_state->clearErrors();
foreach ($errors as $element => $error) {
if (!in_array($element, $conditional_fields)) {
$form_state->setErrorByName($element, $error);
}
}
}
}

Related

ReCaptcha with ZF3 wrong value

I use the newest Zend Framework available, and now i want to use ReCaptcha on my form. Together with some other elements, the ReCaptcha element is defined by:
$pubKey = 'replaced by the actual pubkey';
$privKey = 'replaced by the actual privkey';
$recaptcha = new \Zend\Captcha\ReCaptcha(['pubKey' => $pubKey, 'privKey' => $privKey]);
$this->add(array(
'attributes' => array (
'data-role' => 'none',
),
'name' => 'captcha',
'type' => 'captcha',
'options' => array(
'captcha' => $recaptcha,
),
));
This code validates the form in the controller:
public function contactAction () {
$contactForm = new ContactForm();
if($this->getRequest()->isPost()) {
$contactForm->setData($this->getRequest()->getPost());
if($contactForm->isValid()){
// send actual mail
return $this->redirect()->toRoute('page', ['lang' => $this->translator->getLocale(), 'page' => 'contact']);
}
}
$viewModel = new ViewModel ([
'contactForm' => $contactForm
]);
$viewModel->setTemplate('application/index/contact');
return $viewModel;
}
And finally, this is the view:
<?= $this->form($contactForm); ?>
To me, this code is pretty straightforward and should work. However, on sending the contact form, it displays the error 'Captcha value is wrong'. Any ideas?
You have to name the element according to the rules of Google. With this code, it works like a breeze
$pubKey = 'replaced by the actual pubkey';
$privKey = 'replaced by the actual privkey';
$recaptcha = new \Zend\Captcha\ReCaptcha(['pubKey' => $pubKey, 'privKey' => $privKey]);
$this->add(array(
'name' => 'g-recaptcha-response',
'type' => 'captcha',
'options' => [
'captcha' => $recaptcha,
]
));
Anyways, as always the ZF Docs are very short and lack examples.

how to set value from database in Zend Framework 1 in add form element

I have a form in Zend Framework 1. when I click on edit button I want to display values from databases in the form. but I don't know how to do it.
This is my form code:
// Add an email element
$this->addElement('text', 'orgname', array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators'=>Array(
'ViewHelper','Errors'
)
));
This is my controller:
public function editclientcompanyAction()
$form = new Application_Form_Companyform();
$form->addform();
$this->view->form = $form;
$request = $this->getRequest();
$editid=$request->getParam('id');
$edit_show = new Application_Model_Clientcompany;
$showdetails = $edit_show->editclient($editid);
$this->view->assign('datas', $showdetails);
How do I display database vlaues in my Zend Form?
There are two cases.
1) Populating form which has fields same like the database table fields : If you have the form which has same fields like the database fields, then you can populate them easily.
First you need to get the data from the database and then call the Zend_Form populate function passing the data as an associative array, where keys will be same like form fields names and values will be values for the form fields, as below in case of your form.
This will be in your controller
$data = array("orgname" => "Value for the field");
$form = new Application_Form_Companyform();
$form->populate($data);
Now send will automatically populate the form field orgname. You dont need to modify your form or set the value field in the addElement.
*2)Setting field value manually: * The second case is to set the value manually. First you will need to modify your form and add a constructor to it. Also in your form class you will need to create a property (if you have multiple fields, then you can create an array property or multiple properties for each field. This will be all up to you.). And then set the value key in the addElement. Your form should look like this
class Application_Form_Companyform extends Zend_Form
{
private $orgname;
public function __contruct($orgname)
{
$this->orgname = $orgname;
//It is required to call the parent contructor, else the form will not work
parent::__contruct();
}
public function init()
{
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators'=>Array('ViewHelper','Errors'),
'value'=>$this->orgname
)
));
} //end of init
} //end of form
Now your controller, you will need to instantiate the form object passing the value of the orgname field like below
$form = new Application_Form_Companyform("This is the value for orgname");
And thats it.
I used such methods and it works like a charm. For your requirements, you may need to adjust the above sample code, as i did not checked it, but it will run fine for sure i hope :P
Thank you
Ok in either ZF1 or ZF2 just do this.
// Add an email element
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators' => Array('ViewHelper','Errors'),
'value' => $showdetails->orgname
)
));
You might want to test first for null/empty values first though, you could use ternary operators for convenience:
// Add an email element
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators' => Array('ViewHelper','Errors'),
'value' => empty($showdetails->orgname)? null : $showdetails->orgname
)
));
Please have a look in my edit function at /var/www/html/zend1app/application/controllers/CountryController.php :
public function editAction() {
$data = $this->getRequest()->getParams();
$id = (int)$data['id'];
$options = array();
$country = $this->getCountryModel()->fetchRow("id=$id");
if(!$country)
{
throw new Exception("Invalid Request Id!");
}
$form = new Application_Form_Country();
$form->addIdElement();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())){
$data = new Application_Model_Country();
if($data->save($form->getValues()))
{
$message = array("sucess" => "Country has been updated!");
}
else {
$message = array("danger" => "Country could not be updated!");
}
$this->_helper->FlashMessenger->addMessage($message);
return $this->_helper->redirector('index');
}
}
$options = array (
'id' => $country->id,
'name' => $country->name,
'code' => $country->code
);
$form->populate( $options ); // data binding in the edit form
$this->view->form = $form;
}
and form class at /var/www/html/zend1app/application/forms/Country.php :
class Application_Form_Country extends Zend_Form
{
public function init()
{
// Set the method for the display form to POST
$this->setMethod('post');
// Add an email element
$this->addElement('text', 'name', array(
'label' => 'Enter Country Name:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add the comment element
$this->addElement('text', 'code', array(
'label' => 'Enter Country Code:',
'required' => true,
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add the submit button
$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Save',
));
// And finally add some CSRF protection
$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
public function addIdElement()
{
$this->addElement('hidden', 'id');
}
}
HTH

Cake PHP custom validation rule

I got a problem with a custom validation rule in Cake 2.X
I want to check if the entered zipcode is valid and therefore a function in the class zipcode is called from the class post.
But the validation returns false all the time.
Appmodel in class post (rule-3 is it):
'DELIVERYAREA' => array(
'rule-1' => array(
'rule' => array('between', 5, 5),
'message' => 'Bitte eine fünfstellige Postleitzahl eingeben'
),
'rule-2' => array(
'rule' => 'Numeric',
'message' => 'Bitte nur Zahlen eingeben'
),
'rule-3' => array(
'exists' => array(
'rule' => 'ZipExists',
'message' => 'Postleitzahl existiert nicht!'
)
)
),
Appmodel in class zipcode:
class Zipcode extends AppModel {
var $name = 'Zipcode';
var $validate = array(
'zipcode' => array(
'length' => array(
'rule' => array('maxLength', 5),
'message' => 'Bitte einen Text eingeben'
),
'exists' => array(
'rule' => array('ZipExists'),
'message' => 'Postleitzahl existiert nicht!'
)
)
);
function ZipExists($zipcode){
$valid = $this->find('count', array('conditions'=> array('Zipcode.zipcode' =>$zipcode)));
if ($valid >= 1){
return true;
}
else{
return false;
}
}
I hope it´s something stupidly easy?
Thanks in advance
I think this:
'Zipcode.zipcode' =>$zipcode
...needs to be this:
'Zipcode.zipcode' =>$zipcode['zipcode']
Careful what you expect inside the validation rule. Use debug() etc to find out what exactly is coming in. $data is always an array here.
public function zipExists($data) {
$zipcode = array_shift($data); // use the value of the key/value pair
$code = $this->find('first', array('conditions'=> array('Zipcode.zipcode' =>$zipcode)));
return !empty($code);
}
try this for only model validation.
function ZipExists(){
$valid = $this->find('count', array('conditions'=> array('Zipcode.zipcode' =>$this->data['Zipcode']['zipcode'])));
if ($valid >= 1){
return true;
}
else{
return false;
}
I found the solution.
Cake wants the custom validation rules to be in the certain class where the rule is called. So, when you call a custom rule in class post, the custom function has to be written down in class post, otherwise cake won´t find it and validate it to false everytime.
The magic to do here is to import the appmodel-class you want to use in the class you call the validation-function. That works with the following statement:
$Zipcode = ClassRegistry::init('Class to use - in my case "Zipcode"');
But if your tables are associated with each other with hasAny or belongsTo and stuff, the custom function works without that. Another important point you mustn´t miss is, that all validation functions has to be introduced with "public function xyz" otherwise cake won´t find them too.

CakePHP not showing my form errors

I'm trying to create a login form for my web application.
Form validation errros are not showing even though I'm using the $validate Array.
user.php
public $validate = array(
'email' => array(
'notEmpty' => array(
'rule' => 'notEmpty',
'message' => 'notEmpty',
'required' => true
),
'isEmail' => array(
'rule' => 'email'
),
'isUnique' => array(
'rule' => 'isUnique'
)
),
'password' => array(
'notEmpty' => array(
'rule' => 'notEmpty'
),
'minLength' => array(
'rule' => array('minLength', 8)
)
)
);
I can't see an error in my user model, so I show you my controller and my view.
users_controller.php
class UsersController extends AppController {
public $name = 'Users';
public $helpers = array(
'Form'
);
public function login() {
if(!empty($this->data)) {
if ($this->Auth->user() != null) {
$this->Session->setFlash('You are now logged in.', 'flash/success');
$this->redirect('/');
} else {
$this->Session->setFlash('You could not get logged in. Please see errors below.', 'flash/error');
}
}
}
login.ctp
echo $this->Form->create('User', array('action' => 'login'));
echo $this->Form->input('User.email', array(
'label' => __('email address:', true),
'error' => array(
'notEmpty' => __('Email address must not be blank.', true),
'isEmail' => __('Email address must be valid.', true),
)
));
echo $this->Form->input('User.password', array('label' => __('password:', true)));
echo $this->Form->end('Log in');
I hope you can help me. I can't find my mistake since hours. Is there maybe a component or an helper which I need to include?
put echo $this->Session->flash('auth'); before form->create. You don't have to validate login form, Auth will take care of that for you. Read the cookbook: http://book.cakephp.org/view/1250/Authentication
Since you are using Auth, the minLength validation for password is useless.
Validation doesn't occur automatically unless you're saving into the database. Change the first line of the login method in the controller to
if( !empty( $this->data ) && $this->User->validates() ) {
...

How to verify password field in zend form?

In my form, I'm trying to verify that the user fills in the same value both times (to make sure they didn't make a mistake). I think that's what Zend_Validate_Identical is for, but I'm not quite sure how to use it. Here's what I've got so far:
$this->addElement('password', 'password', array(
'label' => 'Password:',
'required' => true,
'validators' => array(
'Identical' => array(What do I put here?)
)
));
$this->addElement('password', 'verifypassword', array(
'label' => 'Verify Password:',
'required' => true,
'validators' => array(
'Identical' => array(What do I put here?)
)
));
Do I need it on both elements? What do I put in the array?
For what its worth, support for comparing two identical form fields within a model was added to the 1.10.5 release. I wrote up a short tutorial on the matter, which you can access via the below link, but the bottom line is that the Zend_Validate_Identical validator has been refactored to accept a form field name as input. For instance, to compare the values of form fields pswd and confirm_pswd, you'll attach the validator to confirm_pswd like so:
$confirmPswd->addValidator('Identical', false, array('token' => 'pswd'));
Works like a charm.
See Validating Identical Passwords with the Zend Framework for a more complete example.
I can't test it at the moment, but I think this might work:
$this->addElement('password', 'password', array(
'label' => 'Password:',
'required' => true
));
$this->addElement('password', 'verifypassword', array(
'label' => 'Verify Password:',
'required' => true,
'validators' => array(
array('identical', true, array('password'))
)
));
After two days I found the right answer follow me step by step:
step 1:
create PasswordConfirmation.php file in root directory of your project with this path:
yourproject/My/Validate/PasswordConfirmation.php with this content below:
<?php
require_once 'Zend/Validate/Abstract.php';
class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract
{
const NOT_MATCH = 'notMatch';
protected $_messageTemplates = array(
self::NOT_MATCH => 'Password confirmation does not match'
);
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
if (is_array($context)) {
if (isset($context['user_password'])
&& ($value == $context['user_password']))
{
return true;
}
}
elseif (is_string($context) && ($value == $context)) {
return true;
}
$this->_error(self::NOT_MATCH);
return false;
}
}
?>
step 2:
Add two field in your form like this:
//create the form elements user_password
$userPassword = $this->createElement('password', 'user_password');
$userPassword->setLabel('Password: ');
$userPassword->setRequired('true');
$this->addElement($userPassword);
//create the form elements user_password repeat
$userPasswordRepeat = $this->createElement('password', 'user_password_confirm');
$userPasswordRepeat->setLabel('Password repeat: ');
$userPasswordRepeat->setRequired('true');
$userPasswordRepeat->addPrefixPath('My_Validate', 'My/Validate', 'validate');
$userPasswordRepeat->addValidator('PasswordConfirmation', true, array('user_password'));
$this->addElement($userPasswordRepeat);
now enjoy your code
class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract
{
const NOT_MATCH = 'notMatch';
protected $_messageTemplates = array(
self::NOT_MATCH => 'Password confirmation does not match'
);
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
if (is_array($context)) {
if (isset($context['password_confirm'])
&& ($value == $context['password_confirm']))
{
return true;
}
} elseif (is_string($context) && ($value == $context)) {
return true;
}
$this->_error(self::NOT_MATCH);
return false;
}
}
http://framework.zend.com/manual/en/zend.form.elements.html
$token = Zend_Controller_Front::getInstance()->getRequest()->getPost('password');
$confirmPassword->addValidator(new Zend_Validate_Identical(trim($token)))
->addFilter(new Zend_Filter_StringTrim())
->isRequired();
Use the above code inside the class which extends zend_form.
I was able to get it to work with the following code:
In my form I add the Identical validator on the second element only:
$this->addElement('text', 'email', array(
'label' => 'Email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress')
));
$this->addElement('text', 'verify_email', array(
'label' => 'Verify Email:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress', 'Identical')
));
And in the controller, just before calling isValid():
$validator = $form->getElement('verify_email')->getValidator('identical');
$validator->setToken($this->_request->getPost('email'));
I don't know if there is a more elegant way of doing this without having to add this code to the controller. Let me know if there is a better way to do this.
With Zend Framework 1.10 the code needed to validate the equality of two fields using Zend Form and Zend Validate is:
$form->addElement('PasswordTextBox',
'password',
array('label' => 'Password')
);
$form->addElement('PasswordTextBox',
'password_confirm',
array('label' => 'Confirm password',
'validators' => array(array('Identical', false, 'password')),
)
);
You can notice, in the validators array of the password_confirm element, that the Identical validator is passed as array, the semantics of that array is: i) Validator name, ii) break chain on failure, iii) validator options
As you can see, it's possible to pass the field name instead of retrieving the value.