简体   繁体   English

Symfony 4单个形式的多个实体

[英]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 . 我检查了Collection表单类型文档表单集合 ,以及Entity表单类型

I have a User entity, UserRole entity and a Role entity. 我有一个User实体, UserRole实体和一个Role实体。 UserRole contains a userID and a roleID. UserRole包含userID和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. 所以我尝试使用EntityType,一个精选的下拉列表显示所有角色(仅当我添加选项mapped => false),但在表单提交后不处理。 It's data is not in the $form->getData(), the user gets created, the user_role entry never created. 它的数据不在$ form-> getData()中,用户被创建,user_role条目从未创建。 If I try it without the mapped => false it throws me: 如果我尝试没有映射=> false它会抛出我:

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. 使用CollectionType它根本不显示选择下拉列表。 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? 我在Controller的代码中遗漏了什么,或者我是否误解了Form类型的使用? 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. 在Symfony中,要获取非映射表单数据,请尝试这样做。

$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. 在下面的代码块中, UserRole::class不应该是UserRole::class而不是Role::class

$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. 坚持使用EntityType并删除mapped = false ,这会告诉Symfony忽略该字段。

I guess the problem is: you have a mixture of $this->user_role and $this->user_roles in your class, probably a renamed variable. 我想问题是:你的类中有$ this-> user_role和$ this-> user_roles的混合,可能是一个重命名的变量。 Clean this up first in __construct(), addUserRole(), removeUserRole(), getUserRoles(), getUserRole(). 首先在__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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM