أساسيات التحقق من الصحة المخصصة في Symfony 4/5 مع أمثلة

في Symfony ، في رأيي ، وظيفة مريحة للغاية للتحقق من الكيان. على وجه الخصوص ، فإن استخدام تنسيق التعليقات التوضيحية لتكوين قواعد التحقق من الصحة يرشوني حقًا. في الغالبية العظمى من المهام ، تغطي الحلول الجاهزة الحالات القياسية. ولكن ، كما تعلم ، فإن التحقق من الصحة مسألة دقيقة ، ولا تعرف أبدًا القيود التي سيتعين عليك فرضها هذه المرة. من ناحية أخرى ، سيساعد التحقق من المرونة والمدروس جيدًا دائمًا على تجنب أخطاء المستخدم.


بموجب هذا الخفض ، أدعوك إلى معرفة مدى سهولة كتابة القيود الخاصة بك وتوسيع المقارنات بين حقلين متاحين باستخدام مثال التحقق الأساسي والتحقق. قد تكون المقالة ذات أهمية لأولئك الذين لا يزالون على دراية قليلة بالتحقق في Symfony أو الذين تجاوزوا إمكانية كتابة أدوات التحقق الخاصة بهم.


في هذه المقالة سنضع في الاعتبار السياق الكلاسيكي للتحقق. هناك كيان معين ، يتم ملء البيانات عليه من النموذج المقابل ، بينما يفرض التحقق من الصحة قيودًا على أي جانب من جوانب البيانات المدخلة. تجدر الإشارة إلى أنه يمكن استخدام أدوات التحقق بدون قيود للتحكم في المنطق الداخلي والتحقق من واجهة برمجة التطبيقات وما إلى ذلك.


نحدد على الفور أن الأمثلة المقترحة ليست هي الحلول الممكنة الوحيدة ولا تدعي الحد الأقصى من المثالية أو الاستخدام المكثف ، ولكن يتم تقديمها لأغراض التوضيح. من ناحية أخرى ، يتم أخذ أجزاء من الأمثلة وتبسيطها من المشاريع القتالية ، وآمل أن تكون مفيدة في توضيح بساطة كتابة عمليات التحقق المخصصة دون انقطاع عن الواقع.


التحقق الأساسي


من أجل التحقق من صحة وظيفية كاملة ، تحتاج إلى إنشاء فئتين فقط - ورثة Constraint و ConstraintValidator. القيد ، كما يوحي الاسم ، يحدد ويصف القيود ، بينما يتحقق ConstraintValidator من هذه القيود. على سبيل المثال ، سنكتب مدققًا للوقت بتنسيق "hh: mm" المخزن بتنسيق نص. في الوثائق الرسمية ، يقترح أن يصف القيد الممتلكات العامة للقيد. لنفعلها اذا.


namespace App\Custom\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 * @Target({"PROPERTY"})
 */
class TextTime extends Constraint
{
    public $message = '  ';
}

هنا ، يحدد التعليق التوضيحي للهدف ما إذا كان سيتم استخدام التحقق: لخاصية أو لفئة. يمكنك أيضًا تعيين هذه المعلمة عن طريق تجاوز الوظيفة.


public function getTargets()
{
    //   self::CLASS_CONSTRAINT
    return self::PROPERTY_CONSTRAINT;
}

يتم استخدام خاصية الرسالة ، كما قد تخمن ، لعرض معلومات حول خطأ التحقق من الصحة.


, .


public function validatedBy()
{
    return \get_class($this).'Validator';
}

, , ConstraintValidator. ConstraintValidator validate.


namespace App\Custom\Constraints;

use Symfony\Component\Validator\ConstraintValidator;

class TextTimeValidator extends ConstraintValidator
{
    /**
     *    
     *
     * @param mixed $value  
     * @param Constraint $constraint   
     */
    public function validate($value, Constraint $constraint)
    {
        $time = explode(':', $value);

        $hours = (int) $time[0];
        $minutes = (int) $time[1];

        if ($hours >= 24 || $hours < 0)
            $this->fail($constraint);
        else if ((int) $time[1] > 60 || $minutes < 0)
            $this->fail($constraint);
    }

    private function fail(Constraint $constraint) 
    {
        $this->context->buildViolation($constraint->message)
            ->addViolation();
    }
}

, , , .


...
    /**
     * @Assert\NotBlank()
     * @Assert\Regex(
     *     pattern="/\d{2}:\d{2}/",
     *     message=" "
     * )
     * @CustomAssert\TextTime()
     * @ORM\Column(type="string", length=5)
     */
    private $timeFrom;
...

, , . , , , message .


. , Symfony Time. : . , "hh:mm:ss". , .



, , - . , , : "hh:mm", "hh:mm"-"hh:mm". , , .


, AbstractComparsion. AbstractComparsion Constraint — .


namespace App\Custom\Constraints;

use Symfony\Component\Validator\Constraints\AbstractComparison;

/**
 * @Annotation
 * @Target({"PROPERTY"})
 */
class TextTimeInterval extends AbstractComparison
{   
    public $message = '       {{ compared_value }}.';
}


namespace App\Custom\Constraints;

use Symfony\Component\Validator\Constraints\AbstractComparisonValidator;

class TextTimeIntervalValidator extends AbstractComparisonValidator
{
    /**
     *       
     *
     * @param mixed $timeFrom   
     * @param mixed $timeTo   
     *
     * @return  true   , false 
     */
    protected function compareValues($timeFrom, $timeTo)
    {
        $compareResult = true;

        $from = explode(':', $timeFrom);
        $to = explode(':', $timeTo);

        try {
            if ((int) $from[0] > (int) $to[0])
                $compareResult = false;
            else if (((int) $from[0] == (int) $to[0]) && ((int) $from[1] > (int) $to[1])) {
                $compareResult = false;
            }
        } catch (\Exception $exception) {
            $compareResult = false;
        }

        return $compareResult;
    }
}

في هذه الحالة فقط (أحد التطبيقات الممكنة) ، تجاوزنا دالة CompareValues ​​، التي تُرجع صواب / خطأ في نجاح التحقق وتتم معالجتها في AbstractComparisonValidator بواسطة وظيفة التحقق ().


يتم وصف هذا بشكل أساسي على النحو التالي


...
 /**
     * @Assert\NotBlank()
     * @Assert\Regex(
     *     pattern="/\d{2}:\d{2}/",
     *     message=" "
     * )
     * @CustomAssert\TextTime()
     * @CustomAssert\TextTimeInterval(
     *     propertyPath="timeTo",
     *     message="       "
     * )
     * @ORM\Column(type="string", length=5)
     */
    private $timeFrom;

    /**
     * @Assert\NotBlank()
     * @Assert\Regex(
     *     pattern="/\d{2}:\d{2}/",
     *     message=" "
     * )
     * @CustomAssert\TextTime()
     * @ORM\Column(type="string", length=5)
     */
    private $timeTo;
...

نأمل أن يكون هذا التحليل الصغير والأمثلة قد أظهرت مدى سهولة استخدام أدوات التحقق المخصصة. نظرًا لأننا في البداية اعتبرنا أبسط أدوات التحقق ، بالطبع ، حتى لا نفرط في تحميل العرض التقديمي بأوصاف الموضوع ، فشلنا في تقديم أمثلة استثنائية. أخطط في المقالات المستقبلية للنظر في المصادقات الأكثر تعقيدًا وحالات محددة.


All Articles