Cake PHP custom validation rule - class

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.

Related

Pass Eloquent Model As An Closure Argument In PHP

I'm using Laravel Illuminate/Database outside of laravel application. I'm trying to pass the Eloquent model as my closure argument but its throwing an error. May be I'm passing it wrongly. My code is as following:
// Create a dummy subject (This is working absolutely fine)
SubjectModel::create(array(
'title' => 'Mathematics',
'description' => 'Math Subject',
'slug' => 'math',
'ka_url' => 'http://khanacademy.org/math'
));
$scrapper = new SubjectScrapper();
$scrapper->setUrl('');
This is not working. SubjectModel is not being passed in the following closure
$scrapper->runScrapper(function($subjects) use ($scrapper, SubjectModel $subjectModel) {
if(!empty($subjects))
{
foreach ($subjects as $subject) {
$urlParts = explode('/', $subject['url']);
$slug = end($urlParts);
$subjectModel::create(array(
'title' => $subject['subject_name'],
'slug' => $slug,
'ka_url' => $scrapper->getBaseUrl().$subject['link'],
));
}
}
});
Could anybody please tell me how to accomplish this task.
Try this. No need to pass object in closure
$scrapper = new SubjectScrapper();
$scrapper->setUrl('');
$scrapper->runScrapper(function($subjects) use ($scrapper, $output) {
SubjectModel::create(array(
'title' => 'Math',
'slug' => 'math',
'ka_url' => 'http://math'
));
$output->writeln('<info>Total Subjects Scrapped:: '.count($subjects).'</info>'.PHP_EOL);
});

Drupal 8 optional in drupal_process_states doesn't work

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);
}
}
}
}

Drupal custom form and autocomplete issue

Some how I managed to get it work. But still the result is not coming along with the autocomplete.
Posting my latest code now,
the textfield code
$form['town'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#autocomplete_path' => 'hfind/town/autocomplete',
);
menu function code
function hfind_menu() {
$items = array();
$items['hfind/town/autocomplete'] = array (
'title' => 'Autocomplete for cities',
'page callback' => 'hfind_town_autocomplete',
'access arguments' => array('use autocomplete'),
'type' => MENU_CALLBACK
);
return $items;
}
the callback function code
function hfind_town_autocomplete($string){
$matches = array();
$result = db_select('towns', 't')
->fields('t', array('town_name'))
->condition('town_name', '%' . db_like($string) . '%', 'LIKE')
->execute();
foreach ($result as $row) {
$matches[$row->city] = check_plain($row->city);
}
drupal_json_output($matches);
}
I hope this may the final edit.
The current situation is, autocomplete is working
The url is hfind/town/autocomplete/mtw
but it is not able to find any data from the database. I found why and unable to fix it.
It is because in the last function I've added above the $string needs to be the 'search query' but it is always querying the database as 'autocomplete'. I mean the $string variable always having the value 'autocomplete' instead of user typed value.
One more problem is, even after providing the permission to all types of user to access search autocomplete on the forms, guests users are not able to use the feature.
Please please someone help me..
`drupal_json_output()` instead of `drupal_to_js` and remove `print` .
<code>
hook_menu() {
$items['cnetusers/autocomplete'] = array(
'title' => 'Auto complete path',
'page callback' => 'cnetusers_employees_autocomplete',
'page arguments' => array(2, 3, 4, 5),
'access arguments' => array('access user profiles'),
'type' => MENU_CALLBACK,
);
return $item;
}
// my autocomplete function is like this
function cnetusers_employees_autocomplete() {
// write your sql query
$matches["$record->ename $record->elname [id: $record->uid]"] = $value;
}
if (empty($matches)) {
$matches[''] = t('No matching records found.');
}
drupal_json_output($matches);
}
$form['disc_info']['approval'] = array(
'#type' => 'textfield',
'#title' => t('Approval By'),
'#autocomplete_path' => 'cnetusers/autocomplete',
);
</code>

CodeIgniter autoloading form validation rules set not working with parameters

Following CI user_guide, I have created a configuration file named "form_validation.php" with in it the following sets:
$config = array(
'user/create' => array(
array(
'field' => 'id',
'label' => '',
'rules' => ''
),
array(
'field' => 'first_name',
'label' => 'lang:First name',
'rules' => 'required|max_length[30]'
),...
),
'user/update' => array(
array(
'field' => 'id',
'label' => '',
'rules' => ''
),
array(
'field' => 'first_name',
'label' => 'lang:First name',
'rules' => 'required|max_length[30]'
),...
)
);
In my 'user' controller, when I call the 'create' method, hence with the URL http://localhost/my_ci_application/user/create, the statement $this->form_validation->run() automatically runs the first set of rules defined in my configuration file. This is the expected behaviour from what I read in the user guide.
But when I run the following URL http://localhost/my_ci_application/user/update/1 to update the user whose ID is 1, it does not automatically load the 'user/update' rules set. It seems like because of the parameter, CI expects to find a 'user/update/1' rules set, which of course I cannot create because the ID of my users will vary all the time when calling this method.
Am I understanding this right? If yes, then that's a pity as I thought standard CI URL were formed like: controller/method/parameters... so I would expect the form validation class to only consider the first two URI segments?!
FYI, if I write in my user.update method the following, my validation rules work fine:
$this->form_validation->run('user/update')
So my question is really if I understood the autoloading of rules properly or not, and if there is anything we can do to autoload those rules even with methods having some parameters.
thank you very much in advance.
In your form_validation.php file:
$CI =& get_instance();
$config = array(
'user/update/' . $CI->uri->segment(3) => array(
....
)
);
if i understant this question u will need call validation, for example:
$this->lang->load('form_validation', 'portuguese'); //if u have order language
if($this->form_validation->run('user/update') == FALSE)
{
//msg error
}
else{
//save
}
To get the value for the url dowel u need:
$this->uri->segment(3);
i hope this has helped
You can extend the library to achieve this
application/libraries/MY_Form_validation.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
function run($group = '')
{
if($group == '')
{
$group = '/' . implode('/', array_slice($this->CI->uri->rsegment_array(), 0, 2));
}
return parent::run($group);
}
}

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.