VichUploader image upload in embedded form (Symfony 3) - forms

How can I successfully embed a running image upload form inside a classified form with OneToOne relationship ?
first post ever on Stackoverflow so please be gentle (and I'm french ...^^)
I have a Symfony 3.3 project, running great. I use VichUploaderBundle for upload and LiipImagine for rendering. Currently, NO PROBLEM for a single image File upload !
I have an uploadtest page, I show one image file upload form, I upload the file ... it goes throught the controller and everything is fine. File uploaded and moved in directory, page shows new image, with all filters. Great !
My real problem comes when embedding the form inside another form.
I would like to embed my "image form" inside a classified form. I started by creating the field mainImage inside this classified form. The relation from the classified is OneToOne, and of course it has cascade="persist" & "remove".
But on validation, nothing is triggered and I got the following error on the image_name :
--- An exception occurred while executing 'INSERT INTO vehicle_ad (createdAt, updatedAt, published, publishedAt, friendsPriority,
friendsPriorityStart, purchaseDate, sellPrice, currency, odometerType,
currentOdometer, energy, gearbox, mainColor, nickname, description,
creator_id, vehicle_brand_id, vehicle_model_id, main_image_id,
vehicle_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?)' with params ["2018-01-23 17:15:39", "2018-01-23
17:15:39", 0, null, 0, null, null, 2650, "eur", "kilometers", 17340,
null, null, null, null, null, 1, 3, 1, null, null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Le champ
'main_image_id' ne peut être vide (null)
File is empty, vichuploader namer not triggered ... and I am stuck with it since a few days. I did a lot of research ... so any help will be greatly appreciated.
I try to give my code as clearly as possible. First, what is OK (single image upload) :
Image class
<?php
namespace Gac\MediasBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* Image
*
* #ORM\Table(name="image")
* #ORM\Entity(repositoryClass="Gac\MediasBundle\Repository\ImageRepository")
* #Vich\Uploadable
*/
class Image
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/* ----------------------------------------------------------------------
--------- Connection with other entities
------------------------------------------------------------------------- */
/**
* #ORM\ManyToOne(targetEntity="Gac\UserBundle\Entity\User", inversedBy="images")
* #ORM\JoinColumn(nullable=false)
*/
private $creator;
/**
* #ORM\ManyToOne(targetEntity="Gac\AdsBundle\Entity\VehicleAd", inversedBy="images")
* #ORM\JoinColumn(nullable=true)
*/
private $vehicleAd;
// -------------------------------------------------------------------------------
/**
* #var string
*
* #ORM\Column(name="imageName", type="string", length=255)
*/
private $imageName;
/**
* #Vich\UploadableField(mapping="users_images", fileNameProperty="imageName")
* #var File
*/
private $imageFile;
/**
* #var \DateTime
*
* #ORM\Column(name="createdAt", type="datetime")
* #Assert\DateTime()
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updatedAt", type="datetime")
* #Assert\DateTime()
*/
private $updatedAt;
/**
* #var \DateTime
*
* #ORM\Column(name="hiddenAt", type="datetime", nullable=true)
* #Assert\DateTime()
*/
private $hiddenAt;
public function __construct($thisuser)
{
$this->creator = $thisuser;
$this->createdAt = new \Datetime();
$this->updatedAt = new \Datetime();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set creator
*
* #param \Gac\UserBundle\Entity\User $creator
*
* #return Image
*/
public function setCreator(\Gac\UserBundle\Entity\User $creator)
{
$this->creator = $creator;
return $this;
}
/**
* Get creator
*
* #return \Gac\UserBundle\Entity\User
*/
public function getCreator()
{
return $this->creator;
}
/**
* Set imageName
*
* #param string $imageName
*
* #return Image
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* Get imageName
*
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
// VERY IMPORTANT:
// 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
if ($image) {
$this->updatedAt = new \DateTime();
}
}
/**
* Get imageFile
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
*
* #return Image
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
*
* #return Image
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set hiddenAt
*
* #param \DateTime $hiddenAt
*
* #return Image
*/
public function setHiddenAt($hiddenAt)
{
$this->hiddenAt = $hiddenAt;
return $this;
}
/**
* Get hiddenAt
*
* #return \DateTime
*/
public function getHiddenAt()
{
return $this->hiddenAt;
}
/**
* Set vehicleAd
*
* #param \Gac\AdsBundle\Entity\VehicleAd $vehicleAd
*
* #return Image
*/
public function setVehicleAd(\Gac\AdsBundle\Entity\VehicleAd $vehicleAd = null)
{
$this->vehicleAd = $vehicleAd;
return $this;
}
/**
* Get vehicleAd
*
* #return \Gac\AdsBundle\Entity\VehicleAd
*/
public function getVehicleAd()
{
return $this->vehicleAd;
}
}
Then the related IMAGE FORM :
<?php
namespace Gac\MediasBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichImageType;
class ImageType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('imageFile', VichImageType::class, [
'label' => false,
'required' => false,
'allow_delete' => false,
]);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Gac\MediasBundle\Entity\Image'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
//return 'gac_mediasbundle_image';
return 'ImageType';
}
}
And the controller
{% extends 'medias/layout.html.twig' %}
{% block bundle_content %}
<div class="jumbotron text-center">
<h1>Testing user's images UPLOAD</h1>
</div>
<p>-----------------</p>
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form) }}
<button type="submit">Upload</button>
{{ form_end(form) }}
<p>-----------------</p>
{% for picture in pictures %}
<div class="row">
<div class="media">
<div class="media-left media-middle">
<img class="media-object" src="{{ picture.imageName | imagine_filter('tiny_test') }}" alt="{{ 'GearsAndCoffee-'~picture.imageName }}" /><br/>
</div>
<div class="media-body">
<h4 class="media-heading">Filter name :</h4>
<em>tiny_test</em>
</div>
</div>
<div class="media">
<div class="media-left media-middle">
<a href="{{ asset('uploads/images/'~picture.imageName) }}" />
<img class="media-object" src="{{ picture.imageName | imagine_filter('std_display') }}" alt="{{ 'GearsAndCoffee-'~picture.imageName }}" /><br/>
</a>
</div>
<div class="media-body">
<h4 class="media-heading">Filter name :</h4>
<em>std_display</em>
</div>
</div>
<p>
<strong>UPDATE IMAGE</strong>
</p>
<p>
<strong>DELETE IMAGE</strong>
</p>
</div>
<p>-----------------</p>
{% endfor %}
{% endblock bundle_content %}
As an information, the VichUploader Bundle config :
vich_uploader:
db_driver: orm
#templating: true
#twig: true
#form: true
mappings:
users_images:
uri_prefix: '%app.path.users_images%'
upload_destination: '%kernel.root_dir%/../web/uploads/images'
namer: vich_uploader.namer_uniqid
inject_on_load: true
delete_on_update: true
delete_on_remove: true
And now the code of what is NOT RUNNING on my app :
The classified class
<?php
namespace Gac\AdsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* VehicleAd
*
* #ORM\Table(name="vehicle_ad")
* #ORM\Entity(repositoryClass="Gac\AdsBundle\Repository\VehicleAdRepository")
* #ORM\HasLifecycleCallbacks
*/
class VehicleAd
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/* ----------------------------------------------------------------------
--------- Connection with other entities
------------------------------------------------------------------------- */
/**
* #ORM\ManyToOne(targetEntity="Gac\UserBundle\Entity\User")
* #ORM\JoinColumn(nullable=false)
*/
private $creator;
/**
* #ORM\ManyToOne(targetEntity="Gac\VehiclesBundle\Entity\VehicleBrand")
* #ORM\JoinColumn(nullable=false)
*/
private $vehicleBrand;
/**
* #ORM\ManyToOne(targetEntity="Gac\VehiclesBundle\Entity\VehicleModel")
* #ORM\JoinColumn(nullable=false)
*/
private $vehicleModel;
/**
* #ORM\OneToOne(targetEntity="Gac\MediasBundle\Entity\Image", cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $mainImage;
// -------------------------------------------------------------------------------
// ---------------- General status and dates for the AD -------------
/**
* #var \DateTime
*
* #ORM\Column(name="createdAt", type="datetime")
* #Assert\DateTime()
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updatedAt", type="datetime")
* #Assert\DateTime()
*/
private $updatedAt;
// ---------------------- AD main content -----------------------
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=true)
* #Assert\Type("string")
*/
private $description;
// ************************* FUNCTIONS ***************************
public function __construct($thisuser)
{
$this->creator = $thisuser;
$this->createdAt = new \Datetime();
$this->updatedAt = new \Datetime();
}
/**
* Change updatedAt field just before ORM update
*
* #ORM\PreUpdate
*/
public function changeUpdatedAt()
{
$this->updatedAt = new \Datetime();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
*
* #return VehicleAd
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
*
* #return VehicleAd
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set creator
*
* #param \Gac\UserBundle\Entity\User $creator
*
* #return VehicleAd
*/
public function setCreator(\Gac\UserBundle\Entity\User $creator)
{
$this->creator = $creator;
return $this;
}
/**
* Get creator
*
* #return \Gac\UserBundle\Entity\User
*/
public function getCreator()
{
return $this->creator;
}
/**
* Set description
*
* #param string $description
*
* #return VehicleAd
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set vehicleBrand
*
* #param \Gac\VehiclesBundle\Entity\VehicleBrand $vehicleBrand
*
* #return VehicleAd
*/
public function setVehicleBrand(\Gac\VehiclesBundle\Entity\VehicleBrand $vehicleBrand)
{
$this->vehicleBrand = $vehicleBrand;
return $this;
}
/**
* Get vehicleBrand
*
* #return \Gac\VehiclesBundle\Entity\VehicleBrand
*/
public function getVehicleBrand()
{
return $this->vehicleBrand;
}
/**
* Set vehicleModel
*
* #param \Gac\VehiclesBundle\Entity\VehicleModel $vehicleModel
*
* #return VehicleAd
*/
public function setVehicleModel(\Gac\VehiclesBundle\Entity\VehicleModel $vehicleModel)
{
$linkedBrand = $vehicleModel->getModelBrand();
$this->vehicleBrand = $linkedBrand;
$this->vehicleModel = $vehicleModel;
return $this;
}
/**
* Get vehicleModel
*
* #return \Gac\VehiclesBundle\Entity\VehicleModel
*/
public function getVehicleModel()
{
return $this->vehicleModel;
}
/**
* Set mainImage
*
* #param \Gac\MediasBundle\Entity\Image $mainImage
*
* #return VehicleAd
*/
public function setMainImage(\Gac\MediasBundle\Entity\Image $mainImage)
{
$this->mainImage = $mainImage;
return $this;
}
/**
* Get mainImage
*
* #return \Gac\MediasBundle\Entity\Image
*/
public function getMainImage()
{
return $this->mainImage;
}
}
Of course the big one, my Classified Form !
<?php
namespace Gac\AdsBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Gac\MediasBundle\Form\ImageType;
use Gac\VehiclesBundle\Entity\VehicleBrand;
use Gac\VehiclesBundle\Entity\VehicleModel;
class VehicleAdType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$globalDatas = $options['globalDatas'];
$builder->add('vehicleBrand', EntityType::class, array(
'class' => 'GacVehiclesBundle:VehicleBrand',
'choice_label' => 'brandName',
'placeholder' => 'Please select a brand :',
))
->add('vehicleModel', EntityType::class, array(
'class' => 'GacVehiclesBundle:VehicleModel',
'choice_label' => 'modelName',
))
->add('description', TextareaType::class, array('required' => false));
$builder->add('mainImage', ImageType::class);
$formModifier = function (FormInterface $form, VehicleBrand $vehicleBrand = null) {
$models = null === $vehicleBrand ? array() : $vehicleBrand->getVehicleModels();
$form->add('vehicleModel', EntityType::class, array(
'class' => 'GacVehiclesBundle:VehicleModel',
'choice_label' => 'modelName',
'choices' => $models,
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. Brand
$data = $event->getData();
$formModifier($event->getForm(), $data->getVehicleBrand());
}
);
$builder->get('vehicleBrand')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$vehicleBrand = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $vehicleBrand);
}
);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Gac\AdsBundle\Entity\VehicleAd',
'globalDatas' => null,
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'gac_adsbundle_vehiclead';
}
}
The classified creation controller
<?php
namespace Gac\AdsBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Gac\MediasBundle\Entity\Image;
use Gac\MediasBundle\Form\ImageType;
use Gac\AdsBundle\Entity\VehicleAd;
use Gac\AdsBundle\Form\VehicleAdType;
use Gac\VehiclesBundle\Entity\Vehicle;
use Gac\VehiclesBundle\Form\VehicleType;
use Gac\VehiclesBundle\Entity\VehicleModel;
use Gac\VehiclesBundle\Entity\VehicleBrand;
class ManageController extends Controller
{
public function sellvehicleAction(Request $request)
{
$this->denyAccessUnlessGranted('ROLE_USER');
$thisuser = $this->get('security.token_storage')->getToken()->getUser();
$em = $this->getDoctrine()->getManager();
// Create new ad and load a "mainImage"
$classified = new VehicleAd($thisuser);
$oneImage = new Image($thisuser);
$classified->setMainImage($oneImage);
$globalDatas = $this->container->get('gac_general.globaldatas'); // Always pass globalDatas VAR to any created form in the application
$form = $this->createForm(VehicleAdType::class, $classified, array(
'globalDatas' => $globalDatas,
));
$form->handleRequest($request);
if ($request->isMethod('POST') && $form->isValid()) {
$em->persist($classified);
$em->flush();
$id = $classified->getId();
return $this->redirectToRoute('gac_ads_previewvehiclead', array('id' => $id));
}
return $this->render('ads/manage/sellvehicle.html.twig', array(
'form' => $form->createView()
));
}
}
And finally the view of my classified form
{% extends 'ads/layout.html.twig' %}
{% block bundle_content %}
<form action="{{ path('gac_ads_sellvehicle') }}" method="post">
<div class="row justify-content-center">
<div class="col-md-8">
{{ form_errors(form) }}
<div class="card mb-3">
<div class="card-body">
<p class="text-primary"><strong>{{ 'mandatory informations'|trans|capitalize }} :</strong></p>
{{ form_row(form.vehicleBrand, {'label': 'Vehicle Brand :'}) }}
{{ form_row(form.vehicleModel, {'label': 'Vehicle Model :'}) }}
</div>
</div>
<div class="card mb-3">
<div class="card-body">
<p class="text-primary">{{ 'image'|trans|capitalize }} :</p>
<div id="toto">
{{ form_row(form.mainImage.imageFile) }}
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-body">
<p class="text-primary">{{ 'other parameters'|trans|capitalize }} ({{ 'optional'|trans }}) :</p>
<p class="text-primary">{{ 'tell us a few words about your vehicle'|trans|capitalize }} ({{ 'optional'|trans }}) :</p>
{{ form_row(form.description, {'label': 'Description :'}) }}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card mb-3">
<div class="card-body">
{{ form_rest(form) }}
</div>
</div>
<button type="submit" class="btn btn-block btn-primary">{{ 'preview your ad'|capitalize }}</button>
</div>
</div>
</form>
{% endblock bundle_content %}
I must say that before asking, I did a lot of searching by myself (tests ...) and tons of google search. I know that there is some tricky stuff with Vich Uploader but I managed everything because ... it works for one file.
So the question is : can you help me make my upload and my form work when embedded in another one ?
Thanks a lot !
Regards

