Session Error on createView - Symfony 5.0 - php

I'm using Symfony 5.0.11 trying to render a form. For some reason on the $form->createView() call it throws the error 'Failed to start the session: already started by PHP.' It is only happening on this form, my other forms are working fine. Other routes in this class are working as well. Here's my code...
Controller method:
<?php
namespace App\Controller;
use App\Entity\Site;
use App\Form\SiteType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class SitesController extends AbstractController
{
/**
* #Route("/sites/add", name="app_sites_add")
*/
public function site_add(EntityManagerInterface $em, Request $request)
{
$form = $this->createForm(SiteType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$site = $form->getData();
$em->persist($site);
$em->flush();
$this->addFlash('success', 'Site Successfully Added!');
return $this->redirectToRoute('sites');
} else {
return $this->render('sites/form.html.twig', ['siteForm' => $form->createView()]);
}
}
}
Form Method:
<?php
namespace App\Form;
use App\Entity\Site;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class SiteType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('url')
->add('type')
->add('is_active')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Site::class,
]);
}
}
Here's the trace:
/app/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php:148
/app/vendor/symfony/http-foundation/Session/Session.php:57
/app/vendor/symfony/security-csrf/TokenStorage/SessionTokenStorage.php:77
/app/vendor/symfony/security-csrf/CsrfTokenManager.php:72
/app/vendor/symfony/form/Extension/Csrf/Type/FormTypeCsrfExtension.php:77
/app/vendor/symfony/form/ResolvedFormType.php:168
/app/vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php:111
/app/vendor/symfony/form/ResolvedFormType.php:161
/app/vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php:111
/app/vendor/symfony/form/Form.php:1039
/app/src/Controller/SitesController.php:98
App\Controller\SitesController->site_edit(Site $id, EntityManagerInterface $em, Request $request) …
return $this->render('sites/form.html.twig', [
'siteForm' => $form->createView()
]);
}
/app/vendor/symfony/http-kernel/HttpKernel.php:157
/app/vendor/symfony/http-kernel/HttpKernel.php:79
/app/vendor/symfony/http-kernel/Kernel.php:191
/app/public/index.php:25
}```
Thanks for your help.

I found the issue. It was in the security configuration. I'm using the guard authenticator and I hadn't setup a firewall rule for these forms.

Related

Symfony - How to create entity with a form and DTO

I want to create entity with symfony form and DTO. I tried to do DTO and form like I've seen on symfonycast. But there's something wrong and I can't figure it out.
After sending json file via postman I get an error:
Typed property App\Form\Model\CreateFacilityDTO::$pitchTypes must not be accessed before initialization (500 Internal Server Error)
postman body:
{
"name": "legia",
"pitchTypes": ["basketball"],
"address": "kosynierów"
}
Can You tell me what I'm doing wrong?
<?php
namespace App\Controller;
use App\Entity\Facility;
use App\Form\CreateFacilityFormType;
use App\Form\Model\CreateFacilityDTO;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* #method saveEntities(array $array)
*/
class CreateFacilityAction extends AbstractController
{
/**
* #Route("/api/create/facility", name="create_facility")
* #param Request $request
* #return Response
*/
public function __invoke(Request $request, EntityManagerInterface $em)
{
$form = $this->createForm(CreateFacilityFormType::class);
$data = json_decode($request->getContent(), true);
$form->submit($data);
// if ($form->isSubmitted() && $form->isValid()) {
/** #var CreateFacilityDTO $facilityDto */
$facilityDto = $form->getData();
$createFacility = new Facility($facilityDto->name, $facilityDto->pitchTypes,
$facilityDto->address);
$em = $this->getDoctrine()->getManager();
$em->persist($createFacility);
$em->flush();
// return new Response($data, 201);
// }
return new Response($createFacility, 201);
}
}
<?php
namespace App\Form;
use App\Form\Model\CreateFacilityDTO;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CreateFacilityFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('pitchTypes')
->add('address');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => CreateFacilityDTO::class,
]);
}
}
<?php
namespace App\Form\Model;
class CreateFacilityDTO
{
public string $name;
public array $pitchTypes;
public string $address;
}

How to make Select from array in Symfony Entity

I'm new to symfony and still learning, my question is how do I populate a select drop-down in a form with an static array of choices. Say I have a class named Cake, I'd like to be able to fill a drop-down for the status of Cake from the array statuses created in the same CakeEntity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\CakeRepository")
*/
class Cake
{
/**
* #ORM\Column(type="string", length=50)
*/
private $status;
private $statuses = array(
'not_ready' => 'Not Ready',
'almost_ready' => 'Almost Ready',
'ready'=>'Ready',
'too_late'=>'Too late'
);
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}
public function getStatuses()
{
return $this->statuses;
}
}
My Controller looks like:
namespace App\Controller;
use App\Entity\Cake;
use App\Form\CakeType;
use App\Repository\CakeRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* #Route("/cake")
*/
class CakeController extends AbstractController
{
/**
* #Route("/new", name="cake_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$cake = new Cake();
$form = $this->createForm(CakeType::class, $cake);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$cake->setCreatedAt(\DateTime::createFromFormat('d-m-Y', date('d-m-Y')));
$cake->setCreatedBy(1);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($cake);
$entityManager->flush();
return $this->redirectToRoute('cake_index');
}
return $this->render('cake/new.html.twig', [
'cake' => $cake,
'form' => $form->createView(),
]);
}
My CakeEntity:
<?php
namespace App\Form;
use App\Entity\cake;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class CakeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
->add('status', ChoiceType::class,
[
'choices'=>function(?Cake $cake) {
return $cake->getStatuses();
}
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Cake::class,
]);
}
}
When trying to browse /cake/new I get the error:
An error has occurred resolving the options of the form "Symfony\Component\Form\Extension\Core\Type\ChoiceType": The option "choices" with value Closure is expected to be of type "null" or "array" or "\Traversable", but is of type "Closure".
You could declare getStatuses on Cake as static, or use public constants. E.g.:
class Cake
{
// with static variables
private static $statuses = [
'not_ready' => 'Not Ready',
'almost_ready' => 'Almost Ready',
'ready' => 'Ready',
'too_late' => 'Too late',
];
public static function getStatuses()
{
return self::$statuses;
}
// or with public const
public const STATUSES = [
'not_ready' => 'Not Ready',
'almost_ready' => 'Almost Ready',
'ready' => 'Ready',
'too_late' => 'Too late',
];
}
This seems reasonable, as the return value is not instance but class specific.
You could then use:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('status', ChoiceType::class, [
'choices'=> Cake::getStatuses(),
]);
// or
$builder->add('status', ChoiceType::class, [
'choices'=> Cake::STATUSES,
]);
}
If the choices actually depend on a given Cake instance, you could pass it via the options array or use form events.

Symfony3 embeded Forms validation not working

I have a Filter and FilterCollection object. The FilterCollection holds a collection of Filters, just like the name indicate.
Now I need to validate everything, so I created a FilterType and FilterTypeCollection Forms. In the FilterCollectionType I have:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('filters', CollectionType::class, array(
'entry_type' => FilterType::class
));
}
And in the FilterCollection definition I have the following:
/**
* #var array
* #Assert\Valid()
*/
private $filters = [];
I created a paramConverter so I could convert elements from my request into FilterCollection ones. In the apply method I try to validate everything by using:
public function apply(Request $request, ParamConverter $configuration)
$filterCollection = new FilterCollection();
$form = $this->formFactory->create(
FilterTypeCollection::class,
$filterCollection
);
$form->submit($request->query->all());
if ($form->isSubmitted() && $form->isValid()) {
$request->attributes->set($configuration->getName(), $filterCollection);
return true;
} else {
throw new FormValidationException($form);
}
}
I was expecting that the validation not only validates the FilterCollection but also the Filters. But the validations I have in my Filter definition, are not working, even if I have validations that should fail, it still passes. I think the validator is not passing on the Filter elements.
Any idea on what might be happening?
I finally got it to work. Perhaps you made the same mistake as me, forgetting to add "data_class" in the configureOptions in the formType.
Anyway, here's the code that works (on fresh install of Symfony 3.3)
DefaultController.php
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Filter;
use AppBundle\Entity\FilterCollection;
use AppBundle\Form\FilterCollectionType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
// add first filter, so we don't have to implement the collection javascript etc to test quickly
$collection = new FilterCollection();
$collection->filters[] = new Filter();
$form = $this->createForm(FilterCollectionType::class, $collection);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
echo "valid input"; // we don't want to see this ;)
}
}
// replace this example code with whatever you need
return $this->render('default/index.html.twig', [
'form' => $form->createView()
]);
}
}
Filter.php
<?php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Filter {
/**
* #var string
* #Assert\NotBlank()
* #Assert\Regex(pattern="/[0-9]+/")
*/
public $name;
}
FilterCollection.php
<?php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class FilterCollection {
/**
* #var Filter[]
* #Assert\Valid()
*/
public $filters = [];
}
FilterType.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FilterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Filter'
]);
}
}
FilterCollectionType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FilterCollectionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('filters', CollectionType::class, [
'entry_type' => FilterType::class,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\FilterCollection',
]);
}
public function getName()
{
return 'app_bundle_filter_collection_type';
}
}
Note: I didn't make a ParamConverter like you did, but that seems beside the point of the question. You can change the code to use a ParamConverter easily.

Could not load type Symfony2

Ok it is probably something simple but i just cant find where the problem is.
I have tried with but no match for my problem
I am trying to create from but from form class, not create form in controller..
here is the code..
this is from controller
/**
* #Route("login", name="login")
*/
public function loginAction (Request $request) {
$registration = new Registration();
$form = $this->createForm(LoginForm::class, $registration, array(
'method' => 'POST'
));
return $this->render(
'admin/login.html.twig',
array('form' => $form->createView())
);
}
Inside controller i used USE to defind LoginForm i use in part createForm, so that is not problem
this is from FORM class
<?php
namespace AppBundle\AppForm;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class LoginForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('password')
->add('save', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'AppBundle\Entity\Registration'
));
}
public function getName()
{
}
}
Your problem in Symfony version. You use code from Symfony3 while really have Symfony2.
Change SubmitType::class to submit, LoginForm::class to new LoginForm() and all will work fine.
Or you can update your Symfony version and all will work fine with your current code.

Populate form from two entities

I'm trying to populate form from database by using two entities. Here's the code I use
CategoryType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
}
public function configureOptions(OptionsResolver $options)
{
return array(
'data_class' => 'AppBundle\Entity\Category',
);
}
public function getName()
{
return 'questionnaire';
}
}
ProductType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
}
public function configureOptions(OptionsResolver $options)
{
return array(
'data_class' => 'AppBundle\Entity\Product',
);
}
public function getName()
{
return 'questionnaire';
}
}
CommonType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use AppBundle\Form\CategoryType;
use AppBundle\Form\ProductType;
class CommonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', new CategoryType());
$builder->add('product', new ProductType());
}
public function getName()
{
return 'app_common_type';
}
}
DefaultController
<?php
namespace AppBundle\Controller;
use AppBundle\Form\CommonType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$data = $this->getDoctrine()->getRepository('AppBundle:Product')->findOneBy(['id' => 2]);
$form = $this->createForm(new CommonType(), $data);
return $this->render('AppBundle:Default:index.html.twig', ['form' => $form->createView()]);
}
}
But I get this error
The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class Proxies\__CG__\AppBundle\Entity\Category. You can avoid this error by setting the "data_class" option to "Proxies\__CG__\AppBundle\Entity\Category" or by adding a view transformer that transforms an instance of class Proxies\__CG__\AppBundle\Entity\Category to scalar, array or an instance of \ArrayAccess.
So what I'm doing wrong and is this the correct way to populate form based on two or more entities?
Your Common form's model data format is an array (as far as no data_class given). So the right data to set is an array with product and category keys:
$product = $this->getDoctrine()->getRepository('AppBundle:Product')->findOneBy(['id' => 2]);
$form = $this->createForm(new CommonType(), ['product' => $product]);

Categories