Taking basic validation rules to a more manageable, readable state by implementing architectural solutions that make our validation requirements beautiful.
10. INSPIRATION
● What started this thought process?
● Jeffrey Way’s twitter post earlier this year about where people put their
validation rules.
11. INSPIRATION
● What started this thought process?
● Jeffrey Way’s twitter post earlier this year about where people put their
validation rules.
● Jason Lewis’ article on advanced validation: http://jasonlewis.
me/article/laravel-advanced-validation
12. INSPIRATION
● What started this thought process?
● Jeffrey Way’s twitter post earlier this year about where people put their
validation rules.
● Jason Lewis’ article on advanced validation: http://jasonlewis.
me/article/laravel-advanced-validation
● Lots of posts about validation on forums, twitter.etc.
14. BUT FIRST, A FEW POINTS
● This approach is best suited to medium-large applications
15. BUT FIRST, A FEW POINTS
● This approach is best suited to medium-large applications
● We’re going to use “users” as a set of use-cases to demonstrate this
approach and style to the handling of validation
16. BUT FIRST, A FEW POINTS
● This approach is best suited to medium-large applications
● We’re going to use “users” as a set of use-cases to demonstrate this
approach and style to the handling of validation
● There will be a little code
17. BUT FIRST, A FEW POINTS
● This approach is best suited to medium-large applications
● We’re going to use “users” as a set of use-cases to demonstrate this
approach and style to the handling of validation
● There will be a little code (Sorry)
19. WHAT WILL WE COVER
● A brief history of MVC (to provide context)
20. WHAT WILL WE COVER
● A brief history of MVC (to provide context)
● Good validation practice (resource vs use-case)
21. WHAT WILL WE COVER
● A brief history of MVC (to provide context)
● Good validation practice (resource vs use-case)
● How to architect your validation rules so that they can grow, adhering to
SOLID design principles
22. WHAT WILL WE COVER
● A brief history of MVC (to provide context)
● Good validation practice (resource vs use-case)
● How to architect your validation rules so that they can grow, adhering to
SOLID design principles
● Where validation should go (controllers, models, repositories - where?)
23. WHAT WILL WE COVER
● A brief history of MVC (to provide context)
● Good validation practice (resource vs use-case)
● How to architect your validation rules so that they can grow, adhering to
SOLID design principles
● Where validation should go (controllers, models, repositories - where?)
● Use exceptions to alter program flow and provide greater readability
24. ASSUMPTIONS
● You know a thing or two about Laravel 4’s validation functionality
25. ASSUMPTIONS
● You know a thing or two about Laravel 4’s validation functionality
● You understand how to use Laravel’s IoC features
26. ASSUMPTIONS
● You know a thing or two about Laravel 4’s validation functionality
● You understand how to use Laravel’s IoC features
● You understand the importance of a separation of concerns (if not, we’ll
cover this a little)
27. ASSUMPTIONS
● You know a thing or two about Laravel 4’s validation functionality
● You understand how to use Laravel’s IoC features
● You understand the importance of a separation of concerns (if not, we’ll
cover this a little)
● You’ve dealt with growing validation concerns before (or not)
37. THE REPOSITORY PATTERN
● Why?
● Helped clean up models
● Ensured a common interface for establishing data storage access
38. THE REPOSITORY PATTERN
● Why?
● Helped clean up models
● Ensured a common interface for establishing data storage access
● Enabled us to easily swap out storage formats, caching mechanisms and
more…
39. THE REPOSITORY PATTERN
● Why?
● Helped clean up models
● Ensured a common interface for establishing data storage access
● Enabled us to easily swap out storage formats, caching mechanisms and
more…
● What about validation?
40. WHY NOT ON THE MODEL?
● Breaks the Single Responsibility Principle
41. WHY NOT ON THE MODEL?
● Breaks the Single Responsibility Principle
● Makes no sense if you’re using repositories
42. WHY NOT ON THE MODEL?
● Breaks the Single Responsibility Principle
● Makes no sense if you’re using repositories
● Should be called as part of the service layer
43. WHY NOT ON THE MODEL?
● Breaks the Single Responsibility Principle
● Makes no sense if you’re using repositories
● Should be called as part of the service layer
● Validation is its own domain of logic
44. WHY NOT ON THE MODEL?
● Breaks the Single Responsibility Principle
● Makes no sense if you’re using repositories
● Should be called as part of the service layer
● Validation is its own domain of logic
● I don’t like model-based validation… it smells.
45. WHY NOT ON THE MODEL?
● Breaks the Single Responsibility Principle
● Makes no sense if you’re using repositories
● Should be called as part of the service layer
● Validation is its own domain of logic
● I don’t like model-based validation… it smells.
● But kirk… why?
46. HOW I VIEW MODELS
● Our models are already a mess of various responsibilities
47. HOW I VIEW MODELS
● Our models are already a mess of various responsibilities
● What table or collection to talk to
48. HOW I VIEW MODELS
● Our models are already a mess of various responsibilities
● What table or collection to talk to
● Relationships
49. HOW I VIEW MODELS
● Our models are already a mess of various responsibilities
● What table or collection to talk to
● Relationships
● Querying
50. HOW I VIEW MODELS
● Our models are already a mess of various responsibilities
● What table or collection to talk to
● Relationships
● Querying
● All part of active record. Validation isn’t.
51. HOW I VIEW MODELS
● Our models are already a mess of various responsibilities
● What table or collection to talk to
● Relationships
● Querying
● All part of active record. Validation isn’t.
● They can (and arguably - should) be used as schema descriptors for your
application
52. class User extends Eloquent
{
public $rules = [
‘name’ => [‘required’, ‘min:8’],
‘address’ => ‘required’
];
public function save() {
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new Exception(‘Ugh, y u no provide good datums!?’);
return parent::save();
}
}
53. class User extends Eloquent
{
public $rules = [
‘name’ => [‘required’, ‘min:8’],
‘address’ => ‘required’
];
public function save() {
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new Exception(‘Ugh, y u no provide good datums!?’);
return parent::save();
}
}
54. class User extends Eloquent
{
public $rules = [
‘name’ => [‘required’, ‘min:8’],
‘address’ => ‘required’
];
public function save() {
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new Exception(‘Ugh, y u no provide good datums!?’);
return parent::save();
}
}
55. class User extends Eloquent
{
public $rules = [
‘name’ => [‘required’, ‘min:8’],
‘address’ => ‘required’
];
public function save() {
$validator = Validator::make($this->getAttributes(), $this->rules);
if (!$validator->fails())
throw new Exception(‘Ugh, y u no provide good datums!?’);
return parent::save();
}
}
60. A CUSTOM VALIDATOR
● Defines an approach to handle validation use-cases
● Easier to use and read in our code
61. A CUSTOM VALIDATOR
● Defines an approach to handle validation use-cases
● Easier to use and read in our code
● Provides the ability to automatically handle validation errors
62. A CUSTOM VALIDATOR
● Defines an approach to handle validation use-cases
● Easier to use and read in our code
● Provides the ability to automatically handle validation errors
● Wraps Laravel’s validator so we’re not reinventing the wheel
63. A CUSTOM VALIDATOR
● Defines an approach to handle validation use-cases
● Easier to use and read in our code
● Provides the ability to automatically handle validation errors
● Wraps Laravel’s validator so we’re not reinventing the wheel
● Inspired by Jason Lewis’ validator (originally based on L3):
http://jasonlewis.me/article/laravel-advanced-validation
64. abstract class Validation
{
protected $rules = [];
protected $messages = [];
protected $input = [];
public function __construct(array $input = []) {
$this->input = $input;
}
public function validate() {
$rules = $this->getRules();
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new ValidationException($validator);
65. abstract class Validation
{
protected $rules = [];
protected $messages = [];
protected $input = [];
public function __construct(array $input = []) {
$this->input = $input;
}
public function validate() {
$rules = $this->getRules();
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new ValidationException($validator);
66. abstract class Validation
{
protected $rules = [];
protected $messages = [];
protected $input = [];
public function __construct(array $input = []) {
$this->input = $input;
}
public function validate() {
$rules = $this->getRules();
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new ValidationException($validator);
67. abstract class Validation
{
protected $rules = [];
protected $messages = [];
protected $input = [];
public function __construct(array $input = []) {
$this->input = $input;
}
public function validate() {
$rules = $this->getRules();
$validator = Validator::make($this->getInput(), $this->rules);
if ($validator->fails())
throw new ValidationException($validator);
68. abstract class Validation
{
public function validate() {
$rules = $this->getRules();
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new ValidationException($validator);
}
public function getRules() {
return $this->rules;
}
}
69. abstract class Validation
{
public function getRules() {
return $this->rules;
}
public function getInput() {
return $this->input;
}
}
70. abstract class Validation
{
public function validate() {
$rules = $this->getRules();
$validator = Validator::make($this->getAttributes(), $this->rules);
if ($validator->fails())
throw new ValidationException($validator);
}
public function getRules() {
return $this->rules;
}
}
71. class ValidationException extends Exception
{
public function __construct(Validator $validator)
{
$this->message = 'Validation has failed, or something.';
$this->validator = $validator;
}
public function getErrors()
{
return $this->validator->messages();
}
72. class ValidationException extends Exception
{
public function __construct(Validator $validator)
{
$this->message = 'Validation has failed, or something.';
$this->validator = $validator;
}
public function getErrors()
{
return $this->validator->messages();
}
73. class ValidationException extends Exception
{
public function __construct(Validator $validator)
{
$this->message = 'Validation has failed, or something.';
$this->validator = $validator;
}
public function getErrors()
{
return $this->validator->messages();
}
75. A VALIDATION USE-CASE
● User registration (everyone loves registration… right?)
● We’ll need to define a validator specific to this requirement
76. A VALIDATION USE-CASE
● User registration (everyone loves registration… right?)
● We’ll need to define a validator specific to this requirement
● Let’s go with the usual:
77. A VALIDATION USE-CASE
● User registration (everyone loves registration… right?)
● We’ll need to define a validator specific to this requirement
● Let’s go with the usual:
○ Username
78. A VALIDATION USE-CASE
● User registration (everyone loves registration… right?)
● We’ll need to define a validator specific to this requirement
● Let’s go with the usual:
○ Username
○ Email address
79. A VALIDATION USE-CASE
● User registration (everyone loves registration… right?)
● We’ll need to define a validator specific to this requirement
● Let’s go with the usual:
○ Username
○ Email address
○ Password
81. class UserRegistrationValidation extends Validation
{
public function getRules()
{
$rules = [
‘username’ => [‘required’, ‘min:3’],
‘email’ => [‘required’, ‘email’],
‘password’ => [‘required’, ‘min:8’]
];
return $rules;
}
}
82. SO… HOW DO WE USE THIS?
● Utilise our validation for user registration
83. SO… HOW DO WE USE THIS?
● Utilise our validation for user registration
● Provide it with the required $input (in this case, probably Input::get())
84. SO… HOW DO WE USE THIS?
● Utilise our validation for user registration
● Provide it with the required $input (in this case, probably Input::get())
● Then call the validate function
85. SO… HOW DO WE USE THIS?
● Utilise our validation for user registration
● Provide it with the required $input (in this case, probably Input::get())
● Then call the validate function
● Handle the onslaught of errors!
86. SO… HOW DO WE USE THIS?
● Utilise our validation for user registration
● Provide it with the required $input (in this case, probably Input::get())
● Then call the validate function
● Handle the onslaught of errors!
● Let’s see an example, shall we?
87. // UserController
public function postRegister()
{
$input = Input::get();
try {
App::make(‘UserRegistrationValidation’, [$input])->validate();
}
catch (ValidationException $e) {
// Handle errors
}
// Create a response
return User::create($input);
}
91. EXCEPTIONS FOR DAYS
● We can use Laravel’s own error-handling to our advantage
92. EXCEPTIONS FOR DAYS
● We can use Laravel’s own error-handling to our advantage
● Automatically catch ValidationException(s)
93. EXCEPTIONS FOR DAYS
● We can use Laravel’s own error-handling to our advantage
● Automatically catch ValidationException(s) ->
○ Render a response
94. EXCEPTIONS FOR DAYS
● We can use Laravel’s own error-handling to our advantage
● Automatically catch ValidationException(s) ->
○ Render a response
○ Be more awesome…. er.
99. TO CONCLUDE
● We’ve setup validation as part of its own domain (it’s entirely responsible
for nothing other than validation)
100. TO CONCLUDE
● We’ve setup validation as part of its own domain (it’s entirely responsible
for nothing other than validation)
● We’ve freed our models from the additional weight of having to handle
possibly very complex validation requirements.
101. TO CONCLUDE
● We’ve setup validation as part of its own domain (it’s entirely responsible
for nothing other than validation)
● We’ve freed our models from the additional weight of having to handle
possibly very complex validation requirements.
● We’ve let Laravel handle our own errors - cleaning up our code!
102. TO CONCLUDE
● We’ve setup validation as part of its own domain (it’s entirely responsible
for nothing other than validation)
● We’ve freed our models from the additional weight of having to handle
possibly very complex validation requirements.
● We’ve let Laravel handle our own errors - cleaning up our code!
● Our validation is now much easier to extend, and implement (and move
around)
103. // Instead of this...
public function postRegister()
{
$input = Input::get();
try {
App::make(‘UserRegistrationValidation’, [$input])->validate();
}
catch (ValidationException $e) {
// Handle errors
}
// Create a response
return User::create($input);
}
104. // Now we have this.
public function postRegister()
{
$input = Input::get();
App::make(‘UserRegistrationValidation’, [$input])->validate();
return User::create($input);
}