Set a list of images to an entity with VichUploaderBundle - php

I have an entity "Comment", and a "Comment" could have one or more images associated.
How do i achieve that.
Now i have this(for just one image):
/**
* #Assert\File(
* maxSize="1M",
* mimeTypes={"image/png", "image/jpeg"}
* )
* #Vich\UploadableField(mapping="comment_mapping", fileNameProperty="imageName")
*
* #var File $image
*/
protected $image;
Thanks in advance

You have to create a ManyToOne relationship between your Comment and Image entities.
Read more on associations with doctrine 2 here.
Comment
/**
* #ORM\ManyToOne(targetEntity="Image", inversedBy="comment")
*/
protected $images;
public function __construct()
{
$this->images = new ArrayCollection();
}
public function getImages()
{
return $this->images;
}
public function addImage(ImageInterface $image)
{
if (!$this->images->contains($image)) {
$this->images->add($image);
}
return $this;
}
public function removeImage(ImageInterface $image)
{
$this->images->remove($image);
return $this;
}
public function setImages(Collection $images)
{
$this->images = $images;
}
// ...
Image
protected $comment;
public function getComment()
{
return $this->comment;
}
public function setComment(CommentInterface $comment)
{
$this->comment = $comment;
return $this;
}
// ...
Then add a collection form field to your CommentFormType with "type" of ImageFormType ( to be created ).

Related

How to fix error with multiple upload with Symfony 4 NoSuchPropertyException

I want to add a field for upload many attached files in a form with Symfony 4. I've two Entity, Member and Documents with a One-To-Many relation but I've an error who doesn't mean anything for me.
In my Entity Document I've this :
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Member", inversedBy="document")
*/
private $member;
/**
* #return mixed
*/
public function getFile()
{
return $this->file;
}
/**
* #param mixed $file
*/
public function setFile($file): void
{
$this->file = $file;
}
public function getMember(): ?Member
{
return $this->member;
}
public function setMember(?Member $member): self
{
$this->member = $member;
return $this;
}
In my Member Entity :
/**
* #ORM\Entity(repositoryClass="App\Repository\MemberRepository")
*/
class Member
{
/**
* #ORM\OneToMany(targetEntity="App\Entity\Documents", mappedBy="member", cascade={"persist"}, orphanRemoval=true)
*/
private $document;
public function __construct()
{
$this->years = new ArrayCollection();
$this->document = new ArrayCollection();
$this->atelier = new ArrayCollection();
}
/**
* #return Collection|Documents[]
*/
public function getDocument(): Collection
{
return $this->document;
}
public function addDocument(Documents $document): self
{
if (!$this->document->contains($document)) {
$this->document[] = $document;
$document->setMember($this);
}
return $this;
}
public function removeDocument(Documents $document): self
{
if ($this->document->contains($document)) {
$this->document->removeElement($document);
// set the owning side to null (unless already changed)
if ($document->getMember() === $this) {
$document->setMember(null);
}
}
return $this;
}
}
I've try to dump the value of my form but when I try to send my form, I've this error when I don't understand
Could not determine access type for property "document" in class "App\Entity\Member": The property "document" in class "App\Entity\Member" can be defined with the methods "addDocument()", "removeDocument()" but the new value must be an array or an instance of \Traversable, "App\Entity\Documents" given.

