如何从第三方控制器使用 FOSUserBundle 的注册程序

How to use the registration procedure of FOSUserBundle from a third controller

我必须在数据库中保留一个实体(为简单起见,我们称之为 Entity),该实体必须引用到使用 FOSUserBundle 处理的 User 为了做这个参考,我有一列 entity_table.userId.

创建新的Entity时,我必须:

  1. 通过FosUserBundle的注册过程创建User
  2. 获取新创建用户的ID: [元代码] $userId = $get->newCreatedUserId();
  3. Entity中设置这个id: $entity->setUserId($userId);
  4. Entity 持久化到数据库。

如何将 FosUserBundle 的注册程序集成到持久化我的 Entity 的控制器中?

更多详情

我第一次尝试简单地从 FOSUserBundle 的 RegistrationController 的 registerAction() 方法复制代码:一种快速而肮脏的方法,无论如何都没有用,因为我作为用户收到错误 class 我通过的是错误的(我通过了我用来覆盖包的自定义 User 实体)。

这种方法还有其他缺点:

所以,我想以最简洁的方式创建用户:我该怎么做?哪个应该是一个好的方法?

  1. 控制器转发?
  2. 无论如何,一个模拟 registerAction() 方法的 "hardcoded" 自定义方法?
  3. 自定义注册表单?

我在 Whosebug 和 Internet 上阅读了很多讨论,我也阅读了 FOSUserBundle 和 Symfony 的文档,但我不能决定采用哪种好方法,也因为我不确定我是否理解所有每种方法的优缺点。

如果有人能告诉我正确的方法...:)

关于我的注册流程的更多信息

我有一个由控制器 GetStarteController 处理的 getStarted 过程。 其中我有两种方法:

  1. indexAction(),显示仅包含字段 "email";
  2. 的注册表单
  3. endAction(),接收表单并使用传递的电子邮件创建公司(它仅获取电子邮件的域部分)。

这是一个混乱的工作代码(公司和商店在其中调用了一些存在于源代码中但不在发布的 classes 中的方法下面,例如 setBrand() 或 setUrl()。

// AppBundle/Controller/getStartedController.php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;

use MyVendor\UserBundle\Entity\User;
use AppBundle\Entity\Companies;
use AppBundle\Entity\Stores;

class GetStartedController extends Controller
{
    /**
     * @Route("getstarted")
     * @Template()
     */
    public function indexAction()
    {
        $data = array();
        $form = $this->createFormBuilder($data, array(
                'action' => $this->generateUrl('getStartedEnd'),
            ))
            ->add('email', 'email')
            ->add('submit', 'submit')
            ->getForm();

        return array(
            'form' => $form->createView(),
        );
    }

    /**
     * @Route("getstarted/end", name="getStartedEnd")
     * @Template()
     */
    public function endAction(Request $request)
    {
        $form = $this->createFormBuilder()
            ->add('email', 'email')
            ->add('submit', 'submit')
            ->getForm();

        $form->handleRequest($request);

        if ($form->isValid()) {
            $data = $form->getData();
        } else {
            /** @todo here we have to raise some sort of exception or error */
            echo 'no data submitted (See the todo in the code)';exit;
        }

        // Pass the email to the template
        $return['email'] = $data['email'];

        // Get the domain part of the email and pass it to the template
        $domain = explode('@', $data['email']);
        $return['domain'] = $domain[1];

        // 1) Create the new user
        $user = new User();

        // Get the token generator
        $tokenGenerator = $this->container->get('fos_user.util.token_generator');

        $user->setEmail($return['email']);
        $userRandomUsername = substr($tokenGenerator->generateToken(), 0, 12);
        $user->setUsername('random-' . $userRandomUsername);

        $plainPassword = substr($tokenGenerator->generateToken(), 0, 12);
        $encoder = $this->container->get('security.password_encoder');
        $encoded = $encoder->encodePassword($user, $plainPassword);

        // Set the password for the user
        $user->setPassword($encoded);

        /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
        $userManager = $this->get('fos_user.user_manager');

        // Perstist the user in the database
        $userManager->updateUser($user);
        $userId = $user->getId();

        // 2) Create the Company object
        $company = new Companies();
        $company->setBrand($return['domain'])
            ->setAdded(new \DateTime())
            ->setOwnerId($userId);

        // 3) Create the Store object
        $store = new Stores();
        $store->setEmail($return['email'])
            ->setUrl($return['domain'])
            ->setAdded(new \DateTime());

        // Get the Entity Manager
        $em = $this->getDoctrine()->getManager();

        // Persist Company and get its ID
        $em->persist($company);
        $em->flush();
        $return['companyId'] = $company->getId();

        // Set the property branchOf of the Store object
        $store->setBranchOf($return['companyId']);

        // Persist the Store object
        $em->persist($store);
        $em->flush();

        $return['storeId'] = $store->getId();

        return $return;
    }
}

这里是覆盖 FOSUserBundle 提供的用户实体

// MyVendor/UserBundle/Entity/User.php

namespace MyVendor\UserBundle\Entity;

use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="prefix_user")
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    public function __construct()
    {
        parent::__construct();
        // your own logic
    }
}

Companies.php

的一些重要代码
// AppBundle/Entity/Companies.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Companies
 *
 * @ORM\Table(name="companies")
 * @ORM\Entity
 */
class Companies
{
    /**
     * @var integer
     *
     * @ORM\Column(name="ownerId", type="integer", nullable=false)
     */
    private $ownerid;

    /**
     * Set ownerid
     *
     * @param integer $ownerid
     * @return Companies
     */
    public function setOwnerid($ownerid)
    {
        $this->ownerid = $ownerid;

        return $this;
    }

    /**
     * Get ownerid
     *
     * @return integer 
     */
    public function getOwnerid()
    {
        return $this->ownerid;
    }
}

Stores.php

的一些重要代码
// AppBundle/Entity/Stores.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Stores
 *
 * @ORM\Table(name="stores", uniqueConstraints={@ORM\UniqueConstraint(name="branchOf", columns={"branchOf"})})
 * @ORM\Entity
 */
class Stores
{
    /**
     * @var integer
     *
     * @ORM\Column(name="branchOf", type="integer", nullable=false)
     */
    private $branchof;

    /**
     * Set branchof
     *
     * @param integer $branchof
     * @return Stores
     */
    public function setBranchof($branchof)
    {
        $this->branchof = $branchof;

        return $this;
    }

    /**
     * Get branchof
     *
     * @return integer 
     */
    public function getBranchof()
    {
        return $this->branchof;
    }
}

您可以使用自定义注册表单,但最好的方法显然是监听 FOSUser 发送的注册事件。

这是一个例子:

class RegistrationListener implements EventSubscriberInterface
{

    /**
     * L'entity manager
     *
     * @var EntityManager
     */
    private $em;

    /**
     * Constructeur de l'EventListener
     *
     * @param \Doctrine\ORM\EntityManager $entityManager
     */
   public function __construct(EntityManager $entityManager)
    {
        $this->em = $entityManager;
    }

    /**
     * {@inheritDoc}
     */
    public static function getSubscribedEvents()
    {
        return array(
            FOSUserEvents::REGISTRATION_INITIALIZE => 'onRegistrationInit',
        );
    }

    /**
     * Triggered when FOSUserEvents::REGISTRATION_INITIALIZE is caught.
     *
     * @param \FOS\UserBundle\Event\UserEvent $userEvent
     */
    public function onRegistrationInit(UserEvent $userEvent)
    {
        $user = $userEvent->getUser();
        // Define your own logic there
    }
}

别忘了将此侦听器设为服务:

#services.yml
services:
    oe_user.registration:
        class: OrienteExpress\UserBundle\EventListener\RegistrationListener
        # arguments are optional but you still can need them 
        # so I let the EM as example which is an often used parameter
        arguments:
            entityManager: "@doctrine.orm.entity_manager"
        tags:
            - { name: kernel.event_subscriber }

您将找到 FOSUser 调度的完整事件列表 here

此外,Symfony 实体是对象的模型。也就是说,您需要了解您在模型中使用的不是 id,而是 object。

您不应该在实体中使用诸如 $var->setUserId() 之类的东西。教义是用来管理你的关系的,所以要小心这一点。如果不按照设计的方式使用 Symfony 和 Doctrine,您可能会遇到意想不到的问题。

编辑:

在您的公司实体中,您的关系是公司对象和用户对象之间的关系。这意味着您不需要公司中的用户 ID,只需一个用户实例即可。

我想你可能会在想做高级的东西之前回到基础。

你的用户和公司之间的关系不应该用一个整数属性来设计,而是一个真正的主义关系。

例如:

class Company {

    /**
     * @ORM\ManyToOne(targetEntity="Path\To\User")
     * @ORM\JoinColumn(nullable=false)
     */
     private $owner;

     /**
      * @param $user User 
      */
     public function setUser(User $user)
     {
         $this->user = $user;
     }
}

然后当你创建一个新公司的时候。您不需要知道用户的 ID,甚至不需要插入它来在它们之间创建 link。但是,如果您还没有意识到这一点,我再次认为您应该回到 Symfony 的基础知识,因为这是需要掌握的最(也许是最)重要的功能之一。