I’m new to symfony. I’m trying to use a simple contact form as a service, but I’ve got an error message :
Notice: Undefined property: AppBundle\Controller\ContactsFormController::$container" at /mnt/400Go/www/sy1/src/AppBundle/Controller/ContactsFormController.php line 23
I understand the message (I try to access a property that does not exist), but it’s… the container property? Why isn’t it there? Shall I call it during the __construct() ?
<?php
// src/AppBundle/Controller/ContactsFormController.php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use AppBundle\Entity\ContactSetClass;
use AppBundle\Form\Type\ContactsFormType;
/* */
class ContactsFormController
{
private $formFactory;
public function __construct($formFactory)
{
$this->formFactory = $formFactory;
}
public function createForm($type, $data = null, array $options = array())
{
return $this->container->get('form.factory')->create($type, $data, $options); // THIS IS THE LINE CAUSING THE ERROR
}
public function contactsFormAction(Request $request)
{
$message='';
$contactSet=new ContactSetClass();
$ContactsFormType=new ContactsFormType();
$form=$this->createForm(ContactsFormType::class, $contactSet);
$form->handleRequest($request);
if($form->isSubmitted())
{
if($form->isValid())
{
$contactName=$form->get('contactName')->getData();
$contactEmail=$form->get('contactEmail')->getData();
$contactSet->setContactName($contactName);
$contactSet->setContactEmail($contactEmail);
$entityManager=$this->getDoctrine()->getManager();
$entityManager->persist($contactSet);
$entityManager->flush();
$message='Contact '.$contactName.' has been created for '.$contactEmail.'.';
/* Reset of the form fields. */
$contactSet=new ContactSetClass();
$ContactsFormType=new ContactsFormType();
$form=$this->createForm(ContactsFormType::class, $contactSet);
// Will not work with render controller
//return $this->redirect($request->getUri());
}
else
{
$message='Please correct your data.';
}
}
return $this->render('contactsForm.html.twig', array('contactsForm' => $form->createView(),'message'=>$message,));
}
}
Attempted to call an undefined method named “create” of class “Symfony\Bundle\TwigBundle\TwigEngine”." at /mnt/400Go/www/sy1/src/AppBundle/Controller/ContactsFormController.php line 25
The Symfony base controller has a number of helper functions such as createForm, getUser, render etc. For these to work you need to inject the container using the setContainer method. So to answer your first post, something like:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ContactsFormController extends Controller
services:
contacts_form_controller:
class: AppBundle\Controller\ContactsFormController
calls: [[setContainer, ['@service_container']]]
arguments: ['@contacts.repository']
This approach allows you to define controllers as services and use all the default functionality. It is extremely instructive to examine the base controller class to see how it does things.
You can then use constructor injection to inject services specific to a particular controller. In this case, I added the contacts repository as an example. The idea is to avoid any direct access to the container from within your controller action methods.
Going one step further, I think you will find that instead of defining controllers with multiple action methods as services, you will define each individual action as it’s own class. Lookup Action Domain Responder for more details.
But I understand, that without “extends Controller”, I’d have had to define the container before using it :
private $container;
public function setContainer (ContainerInterface $container)
{
$this->container = $container;
}
Am I right ?
I’ll dive in the doc for the calls and arguments parts. To thin down the controller used as a service through a class was of course the next step. Thanks a lot.
Either you read wrong or whomever wrote this was wrong. Injecting the container is often discouraged as it should be. But in this case, the advantages outweigh the disadvantages. At least in my opinion. Good luck.