Validation
As common as it is, validation is essential for every application. Lucid brings a domain-driven approach that embraces Laravel’s validation. In short, if you’ve done validation with Laravel you’re already familiar with everything here, we will only choose convenient locations for Validators and Form Requests by placing them in domains.
Domain-Driven Validation
Often times validation is a matter of context, and domains in Lucid are an ideal place to encapsulate functionality,
and form requests fit perfectly there! e.g. Domains/{domain}/Requests/{Request}.php
Eventually we’d end up with a categorical directory structure that protects our validation files from becoming unmanageable.
Form Requests
app/Domains
├── Chat
│ └── Requests
│ └── SendMessage.php
├── Comment
│ └── Requests
│ └── AddComment.php
├── Filesystem
│ └── Requests
│ └── UploadFiles.php
└── Post
└── Requests
├── CreatePost.php
└── UpdatePost.php
Validation Jobs
app/Domains
├── Chat
│ └── Jobs
│ └── ValidateNewMessageJob.php
├── Comment
│ └── Jobs
│ └── ValidateNewCommentJob.php
├── Filesystem
│ └── Jobs
│ └── ValidateFilesUploadJob.php
└── Post
└── Jobs
├── ValidateNewPostJob.php
└── ValidatePostUpdateJob.php
Form Request Validation
In an effort to keep our controllers thin and reduce their clutter, as well as having features carry their requirements with them wherever we decide to serve them from, it is recommended for validation using Form Request to happen in features instead of controllers, to maintain their integrity whenever they’re served.
Nevertheless, it is done exactly the same as Laravel controllers in any of Lucid’s units, by injecting the form request class in the method signature as a parameter:
class CustomFeature extends Feature
{
public function handle(UpdatePost $request)
{
// request is valid according to the rules specified in UpdatePost
}
}
This will perform Form Request Validation using UpdatePost
class.
The same can be done in any unit: Feature, Job and Operation.
For more on Form Request classes see Laravel’s docs.
Generate Form Request
Signature
lucid make:request <name> <domain>
Example
lucid make:request UpdatePost post
Generated class will be at app/Domains/Post/Requests/UpdatePost.php
Signature
lucid make:request <name> <domain>
Example
lucid make:request UpdatePost post
Generated class will be at src/Domains/Post/Requests/UpdatePost.php
<?php
namespace App\Domains\Post\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdatePost extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
Requests as Unit Dispatchers
One of the most powerful aspects of Lucid is the degree of code reuse it introduces. Specifically when dealing with Job and Operation classes which can be called from any custom dispatcher class.
Here, we will be setting up UpdatePost
Request class to authorize using AuthorizeUserOperation
, and on after hook
to run FaliedValidationJob
.
Benefit: Doing so would increase the degree of consistency and integrity in our application,
where AuthorizeUserOperation
could contain our consolidated authorization mechanism and
can be called from any other class such as middleware to authoriza pre-flight.
As for FaliedValidationJob
it will ensure that all of our failed validations are handled consistently as expected.
<?php
namespace App\Domains\Post\Requests;
use Lucid\Bus\UnitDispatcher;
use App\Operations\AuthorizeUserOperation;
use Illuminate\Foundation\Http\FormRequest;
use App\Domains\Http\Jobs\FailedValidationJob;
class UpdatePost extends FormRequest
{
use UnitDispatcher;
public function authorize()
{
return $this->run(new AuthorizeUserOperation());
}
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$this->run(new FailedValidationJob($validator));
}
});
}
}
Validation Jobs
Another approach to validation is to validate using jobs. This is most useful with protocols other than HTTP (e.g. Console, AMQP, etc.), or if you simply choose not to use Requests.
Our validation jobs would contain validation logic so it can be called whenever validation is required.
Start by creating a job:
lucid make:job ValidatePostUpdate post
Then inject Illuminate\Http\Request
and fill in your validation logic:
<?php
namespace App\Domains\Post\Jobs;
use Lucid\Units\Job;
use Illuminate\Http\Request;
class ValidatePostUpdateJob extends Job
{
public function handle(Request $request)
{
$validData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
return $validData;
}
}