Andy-H Posted June 18, 2012 Share Posted June 18, 2012 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 Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 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 Quote Link to comment Share on other sites More sharing options...
cpd Posted June 18, 2012 Share Posted June 18, 2012 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. Quote Link to comment Share on other sites More sharing options...
cpd Posted June 18, 2012 Share Posted June 18, 2012 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. Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 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? Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 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? Quote Link to comment Share on other sites More sharing options...
cpd Posted June 18, 2012 Share Posted June 18, 2012 "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. Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 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? Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 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; } } } Quote Link to comment Share on other sites More sharing options...
cpd Posted June 18, 2012 Share Posted June 18, 2012 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! Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 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? Quote Link to comment Share on other sites More sharing options...
cpd Posted June 18, 2012 Share Posted June 18, 2012 Yes DI is very good, just don't become obsessive as some situations may be more suited to hard-coded dependency but if it can be avoided, avoid it. Quote Link to comment Share on other sites More sharing options...
cpd Posted June 18, 2012 Share Posted June 18, 2012 On a side note, I've begun using Registries and DI together harmoniously and its working quite well. You've got to be extremely careful what you put in the registry but even so its good. Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 Isn't that just exposing your objects to the global scope though? Quote Link to comment Share on other sites More sharing options...
cpd Posted June 18, 2012 Share Posted June 18, 2012 Like I said you've gotta be careful. Some of my classes I use everywhere doing random stuff. Many classes I don't. I'm moving more towards DI every day actually but at the minute its all integrated... fun times. Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 Fair enough, I guess I'm getting too hung up on following best practice rather than getting things done. Thanks for your help Quote Link to comment Share on other sites More sharing options...
scootstah Posted June 18, 2012 Share Posted June 18, 2012 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. Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 18, 2012 Author Share Posted June 18, 2012 lol OK, thanks scootstah, thanks for clearing that up, time to hit the sack I think, thanks again for the help. Night. Quote Link to comment Share on other sites More sharing options...
cpd Posted June 19, 2012 Share Posted June 19, 2012 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! Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 19, 2012 Author Share Posted June 19, 2012 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 Quote Link to comment Share on other sites More sharing options...
scootstah Posted June 19, 2012 Share Posted June 19, 2012 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. Quote Link to comment Share on other sites More sharing options...
Andy-H Posted June 19, 2012 Author Share Posted June 19, 2012 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)); } } Quote Link to comment Share on other sites More sharing options...
cpd Posted June 19, 2012 Share Posted June 19, 2012 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. Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted June 19, 2012 Share Posted June 19, 2012 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.