Doctrine2 - No foreign key inserted in the table with relation OneToMany(

I have a problem with doctrine2 with a simple relationship between the two models
Below I have prepared a simple example
/**
* #Entity(repositoryClass="PlayerRepository") #Table(name="players")
*/
class Player {
/**
* #Id #Column(type="integer") #GeneratedValue
*/
protected $id;
/**
* #OneToMany(targetEntity="Wallet", mappedBy="player", cascade={"persist"})
* #var Wallet[]
*/
private $wallets;
public function __construct() {
$this->wallets = new ArrayCollection();
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getWallets() {
return $this->wallets;
}
public function addWallets($wallets) {
$this->wallets[] = $wallets;
}
}
And second class
/**
* #Entity(repositoryClass="WalletRepository") #Table(name="wallets")
*/
class Wallet
{
/**
* #Id #Column(type="integer") #GeneratedValue
*/
protected $id;
/**
* #ManyToOne(targetEntity="Player", inversedBy="wallets")
*/
private $player;
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getPlayer() {
return $this->player;
}
public function setPlayer($player) {
$this->player = $player;
}
}
For the following code execution, I am not able to add Player object relations to Wallet:
player = new Player();
$player->addWallets(new Wallet);
$player->addWallets(new Wallet);
$entityManager->persist($player);
$entityManager->flush();
Maybe it will be better seen in the attached picture:
As far as I know you have to set this on the owning site, in this case Wallet, give it a try:
$player = new Player();
$wallet = new Wallet();
$wallet->setPlayer($player);
$entityManager->persist($player);
$entityManager->persist($wallet);
$entityManager->flush();

Symfony 4 multiple entities in single form

Been trying for hours and hours to get my multi entity form to work, but it really breaks my head and none of the examples I've found work.
I checked the Collection form type documentation and form collections, as well as the Entity form type.
I have a User entity, UserRole entity and a Role entity.
UserRole contains a userID and a roleID. Just a linking table.
The form shows fields to create a User and I want to be able to as well select a new Role for the new user. So I've tried to use the EntityType, a select dropdown shows with all the roles nicely (only if i add the option mapped => false), but doesn't process after form submit.
It's data is not in the $form->getData(), the user gets created, the user_role entry never created.
If I try it without the mapped => false it throws me:
Could not determine access type for property "user_roles" in class "App\Entity\User": The property "user_roles" in class "App\Entity\User" can be defined with the methods "addUserRole()", "removeUserRole()" but the new value must be an array or an instance of \Traversable, "App\Entity\Role" given..
Code:
$form = $this->createFormBuilder(new User)
... //other add entries
->add('user_roles', EntityType::class, array(
'label' => 'Group (role)',
'class' => Role::class,
'choice_label' => 'name',
// 'mapped' => false, // Form works when false, but doesn't save/create UserRole entry
))
->getForm();
$form->handleRequest($request);
Using the CollectionType it's not showing a select dropdown at all.
Code:
$form = $this->createFormBuilder($user)
.... //other add entries
->add('user_roles', CollectionType::class, array(
'entry_type' => ChoiceType::class,
'entry_options' => array(
'choices' => $roleChoices,
),
))
->getForm();
$form->handleRequest($request);
Am I missing something in my Controller's code or do I misunderstand the use of the Form types? I really have no clue what I'm doing wrong.
User Entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use JMS\Serializer\Annotation\Exclude;
/**
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
* #ORM\HasLifecycleCallbacks()
*/
class User implements UserInterface
{
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Exclude
*/
private $apiToken;
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* #ORM\Column(type="json_array")
*/
private $roles = [];
/**
* #ORM\Column(type="string", length=255)
*/
private $first_name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $middle_name;
/**
* #ORM\Column(type="string", length=255)
*/
private $last_name;
/**
* #ORM\Column(type="boolean")
*/
private $enabled;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $blocked_at;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Project", mappedBy="created_by")
*/
private $projects;
/**
* #ORM\OneToMany(targetEntity="App\Entity\UserRole", mappedBy="user", fetch="EAGER")
*/
private $user_roles;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Category", mappedBy="created_by")
*/
private $categories;
/**
* #ORM\OneToMany(targetEntity="App\Entity\ProjectFileIos", mappedBy="created_by")
*/
private $projectFileIos;
/**
* #ORM\OneToMany(targetEntity="App\Entity\ProjectFileAndroid", mappedBy="created_by")
*/
private $projectFileAndroid;
/**
* Generate full name
*/
private $full_name;
/**
* #var string The hashed password
* #ORM\Column(type="string")
* #Exclude
*/
private $password;
/**
* #ORM\OneToMany(targetEntity="App\Entity\ProjectUser", mappedBy="user", fetch="EAGER")
*/
private $projectUsers;
/**
* #ORM\Column(type="datetime")
*/
private $created_at;
/**
* #ORM\Column(type="datetime")
*/
private $updated_at;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="project")
*/
private $created_by;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="project")
* #ORM\JoinColumn(nullable=true)
*/
private $last_updated_by;
public function __construct()
{
$this->user_roles = new ArrayCollection();
$this->user_role = new ArrayCollection();
$this->categories = new ArrayCollection();
$this->projectFileIos = new ArrayCollection();
$this->projectFileAndroid = new ArrayCollection();
$this->projectUsers = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getApiToken(): ?string
{
return $this->apiToken;
}
public function setApiToken(string $apiToken): self
{
$this->apiToken = $apiToken;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getFirstName(): ?string
{
return $this->first_name;
}
public function setFirstName(string $first_name): self
{
$this->first_name = $first_name;
return $this;
}
public function getMiddleName(): ?string
{
return $this->middle_name;
}
public function setMiddleName(string $middle_name): self
{
$this->middle_name = $middle_name;
return $this;
}
public function getLastName(): ?string
{
return $this->last_name;
}
public function setLastName(string $last_name): self
{
$this->last_name = $last_name;
return $this;
}
public function getEnabled(): ?bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): self
{
$this->enabled = $enabled;
return $this;
}
public function getBlockedAt(): ?\DateTimeInterface
{
return $this->blocked_at;
}
public function setBlockedAt(?\DateTimeInterface $blocked_at): self
{
$this->blocked_at = $blocked_at;
return $this;
}
/**
* #return Collection|UserRole[]
*/
public function getUserRoles(): ?Collection
{
return $this->user_roles;
}
public function getUserRole(): ?Collection
{
return $this->user_role;
}
public function addUserRole(UserRole $userRole): self
{
if (!$this->user_role->contains($userRole)) {
$this->user_role[] = $userRole;
$user_role->setUserId($this);
}
return $this;
}
public function removeUserRole(UserRole $userRole): self
{
if ($this->user_role->contains($userRole)) {
$this->user_role->removeElement($userRole);
// set the owning side to null (unless already changed)
if ($user_role->getUserId() === $this) {
$user_role->setUserId(null);
}
}
return $this;
}
/**
* #return Collection|Project[]
*/
public function getProjects(): Collection
{
return $this->projects;
}
public function addProject(Project $project): self
{
if (!$this->project->contains($project)) {
$this->project[] = $project;
$project->setUserId($this);
}
return $this;
}
public function removeProject(Project $project): self
{
if ($this->project->contains($project)) {
$this->project->removeElement($project);
// set the owning side to null (unless already changed)
if ($project->getUserId() === $this) {
$project->setUserId(null);
}
}
return $this;
}
/**
* #return Collection|Category[]
*/
public function getCategories(): Collection
{
return $this->categories;
}
public function addCategory(Category $category): self
{
if (!$this->categories->contains($category)) {
$this->categories[] = $category;
$category->setCreatedBy($this);
}
return $this;
}
public function removeCategory(Category $category): self
{
if ($this->categories->contains($category)) {
$this->categories->removeElement($category);
// set the owning side to null (unless already changed)
if ($category->getCreatedBy() === $this) {
$category->setCreatedBy(null);
}
}
return $this;
}
/**
* #return Collection|ProjectFileIos[]
*/
public function getProjectFileIos(): Collection
{
return $this->projectFileIos;
}
public function addProjectFileIo(ProjectFileIos $projectFileIo): self
{
if (!$this->projectFileIos->contains($projectFileIo)) {
$this->projectFileIos[] = $projectFileIo;
$projectFileIo->setCreatedBy($this);
}
return $this;
}
public function removeProjectFileIo(ProjectFileIos $projectFileIo): self
{
if ($this->projectFileIos->contains($projectFileIo)) {
$this->projectFileIos->removeElement($projectFileIo);
// set the owning side to null (unless already changed)
if ($projectFileIo->getCreatedBy() === $this) {
$projectFileIo->setCreatedBy(null);
}
}
return $this;
}
/**
* #return Collection|ProjectFileAndroid[]
*/
public function getProjectFileAndroid(): Collection
{
return $this->projectFileAndroid;
}
public function addProjectFileAndroid(ProjectFileAndroid $projectFileAndroid): self
{
if (!$this->projectFileAndroid->contains($projectFileAndroid)) {
$this->projectFileAndroid[] = $projectFileAndroid;
$projectFileAndroid->setCreatedBy($this);
}
return $this;
}
public function removeProjectFileAndroid(ProjectFileAndroid $projectFileAndroid): self
{
if ($this->projectFileAndroid->contains($projectFileAndroid)) {
$this->projectFileAndroid->removeElement($projectFileAndroid);
// set the owning side to null (unless already changed)
if ($projectFileAndroid->getCreatedBy() === $this) {
$projectFileAndroid->setCreatedBy(null);
}
}
return $this;
}
public function getFullName()
{
$lastName = $this->middle_name ? $this->middle_name . ' ' : '';
$lastName .= $this->last_name;
return $this->first_name . ' ' . $lastName;
}
/**
* Triggered after entity has been loaded into the current EntityManager from de database
* or after refresh operation applied to it
* #ORM\PostLoad
*/
public function postLoad()
{
$this->full_name = $this->getFullName();
}
/**
* #return Collection|ProjectUser[]
*/
public function getProjectUsers(): Collection
{
return $this->projectUsers;
}
public function addProjectUser(ProjectUser $projectUser): self
{
if (!$this->projectUsers->contains($projectUser)) {
$this->projectUsers[] = $projectUser;
$projectUser->setUser($this);
}
return $this;
}
public function removeProjectUser(ProjectUser $projectUser): self
{
if ($this->projectUsers->contains($projectUser)) {
$this->projectUsers->removeElement($projectUser);
// set the owning side to null (unless already changed)
if ($projectUser->getUser() === $this) {
$projectUser->setUser(null);
}
}
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeInterface $created_at): self
{
$this->created_at = $created_at;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updated_at;
}
public function setUpdatedAt(\DateTimeInterface $updated_at): self
{
$this->updated_at = $updated_at;
return $this;
}
public function getCreatedBy(): ?User
{
return $this->created_by;
}
public function setCreatedBy(?User $created_by): self
{
$this->created_by = $created_by;
return $this;
}
public function getLastUpdatedBy(): ?User
{
return $this->last_updated_by;
}
public function setLastUpdatedBy(?User $last_updated_by): self
{
$this->last_updated_by = $last_updated_by;
return $this;
}
/**
* Triggered on insert
* #ORM\PrePersist
*/
public function onPrePersist()
{
$this->enabled = true;
$this->created_at = new \DateTime("now");
$this->updated_at = new \DateTime();
$this->roles = 'a:1:{i:0;s:9:"ROLE_USER";}';
}
/**
* Triggered on update
* #ORM\PreUpdate
*/
public function onPreUpdate()
{
$this->updated_at = new \DateTime("now");
}
}
In Symfony, to get non-mapped form data, try doing like this.
$data = $form->getData();
$roles = $form->get("user_roles")->getData();
Also, noted one thing. Shouldn't the class be UserRole::class instead of Role::class, in the code block below.
$form = $this->createFormBuilder(new User)
... //other add entries
->add('user_roles', EntityType::class, array(
'label' => 'Group (role)',
'class' => Role::class,
'choice_label' => 'name',
// 'mapped' => false, // Form works when false, but doesn't save/create UserRole entry
))
->getForm();
Hope this helps,
Cheers..
The general way you have chosen is okay. Stick with the EntityType and remove the mapped = false, this would tell Symfony to ignore the field.
I guess the problem is: you have a mixture of $this->user_role and $this->user_roles in your class, probably a renamed variable. Clean this up first in __construct(), addUserRole(), removeUserRole(), getUserRoles(), getUserRole().
Then add a method
public function setUserRoles($userRoles)
{
$this->user_roles = new ArrayCollection();
foreach ($userRoles as $role) {
$this->addUserRole($role);
}
return $this;
}

Doctrine arraycollection keeps being null

Hey Im just trying out doctrine for php alittle and i got an issue with my $matches arraycollection, when i set it in the __construct it works but afterwards its just null and i cant seem to figure out why, the other arraycollections works perfectly
<?php
// src/Player.php
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity #Table(name="teams")
**/
class Team
{
/**
* #Id #Column(type="integer") #GeneratedValue
**/
protected $id;
/**
* #Column(type="string")
**/
protected $name;
/**
* #OneToMany(targetEntity="Player", mappedBy="team")
**/
protected $players;
/**
* #OneToMany(targetEntity="Goal",mappedBy="againstTeam")
**/
protected $goalsAgainst;
/**
* #Column(type="string")
**/
protected $color;
/**
* ManyToMany(targetEntity="Match", mappedBy="teams")
**/
protected $matches;
public function __construct()
{
$this->matches = new ArrayCollection();
$this->players = new ArrayCollection();
$this->goalsAgainst = new ArrayCollection();
}
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
public function getMatches() {
return $this->matches;
}
public function addMatch(Match $match) {
$this->matches->add($match);
}
public function setName($name) {
$this->name = $name;
}
public function setColor($color) {
$this->color = $color;
}
public function addGoalsAgainst(Goal $goal) {
$this->goalsAgainst->add($goal);
$goal->setAgainstTeam($this);
}
public function getJson() {
return array(
'Id'=>$this->id,
'Name'=>$this->name,
'Players'=>null,
'GoalsAgainst'=>null,
'Color'=>$this->color,
'Matches'=>null
);
}
}
?>
if i add an nullcheck to the addMatches(Match $match) like
public function addMatch(Match $match) {
if ($this->matches == null) {
$this->matches = new ArrayCollection();
}
$this->matches->add($match);
}
then the match is added but if i then at next line uses $team->getMatches() then the $matches is null again

Doctrine2 / transfer Collection element to another Collection

Here are 3 entities :
Entity A
class EntityA
{
/**
* #ORM\OneToMany(targetEntity="EntityB", mappedBy="entityA", cascade={"all"}, orphanRemoval=true)
*/
protected $entitiesB;
public function __construct()
{
$this->entitiesB = new ArrayCollection();
}
public function getEntitiesB()
{
return $this->entitiesB;
}
public function setEntitiesB($entitiesB)
{
$this->entitiesB = new ArrayCollection();
return $this->addEntitiesB($entitiesB);
}
public function addEntityB(EntityB $entityB)
{
if (!$this->entitiesB->contains($entityB))
{
$this->entitiesB->add($entityB);
$entityB->setEntityA($this);
}
return $this;
}
public function addEntitiesB($entitiesB)
{
foreach ($entitiesB as $entityB)
{
$this->addEntityB($entityB);
}
return $this;
}
public function removeEntityB(EntityB $entityB)
{
if ($this->entitiesB->contains($entityB))
{
$this->entitiesB->removeElement($entityB);
}
return $this;
}
public function removeEntitiesB($entitiesB)
{
foreach ($entitiesB as $entityB)
{
$this->removeEntityB($entityB);
}
return $this;
}
}
Entity B
class EntityB
{
/**
*
* #ORM\OneToMany(targetEntity="EntityC", mappedBy="entityB", cascade={"all"}, orphanRemoval=true)
*/
protected $entitiesC;
/**
* #ORM\ManyToOne(targetEntity="EntityA", inversedBy="entitiesB")
* #ORM\JoinColumn(name="entity_a_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $entityA;
public function __construct()
{
$this->entitiesC = new ArrayCollection();
}
public function getEntityA()
{
return $this->entityA;
}
public function setEntityA(EntityA $entityA)
{
$this->entityA = $entityA;
$entityA->addEntityB($this);
return $this;
}
public function getEntitiesC()
{
return $this->entitiesC;
}
public function setEntitiesC($entitiesC)
{
$this->entitiesC = new ArrayCollection();
return $this->addEntitiesC($entitiesC);
}
public function addEntityC(EntityC $entityC)
{
if (!$this->entitiesC->contains($entityC))
{
$this->entitiesC->add($entityC);
$entityC->setEntityB($this);
}
return $this;
}
public function addEntitiesC($entitiesC)
{
foreach ($entitiesC as $entityC)
{
$this->addEntityC($entityC);
}
return $this;
}
public function removeEntityC(EntityC $entityC)
{
if ($this->entitiesC->contains($entityC))
{
$this->entitiesC->removeElement($entityC);
}
return $this;
}
public function removeEntitiesC($entitiesC)
{
foreach ($entitiesC as $entityC)
{
$this->removeEntityC($entityC);
}
return $this;
}
}
Entity C
class EntityC
{
/**
* #ORM\ManyToOne(targetEntity="EntityB", inversedBy="entitiesC")
* #ORM\JoinColumn(name="entity_b_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $entityB;
public function getEntityB()
{
return $this->entityB;
}
public function setEntityB(EntityB $entityB)
{
$this->entityB = $entityB;
$entityB->addEntityC($this);
return $this;
}
}
So, now, assume that we have this data :
EntityA [
EntitiesB [
EntityB1 [
EntitiesC [
EntityC1
EntityC2
EntityC3
]
]
EntityB2 [
EntitiesC [
EntityC4
]
]
]
]
That I want is to transfer EntityC4 to the EntityB1[EntitieC] collection.
To achieve that, the process would be :
- EntityB2.EntitiesC::removeEntityC(EntityC4)
- EntityB1.EntitiesC::addEntity(EntityC4)
But it will not do the trick ... EntityC4 is removed and not transferred !
So, it works when orphanRemoval=false on EntityB.EntitiesC, but I want to keep this Doctrine flag.
Is it another way to achieve that properly ?
Thanks for your ideas.
If you read the Doctrine documentation chapter 8.7. Orphan Removal you can see the following:
When using the orphanRemoval=true option Doctrine makes the assumption that the entities are privately owned and will NOT be reused by other entities. If you neglect this assumption your entities will get deleted by Doctrine even if you assigned the orphaned entity to another one.
Seems to me that this this is exactly the mistake you are making in this case.
You simply cannot use orphanRemoval in this case.

Categories