在Symfony4中注册自定义Doctrine类型

6

我有一个自定义的Doctrine类型

命名空间为App\Doctrine\Types;

使用了Doctrine\DBAL\Platforms\AbstractPlatform以及Doctrine\DBAL\Types\TextType。

class MyType extends TextType
{
   private $prefix='';

   public function getName()
   {
      return 'my_type';
   }
   public function setPrefix(string $prefix)
   {
      $this->prefix=$prefix;
   }
}

我在config/packages/doctrine.yml中注册了:

doctrine:
    dbal:
        types:
            my_type: App\Doctrine\Types\MyType

在内核的boot()函数中,我试图向这个类型添加一些参数:
public function boot() {
   parent::boot();

   $myType=Type::getType('my_type');
   $myType->setPrefix('abc');
}

第一次运行应用程序时,它可以完美地工作。前缀已经为该类型设置并可以在整个应用程序中使用。然而,第二次运行时出现异常:

请求了未知的列类型“encrypted_text”。您使用的任何Doctrine类型都必须在\Doctrine\DBAL\Types\Type::addType()中进行注册。您可以使用\Doctrine\DBAL\Types\Type::getTypesMap()获取所有已知类型的列表。如果此错误在数据库内省期间发生,则可能已经忘记为Doctrine Type注册所有数据库类型。使用AbstractPlatform#registerDoctrineTypeMapping()或使您的自定义类型实现Type#getMappedDatabaseTypes()。如果类型名称为空,则可能存在缓存问题或遗漏了某些映射信息。

我随后将boot()更改为:

    public function boot() {
       parent::boot();
       if (!Type::hasType('my_type')) {
           Type::addType('my_type', 'App\Doctrine\Types\MyType');
       }
       $myType=Type::getType('my_type');
       $myType->setPrefix('abc');
   }

现在异常已经消失了,但前缀没有设置。我知道异常会告诉我该做什么,但我真的不知道从哪里开始。

有人能指引我正确的方向吗?


