Using Laravel's Illuminate Validation in any PHP project
Tags: validation, php, laravel, illuminate
Published: 2022-02-19 14:12:05

I'm developing a Wordpress plugin that requires strict data for the frontend. The frontend is built with Vue.js and it's basically a multistep wizard where every step is represented by a specific Vue component.

## A little bit of context
I want to give the freedom to any developer that's going to use this wizard to pass any step they want in any order they want. On the backend side, each step is represented by a class that's instantiated as follows:
```
new \StaxWp\Gandalf\Core\Components\YoutubeVideo(
	[
		'title'       => '',
		'description' => '',
		'url'         => '',
		'autoplay'    => false,
	],
	1,
);
```

This is a step that contains a `title`, a `description`, an `url` and an option to `autoplay`. Every step accepts in its constructor an array of data and an int for priority. Because we're humans and we can make mistakes I need to make sure all the fields from the array have specific values.

If you are familiar with Laravel, you know how the validation works. We can use the same validation outside Laravel. This is how I enforced validation rules for my step's data array:

```
final class YoutubeVideo extends Step {

	/**
	 * YoutubeVideo constructor
	 *
	 * @param array   $data
	 * @param integer $priority
	 */
	public function __construct( array $data, int $priority = 0 ) {
		parent::__construct( $data, $priority );

		$this->add_validation_rules(
			[
				'title'       => 'sometimes|required|string|nullable',
				'description' => 'sometimes|required|string|nullable',
				'url'         => [ 'required', 'string', 'regex:/^(https?\:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/watch\?v\=\w+$/' ],
				'autoplay'    => 'required|boolean',
			]
		);
	}

}
```
This of course won't work out of the box, so first we'll need to install `illuminate/validation` and `illuminate/translation`.

## Setting up the requirements
```
composer require illuminate/validation
composer require illuminate/translation
```
Next we need to include the following in our class...
```
use Illuminate\Container\Container;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Translation\FileLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\Factory;
```
...then declare our private variable for validation and validation rules...
```
/**
* Step data validator
*
* @var Factory
*/
private $validation;

/**
* Step data validation rules
*
* @var array
*/
private $validation_rules = [];
```
... and then we need instantiate our validator in the constructor:
```
$loader           = new FileLoader( new Filesystem(), 'lang' );
$translator       = new Translator( $loader, 'en' );
$this->validation = new Factory( $translator, new Container() );
```
I'm not gonna add any localization files for the error messages because I won't display them. Everytime the validator fails I'm gonna throw an exception.

## Actually doing the validation
Every step is casted to array and converted to JSON and then passed to the Vue, so where do I do the validation? In the array casting function of course:
```
/**
* Get step as array
*
* @return mixed
*/
public function to_array() {
	$this->validate_data();

	return get_object_vars( $this );
}

/**
* Validate step's data
*
* @return mixed
*/
protected function validate_data() {
	if ( ! empty( $this->data() ) && empty( $this->validation_rules ) ) {
		throw new Exception( $this->type() . ' has data but no validation rules.' );
	}

	$validator = $this->validation->make( $this->data(), $this->validation_rules );

	if ( $validator->fails() ) {
		throw new Exception( $this->type() . ' has an incorrect data format.' );
	}
}
```

By doing this I know for sure that my `$data` array has all the required fields and each field has the required value.

I hope you've found this short tutorial useful.

#### Support & follow me
| [![Buy me a coffee](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/geowrgetudor) | [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/geowrgetudor) | [![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/geowrgetudor) | [![Linkedin](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://linkedin.com/in/geowrgetudor) |
| ------------- | ------------- | ------------- | ------------- |