Skip to content

Instantly share code, notes, and snippets.

@codeliner
Last active December 27, 2023 19:32
Show Gist options
  • Save codeliner/b02871398c2ac44009f6 to your computer and use it in GitHub Desktop.
Save codeliner/b02871398c2ac44009f6 to your computer and use it in GitHub Desktop.
DoctrineModule\Form\ObjectSelect fix to define custom value property
<?php
$element = array(
'name' => 'task',
'type' => 'Application\Form\Element\ObjectSelect', //Point to extended ObjectSelect which provides custom proxy impl.
'options' => array(
'label' => 'task',
'object_manager' => $this->getObjectManager(),
'target_class' => 'Application\Entity\Task',
'property' => 'name',
'find_method' => 'findBy',
'value' => 'getForeignEntityId', //Define entity property or method to populate options values
'value_is_method' => true, //Flag to indicate whether "value" should be treated as method or property
),
'attributes' => array(
'multiple' => false,
'required' => false,
'type' => 'select',
)
);
<?php
namespace Application\Form\Element;
use Application\Form\Element\ObjectSelect\Proxy;
use DoctrineModule\Form\Element\ObjectSelect as DoctrineObjectSelect;
/**
* Class ObjectSelect
*
* Extends doctrines ObjectSelect to provide own Proxy implementation
*
* @package Application\Form\Element
* @author Alexander Miertsch <[email protected]>
*/
class ObjectSelect extends DoctrineObjectSelect
{
/**
* Provide own Proxy implementation to fix bug that only identifier can be loaded as option value
*/
public function init()
{
$this->proxy = new Proxy();
}
}
<?php
namespace Application\Form\Element\ObjectSelect;
use DoctrineModule\Form\Element\Proxy as DoctrineProxy;
use RuntimeException;
/**
* Class Proxy
*
* Extends doctrines Form\Element\Proxy to fix bug that only identifier can be loaded as option value
*
* @package Application\Form\Element\ObjectSelect
* @author Alexander Miertsch <[email protected]>
*/
class Proxy extends DoctrineProxy
{
protected $value = false;
protected $valueIsMethod = false;
public function setOptions($options)
{
if (isset($options['value'])) {
$this->value = $options['value'];
unset($options['value']);
}
if (isset($options['value_is_method'])) {
$this->valueIsMethod = $options['value_is_method'];
unset($options['value_is_method']);
}
parent::setOptions($options);
}
/**
* Load value options
*
* @throws RuntimeException
* @return void
*/
protected function loadValueOptions()
{
if (!($om = $this->objectManager)) {
throw new RuntimeException('No object manager was set');
}
if (!($targetClass = $this->targetClass)) {
throw new RuntimeException('No target class was set');
}
$metadata = $om->getClassMetadata($targetClass);
$identifier = $metadata->getIdentifierFieldNames();
$objects = $this->getObjects();
$options = array();
if ($this->displayEmptyItem || empty($objects)) {
$options[''] = $this->getEmptyItemLabel();
}
if (!empty($objects)) {
foreach ($objects as $key => $object) {
if (null !== ($generatedLabel = $this->generateLabel($object))) {
$label = $generatedLabel;
} elseif ($property = $this->property) {
if ($this->isMethod == false && !$metadata->hasField($property)) {
throw new RuntimeException(
sprintf(
'Property "%s" could not be found in object "%s"',
$property,
$targetClass
)
);
}
$getter = 'get' . ucfirst($property);
if (!is_callable(array($object, $getter))) {
throw new RuntimeException(
sprintf('Method "%s::%s" is not callable', $this->targetClass, $getter)
);
}
$label = $object->{$getter}();
} else {
if (!is_callable(array($object, '__toString'))) {
throw new RuntimeException(
sprintf(
'%s must have a "__toString()" method defined if you have not set a property'
. ' or method to use.',
$targetClass
)
);
}
$label = (string) $object;
}
if ($valueProperty = $this->value) {
if ($this->valueIsMethod == false && !$metadata->hasField($valueProperty)) {
throw new RuntimeException(
sprintf(
'Property "%s" could not be found in object "%s"',
$valueProperty,
$targetClass
)
);
}
$getter = ($this->valueIsMethod)? $valueProperty : 'get' . ucfirst($valueProperty);
if (!is_callable(array($object, $getter))) {
throw new RuntimeException(
sprintf('Method "%s::%s" is not callable', $this->targetClass, $getter)
);
}
$value = $object->{$getter}();
} else {
if (count($identifier) > 1) {
$value = $key;
} else {
$value = current($metadata->getIdentifierValues($object));
}
}
$options[] = array('label' => $label, 'value' => $value);
}
}
$this->valueOptions = $options;
}
}
@chateaux
Copy link

chateaux commented Feb 1, 2015

Thank you - very useful and saved me the trouble of writing this.

@juliangorge
Copy link

juliangorge commented Jun 9, 2021

Excellent!
In doctrine 3.0 change:

public function setOptions($options) to public function setOptions(array $options): void
and
protected function loadValueOptions() to protected function loadValueOptions(): void

@jjwdesign
Copy link

jjwdesign commented Dec 27, 2023

Code is a bit out dated now, but still very helpful! Thank you.
I'm surprised doctrine still doesn't have this functionality at the end of 2023.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment