ManyToOne relation in sonata admin bundle - php

I have an entity which DishesWithCategory by the link to other entities:
/**
* #ORM\ManyToOne(targetEntity="Dishes", cascade={"persist"})
*/
protected $dishes;
/**
* #ORM\ManyToOne(targetEntity="MenuCategory", cascade={"persist"})
*/
protected $category;
In admin i have:
$formMapper
->add('dishes', 'sonata_type_admin', [
'delete' => false,
'btn_add' => false
])
->add('category', 'sonata_type_model',[
'expanded' => true,
'multiple' => true,
])
;
When I try to create a dish, I get the error:
Found entity of type Doctrine\Common\Collections\ArrayCollection on association ZaWeb\MenuBundle\Entity\DishesWithCategory#category, but expecting ZaWeb\MenuBundle\Entity\MenuCategory
Can someone faced with this? how can I fix it?

I didn't fully understand your model but i think that the issue comes from : the multiple => true on category because you can set only one category (ManyToOne) for a DishesWithCategory.
Either you need to change your model to a OneToMany for your $category or you need to remove the ArrayCollection which might be in the constructor of your model and remove multiple => true.
You might need to do :
$formMapper
->add('dishes', 'sonata_type_admin', [
'delete' => false,
'btn_add' => false
])
->add('category', 'sonata_type_model',[
'expanded' => true
])
;

Related

Sonata admin ignores "required" attribute

I am working on a Symfony 2.7 application that uses the Sonata admin bundle. In one of my entities' configureFormFields() method, I have the following:
->add('market',
'entity',
array(
'multiple' => true,
'class' => 'MyCompany\AppBundle\Entity\Market',
'choices' => $query = $this
->entityManager
->getRepository(Market::class)
->findBy(['status' => 100])
,
'placeholder' => 'no_selection',
'required' => true,
'label' => $this->trans('country_of_origin', [], 'messages'),
'attr' => array(
'class' => 'jsb_ jsb_GetDealersForCountry jsb_HideOtherTabs',
'data-jsb' => json_encode(array(
'url' => $this->getRequest()->getBaseUrl() . '/dealers/country/id/'
)),
)
)
)
... but I find that I am able to save without any value in the 'market' field.
Here is the annotation over the market property in my entity:
/**
*
* #ORM\ManyToMany(targetEntity="MyCompany\AppBundle\Entity\Market", cascade={"persist"})
*
*/
private $market;
So anyway, is there a simple way to make this field truly mandatory?
Please Refer below link and create your custom validation for market field in admin class
sonata admin validation
Here is how my annotations now look:
/**
*
* #ORM\ManyToMany(targetEntity="MyCompany\AppBundle\Entity\Market", cascade={"persist"})
* #Assert\Count(min=1)
*
*/
private $market;
This change comes courtesy of the Symfony documentation:
https://symfony.com/doc/2.8/reference/constraints/NotNull.html

Symfony2 Sonata Project sonata_type_model with OneToMany entity sortby