你在哪里看到使用boot()方法的文档了?这似乎有点不寻常。诚然,我以前从未见过setPrefix方法。你确定它真的存在吗?在基类中没有看到它。这是你自己的方法之一吗?通常我会期望编译器通过这种方式进行处理。 - Cerad
我在这个问题中看到了它:https://stackoverflow.com/questions/48154380/how-to-pass-parameters-to-a-custom-doctrine-type-in-symfony4?rq=1。方法setPrefix存在,我需要从配置文件中传递一个前缀给该类型。 - Nin
我假设你正在从你的启动方法中调用parent::boot()吗? - Cerad
是的,我已经编辑了我的问题。 - Nin
只是一次彻底的尝试,但请将您的代码用 if ($this->booted === false) { 包围起来并删除缓存。可能不会有帮助。 - Cerad
非常感谢您关注此事。不幸的是,它并没有起作用。异常已经消失了,但前缀不再设置。因此,类型可以正常加载并且我可以使用它,但是由于未执行boot(),因此它没有设置前缀(它在第一次运行应用程序时执行)。清除缓存只能起到一次作用... - Nin
2个回答

4

目前我通过从config/packages/doctrine.yml中删除它来解决了这个问题,因此它不再在那里注册。在内核中,现在我可以加载它:

    public function boot() {
       parent::boot();
       if (!Type::hasType('my_type')) {
           Type::addType('my_type', 'App\Doctrine\Types\MyType');
       }
       $myType = Type::getType('my_type');
       $myType->setPrefix('abc');
   }

我仍然无法真正理解为什么在构建缓存之前可以工作,但是一旦缓存构建完成就不能工作。但好吧,我现在可以继续。

如果有人有更好的答案,我将非常乐意接受。


尝试使用从官方ramsey uuid doctrine repo doc中获取的引导文件,这对我有效。看起来有些奇怪,但这是推荐的方式。https://github.com/ramsey/uuid-doctrine#usage - DevJ3rry

-2
#This is may answer!!!


 **IMPORTANTE!! Because in Symfony/PHP (NO Object Oriented Language) don't storaging a state it's need make this form to mapping an ENUM type or any Custom Type similary to ENUM.**

如果您想在数据库表中自定义和映射类型,您需要使用 Symfony 的更高版本,Symfony >= 4.4 才能使用此 Bundle。请在您的项目中执行此命令(命令提示符)。

                composer req fresh/doctrine-enum-bundle 

Link  example --> [https://github.com/fre5h/DoctrineEnumBundle][1] .
I made do this and it's ok for my app.

1

    So, copy this class from this link 
    [https://github.com/fre5h/DoctrineEnumBundle/blob/master/DBAL/Types/AbstractEnumType.php][1] 
    and storage it in src/DBAL/Types =(IF NOT EXIST, CREATE IT), in your project Symfony => 4.4 o higher version.

    #This is your Base class type.

2

    Create this Table in Your Database (in my case I'm using MySql DB):

    CREATE TABLE players (
        id INT AUTO_INCREMENT NOT NULL,
        position ENUM('PG', 'SG', 'SF', 'PF', 'C') NOT NULL,
        PRIMARY KEY(id)
    ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = INNODB
    *****************

3

    Create an Entity class for mapping table  (Players) from your Databae inside your project level directory.

    D:SYMFONY\app\myApp
    php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity --filter="Players"

4

    Create getter and setters for your new Entity:

    D:SYMFONY\app\myApp
    php bin/console make:entity --regenerate App 

5

    Generate your CRUD operation for Entty class + frontend.

    D:SYMFONY\app\myApp
    php bin/console make:entity --regenerate App 

6

 Create your custom Type class BasketballPositionType 

    <?php
namespace App\DBAL\Types;

use Fresh\DoctrineEnumBundle\DBAL\Types\AbstractEnumType;

final class BasketballPositionType extends AbstractEnumType
{
    public const POINT_GUARD = 'PG';
    public const SHOOTING_GUARD = 'SG';
    public const SMALL_FORWARD = 'SF';
    public const POWER_FORWARD = 'PF';
    public const CENTER = 'C';

    protected static $choices = [
        self::POINT_GUARD => 'Point Guard',
        self::SHOOTING_GUARD => 'Shooting Guard',
        self::SMALL_FORWARD => 'Small Forward',
        self::POWER_FORWARD => 'Power Forward',
        self::CENTER => 'Center'
    ];
}


7

Go inside this path in your Symfony project at 

                      D:SYMFONY\app\myApp\config\packages

and create this class php : doctrime.php.
This class it's necesary for to Register your new Type. 
Can you find more information at link for register new type in synfony 
[https://symfony.com/doc/current/doctrine/dbal.html][1]

so - REGISTER YOUR NEW TYPE
    Copy this fragment of code end paste in doctrime.php class:

    <?php
    $container->loadFromExtension('doctrine', [
        'dbal' => [
            'mapping_types' => [
                'enum'  => 'string', /////////mapping enum to as stringa
            ],
            'types' => [
                'BasketballPositionType' => App\DBAL\Types\BasketballPositionType::class,
            ],
        ],
    ]);

   So, bindig ENUM type db in String and your new Type is "BasketballPositionType"  !!!!


8

    Now, use your Custom Type in your Entity Class mapping 'Players'.

     <?php

namespace App\Entity;
     ** very important
use App\DBAL\Types\BasketballPositionType;  
use Fresh\DoctrineEnumBundle\Validator\Constraints as DoctrineAssert; 

use Doctrine\ORM\Mapping as ORM;

/**
 * Players
 *
 * @ORM\Table(name="players")
 * @ORM\Entity
 */
class Players
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="position", type="BasketballPositionType", length=255, nullable=false)
     * @DoctrineAssert\Enum(entity="App\DBAL\Types\BasketballPositionType")
     */
    private $position;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getPosition(): ?string
    {
        return $this->position;
    }

    public function setPosition(string $position): self
    {
        $this->position = $position;

        return $this;
    }


}

运行

         ####################### RUM #######################

             Run you Symfony embeded server 
                                    [  symfony serve ]
             And go later in browser at https://127.0.0.1:8000/players


        I'm use CMDER prompt command because it has Git incorporated. 
        It's very easy!!

      [1]: https://symfony.com/doc/current/doctrine/dbal.html

我无法理解你的格式:你想要展示什么? - greybeard
请在您的答案中添加所有信息,而不是链接到外部资源。 - Nico Haase
你在这方面付出了很多努力,可惜结果有点难以理解。 - James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接