2016-08-05 2 views
1

Я хочу реализовать новый тип данных доктрины (http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html).Тип данных Doctrine (используйте Factory)

Я реализовал службу страны, которая загружает данные страны через адаптер из любой библиотеки. Знай я иметь следующую реализацию:

<?php 
    interface CountryInterface; 

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

Итак, что я хочу сделать, это - сделать CountryType, который преобразует Country объекта к определенному значению строки (используется поле будет установлено через OptionClass, напр .: ALPHA2, Alpha3, IsoNumber).

Моя проблема заключается в том, что доктрина допускает сопоставление типов данных через имя класса, поэтому я не могу реализовать фабрику для загрузки всех необходимых зависимостей.

Надеюсь, это понятно.

рассматривает

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

Этот тип необходим для реализации четырех методов getName, getSQLDeclaration, convertToDatabaseValue и convertToPHPValue.

  • Тр первые один возвращает имя типа
  • Второй для объявления типа в (SQL) базы данных (я использовал text в примере, но вы также можете использовать целое число или любой другие действительным тип базы данных доктрины).
  • Третий метод преобразует объект вашей страны в значение базы данных (так что в этом случае текстовое значение).
  • Последний метод делает обратное; он преобразует текстовое значение из базы данных. В этом случае я просто создаю экземпляр класса Country и передаю значение базы данных конструктору. Вам нужно добавить свою собственную логику в свой конструктор класса.

В моем примере я допускаю, что значения null также допускаются.

Простая версия вашего класса Country может выглядеть следующим образом:

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

Смежные вопросы