Skip to content

Instantly share code, notes, and snippets.

@anselmdk
Created November 30, 2016 18:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anselmdk/c042819dce6e55587fbae12088e3dcb0 to your computer and use it in GitHub Desktop.
Save anselmdk/c042819dce6e55587fbae12088e3dcb0 to your computer and use it in GitHub Desktop.
SilverStripe 4 React Form Schema on frontend POC
import React from 'react'
import ReactDOM from 'react-dom'
import Field from './Field';
import FormBuilder from '../../../framework/admin/client/src/components/FormBuilder/FormBuilder'
import Form from '../../../framework/admin/client/src/components/Form/Form';
const schemaUrl = '/formschematest/schema/TestForm';
$.get(schemaUrl, function(data) {
const props = {
form: 'MyForm',
schema: data,
baseFormComponent: Form,
baseFieldComponent: Field
};
ReactDOM.render(
<div>
<FormBuilder {...props} />
</div>,
document.getElementById('approot')
);
});
<?php
use SilverStripe\Forms\FormFactory;
use SilverStripe\Forms\DefaultFormFactory;
use SilverStripe\Control\Controller;
/**
* AppFormFactory
*
* @author Anselm Christophersen <ac@anselm.dk>
* @date November 2016
*/
class AppFormFactory extends DefaultFormFactory {
public function getForm(Controller $controller, $name = FormFactory::DEFAULT_NAME, $context = [])
{
$form = parent::getForm($controller, $name, $context);
return $form;
}
protected function getFormFields(Controller $controller, $name, $context = [])
{
$fields = $context['Record']->scaffoldFormFields();
$this->invokeWithExtensions('updateFormFields', $fields, $controller, $name, $context);
return $fields;
}
}
import React, { Component } from 'react';
import TextField from 'components/TextField/TextField';
import HiddenField from 'components/HiddenField/HiddenField';
import CheckboxField from 'components/CheckboxField/CheckboxField';
import CheckboxSetField from 'components/CheckboxSetField/CheckboxSetField';
import OptionsetField from 'components/OptionsetField/OptionsetField';
import GridField from 'components/GridField/GridField';
import SingleSelectField from 'components/SingleSelectField/SingleSelectField';
class Field extends Component {
constructor(props) {
super(props);
this.state = {
value: null
};
}
onChange(event, options) {
this.setState({
value: options.value
});
}
render() {
let value = this.state.value;
if (!value) {
value = this.props.value;
}
const props = {...this.props, ...{
value: value,
onChange: this.onChange.bind(this)
}};
switch (this.props.type) {
case 'Text':
case 'DateTime':
return <TextField {...props} />
case 'Hidden':
return <HiddenField {...props} />
case 'SingleSelect':
return <SingleSelectField {...props} />
//case 'Custom':
// return this.components.GridField;
//case 'Structural':
// return this.components.CompositeField;
case 'Boolean':
return <CheckboxField {...props} />
// return this.components.CheckboxField;
//case 'MultiSelect':
// return this.components.CheckboxSetField;
default:
return <div>
{this.props.type}
</div>;
}
}
}
export default Field;
<?php
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\DefaultFormFactory;
use SilverStripe\Forms\Form;
/**
* FormSchemaTestController
* Much this is taken from {@see LeftAndMain}
*
* @author Anselm Christophersen <ac@anselm.dk>
* @date November 2016
*/
class FormSchemaTestController extends \SilverStripe\Control\Controller {
/**
* @var array
*/
private static $allowed_actions = array(
'schema',
'TestForm'
);
private static $url_handlers = [
'GET schema/$FormName/$ItemID' => 'schema'
];
private static $dependencies = [
'schema' => '%$FormSchema'
];
/**
* Gets a JSON schema representing the current edit form.
*
* WARNING: Experimental API.
*
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function schema($request) {
$response = $this->getResponse();
$formName = $request->param('FormName');
$itemID = $request->param('ItemID');
if (!$formName) {
return (new HTTPResponse('Missing request params', 400));
}
if(!$this->hasMethod("get{$formName}")) {
return (new HTTPResponse('Form not found', 404));
}
if(!$this->hasAction($formName)) {
return (new HTTPResponse('Form not accessible', 401));
}
$form = $this->{"get{$formName}"}($itemID);
$response->addHeader('Content-Type', 'application/json');
$response->setBody(Convert::raw2json($this->getSchemaForForm($form)));
return $response;
}
/**
* Returns a representation of the provided {@link Form} as structured data,
* based on the request data.
*
* @param Form $form
* @param String $id Optional, will default to the current request URL
* @return array
*/
protected function getSchemaForForm(Form $form, $id = null) {
$request = $this->getRequest();
$id = $id ? $id : $request->getURL();
$return = null;
// Valid values for the "X-Formschema-Request" header are "schema" and "state".
// If either of these values are set they will be stored in the $schemaParst array
// and used to construct the response body.
if ($schemaHeader = $request->getHeader('X-Formschema-Request')) {
$schemaParts = array_filter(explode(',', $schemaHeader), function($value) {
$validHeaderValues = ['schema', 'state'];
return in_array(trim($value), $validHeaderValues);
});
} else {
$schemaParts = ['schema'];
}
$return = ['id' => $id];
if (in_array('schema', $schemaParts)) {
$return['schema'] = $this->schema->getSchema($form);
}
//this is uncommented for now as we want the values to be part of a request
//if (in_array('state', $schemaParts)) {
$return['state'] = $this->schema->getState($form);
//}
return $return;
}
public function getTestForm($id)
{
$record = MyDataObject::get()->first();
$scaffolder = Injector::inst()->get(AppFormFactory::class);
$form = $scaffolder->getForm($this, 'TestForm', [
'Record' => $record,
]);
return $form;
}
public function TestForm()
{
// Get ID either from posted back value, or url parameter
$request = $this->getRequest();
$id = $request->param('ID') ?: $request->postVar('ID');
return $this->getTestForm($id);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment