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.
Related
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'],
]);
I am working with two ManyToMany related entities, namely category and tag.
The entity Tag(relevant details):
/**
*
* #var string
*
* #ORM\Column(name="tagname", type="string")
*/
protected $tagname;
/**
* #ORM\ManyToMany(targetEntity="Category", mappedBy="tags")
*/
protected $categories;
The entity Category(relevant details):
/**
*
* #var string
*
* #ORM\Column(name="CategoryName", type="string",length=200)
*/
protected $categoryname;
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="categories")
*/
protected $tags;
I have a form with a select-input(CategoryType) and a multiple select-input(TagType) fields. Both the fields are EntityType fields. The TagType is embedded inside the CatgoryType.
For this I am not able to utilise the cascade=persist functionality and am adding the submitted tags manually inside my controller. On submission the form data gets persisted in the database without any issues.
The problem is, after submission, when I fetch the submitted category(and the associated tags) in my controller, and pass it to the form, I get this error - Unable to transform value for property path "tagname": Expected a Doctrine\Common\Collections\Collection object.
The var_dump result of the fetched category object(var_dump($category->getTags()->getValues());) gives me an array of the associated Tag objects, with the property protected 'tagname' => string 'tag1'.
From what I understand Interface Collection is quite similar to a php array and My guess is that the tagname field expects all the tagnames in an ArrayCollection or Collection object format. I am not sure whether what is the specific difference.
However I am still clueless how do I pass the already persisted category object in my form.
Here are the categoryname and tags field in the CategoryType:
$builder->add('categoryname', EntityType::class, array(
'class' => 'AppBundle:Category',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.id', 'ASC');
},
'choice_label' => 'categoryname',
'expanded' => false,
'multiple' => false,
'label' => 'Choose Category',
));
$builder->add('tags', CollectionType::class, array(
'entry_type' => TagType::class,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
));
Here is the embedded tagname field in the TagType:
$builder->add('tagname', EntityType::class, array(
'class' => 'AppBundle:Tag',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('t')
->orderBy('t.id', 'ASC');
},
'choice_label' => 'tagname',
'expanded' => false,
'multiple' => true,
'label' => 'Choose Tags',
));
Any ideas?
Try to rid off 'multiple' => true in embedded form. This worked for me.
I've had a similar problem where my EntityType form element gave me this error message:
Unable to reverse value for property path 'my_property' Expected an array.
Setting multiple to false would make the implementation useless, so a better option for me was to set the empty_data to an empty array:
"empty_data" => [],
In your case you might be able to solve the problem by setting the empty_data to a Collection, something like this will probably work:
"empty_data" => new ArrayCollection,
Here is how you do it (from source: https://www.youtube.com/watch?v=NNCpj4otnrc):
***And here is a text version of this image #1, the reason I did not add text because it was hard to read when the format is not proper!
<?php
namespace App\Form;
use App\Entity\Post;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class PostType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, [
'attr' => [
'placeholder' => 'Etner the title here',
'class' => 'custom_class'
]
])
->add('description', TextareaType::class, [
'attr' => [
'placeholder' => 'Enter teh description here',
]
])
->add('category', EntityType::class, [
'class' => 'App\Entity\Category'
])
->add('save', SubmitType::class, [
'attr' => [
'class' => 'btn btn-success'
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Post::class,
]);
}
}
***And here is a text version of this image #2, the reason I did not add text because it was hard to read when the format is not proper!
class FormController extends AbstractController
{
/**
* #Route("/form", name="form")
* #param Request $request
* #return Response
*/
public function index(Request $request)
{
$post = new Post(); // exit('this');
/*$post->setTitle('welcome');
$post->setDescription('description here');*/
$form = $this->createForm(PostType::class, $post, [
'action' => $this->generateUrl('form'),
'method' => 'POST'
]);
// handle the request
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// var_dump($post); die();
// save to database
$em = $this->getDoctrine()->getManager();
$em->persist($post);
$em->flush();
}
return $this->render('form/index.html.twig', [
'postaform' => $form->createView()
]);
}
My assumption was wrong, I need to either make tagname field an array or create a ManyToOne or ManyToMany relationship with any other entity so it can be an arraycollection. Only then it is possible to use tagname as a multiple select field.
/**
*
* #var array
*
* #ORM\Column(name="tagname", type="array")
*/
protected $tagname;
or
/**
* #ORM\ManyToMany(targetEntity="SOME_ENTITY", mappedBy="SOME_PROPERTY")
*/
protected $tagname;
or
/**
* #ORM\ManyToOne(targetEntity="SOME_ENTITY", mappedBy="SOME_PROPERTY")
*/
protected $tagname;
The exception thrown is pretty explicit, and the problem is probably here:
$builder->add('tagname', EntityType::class, array()
According to your Tag entity, Tag::$tagname is not an entity collection, it's a string. You should add the property with
$builder->add('tagname', TextType::class, array()
shouldn't you ?
I work on a symfony 2 app and I need some help to resolve a case I never had before.
My app has only one page with multiple blocs. Let's consider animals for a simple example. On my page, I have a first bloc where I show N dogs with all their caracteristics, then a second bloc where I show rabbits, then a third bloc with cats ect.
I also have an admin page where the user may modify the displayed data on the main page. The problem I have is that I must use only one page to admin all the blocs. That means that I have N dog, M rabbits, P cats entities displayed on my admin page and when I submit my form, Symfony must delete, update or insert each entity in database.
To do so, I created an entity and a formType for each animal, and a mapped superclass called Website with arraycollections for each entity.
Website Entity :
/**
* Website
* #ORM\MappedSuperclass()
*/
class Website
{
/**
* #var ArrayCollection
*/
private $dogs;
/**
* #var ArrayCollection
*/
private $rabbits;
/**
* #var ArrayCollection
*/
private $cats;
...
}
Website Type :
class WebsiteType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('dogs', 'collection', array(
'type' => new DogType(),
'allow_add' => true,
'allow_delete' => true
))
->add('rabbits', 'collection', array(
'type' => new RabbitType(),
'allow_add' => true,
'allow_delete' => true
))
->add('cats', 'collection', array(
'type' => new CatType(),
'allow_add' => true,
'allow_delete' => true
))
->add('save', 'submit')
;
}
}
In my controller :
$manager = $this->getDoctrine()->getManager();
$dogs = $manager->getRepository('MyBundle:Dog')->findAll();
$rabbits = $manager->getRepository('MyBundle:Rabbit')->findAll();
$cats = $manager->getRepository('MyBundle:Cat')->findAll();
$website = new Website();
$website->setDogs($dogs);
$website->setRabbits($rabbits);
$website->setCats($cats);
$form = $this->createForm(new WebsiteType(), $website);
if ($form->handleRequest($request)->isValid()) {
$manager->persist($website);
$manager->flush();
}
return $this->render('MyBundle:Default:admin.html.twig', array(
'form' => $form->createView(),
'website' => $website
));
When I submit the form, I have this error :
The given entity of type 'MyBundle\Entity\Website'
(MyBundle\Entity\Website#0000000040d8aeb900007fd77a072110) has no
identity/no id values set. It cannot be added to the identity map.
What should I do ?
I'm trying to use a choice list in a form with the entity type but it's not working if I add data to the form. It's giving me a "could not convert object to int" error.
My buildForm method
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('department', 'entity', array(
'label' => 'Form.department',
'class' => 'HotfloSystemCoreBundle:Department',
'choice_list' => $this->departmentChoiceList,
'multiple' => true,
'required' => false,
'attr' => array(
'class' => 'selectpicker',
'data-actions-box' => true,
'data-live-search' => true,
'data-selected-text-format' => 'count'
),
'horizontal' => false,
));
}
My ChoiceList
class DepartmentChoiceList extends LazyChoiceList
{
/**
* #var EntityManager
*/
protected $em;
public function __construct($em)
{
$this->em = $em;
}
/**
* Loads the choice list
* Should be implemented by child classes.
*
* #return ChoiceListInterface The loaded choice list
*/
protected function loadChoiceList()
{
$departments = $this->getDepartments();
$departmentChoices = [];
foreach ($departments as $department) {
$departmentChoices[$department->getId()] = $department;
}
// Return the choice list
return new SimpleChoiceList($departmentChoices);
}
/**
* Get the departments available in the poli appointment data
*
* #return Department[]
*/
protected function getDepartments()
{
// Get the used department out of the appointment table by using a group by SQL statement
/** #var $qb QueryBuilder */
$qb = $this->em->getRepository('MyBundle:PoliAnalyzeAppointment')
->createQueryBuilder('appointment');
$qb->select('DISTINCT IDENTITY(appointment.department)');
// Get the actual departments
/** #var $qb2 QueryBuilder */
$qb2 = $this->em->getRepository('MyBundle:Department')
->createQueryBuilder('department');
$qb2->where($qb2->expr()->in('department.id', $qb->getDQL()));
$qb2->orderBy('department.name', 'ASC');
return $qb2->getQuery()->getResult();
}
}
I'm using the entity type because it should be converted to an entity and back. If I use the choice type I have to do this myself (which I don't want).
How can I achieve this?
Use query_builder option to filter entity choice list. Something like:
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('a')
->select(array('DISTINCT IDENTITY(a.department)', 'd'))
->from('MyBundle:PoliAnalyzeAppointment', 'a')
->innerJoin('a.department', 'd')
->groupBy('a.department')
->orderBy('d.name', 'ASC');
}
In the buildForm method I would fill it with the standard options array:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('department', 'entity', array(
'label' => 'Form.department',
'choice_list' => $options['departmentChoiceList'],
'multiple' => true,
'required' => false,
'attr' => array(
'class' => 'selectpicker',
'data-actions-box' => true,
'data-live-search' => true,
'data-selected-text-format' => 'count'
),
'horizontal' => false,
));
}
And then in the same formType add another method:
public function setDefaultOptions(OptionsResolverInterface $resolver) {
/*
* Instantiate DepartmentChoiceList and
* Implement the logic to build your Array and then set it this way
*/
$resolver->setDefaults(array(
'departmentChoiceList' => $yourDepartamentChoiceArray,
'data_class' => 'HotfloSystemCoreBundle:Department'
));
}
Note: I declared also the data_class here for the whole form, but you can also leave it out of the setDefaults if you want.
I suggest taking a look into the Entity type so you don't have to use a Transformer to convert object to int -> int to object for choice fields.
I've this Form defined:
class NaturalFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
....
->add('servicio', 'entity', array(
'mapped' => FALSE,
'class' => 'ComunBundle:TipoServicio',
'property' => 'nombre',
'required' => FALSE,
'label' => FALSE,
'expanded' => TRUE,
'multiple' => TRUE
));
}
...
}
And this is the definition for TipoServicio entity:
/**
* #ORM\Entity
* #ORM\Table(name="nomencladores.tipo_servicio", schema="nomencladores")
* #ORM\Entity(repositoryClass="Sencamer\ComunBundle\Entity\Repository\TipoServicioRepository")
*/
class TipoServicio
{
protected $id;
protected $nombre;
protected $activo = true;
protected $cedula_benef_sisgesp;
... setters/getters function above
}
Any time I try to build the form on the controller:
public function naturalAction() {
$entity = new Natural();
$form = $this->createForm(new NaturalFormType(), $entity, array('action' => $this->generateUrl('guardar-registro')));
return array('entity' => $entity, 'form' => $form->createView());
}
I get this error:
Property ComunBundle\Entity\TipoServicio::$tipo_usuario does not exist
Why? What I'm doing wrong or what I'm not seeing in my code?
I clear the cache several times and run the command cache:clear and cache:warmup without success.
PS: I deleted some parts from code for easier reading and do the code less extensive
PS1: Sorry for the spanish language on some parts but this code is for a spanish client so he wants her code on spanish (ugly for me but clients always have the reason)
EDIT
Search for $tipo_usuario:
Search for tipo_usuario:
Your code is trying to get this tipo_usuario property somewhere.
In where file and line this error is throw ? Do you have the full stack trace ?