Skip to content

Instantly share code, notes, and snippets.

@willmorgan
Last active December 18, 2015 11:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save willmorgan/5774423 to your computer and use it in GitHub Desktop.
Save willmorgan/5774423 to your computer and use it in GitHub Desktop.
3,1 DataObjectManager style field that allows arbitrary options to be rendered on the frontend with maximum flexibility and ease.
<?php
/**
* TableOptionsetField
* DataObjectManager style field that allows arbitrary options to be rendered on
* the frontend with maximum flexibility and ease.
* @author Will Morgan <will@betterbrief.co.uk>
*/
class TableOptionsetField extends FormField {
/**
* @var SS_List $source The iterable data source
*/
protected $source;
/**
* @var array A hash of field => title column names, to be used in rendering
*/
protected $sourceColumns;
/**
* @var callable A function that is run to get the value of a source item
*/
protected $sourceValueGetter;
/**
* @var string The HTML attribute name to determine input selection
*/
protected static $selected_attr = 'checked';
public function __construct($name, $title = null, $source, $sourceColumns = null, $sourceValueGetter = null, $value = null, $form = null) {
parent::__construct($name, $title, $value);
$this
->setSource($source)
->setSourceColumns($sourceColumns)
->setSourceValueGetter($sourceValueGetter)
->setForm($form);
}
/**
* @return SS_List
*/
public function getSource() {
return $this->source;
}
public function setSource(SS_List $source) {
$this->source = $source;
return $this;
}
public function getSourceColumns() {
return $this->sourceColumns;
}
public function setSourceColumns(array $columns) {
$this->sourceColumns = $columns;
return $this;
}
/**
* @param callable $callable The function to call on the source object.
*/
public function setSourceValueGetter($callable) {
if(!is_null($callable) && !is_callable($callable)) {
throw new InvalidArgumentException('Must be a callable: ' . var_export($callable, true));
}
$this->sourceValueGetter = $callable;
return $this;
}
/**
* Gets the HTML attributes for the input field.
* @return string
*/
public function getFieldAttrs($source) {
$sourceValue = $this->getSourceValue($source);
$attrs = array(
'id' => sprintf('%s_%s', $this->ID(), $sourceValue),
'name' => $this->getName(),
'value' => $sourceValue,
static::$selected_attr => $this->isSourceSelected($source),
);
return $this->getAttributesHTML($attrs);
}
/**
* @return boolean Whether this source is selected in the field
*/
public function isSourceSelected($source) {
return $this->dataValue() == $this->getSourceValue($source);
}
/**
* @return string The "value" to use for this source item.
*/
public function getSourceValue($source) {
// 99% of the time...
if(!$this->sourceValueGetter && $source instanceof DataObject) {
return $source->ID;
}
return $this->sourceValueGetter($source);
}
/**
* Prepares data for the view to render in to a table.
* @return string
*/
public function Field($properties = array()) {
$options = array();
$columns = $this->getSourceColumns();
// 99% of the time it'll be a DataList, so use convention!
if($this->getSource() instanceof DataList && empty($columns)) {
$colClass = $this->getSource()->dataClass();
$columns = $colClass::config()->get('summary_fields');
}
foreach($this->getSource() as $id => $sourceObject) {
$fields = array();
foreach($columns as $colName => $colTitle) {
if($sourceObject->hasMethod($colName)) {
$value = $sourceObject->$colName();
}
else {
$value = $sourceObject->getField($colName);
}
$fields[] = array('Value' => $value);
}
$options[] = array(
'Object' => $sourceObject,
'FieldAttrs' => $this->getFieldAttrs($sourceObject),
'Fields' => new ArrayList($fields),
);
}
$viewColumns = array();
// Convert these in to template-friendly variables
foreach($columns as $field => $title) {
$viewColumns[] = array(
'Field' => $field,
'Title' => $title,
);
}
$tplOptions = array_merge($properties, array(
'Columns' => new ArrayList($viewColumns),
'Options' => new ArrayList($options),
));
return $this->customise($tplOptions)->renderWith(
$this->getTemplates()
);
}
}
<table>
<tr>
<td></td>
<% loop $Columns %>
<th>$Title</th>
<% end_loop %>
</tr>
<% loop $Options %>
<tr>
<td><input type="radio" $FieldAttrs></td>
<% loop $Fields %>
<td>$Value</td>
<% end_loop %>
</tr>
<% end_loop %>
</table>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment