I'm having an error using the paginator bundle inside a twig loop , I think missions is waiting for a sliddingpagination and not a persistentcollection , I think it's in the controller in the FindAllVisibleQuery, like waiting for an array but IDK..
This is the error I'm receiving:
Argument 2 passed to
Knp\Bundle\PaginatorBundle\Twig\Extension\PaginationExtension::render()
must be an instance of
Knp\Bundle\PaginatorBundle\Pagination\SlidingPaginationInterface,
array given, called in
/Applications/MAMP/htdocs/MySUPER/var/cache/dev/twig/12/12cef122792496c7b8dbcf0cc1f03b575f10f859de41093d7a8fd223b1623d7d.php
on line 176
MissionController.php
<?php
namespace App\Controller;
use App\Entity\Mission;
use App\Entity\MissionSearch;
use App\Form\MissionSearchType;
use App\Repository\MissionRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class MissionController extends AbstractController {
/**
* #var MissionRepository
*/
private $repository;
/**
* #var EntityManagerInterface
*/
private $em;
public function __construct(MissionRepository $repository, EntityManagerInterface $em)
{
$this->repository = $repository;
$this->em = $em;
}
/**
* #return Response
* #throws \Twig\Error\LoaderError
* #throws \Twig\Error\RuntimeError
* #throws \Twig\Error\SyntaxError
* #Route ("/missions" , name="Missions")
*/
public function index(PaginatorInterface $paginator, Request $request): Response
{
$search = new MissionSearch();
$form = $this->createForm(MissionSearchType::class, $search);
$form->handleRequest($request);
$missions = $paginator->paginate(
$this->repository->findAllVisibleQuery($search),
$request->query->getInt('page', 1),
18
);
return $this->render('lesmissions/index.html.twig', [
'current_menu' => 'missions',
'missions' => $missions,
'form' => $form->createView()
]);
}
/**
* #Route("/missions/{slug}-{id}", name="mission.show", requirements={"slug": "[a-z0-9\-]*"})
* #param Mission $mission
* #return Response
*/
public function show(Mission $mission, string $slug): Response
{
if ($mission->getSlug() !== $slug) {
return $this->redirectToRoute('mission.show', [
'id' => $mission->getId(),
'slug' => $mission->getSlug()
], 301);
}
return $this->render('lesmissions/show.html.twig', [
'mission' => $mission,
'current_menu' => 'missions'
]);
}
}
?>
Twig snippet
{% extends 'base.html.twig' %}
{% block title 'Missions' %}
{% block body %}
<div class="jumbotron text-center">
<h1>Trouvez une mission qui vous correspond</h1>
<p>My super est encore en developpement , vous pouvez apporter vos idées via le formulaire de contact</p>
</div>
<div class="jumbotron">
<div class="container">
{% if form is defined %}
{{ form_start(form) }}
<div class="form-row align-items-end">
<div class="col">
{{ form_row(form.maxGain) }}
</div>
<div class="col">
{{ form_row(form.deltaVille) }}
</div>
<div class="col">
{{ form_row(form.options) }}
</div>
<div class="col">
<div class="form-group">
<button class="btn btn-primary">Rechercher</button>
</div>
</div>
</div>
{{ form_end(form) }}
{% endif %}
</div>
</div>
<div class="container">
<h2>Les dernieres missions</h2>
<div class="row flex">
{% for mission in missions %}
<div class="col-3">
<div class="card mb-4">
<div class="card-body">
<h5 class="card-title">
{{ mission.titre }}
</h5>
<p class="card-text">{{ mission.adresse }} {{ mission.ville }}</p>
<div class="text-primary" style="font-weight: bold;font-size: 2rem;">{{ mission.gain }} €</div>
</div>
</div>
</div>
<div class="pagination">
{{ knp_pagination_render(missions) }}
</div>
{% endfor %}
</div>
</div>
{% endblock %}
MissionRepository.php
<?php
namespace App\Repository;
use App\Entity\Mission;
use App\Entity\MissionSearch;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Query;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\ORM\QueryBuilder;
/**
* #method Mission|null find($id, $lockMode = null, $lockVersion = null)
* #method Mission|null findOneBy(array $criteria, array $orderBy = null)
* #method Mission[] findAll()
* #method Mission[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class MissionRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Mission::class);
}
/**
* #return Query
*/
public function findAllVisibleQuery(MissionSearch $search): Query
{
$query = $this->findVisibleQuery();
if ($search->getMaxGain()) {
$query = $query
->andWhere('p.price <= :maxgain')
->setParameter('maxgain', $search->getMaxGain());
}
if ($search->getDeltaVille()) {
$query = $query
->andWhere('m.ville = :deltaville')
->setParameter('deltaville', $search->getDeltaVille());
}
if ($search->getOptions()->count() > 0) {
$k = 0;
foreach($search->getOptions() as $option) {
$k++;
$query = $query
->andWhere(":option$k MEMBER OF m.options")
->setParameter("option$k", $option);
}
}
return $query->getQuery();
}
/**
* #return Mission[]
*/
public function findLatest(): array
{
return $this->findVisibleQuery()
->setMaxResults(30)
->getQuery()
->getResult();
}
private function findVisibleQuery(): QueryBuilder
{
return $this->createQueryBuilder('m')
->where('m.Accepted = false');
}
// /**
// * #return Mission[] Returns an array of Mission objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('m')
->andWhere('m.exampleField = :val')
->setParameter('val', $value)
->orderBy('m.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Mission
{
return $this->createQueryBuilder('m')
->andWhere('m.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
you need to edit your repository class to return the QueryBuilder instead of the Query itself.
Your function must be something lke that:
public function findAllVisibleQuery(MissionSearch $search): Query
{
$query = $this->findVisibleQuery();
if ($search->getMaxGain()) {
$query = $query
->andWhere('p.price <= :maxgain')
->setParameter('maxgain', $search->getMaxGain());
}
if ($search->getDeltaVille()) {
$query = $query
->andWhere('m.ville = :deltaville')
->setParameter('deltaville', $search->getDeltaVille());
}
if ($search->getOptions()->count() > 0) {
$k = 0;
foreach($search->getOptions() as $option) {
$k++;
$query = $query
->andWhere(":option$k MEMBER OF m.options")
->setParameter("option$k", $option);
}
}
return $query;
}
Related
i've been having the Csrf token is invalid I tried to add the {{ form_end(form) }}
or remove token from {{ form_widget(form._token) }} but it doens't work please help me fix this problem
here'is my registration content file
{% trans_default_domain 'FOSUserBundle' %}
<div class="login-container bg-white">
<div class="p-l-50 m-l-20 p-r-50 m-r-20 p-t-50 m-t-30 sm-p-l-15 sm-p-r-15 sm-p-t-40">
<img src="assets/img/logo.png" alt="logo" data-src="assets/img/logo.png"
data-src-retina="assets/img/logo_2x.png" width="78" height="22">
<p class="p-t-35">Sign into your pages account</p>
<form action="{{ path("fos_user_security_check") }}" method="post">
<div class="form-group form-group-default">
<label>Username</label>
<div class="controls">
{{ form_widget(form.username,{'attr' : {'class' : 'form-control' , 'placeholder' : 'E-mail'}}) }}
</div>
</div>
<div class="form-group form-group-default">
<label>E-mail</label>
<div class="controls">
{{ form_widget(form.email,{'attr' : {'class' : 'form-control' , 'placeholder' : 'E-mail'}}) }}
</div>
</div>
<div class="form-group form-group-default">
<label>Passowrd</label>
<div class="controls">
{{ form_widget(form.plainPassword.first,{'attr' : {'class' : 'form-control' , 'placeholder' : 'Mot de passe'}}) }}
</div>
</div>
<div class="form-group form-group-default">
<label>Passowrd</label>
<div class="controls">
{{ form_widget(form.plainPassword.second,{'attr' : {'class' : 'form-control' , 'placeholder' : 'Confirmez mot de passe'}}) }}
</div>
</div>
{{ form_rest(form) }}
{{ form_widget(form._token) }}
<input type="submit" value="{{ 'registration.submit'|trans }}"class="btn btn-primary btn-cons m-t-10" />
</form>
<div class="pull-bottom sm-pull-bottom">
<div class="m-b-30 p-r-80 sm-m-t-20 sm-p-r-15 sm-p-b-20 clearfix">
<div class="col-sm-3 col-md-2 no-padding">
<img alt="" class="m-t-5" data-src="assets/img/demo/pages_icon.png"
data-src-retina="assets/img/demo/pages_icon_2x.png" height="60"
src="assets/img/demo/pages_icon.png" width="60">
</div>
<div class="col-sm-9 no-padding m-t-10">
<p>
<small>
Create a pages account. If you have a facebook account, log into it for this
process. Sign in with Facebook or <a href="#"
class="text-info">Google</a>
</small>
</p>
</div>
</div>
</div>
</div>
</div>
<?php
/*
* This file is part of the FOSUserBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FOS\UserBundle\Controller;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Form\Factory\FactoryInterface;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Model\UserInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
/**
* Controller managing the registration.
*
* #author Thibault Duplessis <thibault.duplessis#gmail.com>
* #author Christophe Coevoet <stof#notk.org>
*/
class RegistrationController extends Controller
{
/**
* #param Request $request
*
* #return Response
*/
public function registerAction(Request $request)
{
/** #var $formFactory FactoryInterface */
$formFactory = $this->get('fos_user.registration.form.factory');
/** #var $userManager UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
/** #var $dispatcher EventDispatcherInterface */
$dispatcher = $this->get('event_dispatcher');
$user = $userManager->createUser();
$user->setEnabled(true);
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_registration_confirmed');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_FAILURE, $event);
if (null !== $response = $event->getResponse()) {
return $response;
}
}
return $this->render('#FOSUser/Registration/register.html.twig', array(
'form' => $form->createView(),
));
}
/**
* Tell the user to check their email provider.
*/
public function checkEmailAction()
{
$email = $this->get('session')->get('fos_user_send_confirmation_email/email');
if (empty($email)) {
return new RedirectResponse($this->get('router')->generate('fos_user_registration_register'));
}
$this->get('session')->remove('fos_user_send_confirmation_email/email');
$user = $this->get('fos_user.user_manager')->findUserByEmail($email);
if (null === $user) {
throw new NotFoundHttpException(sprintf('The user with email "%s" does not exist', $email));
}
return $this->render('#FOSUser/Registration/check_email.html.twig', array(
'user' => $user,
));
}
/**
* Receive the confirmation token from user email provider, login the user.
*
* #param Request $request
* #param string $token
*
* #return Response
*/
public function confirmAction(Request $request, $token)
{
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserByConfirmationToken($token);
if (null === $user) {
throw new NotFoundHttpException(sprintf('The user with confirmation token "%s" does not exist', $token));
}
/** #var $dispatcher EventDispatcherInterface */
$dispatcher = $this->get('event_dispatcher');
$user->setConfirmationToken(null);
$user->setEnabled(true);
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_CONFIRM, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_registration_confirmed');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_CONFIRMED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
/**
* Tell the user his account is now confirmed.
*/
public function confirmedAction()
{
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
return $this->render('#FOSUser/Registration/confirmed.html.twig', array(
'user' => $user,
'targetUrl' => $this->getTargetUrlFromSession(),
));
}
/**
* #return mixed
*/
private function getTargetUrlFromSession()
{
$key = sprintf('_security.%s.target_path', $this->get('security.token_storage')->getToken()->getProviderKey());
if ($this->get('session')->has($key)) {
return $this->get('session')->get($key);
}
}
}
I am using CollectionType Field in my Symfony project, to be able to generate as many similar form items as user needs. The problem I have appears while form is being submitted - it passes all the values directly to db, but the foreign key id (household_app_id) remains null, even though relations seem to be correct.
What can I do to prevent this bug? And why is this happening?
My project code is below:
Both Entities:
<?php //HouseholdApp.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* HouseholdApp
*
* #ORM\Table(name="household_application")
* #ORM\Entity(repositoryClass="AppBundle\Repository\HouseholdAppRepository")
* #Vich\Uploadable
*
*/
class HouseholdApp
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* One Application has One Household.
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Household", inversedBy="householdApp")
* #ORM\JoinColumn(name="household_id", referencedColumnName="id")
*/
private $household;
/**
* #var File
*
* #Vich\UploadableField(mapping="union_register", fileNameProperty="unionRegisterName")
*/
private $unionRegister;
/**
* #var File
*
* #Vich\UploadableField(mapping="apt_owners_decision", fileNameProperty="aptOwnersDecisionName")
*/
private $aptOwnersDecision;
/**
* #var File
*
* #Vich\UploadableField(mapping="mulaptinventory", fileNameProperty="multiAptInventoryName")
*/
private $multiAptInventory;
/**
* #var File
*
* #Vich\UploadableField(mapping="buildtechsurvey", fileNameProperty="buildingTechnicalSurveyName")
*/
private $buildingTechnicalSurvey;
/**
* #var File
*
* #Vich\UploadableField(mapping="defectact", fileNameProperty="defectActName")
*/
private $defectAct;
/**
* #var File
*
* #Vich\UploadableField(mapping="activitycost", fileNameProperty="activityCostName")
*/
private $activityCost;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\DefectAct", mappedBy="householdApp", cascade={"persist"}, orphanRemoval=true)
*/
protected $actOfDefects;
/**
* Set unionRegister
*
* #param File|UploadedFile $unionRegister
*
* #return HouseholdApp
*/
public function setUnionRegister(File $unionRegister = null)
{
$this->unionRegister = $unionRegister;
if ($unionRegister) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->uUpdatedAt = new \DateTime('now');
}
return $this;
}
/**
* Get unionRegister
*
* #return File|UploadedFile
*/
public function getUnionRegister()
{
return $this->unionRegister;
}
/**
* Set aptOwnersDecision
*
* #param File|UploadedFile $aptOwnersDecision
*
* #return HouseholdApp
*/
public function setAptOwnersDecision(File $aptOwnersDecision = null)
{
$this->aptOwnersDecision = $aptOwnersDecision;
if ($aptOwnersDecision) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->aUpdatedAt = new \DateTime('now');
}
return $this;
}
/**
* Get aptOwnersDecision
*
* #return File|UploadedFile
*/
public function getAptOwnersDecision()
{
return $this->aptOwnersDecision;
}
/**
* Set multiAptInventory
*
* #param File|UploadedFile $multiAptInventory
*
* #return HouseholdApp
*/
public function setMultiAptInventory(File $multiAptInventory = null)
{
$this->multiAptInventory = $multiAptInventory;
if ($multiAptInventory) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->mUpdatedAt = new \DateTime('now');
}
return $this;
}
/**
* Get multiAptInventory
*
* #return File|UploadedFile
*/
public function getMultiAptInventory()
{
return $this->multiAptInventory;
}
/**
* Set buildingTechnicalSurvey
*
* #param File|UploadedFile $buildingTechnicalSurvey
*
* #return HouseholdApp
*/
public function setBuildingTechnicalSurvey(File $buildingTechnicalSurvey = null)
{
$this->buildingTechnicalSurvey = $buildingTechnicalSurvey;
if ($buildingTechnicalSurvey) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->bUpdatedAt = new \DateTime('now');
}
return $this;
}
/**
* Get buildingTechnicalSurvey
*
* #return File|UploadedFile
*/
public function getBuildingTechnicalSurvey()
{
return $this->buildingTechnicalSurvey;
}
/**
* Set defectAct
*
* #param File|UploadedFile $defectAct
*
* #return HouseholdApp
*/
public function setDefectAct(File $defectAct = null)
{
$this->defectAct = $defectAct;
if ($defectAct) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->dUpdatedAt = new \DateTime('now');
}
return $this;
}
/**
* Get defectAct
*
* #return File|UploadedFile
*/
public function getDefectAct()
{
return $this->defectAct;
}
/**
* Set activityCost
*
* #param File|UploadedFile $activityCost
*
* #return HouseholdApp
*/
public function setActivityCost(File $activityCost = null)
{
$this->activityCost = $activityCost;
if ($activityCost) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->acUpdatedAt = new \DateTime('now');
}
return $this;
}
/**
* Get activityCost
*
* #return File|UploadedFile
*/
public function getActivityCost()
{
return $this->activityCost;
}
}
<?php //DefectAct.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* DefectAct
*
* #ORM\Table(name="defect_act")
* #ORM\Entity(repositoryClass="AppBundle\Repository\DefectActRepository")
*
*/
class DefectAct
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $defectWork;
/**
* #var string
*
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $defectDescription;
/**
* #var string
*
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $preventionDeadline;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\HouseholdApp", inversedBy="actOfDefects")
*/
private $householdApp;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set defectWork
*
* #param string $defectWork
*
* #return DefectAct
*/
public function setDefectWork($defectWork)
{
$this->defectWork = $defectWork;
return $this;
}
/**
* Get defectWork
*
* #return string
*/
public function getDefectWork()
{
return $this->defectWork;
}
/**
* Set defectDescription
*
* #param string $defectDescription
*
* #return DefectAct
*/
public function setDefectDescription($defectDescription)
{
$this->defectDescription = $defectDescription;
return $this;
}
/**
* Get defectDescription
*
* #return string
*/
public function getDefectDescription()
{
return $this->defectDescription;
}
/**
* Set preventionDeadline
*
* #param string $preventionDeadline
*
* #return DefectAct
*/
public function setPreventionDeadline($preventionDeadline)
{
$this->preventionDeadline = $preventionDeadline;
return $this;
}
/**
* Get preventionDeadline
*
* #return string
*/
public function getPreventionDeadline()
{
return $this->preventionDeadline;
}
/**
* Set householdApp
*
* #param \AppBundle\Entity\HouseholdApp $householdApp
*
* #return DefectAct
*/
public function setHouseholdApp(\AppBundle\Entity\HouseholdApp $householdApp = null)
{
$this->householdApp = $householdApp;
return $this;
}
/**
* Get householdApp
*
* #return \AppBundle\Entity\HouseholdApp
*/
public function getHouseholdApp()
{
return $this->householdApp;
}
}
Controller:
/**
* #Security("has_role('ROLE_HOUSEHOLD')")
* #param \Symfony\Component\HttpFoundation\Request $request
* #return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
public function householdApplicationAction(Request $request) {
$application = $this->getUser()->getRhousehold()->getHouseholdApp();
$flag = true;
if(is_null($application)) {
$flag = false;
}
$form = $this->createForm(HouseholdAppType::class, $application, ['disabled' => false]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$appData = $form->getData();
$em = $this->get("doctrine.orm.default_entity_manager");
$household = $this->getUser()->getRhousehold();
$appData->setHousehold($household);
$em->persist($appData);
$em->flush();
return $this->redirectToRoute("householder_app");
}
return $this->render("#App/household_application.html.twig",
['form' => $form->createView(), 'householdapp' => $application]);
}
Forms:
<?php //HouseholdAppType
namespace AppBundle\Form;
use AppBundle\Entity\HouseholdApp;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class HouseholdAppType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('multiapthouseaddress', TextType::class, ['label' => 'form.multiapthouseaddress'])
->add('cadastralnumberofbuilding', TextType::class, ['label' => 'form.cadastralnumberofbuilding'])
->add('totalbuildingarea', TextType::class, ['label' => 'form.totalbuildingarea'])
->add('house_constructive_solution', TextType::class, ['label' => 'form.house_constructive_solution'])
->add('exploitation_start_year', IntegerType::class, ['label' => 'form.exploitation_start_year'])
->add('non_residential_area', TextType::class, ['label' => 'form.non_residential_area'])
->add('has_heat_supply_system', CheckboxType::class, ['label' => 'form.has_heat_supply_system'])
->add('apts_with_individual_heating', TextType::class, ['label' => 'form.apts_with_individual_heating'])
->add('authorized_person_data', TextType::class, ['label' => 'form.authorized_person_data'])
->add('is_vatpayer', CheckboxType::class, ['label' => 'form.is_vatpayer'])
->add('personal_code', TextType::class, ['label' => 'form.personal_code'])
->add('declared_address', TextType::class, ['label' => 'form.declared_address'])
->add('contact_person_data', TextType::class, ['label' => 'form.contact_person_data'])
->add('unionRegister', VichFileType::class, ['required' => false, 'label' => 'form.unionRegister'])
->add('aptOwnersDecision', VichFileType::class, ['required' => false, 'label' => 'form.aptOwnersDecision'])
->add('multiAptInventory', VichFileType::class, ['required' => false, 'label' => 'form.multiAptInventory'])
->add('buildingTechnicalSurvey', VichFileType::class, ['required' => false, 'label' => 'form.buildingTechnicalSurvey'])
->add('defectAct', VichFileType::class, ['required' => false, 'label' => 'form.defectAct'])
->add('activityCost', VichFileType::class, ['required' => false, 'label' => 'form.activityCost'])
->add('actOfDefects', CollectionType::class, [
'label' => true,
'entry_type' => DefectsActCollectionType::class,
'allow_add' => true,
'prototype' => true,
'allow_delete' => true,
'by_reference' => false,
'delete_empty' => true,
'required' => false
])
->add('save', SubmitType::class, [
'label' => 'form.save',
'attr' => [
'class' => 'btn2'
]]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => HouseholdApp::class,
'translation_domain' => 'main',
));
}
}
<?php //DefectActCollectionType
namespace AppBundle\Form;
use AppBundle\Entity\DefectAct;
use AppBundle\Entity\HouseholdApp;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DefectsActCollectionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('defectWork', TextType::class)
->add('defectDescription', TextType::class)
->add('preventionDeadline', TextType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'translation_domain' => 'main',
'data_class' => DefectAct::class
]);
}
public function getBlockPrefix()
{
return 'app_bundle_defects_act_collection_type';
}
}
Template:
{% extends '#App/templates/base.html.twig' %}
{% trans_default_domain "main" %}
{% block main %}
{% include '#App/templates/progressbar.html.twig' %}
{% include '#App/templates/tabs.html.twig' %}
{% include '#App/h_apply_menu.html.twig' %}
<section id='cabinet_household_app'>
<div class='container'>
<div class="tab-content">
<div id="h-apply" class="tab-pane fade in active form_page">
{{ form_start(form)}}
{{ form_row(form._token) }}
<h3>{{ 'form.house_data'|trans }}</h3>
<div class='field'><div class="form-group"> {{ form_row(form.multiapthouseaddress)}}</div></div>
<div class='field'><div class="form-group"> {{ form_row(form.cadastralnumberofbuilding)}}</div></div>
<div class='field'><div class="form-group"> {{ form_row(form.totalbuildingarea)}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.house_constructive_solution)}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.exploitation_start_year)}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.non_residential_area)}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.has_heat_supply_system, {'required': false})}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.apts_with_individual_heating)}}</div></div>
<h3>{{ 'form.app_applying_person'|trans }}</h3>
<div class='field'><div class="form-group">{{ form_row(form.authorized_person_data)}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.is_vatpayer, {'required': false})}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.personal_code)}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.declared_address)}}</div></div>
<div class='field'><div class="form-group">{{ form_row(form.contact_person_data)}}</div></div>
<h3>{{ 'form.apply_documents'|trans }}</h3>
<section id='cabinet_household_inner_app'>
{% if householdapp is null %}
<h4>{{ 'form.unionRegister'|trans }}</h4>
<div class='field'><div class="form-group">{{ form_widget(form.unionRegister) }}</div></div>
<h4>{{ 'form.aptOwnersDecision'|trans }}</h4>
<div class='field'><div class="form-group">{{ form_widget(form.aptOwnersDecision) }}</div></div>
<h4>{{ 'form.multiAptInventory'|trans }}</h4>
<div class='field'><div class="form-group">{{ form_widget(form.multiAptInventory) }}</div></div>
<h4>{{ 'form.buildingTechnicalSurvey'|trans }}</h4>
<div class='field'><div class="form-group">{{ form_widget(form.buildingTechnicalSurvey) }}</div></div>
<h4>{{ 'form.defectAct'|trans }}</h4>
<div class='field'><div class="form-group">{{ form_widget(form.defectAct) }}</div></div>
<h4>{{ 'form.activityCost'|trans }}</h4>
<div class='field'><div class="form-group">{{ form_widget(form.activityCost) }}</div></div>
{% else %}
<h4>{{ 'form.unionRegister'|trans }}</h4>
Download
<h4>{{ 'form.aptOwnersDecision'|trans }}</h4>
Download
<h4>{{ 'form.multiAptInventory'|trans }}</h4>
Download
<h4>{{ 'form.buildingTechnicalSurvey'|trans }}</h4>
Download
<h4>{{ 'form.defectAct'|trans }}</h4>
Download
<h4>{{ 'form.activityCost'|trans }}</h4>
Download
{% endif %}
<div class="container center" data-prototype="{{ form_widget(form.actOfDefects.vars.prototype)|e('html_attr') }}">
{% for actOfDefect in form.actOfDefects %}
<div class="row document">{{ form_row(actOfDefect) }}</div>
{% endfor %}
<div class="row">
<div class="col-xs-12 center">
<div id="add" class="btn2">{{ "common.addFile"|trans }}</div>
</div>
</div>
</div>
</section>
<div class="center">{{ form_row(form.save) }}</div>
{{ form_end(form, {'render_rest': false}) }}
</div>
</div>
</div>
</section>
{% endblock main %}
{% block js_bottom %}
<script>
var $collectionHolder;
$(document).ready(function () {
// Get the ul that holds the collection of tags
$collectionHolder = $('div.container.center');
// add a delete link to all of the existing tag form li elements
$collectionHolder.find('li').each(function() {
addTagFormDeleteLink($(this));
});
// add the "add a tag" anchor and li to the tags ul
//$collectionHolder.append($newLinkLi);
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$('#add').on('click', function (e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
addTagForm($collectionHolder);
});
});
function addTagFormDeleteLink($tagFormLi) {
var $removeFormA = $('{{ "common.cancel"|trans }}');
$tagFormLi.append($removeFormA);
$removeFormA.on('click', function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// remove the li for the tag form
$tagFormLi.remove();
});
}
function addTagForm($collectionHolder) {
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormBlock = $('<div class="row document"></div>').append(newForm);
$collectionHolder.append($newFormBlock);
addTagFormDeleteLink($newFormBlock);
}
</script>
{% endblock %}
In your class HouseholdApp, you must have :
public function addActOfDefects(\AppBundle\Entity\DefectAct $actOfDefect)
{
$this->actOfDefects[] = $actOfDefect;
$actOfDefect->setHouseholdApp($this);
return $this;
}
public function removeActOfDefects(\AppBundle\Entity\DefectAct $actOfDefect)
{
$this->actOfDefects->removeElement($actOfDefect);
}
HI everyone Im working on a project using FOSUserBundle to manage users inside the application, what I want to do is to - almost the same thing as - move/copy the template of password change inside a page that contains the profile of the current user, it works fine, it displays for me ChangePasswordFormType, however when I submit the changes to the controller it gives me an error like this :
Catchable Fatal Error: Argument 1 passed to User\UserBundle\Entity\Acces::checkAllFields() must be an instance of Symfony\Component\Validator\ExecutionContext, instance of Symfony\Component\Validator\Context\ExecutionContext given
thats my controller :
$request = $this->get('request');
$em = $this->getDoctrine()->getManager();
$roles = $em->getRepository('AdminAdminBundle:Role')->findAll();
$userManager = $this->get('fos_user.user_manager');
$user = new \User\UserBundle\Entity\Acces();
$user = $this->container->get('security.context')->getToken()->getUser();
/** #var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
$dispatcher = $this->container->get('event_dispatcher');
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::CHANGE_PASSWORD_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->container->get('fos_user.change_password.form.factory');
$form = $formFactory->createForm();
$form->setData($user);
$currentuser = $user;
$personnel = $em->getRepository('AdminAdminBundle:Personnel')->findBy(array('acces' => $user));
$user = $this->container->get('security.context')->getToken()->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('Cet utilisateur n\'a pas d\'acces à ce contenu.');
}
if ($request->isMethod('POST')) {
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->get('fos_user.change_password.form.factory');
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->container->get('fos_user.user_manager');
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::CHANGE_PASSWORD_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->container->get('router')->generate('personnel_profile');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::CHANGE_PASSWORD_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
}
The View code is :
<form role="form" name="passchange" method="post" {{ form_enctype(password_form) }} action="{{ path('personnel_update_personnal') }}" id="form_sample_2">
<input type="hidden" name="passchange" value="0" />
<div class="form-group">
<label class="control-label">Mot de passe actuel</label>
{{ form_widget(password_form.current_password,{ 'attr': {'required': 'required', 'class':'form-control'} }) }}
<span class="help-block">
{{ form_errors(password_form.current_password) }} </span>
</div>
<div class="form-group">
<label class="control-label">Nouveau mot de passe</label>
{{ form_widget(password_form.plainPassword.first,{ 'attr': {'required': 'required', 'class':'form-control'} }) }}
<span class="help-block">
{{ form_errors(password_form.plainPassword.first) }} </span>
</div>
<div class="form-group">
<label class="control-label">Confirmation mot de passe</label>
{{ form_widget(password_form.plainPassword.second,{ 'attr': {'required': 'required', 'class':'form-control'} }) }}
<span class="help-block">
{{ form_errors(password_form.plainPassword.second) }} </span>
</div>
<div class="margin-top-10">
<button type="submit" class="btn green-haze">Valider le changement</button>
<button type="reset" class="btn default reset">Annuler le changement</button>
</div>
</form>
A simple note: The entity User (of the userBundle) in my case is named Acces
The error given above is generated on the line : $form->handleRequest($request);
Plz if someone has encountered this error, any info could be helpful
Thanks a lot.
Edit : the Use Entity :
namespace User\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use Symfony\Component\Validator\ExecutionContext;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
* #Assert\Callback(methods={"checkAllFields"})
* #ORM\AttributeOverrides({
* #ORM\AttributeOverride(name="username", column=#ORM\Column(nullable=true)),
* #ORM\AttributeOverride(name="email", column=#ORM\Column(nullable=true)),
* #ORM\AttributeOverride(name="password", column=#ORM\Column(nullable=true)),
* })
*/
class Acces extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="\Admin\AdminBundle\Entity\Role" )
* #ORM\JoinColumn(name="role_id", referencedColumnName="id")
* #Assert\Null(groups={"Registration"})
*/
private $role;
public function __construct()
{
parent::__construct();
// your own logic
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set role
*
* #param \Admin\AdminBundle\Entity\Role $role
* #return Acces
*/
public function setRole(\Admin\AdminBundle\Entity\Role $role = null)
{
$this->role = $role;
return $this;
}
/**
* Get role
*
* #return \Admin\AdminBundle\Entity\Role
*/
public function getRole()
{
return $this->role;
}
public function checkAllFields(ExecutionContext $context) {
if (!(($this->username == null && $this->password == null && $this->email == null && $this->role == null )
|| ($this->username != null && $this->password != null && $this->email != null && $this->role != null )
)) {
$context->validate($this->getRole(), 'Acces', array("Registration"));
}
}
public function __toString() {
return parent::__toString();
}
}
Having the following error in my doctrine query when trying to find a specific tag selected by the user.
[Semantical Error] line 0, col 78 near 'tag WHERE blog.tags': Error: Class Acme\DemoBundle\Entity\Blog has no association named tags
Can someone tell what's wrong with the query? (trying to query for a tag selected in the side bar that brings up all posts related to the tag)
Repository
public function getPostsByTags($tags)
{
$qb = $this->createQueryBuilder('b');
$qb->select('b')
->join('b.tags', 'tag')
->where('b.tags LIKE ?', '%'.$tags.'%');
return $qb->getQuery()->getResult();
}
Blog Entity
/**
* #var string
*
* #ORM\Column(name="tags", type="text")
*/
private $tags;
/**
* Set tags
*
* #param string $tags
* #return Blog
*/
public function setTags($tags)
{
$this->tags = $tags;
return $this;
}
/**
* Get tags
*
* #return string
*/
public function getTags()
{
return $this->tags;
}
Controller
/**
* #Route("/tag/{tag}", name="AcmeDemoBundle_tag")
* #Template("AcmeDemoBundle:Page:tag.html.twig")
*/
public function tagAction($tag = null)
{
$em = $this->getDoctrine()->getManager();
$tags = $em->getRepository('AcmeDemoBundle:Blog')
->getPostsByTags($tag);
if (!$tags) {
throw $this->createNotFoundException('Unable to find blog posts');
}
return array(
'tags' => $tags,
);
}
Sidebar Twig
<p class="tags">
{% for tag, weight in tags %}
<span class="weight-{{ weight }}">{{ tag }}</span>
{% else %}
<p>There are no tags</p>
{% endfor %}
</p>
Tag results twig
{% block body %}
{% for tag in tags %}
<article class="result">
<div class="date"><time datetime="{{ tag.created|date('c') }}">{{ tag.created|date('l, F j, Y') }}</time></div>
<header>
<h2>{{ tag.title }}</h2>
</header>
<img src="{{ asset(['images/', tag.image]|join) }}" />
<div class="snippet">
<p>{{ tag.blog|truncate(250, true) }}</p>
<p class="continue">More...</p>
</div>
<footer class="meta">
<p>Comments: -</p>
<p>Posted by <span class="highlight">{{tag.author}}</span> at {{ tag.created|date('h:iA') }}</p>
<p>Tags: <span class="highlight">{{ tag.tags }}</span></p>
</footer>
</article>
{% else %}
<p>There are no blog entries for Health&Fitness blog</p>
{% endfor %}
{% endblock %}
Updated solution: repository query (no blogs found)
public function getPostsByTags($tags)
{
$query = $this->createQueryBuilder('b')
->where('b.tags = :tags')
->setParameter('tags', $tags);
return $query->getQuery()->getResult();
}
Updated solution: controller using query (no blogs found)
public function tagAction(tags=null)
{
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('AcmeDemoBundle:Blog');
$tags = $repository->createQueryBuilder('b')
->where('b.tags = :tags')
->setParameter('tags', $tags)
->getQuery()
->getResult();
return array(
'tags' => $tags,
);
}
Change your getPostsByTags function to:
$repository = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Blog');
$query = $repository->createQueryBuilder('b')
->where('b.tags = :tags')
->setParameter('tags', $tags)
->getQuery();
return $query->getResult();
This is the query that worked. Hope this helps others.
public function getPostsByTags($tag)
{
$query = $this->createQueryBuilder('b')
->where('b.tags like :tag')
->setParameter('tag', '%'.$tag.'%');
return $query->getQuery()->getResult();
}
You can take a look at the answer i give to a similar problem (3rd solution) : Symfony2 - Need help setting up a doctrine query for finding tags
public function getBlogsWithTag($tagRequested)
{
$blogs = $this->findAll();
$blogsWithTag = array();
$tags = array();
foreach ($blogs as $blog)
{
$tags = explode(",", $blog->getTags());
foreach ($tags as &$tag)
{
$tag = trim($tag);
}
if(in_array($tagRequested, $tags)) {
array_push($blogsWithTag, $blog);
}
}
return $blogsWithTag;
}
I have the todolist where i display three forms of task type
$task1 = new Task();
$form1 = $this->createForm(new MyForm('f1'), $task1);
$task2 = new Task('fo');
$form2 = $this->createForm(new MyForm('f2'), $task2);
$task3 = new Task();
$form3 = $this->createForm(new MyForm('f3'), $task3);
Now the problem is i have one submit button only . How can i persist these three tasks within one controller. and user can add more forms dynamically as well.
so what the way to solve this
Create a Form Model class — like TaskList — that holds a collection of Tasks. Then create TaskListType that holds a collection of TaskTypes. This way you'll have one form with as many tasks as you want.
For the sake of completeness find below a complete example.
You should create a new Model that represents the desired form. The point is that you probably don't want to affect Doctrine (eg. see doctrine:schema:update command). It might try to create a table for an entity that doesn't really exist. To avoid that, just put your model class under the Model folder (\src\Acme\Bundle\DemoBundle\Model\TaskList.php).
Assume that the following is your TaskType form class:
<?php
namespace Acme\Bundle\DemoBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', null, array('read_only' => true))
->add('name');
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Acme\Bundle\DemoBundle\Entity\Task'
)
);
}
/**
* #return string
*/
public function getName()
{
return 'acme_demo_task';
}
}
This should be your TaskList model class:
<?php
namespace Acme\Bundle\DemoBundle\Model;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Class TaskList
* #package Acme\Bundle\DemoBundle\Model
*
* #ORM\Entity()
*/
class TaskList
{
/**
* #var \Doctrine\Common\Collections\ArrayCollection
* #ORM\ManyToMany(targetEntity="\Acme\Bundle\DemoBundle\Entity\Task")
*/
private $tasks;
public function __construct()
{
$this->tasks = new ArrayCollection();
}
/**
* #param \Acme\Bundle\DemoBundle\Entity\Task $task
* #return $this
*/
public function addTask(\Acme\Bundle\DemoBundle\Entity\Task $task)
{
$this->tasks[] = $task;
return $this;
}
/**
* #param \Acme\Bundle\DemoBundle\Entity\Task $task
* #return $this
*/
public function removeTask(\Acme\Bundle\DemoBundle\Entity\Task $task)
{
$this->tasks->remove($task);
return $this;
}
/**
* #return ArrayCollection
*/
public function getTasks()
{
return $this->tasks;
}
/**
* #param \Doctrine\Common\Collections\Collection $tasks
* #return $this
*/
public function setTasks(\Doctrine\Common\Collections\Collection $tasks)
{
$this->tasks = $tasks;
return $this;
}
/**
* #param \Knp\Component\Pager\Pagination\PaginationInterface $pagination
* #return $this
*/
public function setFromPagination(\Knp\Component\Pager\Pagination\PaginationInterface $pagination)
{
foreach ($pagination as $task) {
$this->addTask($task);
}
return $this;
}
}
And find below the TaskListType class:
<?php
namespace Acme\Bundle\DemoBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskListType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'tasks',
'collection',
array(
'type' => new \Acme\Bundle\DemoBundle\Form\TaskType(),
)
)
->add('save', 'submit');
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Acme\Bundle\DemoBundle\Model\TaskList'
)
);
}
/**
* #return string
*/
public function getName()
{
return 'acme_demo_task_list';
}
}
And your services.yml (optional):
services:
acme.demo.form.type.task_list:
class: Acme\Bundle\DemoBundle\Form\TaskListType
tags:
- { name: form.type, alias: acme_demo_task_list }
And a sample controller:
public function indexAction($page)
{
ini_set('xdebug.max_nesting_level', 300); // this might be useful with deeply nested forms
$search = $this->getRequest()->get(
'search',
array(
'name' => '',
'date' => '',
'lang' => $this->container->getParameter('acme_core.default_lang')
)
);
/**
* #var \Doctrine\ORM\EntityManager $em
*/
$em = $this->getDoctrine()->getManager();
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$em->getRepository('AcmeDemoBundle:Task')->getQueryFilteringByLangNameAndDate(
$search['lang'],
$search['name'],
$search['date'] != '' ? new \DateTime($search['date']) : null
),
$page,
$this->getRequest()->get('elementsPerPage', 10)
);
$taskList = new TaskList();
$taskList->setFromPagination($pagination);
$form = $this->createForm('acme_demo_task_list', $taskList); // "acme_demo_task_list" has been defined in the services.yml file
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
foreach ($form->getData() as $task) {
$em->merge($task);
}
$em->flush();
}
return $this->render(
'AcmeDemoBundle:Task:index.html.twig',
array(
'search' => $search,
'pagination' => $pagination,
'form' => $form->createView()
)
);
}
I hope this helps!
We followed the exapmle shown by 'Francesco Casula' and it worked perfectly.
For orur purposes we didn't need pagination, so this is how we filled our collection (in the controller):
$entities = $em->getRepository('AcmeBundle:Stock')->findAll();
$stockList = new StockList(); // This is our model, what Francesco called 'TaskList'
foreach ($entities as $entity) {
$stockList->addStock($entity);
}
// StockListType() is what Francesco called TaskListType
$form = $this->createForm(new StockListType(), $stockList, array(
'action' => $this->generateUrl('stock_take_update'),
'method' => 'POST',
'attr' => array('class' => 'form-horizontal'),
));
For those who needs to customise the output of the form collections, we managed to access the subform by iterating on {% for form in forms.children.stocks %}. 'Stocks' being the name of the field in our form builder (in StockListType):
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'stocks', 'collection', array(
'type' => new StockType(),
)
)
->add('submit', 'submit')
;
}
This is what we ended up using in our twig view:
{{ form_start(forms) }}
<table class="table table-stripped table-hover">
<thead>
<th>#</th>
<th>Name</th>
<th>Code</th>
<th>Location</th>
<th>Total</th>
<th>Updated Toal</th>
</thead>
<tbody>
{% set counter = 1 %}
{% for form in forms.children.stocks %}
<tr>
<div class="hidden">
{{ form_widget(form.name) }}
{{ form_widget(form.code) }}
{{ form_widget(form.location) }}
{{ form_widget(form.available) }}
{{ form_widget(form.assigned) }}
{{ form_widget(form.minLevel) }}
{{ form_widget(form.type) }}
{{ form_widget(form.colourCode) }}
</div>
<td>{{ counter }}</td>
<td>
{% if form.vars.data.name is defined %}
{{ form.vars.data.name }}
{% endif %}
</td>
<td>
{% if form.vars.data.code is defined %}
{{ form.vars.data.code }}
{% endif %}
</td>
<td>
{% if form.vars.data.location is defined %}
{{ form.vars.data.location }}
{% endif %}
</td>
<td>
{% if form.vars.data.total is defined %}
{{ form.vars.data.total }}
{% endif %}
</td>
<td>{{ form_widget(form.total) }}</td>
</tr>
{% set counter = counter + 1 %}
{% endfor %}
</tbody>
</table>
{{ form_widget(forms.submit) }}
{{ form_end(forms) }}