Symfony 5 :Call to a member function encodePassword() on null - php

hi im trying to encode My password for My app user So i tried to encrypted in my setPassword function
unfortunately i get this error that i don't understand: Call to a member function encodePassword() on null error pic
<?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 ;
}
.......
whats wrong, and how can i fix it ! thnx

but this one work
<?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()));
}
});
}
}

i tried to add an Event listener so i create this class
<?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);
}
}
and it didn't work too

You should do that when User register, so add this before doing flush(); for new user:
$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();
Notice: $request containe payload comes form frontend {"email": "", "passwprd": ""}.
Notice: $createUser is a user object to flush.

Related

Symfony "Invalid credentials"

I'm developing my first Symfony project and so far pretty good except for the Login since the warning "invalid credentials" started popping up everytime I try to log in and don't really know why because I'm using AbstractLoginFormAuthenticator instead of AbstractFormLoginAuthenticator (the one I see the most), which is driving me a bit crazy because there is not much info.
User entity:
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
* #method string getUserIdentifier()
*/
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=false)
*/
private $name;
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* #ORM\Column(type="json")
*/
private $roles = [];
/**
* #var string The hashed password
* #ORM\Column(type="string")
*/
private $password;
/**
* #ORM\OneToMany(targetEntity="Booking", mappedBy="user")
*/
private $userBooking;
public function getId(): ?int
{
return $this->id;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name): void
{
$this->name = $name;
}
public function getEmail(): ?string
{
return $this->email;
}
/**
* #param mixed $email
*/
public function setEmail($email): void
{
$this->email = $email;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* Returning a salt is only needed, if you are not using a modern
* hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
*
* #see UserInterface
*/
public function getSalt(): ?string
{
return null;
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
}
Security controller:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* #Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
// if ($this->getUser()) {
// return $this->redirectToRoute('target_path');
// }
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
/**
* #Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
LoginFormAuthenticator:
<?php
namespace App\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private UrlGeneratorInterface $urlGenerator;
public function __construct(UrlGeneratorInterface $urlGenerator)
{
$this->urlGenerator = $urlGenerator;
}
public function authenticate(Request $request): PassportInterface
{
$email = $request->request->get('email', '');
$request->getSession()->set(Security::LAST_USERNAME, $email);
return new Passport(
new UserBadge($email),
new PasswordCredentials($request->request->get('password', '')),
[
new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
return new RedirectResponse($targetPath);
}
// For example:
//return new RedirectResponse($this->urlGenerator->generate('some_route'));
//throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
return new RedirectResponse('home');
}
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
Create User:
<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\UserTypeUser;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class NewUserController extends AbstractController
{
#[Route('/newuser', name: 'new_user', methods: ['GET', 'POST'])]
public function index(Request $request): Response
{
$user = new User();
$form = $this->createForm(UserTypeUser::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user->setRoles(['ROLE_USER']);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('home');
}
return $this->render('new_user/index.html.twig', [
'user' => $user,
'form' => $form->createView(),
]);
}
}
Thanks a lot in advance.
In your NewUserController you need to hash the password before you persist the user.
First you need to inject the service into the controller:
private $passwordHasher;
public function __construct(UserPasswordHasherInterface $passwordHasher)
{
$this->passwordHasher = $passwordHasher;
}
Then in your action you need to add one line inside the if condition:
if ($form->isSubmitted() && $form->isValid()) {
$user->setRoles(['ROLE_USER']);
$user->setPassword($this->passwordHasher->hashPassword($user, $user->getPassword());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('home');
}
This assumes that you already set the password in your form, but it's not properly encoded yet. You can find this in the docs here: https://symfony.com/doc/current/security.html#c-hashing-passwords
Be careful, prior to Symfony 5.3 the password hasher was called password encoder and lived inside the security component. The code is fundamentally the same, but the class looks a bit different. See: https://symfony.com/doc/5.2/security.html#c-encoding-passwords

Constraint is not taken in consideration

I am doing a crud for an entity in my application. The form have to upload a file, so i added the assert in the entity file. But when i submit my form the validator give me an error and said to me that the field image have to be a string. I've done upload of file a hundred times, that why i don't understand this time why the validator bundles react like that.
My entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass="App\Repository\AlgorithmeRepository")
*/
class Algorithme
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $titre;
/**
* #ORM\Column(type="date")
*/
private $dateCreationArticle;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Assert\File(mimeTypes={ "image/jpeg","image/png"})
*/
private $image;
/**
* #ORM\Column(type="array")
*/
private $analyse = [];
public function getId(): ?int
{
return $this->id;
}
public function getTitre(): ?string
{
return $this->titre;
}
public function setTitre(string $titre): self
{
$this->titre = $titre;
return $this;
}
public function getDateCreationArticle(): ?\DateTimeInterface
{
return $this->dateCreationArticle;
}
public function setDateCreationArticle(\DateTimeInterface $dateCreationArticle): self
{
$this->dateCreationArticle = $dateCreationArticle;
return $this;
}
public function getImage()
{
return $this->image;
}
public function setImage($image)
{
$this->image = $image;
return $this;
}
public function getAnalyse(): ?array
{
return $this->analyse;
}
public function setAnalyse(array $analyse): self
{
$this->analyse = $analyse;
return $this;
}
}
The form :
<?php
namespace App\Form;
use App\Entity\Algorithme;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AlgorithmeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('titre')
->add('dateCreationArticle',DateType::class,[
'widget' => 'single_text',
// prevents rendering it as type="date", to avoid HTML5 date pickers
'html5' => false,
// adds a class that can be selected in JavaScript
'attr' => ['class' => 'js-datepicker'],
])
->add('image',FileType::class,[
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Algorithme::class,
]);
}
}
And the controller:
<?php
namespace App\Controller;
use App\Entity\Algorithme;
use App\Form\AlgorithmeType;
use App\Repository\AlgorithmeRepository;
use App\Services\CreateFormForArray;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* #Route("/algorithme")
*/
class AlgorithmeController extends AbstractController
{
/**
* #Route("/new", name="algorithme_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$algorithme = new Algorithme();
$form = $this->createForm(AlgorithmeType::class, $algorithme);
$form->handleRequest($request);
// die();
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$CreateFormForArray = new CreateFormForArray();
$CreateFormForArray->handleArrayString($request,$algorithme,"analyse");
$entityManager->persist($algorithme);
$entityManager->flush();
return $this->redirectToRoute('algorithme_index');
} else {
}
return $this->render('algorithme/new.html.twig', [
'algorithme' => $algorithme,
'form' => $form->createView(),
]);
}
}
I found the problem for those who will wondering is was
#auto_mapping:
# App\Entity\: []
that was uncomment in config/packages/validator.yaml

How to inject dependencies into private service using container?

I'm developing Form Request for Symfony, but i have one problem.
I inject FormRequest instances into controller action using argument value resolving. But I would like to inject services to FormRequest instance without making it public in services.yaml file.
Here is my Resolver:
<?php
namespace App\Resolver;
use App\Exception\FormValidationException;
use App\Request\FormRequest;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class ControllerRequestResolver implements ArgumentValueResolverInterface
{
/**
* #var SerializerInterface
*/
private $serializer;
/**
* #var ValidatorInterface
*/
private $validator;
/**
* #var DecoderInterface
*/
private $decoder;
/**
* #var ContainerInterface
*/
private $container;
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
DecoderInterface $decoder,
ContainerInterface $container
) {
$this->serializer = $serializer;
$this->validator = $validator;
$this->decoder = $decoder;
$this->container = $container;
}
/**
* {#inheritdoc}
* #throws FormValidationException
*/
public function resolve(Request $request, ArgumentMetadata $argument)
{
$data = $this->decoder->decode($request->getContent(), 'json');
$request->request->replace($data);
$formRequestClass = $argument->getType();
/** #var FormRequest $form */
$form = $this->container->has($formRequestClass)
? $this->container->get($formRequestClass)
: new $formRequestClass();
$form->initialize(
$request->query->all(), $request->request->all(), $request->attributes->all(),
$request->cookies->all(), $request->files->all(), $request->server->all(), $request->getContent()
);
if (!$form->authorize()) {
throw new AccessDeniedHttpException('Access denied.');
}
$violations = $this->validator->validate($data, $form->rules());
if ($violations->count() > 0) {
throw new FormValidationException($violations, 'Validation error.');
}
yield $form;
}
/**
* {#inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
{
return (new \ReflectionClass($argument->getType()))->isSubclassOf(FormRequest::class);
}
}
So to receive FormRequest with needed dependencies in $this->container->get($formRequestClass) I need to make it public.
Here is FormRequest:
<?php
namespace App\Request;
use App\Entity\User;
use App\Rule\UniqueConfig;
use App\Service\Randomizer;
use App\Validator\Constraints\UniqueEntity;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Validator\Constraints as Assert;
class UserRequest extends FormRequest
{
/**
* #var null|Randomizer
*/
private $randomizer;
public function __construct(Randomizer $randomizer)
{
$this->randomizer = $randomizer;
}
public function authorize(): bool
{
return $this->randomizer->getNumber() > 0.5;
}
public function rules(): Assert\Collection
{
return new Assert\Collection([
'email' => [
new Assert\NotBlank(),
new Assert\Email(),
new UniqueEntity([
'config' => new UniqueConfig(User::class, 'u', 'email', function ($value, QueryBuilder $qb) {
// You can add here additional filtering
}),
]),
],
'firstName' => [
new Assert\Length(['max' => 255]),
],
'lastName' => [
new Assert\Length(['max' => 255]),
],
]);
}
}
Thanks to #Cerad for help! Here is total result:
<?php
namespace App\Locator;
use Symfony\Component\DependencyInjection\ServiceLocator;
class FormRequestServiceLocator extends ServiceLocator
{
}
I inject it (FormRequestServiceLocator) into ControllerRequestResolver
<?php
namespace App\DependencyInjection\Compiler;
use App\Locator\FormRequestServiceLocator;
use App\Request\FormRequest;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
class FormRequestPass implements CompilerPassInterface
{
/**
* {#inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->has(FormRequest::class)) {
return;
}
$taggedServices = $container->findTaggedServiceIds('app.form_request.tag');
$serviceReferences = [];
foreach ($taggedServices as $id => $tags) {
if ($id === FormRequest::class) {
continue;
}
$serviceReferences[$id] = new Reference($id);
}
$driverLocator = $container->getDefinition(FormRequestServiceLocator::class);
$driverLocator->setArguments([$serviceReferences]);
}
}
<?php
namespace App;
// ...
class Kernel extends BaseKernel
{
// ...
protected function build(ContainerBuilder $container)
{
parent::build($container);
$container->registerForAutoconfiguration(FormRequest::class)
->addTag('app.form_request.tag');
$container->addCompilerPass(new FormRequestPass());
}
}

symfony 4 form collection entity with file type create

How to create and upload the document using entity where fileType field is embedded in parent form via collectionType. I did read the documentation Symfony Upload. But didn't manage to accomplish this. Always get this error "Type error: Argument 1 passed to App\Service\FileUploader::upload() must be an instance of Symfony\Component\HttpFoundation\File\UploadedFile, instance of App\Entity\Attachment given".
Below is my Invoice entity
class Invoice
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Attachment", mappedBy="invoiceId", cascade={"persist"})
*/
private $attachments;
public function __construct()
{
$this->attachments = new ArrayCollection();
}
/**
* #return Collection|Attachment[]
*/
public function getAttachments(): Collection
{
return $this->attachments;
}
public function addAttachment(Attachment $attachment): self
{
if (!$this->attachments->contains($attachment)) {
$this->attachments[] = $attachment;
$attachment->setInvoiceId($this);
}
return $this;
}
Attachment entity
class Attachment
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $path;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Invoice", inversedBy="attachments")
*/
private $invoiceId;
public function getId()
{
return $this->id;
}
public function getPath(): ?string
{
return $this->path;
}
public function setPath(string $path): self
{
$this->path = $path;
return $this;
}
public function getInvoiceId(): ?Invoice
{
return $this->invoiceId;
}
public function setInvoiceId(?Invoice $invoiceId): self
{
$this->invoiceId = $invoiceId;
return $this;
}
Attachment form type
namespace App\Form;
use App\Entity\Attachment;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class AttachmentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('path',FileType::class, array(
'label' => false,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Attachment::class,
]);
}
}
Invoice form type
namespace App\Form;
use App\Entity\Invoice;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class InvoiceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('attachments', CollectionType::class, array(
'entry_type' => AttachmentType::class,
'entry_options' => array('label' => false),
'allow_add' => true
))
->add('submit', SubmitType::class, array(
'label' => $options['set_button_label']
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Invoice::class,
'set_button_label' => "Create Invoice",
]);
}
}
and the Controller
namespace App\Controller;
use App\Entity\Invoice;
use App\Form\InvoiceType;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Debug\Debug;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use App\Service\FileUploader;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class InvoiceController extends Controller
{
/**
* #Route("/invoice/create", name="createInvoice")
* #param Request $request
* #param UserInterface $user
* #param FileUploader $fileUploader
* #return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
public function createInvoice( Request $request, UserInterface $user, FileUploader $fileUploader)
{
Debug::enable();
$invoice = new Invoice();
$form = $this->createForm(InvoiceType::class,$invoice);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
// Prepare upload file
/** #var UploadedFile $files */
$files = $invoice->getAttachments();
foreach($files as $file){
$fileName = $fileUploader->upload($file);
}
$file->move(
$this->getParameter('attachment_directory'),
$fileName
);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($invoice);
$entityManager->flush();
return $this->redirectToRoute('user');
}
return $this->render('invoice/createInvoice.html.twig', [
'controller_name' => 'UserController',
'form' => $form->createView()
]);
}
I think the problem is the FileType field return attachment entity instance while it should return File instance. the question is how do i get the value as File instance?
In your case the property $path type of UploadedFile and not $invoice->getAttachments().
Try to add a property to your Attachement class called $file without doctrine mapping, generate it's getter and setter methods.
/**
* #var UploadedFile
*/
protected $file;
In your AttachmentType class change 'path' => 'file'.
Now, try to update this part in your controller:
$attachements = $invoice->getAttachments();
foreach($attachements as $attachement){
/** #var UploadedFile $file */
$file = $attachement->getFile(); // This is the file
$attachement->setPath($this->fileUploader->upload($file));
}
Please, make your fileUploader service the unique responsible for uploading file, no need to use $file->move().

