Как упростить добавление новых правил для Valitron или помощь с ООП от знающих?

96
29 декабря 2021, 18:00

Есть такой симпатичный валидатор - Valitron, добавление новых правил в нем реализуется вот как:

Valitron\Validator::addRule('alwaysFail', function($field, $value, array $params, array $fields) {
        return false;
    }, 'Everything you do is wrong. You fail.');

Я не хочу засорять структуру приложения вот такими обрывками кода и хочу написать механизм, который будет перебирать набор правил из определенной папки и добавлять правила, как-то так:

class UniqueRule {
    public $name;
    public $message;
    public function __construct($name, $message) {
        $this->name = $name;
        $this->message = $message;
    }
    public function handler(function($field, $value, array $params, array $fields) {
        return false;
    }
}

И в цикле цеплять эти файлики, брать нейм в качества имени правила, мессейдж как сообщение об ошибке и саму функцию брать из handler. Но, конкретно как я написал - это с точки зрения ООП че-то не то. Тут явно надо как-то передавать функцию как замыкание, а здесь передача пойдет как вызов. Мне явно не хватает знаний об ООП, чтобы осилить правильную реализацию. Сообщество - помоги! :)

Answer 1

Для начала нужно создать интерфейс который будет имплементировать каждый класс-правило.

Interfaces\RuleInterface

namespace Interfaces;
interface RuleInterface
{
    public function getMessage(): string;
    public function getName(): string;
    public function handler($field, $value, array $params, array $fields): bool;
}

Далее нужно создать само правило, имплементировать RuleInterface, реализовать методы.

Rules\UniqueRule

namespace Rules;
use Interfaces\RuleInterface;
class UniqueRule implements RuleInterface
{
    public function getMessage(): string
    {
        return 'Error! Is not unique';
    }
    public function getName(): string
    {
        return 'unique';
    }
    public function handler($field, $value, array $params, array $fields): bool
    {
        return false;
    }
}

Я бы создал отдельный файл который бы хранил массив с правилами в папке config например, но это уже на собственное усмотрение. Сканировать папку и подгружать классы как по мне не самая лучшая затея. Например:

config/rules.php

return [
    \Rules\UniqueRule::class,
    \Rules\MaxRule::class,
    \Rules\MinRule::class,
    // .....
];

Ну и наконец подгрузка самих правил, в удобном для вас месте.

$rules = include __DIR__ . '/config/rules.php';
foreach ($rules as $ruleClass){
    // создаем объект класса-правила
    $rule = new $ruleClass();
    // если правило не имплементирует нужный интерфей то бросаем исключение
    if (!($rule instanceof \Interfaces\RuleInterface))
        throw new Exception('Rule must implement RuleInterface');
    // расширяем базовый валидатор
    Valitron\Validator::addRule($rule->getName(), function($field, $value, array $params, array $fields) use($rule) {
        // вызываем метод handler и возвращаем результат его работы
        return $rule->handler($field, $value, $params, $fields);
    }, $rule->getMessage());
}
READ ALSO
Посчитать содержимое массива

Посчитать содержимое массива

Помогите, не могу решить следующую задачу на выборку из вложенных массивов

97
MYSQL LEFT JOIN on each value JSON

MYSQL LEFT JOIN on each value JSON

Прошу помощи (mysql 57) В связи с большим количеством данных в таблице было принято решение хранить связи ячеек не в отдельной таблице как обычно...

102
Игра "Виселица" не работает коректно

Игра "Виселица" не работает коректно

Игра работает, но игрок выигрывает если он угадывает всего лишь одну любую букву, что не правильно, потому как игрок должен отгадатать все...

115
Помогите решить задачу с перебором классов и добавлением нового

Помогите решить задачу с перебором классов и добавлением нового

Есть множество div элементов с одинаковым классомПри переборе я должен найти тот div в блоке которого указано например буква 'h' и присвоить...

95