Symfony, user registration

Регистрация, часть 2. Валидация

Каким бы удобным и интуитивно понятным ни был бы интерфейс, пользователь все равно введет в поле email свои паспортные данные, а в пароль с подписью «не менее 7 символов» вставит слово «семь». Как им можно верить? - никак, поэтому валидация наше все. Подключается рецептом composer require validator.

Существует несколько вариантов валидации (подробнее здесь), каждый из которых применим под конкретный сценарий. Мы рассмотрим вариант с валидацией свойств класса, как самый простой и удобный в нашем случае.

        
    /**
     * @Assert\NotBlank()
     * @Assert\Length(min=3)
     * @Assert\Email(message = "The email '{{ value }}' is not a valid.")
     * @ORM\Column(type="string", length=255)
     */
    private $email;
        
    

В примере выше свойству $email заданы следующие правила валидации:

Свойству $plainPassword (напомню, именно его будем выводить в форме) так же присвоим валидаторы:

        
    /**
     * @Assert\NotBlank()
     * @Assert\Length(min=6)
     */
    private $plainPassword;
        
    

Самому классу User добавим аннотацию UniqueEntity, которая поможет нам сохранять в базу только пользователей с уникальным email.

        
    /**
     * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
     * @UniqueEntity(fields="email", message="Email already taken")
     */
        
    

На текущий момент класс User должен выглядеть следующим образом: Local server run

Создание формы

Ранее мы уже создавали форму добавления новости. В данном случае отличия будут только на уровне сущности. Откроем консоль и инициируем работу генератора php bin/console make:form. Local server run На данном этапе нам потребуются только $email и $plainPassword, поэтому оставшиеся поля закомментируем, а password заменим на plainPassword. Local server run Теперь нам надо убедиться, что в email будет записан именно почтовый адрес, а пароль будет "засекречен звездочками". Для этого обновим форму, изменив билдер на следующий код:

                    
    $builder
        ->add('email', EmailType::class)
        ->add('plainPassword', RepeatedType::class, [
            'type' => PasswordType::class
    ])
                    
        

Обратите внимание на namespase:

                    
        use Symfony\Component\Form\Extension\Core\Type\EmailType;
        use Symfony\Component\Form\Extension\Core\Type\PasswordType;
        use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
                    
        

RepeatedType продублирует поле ввода пароля для пользователя и сравнит его с оригиналом.

Создание контроллера

Генерируем контроллер php bin/console make:controller. Local server run Обновляем action. Многое вам уже знакомо из урока по созданию новости, разве что шифрование пароля в новинку. В этом нам помогает UserPasswordEncoderInterface и его метод encodePassword.

                    
    /**
     * @Route("/register", name="register")
     */
    public function registerAction(Request $request, UserPasswordEncoderInterface $passwordEncoder)
    {
        // 1) создаем форму
        $user = new User();
        $form = $this->createForm(UserType::class, $user);

        // 2) обрабатываем форму
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {

            // 3) зашифровываем пароль
            $password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
            $user->setPassword($password);
            $user->setIsConfirmed(false);

            // 4) сохраняем пользователя
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();

            // 5) (временно) перенаправляем обратно
            return $this->redirectToRoute('register');
        }

        return $this->render(
            'register/index.html.twig', [
                'form' => $form->createView()
            ]
        );
    }
                    
        

Небольшое отступление на тему сервис-контейнера.
В отличии от многих других фреймворков, Symfony почти не использует функций ядра. Большую часть всего, что делает приложение обрабатываются сервисами. Каждый сервис находится внутри объекта сервис-контейнер, который мы вызываем в примере выше, используя UserPasswordEncoderInterface. Так же, например, для сохранения какой-нибудь информации в лог, можно воспользоваться LoggerInterface и его методом info. Для просмотра полного списка сервисов воспользуйтесь командой php bin/console debug:container.
Что касается магии, которая присваивает переменной класс (мы в качестве аргумента его передаем), называется она Argument Resolver.


Представление формы пока выведем стандартное, как и в случае с постами. Обновим шаблон index в директории register.

          
    {{ form_start(form) }}
    {{ form_widget(form) }}
    < button type="submit">Save< /button>
    {{ form_end(form) }}