Skip to content

Commit

Permalink
NEW Move form schema logic into FormSchemaController
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Nov 13, 2024
1 parent f7ff272 commit 0fb29a4
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 224 deletions.
162 changes: 162 additions & 0 deletions code/FormSchemaController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php

namespace SilverStripe\Admin;

use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Validation\ValidationResult;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\Schema\FormSchema;

/**
* The base class for controllers in the CMS that need access to form schema functionality.
*/
abstract class FormSchemaController extends AdminController
{
/**
* Form schema header identifier
*/
public const SCHEMA_HEADER = 'X-Formschema-Request';

private static array $allowed_actions = [
'schema',
'methodSchema',
];

private static array $url_handlers = [
'GET schema/$FormName/$ItemID/$OtherItemID' => 'schema',
'GET methodSchema/$Method/$FormName/$ItemID' => 'methodSchema',
];

private static array $dependencies = [
'FormSchema' => '%$' . FormSchema::class,
];

/**
* Current form schema helper
*/
private ?FormSchema $schema = null;

/**
* Get form schema helper
*/
public function getFormSchema(): FormSchema
{
if (!$this->schema) {
$this->schema = FormSchema::singleton();
}
return $this->schema;
}

/**
* Set form schema helper for this controller
*/
public function setFormSchema(FormSchema $schema): static
{
$this->schema = $schema;
return $this;
}

/**
* Gets a JSON schema representing the current edit form.
*/
public function schema(HTTPRequest $request): HTTPResponse
{
$formName = $request->param('FormName');
$itemID = $request->param('ItemID');

if (!$formName) {
$this->jsonError(400, 'Missing request params');
}

// The getter can accept an ID where the main form action wouldn't
$formMethod = "get{$formName}";
if (!$this->hasMethod($formMethod)) {
$formMethod = $formName;
if (!$this->hasMethod($formMethod)) {
$this->jsonError(404, 'Form not found');
}
}

if (!$this->hasAction($formName)) {
$this->jsonError(401, 'Form not accessible');
}

if ($itemID) {
$form = $this->{$formMethod}($itemID);
} else {
$form = $this->{$formMethod}();
}
$schemaID = $request->getURL();
return $this->getSchemaResponse($schemaID, $form);
}

/**
* Get the form schema from a given method.
* The method must return a Form.
*/
public function methodSchema(HTTPRequest $request): HTTPResponse
{
$method = $request->param('Method');
$formName = $request->param('FormName');
$itemID = $request->param('ItemID');

if (!$formName || !$method) {
$this->jsonError(400, 'Missing request params');
}

if (!$this->hasMethod($method)) {
$this->jsonError(404, 'Method not found');
}
if (!$this->hasAction($method)) {
$this->jsonError(401, 'Method not accessible');
}

$methodItem = $this->{$method}();
if (!$methodItem->hasMethod($formName)) {
$this->jsonError(404, 'Form not found');
}
if (!$methodItem->hasAction($formName)) {
$this->jsonError(401, 'Form not accessible');
}

$form = $methodItem->{$formName}($itemID);
$schemaID = $request->getURL();

return $this->getSchemaResponse($schemaID, $form);
}

/**
* Check if the current request has a X-Formschema-Request header set.
* Used by conditional logic that responds to validation results
*/
protected function getSchemaRequested(): bool
{
$parts = $this->getRequest()->getHeader(static::SCHEMA_HEADER);
return !empty($parts);
}

/**
* Generate schema for the given form based on the X-Formschema-Request header value
*
* @param string $schemaID ID for this schema. Required.
* @param Form|null $form Required for 'state' or 'schema' response
* @param ValidationResult $errors Required for 'error' response
* @param array $extraData Any extra data to be merged with the schema response
*/
protected function getSchemaResponse(string $schemaID, ?Form $form = null, ValidationResult $errors = null, array $extraData = []): HTTPResponse
{
$parts = $this->getRequest()->getHeader(static::SCHEMA_HEADER);
$data = $this
->getFormSchema()
->getMultipartSchema($parts, $schemaID, $form, $errors);

if ($extraData) {
$data = array_merge($data, $extraData);
}

$response = new HTTPResponse(json_encode($data));
$response->addHeader('Content-Type', 'application/json');
return $response;
}
}
163 changes: 4 additions & 159 deletions code/LeftAndMain.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,8 @@
* This is essentially an abstract class which should be subclassed.
* See {@link CMSMain} for a good example.
*/
class LeftAndMain extends AdminController implements PermissionProvider
class LeftAndMain extends FormSchemaController implements PermissionProvider
{

/**
* Form schema header identifier
*/
const SCHEMA_HEADER = 'X-Formschema-Request';

/**
* Enable front-end debugging (increases verbosity) in dev mode.
* Will be ignored in live environments.
Expand Down Expand Up @@ -98,7 +92,6 @@ class LeftAndMain extends AdminController implements PermissionProvider
*
* @config
* @var string
* @deprecated 5.4.0 Will be renamed to model_class
*/
private static $model_class = null;

Expand All @@ -110,32 +103,16 @@ class LeftAndMain extends AdminController implements PermissionProvider
'save',
'printable',
'show',
'Modals',
'EditForm',
'AddForm',
'batchactions',
'BatchActionsForm',
'schema',
'methodSchema',
];

