diff --git a/examples/request_superglobals.php b/examples/request_superglobals.php index fff59921..fc4f02a7 100644 --- a/examples/request_superglobals.php +++ b/examples/request_superglobals.php @@ -62,6 +62,7 @@ // useful for determining how to process the request (list/get/create/update) var_dump($requestParser->hasIncludePaths()); +var_dump($requestParser->hasAnySparseFieldset()); var_dump($requestParser->hasSparseFieldset('user')); var_dump($requestParser->hasSortFields()); var_dump($requestParser->hasPagination()); @@ -84,5 +85,10 @@ var_dump($requestParser->getRelationship('ship')); var_dump($requestParser->getMeta('lock')); -// get the full document for custom processing +// useful for determining how to process the request (list/get/create/update) +var_dump($requestParser->hasQueryParameters()); +var_dump($requestParser->hasDocument()); + +// get the full query parameters or document for custom processing +var_dump($requestParser->getQueryParameters()); var_dump($requestParser->getDocument()); diff --git a/src/helpers/RequestParser.php b/src/helpers/RequestParser.php index 5209fda6..0958cee7 100644 --- a/src/helpers/RequestParser.php +++ b/src/helpers/RequestParser.php @@ -25,11 +25,11 @@ class RequestParser { 'useAnnotatedSortFields' => true, ]; /** @var string */ - private $selfLink = ''; + protected $selfLink = ''; /** @var array */ - private $queryParameters = []; + protected $queryParameters = []; /** @var array */ - private $document = []; + protected $document = []; /** * @param string $selfLink the uri used to make this request {@see getSelfLink()} @@ -47,8 +47,33 @@ public function __construct($selfLink='', array $queryParameters=[], array $docu */ public static function fromSuperglobals() { $selfLink = ''; - if (isset($_SERVER['REQUEST_SCHEME']) && isset($_SERVER['HTTP_HOST']) && isset($_SERVER['REQUEST_URI'])) { - $selfLink = $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; + + if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + $selfLink .= $_SERVER['HTTP_X_FORWARDED_PROTO'].'://'; + } + elseif (isset($_SERVER['REQUEST_SCHEME'])) { + $selfLink .= $_SERVER['REQUEST_SCHEME'].'://'; + } + else { + $selfLink .= 'http://'; + } + + if (isset($_SERVER['HTTP_HOST'])) { + $selfLink .= $_SERVER['HTTP_HOST']; + } + elseif (isset($_SERVER['SCRIPT_URI'])) { + $startOfDomain = strpos($_SERVER['SCRIPT_URI'], '://') + strlen('://'); + $endOfDomain = strpos($_SERVER['SCRIPT_URI'], '/', $startOfDomain); + $lengthOfDomain = ($endOfDomain - $startOfDomain); + $selfLink .= substr($_SERVER['SCRIPT_URI'], $startOfDomain, $lengthOfDomain); + } + + if (isset($_SERVER['REQUEST_URI'])) { + $selfLink .= $_SERVER['REQUEST_URI']; + } + elseif (isset($_SERVER['PATH_INFO']) && isset($_SERVER['QUERY_STRING'])) { + $selfLink .= $_SERVER['PATH_INFO']; + $selfLink .= ($_SERVER['QUERY_STRING'] !== '') ? '?'.$_SERVER['QUERY_STRING'] : ''; } $queryParameters = $_GET; @@ -150,6 +175,13 @@ public function getIncludePaths(array $options=[]) { return $restructured; } + /** + * @return boolean + */ + public function hasAnySparseFieldset() { + return (isset($this->queryParameters['fields'])); + } + /** * @param string $type * @return boolean @@ -333,6 +365,27 @@ public function getMeta($metaKey) { return $this->document['meta'][$metaKey]; } + /** + * @return boolean + */ + public function hasQueryParameters() { + return ($this->queryParameters !== []); + } + + /** + * @return array + */ + public function getQueryParameters() { + return $this->queryParameters; + } + + /** + * @return boolean + */ + public function hasDocument() { + return ($this->document !== []); + } + /** * @return array */ diff --git a/tests/helpers/RequestParserTest.php b/tests/helpers/RequestParserTest.php index fd170616..e3a8f878 100644 --- a/tests/helpers/RequestParserTest.php +++ b/tests/helpers/RequestParserTest.php @@ -54,6 +54,7 @@ public function testFromSuperglobals_HappyPath() { $this->assertSame('https://example.org/user/42?'.http_build_query($_GET), $requestParser->getSelfLink()); $this->assertTrue($requestParser->hasIncludePaths()); + $this->assertTrue($requestParser->hasAnySparseFieldset()); $this->assertTrue($requestParser->hasSparseFieldset('user')); $this->assertTrue($requestParser->hasSortFields()); $this->assertTrue($requestParser->hasPagination()); @@ -73,6 +74,10 @@ public function testFromSuperglobals_HappyPath() { $this->assertSame(['data' => ['type' => 'ship', 'id' => '42']], $requestParser->getRelationship('ship')); $this->assertSame(true, $requestParser->getMeta('lock')); + $this->assertTrue($requestParser->hasQueryParameters()); + $this->assertTrue($requestParser->hasDocument()); + + $this->assertSame($_GET, $requestParser->getQueryParameters()); $this->assertSame($_POST, $requestParser->getDocument()); } @@ -90,10 +95,33 @@ public function testFromSuperglobals_WithPhpInputStream() { $this->assertSame([], $requestParser->getDocument()); } + public function testFromSuperglobals_WithForwarding() { + unset($_SERVER['REQUEST_SCHEME']); + unset($_SERVER['HTTP_HOST']); + unset($_SERVER['REQUEST_URI']); + unset($_SERVER['CONTENT_TYPE']); + + $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https'; + $_SERVER['SCRIPT_URI'] = 'http://example.org/users'; + $_SERVER['PATH_INFO'] = '/users'; + $_SERVER['QUERY_STRING'] = 'include=foo'; + + $_GET = []; + $_POST = []; + + $requestParser = RequestParser::fromSuperglobals(); + + $this->assertSame('https://example.org/users?include=foo', $requestParser->getSelfLink()); + } + public function testFromSuperglobals_WithoutServerContext() { + unset($_SERVER['HTTP_X_FORWARDED_PROTO']); unset($_SERVER['REQUEST_SCHEME']); unset($_SERVER['HTTP_HOST']); + unset($_SERVER['SCRIPT_URI']); unset($_SERVER['REQUEST_URI']); + unset($_SERVER['PATH_INFO']); + unset($_SERVER['QUERY_STRING']); unset($_SERVER['CONTENT_TYPE']); $_GET = []; @@ -145,6 +173,7 @@ public function testFromPsrRequest_WithRequestInterface() { $this->assertSame('https://example.org/user/42?'.http_build_query($queryParameters), $requestParser->getSelfLink()); $this->assertTrue($requestParser->hasIncludePaths()); + $this->assertTrue($requestParser->hasAnySparseFieldset()); $this->assertTrue($requestParser->hasSparseFieldset('user')); $this->assertTrue($requestParser->hasSortFields()); $this->assertTrue($requestParser->hasPagination()); @@ -164,6 +193,10 @@ public function testFromPsrRequest_WithRequestInterface() { $this->assertSame(['data' => ['type' => 'ship', 'id' => '42']], $requestParser->getRelationship('ship')); $this->assertSame(true, $requestParser->getMeta('lock')); + $this->assertTrue($requestParser->hasQueryParameters()); + $this->assertTrue($requestParser->hasDocument()); + + $this->assertSame($queryParameters, $requestParser->getQueryParameters()); $this->assertSame($document, $requestParser->getDocument()); } @@ -253,6 +286,21 @@ public function testGetIncludePaths_Raw() { $this->assertSame(['foo', 'bar', 'baz.baf'], $requestParser->getIncludePaths($options)); } + public function testHasAnySparseFieldset() { + $queryParameters = []; + $requestParser = new RequestParser($selfLink='', $queryParameters); + $this->assertFalse($requestParser->hasAnySparseFieldset()); + + // not allowed, but possible + $queryParameters = ['fields' => '']; + $requestParser = new RequestParser($selfLink='', $queryParameters); + $this->assertTrue($requestParser->hasAnySparseFieldset()); + + $queryParameters = ['fields' => ['foo' => 'bar', 'baf' => 'baz']]; + $requestParser = new RequestParser($selfLink='', $queryParameters); + $this->assertTrue($requestParser->hasAnySparseFieldset()); + } + public function testHasSparseFieldset() { $requestParser = new RequestParser(); $this->assertFalse($requestParser->hasSparseFieldset('foo')); @@ -374,7 +422,7 @@ public function testHasAttribute() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertTrue($requestParser->hasAttribute('foo')); $this->assertFalse($requestParser->hasAttribute('bar')); } @@ -388,7 +436,7 @@ public function testGetAttribute() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame('bar', $requestParser->getAttribute('foo')); } @@ -410,7 +458,7 @@ public function testHasRelationship() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertTrue($requestParser->hasRelationship('foo')); $this->assertFalse($requestParser->hasRelationship('bar')); } @@ -429,7 +477,7 @@ public function testGetRelationship() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame(['data' => ['type' => 'bar', 'id' => '42']], $requestParser->getRelationship('foo')); } @@ -444,7 +492,7 @@ public function testHasMeta() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertTrue($requestParser->hasMeta('foo')); $this->assertFalse($requestParser->hasMeta('bar')); } @@ -456,10 +504,54 @@ public function testGetMeta() { ], ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame('bar', $requestParser->getMeta('foo')); } + public function testHasQueryParameters() { + $queryParameters = []; + $requestParser = new RequestParser($selfLink='', $queryParameters, $document=[]); + $this->assertFalse($requestParser->hasQueryParameters()); + + $queryParameters = [ + 'filter' => '42', + ]; + $requestParser = new RequestParser($selfLink='', $queryParameters, $document=[]); + $this->assertTrue($requestParser->hasQueryParameters()); + } + + public function testGetQueryParameters() { + $queryParameters = [ + 'include' => 'ship,ship.wing', + 'fields' => [ + 'user' => 'name,location', + ], + 'sort' => 'name,-location', + 'page' => [ + 'number' => '2', + 'size' => '10', + ], + 'filter' => '42', + ]; + + $requestParser = new RequestParser($selfLink='', $queryParameters, $document=[]); + $this->assertSame($queryParameters, $requestParser->getQueryParameters()); + } + + public function testHasDocument() { + $document = []; + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); + $this->assertFalse($requestParser->hasDocument()); + + $document = [ + 'meta' => [ + 'foo' => 'bar', + ], + ]; + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); + $this->assertTrue($requestParser->hasDocument()); + } + public function testGetDocument() { $document = [ 'data' => [ @@ -481,7 +573,7 @@ public function testGetDocument() { 'foo' => 'bar', ]; - $requestParser = new RequestParser($selfLink='', $quaryParameters=[], $document); + $requestParser = new RequestParser($selfLink='', $queryParameters=[], $document); $this->assertSame($document, $requestParser->getDocument()); } }