I need help with Symfony2 form One to One relation update. I have to entities: User and UserInfo
User entity:
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
/**
* #ORM\OneToOne(targetEntity="UserInfo", mappedBy="user", cascade={"all"})
*/
private $info;
/**
* #ORM\OneToMany(targetEntity="Log", mappedBy="user")
*/
private $logs;
public function __construct()
{
parent::__construct();
$this->logs = new ArrayCollection();
}
/**
* Set info
*
* #param \AppBundle\Entity\UserInfo $info
* #return User
*/
public function setInfo(\AppBundle\Entity\UserInfo $info = null)
{
$this->info = $info;
$info->setUser($this);
return $this;
}
/**
* Get info
*
* #return \AppBundle\Entity\UserInfo
*/
public function getInfo()
{
return $this->info;
}
/**
* Add logs
*
* #param \AppBundle\Entity\Log $logs
* #return User
*/
public function addLog(\AppBundle\Entity\Log $logs)
{
$this->logs[] = $logs;
return $this;
}
/**
* Remove logs
*
* #param \AppBundle\Entity\Log $logs
*/
public function removeLog(\AppBundle\Entity\Log $logs)
{
$this->logs->removeElement($logs);
}
/**
* Get logs
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getLogs()
{
return $this->logs;
}
}
UserInfo entity:
class UserInfo
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="position", type="string", length=255)
*/
private $position;
/**
* #var string
*
* #ORM\Column(name="info", type="text")
*/
private $info;
/**
* #var string
*
* #ORM\Column(name="fullname", type="string", length=255)
*/
private $fullname;
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="info")
*/
private $user;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set position
*
* #param string $position
* #return UserInfo
*/
public function setPosition($position)
{
$this->position = $position;
return $this;
}
/**
* Get position
*
* #return string
*/
public function getPosition()
{
return $this->position;
}
/**
* Set info
*
* #param string $info
* #return UserInfo
*/
public function setInfo($info)
{
$this->info = $info;
return $this;
}
/**
* Get info
*
* #return string
*/
public function getInfo()
{
return $this->info;
}
/**
* Set fullname
*
* #param string $fullname
* #return UserInfo
*/
public function setFullname($fullname)
{
$this->fullname = $fullname;
return $this;
}
/**
* Get fullname
*
* #return string
*/
public function getFullname()
{
return $this->fullname;
}
/**
* Set user
*
* #param \AppBundle\Entity\User $user
* #return UserInfo
*/
public function setUser(\AppBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AppBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
}
These are their types:
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username')
->add('email')
->add('password')
->add('info', new UserInfoType(), [
'by_reference' => false,
])
->add('Submit', 'submit')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\User',
]);
}
public function getName()
{
return 'user';
}
}
and
class UserInfoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('position')
->add('info')
->add('fullname')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\UserInfo',
'allow_delete' => true,
]);
}
public function getName()
{
return 'userinfo';
}
}
New record inserts without any problem, but when I want to update this record with this action:
public function editAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$userRepository = $em->getRepository('AppBundle:User');
$user = $userRepository->findOneBy(['id' => $id]);
$form = $this->createForm(new UserType(), $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_list');
}
return $this->render('#App/User/form.html.twig', [
'form' => $form->createView(),
]);
}
I get this error:
An exception occurred while executing 'INSERT INTO user_info (position, info, fullname, user_id) VALUES (?, ?, ?, ?)' with params ["321", "321", "321", 14]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '14' for key 'UNIQ_B1087D9EA76ED395'
Ok, I understand that he wants to insert new record, but what should I do to make him UPDATE it or DELETE existing one and INSERT new.
Try making User the owning side and UserInfo the inverse one (see docs).
class User extends BaseUser
{
/**
* #ORM\OneToOne(targetEntity="UserInfo", inversedBy="user", cascade={"all"})
*/
private $info;
}
class UserInfo
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="User", mappedBy="info")
*/
private $user;
}
Also related to this SO question.
Edit: To remove old, unreferenced UserInfo records after the update, set the orphanRemoval option in the info property of the User class.
class User extends BaseUser
{
/**
* #ORM\OneToOne(targetEntity="UserInfo", inversedBy="user", cascade={"all"}, orphanRemoval=true)
*/
private $info;
}
You need to use JoinColumn annotation in your User class:
/**
* #ORM\OneToOne(targetEntity="UserInfo", inversedBy="user", cascade={"all"})
* #ORM\JoinColumn(name="info", referencedColumnName="id")
*/
private $info;
UserInfo:
/**
* #ORM\OneToOne(targetEntity="User", mappedBy="info")
*/
private $user;
Related
I have 2 entities, Exercise and Product, they have a One to One relationship (the owning side is Product), and I have an ExerciseFormType and a ProductFormType.
What I want I to be able to create an exercise, and the product associated with it at the same time.
My idea was to add the the builder of exerciseFormType, 'product' and its type would be a ProductFormType. The problem is that the product needs the exercise_id, and the exercise isn't persisted yet so it doesn't have one. Here's what I have so far (it works only for creating a product when the exercise exists).
class ExerciseType extends AbstractType {
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('name')
->add('content')
->add('language')
->add('level')
->add('skillsRequired')
->add('skillsTargetted')
->add('tags')
->add('product', ProductType::class, array(
'required' => false,
'exercise'=> $builder->getData()
)
);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => 'SchoolBundle\Entity\Exercise'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(){
return 'schoolbundle_exercise';
}
class ProductType extends AbstractType {
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('visibility')->add('price', MoneyType::class);
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$product = $event->getData();
$form = $event->getForm();
$field = (!$product || null === $product->getId()) ? 'publicationDate' : 'updateDate';
$form->add($field, DateTimeType::class, array('data' => new \DateTime()));
});
$data = array(
'data' => $options['exercise'],
'class' => Exercise::class,
'choice_label' => 'getName'
);
$builder->add('exercise', EntityType::class, $data);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => 'MarketBundle\Entity\Product'
));
$resolver->setRequired(array(
'exercise'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(){
return 'marketbundle_product';
}
}
In exercise I have that
<?php
/**
* exercise
*
* #ORM\Table(name="exercise")
* #ORM\Entity(repositoryClass="SchoolBundle\Repository\ExerciseRepository")
*/
class Exercise {
/**
* #var int
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
* #ORM\Column(name="content", type="string", length=255)
*/
private $content;
/**
* #var string
* #ORM\Column(name="language", type="string", length=255)
*/
private $language;
/**
* #var int
* #ORM\Column(name="level", type="integer")
*/
private $level;
/**
* #var string
* #ORM\Column(name="skills_required", type="string", length=255)
*/
private $skillsRequired;
/**
* #var string
* #ORM\Column(name="skills_targetted", type="string", length=255)
*/
private $skillsTargetted;
/**
* #var string
* #ORM\Column(name="tags", type="string", length=255)
*/
private $tags;
/**
* #ORM\OneToMany(targetEntity="Session", mappedBy="exercise")
*/
private $sessions;
/**
* #ORM\OneToMany(targetEntity="ExerciseIO", mappedBy="exercise")
*/
private $exerciseIOs;
/**
* #ORM\OneToOne(targetEntity="MarketBundle\Entity\Product", mappedBy="exercise", cascade={"persist"}))
*/
private $product;
/**
* #ORM\ManyToOne(targetEntity="Professor", inversedBy="createdExercises")
* #ORM\JoinColumn(name="creator_id", referencedColumnName="id", nullable=false)
*/
private $creator;
/**
* #ORM\ManyToMany(targetEntity="Professor", mappedBy="boughtExercises")
*/
private $owners;
public function __construct(){
$this->sessions = new ArrayCollection();
$this->exerciseIOs = new ArrayCollection();
$this->owners = new ArrayCollection();
}
/**
* Get creator
* #return Professor
*/
public function getCreator(){
return $this->creator;
}
/**
* Set creator
* #param Professor $creator
* #return Exercise
*/
public function setCreator($creator){
$this->creator = $creator;
return $this;
}
/**
* Get owner
* #return ArrayCollection
*/
public function getOwners(){
return $this->owners;
}
/**
* Get product
* #return Product
*/
public function getProduct(){
return $this->product;
}
/**
* #param Product $product
* #return Exercise
*/
public function setProduct($product){
$this->product = $product;
return $this;
}
/**
* Get exerciseIOs
* #return ArrayCollection
*/
public function getExerciseIOs(){
return $this->exerciseIOs;
}
/**
* Get sessions
* #return ArrayCollection
*/
public function getSessions(){
return $this->sessions;
}
/**
* Get id
* #return int
*/
public function getId(){
return $this->id;
}
/**
* Set name
* #param string $name
* #return Exercise
*/
public function setName($name){
$this->name = $name;
return $this;
}
/**
* Get name
* #return string
*/
public function getName(){
return $this->name;
}
/**
* Set content
* #param string $content
* #return Exercise
*/
public function setContent($content){
$this->content = $content;
return $this;
}
/**
* Get content
* #return string
*/
public function getContent(){
return $this->content;
}
/**
* Set language
* #param string $language
* #return Exercise
*/
public function setLanguage($language){
$this->language = $language;
return $this;
}
/**
* Get language
* #return string
*/
public function getLanguage(){
return $this->language;
}
/**
* Set level
* #param string $level
* #return Exercise
*/
public function setLevel($level){
$this->level = $level;
return $this;
}
/**
* Get level
* #return string
*/
public function getLevel(){
return $this->level;
}
/**
* Set skillsRequired
* #param string $skillsRequired
* #return Exercise
*/
public function setSkillsRequired($skillsRequired){
$this->skillsRequired = $skillsRequired;
return $this;
}
/**
* Get skillsRequired
* #return string
*/
public function getSkillsRequired(){
return $this->skillsRequired;
}
/**
* Set skillsTargetted
* #param string $skillsTargetted
* #return Exercise
*/
public function setSkillsTargetted($skillsTargetted){
$this->skillsTargetted = $skillsTargetted;
return $this;
}
/**
* Get skillsTargetted
* #return string
*/
public function getSkillsTargetted(){
return $this->skillsTargetted;
}
/**
* Set tags
* #param string $tags
* #return Exercise
*/
public function setTags($tags){
$this->tags = $tags;
return $this;
}
/**
* Get tags
* #return string
*/
public function getTags(){
return $this->tags;
}
}
And in Product
/**
* Product
*
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="\MarketBundle\Repository\ProductRepository")
*/
class Product {
/**
* #var int
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var bool
* #ORM\Column(name="visibility", type="boolean")
*/
private $visibility;
/**
* #var float
* #ORM\Column(name="price", type="float")
*/
private $price;
/**
* #var \DateTime
* #ORM\Column(name="publication_date", type="datetimetz")
*/
private $publicationDate;
/**
* #var \DateTime
* #ORM\Column(name="update_date", type="datetimetz", nullable=true)
*/
private $updateDate;
/**
* #ORM\OneToMany(targetEntity="ProductComment", mappedBy="product")
*/
private $productComments;
/**
* #ORM\OneToOne(targetEntity="\SchoolBundle\Entity\Exercise", inversedBy="product")
* #ORM\JoinColumn(name="exercise_id", referencedColumnName="id", nullable=false)
*/
private $exercise;
public function __construct(){
$this->productComments = new ArrayCollection();
}
/**
* Get exercise
* #return Exercise
*/
public function getExercise(){
return $this->exercise;
}
/**
* Set exercise
* #param Exercise $exercise
* #return Product
*/
public function setExercise($exercise){
$this->exercise = $exercise;
return $this;
}
/**
* Get productComments
* #return ArrayCollection
*/
public function getProductComments(){
return $this->productComments;
}
/**
* Get id
* #return int
*/
public function getId(){
return $this->id;
}
/**
* Set visibility
* #param boolean $visibility
* #return Product
*/
public function setVisibility($visibility){
$this->visibility = $visibility;
return $this;
}
/**
* Get visibility
* #return bool
*/
public function getVisibility(){
return $this->visibility;
}
/**
* Set price
* #param float $price
* #return Product
*/
public function setPrice($price){
$this->price = $price;
return $this;
}
/**
* Get price
* #return float
*/
public function getPrice(){
return $this->price;
}
/**
* Set publicationDate
* #param \DateTime $publicationDate
* #return Product
*/
public function setPublicationDate($publicationDate){
$this->publicationDate = $publicationDate;
return $this;
}
/**
* Get publicationDate
* #return \DateTime
*/
public function getPublicationDate(){
return $this->publicationDate;
}
/**
* Set updateDate
* #param \DateTime $updateDate
* #return Product
*/
public function setUpdateDate($updateDate){
$this->updateDate = $updateDate;
return $this;
}
/**
* Get updateDate
* #return \DateTime
*/
public function getUpdateDate(){
return $this->updateDate;
}
}
I've said it works for an existing exercise (and no product).
When I try to create both at the same time I get
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
It's probably from the $builder->getData(), because in that case I only passed to the form a "new Exercice()". Here's the controller action
public function newAction(Request $request){
$exercise = new Exercise();
$form = $this->createForm(ExerciseType::class, $exercise);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$exercise->setCreator($this->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($exercise);
$em->flush();
return $this->redirectToRoute('exercise_show', array('id' => $exercise->getId()));
}
(Also this is another question but when I disable a formType, it is rendered, and the value appears but it's not submitted. I would actually prefer a hiddenFormType but I need the formatting of the DateTimeFormType)
Ok, this is the solution I've made once with Symfony2.8, I hope it can helps you.
/**
* #ORM\Entity
* #ORM\Table(name="picture")
*/
class Picture
{
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Host",
* inversedBy="pictureId"
* )
* #ORM\JoinColumn(name="avatar_host_id", referencedColumnName="id", nullable=true)
*/
private $avatarHostId;
}
/**
* #ORM\Entity
* #ORM\Table(name="host")
*/
class Host
{
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Picture",
* mappedBy="avatarHostId", cascade={"persist", "remove", "merge"}
* )
*/
private $pictureId;
}
class HostType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('pictureId', PictureFileType::class);
}
}
class PictureFileType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('assetFile', FileType::class, array(
'label' => 'Picture File',
'required' => false,
'validation_groups' => array('creation')
));
}
}
First, I recommend moving away from using integers as IDs. There are some issues around them, including that you can't really generate one at will in this kind of scenario. I would recommend Uuids along with ramsey/uuid, which also has a Doctrine mapping.
When you've got a situation where you need an ID before it's been persisted and the Uuid generated, generate the Uuid yourself. For instance, in a contrived example
class Order
{
/**
* #var UuidInterface
*
* #ORM\Id
* #ORM\Column(type="uuid")
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\CustomIdGenerator(class=UuidGenerator::class)
*/
private $id;
...
/**
* Constructor.
*
* #param UuidInterface $id
*/
public function __construct(?UuidInterface $id = null)
{
$this->id = $id ?? Uuid::uuid4();
}
...
}
class OrderController
{
...
public function orderProductAction(): JsonResponse
{
...
// We need this ahead of time, because
// maybe this is Async and we need to
// return the order id. This happens a
// lot with commands.
$generatedId = Uuid::uuid4();
// Here it's going to use the given ID,
// if not given, the Order class will
// generate it.
$order = new Order($generatedId, ...);
// Stuff happens, persisted... maybe we
// don't have the persisted Order object...
return $this->json([
'order' => [
'id' => $generatedId->toString(),
],
]);
}
...
}
The meat of it is providing the generated Uuid in the constructor (which alternately generates it if null). Do not add a setter. Here's a more involved example:
public function createAction(Request $request): JsonResponse
{
$request_data = \json_decode($request->getContent(), true);
$tenant_data = $request_data['data'];
// Pre-generate our Uuid for the Tenant.
$generated_id = Uuid::uuid4();
/** #var CreateTenant $create_tenant_cmd */
$create_tenant_cmd = new CreateTenant($generated_id);
$create_tenant_cmd->setName($tenant_data['name']);
$create_tenant_cmd->setDomainName($tenant_data['domain_name']);
$create_tenant_cmd->setOwnerUsername($tenant_data['owner_username']);
$create_tenant_cmd->setOwnerPassword($tenant_data['owner_password']);
$create_tenant_cmd->setOwnerFirstName($tenant_data['owner_first_name']);
$create_tenant_cmd->setOwnerLastName($tenant_data['owner_last_name']);
$create_tenant_cmd->setOwnerEmail($tenant_data['owner_email']);
if (!$this->isGranted('perform', $create_tenant_cmd)) {
throw new AccessDeniedException('Access denied to create tenant.');
}
// Here, we should expect NO side-effects, the command
// can't return anything. So no Tenant object with
// generated Uuid...
$this->get('command_bus')->handle($create_tenant_cmd);
/* #var Serializer $serializer */
$serializer = $this->get('jms_serializer');
$serializer_context = SerializationContext::create()->setGroups([
'tenant_meta',
]);
$tenant = $this->get('app.repository.tenant')->find($generated_id);
return $this->json(\json_decode($serializer->serialize(
$tenant,
'json',
$serializer_context
)));
}
That's the ID question; the second part of your question is now easily resolved, that being giving the Uuid to the FormType instead:
$form = $this->createForm(OrderProductType::class, $product, [
'product' => $product,
'generatedId' => $generatedId,
]);
class OrderProductType extends AbstractType implements DataMapperInterface
{
/** #var UuidInterface */
protected $generatedId;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->generatedId = $options['generatedId'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'data_class' => OrderProduct::class,
])
->setRequired(['generatedId'])
;
}
public function mapFormsToData($forms, &$data)
{
$forms = iterator_to_array($forms);
$data = new OrderProduct($this->generatedId);
...
}
}
Of course, if you need it as a field, use it with the field type of your choice instead of storing it as a variable, and then get it from that field:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product_id', HiddenType::class, [
'product_id' => $options['generatedId']->toString(),
])
...
;
}
public function mapFormsToData($forms, &$data)
{
$forms = iterator_to_array($forms);
// Note use of Uuid::fromString().
$data = new OrderProduct(Uuid::fromString(
$forms['productId']->getData()
));
...
}
This is one of the downsides of not delegating the process of interaction to a delegate object like a command, instead of generating an entity; you're stuck constructing your object before you need it, in whole, or perverting the design to make it fit. It also makes working with assertions harder as well (you only get one set, the entity's).
I'm trying to add entries to a MySQL database by using a REST endpoint in a Symfony 3.1 app (and PHP 7.1).
I have two entities: Role and Permission, in a many to many relationship.
/**
* Role
*
* #ORM\Table(name="role")
* #ORM\Entity(repositoryClass="DruideBundle\Entity\Repository\RoleRepository")
*
*/
class Role
{
/**
* #var string
* #ORM\Column(name="titre", type="string", length=100, nullable=false)
*/
private $titre = '';
/**
* #var integer
*
* #ORM\Column(name="id_role", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idRole;
/**
* #var \Doctrine\Common\Collections\Collection
* #Type("array<DruideBundle\Entity\Permission>")
* #ORM\ManyToMany(targetEntity="DruideBundle\Entity\Permission", mappedBy="idRole", cascade={"persist", "remove"})
*/
private $idPermission;
/**
* #return string
*/
public function getTitre() {
return $this->titre;
}
/**
* #param string $titre
*/
public function metsTitre($titre) {
$this->titre = $titre;
}
/**
* #param string $titre
*/
public function setTitre($titre) {
$this->titre = $titre;
}
public function getId() {
return $this->idRole;
}
public function addIdPermission($permission) {
$this->idPermission->add($permission);
}
public function removeIdPermission($permission) {
$this->idPermission->remove($permission);
}
public function setIdPermission($permission) {
$this->idPermission = $permission;
}
public function getIdPermission() {
return $this->idPermission;
}
/**
* Constructor
*/
public function __construct()
{
$this->idPermission = new \Doctrine\Common\Collections\ArrayCollection();
}
}
/**
* Permission
*
* #ORM\Table(name="permission", uniqueConstraints={#ORM\UniqueConstraint(name="valeur", columns={"cle"})})
* #ORM\Entity(repositoryClass="DruideBundle\Entity\Repository\PermissionRepository")
*/
class Permission
{
/**
* #var string
*
* #ORM\Column(name="cle", type="string", length=100, nullable=true)
*/
private $cle;
/**
* #return string
*/
public function getCle() {
return $this->cle;
}
/**
* #param string $cle
*/
public function metsCle($cle) {
$this->cle = $cle;
}
/**
* #param string $cle
*/
public function setCle($cle) {
$this->cle = $cle;
}
/**
* #return string
*/
public function getDescription() {
return $this->description;
}
/**
* #param string $description
*/
public function metsDescription($description) {
$this->description = $description;
}
/**
* #param string $description
*/
public function setDescription($description) {
$this->description = $description;
}
public function getId() {
return $this->idPermission;
}
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=255, nullable=true)
*/
private $description;
/**
* #var integer
*
* #ORM\Column(name="id_permission", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idPermission;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="DruideBundle\Entity\Role", inversedBy="idPermission")
* #ORM\JoinTable(name="role_permission",
* joinColumns={
* #ORM\JoinColumn(name="id_permission", referencedColumnName="id_permission")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="id_role", referencedColumnName="id_role")
* }
* )
*/
private $idRole;
/**
* Constructor
*/
public function __construct()
{
$this->idRole = new \Doctrine\Common\Collections\ArrayCollection();
}
}
class RoleType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('titre', TextType::class)->
add('idPermission', CollectionType::class, array('entry_type' => PermissionType::class));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'DruideBundle\Entity\Role', 'allow_extra_fields' => true
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'druidebundle_role';
}
}
class RoleController extends FOSRestController implements ClassResourceInterface
{
public function postAction(Request $request)
{
$form = $this->createForm(RoleType::class, null, [
'csrf_protection' => false,
]);
$form->submit($request->request->all());
if (!$form->isValid()) {
return View::create($form->getErrors(true), Response::HTTP_BAD_REQUEST);
}
/**
* #var $role Role
*/
$role = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($role);
$em->flush();
$routeOptions = [
'id' => $role->getId(),
'_format' => $request->get('_format'),
];
$reponse = $this->routeRedirectView('get_roles', $routeOptions, Response::HTTP_CREATED);
return $this->handleView($reponse);
}
Now, if I send this JSON to create a new role:
{ "titre": "Test Pascal", "permissions": [ { "id": 1 }, { "id": 3 } ] }
I would expect it to create a new Role, and make links to the two existing permissions. Sadly, Doctrine is only creating the Role entity:
[2017-12-04 21:02:08] doctrine.DEBUG: "START TRANSACTION" [] []
[2017-12-04 21:02:08] doctrine.DEBUG: INSERT INTO role (titre) VALUES (?) {"1":"Test Pascal"} []
[2017-12-04 21:02:08] doctrine.DEBUG: "COMMIT" [] []
What is missing?
I have an Employee class which has a OneToMany relation to the PhoneNumber class, and I'm using form builders, and using prototypes to embed multiple phone numbers into the New Employee form, with javascript.
From dumping my employee variable, I see that each submitted PhoneNumber is represented as an array, when I suppose it should be converted to a PhoneNumber object when the submitted data is processed.
My entitites are:
/**
* Employee
*
* #ORM\Table(uniqueConstraints={#UniqueConstraint(name="employee_username_idx", columns={"username"})})
* #ORM\Entity(repositoryClass="Acme\BambiBundle\Entity\EmployeeRepository")
*/
class Employee
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var array
*
* #OneToMany(targetEntity="PhoneNumber", mappedBy="employee", cascade={"persist","remove"}, fetch="EAGER")
**/
private $phoneNumbers;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Constructor
*/
public function __construct()
{
$this->phoneNumbers = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add phoneNumbers
*
* #param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
* #return Employee
*/
public function addPhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
{
$phoneNumbers->setEmployee($this);
$this->phoneNumbers[] = $phoneNumbers;
return $this;
}
/**
* Remove phoneNumbers
*
* #param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
*/
public function removePhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
{
$this->phoneNumbers->removeElement($phoneNumbers);
}
/**
* Get phoneNumbers
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPhoneNumbers()
{
return $this->phoneNumbers;
}
// ...
}
and
/**
* PhoneNumber
*
* #ORM\Table()
* #ORM\Entity
*/
class PhoneNumber
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="type", type="text", nullable=true)
*/
private $type;
/**
* #var string
*
* #ORM\Column(name="number", type="text")
*/
private $number;
/**
* #var Employee
*
* #ManyToOne(targetEntity="Employee", inversedBy="phoneNumbers")
* #JoinColumn(name="employee_id", referencedColumnName="id", onDelete="CASCADE")
**/
private $employee;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set number
*
* #param string $number
* #return PhoneNumber
*/
public function setNumber($number)
{
$this->number = $number;
return $this;
}
/**
* Get number
*
* #return string
*/
public function getNumber()
{
return $this->number;
}
/**
* Set employee
*
* #param \Acme\BambiBundle\Entity\Employee $employee
* #return PhoneNumber
*/
public function setEmployee(\Acme\BambiBundle\Entity\Employee $employee = null)
{
$this->employee = $employee;
return $this;
}
/**
* Get employee
*
* #return \Acme\BambiBundle\Entity\Employee
*/
public function getEmployee()
{
return $this->employee;
}
/**
* Set type
*
* #param string $type
* #return PhoneNumber
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return string
*/
public function getType()
{
return $this->type;
}
}
My form types are:
class EmployeeType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('phoneNumbers', 'collection', array(
'type' => new PhoneNumberType(),
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype_name' => 'phoneNumberPrototype',
'by_reference' => false,
))
// ...
->add('save', 'submit', array('attr' => array('class' => 'btn btnBlue')));
}
public function getName() {
return 'employee';
}
}
and
class PhoneNumberType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('type', 'text', array('required' => false, 'label' => 'Type (optional)'))
->add('number', 'text');
}
public function getName() {
return 'phoneNumber';
}
}
Are there any things I could try to solve the problem? Is there anything that I am obviously doing wrong?
The solution was in a detail that I didn't know about - setting a data_class in the PhoneNumberType class:
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Acme\BambiBundle\Entity\PhoneNumber',
));
}
Without this, the code that processes the data from the submitted form does not know that each phone number should be converted to a PhoneNumber class, and thus they stay as arrays.
Please bear in mind that I am using Symfony 2.6. In Symfony 2.7 the above function is called configureOptions and has a slightly different definition:
public function configureOptions(OptionsResolver $resolver) {
I need to add questionnaire of multiple choice questions to my registration form. The questions and options are in two entities:
<?php
namespace Me\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Question
*
* #ORM\Table(name="question")
* #ORM\Entity(repositoryClass="Me\UserBundle\Entity\QuestionRepository")
*/
class Question
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="questionText", type="text")
*/
private $questionText;
/**
* #var boolean $expanded
*
* #ORM\Column(name="expanded", type="boolean")
*/
private $expanded;
/**
* #var boolean $multiple
*
* #ORM\Column(name="multiple", type="boolean")
*/
private $multiple;
/**
* #var Questionnaire $questionnaire
*
* #ORM\ManyToOne(targetEntity="Questionnaire", inversedBy="questions")
* #ORM\JoinColumn(name="questionnaire", referencedColumnName="id", onDelete="cascade")
*/
private $questionnaire;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $options
*
* #ORM\OneToMany(targetEntity="Option", mappedBy="question", cascade={"all"})
*/
private $options;
public function __construct()
{
$this->expanded = false;
$this->multiple = false;
$this->options = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set questionText
*
* #param string $questionText
* #return Question
*/
public function setQuestionText($questionText)
{
$this->questionText = $questionText;
return $this;
}
/**
* Get questionText
*
* #return string
*/
public function getQuestionText()
{
return $this->questionText;
}
/**
* #param mixed $options
*/
public function setOptions($options)
{
$this->options[] = $options;
return $this;
}
/**
* #return mixed
*/
public function getOptions()
{
return $this->options;
}
function __toString()
{
return $this->getQuestionText();
}
/**
* #param boolean $expanded
*/
public function setExpanded($expanded)
{
$this->expanded = $expanded;
}
/**
* #return boolean
*/
public function getExpanded()
{
return $this->expanded;
}
/**
* #param boolean $multiple
*/
public function setMultiple($multiple)
{
$this->multiple = $multiple;
}
/**
* #return boolean
*/
public function getMultiple()
{
return $this->multiple;
}
/**
* #param \Me\UserBundle\Entity\Questionnaire $questionnaire
*/
public function setQuestionnaire($questionnaire)
{
$this->questionnaire = $questionnaire;
}
/**
* #return \Me\UserBundle\Entity\Questionnaire
*/
public function getQuestionnaire()
{
return $this->questionnaire;
}
}
and
<?php
namespace Me\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* QuestionOption
*
* #ORM\Table(name="option")
* #ORM\Entity(repositoryClass="Me\UserBundle\Entity\OptionRepository")
*/
class Option
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="questionId", type="integer")
*/
private $questionId;
/**
* #var string
*
* #ORM\Column(name="optionText", type="string", length=255)
*/
private $optionText;
/**
* #ORM\ManyToOne(targetEntity="Question", inversedBy="options")
* #ORM\JoinColumn(name="questionId", referencedColumnName="id", onDelete="cascade")
**/
private $question;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set optionText
*
* #param string $optionText
* #return Option
*/
public function setOptionText($optionText)
{
$this->optionText = $optionText;
return $this;
}
/**
* Get optionText
*
* #return string
*/
public function getOptionText()
{
return $this->optionText;
}
/**
* #return mixed
*/
public function getQuestion()
{
return $this->question;
}
/**
* #param mixed $question
*/
public function setQuestion($question)
{
$this->question = $question;
}
/**
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
function __toString()
{
return $this->getOptionText();
}
}
I also have a questionnaire entity, though I don't think I really need it because users won't be creating questionnaires, only filling the single questionnaire during registration.
My user entity:
<?php
namespace Me\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="Me\UserBundle\Entity\UserRepository")
*/
class User
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="firstName", type="string", length=50)
*/
private $firstName;
/**
* #var string
*
* #ORM\Column(name="middleInitial", type="string", length=50)
*/
private $middleInitial;
/**
* #var string
*
* #ORM\Column(name="lastName", type="string", length=50)
*/
private $lastName;
/**
* #var string
*
* #ORM\Column(name="homePhoneArea", type="string", length=3)
*/
private $homePhoneArea;
/**
* #var string
*
* #ORM\Column(name="homePhoneNumber", type="string", length=7)
*/
private $homePhoneNumber;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=50)
*/
private $email;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*/
public $questions;
public function __construct()
{
$this->questions = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set firstName
*
* #param string $firstName
* #return User
*/
public function setFirstName($firstName)
{
$this->firstName = $firstName;
return $this;
}
/**
* Get firstName
*
* #return string
*/
public function getFirstName()
{
return $this->firstName;
}
/**
* Set middleInitial
*
* #param string $middleInitial
* #return User
*/
public function setMiddleInitial($middleInitial)
{
$this->middleInitial = $middleInitial;
return $this;
}
/**
* Get middleInitial
*
* #return string
*/
public function getMiddleInitial()
{
return $this->middleInitial;
}
/**
* Set lastName
*
* #param string $lastName
* #return User
*/
public function setLastName($lastName)
{
$this->lastName = $lastName;
return $this;
}
/**
* Get lastName
*
* #return string
*/
public function getLastName()
{
return $this->lastName;
}
/**
* Set homePhoneArea
*
* #param string $homePhoneArea
* #return User
*/
public function setHomePhoneArea($homePhoneArea)
{
$this->homePhoneArea = $homePhoneArea;
return $this;
}
/**
* Get homePhoneArea
*
* #return string
*/
public function getHomePhoneArea()
{
return $this->homePhoneArea;
}
/**
* Set homePhoneNumber
*
* #param string $homePhoneNumber
* #return User
*/
public function setHomePhoneNumber($homePhoneNumber)
{
$this->homePhoneNumber = $homePhoneNumber;
return $this;
}
/**
* Get homePhoneNumber
*
* #return string
*/
public function getHomePhoneNumber()
{
return $this->homePhoneNumber;
}
/**
* Set email
*
* #param string $email
* #return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getQuestions()
{
return $this->questions;
}
}
My user controller:
public function newAction()
{
$user = new User();
$em = $this->getDoctrine()->getManager();
$questions = $em->getRepository('MeUserBundle:Question')->findAll();
if (!$questions) {
throw $this->createNotFoundException('Unable to find Questions.');
}
$builder = $this->createFormBuilder();
$optionEntities = array();
foreach ($questions as $question)
{
$options = array();
foreach ($question->getOptions() as $option)
{
$options[$option->getId()] = $option->getOptionText();
$optionEntities[$option->getId()] = $option;
}
$builder->add('question_'. $question->getId(), 'choice', array(
'label' => $question->getQuestionText(),
'expanded' => $question->getExpanded(),
'multiple' => $question->getMultiple(),
'choices' => $options
));
}
$user->getQuestions()->add($questions);
$form = $this->createForm(new MyFormType(), array('User' => $user));
return $this->render('MeUserBundle:User:new.html.twig', array(
'entity' => $user,
'form' => $form->createView(),
));
}
The form type as it stands today:
<?php
namespace Me\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MyFormType extends AbstractType
{
protected $questions;
public function __construct( $questions)
{
$this->questions = $questions;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('questions', 'collection', array(
'type' => new QuestionType()
))
->add('firstName')
->add('middleInitial')
->add('lastName')
->add('homePhoneArea')
->add('homePhoneNumber')
->add('email')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
));
}
public function getName()
{
return 'myform_type';
}
}
This setup doesn't work to get the questions and their associated options, and display them in the same user creation form. I've seen instructions and docs for combining forms, but not creating forms with this kind of configuration. Any guidance would be appreciated.
I'm not sure if I've understood your question correctly but maybe this could help.
From what I see you're building the form(for questions) but you're not using it anywhere! The easiest way is to pass the questions(in your case $user->getQuestions() ) to the MyFormType and the add all the questions inside of the type.
So it would look like something like this
$this->createForm(new MyFormType($user->getQuestions()), array('User' => $user));
And inside your type
protected $questions;
public function __construct($questions)
{
$this->questions = $questions;
}
protected $questions;
public function __construct($questions)
{
$this->questions = $questions;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
foreach ($this->questions as $question)
{
$options = array();
foreach ($question->getOptions() as $option)
{
$options[$option->getId()] = $option->getOptionText();
$optionEntities[$option->getId()] = $option;
}
$builder->add('question_'. $question->getId(), 'choice', array(
'label' => $question->getQuestionText(),
'expanded' => $question->getExpanded(),
'multiple' => $question->getMultiple(),
'choices' => $options
));
}
}
Edit 1
Why don't you try the following?
Add the method setQuestionnaire in User and create a type called QuestionnaireType which is responsible to create the whole questionnaire
In the UserType(sorry for the wrong names) add the QuestionnaireType as an embedded form
Once the user submits the data and you call the bind symfony will pass the whole questionnaire object to the created method so you can iterate over it and save the user's aswers!
Your users entity needs a relation to his $answers you should store in an $answers-field in your user entity, (look up "embedding collections")
Then in your controller that digests the form your store the values by $user->setAnswers(value)) and then you'll find the answers values in the users entity's $answers field ($user->getAnswers()).
ANd dont forget to add your getters and setters.
$php app/console doctrine:generate:entities BundleName:Entityname
At first you could add a setQuestions method in user, this method will receive an ArrayCollection.
Then have you got a look at http://symfony.com/doc/current/reference/forms/types/collection.html ?
And maybe you could ask yourself what does this form should display/do
Does it need to embbed a collection or a list of QuestionFormType could be ok?
Each time i have to do embedded form type, i draw sketches and activity diagram for being sure to not dive into a to complex form structure
I'm making the user edit.
I want to view selected role of the current user by Users.role_id = UsersRole.id
The table Users has four columns (id,username,roleId,descriptions)
The table UsersRole has two columns (id,name)
Controller:
public function editAction($id) {
$user = $this->getDoctrine()
->getEntityManager()
->getRepository('TruckingMainBundle:Users')
->find($id);
if (!$user) {
throw $this->createNotFoundException('Unable to find user id.');
}
$form = $this->createForm(new \Trucking\AdminBundle\Form\UserType(), $user);
$request = $this->getRequest();
//save data
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($user);
$em->flush();
return $this->redirect($this->generateUrl('tracking_admin_users'));
}
}
return $this->render('TruckingAdminBundle:user:edit.html.twig', array(
'id' => $id,
'form' => $form->createView()
)
);
}
UserType.php
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('roleId', 'entity', array(
'class' => 'TruckingMainBundle:UsersRole',
'property' => 'name'
))
->...->..
}
I don't know how to set selected (default) value in that list, I've been trying to do it for 5 hours ,but still no results I've used preferred_choices, query_builder -> where I can select by critreia(but i don't need that)
http://symfony.com/doc/current/reference/forms/types/entity.html
I can print my current user id -> print_r($user->getRoleId()); I already have it.
My 'Users' entity has connection with UserRole entity
Users entity
namespace Trucking\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Trucking\MainBundle\Entity\Users
*
* #ORM\Table(name="Users")
* #ORM\Entity
*/
class Users implements UserInterface
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string $password
*
* #ORM\Column(name="password", type="string", length=15)
*/
private $password;
/**
* #var string $username
*
* #ORM\Column(name="username", type="string", length=30)
*/
private $username;
/**
* #var string $description
*
* #ORM\Column(name="description", type="string", length=20)
*/
private $description;
/**
* #var string $permissions
*
* #ORM\Column(name="permissions", type="string", length=300)
*/
private $permissions;
/**
* #var \DateTime $date
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var integer $role_id
*
* #ORM\Column(name="role_id", type="integer")
*/
private $role_id;
/**
* #var integer $company_id
*
* #ORM\Column(name="company_id", type="integer")
*/
private $company_id;
/**
* #ORM\ManyToMany(targetEntity="Company", inversedBy="users")
*
*/
protected $companies;
/**
* #ORM\OneToOne(targetEntity="UsersRole")
* #ORM\JoinColumn(name="role_id", referencedColumnName="id")
*/
protected $roles;
public function __construct() {
$this->companies = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set password
*
* #param string $password
* #return Users
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set username
*
* #param string $username
* #return Users
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set description
*
* #param string $description
* #return Users
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set permissions
*
* #param string $permissions
* #return Users
*/
public function setPermissions($permissions)
{
$this->permissions = $permissions;
return $this;
}
/**
* Get permissions
*
* #return string
*/
public function getPermissions()
{
return $this->permissions;
}
/**
* Set date
*
* #param \DateTime $date
* #return Users
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* #return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set role_id
*
* #param integer $role
* #return Users
*/
public function setRoleId($role_id)
{
$this->roleId = $role_id;
return $this;
}
/**
* Get role_id
*
* #return integer
*/
public function getRoleId()
{
return $this->role_id;
}
/**
* Set company_id
*
* #param Company $company_id
* #return Users
*/
public function setCompany(Company $company_id)
{
$this->company = $company_id;
return $this;
}
/**
* Get company_id
*
* #return integer
*/
public function getCompanyId()
{
return $this->company_id;
}
public function equals(UserInterface $user) {
return $this->getUsername() == $user->getUsername();
}
public function eraseCredentials() {
}
public function getRoles() {
return (array)$this->roles->getName();
}
public function setRoles($role) {
$this->roles = array($role);
}
public function getSalt() {
}
}
UsersRole entity
namespace Trucking\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* USERS_ROLE
*
* #ORM\Table(name="USERS_ROLE")
* #ORM\Entity
*/
class UsersRole
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=30)
*/
protected $name;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=200)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return USERS_ROLE
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* #param string $description
* #return USERS_ROLE
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
UserType (for form)
<?php
namespace Trucking\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints;
class UserType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add("username","text",array(
"label" => "Name",
'attr' => array(
'class' => 'input-xlarge',
),
'constraints' => new Constraints\Length(array('min' => 3))
))
->add('roleId', 'entity', array(
'class' => 'TruckingMainBundle:UsersRole',
"label" => "Roles",
'property' => 'name'
))
->add("description","text",array(
"label" => "Description",
'attr' => array(
'class' => 'input-xlarge'
),
'constraints' => new Constraints\NotBlank()
));
}
public function getName()
{
return 'trucing_adminbundle_usertype';
}
}
Set the property on your entity before you render the form:
if (!$user) {
throw $this->createNotFoundException('Unable to find user id.');
}
//THIS IS NEW
$theRole = getRoleEntityFromSomewhereItMakesSense();
$user->setRole($theRole); //Pass the role object, not the role's ID
$form = $this->createForm(new \Trucking\AdminBundle\Form\UserType(), $user);
$request = $this->getRequest();
When you generate a form, it gets automatically populated with the properties of the entity you are using.
EDIT
Change
->add('roleId', 'entity', array(
to
->add('roles', 'entity', array(
I don't get why you have roleId and roles at the same time.
Also change the following, since roles is a single element, not an array (you have a relation one-to-one on it, and should be one-to-many and reversed as many-to-one, but I guess it will also work)
public function getRoles() {
return $this->roles;
}
public function setRoles($role) {
$this->roles = $role;
}
There has been a problem with ORM JOINS. id to role_id
I've changed the mapping from One-To-One Bidirectional
to One-To-One, Unidirectional with Join Table.
Full code:
Users.php
<?php
namespace Trucking\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Trucking\MainBundle\Entity\Users
*
* #ORM\Table(name="Users")
* #ORM\Entity
*/
class Users implements UserInterface
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string $password
*
* #ORM\Column(name="password", type="string", length=15)
*/
protected $password;
/**
* #var string $username
*
* #ORM\Column(name="username", type="string", length=30)
*/
protected $username;
/**
* #var string $description
*
* #ORM\Column(name="description", type="string", length=20)
*/
protected $description;
/**
* #var string $permissions
*
* #ORM\Column(name="permissions", type="string", length=300)
*/
protected $permissions;
/**
* #var integer $company_id
*
* #ORM\Column(name="company_id", type="integer")
*/
protected $company_id;
/**
* #var integer $role_id
*
* #ORM\Column(name="role_id", type="integer")
*/
protected $role_id;
/**
* #ORM\OneToOne(targetEntity="Company")
* #ORM\JoinColumn( name="company_id", referencedColumnName="id" )
*/
protected $companies;
/**
* #ORM\OneToOne(targetEntity="UsersRole")
* #ORM\JoinColumn( name="role_id", referencedColumnName="id" )
*/
protected $listRoles;
public function __construct() {
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set password
*
* #param string $password
* #return Users
*/
public function setPassword($password)
{
$this->password = sha1($password);
return $this;
}
/**
* Get password
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set username
*
* #param string $username
* #return Users
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set description
*
* #param string $description
* #return Users
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set permissions
*
* #param string $permissions
* #return Users
*/
public function setPermissions($permissions)
{
$this->permissions = $permissions;
return $this;
}
/**
* Get permissions
*
* #return string
*/
public function getPermissions()
{
return $this->permissions;
}
/**
* Set company_id
*
* #param Company $company_id
* #return Users
*/
public function setCompanyId($company_id)
{
$this->company_id = $company_id;
return $this;
}
/**
* Get company_id
*
* #return integer
*/
public function getCompanyId()
{
return $this->company_id;
}
public function equals(UserInterface $user) {
return $this->getUsername() == $user->getUsername();
}
public function eraseCredentials() {
}
/**
* Get roles
*
* #return String
*/
public function getRoles() {
$roles = $this->getListRoles();
return (array)$roles->getName();
}
/**
* Get roles
*
* #return \UsersRole
*/
public function getListRoles()
{
return $this->listRoles;
}
/**
* Set roles
*
* #param \UsersRole
* #return Users
*/
public function setListRoles($roles)
{
$this->listRoles = $roles;
return $this;
}
/**
* Set role_id
*
* #param integer
* #return Users
*/
public function setRoleID($roleId) {
$this->role_id = $roleId;
return $this;
}
public function getSalt() {
}
/**
* Get company
*
* #return Company
*/
public function getCompanies()
{
return $this->companies;
}
/**
* Set company
*
* #param Company $company
* #return Users
*/
public function setCompanies($company)
{
$this->companies = $company;
return $this;
}
}
UsersRole.php
<?php
namespace Trucking\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* USERS_ROLE
*
* #ORM\Table(name="USERS_ROLE")
* #ORM\Entity
*/
class UsersRole
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=30)
*/
protected $name;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=200)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return USERS_ROLE
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* #param string $description
* #return USERS_ROLE
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
The controller hasn't been changed
public function editAction($id) {
$user = $this->getDoctrine()
->getEntityManager()
->getRepository('TruckingMainBundle:Users')
->find($id);
if (!$user) {
throw $this->createNotFoundException('Unable to find user id.');
}
$form = $this->createForm(new \Trucking\AdminBundle\Form\UserType(), $user);
$request = $this->getRequest();
//save data
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($user);
$em->flush();
return $this->redirect($this->generateUrl('tracking_admin_users'));
}
}
return $this->render('TruckingAdminBundle:user:edit.html.twig', array(
'id' => $id,
'form' => $form->createView()
)
);
}
UserType.php
<?php
namespace Trucking\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints;
class UserType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add("username","text",array(
"label" => "Name",
'attr' => array(
'class' => 'input-xlarge',
),
'constraints' => new Constraints\Length(array('min' => 3))
))
->add("password","password",array(
"label" => "Password",
'attr' => array(
'class' => 'input-xlarge',
),
'constraints' => new Constraints\Length(array('min' => 3))
))
->add("listRoles","entity",array(
'label' => 'Roles',
'class' => 'TruckingMainBundle:UsersRole' ,
'property' => 'name'
))
->add("companies","entity",array(
'label' => 'Companies',
'class' => 'TruckingMainBundle:Company' ,
'property' => 'name'
))
->add("description","text",array(
"label" => "Description",
'attr' => array(
'class' => 'input-xlarge'
),
'constraints' => new Constraints\NotBlank()
));
}
public function getName()
{
return 'trucking_adminbundle_usertype';
}
}