I'm trying to persist an object via Symfony's Form component. It's not working.
When submitting the form, Symfony redirects me to the actual form, with the data previously submitted appearing in the url with GET method. In the Profiler, I can observe that there is "no POST parameters".
The Controller :
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Entity\Quest;
use AppBundle\Form\QuestType;
class QuestController extends Controller
{
\\...
/**
* @Route("/admin/quest/add", name="quest_add")
*/
public function addAction(Request $request)
{
$quest = new Quest();
$form = $this->createForm(QuestType::class, $quest);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($quest);
$em->flush();
return $this->redirectToRoute('quest_view');
}
return $this->render('admin/quest/add.html.twig', array(
'form' => $form->createView(),
));
}
}
The Type:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
class QuestType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('questName', TextType::class)
->add('questCost', IntegerType::class)
->add('nbEnigma', IntegerType::class)
->add('dateStart', DateTimeType::class)
->add('dateEnd', DateTimeType::class)
->add('rewardFinish', IntegerType::class)
->add('rewardFurther', IntegerType::class)
->add('speech', TextareaType::class)
;
}
\\...
}
The View:
/* ... */
<div class="well">
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.questName) }}
/* ... */
<input type="submit" value="Create" method="post" class="btn btn-default pull-right" />
{{ form_end(form) }}
</div>
/* ... */
Note that I don't use validations for the moment.
The Entity I use is OK, the corresponding table has been created in my PostgreSQL DB via Symfony console, configuration of the parameters.yml is OK too. I can post these elements if needed.
So what could possibly go wrong ? Is that a problem in my Wamp installation or configuration, such as Apache concerns for example ? The fact is I have no clue where the problem is.
Please note that I'm a totally beginner in web-developping. I actually try to learn PHP as well as Symfony2.
EDITS following comments
1) Resulting HTML shows that the form resulting from the Twig render is setting the method of the form to "POST" :
<form name="quest" method="post">
2) Adding @Method({"GET", "POST"})
under the @Route
with use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
didn't changed anything.
3.1) Informations about my Environment :
- Wampserver 2.5 (32 bits & PHP 5.5.12, Apache 2.4.9 )
- PostgreSQL 9.3.2
- Symfony 2.8.1, using Standard Edition + FOSUserBundle ~2.0@dev
- Working with Doctrine2
- Working logged as SuperAdmin (it's a backend form located in my
/admin
directory) in the dev environment (app_dev.php
).
3.2) In my same environment, I've reproduced various forms shown in 3 different online tutorials (from Symfony book, from openclassrooms.com, and from dynamic-mess.com), and it all ended in this same way.
4) Just in case, I just went to restart the project, by reinstalling Symfony, with the same version and the same configuration, with the same Wampserver and PostgreSQL. I just kept an eye on preventing to miss some steps. It still does'nt work.
5) TEST of a Basic HTML form in my environment : Using a Form without a Class (without Entity)
The Controller :
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class QuestController extends Controller
{
// ...
/**
* @Route("/admin/test/add", name="test")
*/
public function testAction(Request $request)
{
$defaultData = array('message' => 'Type your message here');
$form = $this->createFormBuilder($defaultData)
->add('nametest', TextType::class)
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$data = $form->getData();
}
return $this->render('admin/test.html.twig', array(
'form' => $form->createView(),
));
}
}
The View :
/* ... */
<div class="well">
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.nametest) }}
<input type="submit" value="Create" method="post" class="btn btn-default pull-right" />
{{ app.request }}
{{ form_end(form) }}
</div>
/* ... */
For this test, I used the Twig global template variable {{ app.request }}
.
Before clicking the submitting button, the page show these informations :
GET /gowinquest/web/app_dev.php/admin/test/add HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Cache-Control: max-age=0 Connection: keep-alive Cookie: __utma=111872281.2124856035.1451232730.1452442012.1452447222.32; __utmz=111872281.1451232730.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=111872281; PPA_ID=not8odr8dlslv6eoo25l2llai6; webfx-tree-cookie-persistence=wfxt-14+wfxt-36+wfxt-20+wfxt-4+wfxt-16+wfxt-18+wfxt-6; PHPSESSID=h94nvh0nn315po8np66httkv56; __utmb=111872281.0.10.1452447222 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0 X-Php-Ob-Level: 1
After, the resulting page discards these informations :
GET /gowinquest/web/app_dev.php/admin/test/add?form%5Bnametest%5D=blablabla&form%5B_token%5D=pzhE6hrzsNf3EYbHJLmEXf0miAh4J5jeOH_ccrmlmW4 HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Connection: keep-alive Cookie: __utma=111872281.2124856035.1451232730.1452442012.1452447222.32; __utmz=111872281.1451232730.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=111872281; PPA_ID=not8odr8dlslv6eoo25l2llai6; webfx-tree-cookie-persistence=wfxt-14+wfxt-36+wfxt-20+wfxt-4+wfxt-16+wfxt-18+wfxt-6; PHPSESSID=h94nvh0nn315po8np66httkv56; __utmb=111872281.0.10.1452447222 Host: localhost Referer: http://localhost/gowinquest/web/app_dev.php/admin/test/add User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0 X-Php-Ob-Level: 1
6) I tried the Symfony's generator for CRUD controllers and templates on my Entity, IT WORKED ! My data was sending by POST, and has been registered in database.
But that's still a huge mistery to me, since the methods generated in the Controller and the Form by Symfony are the same than the methods I manually tried before...
The CRUD generator uses @Method({"GET", "POST"})
, that's the only difference I have observed with my initially code. But it is strange, because I also tried @Method
annotations by myself before and it didn't changed nothing (see my 2nd EDIT)...
Still, I'm a very beginner with PHP and with Symfony, a totally newbie, so for sure there is something evident that I missed... But what ? At this moment I have NO IDEA. Explanations are welcome, if someone's got a clue ? I've got to figure out the key of that mistery.
7) Here's the log provided by default by Symfony2.8 in app/logs/dev.log
file, from the time I initially show the form until the request is redirected :
[2016-01-11 16:02:38] request.INFO: Matched route "_wdt". {"route_parameters":{"_controller":"web_profiler.controller.profiler:toolbarAction","token":"e945fe","_route":"_wdt"},"request_uri":"http://localhost/gowinquest/web/app_dev.php/_wdt/e945fe"} []
[2016-01-11 16:03:16] request.INFO: Matched route "quest_add". {"route_parameters":{"_controller":"AppBundle\\Controller\\QuestController::addAction","_route":"quest_add"},"request_uri":"http://localhost/gowinquest/web/app_dev.php/admin/quest/add?quest%5B_token%5D=74fPFHnb4NPKfAotccGEE9T4EDCUhaEHY4w-hqViwUw&quest%5BdateEnd%5D%5Bdate%5D%5Bday%5D=1&quest%5BdateEnd%5D%5Bdate%5D%5Bmonth%5D=1&quest%5BdateEnd%5D%5Bdate%5D%5Byear%5D=2011&quest%5BdateEnd%5D%5Btime%5D%5Bhour%5D=0&quest%5BdateEnd%5D%5Btime%5D%5Bminute%5D=0&quest%5BdateStart%5D%5Bdate%5D%5Bday%5D=1&quest%5BdateStart%5D%5Bdate%5D%5Bmonth%5D=1&quest%5BdateStart%5D%5Bdate%5D%5Byear%5D=2011&quest%5BdateStart%5D%5Btime%5D%5Bhour%5D=0&quest%5BdateStart%5D%5Btime%5D%5Bminute%5D=0&quest%5BnbEnigma%5D=1&quest%5BquestCost%5D=1&quest%5BquestName%5D=Test4&quest%5BrewardFinish%5D=1&quest%5BrewardFurther%5D=1&quest%5Bspeech%5D=test4speech"} []
[2016-01-11 16:03:16] security.DEBUG: Read existing security token from the session. {"key":"_security_main"} []
[2016-01-11 16:03:16] doctrine.DEBUG: SELECT t0.username AS username_1, t0.username_canonical AS username_canonical_2, t0.email AS email_3, t0.email_canonical AS email_canonical_4, t0.enabled AS enabled_5, t0.salt AS salt_6, t0.password AS password_7, t0.last_login AS last_login_8, t0.locked AS locked_9, t0.expired AS expired_10, t0.expires_at AS expires_at_11, t0.confirmation_token AS confirmation_token_12, t0.password_requested_at AS password_requested_at_13, t0.roles AS roles_14, t0.credentials_expired AS credentials_expired_15, t0.credentials_expire_at AS credentials_expire_at_16, t0.id AS id_17 FROM fos_user t0 WHERE t0.id = ? LIMIT 1 [1] []
[2016-01-11 16:03:16] security.DEBUG: User was reloaded from a user provider. {"username":"admin","provider":"FOS\\UserBundle\\Security\\EmailUserProvider"} []
[2016-01-11 16:03:17] security.DEBUG: Stored the security token in the session. {"key":"_security_main"} []
[2016-01-11 16:03:18] request.INFO: Matched route "_wdt". {"route_parameters":{"_controller":"web_profiler.controller.profiler:toolbarAction","token":"83737b","_route":"_wdt"},"request_uri":"http://localhost/gowinquest/web/app_dev.php/_wdt/83737b"} []
As for the Profiler (configured by default), there's nothing more than this :
200 ::1 GET http://localhost/gowinquest/web/app_dev.php/admin/quest/add?quest%5B_token%5D=74fPFHnb4NPKfAotccGEE9T4EDCUhaEHY4w-hqViwUw&quest%5BdateEnd%5D%5Bdate%5D%5Bday%5D=1&quest%5BdateEnd%5D%5Bdate%5D%5Bmonth%5D=1&quest%5BdateEnd%5D%5Bdate%5D%5Byear%5D=2011&quest%5BdateEnd%5D%5Btime%5D%5Bhour%5D=0&quest%5BdateEnd%5D%5Btime%5D%5Bminute%5D=0&quest%5BdateStart%5D%5Bdate%5D%5Bday%5D=1&quest%5BdateStart%5D%5Bdate%5D%5Bmonth%5D=1&quest%5BdateStart%5D%5Bdate%5D%5Byear%5D=2011&quest%5BdateStart%5D%5Btime%5D%5Bhour%5D=0&quest%5BdateStart%5D%5Btime%5D%5Bminute%5D=0&quest%5BnbEnigma%5D=1&quest%5BquestCost%5D=1&quest%5BquestName%5D=test5&quest%5BrewardFinish%5D=1&quest%5BrewardFurther%5D=1&quest%5Bspeech%5D=test5
11-Jan-2016 16:24:32 ee563e
200 ::1 GET http://localhost/gowinquest/web/app_dev.php/admin/quest/add 11-Jan-2016 16:23:39 d0f70c