Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

API CHANGE: Added GridField_URLHandler component interface.

  • Loading branch information...
commit cb13299cf936ac8636cf9d1f28d76f8b328cd9e0 1 parent 1e1e3a2
@sminnee sminnee authored
View
50 docs/en/topics/grid-field.md
@@ -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
68 forms/gridfield/GridField.php
@@ -461,6 +461,74 @@ public function handleAction($actionName, $args, $data) {
}
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
11 forms/gridfield/GridFieldComponent.php
@@ -41,4 +41,15 @@ function handleAction(GridField $gridField, $actionName, $arguments, $data);
* 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);
}
Please sign in to comment.
Something went wrong with that request. Please try again.