How to Use Object Manager in Symfony3

Error
Catchable Fatal Error: Argument 2 passed to Acme\StoreBundle\Security\TokenAuthenticator::__construct() must be an instance of Doctrine\Common\EventManager, instance of Doctrine\Bundle\MongoDBBundle\ManagerRegistry given, called in D:\xamppNew\htdocs\mtl_project\var\cache\dev\appDevDebugProjectContainer.php on line 6178 and defined
TokenAuthenticator.php
<?php
namespace Acme\StoreBundle\Security;
use Doctrine\Common\EventManager;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\MongoDB\Connection;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
use Doctrine\ODM\MongoDB\Mapping\MappingException;
use Doctrine\ODM\MongoDB\Hydrator\HydratorFactory;
use Doctrine\ODM\MongoDB\Proxy\ProxyFactory;
use Doctrine\ODM\MongoDB\Query\FilterCollection;
use Doctrine\ODM\MongoDB\Repository\RepositoryFactory;
//use Acme\StoreBundle\Security\TokenAuthenticator;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\AuthorizationHeaderTokenExtractor;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
class TokenAuthenticator extends AbstractGuardAuthenticator
{
/**
* #var JWTEncoderInterface
*/
private $jwtEncoder;
/**
* #var Doctrine\Common\Persistence\ObjectManager
*/
protected $om;
/**
* #param JWTEncoderInterface $jwtEncoder
* #param ObjectManager $om
*/
public function __construct(JWTEncoderInterface $jwtEncoder, Doctrine\Common\Persistence\ObjectManager $om)
{
$this->jwtEncoder = $jwtEncoder;
$this->om = $om;
}
/**
* #inheritdoc
*/
public function getCredentials(Request $request)
{
$extractor = new AuthorizationHeaderTokenExtractor(
'Bearer',
'Authorization'
);
$token = $extractor->extract($request);
if (!$token) {
return;
}
return $token;
}
/**
* #inheritdoc
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
$data = $this->jwtEncoder->decode($credentials);
if ($data === false) {
throw new CustomUserMessageAuthenticationException('Invalid Token');
}
$username = $data['username'];
return $this->om
->getRepository('UserBundle:User')
->findOneBy(['username' => $username]);
}
/**
* #inheritdoc
*/
public function checkCredentials($credentials, UserInterface $user)
{
return true;
}
/**
* #inheritdoc
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
}
/**
* #inheritdoc
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
}
/**
* #inheritdoc
*/
public function supportsRememberMe()
{
return false;
}
/**
* #inheritdoc
*/
public function start(Request $request, AuthenticationException $authException = null)
{
return new Response('Token is missing!', Response::HTTP_UNAUTHORIZED);
}
}
Refrence
Difference between ObjectManager and EntityManager in Symfony2?
https://github.com/doctrine/mongodb-odm/blob/785c5039d51923d22902fa1249d1e3dd64018838/lib/Doctrine/ODM/MongoDB/DocumentManager.php#L44
im new in symfonymongodb bundle
can anyone suggest how can i use object manager in contructor as symfony is throwing errors.
doctrine_mongodb is a service that returns a Doctrine\Bundle\MongoDBBundle\ManagerRegistry object. You can get ObjectManager by calling getManager from it.
<?php
namespace Acme\StoreBundle\Security;
use Doctrine\Bundle\MongoDBBundle\ManagerRegistry;
// ...
class TokenAuthenticator extends AbstractGuardAuthenticator
{
/**
* #var Doctrine\Common\Persistence\ObjectManager
*/
protected $om;
// ...
public function __construct(JWTEncoderInterface $jwtEncoder, ManagerRegistry $registry)
{
// ...
$this->om = $registry->getManager();
}

Categories