Skip to content

Commit

Permalink
refactored to type sensitive option_attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
manuakasam committed May 5, 2015
1 parent 370f0d9 commit f631572
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 51 deletions.
27 changes: 17 additions & 10 deletions docs/form-element.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,25 +160,28 @@ $this->add(
);
```

### Example 5 : including custom valueOption attributes
### Example 5 : Add html attributes to the <option> elements

To set custom HTML attributes on each `valueOption` you can use the
`option_attributes` setting to specify an array of key/value pairs whereby the
keys represent a valid HTML attribute (data-, aria-, onEvent, etc.) and the
value is a valid method to be called on the entity object which in turn returns
the string to use as the value for the attribute.
To set custom HTML attributes on each `valueOption` you can use the `option_attributes` setting to specify an array of
key/value pairs whereby the keys represent a valid HTML attribute (data-*, aria-*, onEvent, etc.).

The value needs to be of type `string` or `callable` (in which case a `string` - or something able to be casted to
string - needs to be returned). Check the following example:

```php
$this->add(
array(
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'name' => 'name',
'name' => 'test',
'options' => array(
'object_manager' => $this->getObjectManager(),
'target_class' => 'Module\Entity\SomeEntity',
'property' => 'property',
'option_attributes' => array(
array('data-type'=>'getDataType')
'class' => 'styledOption',
'data-id' => function (\Module\Entity\SomeEntity $entity) {
return $entity->getId();
}
),
),
)
Expand All @@ -189,11 +192,15 @@ The above example will generate HTML options with a data-key attribute:

```html
<select name="test">
<option value="myValue" data-key="value">myLabel</option>
<option value="myValue2" data-key="value2">myLabel2</option>
<option value="1" class="styledOption" data-id="1">property one</option>
<option value="2" class="styledOption" data-id="2">property two</option>
</select>
```

It is noteworthy that, when working with an option_attribute value of type `callable`, you do **not** need to define
the fully qualified classname into the function. The object passed into the function will always be identical to
the type you define on the key `target_class`.

### Example 6: Implementing <optgroup> support

Once lists become larger there's a big user-experience bonus when lists are groupt using the html <optgroup> attribute.
Expand Down
50 changes: 16 additions & 34 deletions src/DoctrineModule/Form/Element/Proxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,6 @@ class Proxy implements ObjectManagerAwareInterface
*/
protected $optgroupDefault;

/**
* @var array
*/
protected $dataAttributes = array();

public function setOptions($options)
{
if (isset($options['object_manager'])) {
Expand Down Expand Up @@ -138,10 +133,6 @@ public function setOptions($options)
$this->setOptionAttributes($options['option_attributes']);
}

if (isset($options['data_attributes'])) {
$this->setDataAttributes($options['data_attributes']);
}

if (isset($options['optgroup_identifier'])) {
$this->setOptgroupIdentifier($options['optgroup_identifier']);
}
Expand Down Expand Up @@ -360,22 +351,6 @@ public function setOptgroupDefault($optgroupDefault)
$this->optgroupDefault = (string) $optgroupDefault;
}

/**
* @return array
*/
public function getDataAttributes()
{
return $this->dataAttributes;
}

/**
* @param array $dataAttributes
*/
public function setDataAttributes($dataAttributes)
{
$this->dataAttributes = $dataAttributes;
}

/**
* Set if the property is a method to use as the label in the options
*
Expand Down Expand Up @@ -618,19 +593,26 @@ protected function loadValueOptions()
}

foreach ($this->getOptionAttributes() as $optionKey => $optionValue) {
$optionAttributes[$optionKey] = (string) $optionValue;
}
if (is_string($optionValue)) {
$optionAttributes[$optionKey] = $optionValue;

foreach ($this->getDataAttributes() as $dataKey => $property) {
$dataGetter = 'get' . ucfirst($property);
continue;
}

if (!is_callable([$object, $dataGetter])) {
throw new RuntimeException(
sprintf('Method "%s::%s" is not callable', $this->targetClass, $dataGetter)
);
if (is_callable($optionValue)) {
$callableValue = call_user_func($optionValue, $object);
$optionAttributes[$optionKey] = (string) $callableValue;

continue;
}

$optionAttributes[$dataKey] = (string) $object->{$dataGetter}();
throw new RuntimeException(
sprintf(
'Parameter "option_attributes" expects an array of key => value where value is of type'
. '"string" or "callable". Value of type "%s" found.',
gettype($optionValue)
)
);
}

// If no optgroup_identifier has been configured, apply default handling and continue
Expand Down
16 changes: 9 additions & 7 deletions tests/DoctrineModuleTest/Form/Element/ProxyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ public function testExceptionThrownForNonCallableLabelGenerator()
$this->proxy->setOptions(array('label_generator' => 'I throw an InvalidArgumentException'));
}

public function testUsingOptionAttributes()
public function testUsingOptionAttributesOfTypeString()
{
$this->prepareProxy();

Expand All @@ -322,13 +322,15 @@ public function testUsingOptionAttributes()
$this->assertEquals($expectedAttributes, $options[1]['attributes']);
}

public function testDataAttributesAddedProperly()
public function testUsingOptionAttributesOfTypeCallableReturningString()
{
$this->prepareProxy();

$this->proxy->setOptions([
'data_attributes' => [
'data-id' => 'id'
'option_attributes' => [
'data-id' => function($object) {
return $object->getId();
},
]
]);

Expand All @@ -343,13 +345,13 @@ public function testDataAttributesAddedProperly()
$this->assertEquals(['data-id' => 2], $options[1]['attributes']);
}

public function testExceptionThrownWhenDataAttributesGetterNotCallable()
public function testRuntimeExceptionOnWrongOptionAttributesValue()
{
$this->prepareProxy();

$this->proxy->setOptions([
'data_attributes' => [
'data-id' => 'nonExistantMethodName'
'option_attributes' => [
'data-id' => new \stdClass(['id' => 1])
]
]);

Expand Down

0 comments on commit f631572

Please sign in to comment.