Asked  8 Months ago    Answers:  5   Viewed   34 times

I am working on a PHP project which makes extensive use of the MVC design pattern. I am looking to add validation to a form and am curious as to what the right place for validation is.

Due to the way that forms are generated, validation on postback data is a lot simpler and less repetitive in view components. Is it acceptable to have the view validating response data, or should this be implemented within the controller, or even the model?

What are the benefits?

 Answers

90

If you're validating the data on client side (i.e Javascript validation) which is absolutely not enough and not secure at all, You should implement it in View.

If you're validating data on server side, And your validation does not require application business logic (i.e you're not checking to see if the user has enough credit in his account), You should validate in the controller.

If the validation requires business logic, Implement it inside the model and call it via controller.

Postback validation is not good since it puts lots of pressure and delay, And the only advantage is to the programmer (not to be accounted).

You can use regex for most of validation, Which has the same syntax (almost) on PHP and JS.

Wednesday, March 31, 2021
 
Akdeniz
answered 8 Months ago
46

Ok I'm just gonna start by saying I'm no expert in PHP and I recommend using a framework such as symphony to do your routing, but here is one possible solution that you could use.

function regexPath($path)
{
    return '#' . str_replace([":int:", ":string:"], ["d+", ".+"], $path) . '#';
}

function parseRequestedView($url)
{
    $ressource_requested = explode('/', trim($url, '/'));


    // define our routes, and the indices that each route will use (from the exploded url)
    // this could be defined as another parameter or as a member of the class
    $routes = [
        regexPath("article/:int:/comments/show") => [0,  2, 3,  1], // will return array(resource[0], resource[2], resource[3], resource[1]), etc
        regexPath("article/:int:/show")          => [0, -1, 2,  1], // -1 will return a null
        regexPath("archive/show")                => [0, -1, 1, -1]
    ];


    // go through each route, checking to see if we have a match
    foreach ($routes as $regex => $indices)
    {
        if (preg_match($regex, $url))
        {
            // it matched, so go over the index's provided and put that data into our route array to be returned
            foreach ($indices as $index)
            {
                $route[] = $index > -1 ? $ressource_requested[$index] : null;
            }

            // include the post data (not really nessesary)
            $route[] = $_POST; // unnessesary to pass $_POST data through function, because it is global

            return $route;
        }
    }

    return null; // or some default route maybe?
}

$route = parseRequestedView("article/13/comments/show");

echo '<pre>';
print_r($route);
echo '</pre>';

/* returns:
Array
(
    [0] => article
    [1] => comments
    [2] => show
    [3] => 13
    [4] => Array // this is our $_POST data
        (
        )

)
*/
Wednesday, March 31, 2021
 
PLPeeters
answered 8 Months ago
99

I would suggest moving the validation logic to your model or formModel thus keeping your controller thin/skinny.

Example:

A generic form model

abstract class FormModel 
{ 

protected $_errors = array();

//add an error for an attribute if the validation fails
public function addError($attribute, $error) { 
  $this->_errors[$attribute] = $error;
}

//get the error for an attribute
public function getError($attribute) { 
  return (isset($this->_errors[$attribute])) ? $this->_errors[$attribute] : '';
}
//get all errors for all attributes
public function getErrors() {
     return $this->_errors;       
 }

public abstract function load($data);
public abstract function validate();

}

Now for your user formModel you could to do something like:

class UserFormModel extends FormModel 
{
   public $firstName;
   public $lastName;
   public $email;
   public $password;

   public function load($data) {
      //you could use the filter_var function to read the values form the $data array. this is just an example
      $this->firstName = $data['reg-form-first-name'];
      $this->lastName = $data['reg-form-last-name'];
      $this->email = $data['reg-form-email'];
      $this->password = $data['reg-form-password'];
   }

   //this is where your form validation logic goes
   //return true if all fields are valid or false if a validation fails
   public function validate() {

       //for example
       if(empty($this->firstName)) { 
         $this->addError('firstName', 'Your first name is required');
         return false;
       }
       return true;
   }
}

Now in your controller you could do something like:

class RegistrationController extends Controller {

public function __construct($data = array()) {
    parent::__construct($data);
}

public function index() {
    // form fields are correctly filled in

    if($_SERVER['REQUEST_METHOD'] == 'POST') {

        $formModel = new UserFormModel();
        $formModel->load($_POST); 
        if($formModel->validate()) { 
         userService = new UserService();
         userService->createNewUser($formModel->firstName,...);
        } else {
           //example
           var_dump($formModel->getErrors());
        }
    }
}
}
Saturday, May 29, 2021
 
xrock
answered 5 Months ago
13

I personally subclass both Zend_Db_Table_Abstract and Zend_Db_Table_Row_Abstract. The main difference between my code and yours is that explicitly treat the subclass of Zend_Db_Table_Abstract as a "table" and Zend_Db_Table_Row_Abstract as "row". Very rarely do I see direct calls to select objects, SQL, or the built in ZF database methods in my controllers. I try to hide the logic of requesting specific records to calls for behind Zend_Db_Table_Abstract like so:

class Users extends Zend_Db_Table_Abstract {

    protected $_name = 'users';

    protected $_rowClass = 'User'; // <== THIS IS REALLY HELPFUL

    public function getById($id) {
        // RETURNS ONE INSTANCE OF 'User'
    }

    public function getActiveUsers() {
        // RETURNS MULTIPLE 'User' OBJECTS            
    }

}

class User extends Zend_Db_Table_Row_Abstract {

    public function setPassword() {
        // SET THE PASSWORD FOR A SINGLE ROW
    }

}

/* CONTROLLER */
public function setPasswordAction() {

    /* GET YOUR PARAMS */

    $users = new Users();

    $user = $users->getById($id);

    $user->setPassword($password);

    $user->save();
}

There are numerous ways to approach this. Don't think this is the only one, but I try to follow the intent of the ZF's design. (Here are more of my thoughts and links on the subject.) This approach does get a little class heavy, but I feel it keeps the controllers focused on handling input and coordinating with the view; leaving the model to do the application specific work.

Tuesday, July 27, 2021
 
Juriy
answered 3 Months ago
12

Loop through each input element in the form, and check if it has a value. If not append the error message to a string which you later alert out if valid is false.

$('#submit').on('click', function() {
    var valid = true,
        message = '';

    $('form input').each(function() {
        var $this = $(this);

        if(!$this.val()) {
            var inputName = $this.attr('name');
            valid = false;
            message += 'Please enter your ' + inputName + 'n';
        }
    });

    if(!valid) {
        alert(message);
    }
});

Fiddle: http://jsfiddle.net/WF2J9/17/

Thursday, August 5, 2021
 
Nil
answered 3 Months ago
Nil
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share