Symfony:创建新用户会导致覆盖属性
Symfony: Creating a new user results in overwriting of properties
当有人在我们的应用程序上创建新用户时,他自己的一些属性会被新用户属性覆盖。我还不知道在哪里寻找错误,因为在控制器或实体中,没有任何改变。
这里有一些信息:用户实体(我们使用的是 FOS 用户包)
class User extends BaseUser{
/**
* @Solr\Id
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @Solr\Field(type="string")
* @Assert\NotBlank()
* @var string
* @ORM\Column(type="string", length=32, nullable=false)
*/
protected $firstName;
/**
* @Solr\Field(type="string")
* @Assert\NotBlank()
* @var string
* @ORM\Column(type="string", length=32, nullable=false)
*/
protected $lastName;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Agency", inversedBy="useragencies", cascade={"persist"})
* @ORM\JoinTable(name="user_user_agencies",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="iata8", referencedColumnName="iata8")})
* @var \AppBundle\Entity\Agency
**/
private $agencies;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Product", inversedBy="users", cascade={"persist"})
* @ORM\JoinTable(name="user_user_products",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")})
* @var \AppBundle\Entity\Product
**/
private $products;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Market", inversedBy="users", cascade={"persist"})
* @ORM\JoinTable(name="user_user_markets",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="market_id", referencedColumnName="id")})
* @var \AppBundle\Entity\Market
* @Solr\Field(type="string", getter="getId")
**/
private $markets;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Airline", inversedBy="users", cascade={"persist"})
* @ORM\JoinTable(name="user_user_airlines",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="airline_id", referencedColumnName="id")})
* @var \AppBundle\Entity\Airline
* @Solr\Field(type="string", getter="getId")
**/
private $airlines;
...
被覆盖的属性是 products 和 airlines。此实体没有 prePersist() 或 preUpdate() 函数!
创建控制器
class CreateController extends Controller
{
/**
* @Security("has_role('ROLE_USER_INVITER')")
* @Route("/user/create/{employer}", defaults={"employer": 1}
* , requirements={"employer": "\d+"}, name="userBundle_create")
*/
public function createAction($employer, Request $request)
{
$currentUser=$this->container->get('security.token_storage')->getToken()->getUser();
// get employer Object
$em = $this->getDoctrine ()->getManager ();
$repository = $this->getDoctrine()
->getRepository('UserBundle:Employer');
$employerObj = $repository->findOneByIdInContext($employer, $currentUser);
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->createUser();
$url = $this->get('router')->generate('userBundle_create', array(
'employer' => $employerObj->getId()
));
// generate form and handle
$form = $this->createForm(CreateType::class, $user
, array('employer' => $employerObj,
'action' => $url,)
);
$form->handleRequest($request);
if ($form->isValid()) {
$tokenGenerator = $this->container->get('fos_user.util.token_generator');
$user->setConfirmationToken($tokenGenerator->generateToken());
$user->setUsername($user->getEmail());
$user->setEnabled(false);
$user->setApprover($currentUser);
$user->setInviter($currentUser);
$user->addRole($user->getMainRole()->getName());
$userManager->updateUser($user);
if(count($user->getAgencies()) > 0){
$userId = rtrim($user->getId(),"_user");
$query = $em->createQuery("SELECT DISTINCT (a.market) FROM UserBundle\Entity\User u JOIN u.agencies a WHERE u.id = $userId");
$marketIds = $query->getResult();
$em = $this->getDoctrine ()->getManager ();
$repository = $this->getDoctrine()
->getRepository('AppBundle:Market');
$markets = $repository->findOneById($marketIds[0]);
$user->addMarket($markets);
$userManager->updateUser($user);
}
$this->addFlash(
'success',
'The user was created and an activation email was sent!'
);
return $this->redirectToRoute('userBundle_list');
}
return $this->render('UserBundle:User:create.html.twig', array(
'form' => $form->createView(),
'user'=>$user,
));
}
}
这里有更多 类 可能会帮助我指明正确的方向。
CreateType
class CreateType extends AbstractType
{
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
'employer' => null
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$employer = $options['employer'];
$builder
->add('firstName', 'text', array('label' => 'label.firstname',
'translation_domain' => 'User',))
->add('lastName', 'text', array('label' => 'label.lastname',
'translation_domain' => 'User',))
;
$user = $this->tokenStorage->getToken()->getUser();
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($user, $employer){
$form = $event->getForm();
// show iata selection if empoyer is any agency
$employerArr = array(10, 11);
if (in_array($employer->getId(), $employerArr)) {
// only show iata based on user's employer
if($user->hasRoles(array('ROLE_AGENCY_TC_ONLY',
'ROLE_AGENCY_WAIVER_REQUEST_ONLY',
'ROLE_AGENCY_CORE_TEAM',
'ROLE_AGENCY',
'ROLE_AGENCY_MANAGEMENT',
'ROLE_AGENCY_SIGNEE','ROLE_CORPORATION_TRAVEL_MANAGER' ))){
$form
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er) use ($user) {
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.id IN (:ids)')
->setParameter('ids',$user->getAgencies());
},
'choice_label' => 'agencyName',
// 'data' => $user->getAgencies(),
'label' => 'label.iata',
'empty_value' => "label.select.agency",
'property' => 'id',
'expanded' => false, 'multiple' => true,
'required' => true,
'translation_domain' => 'User',
'choice_translation_domain' => 'User'));
} else {
// only show iata based on user's context
$form
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er) use ($user) {
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.market IN (:markets)')
->setParameter('markets',$user->getMarkets());
},
'choice_label' => 'agencyName',
'label' => 'label.iata',
'empty_value' => "label.select.agency",
'property' => 'id',
'expanded' => false, 'multiple' => true,
'required' => true,
'translation_domain' => 'User',
'choice_translation_domain' => 'User'));
}
// show market only if not agency user
} else {
// only show specific markets based on user's context
$form->add('markets', 'entity', array(
'class' => 'AppBundle:Market', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$markets = $user->getMarkets();
return $er->createQueryBuilder('m')
->addOrderBy('m.id', 'ASC')
->andWhere('m.id IN (?1)')
->setParameter(1,$markets);
},
// 'choice_value' => 'id',
'choice_label' => 'id', 'label' => 'label.markets',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,));
}
// only show specific roles based on user's employer
$form->add('mainRole', 'entity', array(
'class' => 'UserBundle:Role',
'query_builder' => function (EntityRepository $er) use ($employer){
$roles = $employer->getRoles();
return $er->createQueryBuilder('r')
->orderBy('r.sort', 'ASC')
->andWhere('r.id IN (?1)')
->setParameter(1,$roles);
},
'choice_label' => 'translationKey',
'choices_as_values' => true, 'label' => 'label.role',
'expanded' => true, 'multiple' => false,
'translation_domain' => 'User',
'choice_translation_domain' => 'Role',));
// only show specific airlines based on user's context
$form->add('airlines', 'entity', array(
'class' => 'AppBundle:Airline', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$airlines = $user->getAirlines();
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.id IN (?1)')
->setParameter(1,$airlines);
},
'choice_value' => 'id',
'data' => $user->getAirlines(),
'choice_label' => 'id', 'label' => 'label.airlines',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,));
// only show specific products based on user's context
$form->add('products', 'entity', array(
'class' => 'AppBundle:Product', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$products = $user->getProducts();
return $er->createQueryBuilder('p')
->addOrderBy('p.id', 'ASC')
->andWhere('p.id IN (?1)')
->setParameter(1,$products);
},
'choice_value' => 'id',
'data' => $user->getProducts(),
'choice_label' => 'translationKey', 'label' => 'label.products',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,
'choice_translation_domain' => 'AppBundle',));
});
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'userBundle_create';
}
}
您的问题是由以下几行引起的:
'data' => $user->getAirlines(),
和
'data' => $user->getProducts(),
更改新用户s airlines & products collection, symfony form uses the loggedin user
的航空公司和产品集合参考。
将集合设为默认时克隆集合,以删除对已登录用户的引用。
'data' => clone $user->getAirlines(),
和
'data' => clone $user->getProducts(),
希望对您有所帮助。
错误假设:你的错误在CreateTypeclass。您使用登录用户的属性来填充表单的 agencies、airlines 和 products 字段:
$user = $this->tokenStorage->getToken()->getUser();
...
'query_builder' => function (EntityRepository $er) use ($user) {
您应该改用您编辑的用户。在您的 buildForm 函数中添加:
$userEdited = $builder->getData();
然后更改:
'query_builder' => function (EntityRepository $er) use ($userEdited) {
在所有地方。
也别忘了改:
$user->getMarkets()
至
$userEdited->getMarkets()
在您的回传中,对于 ailines 和产品也是如此。
当有人在我们的应用程序上创建新用户时,他自己的一些属性会被新用户属性覆盖。我还不知道在哪里寻找错误,因为在控制器或实体中,没有任何改变。
这里有一些信息:用户实体(我们使用的是 FOS 用户包)
class User extends BaseUser{
/**
* @Solr\Id
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @Solr\Field(type="string")
* @Assert\NotBlank()
* @var string
* @ORM\Column(type="string", length=32, nullable=false)
*/
protected $firstName;
/**
* @Solr\Field(type="string")
* @Assert\NotBlank()
* @var string
* @ORM\Column(type="string", length=32, nullable=false)
*/
protected $lastName;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Agency", inversedBy="useragencies", cascade={"persist"})
* @ORM\JoinTable(name="user_user_agencies",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="iata8", referencedColumnName="iata8")})
* @var \AppBundle\Entity\Agency
**/
private $agencies;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Product", inversedBy="users", cascade={"persist"})
* @ORM\JoinTable(name="user_user_products",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")})
* @var \AppBundle\Entity\Product
**/
private $products;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Market", inversedBy="users", cascade={"persist"})
* @ORM\JoinTable(name="user_user_markets",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="market_id", referencedColumnName="id")})
* @var \AppBundle\Entity\Market
* @Solr\Field(type="string", getter="getId")
**/
private $markets;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Airline", inversedBy="users", cascade={"persist"})
* @ORM\JoinTable(name="user_user_airlines",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="airline_id", referencedColumnName="id")})
* @var \AppBundle\Entity\Airline
* @Solr\Field(type="string", getter="getId")
**/
private $airlines;
...
被覆盖的属性是 products 和 airlines。此实体没有 prePersist() 或 preUpdate() 函数!
创建控制器
class CreateController extends Controller
{
/**
* @Security("has_role('ROLE_USER_INVITER')")
* @Route("/user/create/{employer}", defaults={"employer": 1}
* , requirements={"employer": "\d+"}, name="userBundle_create")
*/
public function createAction($employer, Request $request)
{
$currentUser=$this->container->get('security.token_storage')->getToken()->getUser();
// get employer Object
$em = $this->getDoctrine ()->getManager ();
$repository = $this->getDoctrine()
->getRepository('UserBundle:Employer');
$employerObj = $repository->findOneByIdInContext($employer, $currentUser);
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->createUser();
$url = $this->get('router')->generate('userBundle_create', array(
'employer' => $employerObj->getId()
));
// generate form and handle
$form = $this->createForm(CreateType::class, $user
, array('employer' => $employerObj,
'action' => $url,)
);
$form->handleRequest($request);
if ($form->isValid()) {
$tokenGenerator = $this->container->get('fos_user.util.token_generator');
$user->setConfirmationToken($tokenGenerator->generateToken());
$user->setUsername($user->getEmail());
$user->setEnabled(false);
$user->setApprover($currentUser);
$user->setInviter($currentUser);
$user->addRole($user->getMainRole()->getName());
$userManager->updateUser($user);
if(count($user->getAgencies()) > 0){
$userId = rtrim($user->getId(),"_user");
$query = $em->createQuery("SELECT DISTINCT (a.market) FROM UserBundle\Entity\User u JOIN u.agencies a WHERE u.id = $userId");
$marketIds = $query->getResult();
$em = $this->getDoctrine ()->getManager ();
$repository = $this->getDoctrine()
->getRepository('AppBundle:Market');
$markets = $repository->findOneById($marketIds[0]);
$user->addMarket($markets);
$userManager->updateUser($user);
}
$this->addFlash(
'success',
'The user was created and an activation email was sent!'
);
return $this->redirectToRoute('userBundle_list');
}
return $this->render('UserBundle:User:create.html.twig', array(
'form' => $form->createView(),
'user'=>$user,
));
}
}
这里有更多 类 可能会帮助我指明正确的方向。
CreateType
class CreateType extends AbstractType
{
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
'employer' => null
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$employer = $options['employer'];
$builder
->add('firstName', 'text', array('label' => 'label.firstname',
'translation_domain' => 'User',))
->add('lastName', 'text', array('label' => 'label.lastname',
'translation_domain' => 'User',))
;
$user = $this->tokenStorage->getToken()->getUser();
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($user, $employer){
$form = $event->getForm();
// show iata selection if empoyer is any agency
$employerArr = array(10, 11);
if (in_array($employer->getId(), $employerArr)) {
// only show iata based on user's employer
if($user->hasRoles(array('ROLE_AGENCY_TC_ONLY',
'ROLE_AGENCY_WAIVER_REQUEST_ONLY',
'ROLE_AGENCY_CORE_TEAM',
'ROLE_AGENCY',
'ROLE_AGENCY_MANAGEMENT',
'ROLE_AGENCY_SIGNEE','ROLE_CORPORATION_TRAVEL_MANAGER' ))){
$form
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er) use ($user) {
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.id IN (:ids)')
->setParameter('ids',$user->getAgencies());
},
'choice_label' => 'agencyName',
// 'data' => $user->getAgencies(),
'label' => 'label.iata',
'empty_value' => "label.select.agency",
'property' => 'id',
'expanded' => false, 'multiple' => true,
'required' => true,
'translation_domain' => 'User',
'choice_translation_domain' => 'User'));
} else {
// only show iata based on user's context
$form
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er) use ($user) {
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.market IN (:markets)')
->setParameter('markets',$user->getMarkets());
},
'choice_label' => 'agencyName',
'label' => 'label.iata',
'empty_value' => "label.select.agency",
'property' => 'id',
'expanded' => false, 'multiple' => true,
'required' => true,
'translation_domain' => 'User',
'choice_translation_domain' => 'User'));
}
// show market only if not agency user
} else {
// only show specific markets based on user's context
$form->add('markets', 'entity', array(
'class' => 'AppBundle:Market', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$markets = $user->getMarkets();
return $er->createQueryBuilder('m')
->addOrderBy('m.id', 'ASC')
->andWhere('m.id IN (?1)')
->setParameter(1,$markets);
},
// 'choice_value' => 'id',
'choice_label' => 'id', 'label' => 'label.markets',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,));
}
// only show specific roles based on user's employer
$form->add('mainRole', 'entity', array(
'class' => 'UserBundle:Role',
'query_builder' => function (EntityRepository $er) use ($employer){
$roles = $employer->getRoles();
return $er->createQueryBuilder('r')
->orderBy('r.sort', 'ASC')
->andWhere('r.id IN (?1)')
->setParameter(1,$roles);
},
'choice_label' => 'translationKey',
'choices_as_values' => true, 'label' => 'label.role',
'expanded' => true, 'multiple' => false,
'translation_domain' => 'User',
'choice_translation_domain' => 'Role',));
// only show specific airlines based on user's context
$form->add('airlines', 'entity', array(
'class' => 'AppBundle:Airline', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$airlines = $user->getAirlines();
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.id IN (?1)')
->setParameter(1,$airlines);
},
'choice_value' => 'id',
'data' => $user->getAirlines(),
'choice_label' => 'id', 'label' => 'label.airlines',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,));
// only show specific products based on user's context
$form->add('products', 'entity', array(
'class' => 'AppBundle:Product', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$products = $user->getProducts();
return $er->createQueryBuilder('p')
->addOrderBy('p.id', 'ASC')
->andWhere('p.id IN (?1)')
->setParameter(1,$products);
},
'choice_value' => 'id',
'data' => $user->getProducts(),
'choice_label' => 'translationKey', 'label' => 'label.products',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,
'choice_translation_domain' => 'AppBundle',));
});
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'userBundle_create';
}
}
您的问题是由以下几行引起的:
'data' => $user->getAirlines(),
和
'data' => $user->getProducts(),
更改新用户s airlines & products collection, symfony form uses the loggedin user
的航空公司和产品集合参考。
将集合设为默认时克隆集合,以删除对已登录用户的引用。
'data' => clone $user->getAirlines(),
和
'data' => clone $user->getProducts(),
希望对您有所帮助。
错误假设:你的错误在CreateTypeclass。您使用登录用户的属性来填充表单的 agencies、airlines 和 products 字段:
$user = $this->tokenStorage->getToken()->getUser();
...
'query_builder' => function (EntityRepository $er) use ($user) {
您应该改用您编辑的用户。在您的 buildForm 函数中添加:
$userEdited = $builder->getData();
然后更改:
'query_builder' => function (EntityRepository $er) use ($userEdited) {
在所有地方。
也别忘了改:
$user->getMarkets()
至
$userEdited->getMarkets()
在您的回传中,对于 ailines 和产品也是如此。