Прийшов час осідлати справжнього Буцефала🏇🏻Приборкай норовливого коня разом з Newxel🏇🏻Умови на сайті
×Закрыть

Як автоматизувати валідацію даних в PHP

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Якось мені необхідно було написати класи з багатьма властивостями. Здебільшого програмісти особливо цим не переймаються — наклонують гетери разом з сетерами та й закриють це питання. До того ж сучасні IDE мають необхідні засоби для автоматизації цього процесу. Але мене осяйнула думка про те, що можна значно спростити створення класів, відмовившись від написання нудних однотипних операцій.


Автоматизація валідації даних в PHP

Я змоделював яка саме на моєму проєкті необхідна валідація та розклав її на частини. Перша частина — це валідація згідно з регулярним виразом. Цей вид валідації настільки універсальний, що може задовольнити майже всі перевірки. Хоча він має один суттєвий недолік: з його допомогою важко перевіряти допустимі діапазони чисел. Тобто зробити це можливо, але зазвичай дуже складно та незручно.

Тому ми підходимо до другої частини — звірка згідно з мінімальним або максимальним обмеженням числового значення. Вона компенсує недоліки попередньої частини й розширить можливості майже до ідеалу. Але й ця перевірка не зможе зробити валідацію максимально універсальною, тому що всі можливі ситуації передбачити неможливо.

На цей випадок впроваджуємо третю частину — користувацьку валідацію за допомогою методу. А от у методі ви зможете перевіряти значення властивості як вашій душі буде завгодно.

Є й четверта частина — перевірка на обов’язкову присутність значення властивості сутності. Але вона настільки проста, що я особливо зупинятися на ній не буду.

Базова сутність

Тепер саме час перейти до практичної частини та написати майже порожній базовий клас сутності для наслідування. А згодом я буду поступово додавати в нього необхідний функціонал, супроводжуючи власними скупими коментарями.

Клас із прикладами та шаблонами

Почнемо так, як я люблю, з простого — напишемо абстрактний клас Entity з прикладом опису властивостей та шаблонами регулярних виразів.


use \Exception\Validation as ValidationException;

abstract class Entity {

    /* Приклад опису властивостей сутності
    protected $propertyExample1Short1 = 'PatternName';
    protected $propertyExample1Short2 = '/^.*$/';
    protected $propertyExampleFull = [
        'pattern' => 'PatternName', // Ключ масиву з необхідним шаблоном або сам шаблон
        'minimum' => 0,             // Мінімальне обмеження для числового значення
        'maximum' => 100,           // Максимальне обмеження для числового значення
        'required' => false,        // Обов'язкова наявність значення [TRUE]
        'value' => 10               // Значення за замовченням
    ];
    */

    protected const PATTERNS = [
        'String'            => '/^.*$/',
        'Float'             => '/^-?(0\.\d*[1-9]\d*|[1-9]\d*(\.\d+)?)$/',
        'Integer'           => '/^(-?[1-9]\d*|0)$/',
        'IntegerUnsigned'   => '/^([1-9]\d*|0)$/',
        'IntegerPositive'   => '/^[1-9]\d*$/',
        'Time'              => '/^\d{2}:\d{2}:\d{2}$/',
        'Date'              => '/^\d{4}-\d{2}-\d{2}$/',
        'DateTime'          => '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/',
        'Title'             => '/^[^\n\r\t]{1,64}$/',
        'Alias'             => '/^[a-z0-9-]{1,64}$/',
        'Description'       => '/^[^\n\r\t]{1,128}$/',
        'Text'              => '/^.{0,8192}$/',
        'Phone'             => '/^\d{10}$/',
        'Domain'            => '/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/',
        'Email'             => '/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/',
        'Path'              => '/^(/[^/ ]*)+/?$/i',
        'Boolean'           => '/^[01]$/'
    ];
}

Спочатку я навів, як шпаргалку, приклад типового опису властивостей сутності та їхні значення в дочірньому класі. Такий класичний підхід, на противагу зберіганню всіх властивостей в окремому масиві, дасть можливість вибірково перезавантажувати деякі властивості в разі успадкування класу. А от значення властивостей записується трохи інакше. Для цього необхідно створити маленьку конфігурацію для автоматичної валідації, у якій визначено, як саме її здійснювати.

Якщо для валідації необхідно тільки звірити нове значення із шаблоном регулярного виразу використовуємо короткий запис значення. У значення властивості необхідно прописати назву ключа масиву константи PATTERNS з необхідним шаблоном або конкретно сам шаблон.

У випадку, коли регулярного виразу для перевірки буде недостатньо, необхідно використати повний запис конфігурації автоматичної валідації у вигляді асоціативного масиву. Більша частина записів конфігурації вказує на те, яку саме перевірку необхідно здійснити з новим значенням перед його збереженням. Це може бути описана вище перевірка за шаблоном (pattern), за числовим обмеженням (minimum та maximum) або за обов`язковою присутністю значення (required). Також у ній можна вказати значення за замовчуванням для властивості (value).

Але якщо й цих перевірок виявиться недостатньо необхідно створити класичні гетери та сетери у вигляді методів із назвою властивості у звичному вигляді getPropertyExample() та setPropertyExample().

Типові валідації

А зараз додамо декілька простих та подібних методів для здійснення перевірок згідно з конфігурацією автоматичної валідації.


protected function isPresent(string $name) {
    if (!isset($this->$name))
        throw new ValidationException(
            sprintf('Невідома властивість "%s" для сутності "%s"', $name, get_class($this))
        );
}

protected function isRequired(string $name) {
    if (!isset($this->{$name}['required']) || ($this->{$name}['required'] !== false))
        throw new ValidationException(
            sprintf('Відсутнє обов`язкове значення (%s->%s)', get_class($this), $name)
        );
}

protected function validateByPattern(string $name, $value, string $pattern) {
    if (preg_match($pattern, $value) != 1)
        throw new ValidationException(
            vsprintf(
                'Значення "%s" не відповідає шаблону "%s" (%s->%s)',
                [$value, $pattern, get_class($this), $name]
            )
        );
}

protected function validateByMinimum(string $name, int $value, int $limit) {
    if ($value < $limit)
        throw new ValidationException(
            vsprintf(
                'Значення "%s" менше дозволеного мінімуму "%s" (%s->%s)',
                [$value, $limit, get_class($this), $name]
            )
        );
}

protected function validateByMaximum(string $name, int $value, int $limit) {
    if ($value > $limit)
        throw new ValidationException(
            vsprintf(
                'Значення "%s" більше дозволеного максимуму "%s" (%s->%s)',
                [$value, $limit, get_class($this), $name]
            )
        );
}

Перший метод необхідний для перевірки присутності властивості в сутності, другий — для перевірки обов’язкової наявності значення властивості. Решта потрібні для перевірки згідно з шаблоном регулярного виразу, числового обмеження згідно з мінімумом або максимумом.

Універсальні гетери та сетери

А зараз додамо в наш клас конструктор для ініціації сутності та універсальні гетери/сетери, які грають роль інтерпретатора для команд керування процесом валідації, записаних у конфігурації властивості.


public function __construct(array $entity) {

    $properties = get_object_vars($this);

    foreach($properties as $name => $value)  {

        if (!is_array($value))
            $this->$name = isset($this->$name) ? ['pattern' => $value] : [];

        if (isset($this->{$name}['pattern']) && (strlen($this->{$name}['pattern']) > 0))
            if (substr($this->{$name}['pattern'],0, 1) !== '/')
                $this->{$name}['pattern'] = self::PATTERNS[$this->{$name}['pattern']];

        if (isset($entity[$name])) {
            $this->set($name, $entity[$name]);
        } else if (!isset($this->{$name}['value'])) {
            $this->set($name);
        }
    }
}

public function get(string $name) {

    $this->isPresent($name);

    $value = $this->{$name}['value'];
    $method = 'get' . ucfirst($name);

    if (method_exists($this, $method))
        call_user_func_array([$this, $method], [&$value]);

    return $value;
}

public function set(string $name, $value = null) {

    $this->isPresent($name);

    if (!isset($value)) {
        $this->isRequired($name);
        $this->{$name}['value'] = null;
        return;
    }

    if (isset($this->{$name}['pattern']))
        $this->validateByPattern($name, $value, $this->{$name}['pattern']);
    if (isset($this->{$name}['minimum']))
        $this->validateByMinimum($name, $value, $this->{$name}['minimum']);
    if (isset($this->{$name}['maximum']))
        $this->validateByMaximum($name, $value, $this->{$name}['maximum']);

    $method = 'set' . ucfirst($name);
    if (method_exists($this, $method))
        call_user_func_array([$this, $method], [&$value]);

    $this->{$name}['value'] = $value;
}

Конструктор здійснює імпорт даних із масиву в сутність з попередньою адаптацією конфігурації валідації. Гетер перевіряє тільки наявність властивості та запускає виконання метода з іменем властивості в разі її наявності. Сетер здійснює послідовні перевірки згідно з конфігурацією автоматичної валідації.

Зверніть особливу увагу на те, що перевірки не виключають одна одну, а доповнюють і ви можете в одній конфігурації використовувати одночасно декілька з них. Уявімо, ніби вам необхідно перевірити, щоби значення властивості було простим числом у певному діапазоні. Тоді ви можете в конфігурації валідації задати шаблон регулярного виразу для перевірки значення на додатне число, потім вказати дозволений числовий діапазон. Після цього написати метод для перевірки чи число ділиться тільки на себе. Усі ці валідації виконаються послідовно.

Користувацькі валідації та модифікації

Наведу декілька прикладів для демонстрації реалізації користувацьких перевірок чи модифікацій за допомогою методів. Доцільність виконання модифікації значення властивості сутності в самій сутності питання доволі неоднозначне. Але я, про всяк випадок, додав таку можливість.


/** @noinspection PhpUnused */
protected function setDateTime(string $value) {

    list($date, $time) = explode(' ', $value);
    list($years, $months, $days) = explode('-', $date);
    list($hours, $minutes, $seconds) = explode(':', $time);

    $this->validateByMinimum('dateTime->years', $years, 2000);
    $this->validateByMaximum('dateTime->years', $years, date('Y'));
    $this->validateByMinimum('dateTime->months', $months, 1);
    $this->validateByMaximum('dateTime->months', $months, 12);
    $this->validateByMinimum('dateTime->days', $days, 1);
    $this->validateByMaximum('dateTime->days', $days, 31);
    $this->validateByMinimum('dateTime->hours', $hours, 0);
    $this->validateByMaximum('dateTime->hours', $hours, 23);
    $this->validateByMinimum('dateTime->minutes', $minutes, 0);
    $this->validateByMaximum('dateTime->minutes', $minutes, 59);
    $this->validateByMinimum('dateTime->seconds', $seconds, 0);
    $this->validateByMaximum('dateTime->seconds', $seconds, 59);

    if ($value != date('Y-m-d H:i:s', strtotime($value)))
        throw new ValidationException(
            vsprintf(
                'Неправильне значення %s (%s->%s)',  [$value, get_class($this), 'dateTime']
            )
        );
}

/** @noinspection PhpUnused */
protected function setImage(string &$value) {

    $value = substr($value, 7);
}

/** @noinspection PhpUnused */
protected function getImage(string &$value) {

    $value = '/images' . $value;
}

Користувацькі перевірки з допомогою методів, які розміщенні в базовому класі, будуть здійснюватись у будь-якому успадкованому класі за наявності однойменної властивості. Тому я додаю тут тільки перевірки для поширених властивостей, а в наслідуваному класі — тільки специфічні для нього.

Успадкована сутність

Нарешті ми підійшли до найцікавішого, заради чого ми все це вище створювали — до автоматизації валідації в успадкованій сутності.


/** @noinspection PhpUnused PhpMissingFieldTypeInspection */

namespace Entity;

use \Entity;

class Article extends Entity {

    protected
        $id             = 'IntegerPositive',
        $dateTime       = 'DateTime',
        $title          = 'Title',
        $description    = 'Description',
        $text           = 'Text',
        $image          = '/^\/images\/articles\/[0-9a-z]{32}\.(jpg|png|gif)$/',
        $alias          = 'Alias',
        $category       = ['pattern' => 'IntegerPositive', 'maximum' => 8],
        $user           = ['pattern' => 'IntegerPositive', 'maximum' => 255],
        $hits           = ['pattern' => 'IntegerUnsigned', 'required' => false, 'value' => 0],
        $comments       = ['pattern' => 'IntegerUnsigned', 'required' => false],
        $location       = ['required' => false],
        $status         = ['pattern' => '/^[012]$/', 'required' => false, 'value' => 1];

    protected function setLocation(string $value) {

        list($latitude, $longitude) = explode(' ', $value);

        $this->validateByPattern('location->latitude', $latitude, self::PATTERNS['Float']);
        $this->validateByPattern('location->longitude', $longitude, self::PATTERNS['Float']);

        $this->validateByMinimum('location->latitude', $latitude, -90);
        $this->validateByMaximum('location->latitude', $latitude, 90);
        $this->validateByMinimum('location->longitude', $longitude, -180);
        $this->validateByMaximum('location->longitude', $longitude, 180);
    }
}

Зверніть увагу, як лаконічно ми описуємо все, що нам необхідно — немає нічого зайвого. Навіть якщо кількість властивостей збільшити в декілька разів сприйматися сутність буде легко та зрозуміло. Також як приклад я додав метод для перевірки значення властивості location. Вона, на відміну від перевірок у батьківському класі, використовується тільки в цьому конкретному класі.

Приклад використання сутності

А зараз ми розглянемо простенький приклад використання сутності з автоматичною валідацією.


use \Entity\Article as ArticleEntity;
use \Repository\Article as ArticleRepository;
use \Exception\Validation as ValidationException;
use \Log\Validation as ValidationLog;

try {

    // Імітація надходження даних з форми
    $article = [
        'id' => 853951,
        'dateTime' => '2020-07-19 20:47:34',
        'title' => 'Заголовок ...',
        'description' => 'Опис ...',
        'text' => 'Текст ...',
        'image' => '/images/articles/a93d205e85f71c4b6c0db6ccef5b8e3d.jpg',
        'alias' => 'zagolovok-tri-krapki',
        'category' => 3,
        'user' => 14,
        'location' => '21.3280193 -157.8691133'
    ];
    dbg($article);

    $articleEntity = new ArticleEntity($article);

    // Імітація роботи зі значеннями властивостей сутності
    dbg($articleEntity->get('hits'), 'hits1');
    $articleEntity->set('hits', 123);
    dbg($articleEntity->get('hits'), 'hits2');

    dbg($articleEntity->get('comments'), 'comments1');
    $articleEntity->set('comments', 5);
    dbg($articleEntity->get('comments'), 'comments2');

    dbg($articleEntity->get('image'), 'image');

    dbg($articleEntity);

    // Приклад подальшого використання сутності
    $mapper = new Mapper();
    $articleRepository = new ArticleRepository($mapper);
    $articleRepository->set($articleEntity);

} catch (ValidationException $exception) {
    /** @noinspection PhpUndefinedFieldInspection */
    echo '<table>' . $exception->xdebug_message . '</table>';
    ValidationLog::addException($exception);
}

function dbg($value, string $name = null) {
    if (is_array($value) || is_object($value))
        $value = '<pre>'. print_r($value, true) . '</pre>';
    echo ((is_null($name)) ? "$value" : "$name = $value") . "<br />\n\r";
}

Спочатку в прикладі створюється асоціативний масив із довільними даними $article, який імітує масив $_POST. Потім створюється об’єкт сутності $articleEntity, у який передається масив зі значеннями для властивостей сутності. Вони відразу, під час створення сутності, проходять обов’язкову автоматичну валідацію та зберігаються. Після цього сутність із даними передається в створений об’єкт $articleRepository для імітації збереження її в БД.

У проміжках між цими операціями, для зручності демонстрації прикладу, виводимо деякі дані за допомогою функції dbg(). Раджу також додатково реалізувати можливість запису в log-файл перехоплених винятків, що виникають під час валідації. Це допоможе ефективніше контролювати процес перевірки та своєчасно виявляти рідкісні помилки.


Array
(
    [id] => 853951
    [dateTime] => 2020-07-19 20:47:34
    [title] => Заголовок ...
    [description] => Опис ...
    [text] => Текст ...
    [image] => /images/articles/a93d205e85f71c4b6c0db6ccef5b8e3d.jpg
    [alias] => zagolovok-tri-krapki
    [category] => 3
    [user] => 14
    [location] => 21.3280193 -157.8691133
)

hits1 = 0
hits2 = 123
comments1 =
comments2 = 5
image = /images/articles/a93d205e85f71c4b6c0db6ccef5b8e3d.jpg

Entity\Article Object
(
    [id:protected] => Array
        (
            [pattern] => /^[1-9]\d*$/
            [value] => 853951
        )
    [dateTime:protected] => Array
        (
            [pattern] => /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/
            [value] => 2020-07-19 20:47:34
        )
    [title:protected] => Array
        (
            [pattern] => /^[^\n\r\t]{1,64}$/
            [value] => Заголовок ...
        )
    [description:protected] => Array
        (
            [pattern] => /^[^\n\r\t]{1,128}$/
            [value] => Опис ...
        )
    [text:protected] => Array
        (
            [pattern] => /^.{0,8192}$/
            [value] => Текст ...
        )
    [image:protected] => Array
        (
            [pattern] => /^\/images\/articles\/[0-9a-z]{32}\.(jpg|png|gif)$/
            [value] => /articles/a93d205e85f71c4b6c0db6ccef5b8e3d.jpg
        )
    [alias:protected] => Array
        (
            [pattern] => /^[a-z0-9-]{1,64}$/
            [value] => zagolovok-tri-krapki
        )
    [category:protected] => Array
        (
            [pattern] => /^[1-9]\d*$/
            [maximum] => 8
            [value] => 3
        )
    [user:protected] => Array
        (
            [pattern] => /^[1-9]\d*$/
            [maximum] => 255
            [value] => 14
        )
    [hits:protected] => Array
        (
            [pattern] => /^([1-9]\d*|0)$/
            [required] =>
            [value] => 123
        )
    [comments:protected] => Array
        (
            [pattern] => /^([1-9]\d*|0)$/
            [required] =>
            [value] => 5
        )
    [location:protected] => Array
        (
            [required] =>
            [value] => 21.3280193 -157.8691133
        )
    [status:protected] => Array
        (
            [pattern] => /^[012]$/
            [required] =>
            [value] => 1
        )
)

