Show only one error in Zend form validation - php

I'm looking to set a single error message for a form, but still validate each field.
The form is a survey with 10 questions. Each of them validates the same way (->setRequired(true)). So basically, I just to validate that each questions has an answer and display one message at the top of the form if one of them is not answered.
I've tried several solutions and gotten the same result. My error is added to the form, but also, all of the individual errors show as well.
This is my latest shot at it:
public function isValid($data)
{
$errors = 0;
parent::isValid($data);
foreach ($this->getElements() as $element) {
if ($element->hasErrors()) {
$element->clearErrorMessages();
$element->setErrors(array());
$errors++;
}
}
if (count($errors) > 0) {
$this->setErrorMessages(array('Please answer all questions before proceeding.'));
return false;
}
return true;
}
Can anyone shed some light on why this isn't working as I'd expect? There has to be a more elegant way of doing this.
EDIT:
This is what I ended up with. Probably a little different than most since my form elements are dynamically populated based on an array of questions, but the general idea should apply. Normally, you could just count the number of radio elements, but in my case, rather than looping through the elements and checking the type, it was just easier to count my array of questions.
public function isValid($data)
{
$valid_values = 0;
parent::isValid($data);
foreach ($this->getValues() as $value) {
if ($value >= 1 && $value <= 10) {
$valid_values++;
}
}
if ($valid_values <> count($this->_questions)) {
$this->setErrorMessages(array('Please answer all questions before proceeding.'));
return false;
}
return true;
}
Still not sure this is the most elegant way, but it works for my particular case.

The way I see it, if you really have only that one validator one each field, why don't manage that in the controller, instead of overriding isValid ?
if ($form->isValid($_POST))
{ /* success */ }
else
{ /* error as at least one field is missing */ }

You can remove the error elements by removing the 'Error' decorator from the form elements while creating it. This will validate all the elements but will not produce any error messages. But you have to cannot show errors in the form element. You have to find someother way to feedback the errors.

