Write Your Laravel Validation Logic Like a Senior Dev, Part 3
Extending the Rule Object with a DateTime Trait

I am a full-stack web developer that enjoys coding in Laravel and React.
Search for a command to run...
Extending the Rule Object with a DateTime Trait

I am a full-stack web developer that enjoys coding in Laravel and React.
No comments yet. Be the first to comment.
Here I will post some articles that help devs with simple and complex topics in Laravel.
From time-to-time, you will happen upon a problem between your frontend and API that you can't quite see. A dd() in your controller or a console.log() in your frontend just doesn't seem to cut it and the problem seems out of reach. Luckily, Laravel p...
Switching stacks

If you don't know what Twin Macro is, check it out! It's a great library that blends Tailwind CSS and Styled Component systems, like Emotion. I love using Twin because it lets me use Tailwind while separating my styling from my markup and methods. If...

Many developers know that full-stack apps with a Vue frontend can be quickly spun up with Laravel Jetstream. What many don’t know is that recently, the Laravel team made it easy to make an Inertia app with Laravel Breeze. In this article, we'll make ...

Using Custom Console Commands

In one of my projects, I needed some DateTime-related rules for Laravel, such as preventing the creation of an item after a certain time. Laravel does come with some DateTime validation rules out-of-the-box, but sometimes you want more control than what you can get. In this article, I'll discuss how I used a custom DateTime Trait in my Rules object to create and extend a powerful custom rule. Below, I'll show you how to create an extended Rule object that prevents an event from being added after the date has passed. I know part 3 to Laravel Validation was long overdue, so let's get down to business, shall we?
Prerequisites:
First Steps:
DateTime Trait that will have all our methods concerning DateTime. Please follow the steps in the article mentioned earlier if you don't know how to create one. Name your Trait DateTimeTrait. We'll be importing the Carbon library to help us handle DateTime functions.
<?php
namespace App\Traits;
use Carbon\Carbon;
trait DateTimeTrait {
public function getCurrentTime(){
$current = Carbon::now('America/New_York');
return $current;
}
public function convertTimetoEastern($date, $tz){
$newdate = Carbon::createFromFormat('Y-m-d H:i:s', $date, $tz)
->setTimezone('America/New_York');
return $newdate;
}
}
Carbon::parse(). This method is another way of instantiating Carbon and passing a time string to the object so that it can be manipulated.diffInSeconds() method to get the difference in seconds. This method accepts a boolean as an optional second parameter to say whether we want an absolute value or not. Because we want our value to be positive or negative, we set it to false. public function getDateDifferenceFromNow($event_date, $timezone){
$date = Carbon::parse(
$this->convertTimetoEastern($event_date, $timezone)
);
$difference = $date->diffInSeconds($this->getCurrentTime(), false);
return $difference;
}
The Work Begins:
EventRequest and it will handle our validation. <?php
namespace App\Http\Requests;
use App\Http\Requests\APIFormRequest;
class EventRequest extends APIFormRequest
{
/**
* 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 [
'name' => 'required',
'start_time' => 'required',
'end_time' => 'date_format:Y-m-d H:i:s|after:start_time',
'venue' => 'required',
'price' => 'required',
'timezone' => 'required|timezone'
];
}
}
TimeTooLate by running php artisan make:rule TimeTooLate. We'll then import our newly-made DateTimeTrait. passes() method, and a message() method. passes() method takes in two parameters, $attribute and $value. The $attribute describes the name of the field that we'll be working with, which in this case, is start_time. The $value describes the value that is attached to that field. The $value param will be used in the passes() method to determine whether the rule passes or not. <?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use App\Traits\DateTimeTrait;
class TimeTooLate implements Rule
{
use DateTimeTrait;
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct(string $timezone)
{
//
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
//
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'The validation error message.';
}
}
The Work Continues:
public $tz;
public function __construct(string $timezone)
{
$this->tz = $timezone;
}
passes() method, we need to make sure that it returns false so that message() can return an error message. With the getDateDifferenceFromNow() method in our DateTimeTrait, a positive integer is returned if the event date has surpassed the current date and time. public function passes($attribute, $value)
{
$difference = $this->getDateDifferenceFromNow($value, $this->tz);
return $difference >= 0 ? false : true;
}
message() method will fire. You can put anything here. Also, usually, you could access the name of the $attribute and bind it to your returned string by using :attribute. We won't use it here, but you're free to use it if you wish.public function message()
{
return 'It\'s too late to add this event now';
}
The Work Ends:
start_time into an array and include TimeTooLate as an element. We'll instantiate TimeTooLate, and pass in the timezone.<?php
namespace App\Http\Requests;
use App\Http\Requests\APIFormRequest;
use App\Rules\TimeTooLate;
class ShowRequest extends ApiFormRequest
{
/**
* 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 [
'name' => 'required',
'start_time' => ['required',
'date_format:Y-m-d H:i:s',
new TimeTooLate(request('timezone'))],
'end_time' => 'date_format:Y-m-d H:i:s|after:start_time',
'venue' => 'required',
'price' => 'required',
'timezone' => 'required|timezone'
];
}
<?php
use Illuminate\Http\Request;
use App\Http\Requests\EventRequest;
use Illuminate\Support\Facades\Route;
Route::post('event/new', function(EventRequest $request){
$validated = $request->validated();
dd($validated);
});
$ php artisan serve. form-data section of the Body tab that matches the fields we're trying to validate. Make sure that your start_time is some time in the past. Once you run the request, it should look something like this:
Conclusion: