我面临一个非常奇怪的情况,一旦我更改名称,ROLE_ADMIN
用户就会被注销,即使我没有更改任何内容并按下保存按钮,它也会被注销。如果我将用户的角色直接在数据库中更改为ROLE_USER
,则相同的代码可以正常工作,用户也不会注销。
以下是负责配置文件更新的控制器
/**
* @Route("/profile", name="profile")
*/
public function profileAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$userInfo = $this->getUser();
//create the form object
$profileForm = $this->createForm(UserType::class, $userInfo);
$profileForm->handleRequest($request);
//check data validity
if($profileForm->isValid()){
$em->persist($userInfo);
$em->flush();
$this->get('session')->getFlashBag()->add(
'success',
'Your profile information has been updated'
);
return $this->render('AppBundle:admin/user:admin-edit.html.twig',array(
'edit_form' => $profileForm->createView()
));
}
// render registration form
return $this->render('AppBundle:admin/user:admin-edit.html.twig',array(
'edit_form' => $profileForm->createView()
));
}
}
这是我的security.yml
security:
encoders:
# Our user class and the algorithm we'll use to encode passwords
# http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
AppBundle\Entity\User: bcrypt
providers:
# Simple example of loading users via Doctrine
# To load users from somewhere else: http://symfony.com/doc/current/cookbook/security/custom_provider.html
database_users:
entity: { class: AppBundle:User, property: username }
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
http_basic: ~
anonymous: ~
logout: ~
guard:
authenticators:
- app.form_login_authenticator
- app.facebook_authenticator
# by default, use the start() function from FormLoginAuthenticator
entry_point: app.form_login_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, roles: ROLE_ADMIN }
- { path: ^/user, roles: ROLE_USER }
更新1
这是我的UserType
namespace AppBundle\Form;
use AppBundle\Form\EventListener\AddDepartmentDegreeCourseFieldSubscriber;
use AppBundle\Form\EventListener\AddProfileFieldSubscriber;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
private $addDepartmentDegreeCourseFieldSubscriber;
private $addProfileFieldSubscriver;
function __construct(AddDepartmentDegreeCourseFieldSubscriber $subscriber, AddProfileFieldSubscriber $fields)
{
$this->addDepartmentDegreeCourseFieldSubscriber = $subscriber;
$this->addProfileFieldSubscriver = $fields;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber($this->addProfileFieldSubscriver);
$builder->addEventSubscriber($this->addDepartmentDegreeCourseFieldSubscriber);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User'
));
}
}
这是我的AddProfileFieldSubscriber
namespace AppBundle\Form\EventListener;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Validator\Constraints\NotBlank;
class AddProfileFieldSubscriber implements EventSubscriberInterface
{
protected $authorizationChecker;
function __construct(AuthorizationChecker $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
public static function getSubscribedEvents()
{
// Tells the dispatcher that you want to listen on the form.pre_set_data
// event and that the preSetData method should be called.
return array(FormEvents::PRE_SET_DATA => 'preSetData');
}
public function preSetData(FormEvent $event)
{
$user = $event->getData();
$form = $event->getForm();
if($user){
$form->add('firstName', TextType::class);
$form->add('lastName', TextType::class);
$form->add('password', PasswordType::class, array(
'mapped' => false
));
$form->add('profileImage', FileType::class, array(
'data_class' => null
));
if (in_array("ROLE_USER", $user->getRoles())) {
$form->add('contactNumber', TextType::class);
$form->add('gender', ChoiceType::class, array(
'choices' => array(
'Male' => 'm',
'Female' => 'f'
),
'placeholder' => 'provide_gender'
));
$form->add('college', EntityType::class, array(
'placeholder' => 'provide_college',
'class' => 'AppBundle\Entity\College')
);
$form->add('interest', EntityType::class, array(
'class' => 'AppBundle\Entity\Interest',
'multiple' => true,
'expanded' => false,
'by_reference' => false,
)
);
}
if($this->authorizationChecker->isGranted('ROLE_ADMIN') ) {
$form->add('isActive', ChoiceType::class, array(
'choices' => array(
'account_active' => '1',
'account_inactive' => '0'
),
'placeholder' => 'provide_status'
));
}
}
//if the selected user has role_user only then display the following fields in edit profile view
else {
$form->add('username', EmailType::class);
$form->add('password', PasswordType::class, array(
'constraints' => array(new NotBlank(array(
'message' => 'user.password.not_blank'
)
),),
));
}
}
}
这是AddDepartmentDegreeCourseFieldSubscriber
namespace AppBundle\Form\EventListener;
use AppBundle\Entity\Degree;
use AppBundle\Entity\Department;
use Doctrine\ORM\EntityManager;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormInterface;
class AddDepartmentDegreeCourseFieldSubscriber implements EventSubscriberInterface
{
protected $em;
function __construct(EntityManager $em)
{
$this->em = $em;
}
public static function getSubscribedEvents()
{
// Tells the dispatcher that you want to listen on the form.pre_set_data
// event and that the preSetData method should be called.
return array(
FormEvents::PRE_SET_DATA => 'onPreSetData',
FormEvents::PRE_SUBMIT => 'onPreSubmit'
);
}
protected function addElements(FormInterface $form, Department $departments = null, Degree $degree = null)
{
// Add the department element
$form->add('department', EntityType::class, array(
'data' => $departments,
'placeholder' => 'provide_department',
'class' => 'AppBundle\Entity\Department')
);
// Degree are empty, unless we actually supplied a department
$degree = array();
if ($departments) {
// Fetch the courses from specified degree
$repo = $this->em->getRepository('AppBundle:Degree');
$degree = $repo->findByDepartment($departments, array('name' => 'asc'));
}
// Add the province element
$form->add('degree', EntityType::class, array(
'placeholder' => 'provide_degree',
'class' => 'AppBundle\Entity\Degree',
'choices' => $degree)
);
// Cities are empty, unless we actually supplied a province
$courses = array();
if ($degree) {
// Fetch the cities from specified province
$repo = $this->em->getRepository('AppBundle:Course');
$courses = $repo->findByDegree($degree, array('name' => 'asc'));
}
// Add the Course element
$form->add('course', EntityType::class, array(
'class' => 'AppBundle\Entity\Course',
'choices' => $courses,
));
}
function onPreSubmit(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
if (isset($data['degree'])) {
// Note that the data is not yet hydrated into the entity.
$degree = $this->em->getRepository('AppBundle:Degree')->find($data['degree']);
$department = $this->em->getRepository('AppBundle:Department')->find($data['department']);
$this->addElements($form, $department, $degree);
}
}
function onPreSetData(FormEvent $event) {
//echo "before submit";die;
$user = $event->getData();
$form = $event->getForm();
if($user){
//if the selected user has role_user only then display the following fields in edit profile view
if (in_array("ROLE_USER", $user->getRoles())) {
$degree = ( !empty($user) && !empty($user->getCourse())) ? $user->getCourse()->getDegree() : null;
$departments = ( !empty($user) && !empty($user->getCourse())) ? $user->getCourse()->getDegree()->getDepartment() : null;
$this->addElements($form, $departments, $degree);
}
}
}
}
在这一点上,我真的无能为力导致这种情况,我真的很感激这里的任何帮助......
答案 0 :(得分:0)
你所提供的内容有很多不妥之处。其中的元素可能会导致您所看到的行为。
安全规则
在security.yml中,你有这一行:
- { path: ^/admin/, roles: ROLE_ADMIN }
这意味着如果没有ROLE_ADMIN的任何使用,如果他们访问此模式,将会被回击到登录屏幕。
同时,在您的控制器中,您始终将用户引导回基于管理员的路线:
/*
* @Route("admin/profile", name="admin_profile")
*/
这意味着,无论他们做什么,他们总是被发送到管理模式。这意味着如果他们改变了自己的角色,他们就会被防火墙踢掉。
<强>控制器强>
在您的控制器中,您将用户实体绑定到formtype,很好。但是你编码的方式意味着你不明白它是如何工作的。
当您调用handleRequest
时,Symfony会从表单中提取数据(如果已提交),并将其与您传递给它的实体“合并”。这意味着您不必在对象上调用任何setter,因为已经为您完成了所有这些。
用户实体
User
实体应拥有的内容是PlainPassword
字段和Password
字段。表单只映射到PlainPassword
字段..然后,在控制器中,获取PlainPassword
值,对其进行编码,将其设置为实体的Password
字段,并确保清除PlainPassword
值(你不想存储它)。如果您在自定义用户实体上实现了UserInterface
(您应该拥有),则应该有一个名为eraseCredentials
的方法,这就是它的用途。 Here is an example
这样做的结果是,当您检查某些内容时,例如新密码时,您只需执行此操作:
if($profileForm->isValid()){
// $userInfo is populated by handleRequest
if ($userInfo->getPlainPassword()) {
// do your encoding/erasing credentials here
}
// ...
}
我还建议你写一个合适的UserManager
课来处理大部分事情。它集中了事物并使调试更容易。 Heres an example
如果您使用的内容如我在示例中所写的那样,这也意味着当您想要更新用户信息时,您只需要拨打$userManager->updateUser($user)
并完成所有驴工作对你而言。