• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Symfony validacja nie przesłanego pola

VPS Starter Arubacloud
+1 głos
329 wizyt
pytanie zadane 16 września 2020 w PHP przez Klik Obywatel (1,540 p.)
edycja 17 września 2020 przez Klik

Witam.

Przepisuję projekt z Laravela na Symfony 5 i natrafiłem na taki mały szkopuł.

Stworzyłem ręcznie formulrz w html, który posiada jedno pole typu checkbox. A checkboxy w formularzu zachowują się tak że gdy nie są zaznaczone to nie jest nawet wysyłane na serwer.

Więc moja ręczna walidacja cały czas rzuca mi błędem że tego pola brakuje.

Czy jest jakaś "constrain" w symfony która pozowli mi w przypadku braku tego pola rzucić komunikatem "Że to pole musi być zaznaczone"? Albo przepuścić ten formularz że to pole nie jest wymagane i zwalidować poprawnie?

Input w formularzu:

 <input type="checkbox" id="regulation" name="regulation" class="form-control">

Constrains

 'regulation' => [
                    new NotBlank(['message' => 'aaaaaaaa']),
                    new NotNull(['message' => 'cccccc']),
                ]

I validacja w kontrolerze:

$validator->validate($request->request->all(), $constrains);



Dziękuję.

komentarz 16 września 2020 przez VBService Ekspert (251,270 p.)

Może użyj: <input type="checkbox" ... requiredwink

komentarz 17 września 2020 przez Klik Obywatel (1,540 p.)
Tak, to niby rozwiązuje problem ale nie odpowida na moje pytanie :)

1 odpowiedź

0 głosów
odpowiedź 16 września 2020 przez Assasz Nałogowiec (30,460 p.)
komentarz 17 września 2020 przez Assasz Nałogowiec (30,460 p.)

Domyślną wartością checkboxa jest string "on", także nie wiem, dlaczego miałby być on rzutowany na boola. Masz dwie opcje, albo na serwer przychodzi "regulation": "on" albo nic. Zakładam, że próbowałeś dumpować zawartość requesta.

Ja bym taką walidację napisał z użyciem DTO:

final class InputDto
{
    /**
     * @Assert\NotNull(message="Ta wartość nie może być pusta.")
     */
    public ?string $regulation;

    public static function fromRequest(Request $request): self
    {
        $self = new self();
        $self->regulation = $request->request->get('regulation', null);

        return $self;
    }
}

// potem w kontrolerze

/** @var ValidatorInterface $validator */
$validator->validate(InputDto::fromRequest($request));

W przypadku braku wartości "regulation" w requescie, własność "regulation" w DTO będzie nullem. To ztriggeruje NotNull i wywali komunikat.

Możesz również przerobić swojego checkboxa, aby wysyłał boola:

<input type="checkbox" id="regulation" name="regulation" class="form-control" value="1">

Wtedy w DTO:

final class InputDto
{
    /**
     * @Assert\IsTrue(message="Ta wartość nie może być pusta.")
     */
    public bool $regulation;

    public static function fromRequest(Request $request): self
    {
        $self = new self();
        $self->regulation = $request->request->getBoolean('regulation', false);

        return $self;
    }
}

Przykład z adnotacjami, ale możesz równie dobrze użyć XMLa albo Yamla (co jest nawet lepsze). Pytanie, czy Twój walidator też jest dobrze skonfigurowany. Jeśli chcesz korzystać np. z adnotacji, musisz je włączyć w konfiguracji:

# config/packages/framework.yaml
framework:
    validation: { enable_annotations: true }

Możesz też przepisać to na Symfony Forms jak zasugerował Boswell ;)

Jeśli nadal nic z tego nie działa, to możesz mi wysłać link do repo (jeśli jest publiczne) i mogę w wolnej chwili rzucić okiem na szerszy kontekst, może coś zobaczę.

komentarz 17 września 2020 przez Klik Obywatel (1,540 p.)

Ale zachodu żeby jeden checkbox z validować :). Strach pomyśleć co będzie jak będę chciał jakiś bardziej skomplikowane rzeczy zwalidować.

Co do tego "on" to racja, ale miałem na myśli szerszy kontekst. Że jak przypiszę value="1" to też twierdzi że to nie jest bool. Jak przypisałem wartość value="true" to też twierdzi że to nie jest bool.

