Skip to content

Commit

Permalink
NEW LinkFieldController to handle FormSchema
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Oct 24, 2023
1 parent f0a3b25 commit 6011f97
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 1 deletion.
1 change: 0 additions & 1 deletion _config.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@

// Avoid creating global variables
call_user_func(function () {

});
137 changes: 137 additions & 0 deletions src/Controllers/LinkFieldController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

namespace SilverStripe\LinkField\Controllers;

use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\LinkField\Form\FormFactory;
use SilverStripe\Forms\Form;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\Security\SecurityToken;
use SilverStripe\ORM\ValidationResult;

class LinkFieldController extends LeftAndMain
{
private static $url_segment = 'linkfield';

// copying ElementalAreaController
private static $url_handlers = [
// API access points with structured data
'POST api/saveForm/$ID' => 'apiSaveForm',
# '$FormName/field/$FieldName' => 'formAction', // do we need this?
];

/**
* Routed to be LeftAndMain::schema()
* /admin/linkfield/schema/linkForm/<linkID>
*
* Adapted from ElementalAreaController::getElementForm()
*
* @param int $elementID -- TODO not sure if this is required or not
* @return Form
*/
public function getLinkForm(int $linkID): Form
{
$formFactory = FormFactory::create();

// this is a hackish way to get the correct DataObject type, I'm not sure what the clean method is
$obj = Link::get()->byID($linkID);
if ($obj && $obj->exists()) {
$className = $obj->ClassName;
$obj = $className::get()->byID($linkID);
} else {
$obj = Link::create();
}

/** @var Form $form */
$form = $formFactory->getForm($this, "LinkForm_$linkID", ['Record' => $obj]);
$form->addExtraClass('link-editor-editform__form');

if (!$obj->canEdit()) {
$form->makeReadonly();
}


return $form;
}

/**
* Code adapted from https://github.com/silverstripe/silverstripe-elemental/pull/1113/files#diff-942115e4b8f6030e4d72ebc2b3a0772ec65e5dfcd08fbd0e677c70d1231daf28R189
*
* Save an inline edit form for a Link
*/
public function apiSaveForm(HTTPRequest $request): HTTPResponse
{
$id = $this->param('ID'); // $this->urlParams['ID']
// Validate required input data
if (!$id) {
$this->jsonError(400);
}

$data = $request->postVars();
// $data = json_decode($request->getBody(), true);
if (empty($data)) {
$this->jsonError(400);
}

// Check security token - TODO have temporarily disabled for easier dev
if (false) {
if (!SecurityToken::inst()->checkRequest($request)) {
$this->jsonError(400);
}
}

/** @var BaseElement $element */
$link = Link::get()->byID($id);
// Ensure the element can be edited by the current user
if (!$link || !$link->canEdit()) {
$this->jsonError(403);
}

// get form and populate it with POSTed data
$form = $this->getLinkForm($id);
$form->loadDataFrom($data);

// validate the Form
$validationResult = $form->validationResult();

// validate the DataObject
$element->updateFromFormData($data);
$validationResult->combineAnd($element->validate());

// handle validation failure and sent json formschema as response
if (!$validationResult->isValid()) {
// add headers to the request here so you don't need to do it in the client
// in the future I'd like these be the default response from formschema if
// the header wasn't defined
$request->addHeader('X-Formschema-Request', 'auto,schema,state,errors');
// generate schema response
$url = $this->getRequest()->getURL(); // admin/elemntal-area/api/saveForm/3
$response = $this->getSchemaResponse($url, $form, $validationResult);
// returning a 400 means that FormBuilder.js::handleSubmit() submitFn()
// that will end up in the catch() .. throw error block and the error
// will just end up in the javascript console
// $response->setStatusCode(400);
//
// return a 200 for now just to get things to work even though it's
// clearly the wrong code. Will require a PR to admin to fix this
$response->setStatusCode(200);
return $response;
}

$updated = false;
if ($element->isChanged()) {
$element->write();
// Track changes so we can return to the client
$updated = true;
}

// create and send success json response
return HTTPResponse::create(json_encode([
'status' => 'success',
'updated' => $updated,
]))->addHeader('Content-Type', 'application/json');
}
}

0 comments on commit 6011f97

Please sign in to comment.