I have the multiCheckbox element on my form with the common callback validator.
Validator works ok, but error message contains duplicated strings, separated by semicolon instead of single message. If 2 checkboxes selected - the 2 error messages, if 4 - 4 error messages and so on.
Do you know how to modify the code in order to show only one single error message instead of duplicates?
$rolesElement = $form->getElement('role_ids');
$rolesElement->addValidator(new Zend_Validate_Callback(function ($value) use ($rolesElement, $administrator) {
if( *magicHere* ){
$rolesElement->clearErrorMessages();
$rolesElement->setErrorMessages(array('blablabla!'));
return false;
}
return true;
}));
You can always use setMessages() method of the Validator class you are using to set Custom Error Messages.
Here is my Code
$emailIdValidator->setMessages(array(
Zend_Validate_EmailAddress::DOT_ATOM => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::INVALID => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::INVALID_FORMAT => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::INVALID_HOSTNAME => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::INVALID_LOCAL_PART => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::INVALID_MX_RECORD => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::INVALID_SEGMENT => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::LENGTH_EXCEEDED => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
Zend_Validate_EmailAddress::QUOTED_STRING => $this->coreUtils->getApplicationMessages("EMAIL_ERROR"),
));
$form = new Zend_Form ();
$form->addElement ('MultiCheckbox', 'name', array (
'label' => 'test',
'multioptions' => array (
1 => 'fake',
65 => 'dsa',
165 => 'dsa22'
)
));
$form->name->addValidator ('Callback', true, array (
'callback' => array (
$this,
'val'
),
'messages' => array (
'callbackValue' => 'Error in here'
)
));
In this case, the validating function should not add any error messages. Just a boolean value.
function val ($value, $values)
{
return false;
}
The problem is solved by the creation of my own custom validator based on Zend_Validate.
Related
I am using agile toolkit code for developing an application , i do have dropdown that get values from database, I want to show selected value from field 1 to field 2 without submit any thing.
$form->addField('field1', ['caption' => 'Field 1', 'DropDown', 'values'=> $arra1,'isMultiple' => true ,'readonly' => false, ['dropdownOptions' => ['fullTextSearch' => true]]]);
$form->addField('field2', ['caption' => 'Select Specfic Values', 'DropDown','model' => new view_values($db),'dependency' => function (view_values $model, $data)
{isset($data['field1']) ? $model->addCondition($model->fieldName()->id, 'like', '%' . $data['field1'] . '%') : null;}
,'isMultiple' => true ,'readonly' => false, ['dropdownOptions' => ['fullTextSearch' => true]]]);
issue is Fatal Error atk4\ui\Exception: Unable to add form field (), object: atk4\ui\FormField\DropDown () property: "dependency" value: {}. Looking for Help. maybe my logic is wrong.
I have managed to find a solution for 2 field multi selection scenario:
$values = new view_table($db);
$values->addCondition($db->dsql()->orExpr()->where($db->dsql()->
andExpr()->where('field_status','<>','1')));
$Array = array();
reset($Array);
foreach($values as $row){
$Array[$row['id']] = $row['field_1'].": ".$row['field_2'];
}
$fieldvalue_1 = $form->addField('fieldvalue_1', ['caption' => 'fieldvalue_1', 'DropDown', 'values'=> $Array,'isMultiple' => true ,'readonly' => $readonly, ['dropdownOptions' => ['fullTextSearch' => true]]]);
$fieldvalue_2 = $form->addField('fieldvalue_2', ['caption' => 'fieldvalue_2', 'DropDown', 'values'=> $Array,'isMultiple' => true ,'readonly' => $readonly, ['dropdownOptions' => ['fullTextSearch' => true]]])->set($_GET['val'] ?? 'No value');
$fieldvalue_1->js('change' ,new \atk4\ui\JsReload($fieldvalue_2,['val' => $fieldvalue_1->jsInput()->val()]));
I have the following field
->add('specialProduct' , 'entity', array(
'class' => 'BSSmartDistributionBundle:Product',
'expanded' => true,
'multiple' => true,
'required' => true,
'label' => false,
'mapped' => false,
'query_builder' => function(ProductRepository $er) {
return $er->createQueryBuilder('p')
->where('p.active = :active')
->andWhere('p.type = :type')
->setParameter('type', 1)
->setParameter('active', 1);
},
'data' => $this->specialProduct # not working
))
I get the data and store it in session
$specialProduct = $form->get('specialProduct')->getData();
$request->getSession()->set('specialProduct', $specialProduct);
data :
Doctrine\Common\Collections\ArrayCollection Object
(
[elements:Doctrine\Common\Collections\ArrayCollection:private] => Array
(
[0] => BS\SmartDistributionBundle\Entity\Product Object
(
[id:BS\SmartDistributionBundle\Entity\Product:private] => 6
[type:BS\SmartDistributionBundle\Entity\Product:private] => 1
[name:BS\SmartDistributionBundle\Entity\Product:private] => Starter Pack
[duration:BS\SmartDistributionBundle\Entity\Product:private] => 1
[description:BS\SmartDistributionBundle\Entity\Product:private] => Tout de suite
[full_description:BS\SmartDistributionBundle\Entity\Product:private] => blabla
[price:BS\SmartDistributionBundle\Entity\Product:private] => 39
[picture:BS\SmartDistributionBundle\Entity\Product:private] => /tmp/php6h3rXK
[active:BS\SmartDistributionBundle\Entity\Product:private] => 1
)
[1] => BS\SmartDistributionBundle\Entity\Product Object
(
[id:BS\SmartDistributionBundle\Entity\Product:private] => 15
[type:BS\SmartDistributionBundle\Entity\Product:private] => 1
[name:BS\SmartDistributionBundle\Entity\Product:private] => asdsd
[duration:BS\SmartDistributionBundle\Entity\Product:private] => 2
[description:BS\SmartDistributionBundle\Entity\Product:private] => asdasd
[full_description:BS\SmartDistributionBundle\Entity\Product:private] => adsd
[price:BS\SmartDistributionBundle\Entity\Product:private] => 12
[picture:BS\SmartDistributionBundle\Entity\Product:private] => uploads/product/d978b90215d06fbf569203e7cf2d5aef.png
[active:BS\SmartDistributionBundle\Entity\Product:private] => 1
)
)
)
now I'd like to check the corresponding checkboxes !?
Same field with multiple false I can set the value with
'data' => $this->value
I tried
'data' => $this->specialProduct # not working (contains $specialProduct above)
How can I set those values ?
Do I need to pass an array ?
Thanks !
Setting default values for a form is always done on an instance of FormInterface using setData and not as data in options array for each form field. The docs says:
The default values for form fields are taken directly from the underlying data structure (e.g. an entity or an array). The data option overrides this default value.
If you used data option than the form will always have preselected what's in data and not from the entity.
So if I understand your code correctly it'd be:
$form->setData([
specialProduct => $request->getSession()->get('specialProduct')
]);
Because the stored data in session is a collection of Products.
I ended doing it this way :
I was storing and passing to the form an arrayCollection
controller :
$specialProduct = $form->get('specialProduct')->getData();
$request->getSession()->set('specialProduct', $specialProduct);
form :
$this->specialProduct = $options['specialProduct'];
'data' => $this->specialProduct
instead I use an array with only the ids
foreach ($specialProduct as $product) {
$specialProductIds[] = $product->getId();
}
$request->getSession()->set('specialProductIds', $specialProductIds);
pass it to the form with entity manager
$this->specialProductIds = $options['specialProductIds'];
$this->em = $options['em'];
in the form
public function availablespcialProduct($ids) {
if ($this->em) {
return $this->em
->getRepository('BS\SmartDistributionBundle\Entity\Product')
->findById(
$ids
);
}
}
and finally
'data' => $this->availablespcialProduct($this->specialProductIds)
Still waiting for a cleaner solution !
Thanks !
I successfully use the ZF2 Callback validator but I have a problem with the code that it returns. Here the config that use:
'validators'=>array(
array(
'name' => 'Callback',
'options' => array(
'messages'=>array(
Callback::INVALID_VALUE => 'Error',
),
'callback' => function ($value,$context=array()) {
if(empty($value) && empty($context['company'])){
$isValid = false;
}else{
$isValid = true;
}
return $isValid;
},
)
)
),
The problem is in the error code which returns no message
It returns callbackValue which is the value of the constant INVALID_VALUE of the Callback validation class
Is there a way to change this value through the options?
I would like to avoid writing a custom class for each item that I have to validate.
I tried but this code works totally fine:
use Zend\Validator\Callback;
.....
array(
'name' => 'Callback',
'options' => array(
'messages' => array(
Callback::INVALID_VALUE => 'My custom message',
Callback::INVALID_CALLBACK => 'My custom message'
),
'callback' => function(){
return false;
}
)
)
The key of the message is: callbackValue but the message I get is 'My custom message'
in your form class, within your callback function get the form field and set a custom error for it:
...
'callback' => function(){
...
// validation logic returns
// one of the possible messages into $message
$this->getInputFilter()
->get('<FieldName>')
->setErrorMessage($message);
return false;
}
I have a working webService using NuSOAP. Now, I have to make a validation before returning the data requested. If everything is ok, I return it normally, otherwise I would like to return a String message explaining why I'm not giving the information requested. Problem is that I can't get to add two different types of return to RegisterFunction of NuSOAP. If I add a ComplexType as return, I can't return a String.
The function can't have two return-values. You should add the error-message-string to your complex type. If you don't wanna touch your complex type, then you should create another
complex type wich contains your datatype and a string.
Example - the complex type you have right now:
$server->wsdl->addComplexType('myData','complexType','struct','all','',
array( 'important' => array('name' => 'important','type' => 'xsd:string'),
'stuff' => array('name' => 'stuff','type' => 'xsd:string')
)
);
the extra complex type:
$server->wsdl->addComplexType('package','complexType','struct','all','',
array( 'data' => array('name' => 'data','type' => 'tns:myData'),
'errormsg' => array('name' => 'errormsg','type' => 'xsd:string')
)
);
registration of the function:
$server->register(
'getData',
array('validation'=>'xsd:string'),
array('return'=>'tns:package'),
$namespace,
false,
'rpc',
'encoded',
'description'
);
the function:
function GetData($validation)
{
if($validation == "thegoodguy") {
$result['data'] = array(
"important" => "a top secret information",
"stuff" => "another one"
);
$result['errormsg'] = null;
} else {
$result['data'] = null;
$result['errormsg'] = "permission denied!";
}
return $result;
}
That way the client could try to analyse the received data and if it is null then he
shows up the errormessage.
You first need to define a new type that describes an array of strings like so:
$server->wsdl->addComplexType(
'ArrayOfString',
'complexType',
'array',
'sequence',
'',
array(
'itemName' => array(
'name' => 'itemName',
'type' => 'xsd:string',
'minOccurs' => '0',
'maxOccurs' => 'unbounded'
)
)
);
Then you can use tns:ArrayOfString as the return type.
Anyone able to offer some ideas on this? Basically the module I'm building has a form (as per function_email_solicitors_compose), and on submission we obviously route to form_emails_solicitors_compose_submit. Here I define a batch in $batch, and batch_set the aforementioned batch. The drupal documentation says I don't need to run batch_process() if it's called from within a form_submit, which this is, but I've tried with and without. All tests have shown that it gets as far as defining the batch but never goes any further than that. email_solicitors_batch_iteration never runs. Any ideas?
As an additional bit of info, batch_get then returns the following:
Array
(
[sets] => Array
(
[0] => Array
(
[sandbox] => Array
(
)
[results] => Array
(
)
[success] =>
[title] => Emailing.
[operations] => Array
(
[0] => Array
(
[0] =>
email_solicitors_batch_iteration
[1] => Array
(
[0] =>
[1] =>
)
)
)
[finished] => my_finished_callback
[init_message] => Initializing.<br/>
[progress_message] => Remaining
#remaining of #total.
[error_message] => An error has
occurred.
[total] => 1
)
)
)
The code:
function email_solicitors_compose(){
$form['email_solicitors_subject'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#description' => t('Enter the subject of your email'),
'#default_value' => 'Subject',
'#size' => 30
);
$form['email_solicitors_message'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#description' => t('Write your message here. <strong>Please note that we will automatically add "Dear #name", which will be personalised to the solicitor.</strong>'),
'#default_value' => '',
);
$form['email_solicitors_submit'] = array(
'#type' => 'submit',
'#title' => t('Submit'),
'#description' => t('Sumbit this form.'),
'#default_value' => 'Submit',
);
return $form;
}//function email_solicitors_compose
function email_solicitors_compose_submit($form_state)
{
$batch = array(
'title' => t('Sending emails to solicitors'),
'operations' => array(
array('email_solicitors_batch_iteration', array())
),
'finished' => 'email_solicitors_batch_finished', //run this when we're finished
'init_message' => t('Preparing to send emails'), //initialisation message
'progress_message' => t('Sent #current out of #total messages.'),
'error_message' => t('Sorry, something went wrong when sending emails.'),
);// create batch array
$info=print_r($batch,TRUE);
drupal_set_message($info);
batch_set($batch);
batch_process();
}//function email_solicitors_compose_submit
function email_solicitors_batch_iteration(&$context)
{
// Initialize sandbox the first time through.
if (!isset($context['sandbox']['progress'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['current_user_id'] = 0;
$context['sandbox']['max'] = db_result(db_query('SELECT COUNT(DISTINCT field_solicitor_email_value) FROM content_type_solicitor'));
}
$comment="On item ".$context['sandbox']['progress'];
drupal_set_message ($comment);
}//function email_solicitors_batch_iteration
function email_solicitors_batch_finished (&$context)
{
die ('woohoo we finished');
}
As an addition to the answer Clive has given, you could consider adding the "file" parameter to the batch-array. This will tell the API where the function is located.
Example:
$batch = array(
'title' => t('Sending emails to solicitors'),
'operations' => array(
array('email_solicitors_batch_iteration', array())
),
'finished' => 'email_solicitors_batch_finished', //run this when we're finished
'init_message' => t('Preparing to send emails'), //initialisation message
'progress_message' => t('Sent #current out of #total messages.'),
'error_message' => t('Sorry, something went wrong when sending emails.'),
'file' => drupal_get_path('module', '<module_name>').'/path_to_include_file.inc',
);
It worked for me :)
Just in case anyone is still struggling with this the previous two comments are incorrect, you do not need to explicitly set the $context['finished'] variable (see the examples module, batch_example).
The reason it's not working is simply because the batch operation function is in a file not included in the default Drupal bootstrap. If you move the batch operation function out of an include file and into the module file of an enabled module it will work.
Are you having a start of sign that the batch is beginning or just nothing happens?
You are missing two information in your batch operation callback: the increase of the progress and most importantly a statement to determine when the batch should over.
// Update our progress information.
$context['sandbox']['progress']++;
$context['sandbox']['current_node'] = $row['nid'];
$context['message'] = t('Calcul des votes pour %node', array('%node' => $row['title']));
if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
}
You do not need to call batch_process(), just batch_set() in a submit callback is everything you need. See for example http://api.worldempire.ch/api/privatemsg/privatemsg_filter--privatemsg_filter.admin.inc/function/privatemsg_filter_inbox_rebuid_form_submit/7-1.
And as Artusamak said, your batch implementation is incomplete and would result in a endless loop.