Zrobiłem test. Utworzyłem, nowy input typu number i przesyłam tam jakąś liczbę np. 10. W celu walidacji. 

'numreg' => [
                    new Negative(['message' => "Nie większe"]),
                    new Type(['type' => 'integer', 'message' => 'to nie int'])
                ]

I cały czas dostaje błąd że nie jest int. I dlaczego?

Jeszcze raz napiszę że to wszystko jest ręcznie zrobione bez użycia annotacji czy form.

Czyli co cała ta validacja to działa poprawnie tylko z dowma najgorszymi rzeczami w całym symfony (annotacje i symfony forms)?

Wrzucę to później do repo i podeślę linka. 

Dzięki

komentarz 17 września 2020 przez Klik Obywatel (1,540 p.)
komentarz 17 września 2020 przez Assasz Nałogowiec (30,460 p.)
edycja 17 września 2020 przez Assasz

W żądaniu zawierającym przesłany formularz zawsze dostajesz stringi (inputy są tekstowe, również checkbox). To już Twoja rola (albo Symfony), aby to rzutować na typy. Jak napisałem wyżej:

$self->regulation = $request->request->getBoolean('regulation', false);

$request->request->get('regulation') zwróci stringa, ponieważ w żadaniu nie ma 1, tylko "1" (zakładając, że wysyłasz taką wartość).

$request->request->getBoolean('regulation', false) spróbuje zrzutowac Twojego stringa na boola, czyli wysyłając "1" dostaniesz true. W przypadku braku wartości zwracany jest false (drugi argument).

(Swoją drogą, IsTrue akceptuje nie tylko true, ale również 1 oraz "1". Aczkolwiek akceptuje również wartość pustą, więc nie tędy droga.) 

Dlatego też napisałem, że zrobiłbym to przez DTO. Ponieważ konkretnie określam, jakie wartości potrzebuję z Requesta oraz jakiego typu mają być (w przypadku braku wartości w żądaniu przypisuję wartość domyślną - null albo false) - Ty po prostu przekazujesz parameter bag requesta ($request->request->all()) do walidatora.

Kod z repo obejrzę potem - jak będę się nudził, to sobie sklonuję i popatrzę "na żywo" ;)

komentarz 18 września 2020 przez Klik Obywatel (1,540 p.)
edycja 18 września 2020 przez Klik
Przeanalizowałem sposób validacji "Type" i już wiem dlaczego mi rzuca błędem przy sprawdzaniu typu "int, integer" że "10" to nie liczba. Podobnie dla bool, "true" i "1", też rzuca błędem.

Wszystko przez to że jest wykonywane proste sprawdzanie funkcjami "is_int" lub "is_bool".A te funkcje aby zwrócić true oczekują dokładnie takich typów na jakich jest robiony test.

Dziwne jest to że mając validację gdzie sprawdzam czy dany zmienna jest typem int nie jest wykonywana próba rzutowania zmiennej na wymagany typ. Tak to jest właśnie robione w Laravel. I to ma sens. I co lepiej na wyniku walidacji otrzymujemy już gotowe zmienne danych typów.

A tutaj co, zanim prześlę dane do walidacji powinienem wszystkie wartości próbować z konwertować na oczekiwane w walidacji typy. Bardzo to bez sensu.

Zgaduję że jeśli bym to zrobił na assercjiach obiektów to w jakiś magiczny sposób by to działało?

Najwyżej zostaje napisanie własnej klasy validującej.

 

Zostaje jeszcze tylko jeden problem. Jak zabezpieczyć validator aby nie rzucał błędem gdy jakiś parametr nie jest wymagany i nie zostanie przesłany. A w wypadku przesłania to zwalidować według wybranych parametrów. Chyba że zostaje tylko DTO.

Dziękuję.

Podobne pytania

0 głosów
1 odpowiedź 186 wizyt
pytanie zadane 14 grudnia 2017 w PHP przez Smatix Obywatel (1,050 p.)
0 głosów
1 odpowiedź 220 wizyt
pytanie zadane 11 lutego 2022 w PHP przez Moonmaker05 Początkujący (410 p.)
0 głosów
1 odpowiedź 138 wizyt

92,455 zapytań

141,263 odpowiedzi

319,099 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...