Виводимо результат виконання прикладу: дані масиву, деяких властивостей сутності та структура з даними сутності загалом.

Недоліки автоматичної валідації

Перший недолік, який відразу впадає в око, це додаткова складність програмного коду. І це цілком зрозуміло — використання для валідації звичних гетерів та сетерів рішення однозначно простіше та зрозуміліше. До того ж це універсальний підхід, який використовується не тільки в PHP, а й у багатьох інших мовах програмуваннях.

Хоча з іншого боку, складний тут лише базовий клас, а успадковані класи зазвичай суттєво простіші, ніж у класичному підході. Тобто внаслідок ускладнення базового класу, який потрібно вивчити лише один раз, ми значно спрощуємо написання успадкованих класів сутностей.

Як результат першого недоліку автоматично з’являється другий — збільшення часу виконання запиту. Використання наслідування, звернення до декількох методів, перебір даних та з десяток порівнянь явно не пришвидшують його роботу.

Але з іншого боку, валідація необхідна тільки перед записом даних у БД — під час читання вона зайва. А оскільки зазвичай у вебсайтів кількість записів у БД суттєво менша за кількість зчитування з неї, вплив валідації на швидкодію сайту в загальному мінімальний. І чим більше це співвідношення читання/запис, тим більше нівелюється недолік швидкодії. До того ж сам процес запису в БД відбувається довше, ніж читання. А якщо врахувати, що цей запит відбувається через інтернет та додати час завантаження запиту з даними на сервер, то збільшення часу валідації не сильно вплине на загальний час виконання запиту.

Останній недолік — некоректна робота перевірок IDE, якій важко вирахувати правильність написання класу, який створює об’єкт динамічно. Ця проблема легко вирішується за допомогою спеціальних команд у коментарях, які вкажуть IDE, яку частину коду перевіряти не варто. До того ж я глибоко переконаний, що IDE мають підлаштовуватися під програмістів, а не навпаки.

Висновок

Маю зізнатись, що саме цю версію автоматичної валідації я ще не перевіряв на робочому проєкті. Але попередня морально застаріла версія чудово працює на одному моєму маленькому проєкті вже багато років.

І взагалі не варто ставитися до неї як до готового рішення, яке можна без застережень інтегрувати в готовий продукт. Сприймайте її радше як експериментальне дослідження — прототип, розроблений мною для власних потреб. А вам, можливо, доведеться адаптовувати його під себе.

Під кінець статті варто розглянути питання доцільності застосування автоматичної валідації. Якщо у вас маленький проєкт із невеликою кількістю властивостей у сутностях або цих властивостей багато, але вони водночас складні та різні — тоді, вочевидь, використання автоматичної валідації не принесе вам багато користі. З іншого боку, за наявності великої кількості властивостей та в разі їхньої великої подібності — доцільність цілком очевидна. Скажімо так, чим більше властивостей у вашому проєкті та чим більше вони подібні, тим більше користі від використання автоматичної валідації.

LinkedIn

Похожие статьи

Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Розробляю професійні інтернет-видання з нуля без фреймворку та CMS

Господи, він ще й гордиться цим... Ну, тепер, принаймі, зрозуміло звідки у нього ця дічь в голові:-)

А комусь потім то сапортити. Те, скільки його клієнти втрачають коштів, на заміну девелоперів і підтримку його «унікальних» рішень, без матів напевно не описати.

Не перевелись ще кулібіни в країні.

Останні такі динозаври, які публічно ревно відстоювали доцільність розробки без фреймворків купою надуманих аргементів, на моїй пам’яті вимерли десь на початку 2010-их на хабрі.
Але тоді це ще якось можна було пояснити несформованістю галузі, відсутністю в широкому доступі якісної інформації, вузьким колом висококласних спеціалістів, з якими можна проконсультуватися, і т.д.

Але ж не в 2020! Для мене це реально було одкровення.

да, потом эти самописные велосипеды проще выпилить с проекта, чем тонны багов вычищать с них с кучей потерянного времени на рефакторинг, т.к. в «уникальных решениях» почтивсегда нарушены концепции и подходы

Якось мені необхідно було написати класи з багатьма властивостями.
Але мене осяйнула думка про те, що можна значно спростити створення класів

На що тільки люди не ідуть, аби не використовувати православні форми і валідації

Ну, все ж уже давно написано — бери і користуйся. Але ні, треба свій велосипед написати.
Чисто заради спортивного інтересу, щоб розібратися як це можна реалізувати — ок, але практичної цінності в цьому не бачу.

та походу автор темы уже слился) или судорожно рефакторит код для нового валидатора с сорцами на гитхабе и покрытого тестами)

Я, чесно кажучи, взагалі не зрозумів що це було — якийсь дикий поток сознанія, помножений на неймовірну і нічим не підкріпленну пиху автора.

или судорожно рефакторит код для нового валидатора с сорцами на гитхабе и покрытого тестами)

За гроші компанії. Ну не розвитком продукту ж займатись.

Валидация була через регексп, это что за трэш? Чем is_bool не угодило?
Вы в курсе что под капотом регулярок тяжелый конечный автомат? Прогоните миллион циклов на регулярке и через какой-то strcmp хотя бы, а потом жалуются что пхп выедает цпу и надо арендовать мощнее сервера
Тоже самое касается интегеров, есть intval, ctype_digit, которые в сотни раз быстрее работают регулярок и делают идентичное. И домены бывают нелатинские, гуглите IDN. Рекомендую основательно все отрефакторить, прежле чем тащить это в проект. И как это подключать ,непонятно

ну, справделивости ради, валидация формы, даже самой долбанутой, никогда не будет бутылочным горлышком. Ну, конечно, не станем перебором проверять complexity пароля или че-то такое.

Я бачу ви новачок і взагалі нічого не тямите в валідації, не знаєте навіть її основ. Введу вас швиденько в курс справи:

1) Валідація необхідна для перевірки вхідних даних, як правило тих, що вводять користувачі сайтів у формі. Там десь в середньому з десяток змінних (максимум 20-30), які необхідно перевірити. Як ви розумієте про валідацію мільйонів параметрів і мови не йде. Тому швидкодія тут не грає ніякої ролі, про що я згадував в статті.

2) Всі дані з форми пересилаються за допомогою текстового протоколу HTTP і всі значення масиву $_POST, відповідно, будуть мати по замовчуванню тип string. Тому is_bool та подібні їм функції вам абсолютно нічим не допоможуть. Це має знати кожен.

3) Розробники з WHATWG та W3C ввели в стандарт HTML5 підтримку валідації даних форми саме за допомогою регулярних виразів (атрибут pattern). Гадаю там люди розумніші за нас з вами й краще знають як саме проводити валідацію.

Вивчіть спочатку хоча б основи PHP та HTML щоб не писати дурниці в коментарях.

2) Всі дані з форми пересилаються за допомогою текстового протоколу HTTP і всі значення масиву $_POST, відповідно, будуть мати по замовчуванню тип string. Тому is_bool та подібні їм функції вам абсолютно нічим не допоможуть. Це має знати кожен.

Це так. Але можна використати функцію intval.

Розробники з WHATWG та W3C ввели в стандарт HTML5 підтримку валідації даних форми саме за допомогою регулярних виразів (атрибут pattern). Гадаю там люди розумніші за нас з вами й краще знають як саме проводити валідацію.

Я в фронті не дуже шарю, але гуглінг показав:

developer.mozilla.org/...​arn/Forms/Form_validation

«type: Specifies whether the data needs to be a number, an email address, or some other specific preset type.
pattern: Specifies a regular expression that defines a pattern the entered data needs to follow.»

Приклад:

<input type="number" id="number" name="amount" value="1" min="1" max="10">

Тому, може вам теж треба повчити HTML5, і не тулити туди регулярки через pattern без потреби. Якщо є готова функція АПІ для провірки чи це стрінг чи намбер, то треба її брати. Регулярки використовувати лише в крайньому випадку, бо вони складні, повільні і небезпечні.

Усі доступні типи: developer.mozilla.org/...​n/Forms/HTML5_input_types

Я бачу ви новачок і взагалі нічого не тямите в валідації,

Не совсем так, я валидацию держал в руках, когда еще живы били Kohana & CodeIgniter, потом Yii, Симфони, Ларавел. Так что как делается валидация в фреймоврках с мировым успехом, уже видел и испольовал в проектах

Тому швидкодія тут не грає ніякої ролі

1) по поводу как самая простая регулярка можеть уронить существенно производительность www.regular-expressions.info/catastrophic.html
Умножьте количество посетителей на сайте на время выполнения конечного автомата, и у вас будет неплохая загрузка ЦПУ

Тому is_bool та подібні їм функції вам абсолютно нічим не допоможуть. Це має знати кожен.

2) laravel.com/...​x/validation#rule-boolean зачем там тащить движок регулярок для була, когда с фронта бул это максимум 4 варианта «0», «1», «true», «false»

3) Розробники з WHATWG та W3C ввели в стандарт HTML5 підтримку валідації даних форми саме за допомогою регулярних виразів

Валидация на фронте это одно, на бэкенде все данные с фронта должны перевалидироваться все равно, иначе когда сайт поставят на прогон OWASP тестами, где утилита во все запросы фронта начинает вставлять мусорные данные, и смотрит как ответит бэкенд на входящий мусор

Вивчіть спочатку хоча б основи PHP та HTML щоб не писати дурниці в коментарях.

Как бы я уже выучил, и явные ошибки в коде уже вижу беглым взглядом, так как они все типичные

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

list($date, $time) = explode(’ ’, $value);

код может упасть. К сожалению без тестов этого не увидеть

Валідація форми то дійсно чудово, але не самою ж entity, ще й в конструкторі. Сьогодні у вас проста форма x-www-form-urlencoded, завтра ajax + application/json, післязавтра робите інтеграцію з іншими сервісами, і вони вам відправляють date у вигляді timestamp замість Y-m-d. Що будете робити, додавати нові правила в модель? Прокидувати request в модель, щоб розуміти контекст звідки прийшов запит? А якщо там CLI?

У кожному випадку варто створити було б свій маппер raw data -> entity. В мапері лежить відповідний об’єкт валідатора і маппер при створенні entity піклується тим, щоб entity була валідна.

Запихувати валдацію в мапер це наче антипатерн. Валідація має проводитися в контролері. Байдуже яким чином — викликаючи функцію яка збирає мета дані з пропертів, чи функцію, яка приймає конфігурацію в аргументах.

Ну, нажаль в нас кожен сам собі техлід, тому ми фігачимо як вміємо :) Буває і антипатернами. Але навіть я розумію, що пропозиція ТС — рівень джуна, щоб він там про себе не думав.

Вивчіть спочатку хоча б основи PHP та HTML щоб не писати дурниці в коментарях

Вам опытные специалисты указали на недостатки, а вы сразу отправляете учить матчасть их самих, не разобравшись, и не прочитав внимательно документацию.
Если вы на ревью своего кода в команде будете так реагировать, сомневаюсь, что получится долго там продержаться.
На Хабр полно таких статьей выливают, там даже за то, что автор код в зип архиве приаттачил к статье кучу минусов получает, а тут нужно еще потратить какое-то время, чтоб привести в рабочий вид

Як ви розумієте про валідацію мільйонів параметрів і мови не йде. Тому швидкодія тут не грає ніякої ролі, про що я згадував в статті.

Как бы речь и идет о валидации миллионов параметров, или у бека один клиент? Или 100к клиентов с валидацией 10 переменных разве уже не нагрузка? :)

Розробники з WHATWG та W3C ввели в стандарт HTML5 підтримку валідації даних форми саме за допомогою регулярних виразів (атрибут pattern)

А причем тут валидация на клиенте? На клиенте идет валидация только своих данных, а не десятков тысяч клиентов, это чужие ресурсы, за них платить не нужно, там можно позволить избыточность, пока она не напрягает оверхедом юзера.

Гарна стаття. Переважна більша кількість валідацій є стандартними. Відповідно задача автоматизації є розумною.

Проте ділив би валідації принаймні на два типи:
— на фронтенді (наприклад, емейл повинен бути емейлом або значення поля повинно бути між 13 та 19.5)
— на бекенді (наприклад, поле повинно бути унікальним, значення повинно бути в межах min max діапазону іншої змінної)

Деколи також дублювання фронтент валідацій на бекенді. Наприклад, коли потрібно забезпечити взаємодію через API, а не лише чере UI.

Дякую, мій приклад як раз розроблений для бекенду

Деколи також дублювання фронтент валідацій на бекенді.

Деколи?

можливо, має на увазі сінк для складних правил валідації. Мовляв, щоб не писати ідентичний код, давайте запилимо типу-конфіг і для бекенд і для фронтенд валідації. В мене таке було кілька разів, погано закінчувалось, проте аргументи вагомі.

Якщо у вас щось погано закінчувалось це зовсім не означає що і в інших буде так само

звісно. кожен має право особисто попригати по граблях.

ну або розв’язати проблему, яка іншим не піддавалась

На самом деле статья неплохая и довольно четко отвечает на основной вопрос: «Як автоматизувати валідацію даних в PHP». Все эти придирки к коду не имеют никакого смысла, так как он представлен только для иллюстрации главной идеи статьи: для автоматизации валидации нужно добавить её в конструктор и сеттер нужных вам классов.

Дякую! Добре що ви це написали, бо в мене таке враження що я цілий день з ботами переписуюсь :(

Я люблю діставати людей деталями. Он сьогодні клієнта вже дістав.

Здесь всьо нє так однозначна!

А де все однозначно? Життя складне, в ньому є багато різних зацікавлених сторін і в кожного своя правда.

где репозиторий этого проекта, как это юзать, тестить? рипать самому куски кода из статьи и нарезать на файлы?

Який репозиторій? Який проєкт? Прокиньтесь!
Вам показали можливий приклад використання, а ви вже вимагаєте готове рішення.

я хотел взять код и протестировать, а тут оказывается ничего нет, а отправить коммит в гитхаб это целая история. тогда ваш код не имеет практического смысла, если его еще надо самому выдирать из статьи. Посмотрите на на stackoverflow.com — там кидают куски кода с линкой на песочницу, где сразу можно запустить и посмотреть, а что тут смотреть, если код надо еще нарезать по файлам и расфасовывать по неймспейсам. Смысла разбирать очередной велосипед без тестов нет, тем более в этих местах уже есть баги, ответы есть в оф доках)

list($date, $time) = explode(’ ’, $value);
$value != date(’Y-m-d H:i:s’, strtotime($value))
я хотел взять код и протестировать, а тут оказывается ничего нет

Програмний код в статтях на DOU в більшості випадків подається в такому ж вигляді як і в мене. Але ви їм чомусь свої безпідставні вимоги не висуваєте. Цікаво чому?

еще надо самому выдирать из статьи

Це не є готовий продукт, який можна звантажити, встановити та тестувати. Це лише приклад використання, про що я чітко написав в статті та багатьом вашим колегам ботам в коментарях.

Інформацію про незрозумілі для вас команди можете почитати тут:
www.php.net/manual/ru/function.list
www.php.net/...​anual/ru/function.explode
www.php.net/manual/ru/function.date
www.php.net/...​ual/ru/function.strtotime

Це не є готовий продукт, який можна звантажити, встановити та тестувати. Це лише приклад використання, про що я чітко написав в статті та багатьом вашим колегам ботам в коментарях.

Приклад використання, який не можна використати. Клевер! Головне вірити на слово, що приклад хороший і дійсно працює.

Якщо є голова на плечах — розбереться, якщо немає — нічим не можу допомогти.

У вас код не покрыт тестами, если б они были, все баги, которые видны по ходу кода, без тестов не видны. Все эти ссылки я лет 10 назад читал еще, когда 5я пыха была. Просто спорить по доке смысла нет, добавьте тесты и сразу видно будет где посыплятся баги.
Есть категория кодеров — fullstack copy-paste developer, они не думая, берут копипащат код из статьей прямо в проект, после чего куча потраченного время на ревью и на растолковывание ситуаций, когда из копипащеного кода баги пачками начинают сыпаться в нестандартных случаях

github.com/...​tree/7.x/tests/Validation

У вас код не покрыт тестами

В статті наведений простий приклад і якщо вам, щоб його зрозуміти, необхідні тести — пишіть, я не забороняю.

Есть категория кодеров — fullstack copy-paste developer

Я пишу статті для людей які думають головою та за дії ідіотів відповідальності нести не збираюсь. Не перекладайте проблему з хворої голови на здорову.

www.php.net/manual/ru/funcref.php

Класс Article используется только для записи или также при чтении из бд?

Але з іншого боку, валідація необхідна тільки перед записом даних у БД — під час читання вона зайва.

Это понятно, вопрос в том, как вы собираетесь это реализовать, если валидация запускается в конструкторе?