Try to do this in "classified" form: ...add('description', textAreaType::class) ->add('mainImage', ImageType::class); Maybe,using twice FormBuilder instance "$builder" causes problemes. In any case: see here Formulaires Imbriqués. I did so and it works great with embedded forms using vich

Related

Enable Select2Search in Symfony form

I want to enable select 2 search in my Symfony form what i tried so far:
In my form class i have this:
->add('parent', EntityType::class, [
'class' => Category::class,
'choice_label' => 'title',
'attr' => [
'class' => 'select2'
]
])
In my twig file this :
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2-rc.1/css/select2.min.css" rel="stylesheet" />
<!-- Loading jquery here--><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2-rc.1/js/select2.min.js"></script>
</head>
{{ form_start(form) }}
<script type="text/javascript">
$('select').select2();
</script>
{{ form_widget(form) }}
{{ form_end(form) }}
But i do not get the dropdown with the search bar. Just the default dropdown menu of Symfony. What am I doing wrong
The main reason is that the field is created after you try and target it, by this line:
{{ form_widget(form) }}
The JavaScript must be executed after that in order to be able to target the field (besides, the HTML structure of your template is wrong).
Try this :
<!DOCTYPE html>
<html>
<head>
<title>Test form</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2-rc.1/css/select2.min.css" rel="stylesheet" />
<!-- Loading jquery here--><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2-rc.1/js/select2.min.js"></script>
</head>
<body>
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
<script>
$('select').select2();
</script>
</body>
</html>
It's usually better to wait for the page to be loaded before executing scripts, using jQuery you could ensure that it's the case by changing the script to this:
<script>
$(document).ready(function(){
$('.select2').select2();
});
</script>
Notice that I also changed the jQuery selector to use the class you've added to the field in your form builder. This way you control the select field you want to target.
You are initiating the select2 components without configuration, so it doesn't know where is the data source.
Before start coding, you need to install and configure FOSJsRoutingBundle. This bundle will help you with access to ajax routes
For fully configured sync symfony-forms~select2 you could do something like this.
Entity Person
class Person
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="person_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", nullable=true)
*/
private $name;
/**
* #var Country
*
* #ORM\ManyToOne(targetEntity="Country")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="country_id", referencedColumnName="id")
* })
*/
private $country;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Person
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set country
*
* #param \AppBundle\Entity\Country $country
*
* #return Person
*/
public function setCountry(\AppBundle\Entity\Country $country = null)
{
$this->country = $country;
return $this;
}
/**
* Get country
*
* #return \AppBundle\Entity\Country
*/
public function getCountry()
{
return $this->country;
}
public function __toString()
{
return $this->name;
}
}
Entity Country
class Country
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="country_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", nullable=true)
*/
private $name;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Country
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function __toString()
{
return $this->name;
}
}
Country repository
class CountryRepository extends \Doctrine\ORM\EntityRepository
{
public function countriesSelect2($term)
{
$qb = $this->createQueryBuilder('c');
$qb->where(
$qb->expr()->like($qb->expr()->lower('c.name'), ':term')
)
->setParameter('term', '%' . strtolower($term) . '%');
return $qb->getQuery()->getArrayResult();
}
}
Country controller
Check how the route is exposed to the options parameter and returns a JsonResponse. You could also use a serializer too.
/**
* Country controller.
*
* #Route("countries")
*/
class CountryController extends Controller
{
/**
* Lists all person entities.
*
* #Route("/", name="countries",options={"expose"=true})
* #Method("GET")
*/
public function indexAction(Request $request)
{
$countryRepo = $this->getDoctrine()->getRepository('AppBundle:Country');
$data = $countryRepo->countriesSelect2($request->get('q', ''));
//$response = $this->get('serializer')->serialize($data,'json');
return new JsonResponse($data);
}
}
So far so good, now comes the good parts, let's go and configure our form
PersonType
class PersonType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name')
->add('country',EntityType::class,[
'class' => Country::class,
'attr' => [
'class' => 'select2', // the class to use with jquery
'data-source' => 'countries', //the exposed route name for data-soirce as attr
'data-allow-clear' => 'true'//another extra attr to customize
],
]);
}/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Person'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_person';
}
}
JS, showing the select2
Remember, you have configured already the select2 options with attributes, you just have to use them properly
$(document).ready(function () {
$('.select2').each(function () {//using the select2 class
if (!$().select2) {//checking the script
return;
}
$.fn.select2.defaults.set("theme", "bootstrap");//some theming if you want
$($(this)).select2({
placeholder: "Select",
width: 'auto',
allowClear: $(this).attr("data-allow-clear") ? $(this).attr("data-allow-clear") : true, //using my options from the form
ajax: {
url: Routing.generate($(this).attr("data-source")), //here its the magic
dataType: 'json',
processResults: function (data) {
//console.log(data);
return {
results: $.map(data, function (item) {
return {
text: item.name, //you need to map this because the plugin accepts only id and text
id: item.id
}
})
};
}
}
});
});
});
after that, all is done. All the code is working as I tested my self
Hope it helps!
There is a nice bundle for it: TetranzBundle
You can configure your form field in FormType class like that:
->add('product', Select2EntityType::class, [
'label'=>'product',
'required'=>true,
'mapped'=>true,
'multiple' => false,
'remote_route' => 'product_select2_ajax',
'class' => 'AppBundle:Product',
// 'property' => 'name',
'minimum_input_length' => 0,
'page_limit' => 10,
'allow_clear' => true,
'delay' => 250,
'cache' => true,
'cache_timeout' => 60000, // if 'cache' is true
'language' => 'pl',
'placeholder' => "select.product",
])
Try this :
<script type="text/javascript">
$(document).ready(function() {
$('.select2').select2(); //instead $('select2').select2();
});
</script>
see How to select a class in Jquery and the basic usage exemple

Symfony3 - Embedded collection form is empty when displayed

I'm creating a timecard form which has 14 dayslots, one for each day slot.
I have created the entities, controller and formType. In the new action of the controller of the timecard, I create 14 instances of the dayslot and add them to the timecard using the entity function. The form comes up empty - as if the collection is empty. Is there something more I have to do? It seems that the form is not properly bound to the entity collection objects. I have dumped the entity before displaying it seems to be there.
Here is the TimeCard Entity:
<?php
namespace CockpitBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* TCTimeCard
*/
class TCTimeCard
{
/**
* #var integer
*/
private $id;
/**
* #var \DateTime
*/
private $startDate;
/**
* #var \DateTime
*/
private $endDate;
/**
* #var \DateTime
*/
private $approvedDate;
/**
* #var \DateTime
*/
private $processedDate;
/**
* #var \DateTime
*/
private $modifiedDate;
/**
* #var string
*/
private $notes;
/**
* #var \CockpitBundle\Entity\TCStatus
*/
private $status;
/**
* #var \CockpitBundle\Entity\Employee
*/
private $employee;
/**
* #var \CockpitBundle\Entity\Employee
*/
private $approvedBy;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $tcslots;
/**
* #var \DateTime
*/
private $periodBegin;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $tcdayslots;
/**
* Constructor
*/
public function __construct()
{
$this->tcslots = new ArrayCollection();
$this->tcdayslots = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/* Removed some of the getters/setters to save scrolling */
/**
* Set employee
*
* #param \CockpitBundle\Entity\Employee $employee
*
* #return TCTimeCard
*/
public function setEmployee(\CockpitBundle\Entity\Employee $employee = null)
{
$this->employee = $employee;
return $this;
}
/**
* Get employee
*
* #return \CockpitBundle\Entity\Employee
*/
public function getEmployee()
{
return $this->employee;
}
/**
* #ORM\PreUpdate
*/
public function updateModifiedDatetime()
{
// Add your code here
}
/**
* Add tcdayslot
*
* #param \CockpitBundle\Entity\TCDaySlot $tcdayslot
*
* #return TCTimeCard
*/
public function addTcdayslot(\CockpitBundle\Entity\TCDaySlot $tcdayslot)
{
$this->tcdayslots[] = $tcdayslot;
return $this;
}
/**
* Remove tcdayslot
*
* #param \CockpitBundle\Entity\TCDaySlot $tcdayslot
*/
public function removeTcdayslot(\CockpitBundle\Entity\TCDaySlot $tcdayslot)
{
$this->tcdayslots->removeElement($tcdayslot);
}
/**
* Get tcdayslots
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTcdayslots()
{
return $this->tcdayslots;
}
}
Here is the DaySlot entity (TCDaySlot)
<?php
namespace CockpitBundle\Entity;
/**
* TCDaySlot
*/
class TCDaySlot
{
/**
* #var integer
*/
private $id;
/**
* #var \DateTime
*/
private $date;
/**
* #var string
*/
private $reghours;
/**
* #var string
*/
private $othours;
/**
* #var string
*/
private $holidayhours;
/**
* #var string
*/
private $type1hours;
/**
* #var string
*/
private $type2hours;
/**
* #var string
*/
private $type3hours;
/**
* #var string
*/
private $type4hours;
/**
* #var string
*/
private $type5hours;
/**
* #var string
*/
private $note;
/**
* #var \CockpitBundle\Entity\Employee
*/
private $employee;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set date
*
* #param \DateTime $date
*
* #return TCDaySlot
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* #return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set reghours
*
* #param string $reghours
*
* #return TCDaySlot
*/
public function setReghours($reghours)
{
$this->reghours = $reghours;
return $this;
}
/**
* Get reghours
*
* #return string
*/
public function getReghours()
{
return $this->reghours;
}
/**
* Set othours
*
* #param string $othours
*
* #return TCDaySlot
*/
public function setOthours($othours)
{
$this->othours = $othours;
return $this;
}
/**
* Get othours
*
* #return string
*/
public function getOthours()
{
return $this->othours;
}
/**
* Set holidayhours
*
* #param string $holidayhours
*
* #return TCDaySlot
*/
public function setHolidayhours($holidayhours)
{
$this->holidayhours = $holidayhours;
return $this;
}
/**
* Get holidayhours
*
* #return string
*/
public function getHolidayhours()
{
return $this->holidayhours;
}
/**
* Set type1hours
*
* #param string $type1hours
*
* #return TCDaySlot
*/
public function setType1hours($type1hours)
{
$this->type1hours = $type1hours;
return $this;
}
/**
* Get type1hours
*
* #return string
*/
public function getType1hours()
{
return $this->type1hours;
}
/**
* Set type2hours
*
* #param string $type2hours
*
* #return TCDaySlot
*/
public function setType2hours($type2hours)
{
$this->type2hours = $type2hours;
return $this;
}
/**
* Get type2hours
*
* #return string
*/
public function getType2hours()
{
return $this->type2hours;
}
/* Again I removed a few getter/setters to minimize size */
/**
* Set note
*
* #param string $note
*
* #return TCDaySlot
*/
public function setNote($note)
{
$this->note = $note;
return $this;
}
/**
* Get note
*
* #return string
*/
public function getNote()
{
return $this->note;
}
/**
* Set employee
*
* #param \CockpitBundle\Entity\Employee $employee
*
* #return TCDaySlot
*/
public function setEmployee(\CockpitBundle\Entity\Employee $employee = null)
{
$this->employee = $employee;
return $this;
}
/**
* Get employee
*
* #return \CockpitBundle\Entity\Employee
*/
public function getEmployee()
{
return $this->employee;
}
}
And here is the controller TCTimeCardController
/**
* Creates a new tCTimeCard entity.
*
* #Route("/new", name="tctimecard_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$tcTimeCard = new TCTimeCard();
$em = $this->getDoctrine()->getManager();
$periodStart = $em->getRepository('CockpitBundle:TCTimeCard')->getBestDate();
$username = $this->getUser()->getUsername();
$employee = $em->getRepository('CockpitBundle:Employee')->findOneByUsername($username);
$status = $em->getRepository('CockpitBundle:TCStatus')->findOneById(1);
$tcTimeCard->setPeriodBegin($periodStart);
$tcTimeCard->setStatus($status);
$tcTimeCard->setEmployee($employee);
$form = $this->createForm('CockpitBundle\Form\TCTimeCardType', $tcTimeCard);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$cnt=0;
foreach($form->get('tcdayslots') as $slotform) {
print "Cnt =". ++$cnt . "<BR>";
}
$em->persist($tcTimeCard);
$em->flush();
die("done");
return $this->redirectToRoute('tctimecard_show', array('id' => $tcTimeCard->getId()));
}
$days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
$headings = ['-2' => 'Regular','-1' => "Overtime", '0' => "Holiday"];
foreach ($em->getRepository('CockpitBundle:TimeOffType')->findAll() as $tot) {
$headings[$tot->getId()] = $tot->getType();
}
$headings['99'] = "Comments";
$date = $periodStart;
for ($i = 1; $i<=2; $i++) {
foreach ($days as $day) {
$tcDaySlot = new \CockpitBundle\Entity\TCDaySlot;
$tcDaySlot->setDate($date->format('Y-m-d'));
//$tcsForm = $this->slotForm($tcDaySlot,$date,$employee)->createView();
//$tcsForms[$date->format('m/d/y')] = $tcsForm;
$dates[$date->format('m/d/y')] = $day;
$date->add(new \DateInterval('P1D'));
$tcTimeCard->addTcdayslot($tcDaySlot);
}
}
$cnt2 =0;
foreach ($tcTimeCard->getTcdayslots() as $dayslot) {
print "Cnt2 = " . ++$cnt2 . " " . $dayslot->getDate() . "<BR>";
}
dump($form->getData());
return $this->render('tctimecard/new.html.twig', array(
'tCTimeCard' => $tcTimeCard,
'form' => $form->createView(),
'headings' => $headings,
'emp' => $employee,
'dates' => $dates,
));
}
Lastly, here is the twig I am using to display the form
{% extends 'base.html.twig' %}
{% block body %}
<div class="status">
<h1>Time Card for {{ emp.displayname }} Period Beginning: {{ dates|keys|first }}</h1>
</div>
keys = {{form|keys|join('|') }}<BR>
{{ form_start(form) }}
{{ form_widget(form) }}
<table class="timecard">
<tr>
<th>Date</th>
{% for id,heading in headings %}
<th class="tcheader">
{{ heading}}
</td>
{% endfor %}
</tr>
Length = {{ form.tcdayslots|length }}
{% for tcdayslot in form.tcdayslots %}
<tr>
{% if day | slice(0,1) == 'S' %}
<td class="weekend">{{ date }} {{ day }}</td>
{% else %}
<td>{{ date }} {{ day }}{{ form_start(tcdayslot) }}</td>
{% endif %}
<td>
{{ form_row(tcdayslot.reghours) }}
</td>
<td>
{{ form_row(tcdayslot.othours) }}
</td>
<td>
{{ form_widget(tcdayslot.holidayhours) }}
</td>
<td>
{{ form_widget(tcdayslot.type1hours) }}
</td>
<td>
{{ form_widget(tcdayslot.type2hours) }}
</td>
<td>
{{ form_widget(tcdayslot.type3hours) }}
</td>
<td>
{{ form_widget(tcdayslot.type4hours) }}
</td>
<td>
{{ form_widget(tcdayslot.type5hours) }}
</td>
<td>
{{ form_widget(tcdayslot.note) }}
{{ form_end(tcdayslots) }}
</td>
</tr>
{% endfor %}
<tr><td>TOTALS</td>
</table>
<input type="submit" value="Create" />
{{ form_end(form) }}
<ul>
<li>
Back to the list
</li>
</ul>
{% endblock %}
I finally figured out what was going on. The following line in the foreach $days loop:
$tcDaySlot = new \CockpitBundle\Entity\TCDaySlot;
does not call the constructor. I changed it to:
$tcDaySlot = TCDaySlot();
and added a use statement for the entity and that seems to have connected the collection properly. I think it is a static class instantiation instead of an instance of the object or was I just missing the parens?
I also had to remove the form_start and form_end for each collection object in the twig, as there is only one form created (duh, you can't have embedded forms in HTML).

How to concatenate a date field data and a time field data of a form in Symfony2 to be saved as a datetime data in a database datetime field ?

I would like to know how to concatenate a date field data and a time field data of a form in Symfony2 to be saved as a datetime data in a database datetime field. The explanation is as below:
I would like to add two new time fields to the form in this screen shot:
This is the code of the form (it is in twig and html):
<html>
<head>
<title> Wkayet </title>
<link rel="shortcut icon" href="{{asset('bundles/ikprojhome/images/icon-WKAYET.png')}}">
<link rel="stylesheet" type="text/css" href="{{asset('bundles/ikprojhome/css2/css.css')}}"/>
<script src='{{asset('bundles/ikprojhome/lib/jquery.min.js')}}'></script>
</head>
<body>
<center>
<div id="container">
<div id="header">
</div>
<div id="content">
<table width="100%" height="100%" align="center">
<tr>
<td>
{% for x in groupe%}
<form id="EventForm" action='{{path('ikproj_groupe_homepaeventsAdd',{id:x['id']})}}' method="POST" {{ form_enctype(form) }} onsubmit="javascript:parent.jQuery.fancybox.close();">
<!--<form id="EventForm" action='{{path('ikproj_groupe_homepaeventsAdd',{id:x['id']})}}' method="POST" {{ form_enctype(form) }} >-->
{% endfor %}
{{ form_errors(form) }}
<table align="center">
<tr>
<td class="separation"><label for="groupname">Titre</label></td>
<td>
<!--<input id="titre" name="titre" required="required" type="text" size="50"/> -->
<div>
{{ form_errors(form.title) }}
{{ form_widget(form.title) }}
</div>
</td>
</tr>
<tr>
<td class="separation"><label for="debut">Début</label></td>
<td><!--<select id="debut" name="debut" class="select"></select>-->
<div>
{{ form_errors(form.startdate ) }}
{{ form_widget(form.startdate ) }}
</div>
</td>
</tr>
<tr>
<td class="separation"><label for="heure_debut">Heure</label></td>
<td>
<div>
{{ form_errors(form.starttime ) }}
{{ form_widget(form.starttime ) }}
</div>
</td>
</tr>
<tr>
<td class="separation"><label for="fin">Fin</label></td>
<td><!--<select id="fin" name="fin" class="select"></select>-->
<div>
{{ form_errors(form.enddate ) }}
{{ form_widget(form.enddate ) }}
</div>
</td>
</tr>
<tr>
<td class="separation"><label for="heure_fin">Heure</label></td>
<td>
<div>
{{ form_errors(form.starttime ) }}
{{ form_widget(form.starttime ) }}
</div>
</td>
</tr>
<tr>
<td class="separation"><label for="lieu">Lieu</label></td>
<td> <!--<select id="lieu" name="lieu" class="select"></select> -->
<div>
{{ form_errors(form.location) }}
{{ form_widget(form.location , {'attr':{'class':'select '}}) }}
</div>
</td>
</tr>
<tr>
<td id="description" valign="top" class="separation"><label for="description">Description</label></td>
<td><textarea id="ikproj_groupebundle_eventsgroupe_description" name="ikproj_groupebundle_eventsgroupe[description]" rows="5" cols="40"></textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center" id="button" valign="bottom"><input class="button" type="submit" value=""/></td>
</tr>
</table>
{{form_widget(form._token)}}
</form>
</td>
</tr>
</table>
</div>
</div>
</center>
</body>
</html>
This is the code of the form class :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ->add('idGroupe')
->add('title','text')
->add('startdate','date',array(
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',))
->add('starttime', 'time', array(
'input' => 'datetime',
'widget' => 'choice',))
->add('enddate','date',array(
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',))
->add('endtime', 'time', array(
'input' => 'datetime',
'widget' => 'choice',))
->add('location','country')
->add('description','text')
// ->add('partager')
;
}
This is the code of the entity with which I am dealing:
<?php
namespace Ikproj\GroupeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* eventsgroupe
*
* #ORM\Table(name="eventsgroupe")
* #ORM\Entity(repositoryClass="Ikproj\GroupeBundle\Entity\eventsgroupeRepository")
*/
class eventsgroupe
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #var integer
* #ORM\ManyToOne(targetEntity="Groupe", inversedBy="eventsgroupe")
* #ORM\JoinColumn(name="admingroupe_id", referencedColumnName="admingroupe_id", nullable=FALSE)
* #ORM\Column(name="admingroupe_id", type="string", length=255)
*/
private $idGroupe;
/**
*
* #var integer
* #ORM\ManyToOne(targetEntity="Groupe", inversedBy="eventsgroupe")
* #ORM\JoinColumn(name="idgroupe", referencedColumnName="id_groupe", nullable=FALSE)
* #ORM\Column(name="idgroupe", type="string", length=255)
*/
private $idEventGroupe;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #var \DateTime
*
* #ORM\Column(name="start", type="datetime")
*/
private $start;
/**
* #var \Date
*/
private $startdate;
/**
* #var \Time
*/
private $starttime;
/**
* #var \DateTime
*
* #ORM\Column(name="end", type="datetime")
*/
private $end;
/**
* #var \Date
*/
private $enddate;
/**
* #var \Time
*/
private $endtime;
/**
* #var string
*
* #ORM\Column(name="location", type="string", length=255)
*/
private $location;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=255)
*/
private $description;
/**
* #var boolean
*
* #ORM\Column(name="partager", type="boolean")
*/
private $partager;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function getIdGroupe()
{
return $this->idGroupe;
}
/**
* Set title
*
* #param string $title
* #return eventsgroupe
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get startdate
*
* #return date
*/
public function getStartdate()
{
return $this->startdate;
}
/**
* Set startdate
*
* #param date $startdate
* #return eventsgroupe
*/
public function setStartdate($startdate)
{
$this->startdate = $startdate;
return $this;
}
/**
* Get enddate
*
* #return date
*/
public function getEnddate()
{
return $this->enddate;
}
/**
* Set enddate
*
* #param date $enddate
* #return eventsgroupe
*/
public function setEnddate($enddate)
{
$this->enddate = $enddate;
return $this;
}
/**
* Get starttime
*
* #return time
*/
public function getStarttime()
{
return $this->starttime;
}
/**
* Set starttime
*
* #param time $starttime
* #return eventsgroupe
*/
public function setStarttime($starttime)
{
$this->starttime = $starttime;
return $this;
}
/**
* Get endttime
*
* #return time
*/
public function getEndtime()
{
return $this->endttime;
}
/**
* Set endtime
*
* #param time $endtime
* #return eventsgroupe
*/
public function setEndtime($endtime)
{
$this->endtime = $endtime;
return $this;
}
/**
* Set start
*
* #param \DateTime $start
* #return eventsgroupe
*/
public function setStart($startdate,$starttime)
{
//$this->start = $start;
$this->start.date('yyyy-MM-dd') = $startdate;
$this->start.time() = $starttime;
return $this;
}
/**
* Get start
*
* #return \DateTime
*/
public function getStart()
{
return $this->start;
}
/**
* Set end
*
* #param \DateTime $end
* #return eventsgroupe
*/
public function setEnd($enddate,$endtime)
{
$this->end.date('yyyy-MM-dd') = $enddate;
$this->end.time() = $endtime;
return $this;
}
/**
* Get end
*
* #return \DateTime
*/
public function getEnd()
{
return $this->end;
}
/**
* Set location
*
* #param string $location
* #return eventsgroupe
*/
public function setLocation($location)
{
$this->location = $location;
return $this;
}
/**
* Get location
*
* #return string
*/
public function getLocation()
{
return $this->location;
}
/**
* Set description
*
* #param string $description
* #return eventsgroupe
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set partager
*
* #param boolean $partager
* #return eventsgroupe
*/
public function setPartager($partager)
{
$this->partager = $partager;
return $this;
}
/**
* Get partager
*
* #return boolean
*/
public function getPartager()
{
return $this->partager;
}
public function setIdGroupe($idGroupe)
{
$this->idGroupe = $idGroupe;
return $this;
}
public function setIdEventGroupe($idEventGroupe)
{
$this->idEventGroupe = $idEventGroupe;
return $this;
}
public function getIdEventGroupe()
{
return $this->idEventGroupe;
}
}
And this is the structure of the table with which I am dealing in the database:
field name: Type:
----------- -----
id int
title varchar
start datetime
end datetime
location varchar
description varchar
admingroupe_id int
idgroupe int
partager tinyint
Please, focus on the following part of the entity code:
/**
* #var \DateTime
*
* #ORM\Column(name="start", type="datetime")
*/
private $start;
/**
* #var \Date
*/
private $startdate;
/**
* #var \Time
*/
private $starttime;
/**
* #var \DateTime
*
* #ORM\Column(name="end", type="datetime")
*/
private $end;
/**
* #var \Date
*/
private $enddate;
/**
* #var \Time
*/
private $endtime;
And this one too:
/**
* Get startdate
*
* #return date
*/
public function getStartdate()
{
return $this->startdate;
}
/**
* Set startdate
*
* #param date $startdate
* #return eventsgroupe
*/
public function setStartdate($startdate)
{
$this->startdate = $startdate;
return $this;
}
/**
* Get enddate
*
* #return date
*/
public function getEnddate()
{
return $this->enddate;
}
/**
* Set enddate
*
* #param date $enddate
* #return eventsgroupe
*/
public function setEnddate($enddate)
{
$this->enddate = $enddate;
return $this;
}
/**
* Get starttime
*
* #return time
*/
public function getStarttime()
{
return $this->starttime;
}
/**
* Set starttime
*
* #param time $starttime
* #return eventsgroupe
*/
public function setStarttime($starttime)
{
$this->starttime = $starttime;
return $this;
}
/**
* Get endttime
*
* #return time
*/
public function getEndtime()
{
return $this->endttime;
}
/**
* Set endtime
*
* #param time $endtime
* #return eventsgroupe
*/
public function setEndtime($endtime)
{
$this->endtime = $endtime;
return $this;
}
/**
* Set start
*
* #param \DateTime $start
* #return eventsgroupe
*/
public function setStart($startdate,$starttime)
{
//$this->start = $start;
$this->start.date('yyyy-MM-dd') = $startdate;
$this->start.time() = $starttime;
return $this;
}
/**
* Get start
*
* #return \DateTime
*/
public function getStart()
{
return $this->start;
}
/**
* Set end
*
* #param \DateTime $end
* #return eventsgroupe
*/
public function setEnd($enddate,$endtime)
{
$this->end.date('yyyy-MM-dd') = $enddate;
$this->end.time() = $endtime;
return $this;
}
/**
* Get end
*
* #return \DateTime
*/
public function getEnd()
{
return $this->end;
}
The problem is that when I run the code, the form does't show and this is what I see:
So my question is: what is wrong in my code exactly??..is there anyone who has any idea?

