Symfony 3 update Action - symfony

In my project, foreign key should hidden in the form type and have default value so the first id in the table refernced.
In the New Action all good but is in the update action that I block.
I've tried like tkis to give default value for my foreign key in update but It don't works, I have an error: Expected argument of type "AppBundle\Entity\Cursus", "string" given
public function editAction(Request $request, Etudiant $etud)
{
$deleteForm = $this->createDeleteForm($etud);
$editForm = $this->createForm('AppBundle\Form\EtudiantType', $etud);
$editForm->handleRequest($request);
$first = $this->getDoctrine()->getRepository(Cursus::class)->findOneBy([]);
$etud->setIdcursus($first);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('etudiant_edit');
}
return $this->render('etudiant/edit.html.twig', array(
'etudiant' => $etud,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
EDIT
Symfony 3.3.10
form Type
$builder->add('nom')
->add('prenom')
->add('adresse')
->add('matricule')
->add('domaine')
->add('idcursus', HiddenType::class);
The problem
The wrong is in my idcursus whom should hidden and have default value(the first id in cursus entity).

Related

Symfony form validation does not work on edit

I have a form with 3 fields as below : storeClient , type and line that belong to Fashion entity.
I basically have the same problem mentioned here :
Symfony Form Validation not working in Edit
But I was surprised when I edited the form and chose the placeholder as option for Client and I filled the line and type fields , I got that for the client field, it DOES display my validation message "Please choose an option" .which is good .
However for the remaining two fields, if line or type are edited in such a way to choose the placeholder option, the application crashed and gives the argumet exception error.
I did a dump; die; inside the controller (you can see it commented below) . And I got the $fashion object like this when I chose the placeholder for all the fields aka for the client,type and line fields :
Fashion object :
storeClient: null
line: Proxies ...\RefLine
___isinitilized___ :true
and all the info of the line that was set initiallly in this object when I first enterede its edit page.
type: Proxies ...\RefType
___isinitilized___ :true
and all the info of the type that was set initiallly in this object when I first enterede its edit page.
so my question is why the validations work on edit for the client field and does not work for line and type ? I do not think that it is related to the fact that it is a choicettype whereas the other two are entitytype. Moreover, I didn't put a "?" in the setter of client. So i don't see why it works for this field and WHY it gave a Null value when I printed the object and it didn't print the initial client value that was already set in the object when I first landed on the edit page although the two other fields hold the values that were already stored in the object initially.
FashionType.php
->add('storeClient', ChoiceType::class,
[
'label' => 'Store Client',
'choices' => $choicesClient,
'choice_value' => function ($value) {
if ($value instanceof Client) {
return $value->getId();
} else {
return $value;
}
},
'placeholder' => 'Choose ..',
'choice_label' => 'diplayLabel',
'attr' => ['class' => "chosen"],
'required' => true,
]
)
->add('type',
EntityType::class,
[
'label' => 'Clothes Type',
'class' => RefType::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('refType')
->orderBy('refType.id', 'ASC');
},
'attr' => ['class' => "chosen"],
'placeholder' => 'Choose..',
'required' => true,
'choice_label' => 'label',
])
->add('line',
EntityType::class,
[
'label' => 'cotation.creation_form.ligne_de_cotation',
'class' => RefLine::class,
'choice_value' => function ($value) {
if ($value instanceof RefLine) {
return $value->getId();
} else {
return $value;
}
},
'query_builder' => function (EntityRepository $er) {
return $er->getShoppingLines();
},
'attr' => ['class' => "chosen"],
'placeholder' => 'Choose..',
'required' => true,
'choice_label' => 'getLabel',
])
IN my controller, this function is called upon submitting the form :
public function validerAction(Request $request, $idFashion)
{
$em = $this->getDoctrine()->getManager();
/** #var Fashion $fashion */
$fashion = ($idFashion === null) ? new Fashion() : $em->getRepository(
'App:Fashion'
)->find($idFashion);
$form = $this->createForm(FashionType::class, $fashion);
// try {
$form->handleRequest($request);
//} catch(\InvalidArgumentException) {
//dump($fashion);die;
// }
if ($form->isSubmitted() && $form->isValid()) {..}
Here are my setters:
/**
* Set line
*
* #param Refline $line
*
* #return Fashion
*/
public function setLine(RefLine $line)
{
$this->line = $line;
return $this;
}
/**
* Set type
*
* #param RefType $type
*
* #return Fashion
*/
public function setType(RefType $type)
{
$this->type = $type;
return $this;
}
/**
* Set storeClient
*
* #param Client $storeClient
* #return Fashion
*/
public function setStoreClient($storeClient)
{
$this->storeClient = $storeClient;
return $this;
}
THe three fields were declared like this :
/**
* #ORM\ManyToOne(targetEntity="App\Entity\RefLine")
* #ORM\JoinColumn(name="line_id", referencedColumnName="id", nullable=false)
*/
private $line;
In EntityType::class field type is by default nullable. If you want to add validation on that then you have to write this
/**
*
* #Assert\NotBlank(message="Please enter Line", groups="groupName")
*/
private $line;
For more details you can read https://symfony.com/doc/current/validation.html
if you are using group name then you should declare in Form
$resolver->setDefaults([
// ...
'validation_groups' => ['Default', 'groupName'],
]);

symfony2 Entity Object vs. integer crashes

I have defined a entity like :
/**
* #ORM\ManyToOne(targetEntity="Pr\UserBundle\Entity\Client")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client_id;
.....
public function setClientId($clientId = null)
{
$this->client_id = $clientId;
return $this;
}
There are two controllers with which I can create a new db entry. the first one is "admin-only" where the admin can create a db entry with a client id of his choice:
->add('client_id', 'entity', array(
'data_class' => null,
'attr' => array(
'class' => 'selectstyle'),
'class' => 'PrUserBundle:Client',
'property' => 'name',
'required' => true,
'label' => 'staff.location',
'empty_value' => 'admin.customer_name',
'empty_data' => null
)
)
......
// Handling the form
$em = $this->getDoctrine()->getManager();
$saniType->setName($form->get('name')->getData());
$saniType->setClientId($form->get('client_id')->getData());
$saniType->setCreated(new \DateTime(date('Y-m-d H:m:s')));
$saniType->setCreatedBy($user->getUsername());
$em->persist($saniType);
$em->flush();
The second one is for the client itself, where he's not able to set a different client id. Therefor I just removed the form field "client_id" and replace it by the users->getClientId():
$saniType->setSpecialClientId($form->get('client_id')->getData());
When I add an entry as admin, it work fine. If I try to add one as "client", it crashes with following error message
Warning: spl_object_hash() expects parameter 1 to be object, integer given in /var/www/symfony/webprojekt/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php line 1389
I'm a newby in symfony, so I haven't got the strength to figure out what happens. I only knew that in the first case, admin will submit a object (entity). In the second (client) case, I set an integer as I get one by
$user = $this->container->get('security.context')->getToken()->getUser();
Is there a solution for it so that I can handle entity object AND given integers like it comes when the client add an entry?
You should change you relation defnition to:
/**
* #ORM\ManyToOne(targetEntity="Pr\UserBundle\Entity\Client")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
.....
public function setClient($client = null)
{
$this->client = $client;
return $this;
}
Then in form:
->add('client', 'entity', array(
'data_class' => null,
'attr' => array('class' => 'selectstyle'),
'class' => 'PrUserBundle:Client',
'property' => 'name',
'required' => true,
'label' => 'staff.location',
'empty_value' => 'admin.customer_name',
'empty_data' => null
)
)
Handling the form:
form = $this->createForm(new SaniType(), $entity);
$form->handleRequest($request);
if ($form->isValid()) {
// perform some action...
return $this->redirect($this->generateUrl('some_success'));
}
More about handling form: http://symfony.com/doc/current/book/forms.html#handling-form-submissions
Also worth nothing:
for auto update properties like createdBy / updatedBy i would recommend you to use Doctrine Extension: https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/blameable.md
You don't have to know the client id. You have to set the Client himself.
/**
* #ORM\ManyToOne(targetEntity="Pr\UserBundle\Entity\Client")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
.....
public function setClient(\Pr\UserBundle\Entity\Client $client = null)
{
$this->client = $client;
return $this;
}
I found a Solution:
Symfony2: spl_object_hash() expects parameter 1 to be object, string given in Doctrine
It's a workaround but it's ok for the moment.

Entity Field type hidden in Symfony2

I want to make a hidden value for my Foreign Key Entity in controller.
My previous controller is like this (works fine):
->add('id_grup', 'entity', array('class' => 'Sifo\AdminBundle\Entity\MstGrup'))
I want to assign a hidden value to my form like this:
->add('id_grup', 'hidden', array('data' => $id))
But it gives me an error:
ContextErrorException: Catchable Fatal Error: Argument 1 passed to
Sifo\AdminBundle\Entity\DftGrupMapel::setIdGrup() must be an instance
of Sifo\AdminBundle\Entity\MstGrup, string given, called in
C:\Sifony\vendor\symfony\symfony\src\Symfony\Component\PropertyAccess\PropertyAccessor.php
on line 360 and defined in
C:\Sifony\src\Sifo\AdminBundle\Entity\DftGrupMapel.php line 179
How can I assign a value to a foreign key entity which is hidden?
Finally it works! I need define the entity default before create form and don't add again in FormBuilder:
public function manageAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('SifoAdminBundle:MstGrup')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find MstGrup entity.');
}
$entity_new = new DftGrupMapel();
$entity_new->setIdGrup($entity);
$new_form = $this->createFormBuilder($entity_new)
->setAction($this->generateUrl('admin_grup_mapel_manage', array('id' => $id)))
->setMethod('POST')
->getForm();
$new_form->handleRequest($request);
if ($new_form->isValid()) {
$em_new = $this->getDoctrine()->getManager();
$em_new->persist($entity_new);
$em_new->flush();
return $this->redirect($this->generateUrl('admin_grup_mapel_manage', array('id' => $id)));
}
return $this->render('SifoAdminBundle:DftGrupMapel:manage.html.twig', array(
'entity' => $entity,
'new_form' => $new_form->createView(),
));
}

Symfony2 - Generate CRUD

I am trying to generate CRUD of the entities but i have a few questions, i don't know if it's a normal comportment or an error.
I apply the command :
I am adding the route in routing.yml like asking.
Now, when i am testing this crud , just create party work.
Update doesn't working, it's updateAction :
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('IFppoGestionPersonnelBundle:TableTest')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find TableTest entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('tabletest_edit', array('id' => $id)));
}
return $this->render('IFppoGestionPersonnelBundle:TableTest:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
I don't know why it doesn't add "em->persist($entity)", but if i add this line , it does not update ...
I have same errors with deleteAction.
And when i am creating a new tuple, and back to list , the last tuple is not displaying.
It's maybe an error to the class :
IFppo\GestionPersonnelBundle\Entity\TableTest:
type: entity
table: tabletest
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
nom:
type: string
length: 255
column: nom
prenom:
type: string
length: 255
column: prenom
lifecycleCallbacks: { }
In log, i don't have any trace of update ...
[EDIT] When writing to the log for any errors, return an empty array with $editForm->getErrors() and with $editForm->getErrorsAsString() return :
nom: No errors prenom: No errors submit: No errors [] []
Thanks a lot.

Prevent duplicates in the database in a many-to-many relationship

I'm working on a back office of a restaurant's website. When I add a dish, I can add ingredients in two ways.
In my form template, I manually added a text input field. I applied on this field the autocomplete method of jQuery UI that allows:
Select existing ingredients (previously added)
Add new ingredients
However, when I submit the form, each ingredients are inserted in the database (normal behaviour you will tell me ).
For the ingredients that do not exist it is good, but I don't want to insert again the ingredients already inserted.
Then I thought about Doctrine events, like prePersist(). But I don't see how to proceed. I would like to know if you have any idea of ​​the way to do it.
Here is the buildForm method of my DishType:
<?php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('category', 'entity', array('class' => 'PrototypeAdminBundle:DishCategory',
'property' => 'name',
'multiple' => false ))
->add('title', 'text')
->add('description', 'textarea')
->add('price', 'text')
->add('ingredients', 'collection', array('type' => new IngredientType(),
'allow_add' => true,
'allow_delete' => true,
))
->add('image', new ImageType(), array( 'label' => false ) );
}
and the method in my controller where I handle the form :
<?php
public function addDishAction()
{
$dish = new Dish();
$form = $this->createForm(new DishType, $dish);
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($dish);
$em->flush();
return $this->redirect($this->generateUrl('prototype_admin_get_dish', array('slug' => $dish->getSlug())));
}
}
return $this->render('PrototypeAdminBundle:Admin:addDish.html.twig', array(
'form' => $form->createView(),
));
}
I was having the same problem. My entities were projects (dishes in your case) and tags (ingredients).
I solved it by adding an event listener, as explained here.
services:
my.doctrine.listener:
class: Acme\AdminBundle\EventListener\UniqueIngredient
tags:
- { name: doctrine.event_listener, event: preUpdate }
- { name: doctrine.event_listener, event: prePersist }
The listener triggers both prePersist (for newly added dishes) and preUpdate for updates on existing dishes.
The code checks if the ingredient already exists. If the ingredient exists it is used and the new entry is discarded.
The code follows:
<?php
namespace Acme\AdminBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Acme\AdminBundle\Entity\Dish;
use Acme\AdminBundle\Entity\Ingredient;
class UniqueIngredient
{
/**
* This will be called on newly created entities
*/
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
// we're interested in Dishes only
if ($entity instanceof Dish) {
$entityManager = $args->getEntityManager();
$ingredients = $entity->getIngredients();
foreach($ingredients as $key => $ingredient){
// let's check for existance of this ingredient
$results = $entityManager->getRepository('Acme\AdminBundle\Entity\Ingredient')->findBy(array('name' => $ingredient->getName()), array('id' => 'ASC') );
// if ingredient exists use the existing ingredient
if (count($results) > 0){
$ingredients[$key] = $results[0];
}
}
}
}
/**
* Called on updates of existent entities
*
* New ingredients were already created and persisted (although not flushed)
* so we decide now wether to add them to Dishes or delete the duplicated ones
*/
public function preUpdate(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
// we're interested in Dishes only
if ($entity instanceof Dish) {
$entityManager = $args->getEntityManager();
$ingredients = $entity->getIngredients();
foreach($ingredients as $ingredient){
// let's check for existance of this ingredient
// find by name and sort by id keep the older ingredient first
$results = $entityManager->getRepository('Acme\AdminBundle\Entity\Ingredient')->findBy(array('name' => $ingredient->getName()), array('id' => 'ASC') );
// if ingredient exists at least two rows will be returned
// keep the first and discard the second
if (count($results) > 1){
$knownIngredient = $results[0];
$entity->addIngredient($knownIngredient);
// remove the duplicated ingredient
$duplicatedIngredient = $results[1];
$entityManager->remove($duplicatedIngredient);
}else{
// ingredient doesn't exist yet, add relation
$entity->addIngredient($ingredient);
}
}
}
}
}
NOTE: This seems to be working but I am not a Symfony / Doctrine expert so test your code carefully
Hope this helps!
pcruz
Since this post is 2 years old I don't know if help is still needed here, anyway..
You should place an addIngredient function within your Dish entity, this function checks if the Ingredient object exists within the current ingredient collection.
addIngredient(Ingredient $ingredient){
if (!$this->ingredients->contains($ingredient)) {
$this->ingredients[] = $ingredient;
}
}
Hopefully it could still help you out.

Resources