我必须在数据库中保留一个实体(为了简单起见,我们称之为Entity
),该实体必须引用到用FOSUserBundle处理的User
为了进行此引用,我有一个列entity_table.userId
。
创建新的Entity
时,我必须:
-
通过FosUserBundle的注册程序创建
User
-
获取新建用户的ID:[元代码]
$userId = $get->newCreatedUserId()
-
在
Entity
中设置此id:$entity->setUserId($userId)
- 将
Entity
持久化到数据库
如何将FosUserBundle的注册过程集成到保持我的Entity
的控制器中
更多详细信息
我第一次尝试简单地从FOSUserBundle的RegistrationController的方法registerAction()中复制代码:这是一种快速而肮脏的方法,无论如何都不起作用,因为我传递的User类是错误的(我传递了我用来覆盖bundle的自定义User
实体)。
这种方法还有其他缺点:
- 我无法控制注册程序(例如,发送或决定不发送确认电子邮件)
- 我不能对传递的数据使用内置检查
- 我不能确定在FOSUserBundles上更新我的自定义方法是否继续工作
- 其他我现在无法想象
所以,我想以最干净的方式创建用户:我该怎么做?哪种方法应该是好的
- 控制器转发
- 无论如何,一个模拟registerAction()方法的"硬编码"自定义方法
- 定制登记表
我在StackOverflow和互联网上读了很多讨论,我也读了FOSUserBundle和Symfony的文档,但我不能决定采用什么好的方法,也因为我不确定我是否理解每种方法的所有优点和缺点。
如果有人能让我走上正确的道路…:)
关于我的注册流程的更多信息
我有一个由控制器GetStarteController处理的getStarted过程。我有两种方法:
- indexAction(),它只显示一个字段为"电子邮件"的注册表
- endAction(),接收表单并使用传递的电子邮件创建一个公司(它只获取电子邮件的域部分)
这里有一个工作消息代码(对于Companies和Stores,它内部被称为源代码中存在但不在下面发布的类中的一些方法,例如setBrand()或setUrl())。
// AppBundle/Controller/getStartedController.php
namespace AppBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBundleConfigurationTemplate;
use SymfonyComponentHttpFoundationRequest;
use MyVendorUserBundleEntityUser;
use AppBundleEntityCompanies;
use AppBundleEntityStores;
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 FOSUserBundleModelUserManagerInterface */
$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 MyVendorUserBundleEntity;
use FOSUserBundleModelUser as BaseUser;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity
* @ORMTable(name="prefix_user")
*/
class User extends BaseUser
{
/**
* @ORMId
* @ORMColumn(type="integer")
* @ORMGeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
Companies.php 的一些基本代码
// AppBundle/Entity/Companies.php
namespace AppBundleEntity;
use DoctrineORMMapping as ORM;
/**
* Companies
*
* @ORMTable(name="companies")
* @ORMEntity
*/
class Companies
{
/**
* @var integer
*
* @ORMColumn(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 AppBundleEntity;
use DoctrineORMMapping as ORM;
/**
* Stores
*
* @ORMTable(name="stores", uniqueConstraints={@ORMUniqueConstraint(name="branchOf", columns={"branchOf"})})
* @ORMEntity
*/
class Stores
{
/**
* @var integer
*
* @ORMColumn(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 DoctrineORMEntityManager $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 FOSUserBundleEventUserEvent $userEvent
*/
public function onRegistrationInit(UserEvent $userEvent)
{
$user = $userEvent->getUser();
// Define your own logic there
}
}
别忘了让这个监听器成为一项服务:
#services.yml
services:
oe_user.registration:
class: OrienteExpressUserBundleEventListenerRegistrationListener
# 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发送的事件的完整列表
此外,Symfony实体是对象的模型。也就是说,您需要明白,您不是在模型中使用id,而是使用对象。
您不应该在实体中使用$var->setUserId()之类的东西。原则是用来管理你们的关系的,所以要小心这一点。如果不使用Symfony&按照设计的方式行事。
编辑:
在您的公司实体中,您的关系介于"公司"one_answers"用户"对象之间。这意味着你的公司不需要用户id,只需要用户的一个实例。
我认为在想做高级的事情之前,你可能会回到基础。
用户和公司之间的关系不应该是由整数属性设计的,而应该是真正的原则关系。
例如:
class Company {
/**
* @ORMManyToOne(targetEntity="PathToUser")
* @ORMJoinColumn(nullable=false)
*/
private $owner;
/**
* @param $user User
*/
public function setUser(User $user)
{
$this->user = $user;
}
}
然后你将创建一家新公司。你不需要知道用户的id,甚至不需要插入它就可以在它们之间建立链接。但是,如果你还没有意识到这一点,我认为你应该再次回到Symfony的基础知识,因为这是需要掌握的最重要的功能之一。