Саме в моєму випадку ввід всіх даних відбувається в адміністративній частині сайту, де необхідна валідація. А стандартний перегляд сторінок сайту відбувається в іншій частині сайту, де використовується зовсім інший програмний код з іншою архітектурою, в якій валідація повністю відсутня. Такий «розподіл обов’язків» дає можливість максимально адаптувати (спеціалізувати) архітектуру під конкретні потреби.

Я думаю Іван хоче запитати, як застосовувати Вашу валідацію при оновленні моделі, якщо валідація запускається в конструкторі.

... прототип, розроблений мною для власних потреб. А вам, можливо, доведеться адаптовувати його під себе.

Так тримати!
Кілька порад (можливо, корисних для вас):
1. Будь-який проєкт починають з аналізу готових розв’язків.
2. Було б непогано навести причини, чому ви вирішили зробити щось своє замість використання готового?
3. Було б непоганим додати порівняльні таблиці швидкості, використання пам’яті з іншими готовими розв’язками.

Дякую за підтримку та поради!

1. Я частенько читаю технічні статті на DOU та не пригадую щоб вони всі починались з аналізу готових рішень.
2. Я люблю складні специфічні проєкти, що потребують індивідуального підходу.
3. Річ у тім, що моя мета робити те, що краще для конкретного проєкту, а не створювати альтернативу наявним фреймворкам для конкуренції з ними.

Тобто в мене зовсім інший підхід, притаманний більш продуктовим компаніям. Але більшість коментаторів, мабуть, із-за своєї аутсорсинг спрямованості, вирішили що я намагаюсь конкурувати з наявними фреймворками чи бібліотеками :(

Маю зізнатись, що саме цю версію автоматичної валідації я ще не перевіряв на робочому проєкті.

і не треба. бо у кожному розвиненому фреймворку не один рік існує.
про ларку та сімфоні вже написали.

yiiframework.com.ua/...​guide/2/input-validation
framework.zend.com/...​dules/zend.validator.html
api.cakephp.org/...​Validation.Validator.html
...

З іншого боку, за наявності великої кількості властивостей та в разі їхньої великої подібності — доцільність цілком очевидна.

коли проект великий, то там проблеми з валідацією по бізнес правилам, а не базовим типам.
а бізнес правила потребують вже ручного кодування.
бо якщо автоматика буде перевіряти:
має оцей клієнт право на отримання знижки, яка надається якщо за останні три місяці
він купував товарів на суму більшу за X, але не враховоуючи акційні товари, або якщо він купував ..., але ...
і це все — запити до БД, які автоматика універсального валідатора зазвичай буде робити вкрай неефективними.

і, у великих проектах валідацію по базовим типам частенько виносять у constraints БД.

А для невеликих — зазвичай достатньо того що пропонує обраний фреймворк.

і не треба. бо у кожному розвиненому фреймворку не один рік існує.

Не всі проєкти пишуться на готових фреймворках. Трапляються такі, на яких необхідна максимальна оптимізація. До того ж цей приклад може бути корисним для тих хто вивчає PHP.

коли проект великий, то там проблеми з валідацією по бізнес правилам, а не базовим типам.

Перевірка по бізнес-логіці, приклад якої ви навели, немає ніякого відношення до теми моєї статті конкретно та до валідації вхідних даних взагалі.

і, у великих проектах валідацію по базовим типам частенько виносять у constraints БД.

А от ця тема мене дуже цікавить, бо потрійна валідація (Front, Back, DB) мені здається надлишковою. Буду дуже вдячний якщо підкажете де можна про це прочитати. Особливо цікавить практичний аспект з точки зору безпеки.

Не всі проєкти пишуться на готових фреймворках

для таких проектів можно обрати тільки компоненту валідації.

Трапляються такі, на яких необхідна максимальна оптимізація

Трапляються.
Але зазвичай такі проети теж не потребують писати базовий функционал.

А от ця тема мене дуже цікавить, бо потрійна валідація (Front, Back, DB) мені здається надлишковою

тобто валідацію пишем тільки одну, скажімо на фронтенді?
і довіряємо тому всьому що з нього прийде? ;)

так що дві — точно буде, у зрілому проекті.

третя виникає у великих проектах, коли декілька аплікацій починають працювати з одними данними.
або декілька команд пише ізольовані модулі.

Особливо цікавить практичний аспект з точки зору безпеки.

тому й три рівня, а не «мені здається надлишковою»

До того ж цей приклад може бути корисним для тих хто вивчає PHP.

це так.

але я б радив вивчати зрілі реалізації

для таких проектів можно обрати тільки компоненту валідації.

Можна, а можна написати самому

Але зазвичай такі проети теж не потребують писати базовий функционал.

Різні проєкти мають різні потреби

тобто валідацію пишем тільки одну, скажімо на фронтенді?
і довіряємо тому всьому що з нього прийде? ;)

Звичайно що мінімум мають бути дві, бо на фронтенді валідацію легко обійти. Це ж очевидно.

тому й три рівня, а не «мені здається надлишковою»

Спочатку ви пишете, що двох може бути достатньо, потім що треба три валідації.
Ви вже визначтесь з цим питанням, це ж важливо для безпеки.

але я б радив вивчати зрілі реалізації

«Hello World» та подібні приклади достатньо зрілі для навчання?
Чи ви пропонуєте PHP вивчати відразу з фреймворка?

Можна, а можна написати самому

все можна написати самому.
зазвичай головна мета — щоб клієнт потім не зміг піти до інших :)

Різні проєкти мають різні потреби

проект повинен задоволняти функціональним вимогам.
якщо це не пет проект :)

Спочатку ви пишете, що двох може бути достатньо, потім що треба три валідації.

ок, перечитую себе:

і, у великих проектах валідацію по базовим типам частенько виносять у constraints БД.
А для невеликих — зазвичай достатньо того що пропонує обраний фреймворк

ви не бачите умови — великі проекти, та невеликі?
чи ви не розумієте слів — частенько ,зазвичай
?

«Hello World» та подібні приклади достатньо зрілі для навчання?

ну, працюю з дітьми, «Hello World» — то перші 15 хвилин 1го заняття.

Чи ви пропонуєте PHP вивчати відразу з фреймворка?

відразу — це коли?
коли й мова программування невідома?

а вчитися завжди краще на зразках доброго коду, аніж вигадувати колесо.

зазвичай головна мета — щоб клієнт потім не зміг піти до інших

Мені дуже шкода, що ви так негарно відноситись до своїх клієнтів.
Ну нехай це буде на вашій совісті :)

проект повинен задоволняти функціональним вимогам.

Ви виграли приз «Пан очевидність» :)

ок, перечитую себе:
так що дві — точно буде, у зрілому проекті.
тому й три рівня, а не «мені здається надлишковою»

Так 2 чи 3? Чи ви навіть в такому простому питанні не можете визначитись?

ну, працюю з дітьми, «Hello World» — то перші 15 хвилин 1го заняття.

А потім відразу переходите на вивчення зрілого мега проєкту в 100500 рядків кода, перевіреного десятиліттями експлуатації?

а вчитися завжди краще на зразках доброго коду, аніж вигадувати колесо.

Всі зразки доброго коду спочатку були колесами, потім велосипедами, а вже потім, з часом, частина з них, що виживала — ставали зрілими. Звичайний еволюційний процес. Людині з вашим досвідом це мало би бути відомо.

Мені дуже шкода, що ви так негарно відноситись до своїх клієнтів.

я клієнтам не втюхую лісапеди.
навпаки, застерігаю від них.
і без цього вийде унікального коду, та інтеграцій існуючих рішень.

Так 2 чи 3?

залежить від вказаних обставин.
мені ще раз звертати на них вашу увагу?

чи ви ще не второпали що срібної кулі не існує?
і нема рецептів яки можна отак взяти і використовувати завжди?

А потім відразу переходите на вивчення зрілого мега проєкту в 100500 рядків кода

звісно ні :)
велика різниця між — програмувати заради задоволення, та професійно.
і навчання програмуванню тому теж — різне.

Всі зразки доброго коду спочатку були колесами, потім велосипедами,

ви написали нікому не потрібне рішення.
тому що воно вже реалізовано у купі що фреймворків, що книжок.

ніякого ноу хау воно не має.
що ви хтіли показати — незрозуміло.

як то кажуть — кожен початківець пише свій логер, парсер json, та ось, валідацію.
і вважає що це якись важливий приклад :)

я клієнтам не втюхую лісапеди.

Я намагався вам пояснити, що в реальному житті неможливо весь час спиратись тільки на готові рішення. Деколи їх потрібно адаптовувати або повністю переписувати й професійні програмісти повинні вміти це робити. Але ви, на превеликий жаль, не в змозі вийти за рамки своїх обмежень. Ну що ж, це не моя провина, я зі свого боку зробив все що міг.

залежить від вказаних обставин.

Вам потрібно навчитись точніше висловлювати свою думку. Бо якщо ви пишете свій код так само незрозуміло як і коментарі — я не позаздрю вашим колегам :)

