如何从第三方控制器使用 FOSUserBundle 的注册程序
How to use the registration procedure of FOSUserBundle from a third controller
我必须在数据库中保留一个实体(为简单起见,我们称之为 Entity
),该实体必须引用到使用 FOSUserBundle 处理的 User
。 为了做这个参考,我有一列 entity_table.userId
.
创建新的Entity
时,我必须:
- 通过FosUserBundle的注册过程创建
User
;
- 获取新创建用户的ID: [元代码]
$userId = $get->newCreatedUserId()
;
- 在
Entity
中设置这个id: $entity->setUserId($userId)
;
- 将
Entity
持久化到数据库。
如何将 FosUserBundle 的注册程序集成到持久化我的 Entity
的控制器中?
更多详情
我第一次尝试简单地从 FOSUserBundle 的 RegistrationController 的 registerAction() 方法复制代码:一种快速而肮脏的方法,无论如何都没有用,因为我作为用户收到错误 class 我通过的是错误的(我通过了我用来覆盖包的自定义 User
实体)。
这种方法还有其他缺点:
- 我无法控制注册程序(例如,发送或决定不发送确认电子邮件);
- 我无法对传递的数据使用内置检查;
- 我不能确定在 FOSUserBundles 更新时我的自定义方法继续工作
- 其他暂时想不出来...
所以,我想以最简洁的方式创建用户:我该怎么做?哪个应该是一个好的方法?
- 控制器转发?
- 无论如何,一个模拟 registerAction() 方法的 "hardcoded" 自定义方法?
- 自定义注册表单?
我在 Whosebug 和 Internet 上阅读了很多讨论,我也阅读了 FOSUserBundle 和 Symfony 的文档,但我不能决定采用哪种好方法,也因为我不确定我是否理解所有每种方法的优缺点。
如果有人能告诉我正确的方法...:)
关于我的注册流程的更多信息
我有一个由控制器 GetStarteController 处理的 getStarted 过程。
其中我有两种方法:
- indexAction(),显示仅包含字段 "email";
的注册表单
- 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 的基础知识,因为这是需要掌握的最(也许是最)重要的功能之一。
我必须在数据库中保留一个实体(为简单起见,我们称之为 Entity
),该实体必须引用到使用 FOSUserBundle 处理的 User
。 为了做这个参考,我有一列 entity_table.userId
.
创建新的Entity
时,我必须:
- 通过FosUserBundle的注册过程创建
User
; - 获取新创建用户的ID: [元代码]
$userId = $get->newCreatedUserId()
; - 在
Entity
中设置这个id:$entity->setUserId($userId)
; - 将
Entity
持久化到数据库。
如何将 FosUserBundle 的注册程序集成到持久化我的 Entity
的控制器中?
更多详情
我第一次尝试简单地从 FOSUserBundle 的 RegistrationController 的 registerAction() 方法复制代码:一种快速而肮脏的方法,无论如何都没有用,因为我作为用户收到错误 class 我通过的是错误的(我通过了我用来覆盖包的自定义 User
实体)。
这种方法还有其他缺点:
- 我无法控制注册程序(例如,发送或决定不发送确认电子邮件);
- 我无法对传递的数据使用内置检查;
- 我不能确定在 FOSUserBundles 更新时我的自定义方法继续工作
- 其他暂时想不出来...
所以,我想以最简洁的方式创建用户:我该怎么做?哪个应该是一个好的方法?
- 控制器转发?
- 无论如何,一个模拟 registerAction() 方法的 "hardcoded" 自定义方法?
- 自定义注册表单?
我在 Whosebug 和 Internet 上阅读了很多讨论,我也阅读了 FOSUserBundle 和 Symfony 的文档,但我不能决定采用哪种好方法,也因为我不确定我是否理解所有每种方法的优缺点。
如果有人能告诉我正确的方法...:)
关于我的注册流程的更多信息
我有一个由控制器 GetStarteController 处理的 getStarted 过程。 其中我有两种方法:
- indexAction(),显示仅包含字段 "email"; 的注册表单
- 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 的基础知识,因为这是需要掌握的最(也许是最)重要的功能之一。