Edit my entity based on and ID of other Entity

i want to edit my Category entity based on Test ID in the form in Twig and bind it to database,
when i open my edit it displays me the forms i edit them but they don't bind the id test from database , i can't understand why, may be something i wrote wrong :(
my controller :
class DefaultController extends Controller
{
function editAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$test = $em->getRepository('LadelaOdeskTesterBundle:Test')->find($id);
if (!$test) {
throw $this->createNotFoundException('Unable to find Advertiser entity.');
}
return array(
'test' => $test,
);
}
/**
* #Route("/new/{id}/update", name="test.update", requirements={"id" = "\d+"})
* #Method("Post")
* #Template("LadelaOdeskTesterBundle:Default:edit.html.twig")
*/
public function updateAction($id)
{
$test =
$this->getDoctrine()->getRepository('LadelaOdeskTesterBundle:Test')->find($id);
if (!$test) {
throw $this->createNotFoundException('Unable to find Test entity.');
}
$success = 0;
$categoryList = array_map('trim', $this->getRequest()->get('category-new'));
$currentCats = $test->getCategories();
foreach ($currentCats as $current){
$test->removeCategorie($current);
}
$em = $this->getDoctrine()->getEntityManager();
foreach ($categoryList as $category) {
if (!empty($category)) {
$categoryName = new Category();
$categoryName->setName($category);
$categoryName->setTest($test);
$test->addCategorie($categoryName);
$em->persist($categoryName);
$success = ' Category ' . $category . ' was created';
}
}
$em->flush();
return $this->redirect($this->generateUrl('test.edit',array('id' => $id)));
return array(
'test' => $test,
);
}
}
my twig file :
{% extends '::base.html.twig' %}
{% block body %}
{#<div class="wrap">#}
<ul id="breadcrumb">
<li><a href="{{path('homepage')}}" title="Home"><img src="{{ \
asset('bundles/ladelaodesktester/images/home.png') }}" alt="Home" class="home"
/></a> </li>
<li> Please add data to new test </li>
</ul>
<h2>Edit Test </h2>
{% for test in tests %}
<form action="{{ path('test.update',{'id': test.id }) }}" method="post">
Category 1<input type="text" name="category-new[]" >
<div id="customWidget">
<div id="colorSelector1"><div style="background-color: #00ff00"></div>
</div>
<div id="colorpickerHolder1"></div>
</div>
Category 2<input type="text" name="category-new[]" ><br>
Category 3<input type="text" name="category-new[]" ><br>
Category 4<input type="text" name="category-new[]" ><br>
Category 5<input type="text" name="category-new[]" ><br>
Category 6<input type="text" name="category-new[]" ><br>
Category 7<input type="text" name="category-new[]" ><br>
Category 8<input type="text" name="category-new[]" ><br>
Category 9<input type="text" name="category-new[]" ><br>
<input type="submit" value="Add">
</form>
{% endfor %}
</div>
Back to Test
{#</div>#}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('bundles/ladelaodesktester/js/new.js') }}"
type="text/javascript"></script>
<script src="{{ asset('bundles/ladelaodesktester/js/colorpicker.js') }}"
type="text/javascript"></script>
{% endblock %}
Category entity:
class Category
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string $color
*
* #ORM\Column(name="color", type="string", length=255)
*/
private $color;
/**
* #var Category category
*
* #ORM\ManyToOne(targetEntity="Test",inversedBy="categories")
* #ORM\JoinColumn(name="test_id", referencedColumnName="id")
*
*/
protected $test;
public function __construct()
{
$this->color = 'rgb(255,255,0)';
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set color
*
* #param string $color
* #return Category
*/
public function setColor($color)
{
$this->color = $color;
return $this;
}
/**
* Get color
*
* #return string
*/
public function getColor()
{
return $this->color;
}
/**
* Set test
*
* #param Ladela\OdeskTesterBundle\Entity\Test $test
* #return Category
*/
public function setTest(\Ladela\OdeskTesterBundle\Entity\Test $test )
{
$this->test = $test;
return $this;
}
/**
* Get test
*
* #return Ladela\OdeskTesterBundle\Entity\Test
*/
public function getTest()
{
return $this->test;
}
}
Test entity:
class Test
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \DateTime $created_at
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(name="created_at", type="datetime")
*/
private $created_at;
/**
* #Gedmo\Slug(fields={"name"})
* #ORM\Column(length=128,unique=true)
*/
private $slug;
/**
* #ORM\ManyToMany(targetEntity="Question")
* #ORM\JoinTable(name="test_questions",
* joinColumns={#ORM\JoinColumn(name="test_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="question_id",
referencedColumnName="id")}
* )
* #var Collection $questions
**/
protected $questions;
/**
* #ORM\ManyToMany(targetEntity="Result")
* #ORM\JoinTable(name="test_results",
* joinColumns={#ORM\JoinColumn(name="test_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="result_id",
referencedColumnName="id")}
* )
* #var Collection $results
**/
protected $results;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="test")
*/
private $categories;
/**
* #var \DateTime $updated_at
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(name="updated_at", type="datetime")
*/
private $updated_at;
public function __construct()
{
$this->questions = new \Doctrine\Common\Collections\ArrayCollection();
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Test
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getSlug()
{
return $this->slug;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set created_at
*
* #param \DateTime $createdAt
* #return Test
*/
public function setCreatedAt($createdAt)
{
$this->created_at = $createdAt;
return $this;
}
/**
* Get created_at
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->created_at;
}
/**
* Set updated_at
*
* #param \DateTime $updatedAt
* #return Test
*/
public function setUpdatedAt($updatedAt)
{
$this->updated_at = $updatedAt;
return $this;
}
/**
* Get updated_at
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updated_at;
}
/**
*
*/
public function getQuestions()
{
return $this->questions;
}
public function addQuestion( Question $question )
{
$this->questions[] = $question;
}
/**
* Set slug
*
* #param string $slug
* #return Test
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Remove questions
*
* #param Question $questions
*/
public function removeQuestion( Question $questions)
{
$this->questions->removeElement($questions);
}
/**
* Add results
*
* #param Result $results
* #return Test
*/
public function addResult(Result $results)
{
$this->results[] = $results;
return $this;
}
/**
* Remove results
*
* #param Result $results
*/
public function removeResult(Result $results)
{
$this->results->removeElement($results);
}
/**
* Get results
*
* #return Collection
*/
public function getResults()
{
return $this->results;
}
public function countResults()
{
return $this->results->count();
}
public function countQuestions()
{
return $this->questions->count();
}
/**
* Add categories
*
* #param Ladela\OdeskTesterBundle\Entity\Category $categories
* #return Test
*/
public function addCategorie(\Ladela\OdeskTesterBundle\Entity\Category $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* #param Ladela\OdeskTesterBundle\Entity\Category $categories
*/
public function removeCategorie(\Ladela\OdeskTesterBundle\Entity\Category $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* #return Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
}
in the foreach loop > if you never add the $test to the category object.
add this:
$categoryName->setTest($test);
the foreach loop should look like this:
$em = $this->getDoctrine()->getManager(); // <---- Changed this
foreach ($categoryList as $category) {
if (!empty($category)) {
$categoryName = new Category();
$categoryName->setName($category);
$categoryName->setTest($test);
$em->persist($categoryName);
$success = ' Category ' . $category . ' was created';
} else {
$success = 'Test category-new may not be empty';
}
}
$em->flush(); // <---- Changed this
Add this before the foreach loop:
$currentCats = $test->getCategories();
foreach ($currentCats as $current){
$test->removeCategorie($current);
}
FINAL EDIT :
Instead of setting test for the category add the category to test, like this:
$em = $this->getDoctrine()->getManager();
foreach ($categoryList as $category) {
if (!empty($category)) {
$categoryName = new Category();
$categoryName->setName($category);
$categoryName->setTest($test);
$test->addCategorie($categoryName); // <---- This is added
$em->persist($categoryName);
$success = ' Category ' . $category . ' was created';
} else {
$success = 'Test category-new may not be empty';
}
}
$em->flush();

symfony2 label and field from 2 distinct DB

UPDATE: I just to precise that I'm new to Symfony2 and generally with frameworks. I would like to clarify my question: I wish a big form with many fields and the label of each field is from a second DB. It would take 30minutes in pure PHP without a framework, but how can I do it with Sf2?
I'm having an issue to display in one form multiple times the same entity.
Here is the context:
I have a parking lot with multiple parking places. To manage at best the parking lot,it is decided to give a priority order to each parking place to be occuped.
The manager of the parking lot can change the priorities at any moment but a historical must be in place.
The parking places are already declared and the manager can't edit them.
So to do so, I have created to entities: ParkingPlaces and Historical. Historical as ManyToOne ParkingPlaces.
I wish that for each parking place label, there is a field to enter the occupation priority in one form.
The entities are declared as such:
class Historical
{
/**
* #ORM\Column(name="date", type="datetime")
*/
private date;
/**
* #ORM\ManyToOne(targetEntity="ParkingPlace")
* #ORM\JoinColumn(name="parkingplace_id", referencedColumnName="id")
*/
private parkingPlace;
/**
* #ORM\Column(name="priority", type="integer")
*/
private priority;
}
class ParkingPlace
{
/**
* #ORM\Column(name="name", type="string", lenght=255)
*/
private name;
/**
* #ORM\OneToMany(targetEntity="Historical", mappedBy="parkingPlace")
*/
private historical;
}
And that is the render I wish:
<form>
<fieldset>
<legend>Parking A1</legend>
<input name="priority" type="number" />
</fieldset>
<fieldset>
<legend>Parking A2</legend>
<input name="priority" type="number" />
</fieldset>
<fieldset>
<legend>Parking A3</legend>
<input name="priority" type="number" />
</fieldset>
<fieldset>
<legend>Parking A4</legend>
<input name="priority" type="number" />
</fieldset>
...
</form>
I have spent many hours on it, but I didn't any solution. I have tried many solution on Stack but none answers my problem.
I managed to answer the question. I changed the DB architecture and used a 'Collection' field in my form.
I leave here the entire code. I hope it will help other people.
History Entity
//src/Xxx/YyyBundle/Entity/History.php
namespace Xxx\YyyBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* Xxx\YyyBundle\Entity\History
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Xxx\YyyBundle\Entity\HistoryRepository")
* #UniqueEntity(
* fields="name",
* message="Il existe déjà une table ayant ce nom."
* )
*/
class History
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
* #Assert\NotBlank(message="Le nom de la table a été oublié")
*/
private $name;
/**
* #var datetime $date
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var Xxx\ZzzBundle\Entity\User $agent
*
* #ORM\ManyToOne(targetEntity="Ratp\AgentBundle\Entity\User")
* #ORM\JoinColumn(name="agent_id", referencedColumnName="id")
*/
private $agent;
/**
* #var Xxx\YyyBundle\Entity\ParkingPlacePriority $agent
*
* #ORM\OneToMany(targetEntity="ParkingPlacePriority", mappedBy="history", cascade={"persist"})
* #Assert\Valid(traverse=true)
*/
private $parkingPlacesPriorities;
/**
* Constructeur
*
* #return string
*/
public function __construct()
{
$this->parkingPlacesPriorities = new ArrayCollection();
}
/**
* Get History's name
*
* #return string
*/
public function __toString()
{
return $this->name;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set date
*
* #param datetime $date
*/
public function setDate($date)
{
$this->date = $date;
}
/**
* Get date
*
* #return datetime
*/
public function getDate()
{
return $this->date;
}
/**
* Set agent
*
* #param Xxx\ZzzBundle\Entity\User $agent
*/
public function setAgent(\Xxx\ZzzBundle\Entity\User $agent)
{
$this->agent = $agent;
}
/**
* Get agent
*
* #return Xxx\ZzzBundle\Entity\User
*/
public function getAgent()
{
return $this->agent;
}
/**
* Set parkingPlacesPriorities
*
* #param Xxx\YyyBundle\Entity\ParkingPlacePriority $agent
*/
public function setParkingPlacesPriorities(ArrayCollection $parkingPlacesPriorities)
{
$this->parkingPlacesPriorities = $parkingPlacesPriorities;
foreach($parkingPlacesPriorities as $parkingPlacePriority)
{
$parkingPlacePriority->setHistory($this);
}
}
/**
* Get parkingPlacesPriorities
*
* #return Xxx\YyyBundle\Entity\ParkingPlacePriority
*/
public function addParkingPlacesPriorities(\Xxx\YyyBundle\Entity\ParkingPlacePriority $parkingPlacesPriorities)
{
return $this->parkingPlacesPriorities[] = $parkingPlacesPriorities;
foreach($parkingPlacesPriorities as $parkingPlacePriority)
{
$parkingPlacePriority->setHistory($this);
}
}
/**
* Get parkingPlacesPriorities
*
* #return Xxx\YyyBundle\Entity\ParkingPlacePriority
*/
public function getParkingPlacesPriorities()
{
return $this->parkingPlacesPriorities;
}
}
ParkingPlace Entity
//src/Xxx/YyyBundle/Entity/ParkingPlace.php
namespace Xxx\YyyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Xxx\YyyBundle\Entity\ParkingPlace
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Xxx\YyyBundle\Entity\ParkingPlaceRepository")
*/
class ParkingPlace
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer $orderSequence
*
* #ORM\Column(name="orderSequence", type="integer")
* #Assert\Min(
* limit="1",
* message="L'ordre d'affichage ne peux être inférieure à 1",
* invalidMessage="L'ordre d'affichage doit être un chiffre"
* )
*/
private $orderSequence;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\MinLength(
* limit=1,
* message="Le nom SAET doit comporter au minimum 1 caractère"
* )
* #Assert\MaxLength(
* limit=255,
* message="Le nom SAET doit comporter au maximum 255 caractères"
* )
* #Assert\Regex(
* pattern="/^[a-z0-9-]+$/i",
* message="Le nom d'exploitation contient des caractères invalides (seul les caractères alphanumériques et le tiret '-' sont acceptés)"
* )
*/
private $name;
/**
* #var string $saetName
*
* #ORM\Column(name="saetName", type="string", length=255, unique=true)
* #Assert\MinLength(
* limit=5,
* message="Le nom SAET doit comporter au minimum 5 caractères"
* )
* #Assert\MaxLength(
* limit=255,
* message="Le nom SAET doit comporter au maximum 255 caractères"
* )
* #Assert\Regex(
* pattern="/^prk_/i",
* message="Le nom SAET ne commence pas par 'PRK_'"
* )
* #Assert\Regex(
* pattern="/^[a-z0-9_]+$/i",
* message="Le nom SAET contient des caractères invalides (seul les caractères alphanumériques et le trait de soulignemet '_' sont acceptés)"
* )
*/
private $saetName;
/**
* #var string $rail
*
* #ORM\Column(name="rail", type="string", length=5)
* #Assert\NotBlank()
* #Assert\MinLength(
* limit=1,
* message="Le nom SAET doit comporter au minimum 1 caractères"
* )
* #Assert\MaxLength(
* limit=5,
* message="Le nom SAET doit comporter au maximum 5 caractères"
* )
*/
private $rail;
/**
* #var Xxx\YyyBundle\Entity\ParkingZone $parkingZone
*
* #ORM\ManyToOne(targetEntity="ParkingZone")
* #ORM\JoinColumn(name="parkingzone_id", referencedColumnName="id")
*/
private $parkingZone;
/**
* Get ParkingPlace's name
*
* #return string
*/
public function __toString()
{
return $this->name;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set orderSequence
*
* #param integer $orderSequence
*/
public function setOrderSequence($orderSequence)
{
$this->orderSequence = $orderSequence;
}
/**
* Get orderSequence
*
* #return integer
*/
public function getOrderSequence()
{
return $this->orderSequence;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = strtoupper($name);
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set saetName
*
* #param string $saetName
*/
public function setSaetName($saetName)
{
$this->saetName = strtoupper($saetName);
}
/**
* Get saetName
*
* #return string
*/
public function getSaetName()
{
return $this->saetName;
}
/**
* Set rail
*
* #param string $rail
*/
public function setRail($rail)
{
$this->rail = strtoupper($rail);
}
/**
* Get rail
*
* #return string
*/
public function getRail()
{
return $this->rail;
}
/**
* Set parkingZone
*
* #param Xxx\YyyBundle\Entity\ParkingZone $parkingZone
*/
public function setParkingZone(\Xxx\YyyBundle\Entity\ParkingZone $parkingZone)
{
$this->parkingZone = $parkingZone;
}
/**
* Get parkingZone
*
* #return Xxx\YyyBundle\Entity\ParkingZone
*/
public function getParkingZone()
{
return $this->parkingZone;
}
}
ParkingPlacePriority Entity
//src/Xxx/YyyBundle/Entity/ParkingPlacePriority.php
namespace Xxx\YyyBundle\Entity;
use Xxx\YyyBundle\RatpGarageL1Bundle;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Xxx\YyyBundle\Entity\ParkingPlacePriority
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Xxx\YyyBundle\Entity\ParkingPlacePriorityRepository")
*/
class ParkingPlacePriority
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Xxx\YyyBundle\Entity\ParkingPlace $parkingPlace
*
* #ORM\ManyToOne(targetEntity="ParkingPlace")
* #ORM\JoinColumn(name="parkingplace_id", referencedColumnName="id")
*/
private $parkingPlace;
/**
* #var Xxx\YyyBundle\Entity\History $history
*
* #ORM\ManyToOne(targetEntity="History", cascade={"persist"})
* #ORM\JoinColumn(name="history_id", referencedColumnName="id")
*/
private $history;
/**
* #var integer $priorityIn
*
* #ORM\Column(name="priorityIn", type="integer")
* #Assert\NotBlank(message="La priorité de garage n'as pas été donné")
* #Assert\Min(
* limit="1",
* message="La priorité de garage ne peux être inférieure à 1",
* invalidMessage="La priorité doit être un chiffre"
* )
*/
private $priorityIn;
/**
* #var integer $priorityOut
*
* #ORM\Column(name="priorityOut", type="integer")
* #Assert\NotBlank(message="La priorité de dégarage n'as pas été donné")
* #Assert\Min(
* limit="1",
* message="La priorité de dégarage ne peux être inférieure à 1",
* invalidMessage="La priorité doit être un chiffre"
* )
*/
private $priorityOut;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set priorityIn
*
* #param integer $priorityIn
*/
public function setPriorityIn($priorityIn)
{
$this->priorityIn = $priorityIn;
}
/**
* Get priorityIn
*
* #return integer
*/
public function getPriorityIn()
{
return $this->priorityIn;
}
/**
* Set priorityOut
*
* #param integer $priorityOut
*/
public function setPriorityOut($priorityOut)
{
$this->priorityOut = $priorityOut;
}
/**
* Get priorityOut
*
* #return integer
*/
public function getPriorityOut()
{
return $this->priorityOut;
}
/**
* Set parkingPlace
*
* #param Xxx\YyyBundle\Entity\ParkingPlace $parkingPlace
*/
public function setParkingPlace(\Xxx\YyyBundle\Entity\ParkingPlace $parkingPlace)
{
$this->parkingPlace = $parkingPlace;
}
/**
* Get parkingPlace
*
* #return Xxx\YyyBundle\Entity\ParkingPlace
*/
public function getParkingPlace()
{
return $this->parkingPlace;
}
/**
* Set history
*
* #param Xxx\YyyBundle\Entity\History $history
*/
public function setHistory(\Xxx\YyyBundle\Entity\History $history)
{
$this->history = $history;
}
/**
* Get history
*
* #return Xxx\YyyBundle\Entity\History
*/
public function getHistory()
{
return $this->history;
}
}
History Controller
//src/Xxx/YyyBundle/Controller/HistoryController.php
namespace Xxx\YyyBundle\Controller;
use Xxx\YyyBundle\Entity\ParkingPlacePriority;
use Xxx\YyyBundle\Entity\ParkingPlace;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Xxx\YyyBundle\Entity\History;
use Xxx\YyyBundle\Form\HistoryType;
/**
* History controller.
*
* #Route("")
*/
class HistoryController extends Controller
{
/**
* Lists all History entities.
*
* #Route("/", name="history")
* #Template()
*/
public function indexAction()
{
$em = $this->getDoctrine()->getEntityManager();
$entities = $em->getRepository('XxxYyyBundle:History')->findAll();
return array('entities' => $entities);
}
/**
* Displays a form to create a new History entity.
*
* #Route("/new", name="history_new")
* #Template()
*/
public function newAction()
{
$em = $this->getDoctrine()->getEntityManager();
$entities = $em->getRepository('XxxYyyBundle:ParkingPlace')->findAllOrdered();
$parkingZones = $em->getRepository('XxxYyyBundle:ParkingZone')->findAllOrdered();
$history = new History();
foreach ($entities as $entity)
{
$parkingPlacePriority = new ParkingPlacePriority();
$parkingPlacePriority->setParkingPlace($entity);
$history->addParkingPlacesPriorities($parkingPlacePriority);
}
$form = $this->createForm(new HistoryType(), $history);
return array(
'entity' => $history,
'parkingPlaces' => $entities,
'parkingZones' => $parkingZones,
'form' => $form->createView()
);
}
/**
* Creates a new History entity.
*
* #Route("/create", name="history_create")
* #Method("post")
* #Template("XxxYyyBundle:History:new.html.twig")
*/
public function createAction()
{
$em = $this->getDoctrine()->getEntityManager();
$entities = $em->getRepository('XxxYyyBundle:ParkingPlace')->findAllOrdered();
$parkingZones = $em->getRepository('XxxYyyBundle:ParkingZone')->findAllOrdered();
$history = new History();
foreach ($entities as $entity)
{
$parkingPlacePriority = new ParkingPlacePriority();
$parkingPlacePriority->setParkingPlace($entity);
$history->addParkingPlacesPriorities($parkingPlacePriority);
}
$history->setDate(new \DateTime());
$history->setAgent($this->container->get('security.context')->getToken()->getUser());
$request = $this->getRequest();
$form = $this->createForm(new HistoryType(), $history);
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($history);
$em->flush();
return $this->redirect($this->generateUrl('parkingplacepriority_export', array('id' => $history->getId())));
}
return array(
'entity' => $history,
'parkingPlaces' => $entities,
'parkingZones' => $parkingZones,
'form' => $form->createView()
);
}
/**
* Displays a form to edit an existing History entity.
*
* #Route("/{id}/edit", name="history_edit")
* #Template("XxxYyyBundle:History:new.html.twig")
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$parkingPlaces = $em->getRepository('XxxYyyBundle:ParkingPlace')->findAllOrdered();
$parkingZones = $em->getRepository('XxxYyyBundle:ParkingZone')->findAllOrdered();
$entity = $em->getRepository('XxxYyyBundle:History')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find History entity.');
}
$entity->setName('');
$editForm = $this->createForm(new HistoryType(), $entity);
return array(
'entity' => $entity,
'parkingPlaces' => $parkingPlaces,
'parkingZones' => $parkingZones,
'form' => $editForm->createView(),
);
}
/**
* Edits an existing History entity.
*
* #Route("/{id}/update", name="history_update")
* #Method("post")
* #Template("XxxYyyBundle:History:new.html.twig")
*/
public function updateAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('XxxYyyBundle:History')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find History entity.');
}
$editForm = $this->createForm(new HistoryType(), $entity);
$deleteForm = $this->createDeleteForm($id);
$request = $this->getRequest();
$editForm->bindRequest($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('parkingplacepriority_export', array('id' => $id)));
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
);
}
}
History FormType
//src/Xxx/YyyBundle/Form/HistoryType.php
namespace Xxx\YyyBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class HistoryType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name', 'text', array(
'max_length' => 255,
'trim' => true,
)
)
->add('parkingPlacesPriorities', 'collection', array(
'type' => new ParkingPlacePriorityType(),
'by_reference' => false,
)
)
;
}
public function getName()
{
return 'xxx_yyybundle_historytype';
}
}
ParkingPlacePriority FormType
//src/Xxx/YyyBundle/Form/ParkingPlacePriorityType.php
namespace Xxx\YyyBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ParkingPlacePriorityType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('priorityIn', 'number', array(
'precision' => 0,
)
)
->add('priorityOut', 'number', array(
'precision' => 0,
)
)
->add('parkingPlace', 'entity', array(
'class' => 'RatpGarageL1Bundle:ParkingPlace',
'read_only' => true,
)
)
;
}
public function getName()
{
return 'xxx_yyybundle_parkingplaceprioritytype';
}
}
History new entity form template
// src/Xxx/YyyBundle/Resources/views/History/new.html.twig
{% extends '::base.html.twig' %}
{% block title %}
{{ parent() }} | Historique | Nouvelle table
{% endblock %}
{% block zoneMenu %}
<li class="">
Enregistrer
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Zone de garage
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
{% for parkingZone in parkingZones %}
<li class="">
{{ parkingZone.name }}
</li>
{% endfor %}
</ul>
</li>
{% endblock %}
{% block content %}
<h1>Nouvelle table de garage/dégarage</h1>
<form action="{{ path('history_create') }}" method="post" {{ form_enctype(form) }} class="form-horizontal">
<div class="row-fluid">
<div class="control-group offset7 {% if form_errors(form.name) | length > 0 %}error{% endif %}">
{{ form_label(form.name, 'Nom de la table', { 'attr': {'class': 'control-label'} } ) }}
<div class="controls error">
{{ form_widget(form.name, { 'attr': {'class': ''} } ) }}
<span class="help-inline">{{ form_errors(form.name) }}</span>
</div>
</div>
</div>
{% set voie = '0' %}
{% set zone = '0' %}
{% set i = 0 %}
{% for pkPl in form.parkingPlacesPriorities %}
{% if voie != parkingPlaces[i].rail %}
{% if voie != '0' %}
</fieldset>
{% endif %}
{% if zone != parkingPlaces[i].parkingZone %}
{% if zone != '0' %}
</div>
{% endif %}
<div id="{{ parkingPlaces[i].parkingZone.id }}" class="zone row-fluid">
<h3 class="">{{ parkingPlaces[i].parkingZone.name }}</h3>
<div class="synoptique">
<span>{{ asset('bundles/xxxyyy/images/' ~ parkingPlaces[i].parkingZone.image) }}</span>
</div>
{% endif %}
{% set zone = parkingPlaces[i].parkingZone %}
<fieldset class="voie">
{% set voie = parkingPlaces[i].rail %}
<legend class=""><strong>Voie {{ parkingPlaces[i].rail }}</strong></legend>
{% endif %}
<fieldset name="{{ parkingPlaces[i].name }}" class="place_garage span5">
<legend>{{ parkingPlaces[i].name }}</legend>
<div class="control-group {% if form_errors(pkPl.priorityIn) | length > 0 %}error{% endif %}">
{{ form_label(pkPl.priorityIn, 'Garage', { 'attr': {'class': 'control-label'} } ) }}
<div class="controls error">
{{ form_widget(pkPl.priorityIn, { 'attr': {'class': 'garage'} } ) }}
<span class="help-inline">{{ form_errors(pkPl.priorityIn) }}</span>
</div>
</div>
<div class="control-group {% if form_errors(pkPl.priorityOut) | length > 0 %}error{% endif %}">
{{ form_label(pkPl.priorityOut, 'Dégarage', { 'attr': {'class': 'control-label'} } ) }}
<div class="controls">
{{ form_widget(pkPl.priorityOut, { 'attr': {'class': 'degarage'} } ) }}
<span class="help-inline">{{ form_errors(pkPl.priorityOut) }}</span>
</div>
</div>
<div class="control-group">
{{ form_label(pkPl.parkingPlace, 'Place de garage', { 'attr': {'class': 'control-label'} } ) }}
<div class="controls error">
{{ form_widget(pkPl.parkingPlace, { 'attr': {'class': ''} } ) }}
<span class="help-inline">{{ form_errors(pkPl.parkingPlace) }}</span>
</div>
</div>
</fieldset>
{% set i = i + 1 %}
{% endfor %}
</fieldset>
</div>
{{ form_rest(form) }}
<div class="form-actions">
<button type="submit" class="btn btn-primary">Enregistrer</button>
Annuler
</div>
</form>
{% endblock %}
{% block javascript %}
<script src="{{ asset('bundles/xxxyyy/js/script.js') }}"></script>
{% endblock %}