枚举和 Symfony 表单的教义集合

Posted

技术标签:

【中文标题】枚举和 Symfony 表单的教义集合【英文标题】:Doctrine collection of enums and Symfony Form 【发布时间】:2021-12-06 08:51:48 【问题描述】:

用户可以选择他想要接收的电子邮件通知。

通知类型由枚举(MyCLabs 库)定义:

use MyCLabs\Enum\Enum;

final class NotificationType extends Enum

    public const DEADLOCKED = 1;
    public const REJECTED = 2;
    public const SENT = 3;
    public const ACCEPTED = 4;
    public const REFUSED = 5;

    public function translationPath(): string
    
        return 'user.notifications.'.$this->getKey();
    


用户有更多的通知类型:

/**
 * @ORM\Entity()
 */
class Notification

    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="notifications")
     */
    protected User $user;

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     */
    protected int $notificationType;

    public function __construct(User $user)
    
        $this->user = $user;
    

    public function getNotificationType(): NotificationType
    
        return new NotificationType($this->notificationType);
    

    public function setNotificationType(NotificationType $notificationType): self
    
        $this->notificationType = $notificationType->getValue();

        return $this;
    

用户实体:

/**
 * @ORM\Entity()
 */
class User implements UserInterface, EquatableInterface

    /**
     * @var Collection|Notification[]
     * @ORM\OneToMany(targetEntity=Notification::class, mappedBy="user", cascade="persist", "remove", orphanRemoval=true)
     */
    protected Collection $notifications;
    
    //...

这是正确的解决方案吗?现在我在为复选框列表制作 Symfony 表单时遇到问题。

类似这样的事情(我知道,这是错误的):

$builder->add('notifications', ChoiceType::class, [
    'choices' => NotificationType::values(),
    'expanded' => true,
    'multiple' => true,
    'choice_value' => 'value',
    'choice_label' => static function (NotificationType $type): string 
        return $type->translationPath();
    ,
]);

我可以在我的情况下使用内置的 Symfony 表单吗?或者你对关系“实体多对多枚举”有更好的解决方案。

【问题讨论】:

你到底有什么问题/错误? 问题:表单字段“通知”预期的 NotificationType 实例数组(选择选项)。但是给定通知实体的集合。 【参考方案1】:

我用数据转换器编写了我的 EnumChoiceType,它将 NotificationType 的数组转换为 Notification 实体的集合,反之亦然。

不要忘记在实体集合中设置orphanRemoval=true

用法:

$builder->add('notifications', EnumChoiceType::class, [
    'enum' => NotificationType::class,
    'class' => Notification::class,
    'property' => 'notificationType',
    'object' => $options['data'],
    'expanded' => true,
    'multiple' => true,
]);

枚举选择类型:

class EnumChoiceType extends AbstractType implements DataTransformerInterface

    /**
     * @var mixed
     */
    private $object;
    private string $property;
    private string $class;

    public function buildForm(FormBuilderInterface $builder, array $options): void
    
        $this->object = $options['object'];
        $this->property = $options['property'];
        $this->class = $options['class'];

        if ($options['multiple']) 
            $builder->addModelTransformer($this);
        
    

    public function configureOptions(OptionsResolver $resolver): void
    
        $resolver->setRequired([
            'enum',
        ]);

        $resolver->setDefaults([
            'choices' => static function (Options $options) 
                return call_user_func([$options['enum'], 'values']);
            ,
            'choice_value' => 'value',
            'choice_label' => static function (Enum $enum): string 
                return $enum->translationPath();
            ,
            'property' => 'enum',
            'object' => null,
            'class' => null,
        ]);
    

    /**
     * @param mixed $value
     * @return Enum[]
     */
    public function transform($value): array
    
        $array = [];

        foreach ($value as $item) 
            $array[] = PropertyAccess::createPropertyAccessor()->getValue($item, $this->property);
        

        return $array;
    

    /**
     * @param Enum[] $value
     */
    public function reverseTransform($value): ArrayCollection
    
        $collection = new ArrayCollection();

        foreach ($value as $type) 
            $notification = new $this->class($this->object);
            PropertyAccess::createPropertyAccessor()->setValue($notification, $this->property, $type);

            $collection->add($notification);
        

        return $collection;
    

    public function getParent(): string
    
        return ChoiceType::class;
    

【讨论】:

以上是关于枚举和 Symfony 表单的教义集合的主要内容,如果未能解决你的问题,请参考以下文章

使用 Symfony 路由从 .htaccess 重写 URL

Symfony 2.3 Bad Credentials 自定义提供程序

教义 - 如何保持多对一同步?

如何使用 symfony 在教义查询构建器中选择表之间的特定连接?

Symfony2 教义连接返回太多数据

当 Symfony 教义对象的一个​​属性发生变化时更新另一个属性