How addValidator works with Zend Form? - validation

I supposed the $form->addVlidator functions works as some front-end form checking thing, however when I add it, even the input is invalid, it seems the form is still being submited.
Or I was wrong, it's more a controller-side checking, which means the form will submit the data whatever then the server sides returns the error message?
My code works like this.
Form class:
<?php
class Application_Form_Test extends Zend_Form
{
public function init()
{
$this->setName('stdForm');
//$this->setMethod('post');
//$this->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'my-lovely-form'));
$this->setAttrib('enctype', 'multipart/form-data');
$this->setAction('somewhere')
->setMethod('post');
$username = $this->createElement('text', 'name', array('label' => 'Username:'));
$username->addValidator('alnum')
->addValidator('regex', false, array('/^[a-z]+/'))
->addValidator('stringLength', false, array(9, 20, 'messages'=>'Cannot be more than 9 chars'))
->setRequired(true)
->addFilter('StringToLower');
$email = $this->createElement('text', 'email', array('label' => 'E-mail'));
$email->addValidator('StringLength', false, array(8))
->setRequired(true);
$password = $this->createElement('password', 'pass1', array('label' => 'Password'));
$password->addValidator('StringLength', false, array(6))
->setRequired(true);
$password2 = $this->createElement('password', 'pass2', array('label' => 'Repeat password'));
$password2->addValidator('StringLength', false, array(6))
->setRequired(true);
$message = $this->createElement('textarea', 'message', array('label' => 'Message'));
$message->addValidator('StringLength', false, array(6))
->setRequired(true)
->setAttrib('COLS', '40')
->setAttrib('ROWS', '4');
$captcha = new Zend_Form_Element_Captcha('foo', array(
'label' => "human?",
'captcha' => 'Figlet',
'captchaOptions' => array(
'captcha' => 'Figlet',
'wordLen' => 6,
'timeout' => 300,
),
));
// Add elements to form:
$this->addElement($username)
->addElement($email)
->addElement($password)
->addElement($password2)
->addElement($message)
->addElement($captcha)
// use addElement() as a factory to create 'Login' button:
->addElement('submit', 'send', array('label' => 'Form sender'));
}
}
Controller code:
public function aboutAction()
{
$this ->_helper->layout->disableLayout();
$form = new Application_Form_Test();
$this->view->testForm = $form;
}
View file:
<?php echo $this->testForm;?>

The second: "the form will submit the data whatever then the server sides returns the error message". In order to do this you must call $form->isValid($this->_request->getPost()) in your action.
If it is not valid then you need to send data back to the user:
$form->populate($this->_request->getPost());
$this->view->form = $form;
For client side validation you can use http://docs.jquery.com/Plugins/Validation

Related

Ajax is not working in yii

In my Yii web application, any type of Ajax call like Ajax validation, Ajax for dependent dropdown etc.... Is not working.
My codes are,
In my form page:
<?php
$form = $this->beginWidget('CActiveForm', array(
'id' => 'workdetails-form',
'enableClientValidation' => true,
'clientOptions' => array(
'validateOnChange' => true,
'validateOnSubmit' => true,
),
// Please note: When you enable ajax validation, make sure the corresponding
// controller action is handling ajax validation correctly.
// There is a call to performAjaxValidation() commented in generated controller code.
// See class documentation of CActiveForm for details on this.
'enableAjaxValidation' => true,
'htmlOptions' => array('enctype' => 'multipart/form-data'),
));
?>
in controller:
public function actionCreate() {
$model = new Workdetails;
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($model);
if (isset($_POST['Workdetails'])) {
$model->attributes = $_POST['Workdetails'];
if ($model->validate()) {
if ($model->save()) {
$this->redirect(array('create'));
}
}
}
$this->render('create', array(
'model' => $model,
));
}
For dependant dropdown:
<div class="form-group col-sm-6">
<?php echo $form->label($model, 'designationid', array('class' => 'req')); ?>
<?php
$designation = CHtml::listData(Designation::model()->findAll(), 'designationid', 'designation_name');
echo $form->dropDownList($model, 'designationid', $designation, array(
'class' => 'form-control',
'prompt' => 'Please Select',
'ajax' => array(
'type' => 'POST',
'url' => $this->createUrl('workdetails/Fetchemployee'), // here for a specific item, there should be different URL
'update' => '#' . CHtml::activeId($model, 'employeeid'), // here for a specific item, there should be different update
'data'=>array('designationid'=>'js:this.value'),
)));
?>
<?php echo $form->error($model, 'designationid', array('class' => 'school_val_error')); ?>
</div>
How to solve this...
Please help me..
Arya I had the same problem with Yii1 and i gave up using yii-ajax validation cause i could not find a way to fix it. First make sure you have initialize/ register Yii-js file these are
yiiactiveform and yii.js
If you don't have these files on your project, it means you have not registered them. To register the core JS file proceed with this config in your main.
'clientScript' => array(
'scriptMap' => array(
'jquery.js' => true,
'jquery.min.js' => true,
),
),
or if that doesn't work use this on your main view in the header section.
Yii::app()->clientScript->registerCoreScript('jquery');
You can also add it to your base controller which is at components/Controller.php
public function init() {
parent::init();
Yii::app()->clientScript->registerCoreScript('jquery');
}
On your view have this when creating your forms. It will help in placing the error messages. to your elements
<?php
$form = $this->beginWidget('CActiveForm', array(
'id' => 'patient-registration-form',
'enableClientValidation' => True,
'enableAjaxValidation' => FALSE,
'clientOptions' => array(
'validateOnSubmit' => true,
'afterValidate' => 'js:function(form, data, hasError) {
if(hasError) {
for(var i in data) $("#"+i).parent().addClass("has-error");
return false;
}
else {
form.children().removeClass("has-error");
return true;
}
}',
'afterValidateAttribute' => 'js:function(form, attribute, data, hasError) {
if(hasError) $("#"+attribute.id).parent().addClass("has-error");
else $("#"+attribute.id).parent().removeClass("has-error");
$("#"+attribute.id).parent().addClass("has-success");
}'
),
'htmlOptions' => array(
'class' => 'form-horizontal form-bordered form-row-stripped',
),
));
?>
alternatively use Yii2 it has fixed alot of stufff and if you are loading the current page with ajax you need to render the the whole page including the js file again. since when you use renderPartial it doesn't initalize the js files hence no js scripts will work, including validation.

Returning user input after AJAX call in Drupal 7 hook_form_FORM_ID_alter

