Jump to content

Recommended Posts

Basically I have two classes in my filters namespace that I want to pass from Index.php to *Controller.php via dependency injection, to avoid instantiating the classes separately I want to group them into one object called filter, then I can call:

 

 

$Filter->Sanitize->email($email);
if ( $Filter->Validate->email($email) ) // do stuff

 

 

Is this the right way to go about it or am I going to cause problems down the line?

 

 


<?php
namespace phantom\classes\filters;


class FilterFactory {
   public $Sanitize;
   public $Validate;
   public function __construct()
   {
      $this->Sanitize = new Sanitize();
      $this->Validate = new Validate();
   }
}

 

 

Thanks for any help

You shouldn't really try to find a pattern for something your creating. You should be thinking about it logically and creating interfaces or abstract classes or just a range of classes where appropriate.

 

The answers you'd receive for this question could be so broad it would be too much. One person may have a preferred method over another persons. That same person may find method A better today, but tomorrow they prefer method B. You should find a methodology that suits you for your given task.

 

That said, a knowledge and understanding of a variety of patterns is very useful as well as it would lead to you being able to adopt the most appropriate in any given situation.

 

We can offer advice on our own thinking but ultimately it comes down to you adopting a method your comfortable with. For example I love to employee the Registry pattern but I know many people dislike it due to its global state and tendency to make debugging near on impossible; each to their own.

Never mind, I just realised my Validate filter should be dependency injected into my Controllers, whilst my Sanitize filter should be injected into my views

 

And no, validation shouldn't be in the controller and the view couldn't give a shit about sanitization. The model, or more specifically model helpers, should be handling this.

 

Some people may argue differently but I see no point in validating within ControllerA as the minute you utilise the same model in ControllerB, you must revalidate in ControllerB; therefore re-writing code which isn't really OO.

Hmm, you make a good point, it was more I thought to use a factory and wanted someone to validate that what I was doing was right or wrong (which you did, thank you :))

 

 