You could remove the Error decorator from each element (so those errors don't display). Then add a custom decorator to the form (!) that checks $form->isValid() (though in the decorator itself, it will be $this->getElement()->isValid(); kind of confusing that getElement() returns the entity to which the decorator is attached) and then renders your single message (probably above your form, using default placement PREPEND).
It sounds like you have the second part handled (rendering your single message at the form-level), so simply removing the Error decorator from the elements themselves should do the job for you.

Related

CakePHP 3 - How to automatically show form errors for multiple new entities?

I'm trying to leverage any automatic handling of validation and displaying errors for a form using multiple entities.
The user can dynamically create multiple new entities via the form UI. The data is marshalled through newEntities():
$this->MyModel->newEntities($data);
The first part of the problem I have is that in order to check if validation failed on any of the entities, I have to do it manually by checking every entity:
$errors = false;
foreach ($entities as $entity) {
if ($entity->errors()) {
$errors = true;
break;
}
}
if (!$errors) {
// Save...
Does Cake provide anything out of the box which allows you to check if newEntities() failed validation on any of its entities? If not, then never mind...
The main problem is how I get the errors from the individual entities to then show inline in my form next to the relevant inputs.
<?= $this->Form->create(); ?>
What can I pass to create() to link it to the entities? At the moment there doesn't seem to be any way for it to know what happens once the form is submitted, and therefore doesn't show errors.
My form inputs are created using the standard array notation, where $i comes from the loop building the form inputs from all the entities.
$this->Form->hidden("MyModel.$i.field");
simply pass the array of entities to your form
$this->Form->create($entities);
also you don't have to specify the model name in the input name. Simply
$this->Form->hidden("$i.field");
and not
$this->Form->hidden("MyModel.$i.field");
Use newEntity and add those to an array. Loop over that array accessing errors().
$array = [];
$array[] = $TableRegistry->newEntity([
'hi' => 'hey'
]);
foreach($array as $r){
var_dump($r->errors());
}
Hopefully that works with your use-case. I've never used newEntities, but you may be able to iterate over that as well?

Required dynamic Zend_Form_Element_Multiselect

I've got a <select multiple> populated on start up with some values, but where additional options are added via Javascript. However I'd like now to validate this element, that at least one of the options within has been selected.
I'm using Zend_Form_Element_Multiselect to perform the validation:
$tags = new Zend_Form_Element_Multiselect('cms_tags');
$tags->setRegisterInArrayValidator(false)->setRequired(true);
However, of course, this is not working. How can I do something as simple as checking for not emptiness of the cms_tags array without resorting to overloading isValid function?
PS. Validate_Not_Empty is not working as well.
Fortunately, the solution to my question is my code. Unfortunately, Zend, at least to me, has a bug - the problem with my data was an empty value that appeared at the end of the values array, so cms_tags[]=5, cms_tags[]= was considered invalid for this kind of validator. If this a valid behavior, or not, I'll leave it to Zend folks, but this at least answers my issues.
Try something like this:
public function isValid($data) {
$etat_valid = parent::isValid($data);
if(isset($data['cms_tags'])){
// Add your validators
// for example:
if("" == $data['cms_tags']){
$this->getElement('cms_tags')->addErrors(array('This value is required and can not be empty'));
$etat_valid = false;
}
}
return $etat_valid;
}

How should i handle errors in my Codeigniter Models?

i am starting to put validation/sanitization in my codeigniter models, and before diving in too deep I am looking for some suggestions on best practices. the form validation library for controllers is great, but obviously i don't want to rely on the controllers to send me good data.
currently I return bool values, TRUE (or data) on success, FALSE on failure, which makes it really hard to pass error messages back to the caller. I would like to get away from the FALSE on failure.
while definitely not an expert, i have started reading quite a bit on Exceptions and have come across them quite a bit with external libraries, and they seem like a good candidate for this. my question is, is this appropriate use of exceptions? are model errors exceptional errors?
a possible example:
<?php
class person_model extends CI_Model{
public function getPersonById($personId){
//check for int
if(!is_int($personId) OR $personId < 0){
throw new Exception('Invalid person ID');
}
//setup query
$this->db->select('*')
->where('personId', $personId);
//run query
$result = $this->db->get('person');
//failed to get
if(!$result){
throw new Exception('DB query failed');
//should i also return false?
return FALSE;
}
//got info
else{
return $result;
}
}
}
?>
thanks for the help!
EDIT:
I have to say I am quite surprised by the responses suggesting that data validation should only be done in the controller. Models are the last barrier to your data storage. The model is the data and the rules applying to that data, your application logic. Data validation seems like application logic to me. Also you may have many controllers accessing the same model method. Do you want to rely on both controllers implementing the same validation? That seems silly to me.
Also, not all data is coming from user input, some of it could be hardcoded into the script by your programmer writing the controller. What if they pass a string when your model is expecting an integer? Or pass an incorrectly formatted date? shouldn't the model say something about that.
I'm open to a discussion, but I feel data validation DEFINITELY belongs in the model. (in addition to the controller, and even the view (html5/javascript for convenience))
the easiest way i've found to deal with this is to always check for the negative condition first with an if check. this also makes it easy to check multiple steps.
always return something back from your model methods whenever possible. Like even in this example - we need to validate the form - i would use codeigniters form validation to validate that its an integer etc. if it passes validation then we need the $personId for the database search. So instead of just returning true/false from the validation - if validation passes then return the $personId :
function getperson() {
// Validate the form
// AND if its valid, return the validated $personId
// Note the separate private method if the validation failed
if ( ! $personId = $this->person->_validateGetPersonForm() ) {
$this->error_msg = 'Error in validating the form. Please use a number.';
$this->_showGetPersonFailed() ; }
elseif ( ! $person = $this->person->getBy($personId) ) {
$this->error_msg = 'There is no person in our records with the number:'. $personId;
$this->_showGetPersonFailed() ; }
else { $this->_showResultsFor($person) ; }
}
$this->error_msg is automatically available for any of your views and because we have broken out validation and the database search - the error message is easily appropriate for the exact condition. if the search failed then there is a private method _showGetPersonFailed() to show the form again. the last if / else is usually success - there is a separate private method to handle showing the results with the appropriate views.
also suggest not using the word "model" in the file name like "person_model". it just clutters up the overall naming and forces you to type the word model over and over again :-) think of it this way: if you are calling something from a controller and getting back results - its almost always going to be a model. and all your model files will always be in a folder named models.
Go to:
application/config/database.php
and search for db_debug to be TRUE. For example:
...
$db['default']['dbprefix'] = '';
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE; //<-- Have this to true
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = '';
...
In my models, I never throw exceptions or errors. I always return false on a query that returns null. If there is an SQL error in your code you will be notified by codeigniter automatically. I would stay away from throwing exceptions if your query returns no results.
You can then handle the query if it returns false with your controller.
EDIT: Also you should check the data being queried into the database in the controller, and not the model. In my opinion the model should be used strictly for querying data, not for error/data checking, you can do this before hand in the controller when it is submitted.
An example:
Model
function search_replies($term){
$this->db->like('ticket_id', $term);
$this->db->or_like('reply_from', $term);
$this->db->or_like('reply_from_name', $term);
$this->db->or_like('reply_content', $term);
$query = $this->db->get($this->table_ticket_replies);
// Returns the result if the number of rows is greater than 0, returns false otherwise
if ($query->num_rows() > 0) return $query->result();
return false;
}
Controller
function example_controller(){
if($this->search_model->search_replies('Test')){
$data['results'] = $this->search_model->search_replies('Test');
}
$this->load->view('search_results', $data);
}
View
<?php
if(isset($results)){
echo 'Retrieved Results';
foreach($results as $result){
}
} else{
?>
<h2>No results for search term!</h2>
<?php
}
?>
You have probably missed out this part of the form validation page in the user guide:
Showing Errors Individually
Usage:
echo form_error('field_name');
Just put in whatever field name you are using in place of "field_name", for example "username" or "email" etc.

Procedural PHP to where?

All of the code in my project is procedural. It isn't using any framework, or any MVC structure. Most of the PHP is form handlers with some logic. So lots of code like this:
<?php
require "headerFile.php";
$user = array(); // filled with user data
if (isset($_POST['submitButton'])) {
if (isset($_POST['money'])) {
if (is_numeric($_POST['money'])) { // I don't actually validate numbers this way
if ($_POST['money'] <= $user['money']) {
$query = mysql_query("SELECT * FROM someTable WHERE id={$user['id']}");
if($result = mysql_fetch_array($query)) {
if ($someOtherCheck == $user['someOtherData']) {
/*
* run some queries, give user some item
*
*/
} else {
echo "This isn't right.";
}
} else {
echo "You don't have a row in some table!";
}
} else {
echo "You don't have that much money!";
}
} else {
echo "Enter a valid number";
}
} else {
echo "Enter how much you want to wager.";
}
}
// some hard coded form goes here
require "footerFile.php";
?>
There are over a hundred of these forms and nested if handlers, some that are similar with more/fewer conditions.
I want to start using OOP and I've been reading up on design patterns but I can't seem to find anything that applicable to my project.
I'm adding loads of new blocks of code similar to the block above, I don't want to copy and paste and just change a couple of bits here and there, what are my options?
First off, if you are ever copying and pasting code that should be a BIG RED FLAG. This should be a warning that instead of copying and pasting, you need to write a generalized function that can be used.
Secondly, it's really time to stop using mysql_query-like functions. Even the PHP page says use of those functions is discouraged. I would start moving your SQL over to PDO which is more OO-like.
When I inherited an application that looked the code you posted, I wrote a blog post about the steps I took to start getting a handle on things. It may also be helpful to you - http://mattmccormick.ca/2011/10/13/how-to-refactor-a-php-application/
OOP is not always about application. It is about readability and structure. Honestly, how readable is the code you have posted here? There are a ton of things happening and it would take you 10 minutes to decipher them all. However, if you break it down into classes with class functions you would be able to glance at things and know what is going on.
OOP does not do a ton for php all the time, but its something you want to do for almost all other non-static load languages. With the added benefit that if you have more than one programmer on a project you can both read the code. Comments are you friend.
You're best option is to use functions with returns. Return the value and then the function does whatever it needs to do with it. I personally would do something like
$class->check
if error
$this->error_handler
and the function error handler does whatever you want it to do with the error, if its die or echo then do that, but you build the error handler, so if you ever want to change it, you chance it in one place instead of 20.
Even without bringing in OOP, you could do wonders for structuring your code to be readable. There's no need to nest your conditionals if they're not dependent on each other.
$form_is_valid = true;
if (!isset($_POST['submitButton'])) {
echo "This isn't right.";
$form_is_valid = false;
}
if (!isset($_POST['money'])) {
echo "Enter how much you want to wager.";
$form_is_valid = false;
} elseif (!is_numeric($_POST['money'])) {
echo "Enter a valid number";
$form_is_valid = false;
} elseif (!$_POST['money'] <= $user['money']) {
echo "You don't have that much money!";
$form_is_valid = false;
}
if ($form_is_valid) {
do_stuff_here();
}
Regarding Frameworks
A decent framework will help you on your way to organizing code better trough separation of concerns, but does not necessarily enforce best practices. Subjectively, I say it takes hands-on experience and making lots of mistakes before best practices are ingrained in your head.
Try to think of a framework as a delivery mechanism only. Optimally, your code is not tied to any one framework. This generally means using components to handle different aspects of your application such as routing, validation, config, events, dependencies, etc.
Regarding OOP
Something I feel you should start with would be the SOLID principle. This will help you, although not guarantee, avoid making mistakes that cost you a lot of time down the road.
Foremost, your objects should only have a single responsibility. e.g. a Product object should not be responsible for acting as a data store, persisting itself, handling an order, etc etc.
Also another biggy would be dependency injection. This is huge for unit testing your classes (which you should get in the habit of doing). In a nutshell, do not construct dependency within a class. Construct it beforehand and pass it in through either a constructor argument or a setter method.
The process of architecting an application merits having its own books, so I'm not going to attempt writing it all here. If you follow the SOLID principle though, you will be well on your way to being a better developer.
Regarding your code above
That kind of nesting is generally a smell, and I can see why you are asking the question...
Step 1 would be to separate the validation in to its own service. Thinking of this in a MVC sense, at the least, your controller would only have [pseudocode] if ($form->isValid()) { do something }. This alone eliminates the bulk of spaghetti you have.
I want to start using OOP and I've been reading up on design patterns but I can't seem to find anything that applicable to my project.
You don't have to start with patterns yet .. understand the basics and you can progress form there ..
This is a basic example
if (isset($_POST['submitButton'])) {
$db = new \mysqli("localhost", "user", "pass", "db");
$user = new User("Juddling Stack", 123456);
$user->setMoney(500.01);
$player = new PlayerRegister($db, $user);
if (! isset($_POST['money']) || ! is_numeric($_POST['money']))
$player->addError("Enter Valid Wager Money");
if ($_POST['money'] <= $user['money']) {
$player->addError("You don't have that much money!");
}
try {
$player->doSQL();
} catch ( BaseException $e ) {
foreach ( $e->getError() as $error ) {
echo $error, " <br />";
}
}
}
Classes Used
It looks like your code is combining certain components of both the model and view layers. You're running queries against a database, and in the same place, you're including hard coded forms. So, a good place for you to start would be to split these tasks up into two separate classes. For example, write a class to connect to your database and run queries against it, and another class to actually serve your content.
My advice on Design patterns is to not get too bogged down in the details. Instead, try to understand why certain patterns are so helpful, and what problems they are trying to solve. A lot of beginners get too bogged down in the how , and they end up wasting so much time learning the nuances of a framework when a simple solution would have sufficed.
Finally, as you read through your code, keep an eye out for things that could potentially be structured into a class. Also, remember that specialization is key, and by building classes that are very specialized in what they do, you are building modular components that could potentially be used in other projects,
Let's start by stating the problem you are having which is not not using OOP, but called programming-overhead or in programmer terms spaghetti-code.
If you experience a lot of overhead, meaning time wasted writing almost the exact same line of code, where only it's content is different, but the functionality is the same. Then start slicing every peace of code that's the same from it's function, but differentiate its content.
You stated there is more to be copied pasted, and even more complex, I'll just do the form validation part (something I called stage 1), which is just one simple example of how to apply logic that does all the work for you by feeding input it expects. One example might be more elegant than others.
all code below is not tested
An example for locating code of equal functionality.
// functionality on checking values is the same, but it's content is not
if (isset($_POST['submitButton'])) {
if (isset($_POST['money'])) {
if (is_numeric($_POST['money'])) {
and
// though every decision made by its content is only being produced once ..
} else
echo "You don't have that much money!";
} else
echo "Enter a valid number";
} else
echo "Enter how much you want to wager.";
Now the trick is to find a solution to logically solve this. PHP is full of build-in functions, but first grasp the idea on how to solve it. An example would be to have each key, like submitButton, money have a value that would equal to not exists if not set/present, let's say null. Second, you are comparing values with a key supplied by the $_POST, so no matter what.. your $_POST array is the decision maker.
A keen example can be seen on how the jQuery library has been build using the $.extend() method to apply default values to keys, so that a key always has a value and always a decision to make by not checking first if it exists. But so can PHP.
Let's default the values.
$_POST = array_merge(array(
'submitButton' => null,
'money' => 0,
'etc' => '...'
, $_POST);
Building a function to validate this array is a lot easier now, because you can always depend on a value being present.
You stated you have many more forms that need validation, a function that would validate certain fields would be next to figure out.
A formal representation of a valid or invalid form could be an array, e.g.
$valid_form = array(
'submitButton' => array('not_null'),
'money' => array('not_null','int'),
'etc' => '...'
);
A function to validate would be
function validateForm($values, $valid) {
// error array to be returned
$error = array();
// let's iterate over each value, remember we defaulted the $_POST array with
// all the fields it can have, so all fields should be iterated apon.
foreach($values as $key => $value) {
if(array_key_exist($key, $valid)) {
// logic content can be used by different functions, switch
// used here for simplicity
foreach($valid[$key] as $validation) {
switch($validation) {
case 'not_null':
if(is_null($value)) {
$error[] = "error logic";
continue; // skip rest
}
break;
case 'etc':
$error[] = "..";
break;
}
}
}
}
return $error ? $error : true; // true being valid
}
The error handling can be done in a lot of ways, just one simple example (depends on how extensive this project is going to be), you could bind the error content to the validation key, e.g.
$vfe = $valid_form_errors = array( // $vfe for simlicity's sake
'__no_error' => 'no error present for "%key%" validation',
'not_null' => '%key% should not be null',
'int' => '%key% expects to be an integer'
);
$valid_form = array(
'submitButton' => array('not_null'),
'money' => array('not_null','int'),
'etc' => '...'
);
A function to create a formal error message
function error_msg($key, $validation) {
global $vfe;
// error exists?
$eE = array_key_exists($validation,$vfe);
return str_replace('%key%', $eE?$key:$validation, $vfe[$eE?$validation:'__no_error']);
}
And in the simple switch, the error logic is
foreach($valid[$key] as $validation) {
switch($validation) {
case 'not_null':
if(is_null($value))
$error[] = error_msg($key, $validation);
break;
case 'etc':
$error[] = "..";
break;
}
}
So how would your code look like using a different logic?
// first stage ..
$form_valid = validateForm($_POST, $valid_form);
if ($form_valid === true) {
// second stage, same logic be applied as with validateForm, etc.
if($_POST['money'] <= $user['money']) {
$query = mysql_query("SELECT * FROM someTable WHERE id={$user['id']}");
if($result = mysql_fetch_array($query)) {
// third stage, same logic can be applied here..
if ($someOtherCheck == $user['someOtherData']) {
} else {
echo "This isn't right.";
}
} else {
echo "You don't have a row in some table!";
}
}
else {
$errors = $form_valid;
// error handling here
print_r($errors);
}
It all comes to how specific you can define values being expected. You can extend every function to more specific, like binding the errors to a form key so you can specifically target that input at a later stage. They key thing is to erase all possible duplication where a function might do all this for you by simply asking him to compare values you expect, and let him tell which value there actually are.

Show password validation errors of a Zend Form on other action

in all the examples I find of Zend_Form the view showing the form corresponds to the action in which it is processed. However, I want a view that displays multiple independent forms and separate actions to process each of the forms (whose view is not used).
Redirect to individual actions is not a problem, the forms are processed there but when validation errors appears, I want them displayed on the common view next to each item, Zend_Form style. As I understand, when a form is populated (with invalid data) errors are displayed automatically. Then, when a form is invalid, I use FlashMessenger to store the invalid content, then redirected to the main common action and populate the form with him.
The problem arises with the password fields. These, of course, refuse to be populated, and therefore do not show any error message. Could I display it without having to manually figure out which error occurred?
Thank you for your attention and your patience with my english :P
PS: For better understanding i append a sample code explaining what I do...
class TestController extends Zend_Controller_Action
{
...
public function commonAction() {
/*Initialize form objects*/
$form1 = new Application_Form_Form1();
...
$formN = new Application_Form_FormN();
/*Fill forms if needed*/
$flashMess = $this->_helper->FlashMessenger;
if ($flashMess->hasMessages()) {
$messages = $flashMess->getMessages();
switch ($messages[1]) {
case 'form1':
$form1->populate($messages[0]);
break;
...
case 'formN':
$fotmN->populate($messages[0]);
break;
default:
...
break;
}
}
/*Assign to the view*/
$this->view->form1 = $form1;
...
$this->view->formN = $formN;
}
public function form1Action() {
if ($this->getRequest()->isPost()) {
$form1 = new Application_Form_Form1();
$data = $this->getRequest()->getPost();
if ($form1->isValid($data)) {
...
} else {
$this->_helper->FlashMessenger($data);
$this->_helper->FlashMessenger('form1');
}
}
$this->redirect('/test/common');
}
...
}
As I understand, when a form is populated (with invalid data) errors
are displayed automatically.
This is not the case, if you populate the form with invalid values, you will have to call isValid again in order to run the validators and mark the form and elements with the appropriate error messages.
You could also save the error messages for each element in the FlashMessenger and then re-attach the error messages back to each element, but you can also call isValid again. If you ever used a form with a File element, you would have to save the error message as you would not be able to re-populate the element with the uploaded file.
The problem arises with the password fields. These, of course, refuse
to be populated.
If you set the renderPassword flag (ex: $el->setRenderPassword()) on each password field, they will populate along with the rest of the values and when you call isValid, the password field will be validated and any appropriate error message would show up.
Hope that helps.

Categories