I am a beginner on Symfony 6 and I am blocked because I have an error message: "Undefined method getDoctrine" with Intelephense
Here is my code:
#[Route('/recettes', name: 'app_recettes')]
public function index(int $id): Response
{
$em = $this->getDoctrine()->getManager();
$recette = $em->getRepository(Recettes::class)->findBy(['id' => $id]);
return $this->render('recettes/index.html.twig', [
'RecettesController' => 'RecettesController',
]);
}
Your controller should extends AbstractController from use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
You should not use getDoctrine()->getManager() in symfony 6. If you look into the method from AbstractController you can see:
trigger_deprecation('symfony/framework-bundle', '5.4', 'Method "%s()" is deprecated, inject an instance of ManagerRegistry in your controller instead.', __METHOD__);
You should just autowire your entity manager in your method or constructor and use it directly.
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
#[Route('/recettes', name: 'app_recettes')]
public function index(int $id): Response
{
$recette = $this->entityManager->getRepository(Recettes::class)->findBy(['id' => $id]);
return $this->render('recettes/index.html.twig', [
'RecettesController' => 'RecettesController',
]);
}
You could also autowire your RecettesRepository directly instead of the entity manager if you just want to fetch some data.
I'm guessing that you want to show a specific resource by using its id. You probably want to add something /{id} in your route:
#[Route('/recettes/{id}', name: 'app_recettes')]
Dylan response is really good !
If you want to fecth a specific recette (blog de cuisine?), you can autowire the 'recette' as an argument :
#[Route('/recettes/{id}', name: 'app_recettes')]
public function index(Recette $recette): Response
{
return $this->render('recettes/index.html.twig', [
'recette' => $recette,
]);
}
To do so, don't forget to install and import :
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
Related
I'm bulding a webapp in Symfony, and I need to access to some properties of an entity in a controller to add this values to $candidature entity. Thank you for the help.
Controller.php :
class CandidatureController extends AbstractController
{
#[Route('/candidature', name: 'app_candidature')]
public function index(EntityManagerInterface $entityManager): Response
{
$candidature = new Candidature();
//$candidatNom = $entityManager->getRepository(ProfileCandidat::class)->findBy($Nom);
$candidature->setNom($candidatNom);
$candidature->setPrenom('Charles');
$candidature->setCv('cv');
$candidature->setPostId('4');
$entityManager->persist($candidature);
$entityManager->flush();
return $this->render('candidature/index.html.twig', [
'controller_name' => 'CandidatureController',
]);
}
}
$candidatNom = $entityManager->getRepository(ProfileCandidat::class)->findBy(['nom' => $Nom);
should do the trick
I created my first own service in Symfony :
// src/Service/PagesGenerator.php
namespace App\Service;
class PagesGenerator
{
public function getPages()
{
$page = $this->getDoctrine()->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);
$messages = [
'You did it! You updated the system! Amazing!',
'That was one of the coolest updates I\'ve seen all day!',
'Great work! Keep going!',
];
$index = array_rand($messages);
return $messages[$index];
}
}
But I get the error message:
Attempted to call an undefined method named "getDoctrine" of class
"App\Service\PagesGenerator".
I tried then to add in my services.yaml:
PagesGenerator:
class: %PagesGenerator.class%
arguments:
- "#doctrine.orm.entity_manager"
But then I get the error message:
The file "/Users/work/project/config/services.yaml" does not contain
valid YAML in /Users/work/project/config/services.yaml (which is
loaded in resource "/Users/work/project/config/services.yaml").
So, in comments I was saying that is better to let Symfony doing his job and autowiring EntityManager. This is what you should do. Also, can you tell us what Symfony version are you using and if autowiring is enabled (check services.yaml for that)?
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
class PagesGenerator
{
public function __construct(EntityManagerInterface $em) {
$this->em = $em;
}
public function getPages()
{
$page = $this->em->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);
$messages = [
'You did it! You updated the system! Amazing!',
'That was one of the coolest updates I\'ve seen all day!',
'Great work! Keep going!',
];
$index = array_rand($messages);
return $messages[$index];
}
}
With Symfony 4 and the new autowiring you can easily inject certain number of class
To find out, which classes/interface you can use for autowiring, use this command:
bin/console debug:autowiring
We are going to use this one :
Doctrine\ORM\EntityManagerInterface
(doctrine.orm.default_entity_manager)
So let's make it, add this just before getPages function
/**
* #var EntityManagerInterface
*/
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
Then you can use it like this:
$page = $this->em->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);
Hope it helps !
make sure you use proper indent using "spaces" for YAML.
A YAML file use spaces as indentation, you can use 2 or 4 spaces for
indentation, but no tab
read more about this
Before symfony 3.3
for example we have service sms_manager in AppBundle/FrontEndBundle/Services
services:
AppBundle.sms_manager:
class: AppBundle\FrontEndBundle\Services\SmsManager
arguments: [ '#service_container' ,'#doctrine.orm.entity_manager' ]
then your service can receive your arguments in constructor
<?php
namespace AppBundle\FrontEndBundle\Services;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class SmsManager {
private $container;
private $DM;
public function __construct( Container $container, \Doctrine\ORM\EntityManager $DM )
{
$this->container = $container;
$this->DM = $DM;
}
/**
* #return \Doctrine\ORM\EntityManager
*/
public function getDoctrine() {
return $this->DM;
}
}
With Symfony 3.3 or more,
Is there a way to inject EntityManager into a service
use Doctrine\ORM\EntityManagerInterface
class PagesGenerator
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
// ...
}
I want to get current logged user in form event but for some reason I can't get it to work.
I used services to inject token_storage and create constructor method to fetch token storage instance but I got error right at constructor:
Type error: Argument 1 passed to AdminBundle\Form\EventListener\CompanyFieldSubscriber::__construct() must implement interface Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface, none given
I am not sure what is the problem and how to fix it. Does someone knows where is the problem?
EDIT 1:
I think that I found out where is the problem but I can't find "good" solution. I call this event in form type in this way:
->addEventSubscriber(new CompanyFieldSubscriber());
Problem is that I am not using 'service/dependency injection' to create event and I am sending nothing to constructor. That's why I have this error (not 100% sure to be hones).
Since I have around 20-30 forms and new forms will come in time I need to create service for each form that requires user (or token_storage) instance and as a argument call token_storage or this event subscriber as a argument of service.
I know that it will work if I create each form as a service and pass required data as arguments but is there way to process this "automatically" without creating new service for every form that needs to have some user data interaction in form events?
EDIT 2:
As suggested I tried to change event subscriber constructor but I got same error with different class name.
New code:
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
public function __construct(TokenStorage $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
New error:
Type error: Argument 1 passed to AdminBundle\Form\EventListener\CompanyFieldSubscriber::__construct() must be an instance of Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage, none given
This is code I am using:
Services:
admin.form.event_listener.company:
class: AdminBundle\Form\EventListener\CompanyFieldSubscriber
arguments: ['#security.token_storage']
tags:
- { name: form.event_listener }
Event Listener:
namespace AdminBundle\Form\EventListener;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class CompanyFieldSubscriber implements EventSubscriberInterface
{
private $tokenStorage;
private $user;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
$this->user = $this->tokenStorage->getToken()->getUser();
}
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::PRE_SUBMIT => 'preSubmitData',
];
}
public function preSetData(FormEvent $event)
{
$form = $event->getForm();
if (in_array("ROLE_SUPER_ADMIN", $this->user->getRoles())) {
$form->add('company', EntityType::class, [
'class' => 'AppBundle:Company',
'choice_label' => 'name'
]);
}
}
public function preSubmitData(FormEvent $event)
{
$form = $event->getForm();
$bus = $form->getData();
if (!in_array("ROLE_SUPER_ADMIN", $this->user->getRoles())) {
$bus->setCompany($this->user->getCompany());
}
}
}
You call subscriber in wrong way when you use:
new CompanyFieldSubscriber()
You do not pass TokenStorageInterface to subscriber constructor. Call it as a service, if it is in controller then:
->addEventSubscriber($this->get('admin.form.event_listener.company'));
if it is in form than pass from controller to form
$this->get('admin.form.event_listener.company')
as option and then use it in form
for Symfony >= 4
use Symfony\Component\Security\Core\Security;
class ExampleService
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function someMethod()
{
$user = $this->security->getUser();
}
}
See doc: https://symfony.com/doc/current/security.html#fetching-the-user-from-a-service
For my project, I need to redirect the user after registration. In order to achieve that, I created an EventListener as described below :
My Event Listener :
namespace UserBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class RegistrationConfirmListener implements EventSubscriberInterface
{
private $router;
public function __construct(UrlGeneratorInterface $router)
{
$this->router = $router;
}
/**
* {#inheritDoc}
*/
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_CONFIRM => 'onRegistrationConfirm'
);
}
public function onRegistrationConfirm(GetResponseUserEvent $event)
{
$url = $this->router->generate('standard_user_registration_success');
$event->setResponse(new RedirectResponse($url));
}
}
I registered it as a service in my service.yml :
services:
rs_user.registration_complet:
class: UserBundle\EventListener\RegistrationConfirmListener
arguments: [#router]
tags:
- { name: kernel.event_subscriber }
And I need to use it in my RegistrationController but I don't understand how to trigger it.
Here in my registerAction :
public function registerAction(Request $request)
{
$em = $this->get('doctrine.orm.entity_manager');
//Form creation based on my user entity
$user = new StandardUser();
$form = $this->createForm(RegistrationStandardUserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user ->setEnabled(true);
$em ->persist($user);
$em ->flush();
if ($user){
$dispatcher = $this->get('event_dispatcher');
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_CONFIRM);
}
}
return $this->render('UserBundle:Registration:register.html.twig', array(
'form' => $form->createView()
));
}
I don't understand the Symfony2 documentation about the subject neither what I need to pass to the ->dispatch() function to trigger my event.
[EDIT]
I get this error when I register my user :
Type error: Argument 1 passed to
UserBundle\EventListener\RegistrationConfirmListener::onRegistrationConfirm()
must be an instance of UserBundle\EventListener\GetResponseUserEvent,
instance of Symfony\Component\EventDispatcher\Event given
500 Internal Server Error - FatalThrowableError
Your listener declares that it is subscribed to FOSUserEvents::REGISTRATION_CONFIRM but you are dispatching FOSUserEvents::REGISTRATION_COMPLETED. To trigger it you need to dispatch a FOSUserEvents::REGISTRATION_CONFIRM event
edit to match your edit, you need to pass the event in your services tags:
- { name: 'kernel.event_subscriber', event: 'fos_user.registration.confirm'}
I need to set a default value to a new user before saving it.
The problem is that I can't find a way to get an object through its repository from inside the FormHandler.
<?php
namespace Acme\UserBundle\Form\Handler;
use FOS\UserBundle\Form\Handler\RegistrationFormHandler as BaseHandler;
use FOS\UserBundle\Model\UserInterface;
class RegistrationFormHandler extends BaseHandler
{
protected function onSuccess(UserInterface $user, $confirmation)
{
$repository = $this->container->get('doctrine')->getEntityManager()->getRepository('AcmeUserBundle:Photo');
if($user->isMale()){
$photo = $repository->getDefaultForMale();
$user->setPhoto($photo);
}
else {
$photo = $repository->getDefaultForFemale();
$user->setPhoto($photo);
}
parent::onSuccess($user, $confirmation);
}
}
The problem comes from the following line :
$repository = $this->container->get('doctrine')->getEntityManager()->getRepository('AcmeUserBundle:Photo');
... and I can't find a way to get this repository, or the entity manager from this FormHandler.
Many thanks for your help !
A
You have to define a service that reference your extended handler class and point it in app/config.yml. e.g
The class,
//namespace definitions
class MyHandler extends RegistrationFormHandler{
private $container;
public function __construct(Form $form, Request $request, UserManagerInterface $userManager, MailerInterface $mailer, ContainerInterface $container)
{
parent::__construct($form, $request, $userManager, $mailer);
$this->container = $container;
}
protected function onSuccess(UserInterface $user, $confirmation)
{
$repository = $this->container->get('doctrine')->getEntityManager()->getRepository('AcmeUserBundle:Photo');
// your code
}
The service,
my.registration.form.handler:
scope: request
class: FQCN\Of\MyHandler
arguments: [#fos_user.registration.form, #request, #fos_user.user_manager, #fos_user.mailer, #service_container]
Lastly in app/config.yml,
fos_user:
#....
registration:
#...
form:
handler: my.registration.form.handler
FOS got his own UserManager. Try to use this.