-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NEW LinkFieldController to handle FormSchema
- Loading branch information
1 parent
f0a3b25
commit a10ceb0
Showing
4 changed files
with
182 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,4 @@ | |
|
||
// Avoid creating global variables | ||
call_user_func(function () { | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
<?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\LinkField\Type\Registry; | ||
use SilverStripe\Security\SecurityToken; | ||
use SilverStripe\ORM\ValidationResult; | ||
|
||
/** | ||
* this will hopefully get replaced by a more generic centralised FormSchemaController | ||
*/ | ||
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? | ||
]; | ||
|
||
private static $allowed_actions = [ | ||
'apiSaveForm', | ||
// 'linkForm' needs to defined for the benefit of LeftAndMain::schema() even though | ||
// 'getLinkForm()' is the method that's ultimately called | ||
// it's pretty unintuitive and could be made better, though it works for now | ||
'linkForm', | ||
]; | ||
|
||
/** | ||
* TODO have temporarily disabled for easier dev | ||
*/ | ||
public function init() | ||
{ | ||
parent::init(); | ||
SecurityToken::disable(); | ||
} | ||
|
||
/** | ||
* 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(); | ||
} | ||
|
||
$list = (new Registry)->list(); | ||
array_walk($list, function (&$item, $key) { | ||
$item = $item->ClassName; | ||
}); | ||
$typesToTypeKeys = array_flip($list); | ||
$typesToTypeKeys[Link::class] = 'link'; | ||
$className = $obj->ClassName; | ||
$linkTypeKey = $typesToTypeKeys[$className]; | ||
|
||
// add these headers to make dev life easier (should be default anyway) | ||
$this->getRequest()->addHeader('X-Formschema-Request', 'auto,schema,state,errors'); | ||
|
||
/** @var Form $form */ | ||
$form = $formFactory->getForm($this, "LinkForm_$linkID", [ | ||
'LinkType' => $obj, | ||
'LinkTypeKey' => $linkTypeKey, | ||
|
||
// do we need this? | ||
'Record' => $obj, | ||
|
||
// the following is here for (silverstripe/admin) LinkFormFactory::getRequiredContext() | ||
'RequireLinkText' => false | ||
]); | ||
$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 | ||
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 | ||
$response = $this->getResponse(); | ||
$response->setBody(json_encode([ | ||
'status' => 'success', | ||
'updated' => $updated, | ||
])); | ||
$response->addHeader('Content-Type', 'application/json'); | ||
return $response; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters