Недавно я решил эту проблему, создав собственный тип формы (в моем случае это называется «селектор»), к которому подключен преобразователь данных, который возвращает монитор по последовательному каналу:
Тип машины:
class MachineType extends AbstractType {
public function buildForm(FormBuilder $builder, array $options) {
$builder->add('name');
$builder->add('monitor', 'monitor_selector_type');
}
public function getName() {
return 'machine;
}
}
Тип селектора монитора (в конечном итоге это будет просто текстовое поле (родительский тип по умолчанию - «текст»), в котором вы введете серийный номер монитора. В этом поле будет отображаться ошибка, если был введен несуществующий серийный номер.
class MonitorSelectorType extends AbstractType {
private $doctrine
public function __construct(Registry $doctrine) {
$this->doctrine = $doctrine;
}
public function buildForm(FormBuilder $builder, array $options) {
$transformer = new MonitorToSerialTransformer($this->doctrine->getEntityManager());
$builder->appendClientTransformer($transformer);
}
public function getDefaultOptions(array $options) {
return array(
'invalid_message'=>'The selected monitor does not exist',
'error_bubbling'=>false
);
}
public function getName() {
return 'machine;
}
}
Этот класс преобразует серийный номер в фактический монитор, а фактический монитор - в серийный
class MonitorToSerialTransformer {
private $em
public function __construct(EntityManager $em) {
$this->em = $em;
}
public function transform($val) {
if (null === $val) {
return '';
}
return $val->getSerial();
}
public function reverseTransform($val) {
if (!$val) {
return null;
}
$monitor = $this->em->getRepository('xBundle:Monitor')->findOneBy(array('serial' => $val));
if (null === $monitor) {
throw new TransformationFailedException('A monitor with serial '.$val.' does not exist!');
}
return $monitor;
}
}
наконец, зарегистрируйте MonitorSelectorType в вашем сервисном контейнере с идентификатором "monitor_selector_type" и тегом "form.type" и вставьте в него доктрину.
Теперь в любом произвольном месте вашего приложения будет очень легко использовать этот тип селектора для выбора монитора по идентификатору. Никакая логика не должна быть добавлена к вашему контроллеру вообще.
Если вы хотите, чтобы новый монитор создавался при вводе неизвестного серийного номера, вы можете создать его экземпляр, а не выдавать исключение TransformationFailedException, и даже сохранить его в своем диспетчере сущностей, если на машине нет опций приведения в действие для монитора.
С уважением,
Bart