Symfony2 DataTransformers - Как вы преобразовываете обратно без идентификатора или уникальных значений?

У меня есть коллекция объектов PhoneNumber для каждого объекта Contact (Name, Email). Номер телефона разбит на код города, телефонный номер, суффикс, добавочный номер, а затем селектор типа (Рабочий, Домашний, Мобильный). Я хочу использовать DataTransformer, чтобы число могло отображаться в одном поле формы вместо 4 разных текстовых полей. Телефонные номера не уникальны в базе данных.

ОБНОВЛЕНО: Как получить доступ к полному объекту при преобразовании из строковой версии обратно в объект? Ранее я сталкивался с этой проблемой и в итоге поместил идентификатор объекта в скобки в текстовом поле, а затем повторно выразил их в преобразовании, чтобы я мог выполнить запрос для получения объекта.

phonenumber_combined — это служба пользовательского типа формы, которая ссылается на мой класс PhoneNumberCombinedType.

Мой метод добавления для коллекции телефонов в контакте:

->add('phones', 'collection', array(
            'label'     => 'Phones',
            'type'      => new PhoneNumberType(),
            'allow_add' => true,
            'allow_delete' => true
            ))
        ; 

Функция сборки PhoneNumberType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('phone', 'phonenumber_combined')
        ->add('type', 'entity',
            array('class'   => 'Test\Bundle\SystemBundle\Entity\Type',
            'property'      => 'name',
            'query_builder' => function(EntityRepository $er){
                return $er->createQueryBuilder('type')
                ->where('type.type = :t')
                ->orderBy('type.name', 'ASC')
                ->setParameter('t', 'PhoneNumber');
            }))
        ;           
}

Служба PhoneNumberCombinedType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $transformer = new PhoneNumberToStringTransformer($this->om);

    $builder->addViewTransformer($transformer);
}

Трансформатор PhoneNumberToString:

public function transform($phonenumber)
{
    if (null === $phonenumber) {
        return null;
    }

    return $phonenumber->__toString();       
}

public function reverseTransform($phonenumber)
{
    if (!$phonenumber) {
        return null;
    } 

    // PHONE NUMBER IS JUST A STRING AT THIS POINT, HOW DO I GET THE ENTITY?
}

person mhoff    schedule 25.10.2012    source источник


Ответы (2)


Вам нужно будет передать диспетчер объектов через инъекцию конструктора, а затем работать с ним, как обычно.

class PhoneNumberTransformer implements DataTransformerInterface
{
    /**
     * @var ObjectManager
     */
    private $om;

    /**
     * @param ObjectManager $om
     */
    public function __construct(ObjectManager $om)
    {
        $this->om = $om;
    }

    public function transform($phonenumber)
    {
        if ($phonenumber === null) {
            return null;
        }

        return $phonenumber->__toString();
    }

    public function reverseTransform($phonenumber)
    {
        if (!$this->phonenumber) {
            return null;
        }

        $phoneEntity = $this->om
            ->getRepository('{REFERENCE_TO_THE_ENTITY}')
            ->findOneBy(array('phonenumber' => $phonenumber));

        if ($phoneEntity === null) {
            throw new TransformationFailedException();
        }

        return $phoneEntity;
    }
}
person Bill H    schedule 14.03.2013

Извините за отсутствие обновлений, но я нашел достойное решение этой проблемы. Я добавил метод setPhone к объекту PhoneNumber, который, по-видимому, вызывается автоматически после обратного преобразования. В моем преобразователе я добавил регулярное выражение, чтобы разделить свой номер телефона на соответствующие разделы, а затем добавил каждый раздел в массив. Этот массив возвращается преобразователем, который затем используется setPhone для обновления объекта PhoneNumber.

Мой метод setPhone в объекте PhoneNumber:

/**
 * Used by PhoneNumberToStringTransformer to set Entity data
 * @param array $phone_data
 */
public function setPhone($phone_data)
{
    if($phone_data == null) {
        $this->setAreaCode(null);
        $this->setExchange(null);
        $this->setSuffix(null);
        $this->setExtension(null);
        return $this;
    }

    $this->setAreaCode($phone_data['AreaCode']);
    $this->setExchange($phone_data['Exchange']);
    $this->setSuffix($phone_data['Suffix']);
    $this->setExtension($phone_data['Extension']);

    return $this;
}

ReverseTransform в моем PhoneNumberToStringTransformer:

/**
 * Transforms a phonenumber string to an array that will be passed to setPhone
 * which will handle setting each entity field.
 *
 * @param  string $string Phone number string
 * @return (array) areaCode, exchange, suffix and extension
 */
public function reverseTransform($string)
{
    if (!$string || strlen($string) == 0) {
        return null;
    }

    // Split phone number into array for areaCode, exchange, suffix, and extension
    $pattern = '/(\d{3})?-?(\d{3})?-?(\d{4})?( x(\d+))?/';
    preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);

    $phone_data = array('AreaCode'=>null, 'Exchange'=>null, 'Suffix'=>null, 'Extension'=>null);

    $counter = 1;
    foreach($phone_data as $key => $value) {
        if($counter == 4)
            $counter = 5;

        if(isset($matches[$counter][0]) && $matches[$counter][0] !== '') {
            $phone_data[$key] = $matches[$counter][0];
        } else {
            $phone_data[$key] = null;
        }
        $counter++;
    }

    return $phone_data;
}
person mhoff    schedule 09.01.2013