private static $url_handlers = [
'GET schema/$FormName/$ItemID/$OtherItemID' => 'schema',
'GET methodSchema/$Method/$FormName/$ItemID' => 'methodSchema',
];

private static $dependencies = [
'FormSchema' => '%$' . FormSchema::class,
'VersionProvider' => '%$' . VersionProvider::class,
];

/**
* Current form schema helper
*
* @var FormSchema
*/
protected $schema = null;

/**
* Current pageID for this request
*
Expand Down Expand Up @@ -330,141 +307,19 @@ public function getClientConfig(): array
{
// Add WYSIWYG link form schema before extensions are applied
$this->beforeExtending('updateClientConfig', function (array &$clientConfig): void {
$modalController = ModalController::singleton();
$clientConfig['form'] = [
'EditorExternalLink' => [
'schemaUrl' => $this->Link('methodSchema/Modals/EditorExternalLink'),
'schemaUrl' => $modalController->Link('schema/EditorExternalLink'),
],
'EditorEmailLink' => [
'schemaUrl' => $this->Link('methodSchema/Modals/EditorEmailLink'),
'schemaUrl' => $modalController->Link('schema/EditorEmailLink'),
],
];
});
return parent::getClientConfig();
}

/**
* Get form schema helper
*
* @return FormSchema
*/
public function getFormSchema()
{
return $this->schema;
}

/**
* Set form schema helper for this controller
*
* @param FormSchema $schema
* @return $this
*/
public function setFormSchema(FormSchema $schema)
{
$this->schema = $schema;
return $this;
}

/**
* Gets a JSON schema representing the current edit form.
*/
public function schema(HTTPRequest $request): HTTPResponse
{
$formName = $request->param('FormName');
$itemID = $request->param('ItemID');

if (!$formName) {
$this->jsonError(400, 'Missing request params');
}

$formMethod = "get{$formName}";
if (!$this->hasMethod($formMethod)) {
$this->jsonError(404, 'Form not found');
}

if (!$this->hasAction($formName)) {
$this->jsonError(401, 'Form not accessible');
}

if ($itemID) {
$form = $this->{$formMethod}($itemID);
} else {
$form = $this->{$formMethod}();
}
$schemaID = $request->getURL();
return $this->getSchemaResponse($schemaID, $form);
}

/**
* Get the form schema from a given method.
* The method must return a Form.
*/
public function methodSchema(HTTPRequest $request): HTTPResponse
{
$method = $request->param('Method');
$formName = $request->param('FormName');
$itemID = $request->param('ItemID');

if (!$formName || !$method) {
$this->jsonError(400, 'Missing request params');
}

if (!$this->hasMethod($method)) {
$this->jsonError(404, 'Method not found');
}
if (!$this->hasAction($method)) {
$this->jsonError(401, 'Method not accessible');
}

$methodItem = $this->{$method}();
if (!$methodItem->hasMethod($formName)) {
$this->jsonError(404, 'Form not found');
}
if (!$methodItem->hasAction($formName)) {
$this->jsonError(401, 'Form not accessible');
}

$form = $methodItem->{$formName}($itemID);
$schemaID = $request->getURL();

return $this->getSchemaResponse($schemaID, $form);
}

/**
* Check if the current request has a X-Formschema-Request header set.
* Used by conditional logic that responds to validation results
*
* @return bool
*/
protected function getSchemaRequested()
{
$parts = $this->getRequest()->getHeader(static::SCHEMA_HEADER);
return !empty($parts);
}

/**
* Generate schema for the given form based on the X-Formschema-Request header value
*
* @param string $schemaID ID for this schema. Required.
* @param Form $form Required for 'state' or 'schema' response
* @param ValidationResult $errors Required for 'error' response
* @param array $extraData Any extra data to be merged with the schema response
*/
protected function getSchemaResponse($schemaID, $form = null, ValidationResult $errors = null, $extraData = []): HTTPResponse
{
$parts = $this->getRequest()->getHeader(static::SCHEMA_HEADER);
$data = $this
->getFormSchema()
->getMultipartSchema($parts, $schemaID, $form, $errors);

if ($extraData) {
$data = array_merge($data, $extraData);
}

$response = new HTTPResponse(json_encode($data));
$response->addHeader('Content-Type', 'application/json');
return $response;
}

/**
* Try to redirect to an appropriate admin section if we can't access this one
*/
Expand Down Expand Up @@ -1254,16 +1109,6 @@ public function EmptyForm()
return $form;
}

/**
* Handler for all global modals
*
* @return ModalController
*/
public function Modals()
{
return ModalController::create($this, "Modals");
}

/**
* Renders a panel containing tools which apply to all displayed
* "content" (mostly through {@link EditForm()}), for example a tree navigation or a filter panel.
Expand Down
Loading

0 comments on commit 0fb29a4

Please sign in to comment.