 
                    支付宝扫一扫付款
 
                    微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
创建一个注册表单是非常容易的 - 它事实上意味着,你只需要创建一个表单,表单将更新一些User的模型对象(这个例子是一个Doctrine实体)并保存它。
受欢迎的FOSUserBundle 提供了一个注册表单,重置密码表单和其他用户管理功能。
如果你先前没有一个User实体和能工作的登录系统,你要先从怎样从数据库加载安全用户开始。
你的User实体至少应该有以下字段:
username
他是用来登录的,除非你想用email来替代你的用户(在那种情况下,这个字段就不是必要的了)。
email
这是一条不错的信息,很值得收集。您也可以允许用户通过email登录。
password
编译的密码
plainPassword
这个字段不会被持久化:(注意没有上面的@ORM\Column)。他将临时存储注册表单的明文密码。此字段可以被验证,然后被用于password字段的填充。
添加了一些验证,你的类可能看起来像这样:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | // src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
 
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
 
/**
 * @ORM\Entity
 * @UniqueEntity(fields="email", message="Email already taken")
 * @UniqueEntity(fields="username", message="Username already taken")
 */
class User implements UserInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
 
    /**
     * @ORM\Column(type="string", length=255, unique=true)
     * @Assert\NotBlank()
     * @Assert\Email()
     */
    private $email;
 
    /**
     * @ORM\Column(type="string", length=255, unique=true)
     * @Assert\NotBlank()
     */
    private $username;
 
    /**
     * @Assert\NotBlank()
     * @Assert\Length(max=4096)
     */
    private $plainPassword;
 
    /**
     * The below length depends on the "algorithm" you use for encoding
     * the password, but this works well with bcrypt.
     *
     * @ORM\Column(type="string", length=64)
     */
    private $password;
 
    // other properties and methods
 
    public function getEmail()
    {
        return $this->email;
    }
 
    public function setEmail($email)
    {
        $this->email = $email;
    }
 
    public function getUsername()
    {
        return $this->username;
    }
 
    public function setUsername($username)
    {
        $this->username = $username;
    }
 
    public function getPlainPassword()
    {
        return $this->plainPassword;
    }
 
    public function setPlainPassword($password)
    {
        $this->plainPassword = $password;
    }
 
    public function setPassword($password)
    {
        $this->password = $password;
    }
 
    public function getSalt()
    {
        // The bcrypt algorithm doesn't require a separate salt.
        // You *may* need a real salt if you choose a different encoder.
        return null;
    }
 
    // other methods, including security methods like getRoles()
} | 
UserInterface要求要有一些其他的方法,并且你的security.yml文件需要被正确配置,来让User实体工作。更多完整的例子,参见实体提供器文章。
下一步,给User实体创建表单:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // src/AppBundle/Form/UserType.php
namespace AppBundle\Form;
 
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
 
class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email', EmailType::class)
            ->add('username', TextType::class)
            ->add('plainPassword', RepeatedType::class, array(
                'type' => PasswordType::class,
                'first_options'  => array('label' => 'Password'),
                'second_options' => array('label' => 'Repeat Password'),
            )
        );
    }
 
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\User',
        ));
    }
} | 
这里有两个字段:email, username 和 plainPassword(重复确认输入的密码)。
探索更多关于表单组件的事情,请阅读表单指南。
下一步,你需要一个控制器去处理表单渲染和提交。如果表单被提交,控制器执行验证并保存数据到数据库:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | // src/AppBundle/Controller/RegistrationController.php
namespace AppBundle\Controller;
 
use AppBundle\Form\UserType;
use AppBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
 
class RegistrationController extends Controller
{
    /**
     * @Route("/register", name="user_registration")
     */
    public function registerAction(Request $request)
    {
        // 1) build the form
        $user = new User();
        $form = $this->createForm(UserType::class, $user);
 
        // 2) handle the submit (will only happen on POST)
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
 
            // 3) Encode the password (you could also do this via Doctrine listener)
            $password = $this->get('security.password_encoder')
                ->encodePassword($user, $user->getPlainPassword());
            $user->setPassword($password);
 
            // 4) save the User!
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();
 
            // ... do any other work - like sending them an email, etc
            // maybe set a "flash" success message for the user
 
            return $this->redirectToRoute('replace_with_some_route');
        }
 
