Getting the values of one-to-many relationships in the parent entity? - doctrine-orm

So I have a Doctrine 2 ORM entity, Trust, with several one-to-many relationships. I can't work out how to populate the arrays for these.
class Trust implements \JsonSerializable {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="TrustPurpose", mappedBy="trust")
*/
private $purpose;
public function __construct() {
}
public function jsonSerialize() {
return [
'id' => $this->id,
'name' => $this->name,
[...]
'purpose' => $this->purpose,
[...]
];
}
}
In my controller, I might use something like the following.
return new JsonResponse($this->entityManager->find(Trust::class, 1));
And get the following output
{
"id" : 1,
"name" : "Some Trust",
"purpose" : {
}
}
I'm struggling to find documentation on how to edit entity Trust to automatically populate my purpose records?
TrustPurpose
class TrustPurpose implements \JsonSerializable {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", nullable=false)
*/
private $purpose;
/**
* #ORM\ManyToOne(targetEntity="Trust", inversedBy="purpose")
* #ORM\JoinColumn(name="trust_id", referencedColumnName="id")
*/
private $trust;
public function __construct() {
}
public function jsonSerialize() {
return [
'id' => $this->id,
'purpose' => $this->purpose,
'trust' => $this->trust,
];
}
}

Related

Embedding Relations In Results