звісно ні :)

Ну нарешті ви хоч щось визнали :)

ви написали нікому не потрібне рішення

Коли ви висловлюєте свою персональну думку — це нормально, в нас свобода слова і ви маєте на це право. Але коли ви висловлюєте думку за всіх — це манія величі й над цим потрібно працювати :)

ніякого ноу хау воно не має.

Чому обов’язково має бути якесь ноу хау? З якого дива ви мені якісь вимоги висуваєте?

що ви хтіли показати — незрозуміло.

Мені дуже шкода що ви нічого не зрозуміли, але це ваші особисті проблеми й не потрібно їх перекидати на мене.

як то кажуть — кожен початківець пише свій логер, парсер json, та ось, валідацію. і вважає що це якись важливий приклад

Яка вам різниця хто що пише і хто що вважає? Чому вас це так сильно зачіпає? Ви тут з якої сторони?

Читачі, які вважають, що я написав щось неважливе, просто закривають сторінку в браузері та й живуть собі далі. А ви вже довгий час, ледь не з піною у рота, намагаєтесь всім довести що автор неправильний, стаття моя неправильна і код в мене неправильний. Таке враження що ви одержимі мною :)

Таке враження що ви одержимі мною :)

Олімпіада же ж.

Я намагався вам пояснити, що в реальному житті неможливо весь час спиратись тільки на готові рішенн

дякую, дійсно, що мені відомо про реальне життя...

Але ви, на превеликий жаль, не в змозі вийти за рамки своїх обмежень.

так, ви як телепат — все побачили. і мої рішення, і код...
нічого не приховати.

Деколи їх потрібно адаптовувати або повністю переписувати й професійні програмісти повинні вміти це робити

так, так, мені до вас, професійного програміста, ще рости та рости...

Вам потрібно навчитись точніше висловлювати свою думку.

if (проект == ’невеликий’) { }
elseif {проект == ’великий’} { }
else {
// пет проекти, тестові завдання та лаби
}

а может так дойде:
it depends on

Бо якщо ви пишете свій код так само незрозуміло як і коментарі — я не позаздрю вашим колегам :)

так, щиро дякую, мені як тех/тім ліду теж дуже шкода підлеглих.

Яка вам різниця хто що пише і хто що вважає?

яка вам різниця що якісь невігласи та говнокодери тіпа мене щось там пишуть у коментах?

і, у великих проектах валідацію по базовим типам частенько виносять у constraints БД.

Хіба це не default для всіх проектів? Чи на малих роблять усюди тип стрінг текст?) І як валідувати? Кожного разу намагатися засунути в базу і ловити ексепшини від ОРМ? Наскільки мені відомо, обмеження в базах даних це останній рубіж оборони, а не перший. І моделі завжди потрібно валідувати на вході від користувача.

Чи про базу ви за подібне? dev.mysql.com/...​le-check-constraints.html

Таке я ще не писав.

Хіба це не default для всіх проектів?

залежить від бюджету, та часу.

І як валідувати?

а як треба, і скільки це коштує?

Кожного разу намагатися засунути в базу і ловити ексепшини від ОРМ?

тобто ані програміст, ані тестувальники не перевіряють нічого, наприклад що кожного разу буде ексепшн?

Наскільки мені відомо, обмеження в базах даних це останній рубіж оборони, а не перший

про це й написав.
читайте уважніше.

. І моделі завжди потрібно валідувати на вході від користувача.

догми — поганий радник.
звісно дозволяє не включати головний мозок.

і так, у ідеальному світі все нічого не коштує, і там default для всіх проектів безкомпромісний — Ідеал.

Таке я ще не писав.

ну тоді що ви знаєте про default?
буває і на трігери чипляють валідацію, бо складна.

тобто ані програміст, ані тестувальники не перевіряють нічого, наприклад що кожного разу буде ексепшн?

То я й питаю — ставити ексепшн кетчер при записі в базу, і таким чином валідувати правильність даних? І як потім формувати респонс юзеру? Парсити меседжі з ексепшина і підставляти в локалізацію?

догми — поганий радник.

Це не догми, а рекомендації до фреймворків. Робиш байдинг — роби і валідацію до пропертів.

звісно дозволяє не включати головний мозок.

Якщо всюди робити особий путь, то вийде безлад з гівнокодом кожного експерта, рішення якого ніхто не провіряв, але експерт впевнений що це краще за існуючі.

ну тоді що ви знаєте про default?

Я мав на увазі типи даних, а також foreign keys check. Це є дефолт. А вішати на тригери то вже специфічний підхід, який не використовується на кожному проекті. Так як і по дефолту використовувати ОРМ. Ну а валідація повноцінна на стороні бази теж не може бути дефолтом, бо вимагає додаткових затрат часу. Тобто в моєму розумінні дефолт — це щось стандартизоване, яке рекомендується робити у більшості проектах.

о я й питаю — ставити ексепшн кетчер при записі в базу, і таким чином валідувати правильність даних?

як треба — так і робіть

звідки мені знати, як вам треба :)

І як потім формувати респонс юзеру?

залежить від типу помилки.
якщо помилка генерується якоюсь регламентною операцією — то невже це цікаво юзеру?
і як ви йому поясните причину помилки, до якої він не має ніякого відношення?

Якщо всюди робити особий путь,

кожен проект — особий.
інакше би не було потреби починати нові проекти.

Я мав на увазі типи даних, а також foreign keys check.

а я валідацію даних.

Це є дефолт.

foreign keys check — не є дефолт.

Тобто в моєму розумінні дефолт — це щось стандартизоване

дайте лінк на стандартизоване.
почитаю.

а я валідацію даних.

Валідація типу даних — теж свого роду валідація даних. Також валідація зв’язків, теж валідують дані(щоб не вставив неіснуючий айді, чи не видалив без відомості звязаної таблиці. Як і на унікнес теж валідує що вставляєш. Хоча дійсно, валідація конкретних даних, а не їх характеристик, я таке ще не писав, бо не бачив потреби, вся валідація винесена на рівень фреймворку. Але добре мати в базі такі базові речі, щоб випадково не зіпсувати все. Не раз мене спасала провірка по unique keys, показуючи на проблему в коді.

foreign keys check — не є дефолт.

Чому? Якщо дві таблиці зв’язані, вказувати це в ОРМ, яка транслює в sql table creation — є дефолтом.

дайте лінк на стандартизоване.
почитаю.

docs.microsoft.com/...​nding?view=aspnetcore-3.1
docs.microsoft.com/...​ation?view=aspnetcore-3.1

Подібне знаходиться по будь-якому фреймворку. Це те з чого потрібно починати зазвичай, а не писати велосипед.

кожен проект — особий.

Що не значить, що під кожен треба робити на замовлення інструмент. Для цього придумані фреймворки і ліби, що підходять під багато різних проектів.

Чому?

тому що ідентифікація entity може бути хитрішою
тому що обслуговування індексів не безкоштовне
тому що типові маніпуляції даних можуть вимагати тимчасової відмови — у рамках транзакції, від цілісності — і це найчастіший сценарій.
і т.д.

мені невідомо про який проект ви кажете.
не можу знати, як вам треба.
робіть як вам не треба.

вказувати це в ОРМ

не моліться на ОРМ. Вони всі мають фундаментльні дефекти.
Тому ОРМи зазвичай гнучкі, використовуйте їх так як вам треба.
Прикладаючи — голову.

Ну а як не прикладати, то і SELECT N + 1 буде за дефолтом.

Що не значить, що під кожен треба робити на замовлення інструмент.

а я про догматизм: «є Едине Велике Правило котре треба використовувати у кожному проекті!»
дайте лінк та такі правила.

то як пхати патерни ООП, «за дефолтом».
Звісно, ваш проект — робіть як можете та знаєте :)

Для цього придумані фреймворки і ліби, що підходять під багато різних проектів.

про це й відразу написав, що не зрозумів мети автора.

ні, звічно, то добра мета — публікація на профільному сайті.

не моліться на ОРМ. Вони всі мають фундаментльні дефекти.

Я знаю, точніше трохи знаю. Але це найшвидше рішення, і якщо без модифікацій все відповідає вимогам, то залишаю як є. Буду працювати над великим проектом з серйозним навантаженням, то напевно наштовхнуся на необхідність серйозної модифікації фреймворків.

а я про догматизм: «є Едине Велике Правило котре треба використовувати у кожному проекті!»

Зрозумів. Тоді я неправильно висловився. правильно було б — керуйтеся правилом, і лише при реальній необхідності пишіть по-своєму.

то як пхати патерни ООП, «за дефолтом».

Такого дефолту не зустрічав. Точніше деякі патерни, які реалізовані в фреймворках — є дефолтом для тих фреймворків. І нерозумно їх не використовувати. Як от DI.

Звісно, ваш проект — робіть як можете та знаєте :)

Та я не кажу що я істину якусь пишу. звісно мені ще багато нюансів вивчати.