        return $this->render(
            'registration/register.html.twig',
            array('form' => $form->createView())
        );
    }
} | 
在安全配置中配置上面步骤3的编码器,来定义用于编译密码的算法:
| 1 2 3 4 | # app/config/security.yml
security:
    encoders:
        AppBundle\Entity\User: bcrypt | 
| 1 2 3 4 5 6 7 8 9 10 11 | <!-- app/config/security.xml -->
<?xml version="1.0" charset="UTF-8" ?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <config>
        <encoder class="AppBundle\Entity\User">bcrypt</encoder>
    </config>
</srv:container> | 
这个案例我们推荐使用bcrypt 算法。了解更多关于如何编码用户密码的细节请看安全章节。
如果您决定不使用注释方式的路由(如上),那么你需要创建一个这个控制器的路由:
| 1 2 3 4 | # app/config/routing.yml
user_registration:
    path:     /register
    defaults: { _controller: AppBundle:Registration:register } | 
| 1 2 3 4 5 6 7 8 9 10 | <!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
 
    <route id="user_registration" path="/register">
        <default key="_controller">AppBundle:Registration:register</default>
    </route>
</routes> | 
| 1 2 3 4 5 6 7 8 9 10 | // app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
 
$collection = new RouteCollection();
$collection->add('user_registration', new Route('/register', array(
    '_controller' => 'AppBundle:Registration:register',
)));
 
return $collection; | 
下一步,创建模板:
| 1 2 3 4 5 6 7 8 9 10 | {# app/Resources/views/registration/register.html.twig #}
 
{{ form_start(form) }}
    {{ form_row(form.username) }}
    {{ form_row(form.email) }}
    {{ form_row(form.plainPassword.first) }}
    {{ form_row(form.plainPassword.second) }}
 
    <button type="submit">Register!</button>
{{ form_end(form) }} | 
| 1 2 3 4 5 6 7 8 9 10 11 | <!-- app/Resources/views/registration/register.html.php -->
 
<?php echo $view['form']->start($form) ?>
    <?php echo $view['form']->row($form['username']) ?>
    <?php echo $view['form']->row($form['email']) ?>
 
    <?php echo $view['form']->row($form['plainPassword']['first']) ?>
    <?php echo $view['form']->row($form['plainPassword']['second']) ?>
 
    <button type="submit">Register!</button>
<?php echo $view['form']->end($form) ?> | 
参见如何自定义表单渲染,里面有更多细节。
如果你在这个教程中已经更新了User实体,你必须要使用下面的命令去更新数据库结构:
| 1 | $ php bin/console doctrine:schema:update --force | 
就是这样!来到/register来尝试一下吧!
如果你想要你的用户通过email登录并不需要用户名,那么你可以从你的User实体中彻底移除他。相反,让getUsername()返回email属性:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // src/AppBundle/Entity/User.php
// ...
 
class User implements UserInterface
{
    // ...
 
    public function getUsername()
    {
        return $this->email;
    }
 
    // ...
} | 
下一步,只更改你security.yml文件的providers 部分,以便Symfony知道如何去通过email属性加载你的用户来登录。参见如何自定义表单渲染。
有时,你想要一个“你接受这个条款和声明吗?”的Checkbox,出现在你的注册表单。唯一窍门,让你要去添加这个字段到你的表单中,而你永远不需要添加多余的termsAccepted属性到你的User实体。
要做到这一点,要添加一个termsAccepted字段到你的表单,但设置它的 mapped 选项为false:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // src/AppBundle/Form/UserType.php
// ...
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
 
class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email', EmailType::class);
            // ...
            ->add('termsAccepted', CheckboxType::class, array(
                'mapped' => false,
                'constraints' => new IsTrue(),
            ))
        );
    }
} | 
constraints配置也被使用了,它允许我们添加验证,尽管没有User中没有termsAccepted属性。
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。