mirror of
https://github.com/silverstripe/silverstripe-restfulserver
synced 2024-10-22 14:05:58 +02:00
Merge pull request #50 from silverstripe-terraformers/feature/validation-result
SS4: Catch ValidationExceptions and return ValidationResult messages.
This commit is contained in:
commit
c30b72e058
@ -260,6 +260,9 @@ abstract class DataFormatter
|
||||
return $this->removeFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOutputContentType()
|
||||
{
|
||||
return $this->outputContentType;
|
||||
@ -341,14 +344,28 @@ abstract class DataFormatter
|
||||
|
||||
/**
|
||||
* Convert a single data object to this format. Return a string.
|
||||
*
|
||||
* @param DataObjectInterface $do
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function convertDataObject(DataObjectInterface $do);
|
||||
|
||||
/**
|
||||
* Convert a data object set to this format. Return a string.
|
||||
*
|
||||
* @param SS_List $set
|
||||
* @return string
|
||||
*/
|
||||
abstract public function convertDataObjectSet(SS_List $set);
|
||||
|
||||
/**
|
||||
* Convert an array to this format. Return a string.
|
||||
*
|
||||
* @param $array
|
||||
* @return string
|
||||
*/
|
||||
abstract public function convertArray($array);
|
||||
|
||||
/**
|
||||
* @param string $strData HTTP Payload as string
|
||||
*/
|
||||
|
@ -22,6 +22,9 @@ class JSONDataFormatter extends DataFormatter
|
||||
|
||||
protected $outputContentType = 'application/json';
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function supportedExtensions()
|
||||
{
|
||||
return array(
|
||||
@ -30,6 +33,9 @@ class JSONDataFormatter extends DataFormatter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function supportedMimeTypes()
|
||||
{
|
||||
return array(
|
||||
@ -38,6 +44,15 @@ class JSONDataFormatter extends DataFormatter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
* @return string
|
||||
*/
|
||||
public function convertArray($array)
|
||||
{
|
||||
return Convert::array2json($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a JSON representation of the given {@link DataObject}.
|
||||
*
|
||||
@ -163,6 +178,10 @@ class JSONDataFormatter extends DataFormatter
|
||||
return Convert::array2json($serobj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $strData
|
||||
* @return array|bool|void
|
||||
*/
|
||||
public function convertStringToArray($strData)
|
||||
{
|
||||
return Convert::json2array($strData);
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\RestfulServer\DataFormatter;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\RestfulServer\DataFormatter;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
@ -24,6 +25,9 @@ class XMLDataFormatter extends DataFormatter
|
||||
|
||||
protected $outputContentType = 'text/xml';
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function supportedExtensions()
|
||||
{
|
||||
return array(
|
||||
@ -31,6 +35,9 @@ class XMLDataFormatter extends DataFormatter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function supportedMimeTypes()
|
||||
{
|
||||
return array(
|
||||
@ -39,6 +46,48 @@ class XMLDataFormatter extends DataFormatter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function convertArray($array)
|
||||
{
|
||||
$response = Controller::curr()->getResponse();
|
||||
if ($response) {
|
||||
$response->addHeader("Content-Type", "text/xml");
|
||||
}
|
||||
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
|
||||
<response>{$this->convertArrayWithoutHeader($array)}</response>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function convertArrayWithoutHeader($array)
|
||||
{
|
||||
$xml = '';
|
||||
|
||||
foreach ($array as $fieldName => $fieldValue) {
|
||||
if (is_array($fieldValue)) {
|
||||
if (is_numeric($fieldName)) {
|
||||
$fieldName = 'Item';
|
||||
}
|
||||
|
||||
$xml .= "<{$fieldName}>\n";
|
||||
$xml .= $this->convertArrayWithoutHeader($fieldValue);
|
||||
$xml .= "</{$fieldName}>\n";
|
||||
} else {
|
||||
$xml .= "<$fieldName>$fieldValue</$fieldName>\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an XML representation of the given {@link DataObject}.
|
||||
*
|
||||
@ -56,6 +105,12 @@ class XMLDataFormatter extends DataFormatter
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" . $this->convertDataObjectWithoutHeader($obj, $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataObject $obj
|
||||
* @param null $fields
|
||||
* @param null $relations
|
||||
* @return string
|
||||
*/
|
||||
public function convertDataObjectWithoutHeader(DataObject $obj, $fields = null, $relations = null)
|
||||
{
|
||||
$className = $this->sanitiseClassName(get_class($obj));
|
||||
@ -195,6 +250,11 @@ class XMLDataFormatter extends DataFormatter
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $strData
|
||||
* @return array|void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function convertStringToArray($strData)
|
||||
{
|
||||
return Convert::xml2array($strData);
|
||||
|
@ -10,6 +10,8 @@ use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\ORM\ValidationException;
|
||||
use SilverStripe\ORM\ValidationResult;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
@ -443,8 +445,13 @@ class RestfulServer extends Controller
|
||||
return $this->unsupportedMediaType();
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var DataObject|string */
|
||||
$obj = $this->updateDataObject($obj, $reqFormatter);
|
||||
} catch (ValidationException $e) {
|
||||
return $this->validationFailure($responseFormatter, $e->getResult());
|
||||
}
|
||||
|
||||
if (is_string($obj)) {
|
||||
return $obj;
|
||||
}
|
||||
@ -515,8 +522,13 @@ class RestfulServer extends Controller
|
||||
|
||||
$responseFormatter = $this->getResponseDataFormatter($className);
|
||||
|
||||
try {
|
||||
/** @var DataObject|string $obj */
|
||||
$obj = $this->updateDataObject($obj, $reqFormatter);
|
||||
} catch (ValidationException $e) {
|
||||
return $this->validationFailure($responseFormatter, $e->getResult());
|
||||
}
|
||||
|
||||
if (is_string($obj)) {
|
||||
return $obj;
|
||||
}
|
||||
@ -643,6 +655,9 @@ class RestfulServer extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function permissionFailure()
|
||||
{
|
||||
// return a 401
|
||||
@ -652,6 +667,9 @@ class RestfulServer extends Controller
|
||||
return "You don't have access to this item through the API.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function notFound()
|
||||
{
|
||||
// return a 404
|
||||
@ -660,6 +678,9 @@ class RestfulServer extends Controller
|
||||
return "That object wasn't found";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function methodNotAllowed()
|
||||
{
|
||||
$this->getResponse()->setStatusCode(405);
|
||||
@ -667,6 +688,9 @@ class RestfulServer extends Controller
|
||||
return "Method Not Allowed";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function unsupportedMediaType()
|
||||
{
|
||||
$this->response->setStatusCode(415); // Unsupported Media Type
|
||||
@ -674,6 +698,23 @@ class RestfulServer extends Controller
|
||||
return "Unsupported Media Type";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ValidationResult $result
|
||||
* @return mixed
|
||||
*/
|
||||
protected function validationFailure(DataFormatter $responseFormatter, ValidationResult $result)
|
||||
{
|
||||
$this->getResponse()->setStatusCode(400);
|
||||
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
|
||||
|
||||
$response = [
|
||||
'type' => ValidationException::class,
|
||||
'messages' => $result->getMessages(),
|
||||
];
|
||||
|
||||
return $responseFormatter->convertArray($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to authenticate a user
|
||||
*
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestAuthorRating;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\RestfulServer\Tests\Stubs\RestfulServerTestValidationFailure;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
@ -572,4 +573,17 @@ class RestfulServerTest extends SapphireTest
|
||||
unset($_SERVER['PHP_AUTH_USER']);
|
||||
unset($_SERVER['PHP_AUTH_PW']);
|
||||
}
|
||||
|
||||
public function testValidationErrorWithPOST()
|
||||
{
|
||||
$urlSafeClassname = $this->urlSafeClassname(RestfulServerTestValidationFailure::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('SilverStripe\\ORM\\ValidationException', $responseArr['type']);
|
||||
}
|
||||
}
|
||||
|
63
tests/unit/Stubs/RestfulServerTestValidationFailure.php
Normal file
63
tests/unit/Stubs/RestfulServerTestValidationFailure.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\RestfulServer\Tests\Stubs;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class RestfulServerTestValidationFailure
|
||||
* @package SilverStripe\RestfulServer\Tests\Stubs
|
||||
*
|
||||
* @property string Content
|
||||
* @property string Title
|
||||
*/
|
||||
class RestfulServerTestValidationFailure extends DataObject implements TestOnly
|
||||
{
|
||||
private static $api_access = true;
|
||||
|
||||
private static $table_name = 'RestfulServerTestValidationFailure';
|
||||
|
||||
private static $db = array(
|
||||
'Content' => 'Text',
|
||||
'Title' => 'Text',
|
||||
);
|
||||
|
||||
/**
|
||||
* @return \SilverStripe\ORM\ValidationResult
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$result = parent::validate();
|
||||
|
||||
if (strlen($this->Content) === 0) {
|
||||
$result->addFieldError('Content', 'Content required');
|
||||
}
|
||||
|
||||
if (strlen($this->Title) === 0) {
|
||||
$result->addFieldError('Title', 'Title required');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
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