I'm using API-Platform to deliver content via API. I have a Potential relationship between users and participants (not all users will have participants but all participants will have at least one user). My main goal is to embed the relationship's User data in the result set of Participants as that result will be consumed by a data table and it would be more efficient to have that data already present within the result opposed to performing an additional request for the data.
e.g.:
{
"#context": "/api/contexts/Participants",
"#id": "/api/participants",
"#type": "hydra:Collection",
"hydra:member": [
{
"#id": "/api/participants/1",
"#type": "Participants",
"id": 1,
"name": "Jeffrey Jones",
"users": [
{
"#id": "/api/users/1",
"#type": "User",
"name": "Jenny Jones"
},
{
"#id": "/api/users/2",
"#type": "User",
"name": "Jessie Jones"
}
]
}
],
"hydra:totalItems": 1
}
However, I'm not sure if this is possible. I have looked at https://api-platform.com/docs/core/serialization#embedding-relations but I am not certain it would work for multiple result sets as the example is one book to one author. However, my scenario is one participant to multiple users.
Also (and I may need to go about this in a more direct manner), I'm using a joining table so that I can assign additional metadata to the relationship. So... participants > joint table (containing additional data) > users (and vice versa). Again, I may need to consider having a direct relationship between participants and users and then using a ParticipantUserMeta table to hold the additional metadata. However, at the moment, I'm leaning towards the join table containing the association as well as the additional metadata.
Here are the basics of my entities (most unnecessary data omitted):
User:
/**
* #ApiResource
* ...
*/
class User implements UserInterface, \Serializable
{
/**
* #var int
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var string
* #ORM\Column(type="string")
* #Assert\NotBlank()
*/
private $name = '';
/**
* #ORM\OneToMany(targetEntity="App\Entity\ParticipantRel", mappedBy="user")
*/
private $participants;
public function __construct()
{
$this->participants = new ArrayCollection();
}
public function getId(): int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
/**
* #return Collection|ParticipantRel[]
*/
public function getParticipants(): Collection
{
return $this->participants;
}
}
ParticipantRel:
/**
* #ApiResource
* ...
*/
class ParticipantRel
{
/**
* #var int The Participant Id
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var int
*
* #ORM\Column(type="boolean")
*/
private $primary_contact;
/**
* #var string Relationship notes
*
* #ORM\Column(type="text", nullable=true)
*/
private $notes;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Participants", inversedBy="users")
* #ORM\JoinColumn(nullable=false)
*/
private $participant;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="participants")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
public function getId (): int
{
return $this->id;
}
public function getPrimaryContact(): ?bool
{
return $this->primary_contact;
}
public function getNotes(): ?string
{
return $this->notes;
}
public function getParticipant(): ?Participants
{
return $this->participant;
}
public function getUser(): ?User
{
return $this->user;
}
}
Participants
/**
* #ApiResource
* ...
*/
class Participants
{
/**
* #var int The Participant Id
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var string Participant's first name
*
* #ORM\Column(name="name")
* #Assert\NotBlank
*/
public $name;
/**
* #ORM\OneToMany(targetEntity="App\Entity\ParticipantRel", mappedBy="participant")
*/
private $users;
public function __construct() {
$this->users = new ArrayCollection();
}
public function getId (): int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
/**
* #return Collection|ParticipantRel[]
*/
public function getUsers(): Collection
{
return $this->users;
}
}
My question: Is what I'm attempting possible within an entity and if so, what am I missing? I have researched this a lot before coming here but haven't come up w/ any solution as most of the solutions I see involve a Twig tpl but I'm simply sending the data via api-platform. Any positive direction would be greatly appreciated.
So, it turns out that I just needed to experiment more w/ the Groups option (https://api-platform.com/docs/core/serialization#embedding-relations). Associating all related fields w/ the relative groups on all relative enities did end up returning the results in the desired format.

Symfony 3.3 and doctrine 2

I have two entities Article and Image related by a ManytoMany relations using a third entity called ArticlesHaveImages.
I don't use classical ManytoMany relation of Doctrine because I have a third field in ArticlesHaveImages called sequence.
class Article
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
...
/**
* One Article has Many articleHaveImage.
* #ORM\OneToMany(targetEntity="ArticlesHaveImages", mappedBy="article")
*/
private $images;
class Image
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
...
/**
* One Image has Many articleHaveImage.
* #ORM\OneToMany(targetEntity="ArticlesHaveImages", mappedBy="image")
*/
private $articles;
public function __construct() {
$this->articles = new ArrayCollection();
}
class ArticlesHaveImages
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* Many ArticlesHaveImages have One Article.
* #ORM\ManyToOne(targetEntity="Article", inversedBy="images")
* #ORM\JoinColumn(name="article_id", referencedColumnName="id")
*/
private $article;
/**
* Many ArticlesHaveImages have One Image.
* #ORM\ManyToOne(targetEntity="Image", inversedBy="articles")
* #ORM\JoinColumn(name="image_id", referencedColumnName="id")
*/
private $image;
/**
* #var int
*
* #ORM\Column(name="sequence", type="integer")
*/
private $sequence;
How do I create a form out of this ?
I want a multiple select option which all images name.
I tried :
class ArticleType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$images = $options['images'];
$builder
->add('translations', CollectionType::class, array(
'entry_type' => ArticleTranslationType::class,
'entry_options' => array('label' => false)))
->add('images', ChoiceType::class, array(
"required" => false,
"choices" => $images,
'multiple' => true,
But I get :
Could not determine access type for property "images" in class
"AppBundle\Entity\Article".
BIG THANKS !

Doctrine2 ORM OneToMany or ManyToOne not working

I would like to have the relationship between 2 tables, with OneToMany and ManyToOne relationships.
Survey
id
title
Questions:
id
survey_id
So i am looking to list the surveys and their respective questions, so how can i achieve that.
Here is my code,
Survey Entity:
<?php
namespace Survey\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Library\Entity\BaseEntity;
/**
* Description of Survey
*
* #author Mubarak
*/
/**
* #ORM\Entity
* #ORM\Table(name="surveys")
*/
class Survey extends BaseEntity{
public function __construct() {
$this->questions = new ArrayCollection();
}
/**
* #ORM\Column(name="title", type="string")
* #var string
*/
protected $title;
/**
* #ORM\Column(name="description", type="string")
* #var string
*/
protected $description;
/**
* #ORM\OneToMany(targetEntity="Survey\Entity\Questions", mappedBy="surveys")
*/
private $questions;
public function getTitle() {
return $this->title;
}
public function setTitle($title) {
$this->title = $title;
}
public function getDescription() {
return $this->description;
}
public function setDescription($description) {
$this->description = $description;
return $this;
}
public function getQuestions() {
return $this->questions;
}
public function setQuestions(ArrayCollection $questions) {
$this->questions = $questions;
}
public function __toString() {
return __CLASS__ . ": [id: {$this->id}, name: {$this->name}]";
}
}
Below is the Questions Entity:
<?php
namespace Survey\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Library\Entity\BaseEntity;
/**
* Description of Survey Questions
*
* #author Mubarak
*/
/**
* #ORM\Entity
* #ORM\Table(name="survey_questions")
*/
class Questions extends BaseEntity{
/**
* #ORM\Column(name="question", type="string")
* #var string
*/
protected $question;
/**
* #ORM\ManyToOne(targetEntity="Survey\Entity\Survey", inversedBy="questions")
* #ORM\JoinColumn(name="survey_id", referencedColumnName="id")
*/
private $surveys;
public function getQuestion() {
return $this->question;
}
public function setQuestion($question) {
$this->question = $question;
}
public function getSurveys() {
return $this->surveys;
}
public function setSurveys(ArrayCollection $surveys) {
$this->surveys = $surveys;
}
public function __toString() {
return __CLASS__ . ": [id: {$this->id}, name: {$this->name}]";
}
}
What is the mistake i am doing here, this is my code to get the surveys and questions:
$surveysInterface = $this->surveyService->getAllSurveys();
foreach($surveysInterface as $survey){
$surveysArray[] = array(
'id' => $survey->getId(),
'title' => $survey->getTitle(),
'description' => $survey->getDescription(),
'isActive' => $survey->getActive(),
'questions' => array(
'question' => $survey->getQuestions()->getQuestion()
)
);
}
'questions' => array(
'question' => $survey->getQuestions()->getQuestion()
)
This part look wrong since getQuestions() function return array of Questions entities. Suggest to change it to
'questions' => $survey->getQuestions()

ZF2 doctrine OneToMany annotation form

I have following entities:
User
/**
* Users
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="Users\Entity\Repository\UsersRepository")
* #Annotation\Name("user")
* #Annotation\Hydrator("Zend\Stdlib\Hydrator\ClassMethods")
*/
class User
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100, nullable=false)
* #Annotation\Filter({"name":"StringTrim"})
* #Annotation\Validator({"name":"StringLength", "options":{"min":2, "max":100}})
* #Annotation\Attributes({"type":"text","class":"form-control"})
* #Annotation\Options({"label":"Full name:"})
*/
private $name;
/**
* #var User\Entity\UserItem
*
* #ORM\OneToMany(targetEntity="User\Entity\UserItem", mappedBy="user")
* #Annotation\Exclude()
*/
private $items;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Annotation\Exclude()
*/
private $id;
public function __construct()
{
$this->vessels = new ArrayCollection();
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
public function getId()
{
return $this->id;
}
public function getItems()
{
return $this->items
}
public function setItems($items)
{
$this->itemr = $items;
return $this;
}
Item
/**
* Items
* #ORM\Entity
* #ORM\Table(name="items")
* #ORM\Entity(repositoryClass="User\Entity\Repository\ItemsRepository")
* #Annotation\Name("item")
* #Annotation\Hydrator("Zend\Stdlib\Hydrator\ClassMethods")
*/
class Item
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100, nullable=false)
* #Annotation\Filter({"name":"StringTrim"})
* #Annotation\Validator({"name":"StringLength", "options":{"min":2, "max":100}})
* #Annotation\Attributes({"type":"text","class":"form-control"})
* #Annotation\Options({"label":"Name:"})
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Annotation\Exclude()
*/
private $id;
And finally entity keepeing relation between those two
UserItem
/**
* UserItem
*
* #ORM\Table(name="users_items")
* #ORM\Entity(repositoryClass="User\Entity\Repository\UserItemsRepository")
* #Annotation\Name("user_item")
* #Annotation\Hydrator("Zend\Stdlib\Hydrator\ClassMethods")
*/
class UserItem{
/**
* #var Users\Entity\User
*
* #ORM\ManyToOne(targetEntity="Users\Entity\User", inversedBy="items")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* #Annotation\Exclude()
*/
private $user;
/**
* #var User\Entity\Item
*
* #ORM\ManyToOne(targetEntity="User\Entity\Item", inversedBy="users")
* #ORM\JoinColumn(name="item_id", referencedColumnName="id")
* #Annotation\Type("DoctrineModule\Form\Element\ObjectSelect")
*/
private $item;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Annotation\Exclude()
*/
private $id;
With this entities i can create and edit User and Item. Form are generated from annotations.
My question is how can i generate form for assigning items to user. Preferably as select field(s) with multiple selection. And after submitting doctrine should save the relations.
I wrote this form to represent items to select:
class ItemsForm extends Form
{
public function __construct($entityManager, $name = null)
{
parent::__construct('items');
$this->setAttribute('method', 'post');
$this->add(array(
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'name' => 'items',
'attributes' => array(
'id' => 'selectItems',
'multiple' => true,
'data-placeholder' => 'Items'
),
'options' => array(
'object_manager' => $entityManager,
'target_class' => 'User\Entity\Item',
'property' => 'name',
),
)
);
}
}
And now i do not know how to preselect items user has already assigned.
In select field in value you must have id from items. After submit you can do something like that
foreach($post['items'] as $itemId)
{
$userItem = new UserItem();
$userItem->user = $this->getEntityManager()->getReference('User', $userId);
$userItem->item = $this->getEntityManager()->getReference('Item', $itemId);
$this->getEntityManager()->save($userItem);
}

How remove registry from Many To Many relationship - Doctrine 2

I'm trying remove a registry from my database using doctrine 2, but I'm getting the follow error:
Catchable fatal error: Argument 1 passed to Doctrine\ORM\Mapping\DefaultQuoteStrategy::getJoinTableName() must be an array, null given, called in /home/triangulum/www/pedal/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php on line 1020 and defined in /home/triangulum/www/pedal/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php on line 86
I have 3 tables:
grupo = id, name
permissao = id, name
grupo_permissao = grupo_id, permissao_id
My entitys:
Grupo:
<?php
namespace User\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="grupo")
* #ORM\Entity(repositoryClass="User\Entity\GrupoRepository")
*/
class Grupo {
public function __construct($options=null) {
Configurator::configure($this, $options);
$this->permissoes = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var int
*/
protected $id;
/**
* #ORM\Column(type="text")
* #var string
*/
protected $nome;
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Permissao", mappedBy="grupo", cascade={"remove"})
*/
protected $permissoes;
public function getPermissoes()
{
return $this->permissoes;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getNome() {
return $this->nome;
}
public function setNome($nome) {
$this->nome = $nome;
}
public function toArray()
{
return array
(
'id' => $this->getId(),
'nome' => $this->getNome()
);
}
}
?>
Permissao:
<?php
namespace User\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="permissao")
* #ORM\Entity(repositoryClass="User\Entity\PermissaoRepository")
*/
class Permissao {
public function __construct($options=null) {
Configurator::configure($this, $options);
$this->grupos = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var int
*/
protected $id;
/**
* #ORM\Column(type="text")
* #var string
*/
protected $nome;
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Grupo", inversedBy="permissao", cascade={"persist", "remove"})
* #ORM\JoinTable(name="grupo_permissao",
* joinColumns={#ORM\JoinColumn(name="permissao_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="grupo_id", referencedColumnName="id")}
* )
*/
protected $grupos;
public function getGrupos() {
return $this->grupos;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getNome() {
return $this->nome;
}
public function setNome($nome) {
$this->nome = $nome;
}
public function toArray()
{
return array
(
'id' => $this->getId(),
'nome' => $this->getNome()
);
}
}
?>
remove:
public function delete($id)
{
$entity = $this->entityManager->find('User\Entity\Grupo', $id);
if($entity)
{
$this->entityManager->remove($entity);
$this->entityManager->flush();
return $id;
}
}
What am I doing wrong?
I think you have a problem with your mappedBy and inversedBy attributes in the manyToMany annotations. They should match the other entities property name, grupos and permissoes. Try this:
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Permissao", mappedBy="grupos", cascade={"remove"})
*/
protected $permissoes;
/**
* #ORM\ManyToMany(targetEntity="User\Entity\Grupo", inversedBy="permissoes", cascade={"persist", "remove"})
* #ORM\JoinTable(name="grupo_permissao",
* joinColumns={#ORM\JoinColumn(name="permissao_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="grupo_id", referencedColumnName="id")}
* )
*/
protected $grupos;