mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Initial Form Field Schema implementation
- Adds FormSchema class - Adds FormSchema dependency to LeftAndMain via Injector - Adds schema allowed_action method to LeftAndMain for generating Form schemas - Adds FormFieldSchemaTrait to for schema getters and setters on FormFields
This commit is contained in:
parent
827d989836
commit
afccef718c
@ -1,6 +1,9 @@
|
|||||||
---
|
---
|
||||||
Name: coreconfig
|
Name: coreconfig
|
||||||
---
|
---
|
||||||
|
Injector:
|
||||||
|
FormSchema:
|
||||||
|
class: SilverStripe\Forms\Schema\FormSchema
|
||||||
Upload:
|
Upload:
|
||||||
# Replace an existing file rather than renaming the new one.
|
# Replace an existing file rather than renaming the new one.
|
||||||
replaceFile: false
|
replaceFile: false
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
* @subpackage admin
|
* @subpackage admin
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use SilverStripe\Forms\Schema\FormSchema;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LeftAndMain is the parent class of all the two-pane views in the CMS.
|
* LeftAndMain is the parent class of all the two-pane views in the CMS.
|
||||||
* If you are wanting to add more areas to the CMS, you can do it by subclassing LeftAndMain.
|
* If you are wanting to add more areas to the CMS, you can do it by subclassing LeftAndMain.
|
||||||
@ -84,7 +86,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private static $allowed_actions = array(
|
private static $allowed_actions = [
|
||||||
'index',
|
'index',
|
||||||
'save',
|
'save',
|
||||||
'savetreenode',
|
'savetreenode',
|
||||||
@ -97,7 +99,12 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
'AddForm',
|
'AddForm',
|
||||||
'batchactions',
|
'batchactions',
|
||||||
'BatchActionsForm',
|
'BatchActionsForm',
|
||||||
);
|
'schema',
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $dependencies = [
|
||||||
|
'schema' => '%$FormSchema'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @config
|
* @config
|
||||||
@ -169,6 +176,15 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
*/
|
*/
|
||||||
protected $responseNegotiator;
|
protected $responseNegotiator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a JSON schema representing the current edit form.
|
||||||
|
*
|
||||||
|
* @return SS_HTTPResponse
|
||||||
|
*/
|
||||||
|
public function schema() {
|
||||||
|
return $this->schema->getSchema($this->getEditForm());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Member $member
|
* @param Member $member
|
||||||
* @return boolean
|
* @return boolean
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
*/
|
*/
|
||||||
class FormField extends RequestHandler {
|
class FormField extends RequestHandler {
|
||||||
|
|
||||||
|
use SilverStripe\Forms\Schema\FormFieldSchemaTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Form
|
* @var Form
|
||||||
*/
|
*/
|
||||||
@ -80,7 +82,7 @@ class FormField extends RequestHandler {
|
|||||||
* @config
|
* @config
|
||||||
* @var array $default_classes The default classes to apply to the FormField
|
* @var array $default_classes The default classes to apply to the FormField
|
||||||
*/
|
*/
|
||||||
private static $default_classes = array();
|
private static $default_classes = [];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,7 +164,22 @@ class FormField extends RequestHandler {
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $attributes = array();
|
protected $attributes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of front-end component to render the FormField as.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $schemaComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structured schema data representing the FormField.
|
||||||
|
* Used to render the FormField as a ReactJS Component on the front-end.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $schemaData = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a field name and converts camelcase to spaced words. Also resolves combined field
|
* Takes a field name and converts camelcase to spaced words. Also resolves combined field
|
||||||
|
81
forms/FormFieldSchemaTrait.php
Normal file
81
forms/FormFieldSchemaTrait.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Schema;
|
||||||
|
|
||||||
|
trait FormFieldSchemaTrait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the component type the FormField will be rendered as on the front-end.
|
||||||
|
*
|
||||||
|
* @param string $componentType
|
||||||
|
* @return FormField
|
||||||
|
*/
|
||||||
|
public function setSchemaComponent($componentType) {
|
||||||
|
$this->schemaComponent = $componentType;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of front-end component the FormField will be rendered as.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSchemaComponent() {
|
||||||
|
return $this->schemaComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the schema data used for rendering the field on the front-end.
|
||||||
|
* Merges the passed array with the current `$schemaData` or {@link getSchemaDataDefaults()}.
|
||||||
|
* Any passed keys that are not defined in {@link getSchemaDataDefaults()} are ignored.
|
||||||
|
* If you want to pass around ad hoc data use the `data` array e.g. pass `['data' => ['myCustomKey' => 'yolo']]`.
|
||||||
|
*
|
||||||
|
* @param array $schemaData - The data to be merged with $this->schemaData.
|
||||||
|
* @return FormField
|
||||||
|
*
|
||||||
|
* @todo Add deep merging of arrays like `data` and `attributes`.
|
||||||
|
*/
|
||||||
|
public function setSchemaData($schemaData = []) {
|
||||||
|
$current = $this->getSchemaData();
|
||||||
|
|
||||||
|
$this->schemaData = array_merge($current, array_intersect_key($schemaData, $current));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the schema data used to render the FormField on the front-end.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSchemaData() {
|
||||||
|
return array_merge($this->getSchemaDataDefaults(), $this->schemaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the defaults for $schemaData.
|
||||||
|
* The keys defined here are immutable, meaning undefined keys passed to {@link setSchemaData()} are ignored.
|
||||||
|
* Instead the `data` array should be used to pass around ad hoc data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getSchemaDataDefaults() {
|
||||||
|
return [
|
||||||
|
'type' => $this->class,
|
||||||
|
'component' => $this->getSchemaComponent(),
|
||||||
|
'id' => $this->ID,
|
||||||
|
'holder_id' => null,
|
||||||
|
'name' => $this->getName(),
|
||||||
|
'title' => $this->Title(),
|
||||||
|
'source' => null,
|
||||||
|
'extraClass' => $this->ExtraClass(),
|
||||||
|
'description' => $this->getDescription(),
|
||||||
|
'rightTitle' => $this->RightTitle(),
|
||||||
|
'leftTitle' => $this->LeftTitle(),
|
||||||
|
'readOnly' => $this->isReadOnly(),
|
||||||
|
'disabled' => $this->isDisabled(),
|
||||||
|
'customValidationMessage' => $this->getCustomValidationMessage(),
|
||||||
|
'attributes' => [],
|
||||||
|
'data' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
56
forms/FormSchema.php
Normal file
56
forms/FormSchema.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Schema;
|
||||||
|
|
||||||
|
use Convert;
|
||||||
|
use Form;
|
||||||
|
|
||||||
|
class FormSchema {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the schema for this form as a nested array.
|
||||||
|
*
|
||||||
|
* @param Form $form
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSchema(Form $form) {
|
||||||
|
$request = $form->controller()->getRequest();
|
||||||
|
$params = $request->AllParams();
|
||||||
|
|
||||||
|
$schema = [
|
||||||
|
'name' => $form->getName(),
|
||||||
|
'id' => isset($params['ID']) ? $params['ID'] : null,
|
||||||
|
'action' => isset($params['Action']) ? $params['Action'] : null,
|
||||||
|
'method' => $form->controller()->getRequest()->HttpMethod(),
|
||||||
|
'schema_url' => $request->getUrl(),
|
||||||
|
'attributes' => $form->getAttributes(),
|
||||||
|
'data' => [],
|
||||||
|
'fields' => [],
|
||||||
|
'actions' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($form->Actions() as $action) {
|
||||||
|
$schema['actions'][] = $action->getSchemaData();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($form->Fields() as $fieldList) {
|
||||||
|
foreach ($fieldList->getForm()->fields()->dataFields() as $field) {
|
||||||
|
$schema['fields'][] = $field->getSchemaData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert::raw2json($schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current state of this form as a nested array.
|
||||||
|
*
|
||||||
|
* @param From $form
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getState(Form $form) {
|
||||||
|
$state = ['state' => []];
|
||||||
|
|
||||||
|
return Convert::raw2json($state);
|
||||||
|
}
|
||||||
|
}
|
@ -241,6 +241,43 @@ class FormFieldTest extends SapphireTest {
|
|||||||
$this->assertArrayHasKey('extended', $field->getAttributes());
|
$this->assertArrayHasKey('extended', $field->getAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSetSchemaComponent() {
|
||||||
|
$field = new FormField('MyField');
|
||||||
|
$field = $field->setSchemaComponent('MyComponent');
|
||||||
|
$component = $field->getSchemaComponent();
|
||||||
|
$this->assertEquals('MyComponent', $component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetSchemaDataDefaults() {
|
||||||
|
$field = new FormField('MyField');
|
||||||
|
$schema = $field->getSchemaDataDefaults();
|
||||||
|
$this->assertInternalType('array', $schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetSchemaData() {
|
||||||
|
$field = new FormField('MyField');
|
||||||
|
$schema = $field->getSchemaData();
|
||||||
|
$this->assertEquals('MyField', $schema['name']);
|
||||||
|
|
||||||
|
// Make sure the schema data is up-to-date with object properties.
|
||||||
|
$field->setName('UpdatedField');
|
||||||
|
$schema = $field->getSchemaData();
|
||||||
|
$this->assertEquals($field->getName(), $schema['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetSchemaData() {
|
||||||
|
$field = new FormField('MyField');
|
||||||
|
|
||||||
|
// Make sure the user can update values.
|
||||||
|
$field = $field->setSchemaData(['name' => 'MyUpdatedField']);
|
||||||
|
$schema = $field->getSchemaData();
|
||||||
|
$this->assertEquals($schema['name'], 'MyUpdatedField');
|
||||||
|
|
||||||
|
// Make user the user can't define custom keys on the schema.
|
||||||
|
$field = $field->setSchemaData(['myCustomKey' => 'yolo']);
|
||||||
|
$schema = $field->getSchemaData();
|
||||||
|
$this->assertEquals(array_key_exists('myCustomKey', $schema), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
62
tests/forms/FormSchemaTest.php
Normal file
62
tests/forms/FormSchemaTest.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use SilverStripe\Forms\Schema\FormSchema;
|
||||||
|
|
||||||
|
class FormSchemaTest extends SapphireTest {
|
||||||
|
|
||||||
|
public function testGetSchema() {
|
||||||
|
$form = new Form(new Controller(), 'TestForm', new FieldList(), new FieldList());
|
||||||
|
$formSchema = new FormSchema();
|
||||||
|
$expectedJSON = json_encode([
|
||||||
|
'name' => 'TestForm',
|
||||||
|
'id' => null,
|
||||||
|
'action' => null,
|
||||||
|
'method' => '',
|
||||||
|
'schema_url' => '',
|
||||||
|
'attributes' => [
|
||||||
|
'id' => 'Form_TestForm',
|
||||||
|
'action' => 'Controller/TestForm',
|
||||||
|
'method' => 'POST',
|
||||||
|
'enctype' => 'application/x-www-form-urlencoded',
|
||||||
|
'target' => null,
|
||||||
|
'class' => ''
|
||||||
|
],
|
||||||
|
'data' => [],
|
||||||
|
'fields' => [
|
||||||
|
[
|
||||||
|
'type' => "HiddenField",
|
||||||
|
'component' => null,
|
||||||
|
'id' => null,
|
||||||
|
'holder_id' => null,
|
||||||
|
'name' => 'SecurityID',
|
||||||
|
'title' => 'Security ID',
|
||||||
|
'source' => null,
|
||||||
|
'extraClass' => 'hidden',
|
||||||
|
'description' => null,
|
||||||
|
'rightTitle' => null,
|
||||||
|
'leftTitle' => null,
|
||||||
|
'readOnly' => false,
|
||||||
|
'disabled' => false,
|
||||||
|
'customValidationMessage' => '',
|
||||||
|
'attributes' => [],
|
||||||
|
'data' => []
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'actions' => []
|
||||||
|
]);
|
||||||
|
|
||||||
|
$schema = $formSchema->getSchema($form);
|
||||||
|
|
||||||
|
$this->assertJsonStringEqualsJsonString($expectedJSON, $schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetState() {
|
||||||
|
$form = new Form(new Controller(), 'TestForm', new FieldList(), new FieldList());
|
||||||
|
$formSchema = new FormSchema();
|
||||||
|
$expectedJSON = json_encode(['state' => []]);
|
||||||
|
|
||||||
|
$state = $formSchema->getState($form);
|
||||||
|
|
||||||
|
$this->assertJsonStringEqualsJsonString($expectedJSON, $state);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user