3

I'd like to add multiple custom validation, each as their own file.

So far, I've modified my app/start/global.php file to

global.php

ClassLoader::addDirectories(array(
    app_path().'/commands',
    app_path().'/controllers',
    app_path().'/models',
    app_path().'/database/seeds',
    app_path().'/validators'        // <--- Added this folder
));

// Only the first resolver works. 
// I cannot seem to have multiple of these files

Validator::resolver(function($translator, $data, $rules, $messages) 
{
    return new ScheduleValidator($translator, $data, $rules, $messages);
});

Validator::resolver(function($translator, $data, $rules, $messages) 
{
    return new UserValidator($translator, $data, $rules, $messages);
});

And each of my validation files would be in the /validators as

ScheduleValidator.php

class ScheduleValidator extends Illuminate\Validation\Validator
{
    protected $implicitRules = array('Required', 'RequiredWith', 'RequiredWithout', 'RequiredIf', 'Accepted', 'RequiredWithoutField');
    public function __construct(\Symfony\Component\Translation\TranslatorInterface $translator, $data, $rules, $messages = array())
    {
        parent::__construct($translator, $data, $rules, $messages);
        $this->isImplicit('fail');
    }

    /**
    * Validates type to be of the type 'common', 'template', or 'revision'
    */
    public function validateTypeSchedule($attribute, $value, $parameters = null)
    {
        $valid_types = ['template', 'common', 'revision'];
        return in_array($value, $valid_types);
    }

    // and the other validators ...
}

So how can I add multiple of these validators?

3 Answers 3

6

I solved this by making all my separate validators traits, so my one custom validators can simply 'use' my traits and still keep them separated.

My validator:

<?php

use Illuminate\Validation\Validator as LaravelValidator;

class CustomValidator extends LaravelValidator {
    use PhoneValidatorTrait;

}

My trait:

<?php

class PhoneValidatorTrait {
    public function validateSomething(){ ... }
}

resolver:

<?php

Validator::resolver(function($translator, $data, $rules, $messages)
{
    return new CustomValidator($translator, $data, $rules, $messages, []);
});
Sign up to request clarification or add additional context in comments.

Comments

0

My guess is that the call to Validator::resolver simply sets a value if it's not already set, so the second and later calls are ignored.

What you really need is one call to Validator::resolver and include your logic for choosing which validator to use in the closure. It would look something like this:

Validator::resolver(function($translator, $data, $rules, $messages) 
{
    // perform a test to figure out what kind of validator to return
    if ($schedule) {
        return new ScheduleValidator($translator, $data, $rules, $messages);
    } else {
        return new UserValidator($translator, $data, $rules, $messages);
    }
});

The trick is goinge to be the if test - I'm not sure what to do there. The first thing that comes to mind is to check the type of $data:

if ($data instanceof Schedule) {

But the validator is going to receive an array instead of an object for $data. So that means either a) you need to examine the array values and puzzle out what it is you're trying to validate, or b) you need to add a flag or type value to the array when you're validating it. The second is likely to be easier and a little more robust. For example:

// in the Schedule controller
$data = Input::all();
$data["type"] = "schedule";
$validator = Validator::make($data, $rules);

// in global.php
Validator::resolver(function($translator, $data, $rules, $messages) 
{
    // perform a test to figure out what kind of validator to return
    if ($data["type"]=="schedule") {
        return new ScheduleValidator($translator, $data, $rules, $messages);
    } else {
        return new UserValidator($translator, $data, $rules, $messages);
    }
});

This is, unfortunately, not a very elegant solution. To improve it, you might create a library whose sole task is resolving the type of validator required.

2 Comments

Okay thanks, I'll give this a try. But why isn't there a simple way of doing this? I don't think this is a very unrealistic thing to have. It makes to keep your custom validation separated by their model, specially if a project gets large.
Yeah, I can't say I disagree with you. If you're interested in model-based validation, there is a Laravel package out there that handles validation in the model. I can't recall the name of it of the top of my head.
-1

Create one class with Custom Validator for example:

<?php namespace Acme\Validators;

use Illuminate\Validation\Validator as Validator;
use DB;
use Input;
use Request;

class CustomValidator extends Validator {

    public function validateUniqueWith($attribute, $value, $parameters)
    {
        $table = $parameters[0];

        $query = DB::table($table)
            ->where($parameters[1], Input::get($parameters[1]))
            ->where($attribute, $value);

        if (isset($parameters[3]))
        {
            list($idColumn, $id) = $this->getUniqueIds($parameters);
            $query->where('id', '!=', $idColumn);
        }

        if($query->count() > 0)
        {
            return false;
        }

        return true;
    }

    public function validateDateSame($attribute, $value, $parameters)
    {
        $this->requireParameterCount(1, $parameters, 'date_same');

        if ( ! ($date = strtotime($parameters[0])))
        {
            return strtotime($value) >= strtotime($this->getValue($parameters[0]));
        }
        else
        {
            return strtotime($value) >= $date;
        }
    }

    public function validateDni($attribute, $value, $parameters)
    {
        if(strlen($value)<9) {
            return false;
        }

        $value = strtoupper($value);

        $letra = substr($value, -1, 1);
        $numero = substr($value, 0, 8);

        // Si es un NIE hay que cambiar la primera letra por 0, 1 ó 2 dependiendo de si es X, Y o Z.
        $numero = str_replace(array('X', 'Y', 'Z'), array(0, 1, 2), $numero);

        $modulo = $numero % 23;
        $letras_validas = "TRWAGMYFPDXBNJZSQVHLCKE";
        $letra_correcta = substr($letras_validas, $modulo, 1);

        if($letra_correcta!=$letra) {
            return false;
        }
        else {
            return true;
        }
    }

}

And before resolver Validator in app/routes.php for example or in other file.

use Acme\Validators\CustomValidator as CustomValidator;

Validator::resolver(function($translator, $data, $rules, $messages)
{
    return new CustomValidator($translator, $data, $rules, $messages);
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.