Symfony 3, ManyToOne relation in form - php

I have a few Entities and I try to setup relations between users and permissions. I want to have possibility to assign group of permissions to user, so I created entity User, GroupAssociationsUser, Permissions. I though that best way is to create relation ManyToOne in GroupAssociationsUser to Users and to Permissions. Bellow you can see code of GroupAssociationsUser entity:
/**
* #ORM\ManyToOne(targetEntity="Permissions", inversedBy="group_assoc_user")
* #ORM\JoinColumn(name="group_permissions", referencedColumnName="id", nullable=FALSE)
*/
private $group_permissions;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="group_assoc_user")
* #ORM\JoinColumn(name="user_assoc", referencedColumnName="id", nullable=FALSE)
*/
private $user_assoc;
Then I also created relation in User entity:
/**
* #ORM\OneToMany(targetEntity="GroupAssociationsUser", mappedBy="user_assoc")
*/
private $group_assoc_user;
public function __construct()
{
$this->group_assoc_user = new ArrayCollection();
}
Finally in Permission entity:
/**
* #ORM\OneToMany(targetEntity="GroupAssociationsUser", mappedBy="group_permissions")
*/
private $group_assoc_user;
public function __construct()
{
$this->group_assoc_user = new ArrayCollection();
}
So basically I want to have select list on my user edit page and I want to have possibility to select permission group to assign to user.
So I created form with:
->add('group_assoc_user', EntityType::class, array(
'class' => 'AppBundle:Permissions',
'choice_label'=> 'group_name',
'placeholder' => 'no rights',
))
And the problem is that no mater what I do, I have got only list of exiting permissions or if I change code to :
->add('group_assoc_user', EntityType::class, array(
'class' => 'AppBundle:GroupAssociationsUser',
'choice_label'=> 'Permissions.group_name',
'placeholder' => 'no rights',
));
I have got listed only assigned permission without not assigned. What am I doing wrong?
Even if I got all permissions names how I can force doctrine to mark already assigned field?

Try to set Multiple to true.
http://symfony.com/doc/current/reference/forms/types/entity.html#multiple
->add('group_assoc_user', EntityType::class, array(
'class' => 'AppBundle:GroupAssociationsUser',
'choice_label'=> 'Permissions.group_name',
'placeholder' => 'no rights',
'multiple' => true,
));
You may also like the
'expanded' => true
option

Related

Modifying label for symfony generated form

I currently have a working form in Symfony where I have a list of companies with checkboxes next to each company name. This is so you can check off which company is assigned to each user. The checkbox currently shows the accountID but it would also be helpful to have the entity field 'name' as well. Can you build a property with two entity fields? Here is my form in my controller:
->add('companies', 'entity', array(
'label' => 'Company',
'class' => 'Default\Bundle\Entity\Customer',
'property' => 'accountId', //This puts the company id next to the check box
'multiple' => true,
'expanded' => true,
'query_builder' => function ($repository)
{
return $repository->createQueryBuilder('c')->orderBy('c.accountId', 'ASC');
},))
->add('Save', 'submit')
->getForm();
This is what I am trying to do:
->add('companies', 'entity', array(
'label' => 'Company',
'class' => 'Default\Bundle\Entity\Customer',
'property' => 'accountId' + 'name', // I want to combine my entity fields here
'multiple' => true,
'expanded' => true,
'query_builder' => function ($repository)
here is the entity just for reference
class Customer
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #Assert\NotBlank(message="Please enter a Customer ID.")
* #Assert\Length(max="32")
* #ORM\Column(type="string", length=32)
* #var string
*/
protected $accountId;
/**
* #Assert\NotBlank(message="Please enter a company name.")
* #Assert\Length(max="60")
* #ORM\Column(type="string", length=60)
* #var string
*/
protected $name;
And one last time... I want to go from this:
To this:
Create a simple getter and use that as the property, eg:
public function getNamePlusAccountId()
{
return $this->name." (".$this->accountId.")";
}
and use 'property' => 'namePlusAccountId' in your form.
If you only need to change the label but would like to keep the form field value then http://symfony.com/doc/current/reference/forms/types/entity.html#choice-label probably what are you looking for

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

form select parent hydration

I have a zf2 application that works with doctrine.
I have the following entity:
class Role
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", length=255, unique=true, nullable=true)
*/
protected $name;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="YrmUser\Entity\Role", mappedBy="parent")
*/
protected $children;
/**
* #var Role
* #ORM\ManyToOne(targetEntity="YrmUser\Entity\Role", inversedBy="children", cascade={"persist"})
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
}
for this entity i have a form:
class RoleForm extends Form
{
/**
* [init description]
*
* #return void
*/
public function init()
{
$this->setHydrator(
new DoctrineHydrator($this->objectManager, 'YrmUser\Entity\Role')
)->setObject(new Role());
$this->setAttribute('method', 'post');
$this->add(
array(
'name' => 'name',
'attributes' => array(
'type' => 'text',
'placeholder' =>'Name',
),
'options' => array(
'label' => 'Name',
),
)
);
$this->add(
array(
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'name' => 'parent',
'attributes' => array(
'id' => 'parent_id',
),
'options' => array(
'label' => 'Parent',
'object_manager' => $this->objectManager,
'property' => 'name',
'is_method' => true,
'empty_option' => '-- none --',
'target_class' => 'YrmUser\Entity\Role',
'is_method' => true,
'find_method' => array(
'name' => 'findBy',
'params' => array(
'criteria' => array('parent' => null),
),
),
),
)
);
}
}
The hydration for the select in the form works as it only shows other roles that don't have a parent.
But when editing a existing entity it shows itself in the select so i can select itself as its parent.
I figured if i would have the id of current entity inside the form i can create a custom repo with a method that retrieves all roles without a parent and does not have the current entity id.
But i cant figure out how to get the id of the currently edited entity from inside the form.
Any help is appreciated.
Cheers,
Yrm
You can fetch the bound entity within the form using $this->getObject().
You have actually already set this with setObject(new Role());. Unfortunately this means that it was not loaded via Doctine and you will have the same issue, no $id to work with.
Therefore you will need to add the 'parent role' options (value_options) after you have bound the role loaded via doctrine.
From within the controller, I normally request the 'edit' form from a service class and pass in the entity instance or id that is being edited. Once set you can then modify existing form elements before passing it back to the controller.
// Controller
class RoleController
{
public function editAction()
{
$id = $this->params('id'); // assumed id passed as param
$service = $this->getRoleService();
$form = $service->getRoleEditForm($id); // Pass the id into the getter
// rest of the controller...
}
}
By passing in the $id when you fetch the form you can then, within a service, modify the form elements for that specific role.
class RoleService implements ObjectManagerAwareInterface, ServiceLocatorAwareInterface
{
protected function loadParentRolesWithoutThisRole(Role $role);
public function getRoleEditForm($id)
{
$form = $this->getServiceLocator()->get('Role\Form\RoleEditForm');
if ($id) {
$role = $this->getObjectManager()->find('Role', $id);
$form->bind($role); // calls $form->setObject() internally
// Now the correct entity is attached to the form
// Load the roles excluding the current
$roles = $this->loadParentRolesWithoutThisRole($role);
// Find the parent select element and set the options
$form->get('parent')->setValueOptions($roles);
}
// Pass form back to the controller
return $form;
}
}
By loading the options after the form has initialized you do not need the current DoctrineModule\Form\Element\ObjectSelect. A normal Select element that has no default value_options defined should be fine.

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;
},

Symfony2 & SonataMedia: current field not linked to an admin

I've been tring the last days to make SonataMedia works with Symfony 2.0.16... with no success. Googling around seems like no much people use that bundle or there's a tutorial or an how-to that I'm not aware of, cause I don't get to much info about the error messages I've got so far.
Anyway, my last attempt gave the next error message:
The current field `path` is not linked to an admin. Please create one for the target entity : ``
"path" is the field used to save the file image (relative) path.
AttachmentAdmin.php
<?php
class AttachmentAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add(
'path',
'sonata_type_collection',
array(
'required' => true
),
array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position',
'targetEntity' => 'Application\Sonata\MediaBundle\Entity\GalleryHasMedia',
'link_parameters' => array(
'context' => 'attachment'
)
)
)
->add('notes', 'textarea', array('required' => false))
;
}
// other methods
}
Attachment.php
<?php
class Attachment
{
// other properties
/**
* #var string $path
*
* #ORM\Column(name="path", type="string", nullable=false)
* #ORM\ManyToOne(targetEntity="Application\Sonata\MediaBundle\Entity\GalleryHasMedia", cascade={"persist"})
*/
protected $path;
// other methods
/**
* Set path
*
* #param string $path
*/
public function setPath($path)
{
$this->path = $path;
foreach ($path as $ent) {
$ent->setAttachment($this);
}
}
/**
*
* #return string
*/
public function getPath()
{
return $this->path;
}
/**
*
* #param \Application\Sonata\MediaBundle\Entity\GalleryHasMedia $path
*/
public function addPath(\Application\Sonata\MediaBundle\Entity\GalleryHasMedia $path)
{
$this->path[] = $path;
}
}
GalleryHasMedia.php
<?php
class GalleryHasMedia extends BaseGalleryHasMedia
{
/**
* #var integer $id
*/
protected $id;
/**
*
* #var File
*/
private $attachment;
/**
* Get id
*
* #return integer $id
*/
public function getId()
{
return $this->id;
}
/**
*
* #param \Mercury\CargoRecognitionBundle\Entity\Attachment $attachment
* #return \Application\Sonata\MediaBundle\Entity\GalleryHasMedia
*/
public function setAttachment(\Mercury\CargoRecognitionBundle\Entity\Attachment $attachment = null)
{
$this->attachment = $attachment;
return $this;
}
/**
*
* #return \Application\Sonata\MediaBundle\Entity\File
*/
public function getAttachment()
{
return $this->attachment;
}
}
services.yml
mercury.cargo_recognition.admin.attachment:
class: Mercury\CargoRecognitionBundle\Admin\AttachmentAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: General, label: Attachments }
arguments: [ null, Mercury\CargoRecognitionBundle\Entity\Attachment, "MercuryCargoRecognitionBundle:AttachmentAdmin" ]
Thanks for any info!
Just a wild guess, create an admin class for GalleryHasMedia entity.
You need to add admin_code like this
$formMapper
->add(
'path',
'sonata_type_collection',
array(
'required' => true
),
array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position',
'targetEntity' => 'Application\Sonata\MediaBundle\Entity\GalleryHasMedia',
'link_parameters' => array(
'context' => 'attachment'
),
'admin_code' => 'sonata.media.admin.gallery_has_media' // this will be your admin class service name
)
)
->add('notes', 'textarea', array('required' => false))
;
You are trying to apply 'sonata_type_collection' on field 'path' of same entity class 'attachment' , while 'sonata_type_collection' is for collection of embeded form of different class .
So you will have to one more entity class suppose 'AttachmentCollection' and in this particular AttachmentsCollection's admin class, you should embed the 'Attachment' class admin ..
example:
class AttachmentsCollection extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('attachments', 'sonata_type_collection', array(
'required' => false,
'type_options' => array('delete' => true)
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position',
));
}
}
And also do't forget to do mapping 'one to many' or 'many to many' mapping between 'AttachmentsCollection' and 'Attachments' supposing that one 'AttachmentsCollection' has many 'Attachments' object ..
Looks like what you need to do is pass in an admin_code which is the name of the admin section (mercury.cargo_recognition.admin.attachment) in the $fieldDescriptionOptions parameter to the add() method.
As old as this issue is, I'll still add something on how this can be resolved to help anyone else who might run into it. The root issue is that the $path targetEntity("Application\Sonata\MediaBundle\Entity\GalleryHasMedia") doesn't have an admin class.
To resolve it, add an admin class for your targetEntity:
class GalleryHasMediaAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('attachment', 'file')
;
}
// other methods
}
Then add that admin class to services.yml
mercury.cargo_recognition.admin.galleryhadmedia:
class: Mercury\CargoRecognitionBundle\Admin\GalleryHasMediaAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: General, label: 'Gallery Has Media' }
arguments: [ null, Mercury\CargoRecognitionBundle\Entity\GalleryHasMedia, "MercuryCargoRecognitionBundle:GalleryHasMediaAdmin" ]
if your admin class for GalleryHasMedia is not yet created and you have not put the service code in your config.yml file then first do that and try again. I had the same issue and got resolved this way.
Five years later, it's worth noting that the "target entity" itself appears to be blank in the error text. We get a set of backticks, rather than an entity name.
(I am working on an old app and getting a similar error right now. I have generated an admin class for my entity and registered it in the correct place, and it looks like the app is having trouble figuring out what my target entity is -- which by default prevents it from finding the related admin class. I'm sort of tearing my hair out over this one and will probably put up a bounty tomorrow on it.)

Categories