I'm working on a multiple contact form in Yii 1.1.16. Where the user can add multiple phone numbers.
Problem is, how would i validate this using Yii's rules()?
<div class="form-group">
<?php
echo $form->labelEx($model,'contacts', array('class'=>'col-md-3 control-label'));
?>
<div class="col-md-9">
<div class="multiple-contact multiple-form-group input-group padding-bottom-10px" data-max="5">
<div class="input-group-btn input-group-select">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="concept">Phone</span> <i class="fa fa-caret-down"></i>
</button>
<ul class="dropdown-menu" role="menu">
<li>Phone</li>
<li>Fax</li>
<li>Mobile</li>
</ul>
<?php echo $form->textField($model,'contacts',array('type'=>'text', 'class'=>'input-group-select-val', 'name'=>'contacts[type][]','value'=>'phone')); ?>
</div>
<?php echo $form->textField($model,'contacts',array('size'=>60,'maxlength'=>255, 'name'=>'contacts[value][]','class'=>'form-control')); ?>
<?php echo $form->error($model,'contacts'); ?>
<span class="input-group-btn">
<button type="button" class="btn btn-success btn-add"><i class="fa fa-plus"></i></button>
</span>
</div>
</div>
</div>
i tried using this, but doesn't work
public function rules()
{
return array(
array('contacts[value][]', 'required'),
array('contacts[value][]', 'integerOnly'=>true),
array('contacts[value][]','type','type'=>'array','allowEmpty'=>false)
);
}
Here is a sample Fiddle on how the jQuery side works. I want it to be able to validate with 'enableAjaxValidation'=>true,. Also, when more fields are added, it duplicates the id of the input. and no ajax post is done onblur/onfocus
Use custom validation.
Declare a custom validator in your rules, and define the validation you require in the validator method.
public function rules()
{
return array(
array('contacts', validateContacts),
);
}
public function validateContacts($attribute,$params)
{
if (length($this->contacts) == 0) {
$this->addError($attribute, 'You must add at least one contact!');
}
foreach($this->contacts as $contact) {
// ...
}
}
In your controller, assign the contacts array to the Model field and call the model's validation method. If there are any errors it will display through the line
<?php echo $form->error($model,'contacts'); ?>
in the view.
The controller contains the code to invoke the validation.
$contactModel = new Contact;
// assign the array of contacts to the model
$contactModel->contacts = $POST['myForm]['contacts']
$contactsModel->validate();
$this->render('myform', contactModel);
If you want the validation to happen through Ajax, you need to specify so when creating your form:
$form=$this->beginWidget('CActiveForm', array(
'id'=>'top-websites-cr-form',
'enableAjaxValidation'=>true,
'clientOptions' => array(
'validateOnSubmit'=>true,
'validateOnChange'=>true),
));
In this case your controller can check for ajax forms.
if(isset($_POST['ajax']) && $_POST['ajax']==='branch-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
references:
http://www.yiiframework.com/wiki/168/create-your-own-validation-rule/
You should make it a separate model with it's own validation.
Then in your controller you have to validate the main models and the related models separately.
Here is a good guide for such a setup:
http://www.yiiframework.com/wiki/384/creating-and-updating-model-and-its-related-models-in-one-form-inc-image/
To my opinion for best validation regarding phonenumbers you should use libphonenumber php library and there is an extension for it regarding yii framework here http://www.yiiframework.com/extension/libphonenumber/
basic usage:
Yii::setPathOfAlias('libphonenumber',Yii::getPathOfAlias('application.vendors.libphonenumber'));
$phonenumber=new libphonenumber\LibPhone($your_phone_number);
$phonenumber->validate();
for more details regarding usage and capabilities of libphonenumber php library you can find here:
https://github.com/davideme/libphonenumber-for-PHP
Let us consider you have a model called ContactNo and it looks like
class ContactNo extends CFormModel
{
public $contact;
public function rules()
{
return array(
// your rules
array('contact', 'required'),
array('contact','length','min'=>2)
);
}
/**
* Declares attribute labels.
*/
public function attributeLabels()
{
return array(
'contact'=>'Contact No',
);
}
}
The controller as SiteController and the action Name as actionIndex
Then your controller should look something like this
public function actionIndex()
{
// set how many contact fields you want here
$contactCount = 3;
$models = array();
if(isset($_POST['ContactNo']))
{
$successModels = 0;
foreach($_POST['ContactNo'] as $key=>$value)
{
$model = new ContactNo;
$model->attributes = $value;
if($model->validate()) // this validates your model
$successModels++; // it tells how many contact No.s have been validated
$models[$key]=$model;
}
// if all the contact nos are validated, then perform your task here
if($successModels === $contactCount)
{
// save your models
echo 'models saved';
Yii::app()->end();
}
}
else
{
for($index = 0;$index < $contactCount; $index++)
$models[] = new ContactNo;
}
$params = array();
$params['contactCount']=$contactCount;
$params['models']= $models;
$this->render('index',$params);
}
Now lets Go to view. Obviously the view is index.php and it will be something like
// Include all the initial part required for activeforms
<?php echo $form->errorSummary($models); ?>
<?php foreach ($models as $index=>$model): ?>
<div class="row">
<?php echo $form->labelEx($model,"[{$index}]contact"); ?>
<?php echo $form->textField($model,"[{$index}]contact",array('size'=>60,'maxlength'=>128)); ?>
<?php echo $form->error($model,"[{$index}]contact"); ?>
</div>
<?php endforeach; ?>
// Include the submit button
Hope this helps you or might give you an idea atleast to achieve your goal.
Related
In my codeigniter controller function call $this->form_validation->run(), that return always false, and my validation_errors() not showing error, probably because not receive datas in post method...
my controller
class Reminder extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('reminder_model');
$this->load->helper('form');
$this->load->library('form_validation');
$this->load->helper('url');
$this->load->library('email');
$this->load->library('session');
if(!$this->session->auth_ok) {
redirect('auth/login');
}
}
public function index(){
$data['title'] = 'Reminder';
$data['section'] = 'reminder';
$data['reminders'] = $this->reminder_model->getReminders();
$data['operatori'] = $this->reminder_model->getOperators();
$this->form_validation->set_rules('selectUser','selectUser', '');
if($this->form_validation->run() === FALSE) {
$this->load->view('common/header2', $data);
$this->load->view('reminder/index', $data);
$this->load->view('common/footerReminder');
echo validation_errors();
}else{
echo "<pre>";
print_r($this->input->post());
die();
}
}
my view
<?php echo form_open('reminder/index'); ?>
<div class="form-group">
<label for="selectUser" style=" width: 30%">Utente: </label>
<select class="form-control" name="selectUser" id="selectUser" style="width: 30%">
<?php foreach($operatori as $operatore): ?>
<option value="<?php echo $operatore['ID']?>" <?php echo $r = ($operatore['ID']==$this->session->auth_user['ID']) ? 'selected' : '' ?>><?php echo $operatore['nome']." ".$operatore['cognome'] ?></option>
<?php endforeach; ?>
</select>
</div>
<button type="submit" class="btn btn-primary"><i class="fas fa-search"></i> View</button>
<?php echo form_close(); ?>
In order to get the entire $_POST array using CodeIgniters built-in methods, you have to set the first parameter as NULL and the second parameter as TRUE
Like this:
$this->input->post(NULL, TRUE);
Also, you have not set any rules for validation..
In CodeIgniter, you set rules in the third parameter of the set_rules method within the form_validation object.
Like this:
$this->form_validation->set_rules($FIELD_NAME, $FIELD_NAME(for error messages), $RULES);
You would substitute the first $FIELD_NAME with the value of the name attribute on the HTML element you are looking to validate.
You would substitute the second $FIELD_NAME with the name you would like to use for the field when displaying an error message to the user.
You would substitute $RULES with the validation rules such as: 'required|min_length[#]|max_length[#]'
Hope this helps!
If you are not setting rules (which makes it rather pointless to use $this->form_validation->set_rules()) the form validation will fail as it's missing a required parameter.
If you don't need to validate a field, don't set a rule.
Try updating your set_rules instruction to $this->form_validation->set_rules('selectUser','selectUser', 'required'); to see if it behaves correctly. You can verify by filling something in the form (validation will pass) or leaving the field blank (validation will fail)
Just remember, if you won't set at least one validation rule for a field, don't instantiate the set_rules method for that field
I have this code Im trying to save the content and the title from a form I made..It has an id that autoincrement the id number adds in the database but the title and the content isn't/cant be save in the database. Can you please check my code if I've done something wrong? or what I'm lacking at.
Here is my model ContentForm.php
<?php
class ContentForm extends CActiveRecord{
public $content;
public $title;
public function tableName(){
return 'tbl_content';
}
public function attributeLabels()
{
return array(
'contentid' => 'contentid',
'content' => 'content',
'title' => 'title',
// 'email' => 'Email',
// 'usrtype' => 'Usrtype',
);
}
Here is my view content.php
<div>
<p>User: <a href="viewuserpost">
<?php
echo Yii::app()->session['nameuser'];
?>
</a>
</p>
</div>
<h1>Content</h1>
<?php
$form=$this->beginWidget('CActiveForm', array(
'id'=>'contact-form',
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
));
?>
Title:
<div class="row">
<?php
echo $form->textfield($model,'title');
?>
</div>
</br>
Body:
<div class="row">
<?php
echo $form->textArea($model,'content',array('rows'=>16,'cols'=>110));
?>
</div>
<div class="row buttons">
<?php
echo CHtml::submitButton($model->isNewRecord? 'Create':'Save');
?>
</div>
<?php $this->endWidget(); ?>
and here is my content action in my sitecontroller.php
public function actionContent(){
$model=new ContentForm;
if(isset($_POST['ContentForm'])) {
$model->attributes=$_POST['ContentForm'];
if($model->save())
$this->redirect(array('content','contentid'=>$model->contentid));
$this->redirect(array('content','title'=>$model->title));
$this->redirect(array('content','content'=>$model->content));
}
$this->render('content',array('model'=>$model));
}
Please help.
Remove
public $content;
public $title;
from your class.
Yii uses PHP magic methods. And when you add attributes to your class, PHP doesn't call them but references to your explicitly written attributes.
Moreover, you should add some validation, if you use $model->attributes=$_POST['ContentForm'];. Another variant is to use unsecure $model->setAttributes($_POST[ContentForm], false) where false tells Yii to set all attributes, not only that are considered safe.
Note, that attributes is not real Model attribute, this is virtual attribute accessed through magic methods.
Also, you don't need three redirects. This is HTTP redirect to other page. This time, you just should just specify route to model view action and its parameter that is id, for example. Like this $this->redirect(array('content/view','id'=>$model->contentid));.
Of course, simplest way for you is to create new model and controller with actions using Gii.
you may missed rules , add this in your model ContentForm.php
public function rules()
{
return array(
array('content,title', 'safe'),
);
}
For more about model validation
http://www.yiiframework.com/wiki/56/reference-model-rules-validation/
Hi I am attempting to upload a file and write it to the database using YII, but nothing is happening at all, Its neither saving the file nor name saving to DB.
My View...
<div class="row">
<div class="span4"><?php echo $form->labelEx($model,'slider_image'); ?></div>
<div class="span5"><?php echo $form->fileField($model,'slider_image'); ?></div>
<div class="span3"><?php echo $form->error($model,'slider_image'); ?></div>
</div>
My Model for validation...
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
//more rules
array('slider_image', 'file', 'types'=>'jpg, gif, png', 'allowEmpty'=>true),
//more rules
);
}
Controller:
public function actionEdit()
{
$id = Yii::app()->getRequest()->getQuery('id');
$model = CustomPage::model()->findByPk($id);
if (!($model instanceof CustomPage))
{
Yii::app()->user->setFlash('error',"Invalid Custom Page");
$this->redirect($this->createUrl("custompage/index"));
}
if(isset($_POST['CustomPage']))
{
$model->attributes = $_POST['CustomPage'];
if (CUploadedFile::getInstance($model,'slider_image')) {
$model->slider_image=CUploadedFile::getInstance($model,'slider_image');
}
if ($model->validate())
{
if ($model->deleteMe)
{
$model->delete();
Yii::app()->user->setFlash('info',"Custom page has been deleted");
$this->redirect($this->createUrl("custompage/index"));
}
else {
$model->request_url = _xls_seo_url($model->title);
if (!$model->save())
Yii::app()->user->setFlash('error',print_r($model->getErrors(),true));
else
{
if (CUploadedFile::getInstance($model,'slider_image')) {
$model->slider_image->saveAs(Yii::app()->baseUrl.'images/'.$model->slider_image);
}
Yii::app()->user->setFlash('success',
Yii::t('admin','Custom page updated on {time}.',array('{time}'=>date("d F, Y h:i:sa"))));
$this->beforeAction('edit'); //In case we renamed one and we want to update menu
}
}
}
}
$this->render('edit',array('model'=>$model));
}
I attempted to die; after if (CUploadedFile::getInstance($model,'slider_image')) and nothing is happening, so it seems its not recognising it at all.
Thank you.
I think you're missing a minor directive in your view
Check to confirm that your form tag has the attribute "enctype"
i.e. <form action="" method="post" enctype="multipart/form-data">...</form>
TO set this in CActiveForm, do:
<?php $form = $this->widget('CActiveForm', array(
'htmlOptions'=>array('enctype'=>'multipart/form-data')
));?>
I'm adding dinamically textfields to a property in the model called names, but I like to set validation rules to every name in the array names in the view, Is this possible to do it unsing validation rules in the CForm Model?, for example I like to validate that every name will be required after clicking the Button.
This is the code of the view with a CActiveForm
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'test',
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
)); ?>
<p class="note">Campos <span class="required">*</span> son obligatorios.</p>
<div class="row">
<?php echo $form->labelEx($model,'Age'); ?>
<?php echo $form->textField($model,'age'); ?>
<?php echo $form->error($model,'age'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'Name'); ?>
<?php echo $form->passwordField($model,'names[0]'); ?>
<?php echo $form->error($model,'names[0]'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'Name'); ?>
<?php echo $form->passwordField($model,'names[1]'); ?>
<?php echo $form->error($model,'names[1]'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton('test'); ?>
</div>
<?php $this->endWidget(); ?>
You need to write a custom validator that assumes the attribute being validated is an array and applies the result of another validator to each of its elements.
I used this validator that does exactly the above as a starting point; after slightly cleaning up and simplifying as much as possible, I reached this code for server-side validation:
protected function validateAttribute($object, $attribute)
{
$value = $object->$attribute;
if (!is_array($value) ) {
$this->addError($object, $attribute, "TODO: error message");
return;
}
else if ($this->isEmpty($value)) {
if (!$this->allowEmpty) {
$this->addError($object, $attribute, "TODO: error message");
}
return;
}
// $this->validator and $this->parameters are supposed to be
// attributes of your custom validator class that you set from
// inside rules().
$validator = self::createValidator(
$this->validator,
$object,
array($attribute),
$this->parameters);
$errors = array();
// Iterate over $value, validating each item in turn.
// Since $validator may be a filtering validator, we need to make
// sure that any changes it makes to the validated item stick, so
// we iterate by reference and do a bit of back and forth shuffling.
foreach($value as $key => &$item) {
$object->$attribute = $item; // the only way
$validator->validateAttribute($object, $attribute);
$item = $object->$attribute; // make any changes stick
if ($object->hasErrors($attribute)) {
$errors[$key] = $object->gerErrors($attribute);
$object->clearErrors($attribute);
}
}
unset($item); // always a good idea after foreach by reference
$object->$attribute = $value; // undo the damage
// And now decide what to do with $errors, which is per-item.
// This should be good:
foreach ($errors as $key => $error) {
$object->addError("$attribute[$key]", $error);
}
}
OK, but what about client-side validation? It seems that this should be possible, but I have not tested it:
public function clientValidateAttribute($object,$attribute)
{
// Since this is copy/pasted from above, it's an obvious candidate
// for refactoring into a private method. I 'm keeping it simple.
$validator = self::createValidator(
$this->validator,
$object,
array($attribute),
$this->parameters);
$js = '';
// No need for filtering support here (I think...)
foreach($value as $key => $item) {
$object->$attribute = $item;
$js .= $validator->clientValidateAttribute($object, $attribute);
}
return $js;
}
First you need to specify the relation within the model.Like:
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
Then in the search function use that relation like:
$criteria->with=array('user');
And use that in your view like:
array(
'name'=>'username_search',
'value'=>'$data->user->username',
'header'=>'Posted By',
),
We have a actionSearchType in our User Controller as follows:
public function actionSearchType()
{
if (Yii::app()->user->isGuest == true)
$this->render('login');
else
$this->render('search_type');
}
Our actionLogin in our User Controller is as follows:
public function actionLogin()
{
$model= new Users();
// if it is ajax validation request
if(isset($_POST['ajax']))
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
$this->redirect(Yii::app()->user->returnUrl);
}
}
// display the login form
$this->render('login',array('model'=>$model));
}
The goal is to ensure that only authenticated users can execute the options on the search type view. When I run this page, I receive an error stating Undefined variable: model.
A snippet of the login view is as follows:
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login-form',
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<div class="row">
<?php echo $form->labelEx($model,'username'); ?>
<?php echo $form->textField($model,'username'); ?>
<?php echo $form->error($model,'username'); ?>
</div>
What steps must be taken to remedy the above error and properly check to ensure we have an authenticated user?
update
I changed actionSearchType to render the Login Widget per below:
public function actionSearchType()
{
if (Yii::app()->user->isGuest)
$this->widget('ext.LoginWidget');
else
$this->render('search_type');
}
This indeed resolved the error initially seen. A new problem is that there's no styling of the login widget when it renders. Should I echo my tags with appropriate stylesheet classes, or is there a bit more elegant way of doing that?
public function actionSearchType() {
if (Yii::app()->user->isGuest)
$this->redirect('/user/login');
$this->render('search_type');
}
Notes:
to do something when user is guest, simply use if(Yii::app()->user->isGuest) { statement }
to do something when user is logged in, simply use if(!Yii::app()->user->isGuest) { statement }
in the second code, public function actionLogin(), I think you have 2 more closing curly brackets than needed. Anyway, the login action should look like this:
public function actionLogin() {
$formModel = new Login_Form; // Login_Form.php should be in models folder
if (isset($_POST['Login_Form'])) {
$formModel->attributes = $_POST['Login_Form'];
if ($formModel->validate() && $formModel->login()) {
$this->redirect('/'); // replace / with stuff like Yii::app()->user->returnUrl
}
}
$this->render('login', array(
'formModel'=>$formModel,
));
}
Instead of rendering the view redirect to the user login page / action so you don't have to recreate it.
$this->redirect('login');
Somewhere in search_type you are referencing the variable $model which you do not hand over to the render() function. You need to define that variable otherwise the view will create an Exception.
I don't know which Model/Class your search_type view is expecting but you will need to initialize it before you hand it over to the view like this:
$this->render('search_type',array(
'model' => $model,
));
Here a good read about this topic: Understanding the view rendering flow