Setting an Error Message located in language file - codeigniter

In a form I have a callback function that checks if a number is_available.
If it returns TRUE it shows an error message.
The callback is working but it displays : lang:shortcodes.not_unique instead of the content given in a separate file.
I can't figure out what is wrong and didn't find about that in the user guide.
Thank you for your help.
public function __construct()
{
parent::__construct();
// Load all the required classes
$this->load->model('shortcodes_m');
$this->load->library('form_validation');
$this->lang->load('shortcodes');
// Set the validation rules
$this->item_validation_rules = array(
array(
'field' => 'number',
'label' => 'lang:shortcodes.number',
'rules' => 'trim|max_length[100]|required|numeric'
),
array(
'field' => 'name',
'label' => 'lang:shortcodes.name',
'rules' => 'trim|max_length[100]|required|callback_shortcodes_check'
)
);
}
public function shortcodes_check($str)
{
if($this->shortcodes_m->is_available($str) == TRUE)
{
$this->form_validation->set_message('shortcodes_check','lang:shortcodes.not_unique');
return FALSE;
}
else
{
return TRUE;
}
}

You need to fetch the line from the language file. The docs don't make any mention of being able to use field name translation with the set_message() method. Use:
$this->lang->line('not_unique');

Related

Validating third variable on difference between 2 other variables in cakephp

I can't get my head around this one. I want to validate whether a third variable on a cakephp form is less than or equal to the difference between two other variables on the form. Has anyone tackled this or similar?
Paul
here is some code to show what I have done:
public function lessThanEqualTo($check, $otherfield) {
$value = array_values($check);
$compareTo = $this->data[$this->name][$otherfield];
if (!Validation::comparison($value[0], 'lessorequal', $compareTo)) {
return false;
}
else {
return true;
}
}
public function numDifference($startnumber, $usednumber) {
$sn = int($this->data[$this->name][$startnumber]);
$un = int($this->data[$this->name][$usednumber]);
return ($sn - $un);
}
Model contains validation: but the second rule is plain wrong, I have tried a number of things, but I am just coming up with rubbish:
public $validate = array(
'ag1_compl_dist_num'=>array(
'rule' => array('lessThanEqualTo','ag1_compl_start_number'),
'message' => 'Value must be less than starting number',
'allowEmpty' => true,
'required' => false
),
'ag1_compl_remain' => array(
'rule' => array('lessThanEqualTo','numDifference'),
'message' => 'Value must be less than difference between numbers',
'allowEmpty' => true,
'required' => false
)
);
Clearly, the call to numDifference should have something that identifies which two numbers to work out the difference between..
When you do:
'rule' => array('lessThanEqualTo','numDifference')
And then in your lessThanEqualTo function $compareTo = $this->data[$this->name][$otherfield];, you will look for numDifference field in your data object, which does not exist.
One way would be to create a lessThanEqualToDiff method like this:
public function lessThanEqualToDiff ($check, $startfield, $usedfield) {
$value = array_values($check);
$sn = intval($this->data[$this->name][$startfield]);
$un = intval($this->data[$this->name][$usedfield]);
return Validation::comparison($value[0], 'lessorequal', $sn - $un) ;
}
Then your rule:
public $validate = array(
'ag1_compl_remain' => array(
'rule' => array('lessThanEqualToDiff', 'ag1_compl_start_number', 'ag1_compl_used_number'),
'message' => 'Value must be less than difference between numbers',
'allowEmpty' => true,
'required' => false
)
);
So, the validation method should be like this:
public function lessThanEqualToDiff ($check, $startfield, $usedfield) {
$value = array_values($check);
$sn = (int)$this->data[$this->name][$startfield];
$un = (int)$this->data[$this->name][$usedfield]
return Validation::comparison($value[0], 'lessorequal', $sn - $un) ;
}
to use the php int feature correctly. Thanks to Holt and marian0 for their help.

Override / remove server-side validation in Symfony2.5

