I have two simple entities : Cabinet and Personne with "OneToOne" relation. But when I add Cabinet, I have this error : Column 'personne_id' cannot be null.
Cabinet entity :
class Cabinet
{
/**
* #ORM\OneToOne(targetEntity="LogicielBundle\Entity\Personne", cascade={"persist","remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $personne;
public function setPersonne(\LogicielBundle\Entity\Personne $personne)
{
$this->personne = $personne;
return $this;
}
public function getPersonne()
{
return $this->personne;
}
Personne entity :
class Personne {
/**
* #ORM\OneToOne(targetEntity="UtilisateurBundle\Entity\Cabinet", cascade={"persist","remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $cabinet;
public function setCabinet(\UtilisateurBundle\Entity\Cabinet $cabinet)
{
$this->cabinet = $cabinet;
return $this;
}
public function getCabinet()
{
return $this->cabinet;
}
My Controller is very simple :
public function ajouterAction(Request $request)
{
$personne = new Personne();
$cabinet = new Cabinet();
$cabinet->setPersonne($personne);
$personne->setCabinet($cabinet);
$form = $this->createForm('utilisateur_cabinet_form', $cabinet);
$this->submit($form);
if ($form->handleRequest($request)->isValid()) {
$em = $this->getDoctrine()->getManager();
dump($personne);
dump($cabinet);
$em->persist($cabinet);
$em->flush();
$request->getSession()->getFlashBag()->add('success', 'Le cabinet « '.$cabinet->getVersions()[0]->getLibelle().' » a été ajouté.');
return $this->redirect($this->generateUrl('utilisateur_cabinet_index'));
}
return array(
'form' => $form->createView(),
'title' => 'Ajouter un nouveau cabinet'
);
}
dump($cabinet) ans dump($personne) is true ; can you help me ?
Make sure to allow the Setter parameter to be null as well (nullable=true isn't enough here):
public function setPersonne(\LogicielBundle\Entity\Personne $personne = null)
Related
I'm working on a Symfony project where an I have two types of User Client and EmployeSpie, both have their own entity.
When you create/edit a user you can link EmployeSpie to a CLient.
That's where is my problem, When I edit or create a user I can create a user but nothing is store inside my table which make the link between my table Client and EmployeSpie.
Here is what I've done:
my entity Client having this:
class Client extends User
{
/**
* #ORM\ManyToMany(targetEntity=EmployeSpie::class, mappedBy="clients", cascade={"persist"})
*/
private $employeSpies;
/**
* #return Collection|EmployeSpie[]
*/
public function getEmployeSpies(): Collection
{
return $this->employeSpies;
}
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClientEmploye($this);
}
return $this;
}
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClientEmploye($this);
}
return $this;
}
}
and my table EmployeSpie:
class EmployeSpie extends User
{
/**
* #ORM\ManyToMany(targetEntity=Client::class, inversedBy="employeSpies")
*/
private $clients;
/**
* #return Collection|Client[]
*/
public function getClients(): Collection
{
return $this->clients;
}
public function addClient(Client $client): self
{
if (!$this->clients->contains($client)) {
$this->clients[] = $client;
}
return $this;
}
public function removeClient(Client $client): self
{
if ($this->clients->contains($client)) {
$this->clients->removeElement($client);
}
return $this;
}
public function __toString()
{
return $this->getPrenom()." ".$this->getNom();
}
My forms are made with a Symfony form:
class ClientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email')
->add('password')
->add('nom')
->add('prenom')
->add('telephone')
->add('fax')
->add('is_active')
->add('client_fonction')
->add('site')
->add('employeSpies', EntityType::class, array(
'class' => EmployeSpie::class ,
'label' => 'Sélectionnez les emloyés rattachés à ce client',
'expanded' => false,
'multiple' => true,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Client::class,
]);
}
}
and in my Controller I've made the following thing:
/**
* #Route("/admin/clients/create", name="admin.client.new")
* #param Request $request
* #return RedirectResponse|Response
*/
public function new(Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$client = new Client();
$form = $this->createForm(ClientType::class, $client);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$client->setRoles(array('ROLE_CUSTOMER'));
$client->setPassword(
$passwordEncoder->encodePassword(
$client,
$form->get('password')->getData()
)
);
$this->em->persist($client);
$this->em->flush();
$this->addFlash('success', 'Nouveau client crée avec succès');
$this->redirectToRoute('admin.clients.index');
}
return $this->render("admin/clients/create.html.twig", [
'client' => $client,
'form' => $form->createView()
]);
}
/**
* #Route("/admin/clients/{id}", name="admin.client.edit", methods="GET|POST")
* #param Client $client
* #return Response
*/
public function edit(Client $client,Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$form = $this->createForm(ClientType::class, $client);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$clientEmploye = $request->request->get('client');
$clientEmploye = $clientEmploye['employeSpies'];
$client->setPassword(
$passwordEncoder->encodePassword(
$client,
$form->get('password')->getData()
)
);
foreach ($form->get('employeSpies')->getData() as $employe){
$client->addEmployeSpy($employe);
}
$client->setRoles(array('ROLE_CUSTOMER'));
$this->em->flush();
$this->addFlash('success', 'Nouveau client modifié avec succès');
$this->redirectToRoute('admin.clients.index');
}
return $this->render("admin/clients/edit.html.twig", [
'client' => $client,
'form' => $form->createView()
]);
}
Si my user is created or edited normally but I did not store the link for employeSpies in my form. Do you have any idea why?
I found the answer to my problem.
#Jakumi was right but few other cha ges were needed.
In my client Entity I has to change :
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClientEmploye($this);
}
return $this;
}
to :
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClient($this);
}
return $this;
}
Same thing for the remove.
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClientEmploye($this);
}
return $this;
}
to :
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClient($this);
}
return $this;
}
But after the other change in my ClientType :
->add('employeSpies', EntityType::class, array(
'class' => EmployeSpie::class ,
'by_reference' => false,
'label' => 'Sélectionnez les employés rattachés à ce client',
'expanded' => false,
'multiple' => true,
))
I need to add the 'by_reference' => false,to make it works.
Because of this Symfony will not try to find the "setClient" method but to find addClient method
Hope it could help later some other persons :)
I have table rows with created employees. Every employee has unique ID. When user clicks on employee, he can add a new skill for this employee with name and level fields. I wrote the code that successfully creates employees and show it, but I don't know how to add skill to unique ID, that it was represented just for one specific user, not all of them.
I made two tables with doctrine - Person and Skill, as well as two controllers for them. Also, I made assotiations ManyToOne, so that one employee could have multiple skills.
Entity for Skill
class Skill
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Person", inversedBy="skills")
* #ORM\JoinColumn(nullable=false)
*/
private $person;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=255)
*/
private $level;
public function getId(): ?int
{
return $this->id;
}
public function getPerson(): ?Person
{
return $this->person;
}
public function setPerson(?Person $person): self
{
$this->person = $person;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getLevel(): ?string
{
return $this->level;
}
public function setLevel(string $level): self
{
$this->level = $level;
return $this;
}
}
Entity for Person
class Person
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Skill", mappedBy="person")
*/
private $skills;
public function __construct()
{
$this->skills = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* #return Collection|Skill[]
*/
public function getSkills(): Collection
{
return $this->skills;
}
public function addSkill(Skill $skill): self
{
if (!$this->skills->contains($skill)) {
$this->skills[] = $skill;
$skill->setPerson($this);
}
return $this;
}
public function removeSkill(Skill $skill): self
{
if ($this->skills->contains($skill)) {
$this->skills->removeElement($skill);
// set the owning side to null (unless already changed)
if ($skill->getPerson() === $this) {
$skill->setPerson(null);
}
}
return $this;
}
}
Function that shoud create/add new skill to employee
/**
* #Route("/skill/new", name="new_skill")
* Method({"GET", "POST"})
*/
public function new(Request $request) {
$skill = new Skill();
$form = $this->createFormBuilder($skill)
->add('name', TextType::class, array('attr' => array('class' => 'form-control')))
->add('level', TextareaType::class, array(
'attr' => array('class' => 'form-control')
))
->add('save', SubmitType::class, array(
'label' => 'Create',
'attr' => array('class' => 'btn btn-primary mt-3')
))
->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$skill = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($skill);
$entityManager->flush();
return $this->redirectToRoute('skill_list');
}
return $this->render('main/new.html.twig', array(
'form' => $form->createView()
));
}
You will have to persist($person) as well
You will have to fetch the Person and set him to Skill before your flush
/**
* #Route("/skill/new", name="new_skill")
* Method({"GET", "POST"})
*/
public function new(Request $request) {
$personId = $request->request->get('person_id'); //POST data
$person = $entityManager->getRepository(Person::class)
->find($personId);
$skill = new Skill();
$skill->setPerson($person);
$form = $this->createFormBuilder($skill)
/// add fields
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/// $skill = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($skill);
$entityManager->flush();
return $this->redirectToRoute('skill_list');
}
return $this->render('main/new.html.twig', array(
'form' => $form->createView()
));
}
In your case, you delegate a technique to a person that is not really correct. Since when you want to add this technique to another person, it will send you an error. The preferable in this situation is a ManyToMany. Otherwise you can always create an associative class to retrieve the identifiers of the two classes.
I have a CollectionType fields in my form, and I made it so I can add as many of these fields as you like, here's a pic (the collectiontype are the fields under Exception)
https://imgur.com/a/xQ7qUNT
Now I'm trying to loop through the data and insert it into an array and finally insert it into my database, but this is what I get in my databse https://imgur.com/a/WyBmmwr
also, tried getting the data that is cough after clicking submit: https://imgur.com/a/pLBKx1y and it's there.
this is my method:
/**
* #Route("/new", name="type_parking_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$typeParking = new TypeParking();
$exception = new Exception();
$form = $this->createForm(TypeParkingType::class, $typeParking);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$lesjours = $typeParking->getJourstravail();
$typeParking->getException()->add($exception);
// Here I try getting the data
$excep = $form->get('Exception');
foreach ($excep as $ExceptionForm) {
$name = $ExceptionForm->get('nom')->getData();
$StartDate = $ExceptionForm->get('datedebut')->getData();
$EndDate = $ExceptionForm->get('datefin')->getData();
$StartTime = $ExceptionForm->get('tempsdebut')->getData();
$EndTime = $ExceptionForm->get('tempsfin')->getData();
$exception->setNom($name);
$exception->setDatedebut($StartDate);
$exception->setDatefin($EndDate);
$exception->setTempsdebut($StartTime);
$exception->setTempsfin($EndTime);
$typeParking->addException($exception);
}
// ends here
// this is unrelated
$jour = $lesjours['jour'];
$debut = $lesjours['debut']->format('H:i:s');
$fin = $lesjours['fin']->format('H:i:s');
$newDate = Array('lesjour' => Array($jour => Array('heuredebut' => $debut, 'heurefin' => $fin)));
$typeParking->setJourstravail($newDate);
//end unrelated
$this->addFlash('success', "type added ");
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($typeParking);
$entityManager->flush();
return $this->redirectToRoute('type_parking_index');
}
return $this->render(
'Admin/type_parking/new.html.twig',
['type_parking' => $typeParking, 'form' => $form->createView()]
);
}
and here's my entity TypeParking
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="App\Repository\TypeParkingRepository")
*/
class TypeParking
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=55)
*/
private $libelle;
/**
* #ORM\Column(type="time", nullable=true)
*/
private $tempsmax;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $jourdebut;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $jourfin;
/**
* #ORM\Column(type="json_array", nullable=true)
*/
private $jourstravail;
/**
* #ORM\Column(type="json_array", nullable=true)
*/
private $exception;
public function __construct()
{
$this->exception = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTempsmax(): ?\DateTimeInterface
{
return $this->tempsmax;
}
public function setTempsmax(\DateTimeInterface $tempsmax): self
{
$this->tempsmax = $tempsmax;
return $this;
}
public function getJourdebut(): ?\DateTimeInterface
{
return $this->jourdebut;
}
public function setJourdebut(\DateTimeInterface $jourdebut): self
{
$this->jourdebut = $jourdebut;
return $this;
}
public function getJourfin(): ?\DateTimeInterface
{
return $this->jourfin;
}
public function setJourfin(\DateTimeInterface $jourfin): self
{
$this->jourfin = $jourfin;
return $this;
}
public function getJourstravail()
{
return array_merge([
'jour' => '',
'debut' => null,
'fin' => null,
// other sub-fields "empty" values
], $this->jourstravail ?? [] // prevent array_merge from failing if exception is empty
); }
public function setJourstravail($jourstravail): self
{
$this->jourstravail = $jourstravail;
return $this;
}
public function getException() {
return $this->exception;
}
public function setException($exception): self
{
$this->exception = $exception;
return $this;
}
public function addException($exception)
{
$this->exception->add($exception);
return $this;
}
public function getLibelle(): ?string
{
return $this->libelle;
}
public function setLibelle(string $libelle): self
{
$this->libelle = $libelle;
return $this;
}
}
btw, I have two entities, TypeParking and Exception, TypeParking has a property named Exception which is a json file type and must contain the data from Exception.
I've created CollectionType form, which can add unlimited amount of TicketTime entities into one Ticket entity. It is connected via database by a OneToMany relation.
What I am trying to do is to add one Ticket and multiple TicketTimes to the database at one time. For example, one Ticket and 3 TicketTimes.
I would like to know how to make this method, so I can take one Ticket & multiple TicketTimes and flush them to the database.
My Controller action:
public function createTicket(Request $request)
{
if ($this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
if ($this->getUser()->getrole() == 3) {
$em = $this->getDoctrine()->getManager();
$ticket = new Ticket();
$timeArray = new ArrayCollection();
$form = $this->createForm(TicketType::class, $ticket);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
foreach ($timeArray as $time) {
$time->setTicket($ticket);
$em->persist($time);
}
$ticket->setTaken(0);
$em->persist($ticket);
$em->flush();
return $this->redirectToRoute('main');
}
return $this->render(
'create_ticket.html.twig',
array('form' => $form->createView())
);
}
}
return $this->redirectToRoute('main');
}
Ticket entity:
/**
* #Assert\NotBlank()
* #ORM\OneToMany(targetEntity="TicketTime", mappedBy="ticket", fetch="EXTRA_LAZY", orphanRemoval=true, cascade={"persist"})
*/
private $ticketTimes;
public function setTicketTimes($time): void
{
$this->ticketTimes = $time;
}
/**
* #return ArrayCollection|TicketTime[]
*/
public function getTicketTimes()
{
return $this->ticketTimes;
}
TicketTime entity:
/**
* #ORM\ManyToOne(targetEntity="Ticket", inversedBy="time")
* #ORM\JoinColumn(nullable=false)
*/
private $ticket;
public function getTicket()
{
return $this->ticket;
}
public function setTicket($ticket): void
{
$this->ticket = $ticket;
}
I managed to fix it by myself :)
What was wrong:
I needed to create add method in Ticket entity, so I will be able to add as many TicketTime's as I want, here's the code which I added into Ticket entity:
public function addTicketTime(TicketTime $time)
{
$this->ticketTimes[] = $time;
$time->setTicket($this);
return $this;
}
I've also added some lines into Controller
........
if ($form->isSubmitted() && $form->isValid()) {
$ticketTimes = $form->get('ticketTimes')->getData();
foreach ($ticketTimes as $time) {
$ticket->addTicketTime($time);
}
.......
I want to add a collection of entities in Symfony 2.1.0-dev bug I got:
Neither property "sitterDegrees" nor method "getSitterDegrees()" nor method "isSitterDegrees()" exists in class "xxx\Entity\Degrees"
It happen because I have an entity in DegreesFormType.php and at this line
$this->form->bindRequest($request); in my handler.
I want to add multiple "degrees" on "sitter" entity (but degrees are a choice not like http://symfony.com/doc/master/cookbook/form/form_collections.html)
Did I forget something?
Entities
A simple ManyToMany between Sitter and Degrees
Sitter
class Sitter
{
//some properties
/**
* #var xxx\Entity\Degrees
* #ORM\ManyToMany(targetEntity="xxx\Entity\Degrees", orphanRemoval=true, inversedBy="sitters",cascade={"persist"})
* #ORM\JoinTable(name="sitter_degrees_relationships",
* joinColumns={
* #ORM\JoinColumn(name="sitter_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="degrees_id", referencedColumnName="id")
* }
* )
*/
private $sitterDegrees;
public function getSitterDegrees()
{
return $this->sitterDegrees;
}
public function setSitterDegrees(ArrayCollection $sitterDegrees)
{
foreach ($sitterDegrees as $sitterDegree) {
$sitterDegree->addSitter($this);
}
$this->sitterDegrees = $sitterDegrees;
}
public function addSitterDegree(xxx\Entity\Degrees $sitterDegrees)
{
$this->sitterDegrees[] = $sitterDegrees;
return $this;
}
public function removeSitterDegree(xxx\Entity\Degrees $sitterDegrees)
{
$this->sitterDegrees->removeElement($sitterDegrees);
}
}
Degrees
class Degrees
{
public function __toString(){return $this->name;}
private $id;
private $name;
/**
* #var xxx\Entity\Sitter
* #ORM\ManyToMany(targetEntity="xxx\Entity\Sitter", mappedBy="sitterDegrees")
*/
private $sitters;
public function __construct()
{
$this->sitters = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getSitters()
{
return $this->sitters;
}
public function addSitter(xxx\Entity\Sitter $sitter)
{
if (!$this->sitters->contains($sitter)) {
$this->sitters->add($sitter);
}
}
public function removeSitter(xxx\Entity\Sitter $sitters)
{
$this->sitters->removeElement($sitters);
}
}
FormType
VerifFormType.php is my main form, it embed DegreesFormType.
VerifFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
//->add('some_properties')
->add('sitterDegrees', 'collection', array(
'type' => new DegreesFormType(),
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true,
)
);
}
DegreesFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('sitterDegrees', 'entity', array(
'class' => 'xxx:Degrees'
));
}
Controller
public function indexAction()
{
$user = $this->get('security.context')->getToken()->getUser();
$sitter = $user->sitter;
$formHandler = $this->get('xxx.form.handler');
$form = $formHandler->getForm();
$form->setData($sitter);
if ($formHandler->process()) {
//ok
}
//fail
}
Handler
public function process()
{
$request = $this->container->get('request');
if ('POST' == $request->getMethod()) {
$this->form->bindRequest($request);//Fail at this line
if ($this->form->isValid()) {
return $this->onSuccess();
}
}
return false;
}
public function onSuccess()
{
$sitter = $this->form->getData();
$this->form->bindRequest($this->container->get('request'));
$sitter->setContainer($this->container);
$this->container->get('xxx.manager')->persistSitter($sitter);
return true;
}
index.html.twig
With some javascript like in the cookbook http://symfony.com/doc/master/cookbook/form/form_collections.html
<ul class="degrees" data-prototype="{{ form_widget(form.sitterDegrees.getVar('prototype')) | e }}">
{% for sitterDegree in form.sitterDegrees %}
<li>{{ form_row(sitterDegree) }}</li>
{% endfor %}
</ul>
The error comes from DegreesFormType: The sitterDegrees field maps to a setterDegrees property in your Degrees class. However, this class doesn't have such property.
There is a similar problem in VerifFormType: The sitterDegrees field maps to a setterDegrees property in your Sitter class. However, this class doesn't have such property.