ні, звічно, то добра мета — публікація на профільному сайті.

Добра, але ті програмісти які реально розбираються в написанні подібних ліб — не будуть розбирати роботу автора, бо їм не до того, а от джунів таким чином навчити дурним правилам дуже легко. Тому якщо говорити про несення чогось доброго, то добре б розбирати ті готові ліби, які провірені в боях на тисячах проектів. І можливо тоді вже свій варіант збоку прикладати показуючи плюси і мінуси кожного. Ну це чисто моя віра, хай кожен сам себе фільтрує по своїм догмам.

Для таких випадків я використав «запобіжник» у вигляді конвертації за допомогою функції strtotime у timestamp та назад.

$value = '2019-02-29 20:47:34';
var_dump($value == date('Y-m-d H:i:s', strtotime($value)));  // false

ТС, напиши статтю де розбереш існуючий валідатор з якогось фреймворку з його нутра, і порівняй зі своїм велосипедом показавши на прикладах як оба використовуються і поводяться. Потрібно більше прикладів з реального життя щоб зловити суть. Поки що, мені особисто важкою здається стаття, бо потрібно спочатку сильно влитися в твої абстракції. А було б добре навпаки — навести як оце юзати. Може нам взагалі нецікаво як ти його написав, а цікаво що з цього вийшло. І потім вже подивимося, а що там за тією магією(закинь в репо з один клас один файл).

Це дуже проста стаття з простим кодом та з простим прикладом — там немає що ловити.

Ви мене с кимось сплутали — я не ваш персональний шеф-кухар і замовлень не приймаю. Як вам цікава ця тема, напишіть свою статтю.

там немає що ловити.

Добре, піду далі.

Очень некачественная реализация валидации, впринципе. Полная противоположность тому, как выглядит качественный код на PHP в нынешнее время (как минимум — не соблюдены PSR-ы о code style).
Это не упоминая сам факт изобретения велосипеда с квадратными колесами и без руля.
---

Універсальні гетери та сетери

Наверно автор не в курсе про существование магических методов в ПХП — www.php.net/...​verloading.php#object.get

Цей вид валідації настільки універсальний, що може задовольнити майже всі перевірки.

Интересно, как же регекспом можно проверять тип данных? Или проверять строку чтобы она была валидным JSON’ом?
Это только первое что пришло на ум. В целом, очень голословное заявление — потому что существует очень много кейсов для проверок, где регулярки уже не подойдут.
Кстати, регексп для валидации эмейлов выглядит чуть посложнее: www.ex-parrot.com/...​/Mail-RFC822-Address.html

Зверніть увагу, як лаконічно ми описуємо все, що нам необхідно — немає нічого зайвого.

Это отнюдь не «лаконично» — это ужасно неудобно читать, и ещё сложней вносить сюда изменения. Реализация сама по себе очень примитивная, и полна потенциальных багов при различных corner-кейсах (нет проверки типа данных, привязка к одному-единственному формату даты и времени, итд, даже не буду все видимые косяки перечислять).

Доцільність виконання модифікації значення властивості сутності в самій сутності питання доволі неоднозначне.

Суть ООП в том, что класс — это набор данных, и методы для работы с этими данными. Что тут можеть быть неоднозначного? Налицо что автор не особо знает самую базовую теорию — это видно хотя бы по тому, что наследование классов применяется для простого переиспользования кода.

------

Если по теме, то существует компонент Symfony Validation: symfony.com/...​c/current/validation.html
Это не просто «уже готовая реализация валидации» — это валидация, основанная на Java-стандарте «JSR 303 — Bean Validation» (jcp.org/en/jsr/detail?id=303), который когда-то целая когорта ученых мужей придумала, и много раз проверила на практике.

Я не вижу ничего хорошего в том, чтобы игнорировать наличие полноценной технической спецификации для подобого рода задач — вместо этого втупую делая свою поделку.
Это же время можно было бы потратить на то чтобы _разобраться_ с тем же Симфони Валидейшн — тем более это не самый сложный из его компонентов.

Читаю цей коментар з посмішкою. Як все ж ми легко піддаємося Данінгу-Крюгеру. Велика подяка, Олексій!

В таких історіях підступне те, що більшість вірять «експертам» пропонуючим прості рішення. І їхні рішення дійсно працюють. Але потім, в 1% вистрілює corner case, і ми отримуємо проблеми. І добре якщо це не програмне забезпечення Боінгу, і ніхто не помирає.

Скільки вам заплатили за допомогу в рекламі Symfony? Чи ви безкоштовно?

Оформте ваш валідатор в лібу, завантажте на гітхаб, розрекламуйте якось щоб з’явилися користувачі, зачекайте доки вони виявлять десятки, якщо не сотні issues, пофіксьте їх. І тільки тоді приходьте розказувати як ваш велосипед нічим не гірший за всесвітньо популярні бібліотеки, в сімфоні вони чи ні. Одна справа написати щось для власного проекту під обмежені вимоги, а інша щось, що задовільнятиме потреби багатьох проектів створених багатьма розробниками.

А мені просто здалося, що коментатор вище гарно розбив ваш код декількома прикладами інших вхідних. Особисто я не можу критикувати, бо не прочитав усю статтю, і не спробував на практиці ваш варіант. І також не маю сіньйорського жирного досвіду щоб бачити ці проблеми наперед.

Якщо програмний код не розміщений на гітхабі значить він поганий і не має право на існування. Яволь май фюрер!!!

Якщо програмний код не

протестований на продакшині

значить він поганий

В даному випадку Ви просуваєте код-бібліотеку, і це потребує набагато більшого тестування, аніж власні проекти, аби називатися хорошим.

Що за люди ледачі пішли — та прочитайте нарешті статтю:

І взагалі не варто ставитися до неї як до готового рішення, яке можна без застережень інтегрувати в готовий продукт. Сприймайте її радше як експериментальне дослідження — прототип, розроблений мною для власних потреб. А вам, можливо, доведеться адаптовувати його під себе.

Що я просуваю? Яку бібліотеку? Про що ви взагалі пишете?

Сприймайте її радше як експериментальне дослідження — прототип, розроблений мною для власних потреб.

І навіщо таке публікувати? Мало того що велосипед, так ще й непротестований нормально і з урізаними фічами.

та прочитайте нарешті статтю:

Ні, мені лінь.

І навіщо таке публікувати?

Вибачте, просто я не знав, що мав поцікавитись вашою думкою перед публікацією. Наступного разу я саме так і зроблю.

І навіщо таке публікувати?

Ну, щоб люди прийшли, обісрализауваження озвучили.
Все ж краще, ніж чергова стаття від маркетінг-відділу якоїсь контори. Ну, принаймні, мені це було цікаво прочитати на відміну от.

Я навіть пункт меню додав на днях:
i.imgur.com/jBiDDQE.png

За що велика дяка від авторів технічних статей

Ну свой валидатор данных входит в набор велосипедов, который должен написать каждый кодер, зачем тушить запал? Все же лепили убийц фреймворков, так что... все не без греха :D
В npm вообще десятки аналогов разного качества, и даже самый отстойный велосипед кто-то да качает :)

В npm вообще десятки аналогов разного качества, и даже самый отстойный велосипед кто-то да качает :)

В джаваскриптерів своя атмосфера %)

у меня на проекте прежде чем что-то ставить из npm, либа проходила тщательное ревью — качество кода, активность коммитов на гитхабе, как долго висят открытые ишьюс, ПР. После этого она допускалась в проект, т.к. очень много проблем была из-за того, что npm — большая помойка , где единицы либ качественные

прежде чем что-то ставить из npm, либа проходила тщательное ревью

Ага, вот прям все дерево ее зависимостей? Более менее крупная либа тащит десяток-другой прямых зависимостей, а те... вообщем, все не отревьюрить.

активность коммитов на гитхабе, как долго висят открытые ишьюс, ПР

Так можно долго искать пакеты. Как бы суть опенсорса, что при обнаружении бага в изначально приемлемом и используемом коде, неплохо бы зарепортить и зупушить свой PR- всяко меньше телодвижений, нежели писать свой велосипед.

где единицы либ качественные

В типичных проектах нынче тысячи непрямых зависимостей, так что явно не единицы, но да, в npm куча всего и некоторое совсем не юзабельное — даже без репо, как посмотреть код и дела пакета, без скачки вообще непонятно :) Но с более строгими требованиями, количество пакетов бы знатно просело, а часть с их может дорасти до чего то юзабельного, так что если что менять, то лучше бы npm кнопку избранного добавили и количество звезд :)

Очень некачественная реализация валидации, впринципе. Полная противоположность тому, как выглядит качественный код на PHP в нынешнее время (как минимум — не соблюдены PSR-ы о code style).
Это не упоминая сам факт изобретения велосипеда с квадратными колесами и без руля.

Я бы вам посоветовал воздерживаться от подобных комментариев, если вы хотите работать в команде.