Say I have the following form builder buildForm method:
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'travelTime',
'datetime',
array(
'label' => 'Time',
'date_widget' => 'single_text',
'time_widget' => 'single_text',
'invalid_message' => 'Please enter a valid date and time',
)
)
->add(
'acmeEntity',
'entity',
array(
'label' => 'Acme Entity:',
'class' => 'AcmeBundle:MyEntity',
'expanded' => false,
'multiple' => false,
)
)
}
How can I override (or remove) validation for the 'acmeEntity' form field (and only that field) so that if I call:
$form->handleRequest($request);
$form->isValid();
in a Controller, then acmeEntity will not be included in the validation that determines whether $form->isValid() returns true? I've tried adding constraints => false, to the field options, but I'm receiving this error message:
Notice: Trying to get property of non-object in /var/www/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php line 67
Does anyone know the proper way to disable server-side validation for a Symfony form field?
EDIT:
Note that I am not looking for how to disable validation completely. This can be done by adding:
// Disable form validation
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$event->stopPropagation();
}, 900); // Always set a higher priority than ValidationListener
to the bottom of a form builder.
Rather, I want to know how to completely disable validation for a single form field. Thanks everyone and good hunting!
You can define a custom form type for your entity and use the 'validation_groups' => false. This should disable the validation only for this field.
The custom form type may look like that:
// .../Your/OwnBundle/Form/Type/AcmeEntityType.php
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class AcmeEntityType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => false
));
}
public function getParent()
{
return 'entity';
}
public function getName()
{
return 'acme_entity';
}
}
You can then use:
$builder
->add(
'travelTime',
'datetime',
array(
'label' => 'Time',
'date_widget' => 'single_text',
'time_widget' => 'single_text',
'invalid_message' => 'Please enter a valid date and time',
)
)
->add(
'acmeEntity',
'acme_entity',
array(
'label' => 'Acme Entity:',
'class' => 'AcmeBundle:MyEntity',
'expanded' => false,
'multiple' => false,
)
)
}
I assume that you call buildForm() from MyEntityType extending AbstractType so just use the options resolver by adding the function setDefaultOptions() in your type as said in the symphony doc here
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => false,
));
}
You can try this, I have used it in the past :
Create a validation group for your MainEntity
Add this validation group to your form
Do not add this validation group to AcmeEntity

ZF2 + Duplicate Form Validation on composite key

I have a Form having primary key on two fields (gid, bid). I need to add validation to block duplicate entries into database.
I have checked with ZF2 Solution for this . http://framework.zend.com/manual/2.2/en/modules/zend.validator.db.html#excluding-records . While this approach of handling composite keys is not look the ideal way, But still I am trying it because it look like only buil-in way. Now it require me to provide second field's value (value option in exclude), which is again a problem. As I am trying it
$inputFilter->add(array(
'name' => 'gid',
'required' => true,
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
'isEmpty' => 'required'
),
),
),
array (
'name' => 'Zend\Validator\Db\NoRecordExists',
'options' => array (
'table' => 'gtable',
'field' => 'gid',
'adapter' => $this->dbAdapter,
'messages' => array(
\Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database'
),
'exclude' => array(
'field' => 'bid',
'value' => [?],
),
)
),
)
));
How do I get this value, As Form is absolute separate Class/File than controller where I have the submitted form values. Is some better architecture solution of this problem exists Or Some hack to pass submitted field value to Form Class is only solution ?
Note : I am not in favor of Build My Validation Plugin for this task as short time is constraint for functionality.
You can do all the job in your form. To achieve that, you could define your forms as factories in your module Module.php.
Module.php
use MyNamespace\MyForm;
//NOTE THAT THE SERVICE MANAGER IS INJECTED. YOUR FORM COULD RECEIVE IT THROUGH THE CONSTRUCTOR
public function getServiceConfig()
{
return array(
'factories' => array(
'my_form' => function( $sm ) {
$form = new MyForm( $sm );
return $form;
},
),
);
}
When you want to use the form is as easy as use this code in your controller:
class MyController extends AbstractActionController
{
public function createAction() {
$form = $this->getServiceLocator()->get( 'my_form' ) );
(...)
}
}
And your MyForm.php
use Zend\Form\Form;
class MyForm extends Form
{
public $serviceManager, $request, $postData;
public function __construct( $serviceManager ) {
parent::__construct( null );
$this->serviceManager = $serviceManager;
$this->request = $serviceManager->get( 'Application')->getMvcEvent()->getRequest();
$this->postData = get_object_vars( $this->request->getPost() );
}
}
This way you can get advantage of the Service Manager within your form. And the public postData, where you'll find the bid value you're looking for to build your NoRecordExists filter.
You could add the parameters to the getInputFilter, like this :
getInputFilter($gid, $bid)
And then on the controller, when you set the filter you pass the 2 parameters, and then just check as $form->isValid(); ...
Alternative try this:
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => 'gtable',
'field' => 'gid',
'adapter' => $this->dbAdapter,
),
),
I'm unsure on your use case. If you were to add a database entry the primary keys for that table would not be known until you insert anyway - If you have foreign key constraints you could handle the exception from the database.
I am not in favor of Build My Validation Plugin for this task
The validator is also not designed to validate multiple fields as they are attached to a form element on a 1-1 basis. You will therefore need to create your own.
The below example has NOT been tested, so take it as an example of the approach rather than working code.
The key bit is the isValid method.
namespace MyModule\Validator\Db;
use Zend\Validator\Db\NoRecordExists;
class CompositeNoRecordExists extends NoRecordExists
{
protected $field2;
protected $field2Value;
public function __construct($options = null)
{
parent::__construct($options);
if (array_key_exists('field2', $options)) {
$this->setField2($options['field2']);
} else {
throw new \BadMethodCallException('Missing field2 option!');
}
}
protected function setField2Value(array $context)
{
if (! isset($context[$this->field2])) {
throw new \BadMethodCallException('Unable to find value for field 2');
}
$this->field2Value = $context[$this->field2];
}
public function isValid($value)
{
// The isValid() method is actually given a 2nd argument called $context
// Which is injected by the inputFilter, via the input and into the validator chain
// $context contains all of RAW form element values, keyed by thier element name.
// Unfortunately due to the ValidatorInterface you are unable to add this to the method
// signature. So you will need to be 'creative':
$args = func_get_args();
if (isset($args[1]) && is_array($args[1])) {
$this->setField2Value($args[1]);
} else {
throw new \BadMethodCallException('Missing validator context');
}
return parent::isValid($value);
}
public function getSelect()
{
$select = parent::getSelect();
$select->where->equalTo($this->field2, $this->field2Value);
return $select;
}
}
Then all you would need to do is update the validator config, adding the field2 field name.
array (
'name' => 'MyModule\Validator\Db\CompositeNoRecordExists',
'options' => array (
'table' => 'gtable',
'field' => 'gid',
'field2' => 'bid',
'adapter' => $this->dbAdapter,
'messages' => array(
\Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database'
),
)
),

