9

I'm working with Laravel 5.7 and I need to validate a phone length by using 2 inputs (prefix+number). The total digits has to be 10 always.

I'm using this custom rule for other projects which works fine:

<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;

class PhoneLength implements Rule
{
    public $prefix;

/**
 * Create a new rule instance.
 *
 * @return void
 */
public function __construct($prefix = null)
{
    //
    $this->prefix = $prefix;
}

/**
 * Determine if the validation rule passes.
 *
 * @param  string  $attribute
 * @param  mixed  $value
 * @return bool
 */
public function passes($attribute, $value)
{
    //
    return strlen($this->prefix)+strlen($value) == 10 ? true : false;
}

/**
 * Get the validation error message.
 *
 * @return string
 */
public function message()
{
    return 'El Teléfono debe contener 10 dígitos (prefijo + número)';
}
}

In my controller I do something like

$validatedData = $request->validate([
  'prefix' => 'integer|required',
  'number' => ['integer','required', new PhoneLength($request->prefix)],
]);

Now I need to make use of arrays, so my new validation looks like

$validatedData = $request->validate([
  'phones.*.prefix' => 'required',
  'phones.*.number' => ['required', new PhoneLength('phones.*.prefix')],
]);

The above code doesn't work at all, the parameter is not being sent as expected. How can I send an array value? Of course I need to get the values from the same array element, so if phones[0].number is under validation, the prefix phones[0].prefix is needed.

I've found this question, but I refuse to believe that is not possible to do in a "native" way: Laravel array validation with custom rule

Thanks in advance

3 Answers 3

13

You could get $prefix from the request itself:

class PhoneLength implements Rule
{
    public function passes($attribute, $value)
    {
        $index = explode('.', $attribute)[1];
        $prefix = request()->input("phones.{$index}.prefix");
    }
}

or pass the $request in the PhoneLength rule constructor, then use it.

Sign up to request clarification or add additional context in comments.

Comments

1

The Abdeldayem Sherif's answer is good but there is a problem when the attribute has more level of nesting, for example: clients.*.phones.*.prefix. In this case, exploding and using the 1 index will cause an unexpected error. A better solution is using str_replace.

class PhoneLength implements Rule
{
    public function passes($attribute, $value)
    {
        $prefixAttr = str_replace('.number', '.prefix', $attribute);
        $prefix = request()->input($prefixAttr);
    }
}

Comments

0

According to this https://github.com/laravel/framework/pull/18654 you can use, it will add your custom rule as dependent and replace asterix with needed indexes

Validator::extendDependent('contains', function ($attribute, $value, $parameters, $validator) {
   // The $parameters passed from the validator below is ['*.provider'], when we imply that this
   // custom rule is dependent the validator tends to replace the asterisks with the current
   // indices as per the original attribute we're validating, so *.provider will be replaced
   // with 0.provider, now we can use array_get() to get the value of the other field.

    // So this custom rule validates that the attribute value contains the value of the other given
    // attribute.
    return str_contains($value, 
            array_get($validator->getData(), $parameters[0])
    );
});


Validator::make(
    [['email' => '[email protected]', 'provider' => 'mail.com']],
    ['*.email' => 'contains:*.provider']
)->validate();

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.