I watched a video on KillerPHP (which I've never found to be a great resource) stating that the Controller is the "throw-away" part of the MVC,  (I don't really see how reusable views work, I can't see it being flexible enough), so I assumed this would be where validation and sanitizing should be done (as I've sussed from previous posts, models should not validate inputs as such (i.e. if ( strlen($username) < 40 ) // do something) ? ) so the only place left was the controller, as for sanitizing in the view, I forgot that the view should contain no logic, so this seemed like a good idea in my head.

 

 

So, how do model-helpers work? 

 

// EDIT

 

Thinking about it, whats wrong with sanitizing in my view? It is related to output. I.E. what's wrong with:

 

<?= $Sanitize->html($tweet[0]); ?>

in my view?

 

I see your point about validation in the model, although I'm still intrigued by the model-helper?

I think I understand the model helper (after a quick google search)

 

 

So an instance specific helper:

 

 

class User {
   protected function _validateUsername($username)
   {
      return ( ctype_digit($username) && strlen($username) > 2 && strlen($username) < 40 );
      // I have been using this for a long time without knowing what it was, just not to validate input
   }
}

 

 

Whereas a more generic helper:

 

 

class UserHelper {
   public function validateUsername($username)
   {
      return ( ctype_digit($username) && strlen($username) > 2 && strlen($username) < 40 ); 
      // this is new to me, but seems plausible
   }
}

 

 

Is that right?

"Helpers" as people often refer to them, are often directly related to the class they are helping or group of classes they help. So you could interpret a validation class as a helper to the models but it depends on whether or not its specific validation or generalised validation.

 

Generalised could be Validate::characters($string, "^(a-zA-Z)$"); where the content of the string is validated using a general regex string. Specific validation could be ensuring some POST data from a select tag is an acceptable option thereby eliminating the possibility of tampering. This is specific to that field and model.

 

I'm making the examples up as I go along but hopefully you get the gist.

 

To re-itterate my point on validation in controllers I'll provide an example:

 

class ControllerA {
    public function processData($input){
        $this->validateContent($input);
        (new Model)->insertData($input);
    }
    
    private function validateContent($input){
        
    }
}

class ControllerB {
    public function processData($input){
        $this->validateContent($input);
        (new Model)->insertData($input);
    }
    
    private function validateContent($input){
        
    }
}

class Model {
    public function insertData($input){
        
    }
}

 

This demonstrates code being re-typed and re-written in different places just to get the entire thing to work consistently. Many human errors can occur.

 

class ControllerA {
    
    private validataion;
    
    public function __construct(ValidationObject $validation){
        $this->validation = $validation;
    }
    
    public function processData($input){
        $this->validation->validateContent($input);
        (new Model)->insertData($input);
    }
}

class ControllerB {
    
    private validataion;
    
    public function __construct(ValidationObject $validation){
        $this->validation = $validation;
    }
    
    public function processData($input){
        $this->validation->validateContent($input);
        (new Model)->insertData($input);
    }
}

class ValidationObject {
    public function validateContent($input){
        
    }
}

class Model {
    public function insertData($input){
        
    }
}

 

We now have a validation object which is executed in both controllers but again, this is re-writing code and completely unnecessary.

 

class ControllerA {    
    public function processData($input){
        (new Model)->insertData($input);
    }
}

class ControllerB {
    public function processData($input){
        (new Model)->insertData($input);
    }
}

class Model {
    public function insertData($input){
        (new ValidationObject)->validateContent($input);
        // SQL Insert statement
    }
}


class ValidationObject {
    public function validateContent($input){
        
    }
}

 

Unlike the first two examples, this one clearly shows the validateContent being called ONCE within the Model as opposed to twice (once in each controller class). As a result, we eliminate any validation dependency on the controllers and write less code in the long run with possibly less human errors.

 

Hopefully that clears it up for you.

Yes, I get your point, but is that not tight-coupling (the model class depends on the ValidationObject class being present in the application?)

 

 

Does this mean there are instances where classes should be tightly-coupled with their dependencies as opposed to dependency injected? 

Here is an example of my current Controller, have I got the idea of MVC completely wrong?

 

 

<?php
namespace phantom\classes\controllers;
// Dependancy injection
use \phantom\classes\caching\Cache         as Cache;
use \phantom\classes\templating\Template   as Template;
// Instantiation
use \phantom\classes\data                  as data;
class Index implements Interface_iController {
   protected $_template;
   protected $_cache;
   public function __construct(Template $Template, Cache $Cache)
   {
      $this->_template = $Template;
      $this->_cache    = $Cache;
   }
   public function deploy(array $params = array())
   {
      switch ( count($params) )
      {
         default :
            if ( $this->_cache->isCached('Index') )
               return $this->_cache->getCachedData('Index');
            // Twitter
            $Twitter = new data\Twitter('PhantomLtd');
            // Template
            $this->_template->loadTemplate('default');
            $this->_template->getFragments([
               'b2c/navigation',
               'default/slider',
               'b2c/product_nav'
            ])->insertAfter('#header');
            $this->_template->getFragment('default/content_lr_divider')->prependTo('#content');
            $this->_template->getFragments([
               'content/videos', 
               'content/news', 
               'content/twitter'
            ], [
               2 => [
                  'tweets'  => $Twitter->getLastTweets(2),
                  'user'    => [ 
                     'url'  => $Twitter->getURL(), 
                     'name' => $Twitter->getUsername() 
                  ]
               ] 
            ])->prependTo('#left_content');
            $this->_template->getFragments([
               'content/index/main_content',
               'content/mini_product_slider'
            ])->appendTo('#right_content');
            $html = $this->_template->getContents();
            $this->_cache->cacheData('Index', $html);
            return $html;
         break;
      }
   }
}

My examples were merely to demonstrate how validation code can easily be re-written when content is validated within controllers. I did not intend on going into detail with regards to dependencies etc.

 

No matter what you do, there will always be some form of dependency. If there was no dependency to some degree, classes probably would never interact with one another or you'd end up going into procedural programming or something. Not really sure, never thought about it in depth.

 

 

 

Edit: you seem like your heading along the right lines. You've encapsulated what looks like some form of router perhaps inside your deploy method so when it comes to writing another controller you may find your copying and pasting code. Take a look at the Proem Framework written by Thorpe. Its very nice and may give you a better idea of how MVC works and a nice way for it to be implemented. Bare in mind this is a framework not an actual MVC website. Its designed to handle the MVC methodology, thorpe can elaborate should he wish to but I really like it!

My examples were merely to demonstrate how validation code can easily be re-written when content is validated within controllers. I did not intend on going into detail with regards to dependencies etc.

 

No matter what you do, there will always be some form of dependency. If there was no dependency to some degree, classes probably would never interact with one another or you'd end up going into procedural programming or something. Not really sure, never thought about it in depth.

 

 

OK, this was quite good reading for me: SOLID

 

 

So in practice, you would inject the dependency?

And no, validation shouldn't be in the controller and the view couldn't give a shit about sanitization. The model, or more specifically model helpers, should be handling this.

 

What if you want to use the same data from the model in a different environment that needs different sanitation? Then you'd have to have different models/methods to fetch identical data but format it differently.

 

No, that should be handled in the controller or the view. It makes your application more flexible and more extensible.

lol OK, thanks scootstah, thanks for clearing that up, time to hit the sack I think, thanks again for the help. Night.

 

 

And no, validation shouldn't be in the controller and the view couldn't give a shit about sanitization. The model, or more specifically model helpers, should be handling this.

 

What if you want to use the same data from the model in a different environment that needs different sanitation? Then you'd have to have different models/methods to fetch identical data but format it differently.

 

No, that should be handled in the controller or the view. It makes your application more flexible and more extensible.

 

Just to clarify, I was referring to inbound sanitisation; you're now referring to outbound sanitisation to prevent attacks such as cross-site scripting.

 

In that case it wouldn't make sense to sanitise in the model as the process is reversed.

 

When inserting, your insert data is passed through the controller to the model. When you select, data is often passed through the controller to the view.

 

Following this ethos, it makes sense to have sanitisation at the end point; however as already mentioned, it may be more appropriate to carry it out at the controller layer as it could be generic sanitisation for output.

 

Well pointed out scootstah. Apologies Andy-H for not being clearer about my referencing!

No worries, yeah, I was referring to "inbound validation" and "outbound sanitization" being injected into my controller and view, respectively.

 

Never mind, I just realised my Validate filter should be dependency injected into my Controllers, whilst my Sanitize filter should be injected into my views

 

// EDIT

 

Thanks for the help, by the way :)

Just to clarify, I was referring to inbound sanitisation

 

Ah. Well, I usually let my DB abstraction layer deal with that, I normally don't explicitly escape anything.

 

 

Yeah, I will be using prepared statements, my validation class consists of :

 

 


<?php
namespace phantom\classes\filters;


class Validate {
   public function email($email)
   {
      return filter_var($email, FILTER_VALIDATE_EMAIL);
   }
   public function url($url)
   {
      return filter_var($url, FILTER_VALIDATE_URL);
   }
   public function IP($IP)
   {
      return filter_var($IP, FILTER_VALIDATE_IP);
   }
   public function signed($int)
   {
      return filter_var($int, FILTER_VALIDATE_INT);
   }
   public function unsigned($int)
   {
      return filter_var($int, FILTER_VALIDATE_INT, array('options' => array('min_range' => 0)));
   }
   public function int_range($int, $min = false, $max = false)
   {
      $options = array();
      if ( $min !== false ) $options['options']['min_range'] = $min; 
      if ( $max !== false ) $options['options']['max_range'] = $max;
      return filter_var($int, FILTER_VALIDATE_INT, $options);
   }
   public function regex($input, $pat)
   {
      return filter_var($input, FILTER_VALIDATE_REGEXP, array('options' => $pat));
   }
   public function callback($input, callable $callback)
   {
      return filter_var($input, FILTER_CALLBACK, array('options' => $callback));
   }
}

I would argue that further validation would still be required at the model layer as a good security system involves multiple layers of security. Its one of the reasons a "middle tier" is implemented in systems amongst making a unified method for talking to the database etc.

 

By further validation I mean ensuring the content being input by the end user is expected - and I use that term loosely. I do completely agree sanitisation should be occurring at the "database layer" so to speak; PHP are pushing towards it hence the massive red splash across PHP's MySQL page. We have however, now split the discussion between sanitisation and validation - yet another discussion :).

 

Really good discussion in here anyhow! Has clarified many points and will be very useful for future onlookers.

Just want to chime in and say that CPD has the right of it.  Inbound validation usually happens during or after data binding, when you have a model in hand and are trying to stuff new/edited data in it.  Inbound sanitation usually happens at the DB layer, generally by an ORM using PDO, which will automatically escape the data.

 

Outbound sanitation generally happens in the view, with a view helper that automatically runs dynamic output through htmlentities.

 

This is pretty much the de facto arrangement.  I know that Symfony2 + Doctrine uses it, .NET MVC, likely Rails (since .NET MVC copied borrowed from Rails) and Django, etc.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.