cakephp custom validation does not display error message in the nested rule

im doing a custom validation but it does not display error message when invalidated.
do you know where is the problem? I think the problem might be in the invalidate function. do you know how to set it up for the nested validation like this one?
var $validate = array(
'receiver' => array(
'maxMsg' => array(
'rule' => array('maxMsgSend'),
//'message' => ''
),
'notEmpty' => array(
'rule' => array('notEmpty'),
'message' => 'field must not be left empty'
))......
custom validation method in the model:
function maxMsgSend ( $data )
{
$id = User::$auth['User']['id'];
$count_contacts = (int)$this->Contact->find( 'count', array( 'conditions' =>array( 'and' =>array( 'Contact.contact_status_id' => '2',
'Contact.user_id' => $id))));
$current_credit = (int)$this->field( '3_credit_counter', array( 'id' => $id));
$max_allowed_messages = ($count_contacts >= $current_credit)? $current_credit: $count_contacts ;
if ($data>$max_allowed_messages)
{
$this->invalidate('maxMsg', "you can send maximum of {$max_allowed_messages} text messages.");
}
}
UPDATE: how is solved it.
i moved the the guts of the function to beforeValidate() in the model.
function beforeValidate($data) {
if (isset($this->data['User']['receiver']))
{
$id = User::$auth['User']['id'];
$count_contacts = (int)$this->Contact->find( 'count', array( 'conditions' =>array( 'and' =>array( 'Contact.contact_status_id' => '2',
'Contact.user_id' => $id))));
$current_credit = (int)$this->field( '3_credit_counter', array( 'id' => $id));
$max_allowed_messages = ($count_contacts >= $current_credit)? $current_credit: $count_contacts ;
if ($data>$max_allowed_messages)
{
$this->invalidate('receiver', "you can send maximum of {$max_allowed_messages} text messages.");
return false;
}
}
return true;
}
I think your maxMsgSend function still needs to return false if validation fails.
I think the problem is in your Model::maxMsgSend function. As written in the bakery, (http://bakery.cakephp.org/articles/view/using-equalto-validation-to-compare-two-form-fields), to build a custom validation rule (they want to compare two fields, but the concepts are the same), they write:
I return a false if the values don't match, and a true if they do.
Check out their code for the Model class, about half way down. In short, you don't need to call invalidate from within the custom validation method; you simply return true if it passes validation, and false if it doesn't pass validation.

CakePHP model validation with array

I want to use CakePHP's core validation for lists in my model:
var $validate = array(
'selectBox' => array(
'allowedChoice' => array(
'rule' => array('inList', $listToCheck),
'message' => 'Enter something in listToCheck.'
)
)
);
However, the $listToCheck array is the same array that's used in the view, to populate a selectbox. Where do I put this function?
public function getList() {
return array('hi'=>'Hello','bi'=>'Goodbye','si'=>'Salutations');
}
Already in my controller, in one of the actions I'm setting it for the view, like:
public function actionForForm() {
$options = $this->getList();
$this->set('options', $options);
}
So, I don't want to have to copy the getList() function...where can I put it so the Model can call it to populate its $listToCheck array?
Thanks for your help.
Considering that it's data, you should store the list of valid choices in the model.
class MyModel extends AppModel {
var $fieldAbcChoices = array('a' => 'The A', 'b' => 'The B', 'c' => 'The C');
}
You can get that variable in the Controller simply like this:
$this->set('fieldAbcs', $this->MyModel->fieldAbcChoices);
Unfortunately you can't simply use that variable in the rule declaration for the inList rule, since rules are declared as instance variables and those can only be initialized statically (no variables allowed). The best way around that is to set the variable in the Constructor:
var $validate = array(
'fieldAbc' => array(
'allowedChoice' => array(
'rule' => array('inList', array()),
'message' => 'Enter something in listToCheck.'
)
)
);
function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->validate['fieldAbc']['allowedChoice']['rule'][1] = array_keys($this->fieldAbcChoices);
}
If you're not comfortable overriding the Constructor, you could also do this in a beforeValidate() callback.
Also note that you shouldn't name your field 'selectBox'. :)

Resources