API CHANGE: Added GridField_URLHandler component interface.

This commit is contained in:
Sam Minnee 2012-01-09 18:47:31 +13:00
parent 1e1e3a2d80
commit cb13299cf9
3 changed files with 126 additions and 3 deletions

View File

@ -194,11 +194,55 @@ A `GridField_DataManipulator` component can modify the data list. For example,
* **`getManipulatedData(GridField $gridField, SS_List $dataList)`:** Given this grid's data list, return an updated list to be used with this grid.
### GridField_URLProvider
### GridField_URLHandler
**COMING SOON**
Sometimes an action isn't enough: you need to provide additional support URLs for the grid. These URLs may return user-visible content, for example a pop-up form for editing a record's details, or they may be support URLs for front-end functionality, for example a URL that will return JSON-formatted data for a javascript grid control.
This interface isn't implemented yet, but will let you define a component that provides additional support URLs for the grid. These URLs may return user-visible content, for example a pop-up form for editing a record's details, or they may be support URLs for front-end functionality, for example a URL that will return JSON-formatted data for a javascript grid control.
To build these components, you should implement the `GridField_URLHandler` interface. It only specifies one method: `getURLHandlers($gridField)`. This method should return an array similar to the `RequestHandler::$url_handlers` static. The action handlers should also be defined on the component; they will be passed `$gridField` and `$request`.
Here is an example in full. The actual implementation of the view and edit forms isn't included.
:::php
/**
* Provides view and edit forms at GridField-specific URLs. These can be placed into pop-ups by an appropriate front-end.
*
* The URLs provided will be off the following form:
* - <FormURL>/field/<GridFieldName>/item/<RecordID>
* - <FormURL>/field/<GridFieldName>/item/<RecordID>/edit
*/
class GridFieldPopupForms implements GridField_URLHandler {
function getURLHandlers($gridField) {
return array(
'item/$ID' => 'handleItem',
);
}
function handleItem($gridField, $request) {
$record = $gridField->getList()->byId($request->param("ID"));
return new GridFieldPopupForm_ItemRequest($gridField, $this, $record);
}
}
class GridFieldPopupForm_ItemRequest extends RequestHandler {
protected $gridField;
protected $component;
protected $record;
function __construct($gridField, $component, $record) {
$this->gridField = $gridField;
$this->component = $gridField;
$this->record = $record;
parent::__construct();
}
function index() {
echo "view form for record #" . $record->ID;
}
function edit() {
echo "edit form for record #" . $record->ID;
}
}
## Other tools

View File

@ -461,6 +461,74 @@ class GridField extends FormField {
}
throw new InvalidArgumentException("Can't handle action '$actionName'");
}
/**
* Custom request handler that will check component handlers before proceeding to the default implementation.
*
* @todo There is too much code copied from RequestHandler here.
*/
function handleRequest(SS_HTTPRequest $request, DataModel $model) {
if($this->brokenOnConstruct) {
user_error("parent::__construct() needs to be called on {$handlerClass}::__construct()", E_USER_WARNING);
}
$this->request = $request;
$this->setModel($model);
///
foreach($this->components as $component) {
if(!($component instanceof GridField_URLHandler)) {
continue;
}
$urlHandlers = $component->getURLHandlers($this);
if($urlHandlers) foreach($urlHandlers as $rule => $action) {
if($params = $request->match($rule, true)) {
// Actions can reference URL parameters, eg, '$Action/$ID/$OtherID' => '$Action',
if($action[0] == '$') $action = $params[substr($action,1)];
if(!method_exists($component, 'checkAccessAction') || $component->checkAccessAction($action)) {
if(!$action) {
$action = "index";
} else if(!is_string($action)) {
throw new LogicException("Non-string method name: " . var_export($action, true));
}
try {
$result = $component->$action($this, $request);
} catch(SS_HTTPResponse_Exception $responseException) {
$result = $responseException->getResponse();
}
if($result instanceof SS_HTTPResponse && $result->isError()) {
return $result;
}
if($this !== $result && !$request->isEmptyPattern($rule) && is_object($result) && $result instanceof RequestHandler) {
$returnValue = $result->handleRequest($request, $model);
if(is_array($returnValue)) {
throw new LogicException("GridField_URLHandler handlers can't return arrays");
}
return $returnValue;
// If we return some other data, and all the URL is parsed, then return that
} else if($request->allParsed()) {
return $result;
// But if we have more content on the URL and we don't know what to do with it, return an error.
} else {
return $this->httpError(404, "I can't handle sub-URLs of a " . get_class($result) . " object.");
}
}
}
}
}
return parent::handleRequest($request, $model);
}
}

View File

@ -41,4 +41,15 @@ interface GridField_DataManipulator extends GridFieldComponent {
* Return the new DataList.
*/
function getManipulatedData(GridField $gridField, SS_List $dataList);
}
interface GridField_URLHandler extends GridFieldComponent {
/**
* Return URLs to be handled by this grid field, in an array the same form as $url_handlers.
*
* Handler methods will be called on the component, rather than the grid field.
*
* The handlers will be passed two arguments, $gridField and $request
*/
function getURLHandlers($gridField);
}