mirror of
https://github.com/silverstripe/silverstripe-restfulserver
synced 2024-10-22 14:05:58 +02:00
Add field mapping config
This commit is contained in:
parent
b59d956143
commit
aada3e350f
38
README.md
38
README.md
@ -59,6 +59,44 @@ class Article extends DataObject {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Example DataObject field mapping, allows aliasing fields so that public requests and responses display different field names:
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace Vendor\Project;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class Article extends DataObject {
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title'=>'Text',
|
||||||
|
'Published'=>'Boolean'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $api_access = [
|
||||||
|
'view' => ['Title', 'Content'],
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $api_field_mapping = [
|
||||||
|
'customTitle' => 'Title',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Given a dataobject with values:
|
||||||
|
```yml
|
||||||
|
ID: 12
|
||||||
|
Title: Title Value
|
||||||
|
Content: Content value
|
||||||
|
```
|
||||||
|
which when requesting with the url `/api/v1/Vendor-Project-Article/12?fields=customTitle,Content` and `Accept: application/json` the response will look like:
|
||||||
|
```Javascript
|
||||||
|
{
|
||||||
|
"customTitle": "Title Value",
|
||||||
|
"Content": "Content value"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Similarly, `PUT` or `POST` requests will have fields transformed from the alias name to the DB field name.
|
||||||
|
|
||||||
## Supported operations
|
## Supported operations
|
||||||
|
|
||||||
- `GET /api/v1/(ClassName)/(ID)` - gets a database record
|
- `GET /api/v1/(ClassName)/(ID)` - gets a database record
|
||||||
|
@ -356,4 +356,87 @@ abstract class DataFormatter
|
|||||||
{
|
{
|
||||||
user_error('DataFormatter::convertStringToArray not implemented on subclass', E_USER_ERROR);
|
user_error('DataFormatter::convertStringToArray not implemented on subclass', E_USER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an array of aliased field names to their Dataobject field name
|
||||||
|
*
|
||||||
|
* @param string $className
|
||||||
|
* @param string[] $fields
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getRealFields($className, $fields)
|
||||||
|
{
|
||||||
|
$apiMapping = Config::inst()->get($className, 'api_field_mapping');
|
||||||
|
if (is_array($apiMapping) && is_array($fields)) {
|
||||||
|
$mappedFields = [];
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$mappedFields[] = $this->getMappedKey($apiMapping, $field);
|
||||||
|
}
|
||||||
|
return $mappedFields;
|
||||||
|
}
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the DataObject field name from its alias
|
||||||
|
*
|
||||||
|
* @param string $className
|
||||||
|
* @param string $field
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRealFieldName($className, $field)
|
||||||
|
{
|
||||||
|
$apiMapping = $this->getApiMapping($className);
|
||||||
|
return $this->getMappedKey($apiMapping, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a DataObject Field's Alias
|
||||||
|
* defaults to the fieldname
|
||||||
|
*
|
||||||
|
* @param string $className
|
||||||
|
* @param string $field
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFieldAlias($className, $field)
|
||||||
|
{
|
||||||
|
$apiMapping = $this->getApiMapping($className);
|
||||||
|
$apiMapping = array_flip($apiMapping);
|
||||||
|
return $this->getMappedKey($apiMapping, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the 'api_field_mapping' config value for a class
|
||||||
|
* or return an empty array
|
||||||
|
*
|
||||||
|
* @param string $className
|
||||||
|
* @return string[]|array
|
||||||
|
*/
|
||||||
|
protected function getApiMapping($className)
|
||||||
|
{
|
||||||
|
$apiMapping = Config::inst()->get($className, 'api_field_mapping');
|
||||||
|
if ($apiMapping && is_array($apiMapping)) {
|
||||||
|
return $apiMapping;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to get mapped field names
|
||||||
|
*
|
||||||
|
* @param array $map
|
||||||
|
* @param string $key
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getMappedKey($map, $key)
|
||||||
|
{
|
||||||
|
if (is_array($map)) {
|
||||||
|
if (array_key_exists($key, $map)) {
|
||||||
|
return $map[$key];
|
||||||
|
} else {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,8 @@ class JSONDataFormatter extends DataFormatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
$fieldValue = $obj->obj($fieldName)->forTemplate();
|
$fieldValue = $obj->obj($fieldName)->forTemplate();
|
||||||
$serobj->$fieldName = $fieldValue;
|
$mappedFieldName = $this->getFieldAlias($className, $fieldName);
|
||||||
|
$serobj->$mappedFieldName = $fieldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->relationDepth > 0) {
|
if ($this->relationDepth > 0) {
|
||||||
|
@ -82,7 +82,8 @@ class XMLDataFormatter extends DataFormatter
|
|||||||
} else {
|
} else {
|
||||||
$fieldValue = Convert::raw2xml($fieldValue);
|
$fieldValue = Convert::raw2xml($fieldValue);
|
||||||
}
|
}
|
||||||
$xml .= "<$fieldName>$fieldValue</$fieldName>\n";
|
$mappedFieldName = $this->getFieldAlias(get_class($obj), $fieldName);
|
||||||
|
$xml .= "<$mappedFieldName>$fieldValue</$mappedFieldName>\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ use SilverStripe\ORM\SS_List;
|
|||||||
use SilverStripe\Security\Member;
|
use SilverStripe\Security\Member;
|
||||||
use SilverStripe\Security\Security;
|
use SilverStripe\Security\Security;
|
||||||
use SilverStripe\CMS\Model\SiteTree;
|
use SilverStripe\CMS\Model\SiteTree;
|
||||||
|
use TractorCow\Fluent\Task\ConvertTranslatableTask\Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic RESTful server, which handles webservice access to arbitrary DataObjects.
|
* Generic RESTful server, which handles webservice access to arbitrary DataObjects.
|
||||||
@ -257,7 +258,8 @@ class RestfulServer extends Controller
|
|||||||
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
|
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
|
||||||
|
|
||||||
$rawFields = $this->request->getVar('fields');
|
$rawFields = $this->request->getVar('fields');
|
||||||
$fields = $rawFields ? explode(',', $rawFields) : null;
|
$realFields = $responseFormatter->getRealFields($className, explode(',', $rawFields));
|
||||||
|
$fields = $rawFields ? $realFields : null;
|
||||||
|
|
||||||
if ($obj instanceof SS_List) {
|
if ($obj instanceof SS_List) {
|
||||||
$objs = ArrayList::create($obj->toArray());
|
$objs = ArrayList::create($obj->toArray());
|
||||||
@ -345,10 +347,12 @@ class RestfulServer extends Controller
|
|||||||
|
|
||||||
// set custom fields
|
// set custom fields
|
||||||
if ($customAddFields = $this->request->getVar('add_fields')) {
|
if ($customAddFields = $this->request->getVar('add_fields')) {
|
||||||
$formatter->setCustomAddFields(explode(',', $customAddFields));
|
$customAddFields = $formatter->getRealFields($className, explode(',', $customAddFields));
|
||||||
|
$formatter->setCustomAddFields($customAddFields);
|
||||||
}
|
}
|
||||||
if ($customFields = $this->request->getVar('fields')) {
|
if ($customFields = $this->request->getVar('fields')) {
|
||||||
$formatter->setCustomFields(explode(',', $customFields));
|
$customFields = $formatter->getRealFields($className, explode(',', $customFields));
|
||||||
|
$formatter->setCustomFields($customFields);
|
||||||
}
|
}
|
||||||
$formatter->setCustomRelations($this->getAllowedRelations($className));
|
$formatter->setCustomRelations($this->getAllowedRelations($className));
|
||||||
|
|
||||||
@ -488,6 +492,13 @@ class RestfulServer extends Controller
|
|||||||
return $this->notFound();
|
return $this->notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reqFormatter = $this->getRequestDataFormatter($className);
|
||||||
|
if (!$reqFormatter) {
|
||||||
|
return $this->unsupportedMediaType();
|
||||||
|
}
|
||||||
|
|
||||||
|
$relation = $reqFormatter->getRealFieldName($className, $relation);
|
||||||
|
|
||||||
if (!$obj->hasMethod($relation)) {
|
if (!$obj->hasMethod($relation)) {
|
||||||
return $this->notFound();
|
return $this->notFound();
|
||||||
}
|
}
|
||||||
@ -561,16 +572,23 @@ class RestfulServer extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($body)) {
|
if (!empty($body)) {
|
||||||
$data = $formatter->convertStringToArray($body);
|
$rawdata = $formatter->convertStringToArray($body);
|
||||||
} else {
|
} else {
|
||||||
// assume application/x-www-form-urlencoded which is automatically parsed by PHP
|
// assume application/x-www-form-urlencoded which is automatically parsed by PHP
|
||||||
$data = $this->request->postVars();
|
$rawdata = $this->request->postVars();
|
||||||
|
}
|
||||||
|
|
||||||
|
$className = $this->unsanitiseClassName($this->request->param('ClassName'));
|
||||||
|
// update any aliased field names
|
||||||
|
$data = [];
|
||||||
|
foreach ($rawdata as $key => $value) {
|
||||||
|
$newkey = $formatter->getRealFieldName($className, $key);
|
||||||
|
$data[$newkey] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo Disallow editing of certain keys in database
|
// @todo Disallow editing of certain keys in database
|
||||||
$data = array_diff_key($data, ['ID', 'Created']);
|
$data = array_diff_key($data, ['ID', 'Created']);
|
||||||
|
|
||||||
$className = $this->unsanitiseClassName($this->request->param('ClassName'));
|
|
||||||
$apiAccess = singleton($className)->config()->api_access;
|
$apiAccess = singleton($className)->config()->api_access;
|
||||||
if (is_array($apiAccess) && isset($apiAccess['edit'])) {
|
if (is_array($apiAccess) && isset($apiAccess['edit'])) {
|
||||||
$data = array_intersect_key($data, array_combine($apiAccess['edit'], $apiAccess['edit']));
|
$data = array_intersect_key($data, array_combine($apiAccess['edit'], $apiAccess['edit']));
|
||||||
|
Loading…
Reference in New Issue
Block a user