mirror of
https://github.com/silverstripe/silverstripe-restfulserver
synced 2024-10-22 14:05:58 +02:00
Merge 80b17460c4
into 3c1055e2f0
This commit is contained in:
commit
8dcc0c4ffb
@ -28,7 +28,11 @@
|
||||
"SilverStripe\\RestfulServer\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"extra": [],
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
|
||||
namespace SilverStripe\RestfulServer\DataFormatter;
|
||||
|
||||
use SilverStripe\RestfulServer\RestfulServer;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\RestfulServer\DataFormatter;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\ORM\FieldType;
|
||||
|
||||
/**
|
||||
* Formats a DataObject's member fields into a JSON string
|
||||
@ -88,7 +90,7 @@ class JSONDataFormatter extends DataFormatter
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldValue = $obj->obj($fieldName)->forTemplate();
|
||||
$fieldValue = self::cast($obj->obj($fieldName));
|
||||
$mappedFieldName = $this->getFieldAlias($className, $fieldName);
|
||||
$serobj->$mappedFieldName = $fieldValue;
|
||||
}
|
||||
@ -119,11 +121,13 @@ class JSONDataFormatter extends DataFormatter
|
||||
$serobj->$relName = ArrayData::array_to_object(array(
|
||||
"className" => $relClass,
|
||||
"href" => "$href.json",
|
||||
"id" => $obj->$fieldName
|
||||
"id" => self::cast($obj->obj($fieldName))
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($obj->hasMany() + $obj->manyMany() as $relName => $relClass) {
|
||||
$relClass = RestfulServer::parseRelationClass($relClass);
|
||||
|
||||
//remove dot notation from relation names
|
||||
$parts = explode('.', $relClass);
|
||||
$relClass = array_shift($parts);
|
||||
@ -193,4 +197,19 @@ class JSONDataFormatter extends DataFormatter
|
||||
{
|
||||
return Convert::json2array($strData);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\RestfulServer\RestfulServer;
|
||||
|
||||
/**
|
||||
* Formats a DataObject's member fields into an XML string
|
||||
@ -196,6 +197,8 @@ class XMLDataFormatter extends DataFormatter
|
||||
}
|
||||
|
||||
foreach ($obj->manyMany() as $relName => $relClass) {
|
||||
$relClass = RestfulServer::parseRelationClass($relClass);
|
||||
|
||||
//remove dot notation from relation names
|
||||
$parts = explode('.', $relClass);
|
||||
$relClass = array_shift($parts);
|
||||
|
@ -15,6 +15,7 @@ use SilverStripe\ORM\ValidationResult;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
|
||||
/**
|
||||
* Generic RESTful server, which handles webservice access to arbitrary DataObjects.
|
||||
@ -41,6 +42,10 @@ use SilverStripe\CMS\Model\SiteTree;
|
||||
*/
|
||||
class RestfulServer extends Controller
|
||||
{
|
||||
/**
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $url_handlers = array(
|
||||
'$ClassName!/$ID/$Relation' => 'handleAction',
|
||||
'' => 'notFound'
|
||||
@ -62,10 +67,24 @@ class RestfulServer extends Controller
|
||||
* If no extension is given in the request, resolve to this extension
|
||||
* (and subsequently the {@link self::$default_mimetype}.
|
||||
*
|
||||
* @config
|
||||
* @var string
|
||||
*/
|
||||
private static $default_extension = "xml";
|
||||
|
||||
/**
|
||||
* Whether or not to send an additional "Location" header for POST requests
|
||||
* to satisfy HTTP 1.1: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
*
|
||||
* Note: With this enabled (the default), no POST request for resource creation
|
||||
* will return an HTTP 201. Because of the addition of the "Location" header,
|
||||
* all responses become a straight HTTP 200.
|
||||
*
|
||||
* @config
|
||||
* @var boolean
|
||||
*/
|
||||
private static $location_header_on_create = true;
|
||||
|
||||
/**
|
||||
* If no extension is given, resolve the request to this mimetype.
|
||||
*
|
||||
@ -122,6 +141,32 @@ class RestfulServer extends Controller
|
||||
return str_replace('-', '\\', $className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse many many relation class (works with through array syntax)
|
||||
*
|
||||
* @param string|array $class
|
||||
* @return string|array
|
||||
*/
|
||||
public static function parseRelationClass($class)
|
||||
{
|
||||
// detect many many through syntax
|
||||
if (is_array($class)
|
||||
&& array_key_exists('through', $class)
|
||||
&& array_key_exists('to', $class)
|
||||
) {
|
||||
$toRelation = $class['to'];
|
||||
|
||||
$hasOne = Config::inst()->get($class['through'], 'has_one');
|
||||
if (empty($hasOne) || !is_array($hasOne) || !array_key_exists($toRelation, $hasOne)) {
|
||||
return $class;
|
||||
}
|
||||
|
||||
return $hasOne[$toRelation];
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* This handler acts as the switchboard for the controller.
|
||||
* Since no $Action url-param is set, all requests are sent here.
|
||||
@ -154,21 +199,25 @@ class RestfulServer extends Controller
|
||||
// authenticate through HTTP BasicAuth
|
||||
$this->member = $this->authenticate();
|
||||
|
||||
// handle different HTTP verbs
|
||||
if ($this->request->isGET() || $this->request->isHEAD()) {
|
||||
return $this->getHandler($className, $id, $relation);
|
||||
}
|
||||
try {
|
||||
// handle different HTTP verbs
|
||||
if ($this->request->isGET() || $this->request->isHEAD()) {
|
||||
return $this->getHandler($className, $id, $relation);
|
||||
}
|
||||
|
||||
if ($this->request->isPOST()) {
|
||||
return $this->postHandler($className, $id, $relation);
|
||||
}
|
||||
if ($this->request->isPOST()) {
|
||||
return $this->postHandler($className, $id, $relation);
|
||||
}
|
||||
|
||||
if ($this->request->isPUT()) {
|
||||
return $this->putHandler($className, $id, $relation);
|
||||
}
|
||||
if ($this->request->isPUT()) {
|
||||
return $this->putHandler($className, $id, $relation);
|
||||
}
|
||||
|
||||
if ($this->request->isDELETE()) {
|
||||
return $this->deleteHandler($className, $id, $relation);
|
||||
if ($this->request->isDELETE()) {
|
||||
return $this->deleteHandler($className, $id, $relation);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionThrown($this->getRequestDataFormatter($className), $e);
|
||||
}
|
||||
|
||||
// if no HTTP verb matches, return error
|
||||
@ -459,7 +508,7 @@ class RestfulServer extends Controller
|
||||
return $obj;
|
||||
}
|
||||
|
||||
$this->getResponse()->setStatusCode(200); // Success
|
||||
$this->getResponse()->setStatusCode(202); // Accepted
|
||||
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
|
||||
|
||||
// Append the default extension for the output format to the Location header
|
||||
@ -523,7 +572,8 @@ class RestfulServer extends Controller
|
||||
if (!singleton($className)->canCreate($this->getMember())) {
|
||||
return $this->permissionFailure();
|
||||
}
|
||||
$obj = new $className();
|
||||
|
||||
$obj = Injector::inst()->create($className);
|
||||
|
||||
$reqFormatter = $this->getRequestDataFormatter($className);
|
||||
if (!$reqFormatter) {
|
||||
@ -554,10 +604,15 @@ class RestfulServer extends Controller
|
||||
$type = ".{$types[0]}";
|
||||
}
|
||||
|
||||
$urlSafeClassName = $this->sanitiseClassName(get_class($obj));
|
||||
$apiBase = $this->config()->api_base;
|
||||
$objHref = Director::absoluteURL($apiBase . "$urlSafeClassName/$obj->ID" . $type);
|
||||
$this->getResponse()->addHeader('Location', $objHref);
|
||||
// Deviate slightly from the spec: Helps datamodel API access restrict
|
||||
// to consulting just canCreate(), not canView() as a result of the additional
|
||||
// "Location" header.
|
||||
if ($this->config()->get('location_header_on_create')) {
|
||||
$urlSafeClassName = $this->sanitiseClassName(get_class($obj));
|
||||
$apiBase = $this->config()->api_base;
|
||||
$objHref = Director::absoluteURL($apiBase . "$urlSafeClassName/$obj->ID" . $type);
|
||||
$this->getResponse()->addHeader('Location', $objHref);
|
||||
}
|
||||
|
||||
return $responseFormatter->convertDataObject($obj);
|
||||
}
|
||||
@ -681,7 +736,11 @@ class RestfulServer extends Controller
|
||||
$this->getResponse()->setStatusCode(401);
|
||||
$this->getResponse()->addHeader('WWW-Authenticate', 'Basic realm="API Access"');
|
||||
$this->getResponse()->addHeader('Content-Type', 'text/plain');
|
||||
return "You don't have access to this item through the API.";
|
||||
|
||||
$reponse = "You don't have access to this item through the API.";
|
||||
$this->extend(__FUNCTION__, $reponse);
|
||||
|
||||
return $reponse;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -692,7 +751,11 @@ class RestfulServer extends Controller
|
||||
// return a 404
|
||||
$this->getResponse()->setStatusCode(404);
|
||||
$this->getResponse()->addHeader('Content-Type', 'text/plain');
|
||||
return "That object wasn't found";
|
||||
|
||||
$reponse = "That object wasn't found";
|
||||
$this->extend(__FUNCTION__, $reponse);
|
||||
|
||||
return $reponse;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -702,7 +765,11 @@ class RestfulServer extends Controller
|
||||
{
|
||||
$this->getResponse()->setStatusCode(405);
|
||||
$this->getResponse()->addHeader('Content-Type', 'text/plain');
|
||||
return "Method Not Allowed";
|
||||
|
||||
$reponse = "Method Not Allowed";
|
||||
$this->extend(__FUNCTION__, $reponse);
|
||||
|
||||
return $reponse;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -712,7 +779,11 @@ class RestfulServer extends Controller
|
||||
{
|
||||
$this->response->setStatusCode(415); // Unsupported Media Type
|
||||
$this->getResponse()->addHeader('Content-Type', 'text/plain');
|
||||
return "Unsupported Media Type";
|
||||
|
||||
$reponse = "Unsupported Media Type";
|
||||
$this->extend(__FUNCTION__, $reponse);
|
||||
|
||||
return $reponse;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -729,6 +800,28 @@ class RestfulServer extends Controller
|
||||
'messages' => $result->getMessages(),
|
||||
];
|
||||
|
||||
$this->extend(__FUNCTION__, $response, $result);
|
||||
|
||||
return $responseFormatter->convertArray($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataFormatter $responseFormatter
|
||||
* @param \Exception $e
|
||||
* @return string
|
||||
*/
|
||||
protected function exceptionThrown(DataFormatter $responseFormatter, \Exception $e)
|
||||
{
|
||||
$this->getResponse()->setStatusCode(500);
|
||||
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
|
||||
|
||||
$response = [
|
||||
'type' => get_class($e),
|
||||
'message' => $e->getMessage(),
|
||||
];
|
||||
|
||||
$this->extend(__FUNCTION__, $response, $e);
|
||||
|
||||
return $responseFormatter->convertArray($response);
|
||||
}
|
||||
|
||||
@ -760,6 +853,8 @@ class RestfulServer extends Controller
|
||||
$relations = (array)$obj->hasOne() + (array)$obj->hasMany() + (array)$obj->manyMany();
|
||||
if ($relations) {
|
||||
foreach ($relations as $relName => $relClass) {
|
||||
$relClass = static::parseRelationClass($relClass);
|
||||
|
||||
//remove dot notation from relation names
|
||||
$parts = explode('.', $relClass);
|
||||
$relClass = array_shift($parts);
|
||||
|
46
tests/unit/JSONDataFormatterTest.php
Normal file
46
tests/unit/JSONDataFormatterTest.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\RestfulServer\Tests;
|
||||
|
||||
use SilverStripe\RestfulServer\RestfulServer;
|
||||
use SilverStripe\RestfulServer\Tests\Stubs\JSONDataFormatterTypeTestObject;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\RestfulServer\DataFormatter\JSONDataFormatter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @todo Test Relation getters
|
||||
* @todo Test filter and limit through GET params
|
||||
* @todo Test DELETE verb
|
||||
*
|
||||
*/
|
||||
class JSONDataFormatterTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'JSONDataFormatterTest.yml';
|
||||
|
||||
protected static $extra_dataobjects = [
|
||||
JSONDataFormatterTypeTestObject::class,
|
||||
];
|
||||
|
||||
public function testJSONTypes()
|
||||
{
|
||||
$formatter = new JSONDataFormatter();
|
||||
$parent = $this->objFromFixture(JSONDataFormatterTypeTestObject::class, 'parent');
|
||||
$json = $formatter->convertDataObject($parent);
|
||||
$this->assertRegexp('/"ID":\d+/', $json, 'PK casted to integer');
|
||||
$this->assertRegexp('/"Created":"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}"/', $json, 'Datetime casted to string');
|
||||
$this->assertContains('"Name":"Parent"', $json, 'String casted to string');
|
||||
$this->assertContains('"Active":true', $json, 'Boolean casted to boolean');
|
||||
$this->assertContains('"Sort":17', $json, 'Integer casted to integer');
|
||||
$this->assertContains('"Average":1.2345', $json, 'Float casted to float');
|
||||
$this->assertContains('"ParentID":0', $json, 'Empty FK is 0');
|
||||
|
||||
$child3 = $this->objFromFixture(JSONDataFormatterTypeTestObject::class, 'child3');
|
||||
$json = $formatter->convertDataObject($child3);
|
||||
$this->assertContains('"Name":null', $json, 'Empty string is null');
|
||||
$this->assertContains('"Active":false', $json, 'Empty boolean is false');
|
||||
$this->assertContains('"Sort":0', $json, 'Empty integer is 0');
|
||||
$this->assertContains('"Average":0', $json, 'Empty float is 0');
|
||||
$this->assertRegexp('/"ParentID":\d+/', $json, 'FK casted to integer');
|
||||
}
|
||||
}
|
20
tests/unit/JSONDataFormatterTest.yml
Normal file
20
tests/unit/JSONDataFormatterTest.yml
Normal file
@ -0,0 +1,20 @@
|
||||
SilverStripe\RestfulServer\Tests\Stubs\JSONDataFormatterTypeTestObject:
|
||||
parent:
|
||||
Name: Parent
|
||||
Active: true
|
||||
Sort: 17
|
||||
Average: 1.2345
|
||||
child1:
|
||||
Name: Child 1
|
||||
Active: 1
|
||||
Sort: 4
|
||||
Average: 6.78
|
||||
Parent: =>SilverStripe\RestfulServer\Tests\Stubs\JSONDataFormatterTypeTestObject.parent
|
||||
child2:
|
||||
Name: Child 2
|
||||
Active: false
|
||||
Sort: 9
|
||||
Average: 1
|
||||
Parent: =>SilverStripe\RestfulServer\Tests\Stubs\JSONDataFormatterTypeTestObject.parent
|
||||
child3:
|
||||
Parent: =>SilverStripe\RestfulServer\Tests\Stubs\JSONDataFormatterTypeTestObject.parent
|
@ -2,7 +2,9 @@
|
||||
|
||||
namespace SilverStripe\RestfulServer\Tests;
|
||||
|
||||
use SilverStripe\RestfulServer\RestfulServer;
|
||||
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestComment;
|
||||
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestExceptionThrown;
|
||||
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestSecretThing;
|
||||
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestPage;
|
||||
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestAuthor;
|
||||
@ -38,6 +40,8 @@ class RestfulServerTest extends SapphireTest
|
||||
RestfulServerTestPage::class,
|
||||
RestfulServerTestAuthor::class,
|
||||
RestfulServerTestAuthorRating::class,
|
||||
RestfulServerTestValidationFailure::class,
|
||||
RestfulServerTestExceptionThrown::class,
|
||||
];
|
||||
|
||||
protected function urlSafeClassname($classname)
|
||||
@ -140,7 +144,7 @@ class RestfulServerTest extends SapphireTest
|
||||
$_SERVER['PHP_AUTH_USER'] = 'editor@test.com';
|
||||
$_SERVER['PHP_AUTH_PW'] = 'editor';
|
||||
$response = Director::test($url, $data, null, 'PUT');
|
||||
$this->assertEquals(200, $response->getStatusCode()); // Success
|
||||
$this->assertEquals(202, $response->getStatusCode()); // Accepted
|
||||
|
||||
unset($_SERVER['PHP_AUTH_USER']);
|
||||
unset($_SERVER['PHP_AUTH_PW']);
|
||||
@ -233,7 +237,7 @@ class RestfulServerTest extends SapphireTest
|
||||
'Content-Type' => 'application/x-www-form-urlencoded'
|
||||
);
|
||||
$response = Director::test($url, null, null, 'PUT', $body, $headers);
|
||||
$this->assertEquals(200, $response->getStatusCode()); // Success
|
||||
$this->assertEquals(202, $response->getStatusCode()); // Accepted
|
||||
// Assumption: XML is default output
|
||||
$responseArr = Convert::xml2array($response->getBody());
|
||||
$this->assertEquals($comment1->ID, $responseArr['ID']);
|
||||
@ -302,7 +306,7 @@ class RestfulServerTest extends SapphireTest
|
||||
'Content-Type'=>'application/json',
|
||||
'Accept' => 'application/json'
|
||||
));
|
||||
$this->assertEquals(200, $response->getStatusCode()); // Updated
|
||||
$this->assertEquals(202, $response->getStatusCode()); // Accepted
|
||||
$obj = Convert::json2obj($response->getBody());
|
||||
$this->assertEquals($comment1->ID, $obj->ID);
|
||||
$this->assertEquals('updated', $obj->Comment);
|
||||
@ -312,7 +316,7 @@ class RestfulServerTest extends SapphireTest
|
||||
$url = "{$this->baseURI}/api/v1/$urlSafeClassname/{$comment1->ID}.json";
|
||||
$body = '{"Comment":"updated"}';
|
||||
$response = Director::test($url, null, null, 'PUT', $body);
|
||||
$this->assertEquals(200, $response->getStatusCode()); // Updated
|
||||
$this->assertEquals(202, $response->getStatusCode()); // Accepted
|
||||
$this->assertEquals($url, $response->getHeader('Location'));
|
||||
$obj = Convert::json2obj($response->getBody());
|
||||
$this->assertEquals($comment1->ID, $obj->ID);
|
||||
@ -334,7 +338,7 @@ class RestfulServerTest extends SapphireTest
|
||||
$url = "{$this->baseURI}/api/v1/$urlSafeClassname/" . $comment1->ID;
|
||||
$body = '<RestfulServerTestComment><Comment>updated</Comment></RestfulServerTestComment>';
|
||||
$response = Director::test($url, null, null, 'PUT', $body, array('Content-Type'=>'text/xml'));
|
||||
$this->assertEquals(200, $response->getStatusCode()); // Updated
|
||||
$this->assertEquals(202, $response->getStatusCode()); // Accepted
|
||||
$obj = Convert::xml2array($response->getBody());
|
||||
$this->assertEquals($comment1->ID, $obj['ID']);
|
||||
$this->assertEquals('updated', $obj['Comment']);
|
||||
@ -344,7 +348,7 @@ class RestfulServerTest extends SapphireTest
|
||||
$url = "{$this->baseURI}/api/v1/$urlSafeClassname/{$comment1->ID}.xml";
|
||||
$body = '<RestfulServerTestComment><Comment>updated</Comment></RestfulServerTestComment>';
|
||||
$response = Director::test($url, null, null, 'PUT', $body);
|
||||
$this->assertEquals(200, $response->getStatusCode()); // Updated
|
||||
$this->assertEquals(202, $response->getStatusCode()); // Accepted
|
||||
$this->assertEquals($url, $response->getHeader('Location'));
|
||||
$obj = Convert::xml2array($response->getBody());
|
||||
$this->assertEquals($comment1->ID, $obj['ID']);
|
||||
@ -685,4 +689,30 @@ class RestfulServerTest extends SapphireTest
|
||||
$responseArr = Convert::xml2array($response->getBody());
|
||||
$this->assertEquals('SilverStripe\\ORM\\ValidationException', $responseArr['type']);
|
||||
}
|
||||
|
||||
public function testExceptionThrownWithPOST()
|
||||
{
|
||||
$urlSafeClassname = $this->urlSafeClassname(RestfulServerTestExceptionThrown::class);
|
||||
$url = "{$this->baseURI}/api/v1/$urlSafeClassname/";
|
||||
$data = [
|
||||
'Content' => 'Test',
|
||||
];
|
||||
$response = Director::test($url, $data, null, 'POST');
|
||||
// Assumption: XML is default output
|
||||
$responseArr = Convert::xml2array($response->getBody());
|
||||
$this->assertEquals(\Exception::class, $responseArr['type']);
|
||||
}
|
||||
|
||||
public function testParseClassName()
|
||||
{
|
||||
$manyMany = RestfulServerTestAuthor::config()->get('many_many');
|
||||
|
||||
// simple syntax (many many standard)
|
||||
$className = RestfulServer::parseRelationClass($manyMany['RelatedPages']);
|
||||
$this->assertEquals(RestfulServerTestPage::class, $className);
|
||||
|
||||
// array syntax (many many through)
|
||||
$className = RestfulServer::parseRelationClass($manyMany['SortedPages']);
|
||||
$this->assertEquals(RestfulServerTestPage::class, $className);
|
||||
}
|
||||
}
|
||||
|
29
tests/unit/Stubs/AuthorSortedPageRelation.php
Normal file
29
tests/unit/Stubs/AuthorSortedPageRelation.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\RestfulServer\Tests\Stubs;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class AuthorSortedPageRelation extends DataObject implements TestOnly
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $table_name = 'AuthorSortedPageRelation';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $has_one = [
|
||||
'Parent' => RestfulServerTestAuthor::class,
|
||||
'SortedPage' => RestfulServerTestPage::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $db = [
|
||||
'Sort' => 'Int',
|
||||
];
|
||||
}
|
32
tests/unit/Stubs/JSONDataFormatterTypeTestObject.php
Normal file
32
tests/unit/Stubs/JSONDataFormatterTypeTestObject.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\RestfulServer\Tests\Stubs;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class JSONDataFormatterTypeTestObject extends DataObject implements TestOnly
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $table_name = 'JSONDataFormatterTypeTestObject';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'Active' => 'Boolean',
|
||||
'Sort' => 'Int',
|
||||
'Average' => 'Float',
|
||||
];
|
||||
|
||||
private static $has_one = [
|
||||
'Parent' => JSONDataFormatterTypeTestObject::class,
|
||||
];
|
||||
|
||||
private static $has_many = [
|
||||
'Children' => JSONDataFormatterTypeTestObject::class,
|
||||
];
|
||||
}
|
@ -18,11 +18,17 @@ class RestfulServerTestAuthor extends DataObject implements TestOnly
|
||||
private static $many_many = array(
|
||||
'RelatedPages' => RestfulServerTestPage::class,
|
||||
'RelatedAuthors' => RestfulServerTestAuthor::class,
|
||||
'SortedPages' => [
|
||||
'through' => AuthorSortedPageRelation::class,
|
||||
'from' => 'Parent',
|
||||
'to' => 'SortedPage',
|
||||
],
|
||||
);
|
||||
|
||||
private static $has_many = array(
|
||||
'PublishedPages' => RestfulServerTestPage::class,
|
||||
'Ratings' => RestfulServerTestAuthorRating::class,
|
||||
'SortedPagesRelation' => AuthorSortedPageRelation::class . '.Parent',
|
||||
);
|
||||
|
||||
public function canView($member = null)
|
||||
|
52
tests/unit/Stubs/RestfulServerTestExceptionThrown.php
Normal file
52
tests/unit/Stubs/RestfulServerTestExceptionThrown.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\RestfulServer\Tests\Stubs;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class RestfulServerTestExceptionThrown
|
||||
* @package SilverStripe\RestfulServer\Tests\Stubs
|
||||
*
|
||||
* @property string Content
|
||||
* @property string Title
|
||||
*/
|
||||
class RestfulServerTestExceptionThrown extends DataObject implements TestOnly
|
||||
{
|
||||
private static $api_access = true;
|
||||
|
||||
private static $table_name = 'RestfulServerTestExceptionThrown';
|
||||
|
||||
private static $db = array(
|
||||
'Content' => 'Text',
|
||||
'Title' => 'Text',
|
||||
);
|
||||
|
||||
public function onBeforeWrite()
|
||||
{
|
||||
parent::onBeforeWrite();
|
||||
|
||||
throw new \Exception('This is an exception test');
|
||||
}
|
||||
|
||||
public function canView($member = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canEdit($member = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canDelete($member = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canCreate($member = null, $context = array())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user