I am using the hook_form_FORM_ID_alter in Drupal 7 to create a custom form so that the user can enter and edit data which is then attached to a custom node type.
For a new node the default number of input boxes in a group is 10, this can then be added to in groups of 5. When the node is reloaded for editing the saved data is used to create the form with whatever number of inputs have been saved previously and also the ability to add more fields in the same manner as required.
I have managed to get both the initial version of the form and the editing version to work using the following code however when the 'add five' button is pressed and the AJAX called (in both cases), any values which have been entered without saving are removed.
<?php
/**
* Implements hook_form_FORM_ID_alter().
*/
function entries_form_form_entries_node_form_alter(&$form, &$form_state, $form_id) {
$node = $form['#node'];
// fieldset
$form["section"] = array(
'#type' => 'fieldset',
'#title'=> 'Section 1',
);
$form["section"]["termwrapper"] = array(
"#type" => 'container',
"#attributes" => array(
"id" => 'groupWrapper',
),
);
$form["section"]["termwrapper"]["terms"]["#tree"] = TRUE;
if(!isset($form_state['fired'])){
$form_state['terms'] = $node->entries_form['term'];
}
foreach ($form_state['terms'] as $key => $values) {
$form["section"]["termwrapper"]["terms"][$key] = array(
'#type' => 'textfield',
'#size' => 20,
'#attributes' => array(
'class' => array('left'),
),
'#value' => $values,
);
}
$form['section']['addFive_button'] = array(
'#type' => 'submit',
'#value' => t('+5'),
'#submit' => array('entries_form_add_five_submit'),
'#ajax' => array(
'callback' => 'entries_form_commands_add_callback',
'wrapper' => 'groupWrapper',
),
'#prefix' => "<div class='clear'></div>",
);
dpm($form_state);
}
function entries_form_commands_add_callback($form, $form_state) {
return $form["section"]["termwrapper"];
}
function entries_form_add_five_submit($form, &$form_state){
$form_state['rebuild'] = TRUE;
$form_state['fired'] = 1;
$values = $form_state['values'];
$form_state['terms'] = $values['terms'];
$numterms = count($values['terms']);
$addfivearray = array_fill($numterms,5,'');
$form_state['terms'] = array_merge($values['terms'],$addfivearray);
}
/**
* Implements hook_node_submit().
*/
function entries_form_node_submit($node, $form, &$form_state) {
$values = $form_state['values'];
$node->entries_form['term'] = $values['term'];
}
/**
* Implements hook_node_prepare().
*/
function entries_form_node_prepare($node) {
if (empty($node->entries_form)){
$node->entries_form['term'] = array_fill(0, 10, '');
}
}
/**
* Implements hook_node_load().
*/
function entries_form_node_load($nodes, $types) {
if($types[0] == 'entries'){
$result = db_query('SELECT * FROM {mytable} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)))->fetchAllAssoc('nid');
foreach ($nodes as &$node) {
$node->entries_form['term'] = json_decode($result[$node->nid]->term);
}
}
}
/**
* Implements hook_node_insert().
*/
function entries_form_node_insert($node) {
if (isset($node->entries_form)) {
db_insert('mytable')
->fields(array(
'nid' => $node->nid,
'term' => json_encode($node->entries_form['term']),
))
->execute();
}
}
How can I keep the values which have been typed in and retain the ajax functionality?
Any help or pointers much appreciated. This is my first dip into Drupal so I'm sure there is something which hopefully is quite obvious that I'm missing.
Ok, I think I finally have the answer.
Within the foreach that builds the form input boxes I had set '#value' => $values, when it seems that '#default_value' => $values, should have been set instead.
The updated section of the code that is now working for me is as follows
foreach ($form_state['terms'] as $key => $values) {
$form["section"]["termwrapper"]["terms"][$key] = array(
'#type' => 'textfield',
'#size' => 20,
'#attributes' => array(
'class' => array('left'),
),
'#default_value' => $values,
);
}
Seems to be as simple as that. Hope this helps someone else.

How to "print" a theme during AJAX request (Drupal)

When users click on a button (with id graph), I'd like to fill the default Drupal content div (<div class="content">) with a graphael instance.
The JavaScript:
jQuery(document).ready(function($) {
$('#toggle #graph').click(function() {
$.ajax({
url: "http://www.mysite.com/?q=publications/callback",
type: 'POST',
data: {
'format' : 'graph'
},
success: function(response) {
$('div#content div.content').html(response);
}
});
});
});
The PHP:
$items['publications/callback'] = array(
'type' => MENU_CALLBACK,
'title' => 'All Publications Callback',
'page callback' => '_process_publications',
'page arguments' => array(t('journal')),
'access callback' => TRUE,
);
which leads to the page callback: (I'm concerned with the if code block)
function _process_publications($venue) {
if( isset($_POST['format']) && $_POST['format'] == "graph" ){
_make_bar_chart($venue);
}
elseif( isset($_POST['format']) && $_POST['format'] == "list" ) {
_make_list($venue);
}
else{
return("<p>blah</p>");
}
}
and finally the function called within the callback function:
function _make_bar_chart($venue) {
// get active database connection
$mysql = Database::getConnection();
// if connection is successful, proceed
if($mysql){
// do stuff
$graphael = array(
'method' => 'bar',
'values' => $ycoordinates,
'params' => array(
'colors' => $colors,
'font' => '10px Arial, sans-serif',
'opts' => array(
'gutter' => '20%',
'type' => 'square',
),
'label' => array(
'values' => $xcoordinates,
'isBottom' => true,
),
),
'extend' => array(
'label' => array(
'values' => $ycoordinates,
'params' => array('attrText' => array(
'fill' => '#aaa',
'font' => '10px Arial, sans-serif',
)),
),
),
);
return theme('graphael', $graphael);
}
// else, connection was unsuccessful
else{
print("<p>bad connection</p>");
}
}
THE PROBLEM: returning a theme doesn't really send anything back to the AJAX request (unlike print statements). I tried to print the theme, but that produces a white screen of death. How would I generate the graph without printing something?
Much thanks to nevets on the Drupal forums for the helpful hint: http://drupal.org/node/1664798#comment-6177944
If you want to use AJAX with Drupal, you are best off actually using Drupal-specific AJAX-related functions. In my theme's page.tpl.php file, I added the following to make the links which would call AJAX:
<?php
// drupal_add_library is invoked automatically when a form element has the
// '#ajax' property, but since we are not rendering a form here, we have to
// do it ourselves.
drupal_add_library('system', 'drupal.ajax');
// The use-ajax class is special, so that the link will call without causing
// a page reload. Note the /nojs portion of the path - if javascript is
// enabled, this part will be stripped from the path before it is called.
$link1 = l(t('Graph'), 'ajax_link_callback/graph/nojs/', array('attributes' => array('class' => array('use-ajax'))));
$link2 = l(t('List'), 'ajax_link_callback/list/nojs/', array('attributes' => array('class' => array('use-ajax'))));
$link3 = l(t('Create Alert'), 'ajax_link_callback/alert/nojs/', array('attributes' => array('class' => array('use-ajax'))));
$output = "<span>$link1</span><span>$link2</span><span>$link3</span><div id='myDiv'></div>";
print $output;
?>
When one of the links above is clicked, the callback function is called (e.g. ajax_link_callback/graph):
// A menu callback is required when using ajax outside of the Form API.
$items['ajax_link_callback/graph'] = array(
'page callback' => 'ajax_link_response_graph',
'access callback' => 'user_access',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
.. and the callback to which it refers:
function ajax_link_response_graph($type = 'ajax') {
if ($type == 'ajax') {
$output = _make_bar_chart('journal');
$commands = array();
// See ajax_example_advanced.inc for more details on the available commands
// and how to use them.
$commands[] = ajax_command_html('div#content div.content', $output);
$page = array('#type' => 'ajax', '#commands' => $commands);
ajax_deliver($page);
}
else {
$output = t("This is some content delivered via a page load.");
return $output;
}
}
This replaces any HTML within <div class="content"> with the graphael chart returned from _make_bar_chart above.

CakePHP "Agree TOS" Checkbox Validation

I am trying to have a Checkbox "Agree TOS".
If the Checkbox is not checked, I want to put out a Flash Message.
How do I do this?
My View:
<?php
echo $form->create('Item', array('url' => array_merge(array('action' => 'find'), $this->params['pass'])));
echo $form->input('Search', array('div' => false));
echo $form->submit(__('Search', true), array('div' => false));
echo $form->checkbox('tos', array('label' => false, 'value'=>1)).' Agree TOS';
echo $form->error('tos');
echo $form->end();
?>
My Model:
var $check = array(
'tos' => array(
'rule' => array('comparison', 'equal to', 1),
'required' => true,
'allowEmpty' => false,
'on' => 'index',
'message' => 'You have to agree TOS'
));
This seems working for me. Hope it will help.
In model:
'tos' => array(
'notEmpty' => array(
'rule' => array('comparison', '!=', 0),
'required' => true,
'message' => 'Please check this box if you want to proceed.'
)
In view:
<?php echo $this->Form->input('tos', array('type'=>'checkbox', 'label'=>__('I confirm I have read the privacy statement.', true), 'hiddenField' => false, 'value' => '0')); ?>
Model
'agreed' => array(
'notempty' => array(
'rule' => array('comparison', '!=', 0),//'checkAgree',
'message' => ''You have to agree TOS'',
'allowEmpty' => false,
'required' => true,
'last' => true, // Stop validation after this rule
'on' => 'signup', // Limit validation to 'create' or 'update' operations
),
),
View
<?php echo $this->Form->input('agreed',array('value'=>'0'),array('type'=>'checkbox', 'label'=>'Agree to TOS')); ?>
basically, you add the rule "notEmpty" for this field to the public $validate array of the model.
this way an error will get triggered on Model->validates() if the checkbox has not been checked.
maybe some overhead in your case, but if you happen to use it more often try a DRY (dont repeat yourself) approach. you can also use a behavior for this to use this clean and without tempering too much with the model/controller:
// view form
echo $this->Form->input('confirmation', array('type'=>'checkbox', 'label'=>__('Yes, I actually read it', true)));
and in the controller action
// if posted
$this->Model->Behaviors->attach(array('Tools.Confirmable'=>array('field'=>'confirmation', 'message'=>'My custom message')));
$this->Model->set($this->data);
if ($this->Model->validates()) {
// OK
} else {
// Error flash message here
}
1.x:
https://github.com/dereuromark/tools/blob/1.3/models/behaviors/confirmable.php
for 2.x:
https://github.com/dereuromark/cakephp-tools/blob/2.x/Model/Behavior/ConfirmableBehavior.php
3.x: https://github.com/dereuromark/cakephp-tools/blob/master/src/Model/Behavior/ConfirmableBehavior.php
details:
http://www.dereuromark.de/2011/07/05/introducing-two-cakephp-behaviors/
I believe you need try save it into your model to catch your tos rules. I should do something like =
if(!$mymodel->save()){
// catch error tos.
}
$this->ModelName->invalidFields() returns an array of fields that failed validation.
You could try and search this for the tos field, and output a message if the key exists.
~untested (I'm not sure off the top of my head the exact structure of the invalidFields return array.
$failed_fields = $this->ModelName->invalidFields();
if(array_key_exists('tos', $failed_fields)) {
$this->Session->setFlash('Please accept the terms and conditions');
}
you don't even have to have validation rule for tos, just check that at the controller before saving the data.
if($this->data['Model']['tos']==1){
// save data
}else{
//set flash
}

Why aren't validation errors being displayed in CakePHP?

I'm trying to perform validation in the login page for the name,email and password fields. If the input fails validation,the error message should be displayed.
But here,when I fill in the details and submit, it is redirected to the next page. Only the value is not saved in the database.
Why is the message not displayed?
This is my model:
class User extends AppModel {
var $name = 'User';
var $validate = array(
'name' => array(
'alphaNumeric' => array(
'rule' => 'alphaNumeric',
'required' => true,
'message' => 'Alphabets and numbers only'
),
'between' => array(
'rule' => array('between', 5, 15),
'message' => 'Between 5 to 15 characters'
)
),
'password' => array(
'rule' => array('minLength', '8'),
'message' => 'Mimimum 8 characters long'
),
'email_id' => 'email'
);
function loginUser($data) {
$this->data['User']['email_id'] = $data['User']['email_id'];
$this->data['User']['password'] = $data['User']['password'];
$login = $this->find('all');
foreach ($login as $form):
if ($this->data['User']['email_id'] == $form['User']['email_id'] && $this->data['User']['password'] == $form['User']['password']) {
$this->data['User']['id'] = $this->find('all',
array(
'fields' => array('User.id'),
'conditions' => array(
'User.email_id' => $this->data['User']['email_id'],
'User.password'=>$this->data['User']['password']
)
)
);
$userId=$this->data['User']['id'][0]['User']['id'];
return $userId;
}
endforeach;
}
function registerUser($data) {
if (!empty($data)) {
$this->data['User']['name'] = $data['User']['name'];
$this->data['User']['email_id'] = $data['User']['email_id'];
$this->data['User']['password'] = $data['User']['password'];
if($this->save($this->data)) {
$this->data['User']['id']= $this->find('all', array(
'fields' => array('User.id'),
'order' => 'User.id DESC'
));
$userId=$this->data['User']['id'][0]['User']['id'];
return $userId;
}
}
}
}
This is my controller:
class UsersController extends AppController {
var $name = 'Users';
var $uses=array('Form','User','Attribute','Result');
var $helpers=array('Html','Ajax','Javascript','Form');
function login() {
$userId = $this->User->loginUser($this->data);
if($userId>0) {
$this->Session->setFlash('Login Successful.');
$this->redirect('/forms/homepage/'.$userId);
break;
} else {
$this->flash('Login Unsuccessful.','/forms');
}
}
function register() {
$userId=$this->User->registerUser($this->data);
$this->Session->setFlash('You have been registered.');
$this->redirect('/forms/homepage/'.$userId);
}
}
EDIT
Why is the message,example,"Minimum 8 characters long", is not being displayed when give less than 8 characters in the password field?
<!--My view file File: /app/views/forms/index.ctp -->
<?php
echo $javascript->link('prototype.js');
echo $javascript->link('scriptaculous.js');
echo $html->css('main.css');
?>
<div id="appTitle">
<h2> formBuildr </h2>
</div>
<div id="register">
<h3>Register</h3>
<?php
echo $form->create('User',array('action'=>'register'));
echo $form->input('User.name');
echo $form->error('User.name','Name not found');
echo $form->input('User.email_id');
echo $form->error('User.email_id','Email does not match');
echo $form->input('User.password');
echo $form->end('Register');
?>
</div>
<div id="login">
<h3>Login</h3>
<?php
echo $form->create('User',array('action'=>'login'));
echo $form->input('User.email_id');
echo $form->input('User.password');
echo $form->end('Login');
?>
</div>
Your validation seems correct
How about trying the following:
Make sure set your $form->create to the appropriate function
Make sure there is no $this->Model->read() before issuing Model->save();
Edit
Did you have the following?:
function register()
{
//do not put any $this->User->read or find() here or before saving pls.
if ($this->User->save($this->data))
{
//...
}
}
Edit2
IF you're doing a read() or find() before saving the Model then that will reset the fields. You should be passing the variable as type=hidden in the form. I hope i am making sense.
Edit3
I think you need to move your registerUser() into your controller because having that function in the model doesn't provide you a false return. it's always going to be true even if it has validation errors.
Comment out the redirect line and set the debug to 2 in config/core.php. Then look at the sql that is being generated to see if your insert is working. If the errors are not being displayed, maybe in the view, you are using $form->text or $form->select instead of the $form->input functions. Only the $form->input functions will automatically display the error messages.

Resources