I work with Symfony2 and sonata admin. I have an entity (News) which own a subcategory. Each subcategory own one category, and each category own one Affaire.
In the add page for a news, I have a subcategory list, to choose my subcategory to link to my news. Each item of my select is formated like this :
<li> subcategory (category'affaire) > categoryName </li>.
I would like to sort the fields by the affaire (ASC).
Here is my formfield definition :
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('subCategory', 'sonata_type_model', array("label" => "Catégorie/Sous Catégorie", "btn_add" => false));
}
One News own one Subcategory
One Subcategory own one Category
One category own one Affaire.
I tried to add something like :
->add('subCategory', 'sonata_type_model',
array("label" => "Sub Category",
"btn_add" => false
),
array(
'sortable' => 'ordering',
'label' => 'subcategory.category.affaire.code',
))
But nothing changes. Any Ideas ?
Category entity :
class NewsCategory
{
/**
* #var \My\Custom\Foo\Entity\Affaire
*
* #ORM\ManyToOne(targetEntity="\My\Custom\Foo\Entity\Affaire")
* #ORM\JoinColumn(name="affaire_code", referencedColumnName="code")
*/
private $affaire;
--
Subcategory entity :
class NewsSubCategory
{
/**
* #var \My\Custom\Foo\Entity\NewsCategory
*
* #ORM\ManyToOne(targetEntity="\My\Custom\Foo\Entity\NewsCategory")
* #ORM\JoinColumn(name="category_ref", referencedColumnName="id")
*
*/
private $category;
--
News entity :
class News
{
/**
* #var \My\Custom\Foo\Entity\NewsSubCategory
*
* #ORM\ManyToOne(targetEntity="\My\Custom\Foo\Entity\NewsSubCategory")
* #ORM\JoinColumn(name="sub_category", referencedColumnName="id")
*/
private $subCategory;
[EDIT] :
I tried
->add('subCategory', 'sonata_type_model',array("label" => "Catégorie/Sous Catégorie","btn_add" => false), array("sortable" => "ordering"))
And I doesn't make an error but nothing happend. I don't understand where i could add the option (orderBy => 'Affaire') , or if it has to be done that way ...
[EDIT2] :
I even tried :
->add('subCategory.category.affaire', null,
array("label" => "Catégorie/Sous Catégorie",
"btn_add" => false
))
I don't know how you can do that with a sonata_type_model but you can change the type of your field to null or entity (null set the default type) and add a query_builder option to adapt the query used :
->add('subcategory', null, array(
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('sc')
->leftjoin('sc.category', 'c')
->orderBy('c.affaire', 'ASC');
}
))
If instead of null you choose entity, you have to add the class also :
->add('subcategory', 'entity', array(
'class' => 'MyCustomFooBundle:Subcategory',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('sc')
->leftjoin('sc.category', 'c')
->orderBy('c.affaire', 'ASC');
}
))
It seems that 'Sortable' had to be in the third parameter.
->add('subCategory', 'sonata_type_model',
array("label" => "Sub Category",
"btn_add" => false
'sortable' => 'ordering',
))
And after that, you have two options : Trying to show the Affaire
->add('subCategory.categorie.affaire', 'sonata_type_model',
array("label" => "Affaire",
"btn_add" => false
'sortable' => 'ordering',
))
Or our Entity can implement "Collections Sortable" . Try to have a look to : https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/sortable.md
(Sorry, I'm not fluent in english)

Symfony Entities in a collection

I couldn't find any similar questions so here goes:
I have a Many-To-Many relationship between my (order)Flow Entity and my Product Entity, but it doesn't select an <option> in the <select>.
All the Entities has been setup by Symfony itself so the #ORM\ManyToMany etc. should be ok.
My controller has the following line:
$form = $this->createForm(new \FDM\BestilBundle\Type\FlowsType(), $flow)->add('submit', 'submit');
The $flow is populated correctly from the db.
The FlowsType file has amoung many fields the following code:
->add('product', 'collection', [
'type' => new ProductDropdownType(),
'allow_add' => TRUE,
'allow_delete' => TRUE,
'prototype' => TRUE,
'by_reference' => FALSE,
]
)
All fields in the FlowsType are filled out correctly, except the one below.
The ProductDropdownType has the following code:
$builder->add('name', 'entity', [
'class' => 'FDMBestilBundle:Flows',
'property' => 'name',
'by_reference' => false
]);
The number of rows is correct - if I have three rows in my many-to-many sql table it shows three rows. They just aren't selected.
If I change the ProductDropdownType to:
$builder->add('name', 'text');
The data is showing just fine - so the db and everyting is working. Except when I want a collection of <select>...
The relations are the following in the Entities:
In the Flow Entity:
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="FDM\BestilBundle\Entity\Product", inversedBy="flow")
* #ORM\JoinTable(name="productsinflows",
* joinColumns={
* #ORM\JoinColumn(name="flow", referencedColumnName="flowId")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="product", referencedColumnName="productId")
* }
* )
*/
private $product;
In the Product Entity:
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="FDM\BestilBundle\Entity\Flows", mappedBy="product")
*/
private $flow;
Can someone please help me - I'm stuck!
You can use query builder in your form, this is an exemple :
In the query builder, create the SQL query with DQL
->add('espece', 'entity', array(
'class' => 'ADMapecheBundle:Espece',
'property' => 'nom',
'multiple' => false,
'query_builder' => function(EspeceRepository $er) use ($user) {
return $er->createQueryBuilder('p')
->where("p.user = :user")
->orderBy('p.nom', 'ASC')
->setParameter('user', $user);
I hope to help you, friendly

Symfony User Roles not selected in user form

I have created a simple user/role form. The form shows the user's detail correctly and displays all the possible roles, but for some reason it does not pre-select the users' current role. For the relationship between the user and role I had the following in the user entity class:
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="users", cascade={"persist","remove"})
* #ORM\JoinTable(name="user_role")
*/
protected $roles;
The formtype class was built using:
$builder->add('firstname')
->add('lastname')
->add('email')
->add('roles');
The database looks like this:
Any hints/assistance would be appreciated.
You need to define your roles fields as entity
http://symfony.com/doc/current/reference/forms/types/entity.html
change this line ->add('roles'); to:
->add('roles', 'entity', array(
'multiple' => true,
'expanded' => true,
'property' => 'name',
'class' => 'Your_Path\Entity\Roles',
));
it should work.
Second option:
you can try to create role type form as mentioned here and then do something like this
$builder->add('roles', 'collection', array('type' => new RoleType()));
its recomended to read this this about mapped option and other as by_reference
Had the same problem in symfony4, adding this did the trick for me:
'choice_value' => function ($choice) {
return $choice;
},

Doctrine 2: Understand how entities works with doctrine 2

I have 3 Entities: Person, Affiliation and PersonAffiliation.
In my form, I will display each affiliation as a checked checkbox.
Nowm when the user uncecks the checkbox and click submit, this affiliation should be removed from the PersonAffiliation table.
The problem is that when I submit without unchecking, my data are duplicated.
Example: aff1 and aff2. When both checked and submit, I will then get aff1 aff1 aff2 aff2.
The same, If I uncheck aff2, I will then have aff1 aff1.
The error is probably somewhere in using the doctrine:
Here is how I am managing that:
Entity Persom
#ORM\OneToMany(targetEntity="PersonAffiliation", mappedBy="person", cascade={"persist", "remove"})
protected $affiliations;
Entity Affiliation:
#ORM\OneToMany(targetEntity="PersonAffiliation", mappedBy="affiliation")
protected $person_affiliations;
Entity PersonAffiliation
#ORM\ManyToOne(targetEntity="Person", inversedBy="affiliations")
#ORM\JoinColumn(name="person_id", referencedColumnName="id")
protected $person;
#ORM\ManyToOne(targetEntity="Affiliation", inversedBy="person_affiliations")
#ORM\JoinColumn(name="affiliation_id", referencedColumnName="id")
protected $affiliation;
An idea on how to resolve that?
Thank you.
EDIT:
Cotroller part:
foreach( $enquiry->getAffiliations() as $aff )
{
$pAff = new PersonAffiliation();
$pAff->setPersonId( $person->getId() );
$pAff->setAffiliationId( $aff->getAffiliation()->getId() );
$pAff->setPerson( $person );
$pAff->setAffiliation( $aff->getAffiliation() );
$em->persist($pAff);
$em->flush();
}
Form Part:
public function buildForm(FormBuilder $builder, array $options)
{
$person = $this->person;
$user = $this->user;
$builder->add('firstname', 'text');
$builder->add('middlename', 'text', array('required'=>false));
$builder->add('lastname', 'text');
$builder->add('sex', 'choice', array( 'choices' => array('m' => 'Male', 'f' => 'Female'),
'required' => true,
'multiple' => false,
'expanded' => true));
$builder->add('email', 'text', array('required'=>false));
if( $this->addAffiliations ) {
$builder->add('affiliations', 'entity', array(
'label' => 'Athor\'s affiliations',
'class' => 'SciForumVersion2Bundle:PersonAffiliation',
'query_builder' => function($em) use ($person, $user){
return $em->createQueryBuilder('pa')
->where('pa.person_id = :pid')
->setParameter('pid', $person->getId());
},
'property' => 'affiliation',
'multiple' => true,
'expanded' => true,
));
}
}
In the Person entity :
/**
* #ORM\ManyToMany(targetEntity="Affiliation", inversedBy="people")
* #ORM\JoinTable(name="PersonAffiliation")
*/
protected $affiliations;
And in the Affiliation entity :
/**
* #ORM\ManyToMany(targetEntity="Person", mappedBy="affiliations")
*/
protected $people;
You made a $em->flush() on each iteration of the foreach. It should be done after the end of foreach isnt'it ?
Moreover, you may use a ManyToMany relation.

Categories