milwad-dev / laravel-validate

The Laravel-Validate package enhanced Laravel validation capabilities with custom rules and methods for simplified and efficient validation logic.
https://packagist.org/packages/milwad/laravel-validate
MIT License
456 stars 39 forks source link

[1.x] Migrate validation rule classes from Rule to Validation rule #84

Closed kiankamgar closed 6 months ago

kiankamgar commented 8 months ago

I just refactored rule classes, If you want I can refactor tests as well

kiankamgar commented 6 months ago

Hi again, do you have any plans to merge these changes in the future?

milwad-dev commented 6 months ago

The Laravel-Validate support Laravel 9 and I don't think we can merge this!

kiankamgar commented 6 months ago

I can make the code support laravel 8 and 9 as well, if you want. We can decide to initialize rule class based on the laravel version

kiankamgar commented 6 months ago

The old rule class is deprecated and soon or later it will be removed

milwad-dev commented 6 months ago

Can you show how to do it?

kiankamgar commented 6 months ago

We can change every rule class to a facade, for example consider ValidPhoneNumber:

<?php

namespace Milwad\LaravelValidate\Rules;

use Illuminate\Support\Facades\Facade;

class ValidPhoneNumber extends Facade
{
    protected static function getFacadeAccessor()
    {
        if (app()->version() < 10) {

            return new \Milwad\LaravelValidate\Rules\Legacy\ValidPhoneNumber();
        }

        return new \Milwad\LaravelValidate\Rules\Modern\ValidPhoneNumber();
    }
}

Now we have Modern and Legacy forders in our Rule folder. When a user requests a validation, we check laravel version and return related class based on it: \Milwad\LaravelValidate\Rules\Legacy\ValidPhoneNumber

<?php

namespace Milwad\LaravelValidate\Rules\Legacy;

use Illuminate\Contracts\Validation\Rule;
use Milwad\LaravelValidate\Utils\CountryPhoneCallback;

class ValidPhoneNumber implements Rule
{
    public function __construct(protected ?string $code = null)
    {
    }

    /**
     * Check phone number is valid.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        if (is_string($this->code)) {
            $passes = (new CountryPhoneCallback($value, $this->code))->callPhoneValidator();

            return collect($passes)->some(fn ($passe) => $passe);
        }

        return preg_match('/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/', $value);
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return __('validate.phone-number');
    }
}

\Milwad\LaravelValidate\Rules\Modern\ValidPhoneNumber:

<?php

namespace Milwad\LaravelValidate\Rules\Modern;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Milwad\LaravelValidate\Utils\CountryPhoneCallback;
use function collect;

class ValidPhoneNumber implements ValidationRule
{
    public function __construct(
        protected ?string $code = null
    ){}

    /**
     * Check phone number is valid.
     *
     * @param string $attribute
     * @param mixed $value
     * @param Closure $fail
     * @return void
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (! $this->isPhoneNumberValid($value)) {

            $fail('validate.phone-number')->translate();
        }
    }

    /**
     * Check if phone number is valid
     *
     * @param mixed $value
     * @return bool
     */
    private function isPhoneNumberValid(mixed $value): bool
    {
        if (is_string($this->code)) {
            $passes = (new CountryPhoneCallback($value, $this->code))->callPhoneValidator();

            return collect($passes)->some(fn ($passe) => $passe);
        }

        return preg_match('/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/', $value);
    }
}

Even we can extract our boolean logic from these two classes and bring it to another class that is responsible for the result and in each class we call the Logic class and return its value

kiankamgar commented 6 months ago

Tell me what do you think about this approach. If you want I can do it and you can see the result and decide

milwad-dev commented 6 months ago

I don't like this way, if Laravel doesn't support these rules in the future, we think about it and you can create a new PR again or create an issue to talk about this.