diff --git a/README.md b/README.md index 5e4a321..8a287a4 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ ## Overview This class gives your application a RESTful API. All you have to do is set the `api_access` configuration option to `true` -on the appropriate DataObjects. You will need to ensure that all of your data manipulation and security is defined in -your model layer (ie, the DataObject classes) and not in your Controllers. This is the recommended design for SilverStripe +on the appropriate `DataObject`. You will need to ensure that all of your data manipulation and security is defined in +your model layer (ie, the `DataObject` classes) and not in your Controllers. This is the recommended design for SilverStripe applications. ## Requirements @@ -20,7 +20,7 @@ For a SilverStripe 3.x compatible version of this module, please see the [1.0 br ## Configuration -Example DataObject with simple API access, giving full access to all object properties and relations, +Example `DataObject` with simple API access, giving full access to all object properties and relations, unless explicitly controlled through model permissions. ```php @@ -39,7 +39,7 @@ class Article extends DataObject { } ``` -Example DataObject with advanced API access, limiting viewing and editing to Title attribute only: +Example `DataObject` with advanced API access, limiting viewing and editing to the "Title" attribute only: ```php namespace Vendor\Project; @@ -60,7 +60,7 @@ class Article extends DataObject { } ``` -Example DataObject field mapping, allows aliasing fields so that public requests and responses display different field names: +Example `DataObject` field mapping, allows aliasing fields so that public requests and responses display different field names: ```php namespace Vendor\Project; @@ -83,7 +83,66 @@ class Article extends DataObject { ]; } ``` -Given a dataobject with values: + +Example `DataObject` `HasMany` and `ManyMany` field-display handling. Only available on `JSONDataFormatter`. Declaring a `getApiFields` method in your `DataObject` (or an `Extension` subclass) allows additional fields to be shown on those relations, in addition to "id", "className" and "href": + +```php +namespace Vendor\Project; + +use SilverStripe\ORM\DataObject; + +class Article extends DataObject { + + private static $db = [ + 'Title'=>'Text', + 'Published'=>'Boolean' + ]; + + private static $api_access = true; + + /** + * @param array $baseFields + * @return array + */ + public function getApiFields($baseFields) + { + return [ + 'Title' => $this->Title, + ]; + } +} +``` + +Example `DataObject` `HasMany` and `ManyMany` field-display handling. Only available on `JSONDataFormatter`. Declaring a `getApiFields` method in your `DataObject` (or an `Extension` subclass) allows existing fields that the formatter returns (like "id", "className" and "href"), to be overloaded: + +```php +namespace Vendor\Project; + +use SilverStripe\ORM\DataObject; + +class Article extends DataObject { + + private static $db = [ + 'Title'=>'Text', + 'Published'=>'Boolean' + ]; + + private static $api_access = true; + + /** + * @param array $baseFields + * @return array + */ + public function getApiFields($baseFields) + { + return [ + 'href' => $this->myHrefOverrideMethod($baseFields['href']), + ]; + } +} +``` + +Given a `DataObject` with values: ```yml ID: 12 Title: Title Value diff --git a/src/DataFormatter/JSONDataFormatter.php b/src/DataFormatter/JSONDataFormatter.php index 0ff743d..fc656ef 100644 --- a/src/DataFormatter/JSONDataFormatter.php +++ b/src/DataFormatter/JSONDataFormatter.php @@ -10,6 +10,8 @@ use SilverStripe\ORM\DataObjectInterface; use SilverStripe\Control\Director; use SilverStripe\ORM\SS_List; use SilverStripe\ORM\FieldType; +use SilverStripe\Core\ClassInfo; +use SilverStripe\ORM\DataObject; /** * Formats a DataObject's member fields into a JSON string @@ -118,10 +120,16 @@ class JSONDataFormatter extends DataFormatter ? $this->sanitiseClassName($relClass) . '/' . $obj->$fieldName : $this->sanitiseClassName($className) . "/$id/$relName"; $href = Director::absoluteURL($rel); - $serobj->$relName = ArrayData::array_to_object(array( + $component = $obj->getField($relName); + $baseFields = [ "className" => $relClass, "href" => "$href.json", - "id" => self::cast($obj->obj($fieldName)) + "id" => self::cast($obj->obj($fieldName)), + ]; + + $serobj->$relName = ArrayData::array_to_object(array_replace( + $baseFields, + ClassInfo::hasMethod($component, 'getApiFields') ? (array) $component->getApiFields($baseFields) : [] )); } @@ -152,10 +160,14 @@ class JSONDataFormatter extends DataFormatter } $rel = $this->config()->api_base . $this->sanitiseClassName($relClass) . "/$item->ID"; $href = Director::absoluteURL($rel); - $innerParts[] = ArrayData::array_to_object(array( + $baseFields = [ "className" => $relClass, "href" => "$href.json", "id" => $item->ID + ]; + $innerParts[] = ArrayData::array_to_object(array_replace( + $baseFields, + ClassInfo::hasMethod($item, 'getApiFields') ? (array) $item->getApiFields($baseFields) : [] )); } $serobj->$relName = $innerParts;