I'm going crazy trying out different solutions on the net of a fairly simple problem
I have literally hundreds of dates being stored by my application, and my client's source data has a bad habit of dates being in different formats.
For example, one of my models has rules as followed (for completion all are listed for this specific model)
public function rules() {
return array(
array('function, junior, ces,agreement_expected,start_date', 'required'),
array('start_budget', 'numerical'),
array('visa_received,training_days', 'numerical', 'integerOnly' => true),
array('function, junior, ces,currency', 'length', 'max' => 10),
array('agreement_received, status, stop_date_original, stop_date_extended', 'safe'),
array('agreement_received, visa_received, stop_date_original, stop_date_extended', 'default', 'setOnEmpty' => true, 'value' => null),
array('agreement_received,agreement_expected,start_date,stop_date_original,stop_date_extended', 'date', 'format' => 'Y-m-d', 'allowEmpty' => true),
array('id, Sname,PFces, PFdomain,PDkeyword, PFstatus, PRname,PRcountry,PRscore,PRcomment,PRngo,TRname,TRpic, TFfunction, TFx, TRdateofbirth,TRedufields,TRcoach,TRlocation,TRtask,TRcontract,TRproject,TRcontact,TFdateofbirth,TFedufields,TFcoach,TFlocation,TFtask,TFcontract,TFproject,TFcontact,
date1,date2,idate, ddomains,dkeywords,country,agreement, function,ngo, status,group, junior, junior_lastname, junior_firstname,search_all,search_interrupt, ces, agreement_expected, agreement_received, visa_received, start_date, stop_date_original, stop_date_extended,currency, start_budget, training_days', 'safe', 'on' => 'search'),
);
}
what I want to achieve is depicted by following rules
array('agreement_received, visa_received, stop_date_original, stop_date_extended', 'default', 'setOnEmpty' => true, 'value' => null),
array('agreement_received,agreement_expected,start_date,stop_date_original,stop_date_extended', 'date', 'format' => 'Y-m-d', 'allowEmpty' => true),
When I have a form, and I submit an empty value on say stop_date_extended, it is not set to NULL rather an empty string..
What am I doing wrong?
Surely there must be an easy work-around as not using the date validator works peachy.
Yii Default Validator class handles the empty values like this :
/framework/validators/CDefaultValueValidator.php
protected function validateAttribute($object,$attribute)
{
if(!$this->setOnEmpty)
$object->$attribute=$this->value;
else
{
$value=$object->$attribute;
if($value===null || $value==='')
$object->$attribute=$this->value;
}
}
Given the function above your only issue could be that the value[i.e $value] posting by form could be not empty string probably it might have spaces. Probably you could try trim() the values before assigning them to model attributes. Or extend the default value validator e.g
class CMyDefaultValueValidator extends CDefaultValueValidator
{
protected function validateAttribute($object,$attribute)
{
if(!$this->setOnEmpty)
$object->$attribute=$this->value;
else
{
$value=trim($object->$attribute);
if($value===null || $value==='')
$object->$attribute=$this->value;
}
}
}
just note the line : $value=trim($object->$attribute);
Although,I haven't tested above code, I do not know if this is could be done some better way,
if you want to insert null for empty strings, you can do it in your model, after validation:
public function afterValidate()
{
if(empty(trim($this->yourField))) // put whatever logic that you need
$this->yourField = null;
return parent::afterValidation();
}
Related
inList states that your array should contain a certain string value.
I'm looking for a rule that will exclude certain values for names in my model.
The following code states that the name should be Bob, Bobbie or Bobzilla:
'name' => array(
'rule' => array('inList', array('Bob', 'Bobbie', 'Bobzilla')),
'message' => 'Stop it Bob!'
),
I need the user to be unable to enter any of these names. To me it seems as if inList should be notInList.
I've tried many ways but none of them lead me to Rome.
If you could help me that would be very much appreciated!
Take a look at PHP in_array function
something like
if (!in_array(ENTERED_NAME,YOUR ARRAY)) {
}
This is the best solution I was able to come up with:
public function itsBob($check) {
$bobArr = ['Bob', 'Bobbie', 'Bobzilla'];
if (!in_array($check['name'], bobArr) {
return false;
}
return true;
}
With the following lines in the $validation:
'name' => array(
'rule' => array('itsBob'),
'message' => 'Stop it bob!'
),
itsBob literally does the opposite of inList.
A Zend_Form like this:
class Application_Form_Registration extends Zend_Form
{
public function init()
{
/* Form Elements & Other Definitions Here ... */
$$this->setMethod('post');
//first name
$this->addElement('text', 'email', array(
'label' => 'First name',
'required' => true,
'filters' => array('StringTrim'),
));
//last name
$this->addElement('text', 'lastname', array(
'label' => 'Last name',
'required' => true,
'filters' => array('StringTrim')
));
$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Submit'
));
$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
}
I read through the ZF1 1.12 API and reference document, but I can't find the meaning of the flag "ignore" in the Zend_Form::addElement() configure options.
The api doc is just this:
Surely I googled it and find it but this is not the way to work. How to I find the meaning of certain specific stuff. I don't suppose that I need to read the source code?
Just take this addElement() as an example, am I missing somewhere to look further? Nothing in Zend_Config class that I can find about ignore flag either.
As I know ignore flag defines if form values ($form->getValues()) will contain element value. If ignore is set to true for some element than form values ($form->getValues()) will not contain this element value.
ZF Documentation can be...lacking sometimes. The API docs for the ignore flag state:
getIgnore( ) : bool Get ignore flag (used when retrieving values at form level)
Which hints that the ignore flag has something to do with the behavior of Zend_Form GetValues() but it's not really spelled out.
In these cases I like to go straight to the source code so I can see for myself:
public function getValues($supressArrayNotation = false)
{
...
foreach ($this->getElements() as $key => $element) {
if (!$element->getIgnore()) {
...
}
You can see that the getValues() function in Zend_Form will check the ignore flag on each element before adding the value to the return array. If the flag is true, the value won't be included.
I am using multiple scenarios in my application but facing a problem that every time the last scenario overrides the first one.
Model:
public function rules()
{
return array(
[...]
array('cost_spares', 'cost_spare_func', 'match',
'pattern' => '/^[a-zA-Z]+$/',
'message' => 'Do not enter zero or/and characters for Spare parts!',
'on' => 'cost_spare_func'),
array('cost_labour', 'cost_labour_func', 'match',
'pattern' => '/^[a-zA-Z]+$/',
'message' => 'Do not enter zero or/and characters for Labour Charges!',
'on' => 'cost_labour_func'),
);
}
Controller :
public function actionUpdate ($id)
{
if (isset($_POST['TblEnquiry']))
{
[...]
$model->setScenario('cost_spare_func');
$model->setScenario('cost_labour_func');
}
}
Regarding to the documents:
Firstly it is important to note that any rules not assigned a scenario will be applied to all scenarios.
So I think you maybe do not need a scenario and just use common rules/validation.
OR
You have ONE scenario for your rules like this:
public function rules()
{
return array(
[...]
array('cost_spares','numerical',
'integerOnly' => true,
'min' => 1,
'max' => 250,
'tooSmall' => 'You must order at least 1 piece',
'tooBig' => 'You cannot order more than 250 pieces at once',
'message' => 'Do not enter zero or/and characters for Spare parts!',
'on' => 'myScenario'),
array('cost_labour','numerical',
'integerOnly' => true,
'min' => 1,
'max' => 250,
'tooSmall' => 'You must order at least 1 piece',
'tooBig' => 'You cannot order more than 250 pieces at once',
'message' => 'Do not enter zero or/and characters for Labour Charges!',
'on' => 'myScenario'),
);
}
And in your controller you just write:
public function actionUpdate ($id)
{
if (isset($_POST['TblEnquiry']))
{
[...]
$model->setScenario('myScenario');
}
}
Edit: Regarding to this document, I just see that you only want numerical input. So this might fit better to your needs. And since both got same check, you could just do one check and pass the message later into it. But for now, this should work.
Extra:
There is another bug in your rules like you wrote.
array('cost_spares', 'cost_spare_func', 'match',
'pattern' => '/^[a-zA-Z]+$/',
'message' => 'Do not enter zero or/and characters for Spare parts!',
'on' => 'cost_spare_func'),
That is not possible. You can not mix a rule validate function and a default validation like match.
That means you can only define a validation function like this:
array('cost_spares', 'cost_spare_func',
'message' => 'Do not enter zero or/and characters for Spare parts!',
'on' => 'cost_spare_func'),
OR use a default validation like this:
array('cost_spares', 'match',
'pattern' => '/^[a-zA-Z]+$/',
'message' => 'Do not enter zero or/and characters for Spare parts!',
'on' => 'cost_spare_func'),
I am trying to set a field as reuired only when another field selected value not equal to 11.
I have tried this example
array('role', 'ext.YiiConditionalValidator',
'if' => array(
array('role', 'compare', 'compareValue'=>"11"),
),
'then' => array(
array('company_id', 'required'),
),
),
),
I tried downloading new ConditionalValidator.
And even tried custom condition:
public function checkEndDate($attributes,$params)
{
$this->addError('company_id','Error Message');
}
public function rules() {
return array(
array('company_id', 'checkEndDate')
);
}
But it all shows error. Any simple way to solve this?.
Why not using scenarios? If you're creating/editing model with 'customer_type=active' you can before hand create it with special scenario:
$model = new MyModel(MyModel::SCENARIO_ACTIVE);
and then define your rules including scenario:
array('birthdate, city', 'required', 'on' => MyModel::SCENARIO_ACTIVE),
array('city', 'in', 'range' => array("sao_paulo", "sumare", "jacarezinho"), 'on' => MyModel::SCENARIO_ACTIVE)
If you don't like this way, you can always very simply create your own validator.
In rules:
array('customer_type', 'myCustomValidator'),
In the model class:
function myCustomValidator(){
if($this->customer_type == 'active'){
...
if($error){
$this->addError(...);
}
}
}
I have applied unique validation for Employee Code. it is working fine for Add Emp case. But i am not getting why it is not working in case of Update, here is the code i have used for this:
My rule method is :
public function rules()
{
return array(
array('is_active', 'numerical', 'integerOnly'=>true),
array('first_name, last_name, employee_code, username, password, role,joining_date,', 'required','on'=>array('create','update')),
array('employee_code', 'numerical', 'integerOnly'=>true),
array('employee_code', 'unique','on'=>array('create','update')),
array('employee_code', 'length', 'min' => 4, 'max'=>4, 'message'=>Yii::t("translation", "{attribute} is too short.")),
array('username','email'),
array('username','valid_username','on'=>array('create')),
array('username', 'required','on'=>array('forgotPassword')),
array('currentPassword, newPassword, newPasswordRepeat', 'required','on'=>array('change')),
array('newPassword', 'compare', 'compareAttribute'=>'newPasswordRepeat','on'=>array('change'),'message'=>'New and Confirm Password do not match.'),
array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements(),'on'=>array('forgotPassword')),
array('joining_date', 'safe'),
array('years', 'safe'),
array('user_id, first_name, last_name, employee_code, username, password, role, joining_date, pending_regular_leave, pending_medical_leave, allocated_regular_leave, allocated_medical_leave, is_active', 'safe', 'on'=>'search'),
);
Please can someone identify where i am wrong. Please help me.
Looks like that the value of field "employee code" puts in form field and you are trying to save it. And it is not unique, and it is not save.
Anyway, you can:
$employee->validate(array('/* Here is list of attributes, except employee code */'));
or:
$employee->save(array('/* Here is list of attributes, except employee code */'));
in update action.
You can also delete scenario in validation rule:
array('employee_code', 'unique','on'=>array('insert');
When you update record it already exists in the database and the value you are going to validate already exists too. This is why when you do update you should exclude the record you are going to update from the check. Else the check will fail with the message like this
Employee Code "some value" has already been taken.
For example (new rule with criteria)
array(
'employee_code',
'unique',
'criteria' => array(
'condition' => 'user_id != :id',
'params' => array(':id' => $this->user_id),
),
'on' => array('create', 'update'),
),
I assume that user_id is the primary key.
Formally you might want to have different scenarios for update and create because you do not need any additional checks for the create scenario. Single scenario works as well but you might want to do something like this
array(
'employee_code',
'unique',
'on' => array('create'),
),
array(
'employee_code',
'unique',
'criteria' => array(
'condition' => 'user_id != :id',
'params' => array(':id' => $this->user_id),
),
'on' => array('update'),
),
P.S. As mentioned in one of the comments you might want to use insert instead of create because by default the scenario for newly created model is insert. This is more commonly used name.