2017-11-29 03:20:09 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace SilverStripe\RestfulServer\DataFormatter;
|
|
|
|
|
2018-04-06 01:10:32 +02:00
|
|
|
use SilverStripe\RestfulServer\RestfulServer;
|
2017-12-06 04:18:14 +01:00
|
|
|
use SilverStripe\View\ArrayData;
|
|
|
|
use SilverStripe\Core\Convert;
|
2017-12-05 22:49:45 +01:00
|
|
|
use SilverStripe\RestfulServer\DataFormatter;
|
2017-11-29 03:20:09 +01:00
|
|
|
use SilverStripe\ORM\DataObjectInterface;
|
|
|
|
use SilverStripe\Control\Director;
|
|
|
|
use SilverStripe\ORM\SS_List;
|
2018-04-19 05:54:43 +02:00
|
|
|
use SilverStripe\ORM\FieldType;
|
2017-11-29 03:20:09 +01:00
|
|
|
|
|
|
|
/**
|
2017-12-05 22:49:45 +01:00
|
|
|
* Formats a DataObject's member fields into a JSON string
|
2017-11-29 03:20:09 +01:00
|
|
|
*/
|
|
|
|
class JSONDataFormatter extends DataFormatter
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @config
|
|
|
|
* @todo pass this from the API to the data formatter somehow
|
|
|
|
*/
|
|
|
|
private static $api_base = "api/v1/";
|
|
|
|
|
|
|
|
protected $outputContentType = 'application/json';
|
|
|
|
|
2018-03-01 22:39:47 +01:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
2017-11-29 03:20:09 +01:00
|
|
|
public function supportedExtensions()
|
|
|
|
{
|
|
|
|
return array(
|
|
|
|
'json',
|
|
|
|
'js'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-03-01 22:39:47 +01:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
2017-11-29 03:20:09 +01:00
|
|
|
public function supportedMimeTypes()
|
|
|
|
{
|
|
|
|
return array(
|
|
|
|
'application/json',
|
|
|
|
'text/x-json'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-03-01 22:39:47 +01:00
|
|
|
/**
|
|
|
|
* @param $array
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function convertArray($array)
|
|
|
|
{
|
2018-10-28 22:39:14 +01:00
|
|
|
return json_encode($array);
|
2018-03-01 22:39:47 +01:00
|
|
|
}
|
|
|
|
|
2017-11-29 03:20:09 +01:00
|
|
|
/**
|
|
|
|
* Generate a JSON representation of the given {@link DataObject}.
|
|
|
|
*
|
|
|
|
* @param DataObject $obj The object
|
|
|
|
* @param Array $fields If supplied, only fields in the list will be returned
|
|
|
|
* @param $relations Not used
|
|
|
|
* @return String JSON
|
|
|
|
*/
|
|
|
|
public function convertDataObject(DataObjectInterface $obj, $fields = null, $relations = null)
|
|
|
|
{
|
2018-10-28 22:39:14 +01:00
|
|
|
return json_encode($this->convertDataObjectToJSONObject($obj, $fields, $relations));
|
2017-11-29 03:20:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal function to do the conversion of a single data object. It builds an empty object and dynamically
|
|
|
|
* adds the properties it needs to it. If it's done as a nested array, json_encode or equivalent won't use
|
|
|
|
* JSON object notation { ... }.
|
|
|
|
* @param DataObjectInterface $obj
|
|
|
|
* @param $fields
|
|
|
|
* @param $relations
|
|
|
|
* @return EmptyJSONObject
|
|
|
|
*/
|
|
|
|
public function convertDataObjectToJSONObject(DataObjectInterface $obj, $fields = null, $relations = null)
|
|
|
|
{
|
|
|
|
$className = get_class($obj);
|
|
|
|
$id = $obj->ID;
|
|
|
|
|
|
|
|
$serobj = ArrayData::array_to_object();
|
|
|
|
|
|
|
|
foreach ($this->getFieldsForObj($obj) as $fieldName => $fieldType) {
|
|
|
|
// Field filtering
|
2022-04-13 03:42:48 +02:00
|
|
|
if ($fields && !in_array($fieldName, $fields ?? [])) {
|
2017-11-29 03:20:09 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-19 05:54:43 +02:00
|
|
|
$fieldValue = self::cast($obj->obj($fieldName));
|
2018-03-08 02:20:31 +01:00
|
|
|
$mappedFieldName = $this->getFieldAlias($className, $fieldName);
|
|
|
|
$serobj->$mappedFieldName = $fieldValue;
|
2017-11-29 03:20:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->relationDepth > 0) {
|
|
|
|
foreach ($obj->hasOne() as $relName => $relClass) {
|
2022-11-28 07:19:41 +01:00
|
|
|
if (!$relClass::config()->get('api_access')) {
|
2017-11-29 03:20:09 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Field filtering
|
2022-04-13 03:42:48 +02:00
|
|
|
if ($fields && !in_array($relName, $fields ?? [])) {
|
2017-11-29 03:20:09 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-04-13 03:42:48 +02:00
|
|
|
if ($this->customRelations && !in_array($relName, $this->customRelations ?? [])) {
|
2017-11-29 03:20:09 +01:00
|
|
|
continue;
|
|
|
|
}
|
2018-04-09 01:20:34 +02:00
|
|
|
if ($obj->$relName() && (!$obj->$relName()->exists() || !$obj->$relName()->canView())) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-11-29 03:20:09 +01:00
|
|
|
|
|
|
|
$fieldName = $relName . 'ID';
|
2018-04-04 04:54:00 +02:00
|
|
|
$rel = $this->config()->api_base;
|
|
|
|
$rel .= $obj->$fieldName
|
|
|
|
? $this->sanitiseClassName($relClass) . '/' . $obj->$fieldName
|
|
|
|
: $this->sanitiseClassName($className) . "/$id/$relName";
|
|
|
|
$href = Director::absoluteURL($rel);
|
2017-11-29 03:20:09 +01:00
|
|
|
$serobj->$relName = ArrayData::array_to_object(array(
|
|
|
|
"className" => $relClass,
|
|
|
|
"href" => "$href.json",
|
2018-04-19 05:54:43 +02:00
|
|
|
"id" => self::cast($obj->obj($fieldName))
|
2017-11-29 03:20:09 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($obj->hasMany() + $obj->manyMany() as $relName => $relClass) {
|
2018-04-06 01:10:32 +02:00
|
|
|
$relClass = RestfulServer::parseRelationClass($relClass);
|
|
|
|
|
2017-11-29 03:20:09 +01:00
|
|
|
//remove dot notation from relation names
|
2022-04-13 03:42:48 +02:00
|
|
|
$parts = explode('.', $relClass ?? '');
|
2017-11-29 03:20:09 +01:00
|
|
|
$relClass = array_shift($parts);
|
|
|
|
|
2022-11-28 07:19:41 +01:00
|
|
|
if (!$relClass::config()->get('api_access')) {
|
2017-11-29 03:20:09 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Field filtering
|
2022-04-13 03:42:48 +02:00
|
|
|
if ($fields && !in_array($relName, $fields ?? [])) {
|
2017-11-29 03:20:09 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-04-13 03:42:48 +02:00
|
|
|
if ($this->customRelations && !in_array($relName, $this->customRelations ?? [])) {
|
2017-11-29 03:20:09 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$innerParts = array();
|
|
|
|
$items = $obj->$relName();
|
|
|
|
foreach ($items as $item) {
|
2018-04-09 01:27:20 +02:00
|
|
|
if (!$item->canView()) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-04-04 04:54:00 +02:00
|
|
|
$rel = $this->config()->api_base . $this->sanitiseClassName($relClass) . "/$item->ID";
|
|
|
|
$href = Director::absoluteURL($rel);
|
2017-11-29 03:20:09 +01:00
|
|
|
$innerParts[] = ArrayData::array_to_object(array(
|
|
|
|
"className" => $relClass,
|
|
|
|
"href" => "$href.json",
|
|
|
|
"id" => $item->ID
|
|
|
|
));
|
|
|
|
}
|
|
|
|
$serobj->$relName = $innerParts;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $serobj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a JSON representation of the given {@link SS_List}.
|
|
|
|
*
|
|
|
|
* @param SS_List $set
|
|
|
|
* @return String XML
|
|
|
|
*/
|
|
|
|
public function convertDataObjectSet(SS_List $set, $fields = null)
|
|
|
|
{
|
|
|
|
$items = array();
|
|
|
|
foreach ($set as $do) {
|
|
|
|
if (!$do->canView()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$items[] = $this->convertDataObjectToJSONObject($do, $fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
$serobj = ArrayData::array_to_object(array(
|
|
|
|
"totalSize" => (is_numeric($this->totalSize)) ? $this->totalSize : null,
|
|
|
|
"items" => $items
|
|
|
|
));
|
|
|
|
|
2018-10-28 22:39:14 +01:00
|
|
|
return json_encode($serobj);
|
2017-11-29 03:20:09 +01:00
|
|
|
}
|
|
|
|
|
2018-03-01 22:39:47 +01:00
|
|
|
/**
|
|
|
|
* @param string $strData
|
|
|
|
* @return array|bool|void
|
|
|
|
*/
|
2017-11-29 03:20:09 +01:00
|
|
|
public function convertStringToArray($strData)
|
|
|
|
{
|
2022-04-13 03:42:48 +02:00
|
|
|
return json_decode($strData ?? '', true);
|
2017-11-29 03:20:09 +01:00
|
|
|
}
|
2018-04-19 05:54:43 +02:00
|
|
|
|
|
|
|
public static function cast(FieldType\DBField $dbfield)
|
|
|
|
{
|
|
|
|
switch (true) {
|
|
|
|
case $dbfield instanceof FieldType\DBInt:
|
|
|
|
return (int)$dbfield->RAW();
|
|
|
|
case $dbfield instanceof FieldType\DBFloat:
|
|
|
|
return (float)$dbfield->RAW();
|
|
|
|
case $dbfield instanceof FieldType\DBBoolean:
|
|
|
|
return (bool)$dbfield->RAW();
|
|
|
|
case is_null($dbfield->RAW()):
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return $dbfield->RAW();
|
|
|
|
}
|
2017-11-29 03:20:09 +01:00
|
|
|
}
|