I have a problem in custom validation rules in Yii. I have some fields like day1s, day1e, day2s, day2e etc. I want to check whether these attributes have the same value stored in my db or not before creating a new record. And also check for different userid. If a value already exists I want to generate an error and prompt the user to change the value. I figured to do something like this:
array('day1s, day1e, day2s etc','unique','message'=>'day1s is already exist, please change'),
This kinda work but I want to modify it. The default value of this is "00:00" and if I put this rule then every time I will go and create a new record it generates the error, except the first time. I want to ignore that when day1s==00:00. And also if the user changes(in my occasion the user is SchoolID). I'm having trouble wrapping around my head on how to do that. Thanks in advance!
Add allowEmpty in rule:
array('day1s, day1e, day2s etc','unique','message'=>'day1s is already exist, please change', 'allowEmpty'=>true),
In controller before validation add this code:
if($model->day1s == "00:00") {
$model->day1s = '';
}
Sorry for being so late to answer. In controller you mean in my action Create?Before $model->save?I tried that but it doesn't seem to work. I figured to make a function in my model like this:
public function unique() {
if ($this->day1s == "00:00" || $this->day1s == "0:00") {
$this->day1s='';//here it seems to work for the 00:00
} else {
//but my rule gets ignored now for any other values. What can I add here to make it work?
}
Also sorry for posting an answer instead of editing my question.
I figured it out eventually: my rules are like this:
array('day1s,day1e, day2s, day2e, day3s, day3e, day4s, day4e, day5s, day5e, day6s, day6e, day7s, day7e','unique','message'=>'This already exist, please change', 'allowEmpty'=>true,
'criteria' => array(
'condition' => 'schoolid=:schoolid',
'params' => array(':schoolid' => $this->schoolid))
),
and my controller is like this:
if ($model->day1s == "00:00" || $model->day1s == "0:00") {
$model->day1s='';//for custom validation rule 'unique'
}
if ($model->day1e == "00:00" || $model->day1e == "0:00") {
$model->day1e='';
}
.....
if($model->validate()){
if($model->save())
$this->redirect('admin');}
}
Thanks again for your help!
Related
I'm facing a problem while working on file validation in Codeigniter 4. Codes are given below.
Codes in the validation file are:
public $image = [
'image_path' => [
'label' => 'Image',
'rules' => 'uploaded[image_path]|is_image[image_path]|max_size[image_path, 1024]|mime_in[image_path,image/jpg,image/jpeg,image/png]'
]
];
And, codes in the controller are:
if($image->isValid() && !$image->hasMoved()):
if(!$this->validation->run($image, "image")):
$this->session->setFlashdata('image_errors', $this->validation->getErrors() ?? "");
return redirect()->back()->withInput();
endif;
endif;
But whenever I'm trying to run these code, the following error happened:
Argument 1 passed to CodeIgniter\Validation\Validation::run() must be of the type array or null, object given.
Please suggest me possible solution for this.
Thank you.
When we need to validate form in the controller we follow this steps:
use validate() method instead of using $validation property
see Controller Validate Data
set flashdata within recirect()->with() method
see Common functions
if condition syntax should be with brackets { }, use if else endif in view files only (optional).
see Alternate Syntax
It's very important and recommended to read User Guide
if ($image->isValid() && ! $image->hasMoved())
{
if (! $this->validate('image'))
{
return redirect()->back()->withInput()->with('image_errors', $this->validator->getErrors())
}
}
if you want to use validation class just do this
if ($image->isValid() && ! $image->hasMoved())
{
$this->validation->setRuleGroup('image');
if (! $this->validation->withRequest($this->request)->run())
{
return redirect()->back()->withInput()->with('image_errors', $this->validation->getErrors())
}
}
I hope it will work fine with your code.
I'm using Laravel for a project and want to know how to validate a particular scenario I'm facing. I would like to do this with the native features of Laravel if this is possible?
I have a form which has two questions (as dropdowns), for which both the answer can either be yes or no, however it should throw a validation error if both of the dropdowns equal to no, but they can both be yes.
I've check the laravel documentation, but was unsure what rule to apply here, if there is one at all that can be used? Would I need to write my own rule in this case?
very simple:
let's say both the fields names are foo and bar respectively.
then:
// Validate for those fields like $rules = ['foo'=>'required', 'bar'=>'required'] etc
// if validation passes, add this (i.e. inside if($validator->passes()))
if($_POST['foo'] == 'no' && $_POST['bar'] == 'no')
{
$messages = new Illuminate\Support\MessageBag;
$messages->add('customError', 'both fields can not be no');
return Redirect::route('route.name')->withErrors($validator);
}
the error messge will appear while retrieving.
if you get confuse, just dump the $error var and check how to retrieve it. even if validation passes but it gets failed in the above code, it won't be any difference than what would have happened if indeed validation failed.
Obviously don't know what your form fields are called, but this should work.
This is using the sometimes() method to add a conditional query, where the field value should not be no if the corresponding field equals no.
$data = array(
'field1' => 'no',
'field2' => 'no'
);
$validator = Validator::make($data, array());
$validator->sometimes('field1', 'not_in:no', function($input) {
return $input->field2 == 'no';
});
$validator->sometimes('field2', 'not_in:no', function($input) {
return $input->field1 == 'no';
});
if ($validator->fails()) {
// will fail in this instance
// changing one of the values in the $data array to yes (or anything else, obvs) will result in a pass
}
Just to note, this will only work in Laravel 4.2+
I'm running into some difficulty in using the added componenet requirelogin.php . This is the component that I've added
<?php
class RequireLogin extends CBehavior
{
public function attach($owner)
{
$owner->attachEventHandler('onBeginRequest', array($this, 'handleBeginRequest'));
}
public function handleBeginRequest($event)
{
if (Yii::app()->user->isGuest && !in_array($_GET['r'],array('site/login', 'site/index'))) {
Yii::app()->user->loginRequired();
}
}
}
?>
Note how 'site/index' is allowed in this as a page that I can visit.
Now, in my main.php I added the following
'behaviors' => array(
'onBeginRequest' => array(
'class' => 'application.components.RequireLogin'
)
),
Now, these two force me to go to site/login everytime - even though I have done as other stackoverflow answers have told me to and added
// sets the default controller action as the index page
'defaultController' => 'site/index',
Could anyone explain why this hasn't made my start page site/index?
_____________ ADDITION
I've also figured out that when I am going to the base action (i.e. mywebsite.com) it is NOT going to site/index. rather it is directly redirecting to site/login. This, however, does not occur, when I comment out the behaviors .
So, thank you darkheir for all of your work on this.
Ultimately, what happened was the $_GET['r] in the base path was simply '' because r was not point to anything in particular. As a result, when ever I looked in_array($_GET['r']) what I was getting in the very bae path was in_array('', array('site/login', 'site/account')) Now, unfortunately, '' is neither site/login or site/account so the page redirected using
Yii::app()->user->loginRequired();
The fix to this problem was
public function handleBeginRequest($event)
{
// note that '' is now one of the options in the array
if (Yii::app()->user->isGuest && !in_array($_GET['r'],array('site/login', 'site/index', '' ))) {
Yii::app()->user->loginRequired();
}
}
I have a Profile form that inherits from sfGuardRegisterForm
I have these fields:
$this->useFields(
array('first_name',
'last_name',
'email_address',
'country',
'language',
'current_password',
'new_password',
'password_again',
)
);
Required fields are:
email_address, country and language
And the conditions are:
If the email_address is not equal with the current email_address
then check if it's unique then save it
If the current_password is the actual password of the user then verify if new_password and password_again are equals and verify that the new_password is not equal to the actual password of the user
I just can't figure out in how implement this
EDIT
Thanks 1ed your example works but the problem is that I load the user Profile and I fill the fields: 'first_name', 'last_name', 'email_address', 'country', 'language' with the actual logged user so the email_address field will show the email address:
//...
$this->widgetSchema['email_address']->setDefault($this->_user->getEmailAddress());
//...
If the user dont change the email it will always show this message:
An object with the same "email_address" already exist.
I just want to skip that
Also this $this->getObject()->checkPassword() does not works, always show this message:
Incorrect current password.
I use:
$this->_user = sfContext::getInstance()->getUser()->getGuardUser();
To get actual user profile
EDIT2
Thanks again 1ed
This is very weird and I'm getting frustated, this is the situation
I have a "workaround" for this but it does not follow the standard, I can make it works but using sfContext::getInstance()->getUser()->getGuardUser(); and it will be more unnecesary code
If I use new ProfileForm($user) automatically fills all the fields, that's very good but I can't setDefault() I can't set null or empty any field so I can't use doUpdateObject() because this function only works when the current data is updated, also I have tested overriding bind(), save() etc. without results
email_address uniqueness: you should set unique: true in schema, in sfDoctrineGuardPlugin that's the case by default, so in BasesfGuardUserForm you should see a unique validator already: sfValidatorDoctrineUnique(array('model' => 'sfGuardUser', 'column' => array('email_address'))
current_password: you should create a callback type post validator for this
// in sfGuardRegisterForm::configure()
// these fields can be blank
$this->getValidator('current_password')->setOption('required', false);
$this->getValidator('new_password')->setOption('required', false);
$this->getValidator('password_again')->setOption('required', false);
// check the current password (this validator is not `required` by default)
$this->mergePostValidator(new sfValidatorCallback(array(
'callback' => array($this, 'checkPassword'),
), array(
'invalid' => 'Incorrect current password.'
)));
// add this method to the same form class
public function checkPassword(sfValidatorBase $validator, array $values, array $arguments)
{
// if a new password is given check whether the old one is correct or not and rise an error if not correct
if(0 != strlen($values['new_password']) && !$this->getObject()->checkPassword($values['current_password']))
{
throw new sfValidatorErrorSchema($validator, array(
'current_password' => new sfValidatorError($validator, 'invalid')
));
}
return $values;
}
Alternatively you can create a custom post validator, but I think it's not necessary.
EDIT:
If you would like to display empty email address just like the password fields add these to your form class:
// at form load remove the default value
protected function updateDefaultsFromObject()
{
parent::updateDefaultsFromObject();
if (isset($this['email_address']))
{
$this->setDefault('email_address', '');
}
}
// before save remove empty email address
protected function doUpdateObject($values)
{
if (isset($values['email_address']) && 0 == strlen($values['email_address']))
{
unset($values['email_address']);
}
parent::doUpdateObject($values);
}
I'll try and explain this in methodical terms instead of giving you a big block of code....
So first, you want to if (email_addr != current_email) and if that's true, go on to do
if (new_pass != current_pass) then follow on to make sure if (new_pass == new_pass_again)
Inside all of these IFs, you can return a true/false or some kind of flag, or just //do code inside the brackets :p
EDIT: encase these IFs in: if (country != NULL && language != NULL && email_addr != NULL)
my CakePHP (1.2.5.) doesn't validate my form correct.
$this->UserData->save($this->data);
gives me always a true value back. I can't find the problem. The label for UserData.nichname works.
That's the View:
<?php
echo $form->create('UserData');
echo $form->error('UserData.nick_name');
echo $form->input('UserData.nick_name', array('id' => 'UserDatanick_name', 'rule' => 'alphaNumeric', 'label' =>'Nickname:', 'error' =>'false'));
echo $form->end( array( 'label' => ' Save ') );
?>
Here is my Controller:
class UserDatasController extends AppController {
var $name = 'UserDatas';
function add(){
if (!empty ($this->data)){
$this->UserData->create();
if ($this->UserData->save($this->data)){
$this->Session->setFlash('input is valid');
} else {
$this->Session->setFlash('input is not valid');
}
}
}
}
The rules for are not in the model, that's the reaseon i don't post it.
What else is necessary for a validation?
Thanks in advance
Steve
The validation rules have to be defined in the model, not in the view, see also the chapter about data validation in the cakebook.
^^ also check what your files are called.
you have named your model file user_data.php right? and your controller user_data_controller.php?
Note the underscores because of your CamelCasing. If you get the model file name wrong, it wont complain but will instead use a default magic model - which could be why your validation rules within the model didnt get picked up.
I believe you only specify the rules in the model, but the label would be kept in the $form->input() function