Skip to content

Commit

Permalink
Merge pull request #22 from TomHAnderson/feature/type-hardening
Browse files Browse the repository at this point in the history
Hardened all types
  • Loading branch information
TomHAnderson committed Nov 26, 2023
2 parents 7a0f34c + dbc29a5 commit 6fb8015
Show file tree
Hide file tree
Showing 22 changed files with 490 additions and 56 deletions.
15 changes: 12 additions & 3 deletions src/Type/Blob.php
Expand Up @@ -16,7 +16,6 @@

class Blob extends ScalarType
{
// phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
public string|null $description = 'A binary file base64 encoded.';

public function parseLiteral(ASTNode $valueNode, array|null $variables = null): string
Expand All @@ -27,14 +26,24 @@ public function parseLiteral(ASTNode $valueNode, array|null $variables = null):
public function parseValue(mixed $value): mixed
{
if (! is_string($value)) {
throw new Error('Blob as base64 is not a string: ' . $value);
throw new Error('Blob field as base64 is not a string: ' . $value);
}

return base64_decode($value, true);
$data = base64_decode($value, true);

if ($data === false) {
throw new Error('Blob field contains non-base64 encoded characters');
}

return $data;
}

public function serialize(mixed $value): mixed
{
if (! $value) {
return $value;
}

if (is_resource($value)) {
$value = stream_get_contents($value);
}
Expand Down
24 changes: 16 additions & 8 deletions src/Type/Date.php
Expand Up @@ -4,19 +4,19 @@

namespace ApiSkeletons\Doctrine\ORM\GraphQL\Type;

use DateTime as PHPDateTime;
use DateTime;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node as ASTNode;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Type\Definition\ScalarType;

use function is_string;
use function preg_match;

class Date extends ScalarType
{
// phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
public string|null $description = 'The `Date` scalar type represents datetime data.'
. 'The format is e.g. 2004-02-12';
. 'The format is e.g. 2004-02-12.';

public function parseLiteral(ASTNode $valueNode, array|null $variables = null): string
{
Expand All @@ -30,21 +30,29 @@ public function parseLiteral(ASTNode $valueNode, array|null $variables = null):
return $valueNode->value;
}

public function parseValue(mixed $value): PHPDateTime
public function parseValue(mixed $value): DateTime
{
if (! is_string($value)) {
throw new Error('Date is not a string: ' . $value);
}

return PHPDateTime::createFromFormat('Y-m-d', $value);
if (! preg_match('/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/', $value)) {
throw new Error('Date format does not match Y-m-d e.g. 2004-02-12.');
}

return DateTime::createFromFormat('Y-m-d', $value);
}

public function serialize(mixed $value): string|null
{
if ($value instanceof PHPDateTime) {
$value = $value->format('Y-m-d');
if (is_string($value)) {
throw new Error('Expected DateTime object. Got string.');
}

if (! $value instanceof DateTime) {
throw new Error('Expected DateTime object. Got ' . $value::class);
}

return $value;
return $value->format('Y-m-d');
}
}
24 changes: 16 additions & 8 deletions src/Type/DateImmutable.php
Expand Up @@ -4,19 +4,19 @@

namespace ApiSkeletons\Doctrine\ORM\GraphQL\Type;

use DateTimeImmutable as PHPDateTime;
use DateTimeImmutable;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node as ASTNode;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Type\Definition\ScalarType;

use function is_string;
use function preg_match;

class DateImmutable extends ScalarType
{
// phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
public string|null $description = 'The `date_immutable` scalar type represents datetime data.'
. 'The format is e.g. 2004-02-12';
. 'The format is e.g. 2004-02-12.';

public function parseLiteral(ASTNode $valueNode, array|null $variables = null): string
{
Expand All @@ -30,21 +30,29 @@ public function parseLiteral(ASTNode $valueNode, array|null $variables = null):
return $valueNode->value;
}

public function parseValue(mixed $value): PHPDateTime|false
public function parseValue(mixed $value): DateTimeImmutable|false
{
if (! is_string($value)) {
throw new Error('Date is not a string: ' . $value);
}

return PHPDateTime::createFromFormat('Y-m-d', $value);
if (! preg_match('/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/', $value)) {
throw new Error('Date format does not match Y-m-d e.g. 2004-02-12.');
}

return DateTimeImmutable::createFromFormat('Y-m-d', $value);
}

public function serialize(mixed $value): string|null
{
if ($value instanceof PHPDateTime) {
$value = $value->format('Y-m-d');
if (is_string($value)) {
throw new Error('Expected DateTimeImmutable object. Got string.');
}

if (! $value instanceof DateTimeImmutable) {
throw new Error('Expected DateTimeImmutable object. Got ' . $value::class);
}

return $value;
return $value->format('Y-m-d');
}
}
16 changes: 11 additions & 5 deletions src/Type/DateTime.php
Expand Up @@ -15,8 +15,8 @@
class DateTime extends ScalarType
{
// phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
public string|null $description = 'The `DateTime` scalar type represents datetime data.'
. 'The format is ISO-8601 e.g. 2004-02-12T15:19:21+00:00';
public string|null $description = 'The `datetime` scalar type represents datetime data.'
. 'The format is ISO-8601 e.g. 2004-02-12T15:19:21+00:00.';

public function parseLiteral(ASTNode $valueNode, array|null $variables = null): string
{
Expand All @@ -33,16 +33,22 @@ public function parseLiteral(ASTNode $valueNode, array|null $variables = null):
public function parseValue(mixed $value): PHPDateTime
{
if (! is_string($value)) {
throw new Error('Date is not a string: ' . $value);
throw new Error('datetime is not a string: ' . $value);
}

return PHPDateTime::createFromFormat('Y-m-d\TH:i:sP', $value);
$data = PHPDateTime::createFromFormat(PHPDateTime::ATOM, $value);

if ($data === false) {
throw new Error('datetime format does not match ISO 8601.');
}

return $data;
}

public function serialize(mixed $value): string|null
{
if ($value instanceof PHPDateTime) {
$value = $value->format('c');
$value = $value->format(PHPDateTime::ATOM);
}

return $value;
Expand Down
18 changes: 12 additions & 6 deletions src/Type/DateTimeImmutable.php
Expand Up @@ -4,7 +4,7 @@

namespace ApiSkeletons\Doctrine\ORM\GraphQL\Type;

use DateTimeImmutable as PHPDateTime;
use DateTimeImmutable as PHPDateTimeImmutable;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node as ASTNode;
use GraphQL\Language\AST\StringValueNode;
Expand All @@ -30,19 +30,25 @@ public function parseLiteral(ASTNode $valueNode, array|null $variables = null):
return $valueNode->value;
}

public function parseValue(mixed $value): PHPDateTime|false
public function parseValue(mixed $value): PHPDateTimeImmutable
{
if (! is_string($value)) {
throw new Error('Date is not a string: ' . $value);
throw new Error('datetime_immutable is not a string: ' . $value);
}

return PHPDateTime::createFromFormat('Y-m-d\TH:i:sP', $value);
$data = PHPDateTimeImmutable::createFromFormat(PHPDateTimeImmutable::ATOM, $value);

if ($data === false) {
throw new Error('datetime_immutable format does not match ISO 8601.');
}

return $data;
}

public function serialize(mixed $value): string|null
{
if ($value instanceof PHPDateTime) {
$value = $value->format('c');
if ($value instanceof PHPDateTimeImmutable) {
$value = $value->format(PHPDateTimeImmutable::ATOM);
}

return $value;
Expand Down
49 changes: 48 additions & 1 deletion src/Type/DateTimeTZ.php
Expand Up @@ -4,6 +4,53 @@

namespace ApiSkeletons\Doctrine\ORM\GraphQL\Type;

class DateTimeTZ extends DateTime
use DateTime as PHPDateTimeTZ;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node as ASTNode;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Type\Definition\ScalarType;

use function is_string;

class DateTimeTZ extends ScalarType
{
// phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
public string|null $description = 'The `datetimetz` scalar type represents datetime data.'
. 'The format is ISO-8601 e.g. 2004-02-12T15:19:21+00:00.';

public function parseLiteral(ASTNode $valueNode, array|null $variables = null): string
{
// @codeCoverageIgnoreStart
if (! $valueNode instanceof StringValueNode) {
throw new Error('Query error: Can only parse strings got: ' . $valueNode->kind, $valueNode);
}

// @codeCoverageIgnoreEnd

return $valueNode->value;
}

public function parseValue(mixed $value): PHPDateTimeTZ
{
if (! is_string($value)) {
throw new Error('datetimetz is not a string: ' . $value);
}

$data = PHPDateTimeTZ::createFromFormat(PHPDateTimeTZ::ATOM, $value);

if ($data === false) {
throw new Error('datetimetz format does not match ISO 8601.');
}

return $data;
}

public function serialize(mixed $value): string|null
{
if ($value instanceof PHPDateTimeTZ) {
$value = $value->format(PHPDateTimeTZ::ATOM);
}

return $value;
}
}
49 changes: 48 additions & 1 deletion src/Type/DateTimeTZImmutable.php
Expand Up @@ -4,6 +4,53 @@

namespace ApiSkeletons\Doctrine\ORM\GraphQL\Type;

class DateTimeTZImmutable extends DateTimeImmutable
use DateTimeImmutable as PHPDateTimeTZImmutable;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node as ASTNode;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Type\Definition\ScalarType;

use function is_string;

class DateTimeTZImmutable extends ScalarType
{
// phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
public string|null $description = 'The `datetimetz_immutable` scalar type represents datetime data.'
. 'The format is ISO-8601 e.g. 2004-02-12T15:19:21+00:00';

public function parseLiteral(ASTNode $valueNode, array|null $variables = null): string
{
// @codeCoverageIgnoreStart
if (! $valueNode instanceof StringValueNode) {
throw new Error('Query error: Can only parse strings got: ' . $valueNode->kind, $valueNode);
}

// @codeCoverageIgnoreEnd

return $valueNode->value;
}

public function parseValue(mixed $value): PHPDateTimeTZImmutable|false
{
if (! is_string($value)) {
throw new Error('datetimetz_immutable is not a string: ' . $value);
}

$data = PHPDateTimeTZImmutable::createFromFormat(PHPDateTimeTZImmutable::ATOM, $value);

if ($data === false) {
throw new Error('datetimetz_immutable format does not match ISO 8601.');
}

return $data;
}

public function serialize(mixed $value): string|null
{
if ($value instanceof PHPDateTimeTZImmutable) {
$value = $value->format(PHPDateTimeTZImmutable::ATOM);
}

return $value;
}
}
12 changes: 9 additions & 3 deletions src/Type/Json.php
Expand Up @@ -15,7 +15,7 @@
class Json extends ScalarType
{
// phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
public string|null $description = 'The `JSON` scalar type represents json data.';
public string|null $description = 'The `json` scalar type represents json data.';

public function parseLiteral(ASTNode $valueNode, array|null $variables = null): string
{
Expand All @@ -30,10 +30,16 @@ public function parseLiteral(ASTNode $valueNode, array|null $variables = null):
public function parseValue(mixed $value): array|null
{
if (! is_string($value)) {
throw new Error('Json is not a string: ' . $value);
throw new Error('JSON is not a string: ' . $value);
}

return json_decode($value, true);
$data = json_decode($value, true);

if (! $data) {
throw new Error('Could not parse JSON data');
}

return $data;
}

public function serialize(mixed $value): string|null
Expand Down

0 comments on commit 6fb8015

Please sign in to comment.