2016-08-05 35 views
1

我想實現一個新的學說數據類型(http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html)。學說數據類型(使用工廠)

我已經實施了一項國家服務,它通過任何圖書館的適配器加載國家數據。知道我有以下實現:

<?php 
    interface CountryInterface; 

    interface Address 
    { 
     public function setCountry(CountryInterface $country); 
     public function getCountry() : CountryInterface; 
    } 
?> 

所以,我想要做的是 - 做一個CountryType其中Country對象轉換爲特定的字符串值(用場將通過OptionClass設置,例:α-2, Alpha3,IsoNumber)。

我的問題是,doctrine只允許通過classname進行數據類型映射,所以我不能實現一個工廠來加載所有需要的依賴關係。

我希望這是可以理解的。

問候

+0

您是使用Doctrine 2 ORM還是僅使用DBAL? – edigu

+0

嗨,此刻我使用了主義2 ORM,但是在將來我還會支持主義2 ODM – user3549136

回答

1

首先,您需要註冊您的自定義DBAL類型擴展Doctrine\DBAL\Types\Type類國家:

<?php 

namespace Application\DBAL\Types; 

use Application\Resource\Country; 
use Application\Service\CountryService; 
use Doctrine\DBAL\Platforms\AbstractPlatform; 
use Doctrine\DBAL\Types\ConversionException; 
use Doctrine\DBAL\Types\Type; 
use InvalidArgumentException; 

class CountryType extends Type 
{ 
    const NAME = 'country'; 

    /** 
    * Country service 
    */ 
    protected $countryService; 

    /** 
    * @return string 
    */ 
    public function getName() 
    { 
     return self::NAME; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) 
    { 
     return $platform->getDoctrineTypeMapping('text'); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function convertToDatabaseValue($value, AbstractPlatform $platform) 
    { 
     if($value === null){ 
      return null; 
     } 

     if ($value instanceof Country) { 
      return (string) $value; 
     } 

     throw ConversionException::conversionFailed($value, self::NAME); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function convertToPHPValue($value, AbstractPlatform $platform) 
    { 
     if($value === null){ 
      return null; 
     } 

     $country = $this->countryService->getCountry($value); 
     if(! $country instanceof Country){ 
      throw ConversionException::conversionFailed($value, self::NAME); 
     } 

     return $country; 
    } 

    /** 
    * Set country service 
    * 
    * @var CountryService $service 
    */ 
    public function setCountryService ($service){ 
     $this->countryService = $service; 
    } 
} 

這種類型需要實現四個方法getNamegetSQLDeclarationconvertToDatabaseValueconvertToPHPValue

  • THRE第一個該類型
  • 第二個是在(SQL)類型聲明數據庫(我在這個例子中使用text返回名稱,但你也可以使用整數或任何其他有效的學說數據庫類型)。
  • 第三種方法將您的國家對象轉換爲數據庫值(因此在這種情況下爲文本值)。
  • 最後一種方法正好相反;它轉換來自數據庫的文本值。在這種情況下,我只是實例化Country類並將數據庫值傳遞給構造函數。您需要在您的類構造函數中添加自定義邏輯。

在我的例子中,我假設null值也是允許的。

你的國家類的簡單版本看起來是這樣的:

<?php 

namespace Application\Resource; 

class Country{ 

    protected $value; 

    /** 
    * Magic stringify to cast country object to a string 
    */ 
    public function __toString(){ 
     return $value; 
    } 

    /** 
    * Constructor method 
    */ 
    public function construct($value){ 
     $this->value = $value 
     // set other properties... 
    } 

    // setters and getters... 
} 

這是給你值是否應該alpha2/alpha3/country_name或任何你想在數據庫中可見。你應該以某種方式在構造函數方法中使用其他屬性填充另一個國家。我把這部分留給你。

現在,您需要註冊您的自定義的國家類型,這樣的教義將使用它:

'doctrine' => array(
    //... 
    'configuration' => array(
     'orm_default' => array(
      Application\DBAL\Types\CountryType::NAME => Application\DBAL\Types\CountryType::class, 
     ) 
    ) 
) 

而且你可以在應用程序上的引導您的服務設置Module.php文件:

/** 
* @param EventInterface|MvcEvent $event 
* @return void 
*/ 
public function onBootstrap(EventInterface $event) 
{ 
    $application = $event->getApplication(); 
    $eventManager = $application->getEventManager(); 

    $eventManager->attach(MvcEvent::EVENT_BOOTSTRAP, array($this, 'initializeCountryType'); 
} 

/** 
* @param MvcEvent $event 
*/ 
public function initializeCountryType(MvcEvent $event) 
{ 
    $application = $event->getApplication(); 
    $serviceManager = $application->getServiceManager(); 

    //get your country service from service manager 
    $countryService = $serviceManager->getCountryService(); 

    $countryType = \Doctrine\DBAL\Types\Type::getType('country'); 
    $countryType->setCountryService($countryService); 
} 

現在你可以在任何實體定義中使用您的國家類型如下:

/** 
* @var string 
* @ORM\Column(type="country", nullable=true) 
*/ 
protected $country; 

閱讀更多關於如何映射自定義DBAL類型Doctrine2 documentation chapter Custom Mapping Types

+0

優秀的回答,thx – user3549136