2016-08-05 5 views
1

私は新しいdoctrineデータ型(http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html)を実装したいと思います。Doctrineデータ型(工場使用)

私は任意のライブラリからアダプター経由で国データをロードする国サービスを実装しました。私は次の実装を持って知っている:

<?php 
    interface CountryInterface; 

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

だから、私がやりたいことはある - 元、使用されたフィールドをOptionClass経由で設定されます(特定の文字列値にCountryオブジェクトに変換CountryTypeを作る:アルファ2、 Alpha3、IsoNumber)。

私の問題は、doctrineはclassnameを使ったデータ型のマッピングしか許さないため、必要なすべての依存関係をロードするためのファクトリを実装できないことです。

私はこれが理解できることを望みます。

よろしく

+0

カスタムDBAL型のマッピング方法の詳細はこちらDoctrine 2 ORMまたはDBALだけを使用していますか? – edigu

+0

こんにちは、私は教義2 ORMを使用していますが、将来私は教義2をサポートしますODM – user3549136

答えて

1

まずはDoctrine\DBAL\Types\Typeクラスを拡張国のカスタムDBALタイプを登録する必要があります。

<?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; 
    } 
} 

このタイプは、4つの方法getNamegetSQLDeclarationconvertToDatabaseValueconvertToPHPValueを実装する必要があります。

  • THRE最初のタイプ
  • の名前を返す第二つ(SQL)データベース内の型宣言するためのものである(私は例でtextを使用しますが、整数使用または有効な任意の他のできdoctrineデータベースタイプ)。
  • 3番目のメソッドは、国オブジェクトをデータベース値(この場合はテキスト値)に変換します。
  • 最後の方法は反対です。データベースからテキスト値を変換します。この場合、私は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; 

Doctrine2 documentation chapter Custom Mapping Types

+0

優れた答え、thx – user3549136

関連する問題