1

I have a column in my database which it's json type: values.
But I need to enforce a schema.

  • It must be an array
  • Every object must have 2 and only 2 properties (required). code_name, and description
  • code_name must be unique inside that JSON array

Does Laravel has some out of the box feature for this? or do I need to manually decode the json on create and on update to validate that rules?

Till now. I only have this validation rules in my Model:

/**
 * The model validation rules.
 *
 * @var array
 */
public static $rules = [
    'values' => 'required|json', // TO BE CHECKED (values validation (json schema) and setter)
];

But that's not enough.

Important: this is not a duplicate question to: Laravel: validate json object

Iván E. Sánchez
  • 1,183
  • 15
  • 28
  • I don't believe there is any out-of-the-box validation available for this. Does this blog post help in casting it to an array and to get started on the custom validation required? http://www.qcode.in/use-mysql-json-field-in-laravel/ – kerrin Jun 30 '18 at 00:34

1 Answers1

6

Laravel supports adding your own custom validation rules.

To create a validation rule you should create a new class that implements the interface Illuminate\Contracts\Validation\Rule.

The artisan command php artisan make:rule {NAME} automatically generates a rule template for you in the App\Rules namespace.

Simply put, you write a passes($attribute, $value) function which returns a boolean that determines if the validation fails or succeeds.

I've written an example based on your requirements below.

Example

<?php
namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class ValuesSchemaRule implements Rule
{
    private $validProperties = ['code_name', 'description'];

    public function __construct()
    {
    }

    public function passes($attribute, $value)
    {
        $array = json_decode($value);

        if (is_array($array) === false) {
            return false;
        }

        $codeNames = [];

        foreach ($array as $object) {
            $properties = get_object_vars($object);

            if (count($properties) !== 2) {
                return false;
            }

            $propertyNames = array_keys($properties);

            if (in_array($this->validProperties, $propertyNames) === false) {
                return false;
            }

            array_push($codeNames, $object->code_name);
        }

        if (count($codeNames) !== count(array_unique($codeNames))) {
            return false;
        }

        return true;
    }

    public function message()
    {
        return 'The values does not comply to the JSON schema';
    }
}

To add it to your model validation you should just assign the 'values' property to a new instance of your Rule class:

/**
 * The model validation rules.
 *
 * @var array
 */
public static $rules = [
    'values' => new ValuesSchemaRule,
];
Daniel
  • 10,641
  • 12
  • 47
  • 85