Symfony 4中的输出集合类型



我试图在编辑器中为用户显示集合,但我得到了以下错误:

表单的视图数据应为类的实例App\Entity\Role,但是是一个(n)字符串。您可以通过以下方式避免此错误设置";data_ class";选项为null或通过添加视图将(n)字符串转换为的实例的transformer应用程序\实体\角色。

控制器方法

/**
* @Route("/{id}/edit", name="admin_edit_assign_roles")
*/
public function edit(Request $request, User $user){
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('admin_assign_roles');
}
return $this->render('admin/assign_roles/edit.html.twig', [
'user' => $user,
'form' => $form->createView()
]);
}

AssignRolesType.php

class AssignRolesType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Role::class
]);
}
}

UserType.php

class UserType extends AbstractType
{
function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('email');
$builder->add('roles', CollectionType::class, [
'entry_type' => AssignRolesType::class,
'entry_options' => ['label' => false],
]);
}
function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class
]);
}
}

实体\用户.php

namespace AppEntity;
use AppRepositoryUserRepository;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;
use SymfonyBridgeDoctrineValidatorConstraintsUniqueEntity;
use SymfonyComponentSecurityCoreUserUserInterface;
/**
* @ORMEntity(repositoryClass=UserRepository::class)
* @ORMTable(name="`user`")
* @UniqueEntity(fields={"email"}, message="There is already an account with this email")
*/
class User implements UserInterface
{
private $prefix = "ROLE_";
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="string", length=180, unique=true)
*/
private $email;
//    /**
//     * @ORMColumn(type="json")
//     */
//    private $roles = [];

/**
* @var Collection|Role[]
* @ORMManyToMany(targetEntity="AppEntityRole")
* @ORMJoinTable(
*     name="user_roles",
*     joinColumns={@ORMJoinColumn(name="user_id", referencedColumnName="id")},
*     inverseJoinColumns={@ORMJoinColumn(name="role_id", referencedColumnName="id")}
* )
*/
private $roles;
/**
* @var string The hashed password
* @ORMColumn(type="string")
*/
private $password;
/**
* @ORMColumn(type="boolean")
*/
private $isVerified = false;
/**
* @ORMColumn(type="integer", nullable=true)
*/
private $vkontakteID;

/**
* @ORMColumn(type="string", length=255, nullable=true)
*/
private $vkontakteAccessToken;
/**
* @ORMColumn(type="string", length=255, nullable=true)
*/
private $firstName;
/**
* @ORMColumn(type="string", length=255, nullable=true)
*/
private $lastName;
/**
* @ORMColumn(type="string", length=255, nullable=true, unique=true)
*/
private $nickName;
public function __construct()
{
$this->roles = new ArrayCollection();
}

public function getId(): ?int
{
return $this->id;
}
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
{
foreach ($this->roles->toArray() as $roleItem){
$roles[] = $this->prefix . $roleItem->getSlug();
}
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(Collection $roles): self
{
$this->roles = $roles;
return $this;
}
public function addRole(Role $role){
$this->roles->add($role);
}
public function removeRole(Role $role){
$this->roles->removeElement($role);
}
/**
* @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 isVerified(): bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): self
{
$this->isVerified = $isVerified;
return $this;
}
public function getVkontakteID(): ?int
{
return $this->vkontakteID;
}
public function setVkontakteID(?int $vkontakteID): self
{
$this->vkontakteID = $vkontakteID;
return $this;
}
public function getFirstName(): ?string
{
return $this->firstName;
}
public function setFirstName(?string $firstName): self
{
$this->firstName = $firstName;
return $this;
}
public function getLastName(): ?string
{
return $this->lastName;
}
public function setLastName(?string $lastName): self
{
$this->lastName = $lastName;
return $this;
}
public function getNickName(): ?string
{
return $this->nickName;
}
public function setNickName(string $nickName): self
{
$this->nickName = $nickName;
return $this;
}
public function getVkontakteAccessToken(): ?string
{
return $this->vkontakteAccessToken;
}
public function setVkontakteAccessToken(?string $vkontakteAccessToken): self
{
$this->vkontakteAccessToken = $vkontakteAccessToken;
return $this;
}
public function getIsVerified(): ?bool
{
return $this->isVerified;
}

}

错误消息的原因

User.getRoles()返回一个字符串数组。您的UserType的角色的CollectionType字段的条目类型为AssignRoleType,需要Role实体。表单通过getter访问属性(如果存在的话),而getter(getRoles)只返回一个字符串数组,CollectionType将其提供给AssignRoleType,后者显然抱怨该字符串不是Role实体。

由于您可能正在使用Symfony安全角色系统,getRoles可能必须返回字符串。因此,改变这一点基本上是不可能的。

为盈利而更名

下面的方法并不是很优雅,但很简单。表单组件不关心如何调用User类上的属性,它只关心访问(ors)。

您可以在User上实现方法getRoleObjectsaddRoleObjectremoveRoleObject(后两者应该与addRoleremoveRole相同),并将表单字段重命名为role_objects,然后您应该是金色的。getRoleObjects必须是return $this->roles->toArray(),之后一切都会正常工作。

评论

您可能想要EntityType(multiple选项设置为true)而不是CollectionType,除非您真的想编辑角色的名称。但只是猜测而已。我知道什么,对吧?!^^

使用不同名称的方法不是特别好,还有其他选项,比如在这个特定的用例中使用数据转换器,这可以很好地工作。

最新更新