Symfony 5: вызов функции-члена encodePassword () при нулевом значении

привет, я пытаюсь закодировать свой пароль для пользователя моего приложения Итак, я попытался зашифровать в своей функции setPassword
, к сожалению, я получаю эту ошибку, которую я не понимаю: вызов функции-члена encodePassword () на null изображение ошибки

  <?php

 namespace App\Entity;
 use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
 use Gedmo\Mapping\Annotation as Gedmo;
 use Vich\UploaderBundle\Mapping\Annotation as Vich;
 use Symfony\Component\HttpFoundation\File\File;
 use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Security\Core\User\UserInterface;

/**
 * Admin
 *@Vich\Uploadable
 * @ORM\Table(name="admin")
 * @ORM\Entity
 */
 class Admin implements UserInterface 
 {
  /**
 * @var int
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * Undocumented variable
 *
 * @var UserPasswordEncoderInterface
 */
 private $passwordEncoder ;

    /**
 * @see UserInterface
 */
public function getPassword(): string
{
    return (string) $this->password;
}

public function setPassword(string $password): self

    {
     $hash= $this->passwordEncoder->encodePassword($this,$password);
     $this->password=$hash;
     return $this ;
    }
     ....... 

что не так, и как я могу это исправить! спасибо


person Varus    schedule 19.10.2020    source источник
comment
Контейнер Symfony не знает сущностей доктрины, поэтому он не будет внедрять в них сервисы (например, UserPasswordEncoder). Если вы действительно хотите это сделать, вам нужно передать зависимость самостоятельно. Но это обескураживает, предпочтительный подход - получить услугу извне и установить уже закодированный пароль.   -  person msg    schedule 19.10.2020
comment
привет @msg thnx за комментарий, я использую Easyadmin 3, и я не мог найти способ управлять шифрованием моих паролей ... я пытался погуглить последние 30 минут   -  person Varus    schedule 19.10.2020
comment
Отвечает ли это на ваш вопрос? Symfony 4 EasyAdmin как зашифровать пароли?   -  person msg    schedule 19.10.2020
comment
Эта ссылка, кажется, предназначена для EA2, но идея должна быть такой же, сделайте это в контроллере или используйте система событий, чтобы закодировать пароль перед сохранением пользователя. К сожалению, документации пока немного.   -  person msg    schedule 19.10.2020
comment
Я согласен с @msg, я бы не стал поощрять внедрение зависимости. На самом деле, я бы не стал вкладывать столько бизнеса (шифрование pw) в Entity. Однако, если ваш действительно этого хочет, можете ли вы сделать ->encodePassword статическим методом?   -  person agoldev    schedule 19.10.2020
comment
@agoldev И что именно сделает статическим?   -  person Cerad    schedule 19.10.2020
comment
@Cerad, когда вы делаете encodePassword статическим методом (например, объявляете его с помощью общедоступной статической функции), вы можете получить к нему доступ с помощью PasswordEncoder::encodePassword(), и тогда нет необходимости вводить PasswordEncoder как зависимость от Entity. Для вспомогательных функций это допустимое решение, но вы не можете получить доступ к другим свойствам или функциям с помощью $ this в этом методе. Прочтите также о статических методах.   -  person agoldev    schedule 20.10.2020
comment
Я знаю, что PasswordEncoder - это интерфейс, поэтому для этого вам понадобится класс-оболочка.   -  person agoldev    schedule 20.10.2020
comment
@agoldev Спасибо за подсказку, но это вопрос Symfony. Вы не можете изменить интерфейс. Symfony поддерживает несколько кодировщиков паролей, поэтому один статический интерфейс работать не будет. Обратите внимание, что код фактически использует UserPasswordEncoderInterface, который фактически определяет, какой конкретный кодировщик пароля использовать в зависимости от типа пользователя. Проблема здесь в попытке закодировать пароль в объекте пользователя. Просто нет чистого способа сделать это. И, как видно из «ответов» пользователей, они, похоже, полны решимости поступать нелегко.   -  person Cerad    schedule 20.10.2020


Ответы (3)


Я попытался добавить прослушиватель событий, поэтому создаю этот класс

  <?php
  namespace App\Controller\Admin;
  use App\Entity\Admin;
  use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  use EasyCorp\Bundle\EasyAdminBundle\EventListener\AdminContextListener;

 class AdminController extends AdminContextListener
 {
 /**
 * @var UserPasswordEncoderInterface
 */
 private $encoder ;
 public function __construct(UserPasswordEncoderInterface $encoder)
 {
   $this->encoder=$encoder;
  }
 public static function getSetPasswordEvent()
 {
    return [
        BeforeEntityPersistedEvent::class => ['setPassword'],
    ];
}
public function setPassword(BeforeEntityPersistedEvent $event)
{
    $entity = $event->getEntityInstance();
    if (!($entity instanceof Admin)) {
        return;
    }
    $encoded = $this->encoder->encodePassword($entity, $entity->getPassword());
    $entity->setPassword($encoded);
   }
  }

и это тоже не сработало

person Varus    schedule 19.10.2020

но эта работа

<?php
namespace App\Controller\Admin;

use App\Entity\User;
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Field\Field;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class UserCrudController extends AbstractCrudController
{
    /** @var UserPasswordEncoderInterface */
    private $passwordEncoder;

    public static function getEntityFqcn(): string
    {
        return User::class;
    }

    public function configureFields(string $pageName): iterable
    {
        return [
            FormField::addPanel('Change password')->setIcon('fa fa-key'),
            Field::new('plainPassword', 'New password')->onlyOnForms()
                ->setFormType(RepeatedType::class)
                ->setFormTypeOptions([
                    'type' => PasswordType::class,
                    'first_options' => ['label' => 'New password'],
                    'second_options' => ['label' => 'Repeat password'],
                ]),
        ];
    }

    public function createEditFormBuilder(EntityDto $entityDto, KeyValueStore $formOptions, AdminContext $context): FormBuilderInterface
    {
        $formBuilder = parent::createEditFormBuilder($entityDto, $formOptions, $context);

        $this->addEncodePasswordEventListener($formBuilder);

        return $formBuilder;
    }

    public function createNewFormBuilder(EntityDto $entityDto, KeyValueStore $formOptions, AdminContext $context): FormBuilderInterface
    {
        $formBuilder = parent::createNewFormBuilder($entityDto, $formOptions, $context);

        $this->addEncodePasswordEventListener($formBuilder);

        return $formBuilder;
    }

    /**
     * @required
     */
    public function setEncoder(UserPasswordEncoderInterface $passwordEncoder): void
    {
        $this->passwordEncoder = $passwordEncoder;
    }

    protected function addEncodePasswordEventListener(FormBuilderInterface $formBuilder)
    {
        $formBuilder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
            /** @var User $user */
            $user = $event->getData();
            if ($user->getPlainPassword()) {
                $user->setPassword($this->passwordEncoder->encodePassword($user, $user->getPlainPassword()));
            }
        });
    }
}
person Varus    schedule 19.10.2020

Вы должны сделать это при регистрации пользователя, поэтому добавьте это перед выполнением flush (); для нового пользователя:

    $user = new UserEntity();
    $user->setEmail($request->getEmail());

    if ($request->getPassword())
    {
        $createUser->setPassword($this->encoder->encodePassword($user, $request->getPassword()));
    }

    $this->entityManager->persist($createUser);
    $this->entityManager->flush();
    $this->entityManager->clear();

Примечание: $ request содержит полезную нагрузку из внешнего интерфейса {email:, passwprd:}.

Примечание: $ createUser - это пользовательский объект, который нужно очистить.

person Nano    schedule 20.10.2020