我面临着一个非常奇怪的情况,一旦我更改名称,具有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);
}
}
}
}
在这一点上,我真的不知道可能导致这种情况的原因是什么,我将非常感谢这里的任何帮助......
您提供的内容有很多错误。 其中的元素可能会导致您看到的行为。
安全规则
在security.yml中,你有这样一行:
- { path: ^/admin/, roles: ROLE_ADMIN }
这意味着如果他们访问此模式,任何没有ROLE_ADMIN的使用都将被射回登录屏幕。
同时,在控制器中,您始终将用户引导回基于管理员的路由:
/*
* @Route("admin/profile", name="admin_profile")
*/
这意味着,无论他们做什么,他们总是被发送到管理模式。 这意味着如果他们改变角色,他们将被防火墙踢出。
控制器
在控制器中,您将用户实体绑定到窗体类型,很好。 但是你编码的方式意味着你不明白它是如何工作的。
当你调用handleRequest
时,Symfony从表单中提取数据(如果它已经提交),并将其与你传递给它的实体"合并"。 这意味着您不必在对象上调用任何 setter,因为所有操作都已经为您完成
用户实体
User
实体上应该有一个PlainPassword
字段和一个Password
字段。 表单仅映射到PlainPassword
字段。然后,在控制器中,获取PlainPassword
值,对其进行编码,将其设置为实体的Password
字段,并确保清除PlainPassword
值(不想存储该值)。如果你已经在自定义用户实体上实现了UserInterface
(你应该有),你应该有一个名为 eraseCredentials
的方法,这就是它的用途。下面是一个示例。
这样做的结果是,当您检查某些内容(例如新密码)时,您只需执行以下操作:
if($profileForm->isValid()){
// $userInfo is populated by handleRequest
if ($userInfo->getPlainPassword()) {
// do your encoding/erasing credentials here
}
// ...
}
我还建议,你写一个合适的UserManager
类来处理大部分这些事情。 它集中了事情,使调试更容易。 这是一个例子
如果您使用我在示例中编写的内容,这也意味着当您想要更新用户信息时,您只需调用$userManager->updateUser($user)
,它就会为您完成所有驴工作。