Walidacja w Symfony

0

Witam,
od pewnego czasu realizuje pewien projekt przy pomocy frameworka "Symfony 4". Po raz kolejny w wyżej wymienionym projekcie spotykam się z problemem walidacji. Pierwszy problem polegał na tym, iż zadeklarowane za pomocą adnotacji w encji walidatory uruchamiały się nawet w przypadku gdy podanego pola nie było w input formie. Ten problem udało mi się obejść za pomocą grup np.

 /**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(groups={"register", "password_reset"})
     * @AcmeAssert\ContainsAlphanumeric(groups={"register", "password_reset"})
     */
    //
    private $password;

Za drugim razem problem dotyczył plików podpiętych do encji np. zdjęć do użytkownika, gdzie zgodnie z dokumentacją chciałem, aby w pole image było typu string i zapisywało w bazie danych tylko nazwę i rozszerzenie obrazu. Jednak pomimo, iż w dokumentacji korzystano z Assert/File w ten sposób:

/**
     * @ORM\Column(type="string", length=255, nullable=true)
     *@Assert\File(mimeTypes={ "image/png", "image/jpeg"})
     * 
     */
    
    private $image;

To znów pojawił się problem, iż przy zapisie danych do bazy wszystko było w porządku, lecz przy próbie edycji za każdym razem gdy tylko wcześniej zostało ustawione jakieś zdjęcie, pomimo iż wartość mapped została ustawiona na false ciągle wyłapywał że wartość pola to przykładowo "nazwa.jpg" a nie plik.

$image = $loggedUser->getImage();


        $form =  $this->createFormBuilder($loggedUser)
        ->add('email', EmailType::class, array('attr' => array('class' => 'email-form', 'placeholder' => 'E-mail' ),'label' => false))
        ->add('imageF', FileType::class, array('mapped' => false, 'data_class' => null, 'required' => false, 'attr' => array('class' => 'image-form'),'label' => false))
        ->add('save', SubmitType::class, array('label' => 'Change'))
        ->getForm();

To mi się udało obejść może niezbyt ładnie za pomocą zakomentowania Assert/file i stworzenia w klasie obsługującej upload zdjęć funkcji validate:

public function validateFile(UploadedFile $file)
   {

        $ext = $file->guessExtension();
        $conditions =['png', 'jpg', 'jpeg'];
        if(in_array($ext,$conditions) )
        {
            //$iniVal = ini_get('upload_max_filesize');//2mb
            //$mbSize = str_replace('M', '', $iniVal);
            $byteSize = $this->maxSize * 1048576;
         if ($file->getSize() < $byteSize) {
            return true;
            }
            throw new Exception("Your file its too large!!");
            
        }

        throw new Exception("Wrong extension file!!");
        
   }

Jednak teraz mam kolejny problem, ponieważ chcę za pomocą formularza umożliwić zmianę hasła i walidacja działa tylko wtedy gdy stworzę nowy obiekt klasy User ($user= new User ()) co według mnie jest głupie żeby tworzyć nowy obiekt tylko po to by przetestować poprawność wprowadzonego hasła (pomijając już fakt że musiałbym każde inne pole typu username, e-mail itp znów wyłączać dla danej operacji). Za to jeśli próbuję do formularza wrzucić dane danego użytkownika,którego hasło ma ulec zmianie to walidacja hasła w ogóle nie działa. Poniżej kod operacji zmiany hasła:

 public function userPassReset(Request $req,Crypt $cryp,Register $reg, $token)
    {

        $crname = $cryp->decrypt($token);
            
        $user_rep = $this->getDoctrine()->getRepository(User::class);
        $user = $user_rep->findOneBy(['username' => $crname]);

        
        $form =  $this->createFormBuilder($user)
        ->add('password', RepeatedType::class, array(
                'type' => PasswordType::class,
                'first_options'  => array( 'attr' => array('placeholder' => 'New Password'), 'label' => false),
                'second_options' => array('attr' => array('placeholder' => 'Repeat Password' ),'label' => false),
                'error_bubbling' => true
            ))
        ->add('save', SubmitType::class, array('label' => 'Change'))
        ->getForm();

        $form->handleRequest($req);

        if($form->isSubmitted() && $form->isValid())
        {
            
        
            $reg->newPass($user, $form['password']->getData());
            

           //return $this->redirectToRoute('login');

        }

/// i funkcja newPass
 public function newPass($user, $newPass)// change pass after reset
   {

        $user->setPassword(
            $this->passwordEncoder->encodePassword($user, $newPass)
             );
        $this->om->persist($user);
        $this->om->flush();

   }

Czy istnieje jakieś lepsze rozwiązanie np. poprzez zdefiniowanie warunków walidacji wewnątrz formularza lub w jakiś inny bardziej przyjazny sposób?? Pytam tutaj, ponieważ od dłuższego czasu próbuję coś lepszego znaleźć, lecz póki co bez skutecznie. Z góry bardzo dziękuje za wszystkie rady.
Pozdrawiam Krzysztof

1

Tak, możesz definiować walidację w formularzach. Ale zdecydowanie częściej robi się ją w samej encji. Możesz np. w encji zostawić główną walidację (reguły, które zawsze będą potrzebne, np. notBlank, itp.), a w formularzu dodać walidację dostosowaną do aktualnego przypadku.

Z tego, co widzę, to robisz chyba źle. Powinieneś mieć osobne pole dla plain password, i osobne, które przechowuje już zahashowane hasło w bazie.

Np. coś takiego:

/**
     * @Assert\NotBlank()
     */
    private $plainPassword;
    /**
     * @Assert\NotBlank()
     * @SecurityAssert\UserPassword()
     */
    private $oldPassword;
    /**
     * @ORM\Column(type="string", length=64)
     */
    private $password;

Przejrzyj sobie: https://symfony.com/doc/current/doctrine/registration_form.html

0
serek napisał(a):

Tak, możesz definiować walidację w formularzach. Ale zdecydowanie częściej robi się ją w samej encji. Możesz np. w encji zostawić główną walidację (reguły, które zawsze będą potrzebne, np. notBlank, itp.), a w formularzu dodać walidację dostosowaną do aktualnego przypadku.

To by było coś czego szukałem, a można poprosić o jakiś przykład jak to zdefiniować wewnątrz formularza?? Wtedy, gdy dam w encji dla np. username-'notBlank' i stworzę formularz bez pola username to i tak muszę zdefiniować grupę dla username by się nie czepiał, że jest pusty?? Dobrze rozumiem?

Już widzę w linku od ciebie jak dodać walidację wewnątrz formularza, a co do tworzenia pola w encji z niezahashowanym hasłem to nie stanowi to zagrożenia dla bezpieczeństwa potencjalnego użytkownika?? Do tej pory myślałem, że tak się nie powinno właśnie robić ;/

0
kris016 napisał(a):

Już widzę w linku od ciebie jak dodać walidację wewnątrz formularza, a co do tworzenia pola w encji z niezahashowanym hasłem to nie stanowi to zagrożenia dla bezpieczeństwa potencjalnego użytkownika?? Do tej pory myślałem, że tak się nie powinno właśnie robić ;/

Nie, to jest ok. Tak czy siak przechowujesz i przesyłasz niezahashowane dane najpierw. Jeśli chcesz by było bezpieczne przesyłanie hasła, to użyć musisz SSLa. A plainowe pola powinno się wyczyścić po zakończeniu akcji. Czyli wywołujesz sobie taką metodę w encji User:

public function eraseCredentials()
    {
        $this->plainPassword = null;
        $this->oldPassword   = null;
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1