Мне бы хотелось больше подобных статей на DOU. Автору советую не обращать внимание на подобные опусы джунов!

либа должна быть завернута в компосер, добавлены тесты. Без этого — кусок кода, который придется саппортить самому и интегрировать в проект. Нету тестов в сторонней либе — такой либе нечего делать в серьезном проекте на проде

Ще один коментатор, що не прочитав статтю, а вже всіх вчить як має бути:

І взагалі не варто ставитися до неї як до готового рішення, яке можна без застережень інтегрувати в готовий продукт. Сприймайте її радше як експериментальне дослідження — прототип, розроблений мною для власних потреб. А вам, можливо, доведеться адаптовувати його під себе.

Це не ліба, тому їй не потрібен компосер, тести, підтримка та решта. Ні про який продакшн мова не йде і я чітко про це вказав в статті.

Автор делится своим опытом, который оформил в виде статьи. А то, что вы хотите, необоснованные придирки. Пойдите на Medium, HH там подобного море, в этом и заключается ценность данных ресурсов. На medium.com у меня платная подписка, для доступа к подобным статьям.

Дуже вдячний вам за коментар, бо в мене починає виникати враження ніби я в божевільню попав :(

У коментатора настільки примітивні зауваження, що через них чітко проглядаються не тільки низький рівень професіоналізму, а й до того ж його доволі обмежена уява.

не соблюдены PSR-ы о code style

По-перше — це лише рекомендації. По друге — тільки новачки сліпо дотримуються рекомендацій, як солдати діють згідно з уставом в армії. Всі розробники з досвідом виробляють свій стиль написання коду.

Наверно автор не в курсе про существование магических методов в ПХП

Магічні методи в PHP впливають тільки на спосіб доступу і не мають нічого спільно ні з валідацією конкретно, ні з будь-яким функціоналом взагалі. Такі елементарні речі коментатор мав би вже знати.

Интересно, как же регекспом можно проверять тип данных? ...

По-перше, я використав слово «майже», яке ви навели у своєму ж прикладі. По-друге, відразу в наступних параграфах я навожу додаткові рішення, за допомогою яких можна перевірити в т.ч. JSON. По-третє, більшість простих типів даних (string, int, float, ...) можна перевірити як раз тільки за допомогою регулярних виразів. Як можна не розуміти таких простих та очевидних речей?
До речі, прикладів шаблонів для перевірки емейла в інтернеті дуже багато, з яких я обрав той, що зручніший для прикладу в статті. Проблема точності шаблонів регулярних виразів, як коментатор й сам міг здогадатись, виходить за межі даної статті.

Это отнюдь не «лаконично» — это ужасно неудобно читать ...

А ось тут як раз проявляється жахлива обмеженість коментатора: він вивчив лише один спосіб валідації та будь-яке відхилення від нього викликає паніку.

нет проверки типа данных

А ще коментатор дуже неуважний і не помітив в статті приклад перевірки на типи (String, Float, Integer, ...)

привязка к одному-единственному формату даты и времени

А повна відсутність уяви заважає додати перевірки будь-яких форматів дати та часу, які він тільки зможе придумати.

Суть ООП в том, что класс — это набор данных, и методы для работы с этими данными. Что тут можеть быть неоднозначного?

Коментатор вивчив ООП та думає тепер що він все знає і може всіх вчити. Але от до принципів SOLID він ще не дійшов, бо був дуже зайнятий написанням бездарних коментарів. Тоді він би знав що означає буква S в цій абревіатурі, що таке «Принцип єдиного обов’язку» та не писав би такі дурниці.

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

Притягнуті за вуха аргументи у коментатора закінчились і він вимушений переходити на відверту брехню.

Если по теме, то существует компонент Symfony Validation: symfony.com/...c/current/validation.html ...

Ну нарешті ми підійшли до мети памфлету — реклама Symfony.
Тільки в нього одного в жилах тече арійська кров і відповідно тільки він один має право на існування. Всі інші рішення необхідно знищувати. Хайль Symfony!

Всі розробники з досвідом виробляють свій стиль написання коду.

щиро сподіваюсь, що ви то не серйозно

Можливо в якомусь ідеальному світі весь код написаний згідно з одним стандартом, а реальному світі все зовсім по іншому.

Колись було модно не використовувати фреймворки, а писати з нуля на пхп. Кожен тру пхпшник цим мав займатися. Бо профі непотрібні оті фреймворки, профі знає як краще без них! Стандартизація для пролетаріата, а нінджа робить по своєму!

А який фреймворк кращий? В якому стандарти більш правильні?

Будь-який, яким масово користуються на сьогоднішній день.

Тоді він би знав що означає буква S в цій абревіатурі, що таке «Принцип єдиного обов’язку» та не писав би такі дурниці.

От саме S в SOLID нам і говорить, кожен має робити своє. Валідатор — валідувати, модель — моделювати, мапер — мапіти. А у вас модель якась майже божєствєнна вийшла )

Після валідації в тому ж ларавелі оця надлишковість виглядає зовсім непотрібною

Мені в laravel не сподобався метод запису конфігурації валідації в один рядок «’required|unique:posts|max:255’». До того ж ви вважаєте наведену в статті валідацію надлишковою відносно валідації в laravel, а користувачі symfony, в коментарі нижче, недостатньо гнучкою. Все відносно.

Не сподобався — це такий собі аргумент. Можна і як елементи масиву передавати, так красивіше? :)
Якщо я можу щось зробити 5 строчками то для мене це і зручніше і простіше для розуміння, як і думаю для більшості.

Ви в одному коментарі створили «логічний парадокс»: спочатку нівелювали мої вподобання як аргумент, а потім використали як аргумент свої вподобання :)
Таке враження ніби вам хтось щось нав’язує або ображає ваші вподобання, а це зовсім не так.
В даній ситуації більшість не повинна домінувати над меншістю, хто б ким не був, та вказувати що їм використовувати.

В статье проделана большая работа, но чувствуется попытка сделать валидацию как в симфони, но на свой лад и менее гибко

Ничего не понимаю в РНР, но на вид — лисапет. Например, в Джаве готовых лисапетов целый гараж, на любой вкус. Подключил и пользуйся.

Та всюди їх багато. І коли пишеш свій, то треба публікувати його в пакейдж менеджері, і рекламувати, щоб потім бачити — а чи дійсно твій велосипед чимось хороший. Чи може він нафіг нікому не здався, та ще й нікуди не годиться далі твого вузького scope.

Рекламувати можна різними способами, а не тільки пакейдж менеджері.

Вважаєте хтось буде вручну встановлювати ваш велосипед, позбавляючи себе можилвості автоматичного оновлення, фіксів, і підтримки комюніті?

Вам мед та ще й ложку. Я тільки навів в статті приклад можливого використання автоматичної валідації, а ви вже хочете автоматичне оновлення, фікси та підтримку.

Окей. Залиште свій велосипед з круглою рамою і квадратними колесами собі.

велосипед з круглою рамою і квадратними колесами

Ви щось підозріло часто використовуєте слово «велосипед».

«Повторюйте брехню досить часто, і вона стане правдою», — ці слова приписують керівнику нацистської пропаганди Йозефу Геббельсу. У сучасній психології такий ефект отримав назву «ілюзія істини».

www.bbc.com/...​_the_illusion_of_truth_vp

«велосипед» — функціонал, що розроблений власними руками, причому його можливості повторюють існуюче рішення. Дуже здивуюсь, якщо в вас інше розуміння цього терміну. І також я не бачу нічого поганого ані в слові, ані в самописних рішеннях. Дивно, що воно вас аж так дратує.

Мене дратує не слово, а те як його використовують.

Чи правильно я зрозумів, що згідно з вашим визначенням, наприклад такі проєкти як Facebook, Twiter, Instagram та інші є «велосипедами», бо на момент їх створення вже існували соціальні мережі з подібним функціоналом?

вперше бачу, щоб «велосипед» використовували на адресу платформи, сервіса, продукту, де унікальність взагалі не обов’язкова. На відміну од процесів, маркетингу, бізнес-моделі, команди.

Зазвичай, «велосипед» стосовно патерну, бібліотеки. Принаймні, лиш так бачу.

Хоча, якщо хочется — то не можу завадити :)

Це як використати слово «змінна» стосовно думок. Наче і ніхто не забороня, але який сенс?

Ця стаття може вам допомогти розширити світогляд по цьому питанню:
skillbox.ru/...​e/izobretayte_velosipedy

Я робив валідацію, про що згадував в статті, яка б максимально підійшла під мої потреби, а не була б на когось схожа. В symfony валідація суттєво універсальніша, відповідно набагато більша, як наслідок — надлишкова для мене. До речі, користувачі laravel, в коментарі вище, вважають мій варіант занадто надлишковим. Все відносно.

Цивілізація загине, коли у велосипеда з′явиться в прототипі метод винайти велосипед

Я намагаюсь не використовувати те, що немає практичної цінності для проєкту

Подписаться на комментарии