Skip to content

Commit

Permalink
Escape class names of result types named after PHP reserved keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
spawnia committed Oct 7, 2024
1 parent 340851f commit 2416ae1
Show file tree
Hide file tree
Showing 32 changed files with 283 additions and 84 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## v0.33.1

### Fixed

- Escape class names of result types named after PHP reserved keywords

## v0.33.0

### Changed
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ holds the decoded response returned from the server. You can just grab the `$dat
or `$extensions` off of it:

```php
$result->data // `null` or a generated subclass of `\Spawnia\Sailor\ObjectLike`
$result->errors // `null` or a list of `\Spawnia\Sailor\Error\Error`
$result->extensions // `null` or an arbitrary map
$catchResult->data // `null` or a generated subclass of `\Spawnia\Sailor\ObjectLike`
$catchResult->errors // `null` or a list of `\Spawnia\Sailor\Error\Error`
$catchResult->extensions // `null` or an arbitrary map
```

### Error handling
Expand Down
44 changes: 44 additions & 0 deletions examples/php-keywords/expected/Operations/AllCases.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php declare(strict_types=1);

namespace Spawnia\Sailor\PhpKeywords\Operations;

/**
* @extends \Spawnia\Sailor\Operation<\Spawnia\Sailor\PhpKeywords\Operations\AllCases\AllCasesResult>
*/
class AllCases extends \Spawnia\Sailor\Operation
{
public static function execute(): AllCases\AllCasesResult
{
return self::executeOperation(
);
}

protected static function converters(): array
{
static $converters;

return $converters ??= [
];
}

public static function document(): string
{
return /* @lang GraphQL */ 'query AllCases {
__typename
cases {
__typename
id
}
}';
}

public static function endpoint(): string
{
return 'php-keywords';
}

public static function config(): string
{
return \Safe\realpath(__DIR__ . '/../../sailor.php');
}
}
45 changes: 45 additions & 0 deletions examples/php-keywords/expected/Operations/AllCases/AllCases.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php declare(strict_types=1);

namespace Spawnia\Sailor\PhpKeywords\Operations\AllCases;

/**
* @property array<int, \Spawnia\Sailor\PhpKeywords\Operations\AllCases\Cases\_Case> $cases
* @property string $__typename
*/
class AllCases extends \Spawnia\Sailor\ObjectLike
{
/**
* @param array<int, \Spawnia\Sailor\PhpKeywords\Operations\AllCases\Cases\_Case> $cases
*/
public static function make($cases): self
{
$instance = new self;

if ($cases !== self::UNDEFINED) {
$instance->cases = $cases;
}
$instance->__typename = 'Query';

return $instance;
}

protected function converters(): array
{
static $converters;

return $converters ??= [
'cases' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\ListConverter(new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\PhpKeywords\Operations\AllCases\Cases\_Case))),
'__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter),
];
}

public static function endpoint(): string
{
return 'php-keywords';
}

public static function config(): string
{
return \Safe\realpath(__DIR__ . '/../../../sailor.php');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php declare(strict_types=1);

namespace Spawnia\Sailor\PhpKeywords\Operations\AllCases;

class AllCasesErrorFreeResult extends \Spawnia\Sailor\ErrorFreeResult
{
public AllCases $data;

public static function endpoint(): string
{
return 'php-keywords';
}

public static function config(): string
{
return \Safe\realpath(__DIR__ . '/../../../sailor.php');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types=1);

namespace Spawnia\Sailor\PhpKeywords\Operations\AllCases;

class AllCasesResult extends \Spawnia\Sailor\Result
{
public ?AllCases $data = null;

protected function setData(\stdClass $data): void
{
$this->data = AllCases::fromStdClass($data);
}

/**
* Useful for instantiation of successful mocked results.
*
* @return static
*/
public static function fromData(AllCases $data): self
{
$instance = new static;
$instance->data = $data;

return $instance;
}

public function errorFree(): AllCasesErrorFreeResult
{
return AllCasesErrorFreeResult::fromResult($this);
}

public static function endpoint(): string
{
return 'php-keywords';
}

public static function config(): string
{
return \Safe\realpath(__DIR__ . '/../../../sailor.php');
}
}
45 changes: 45 additions & 0 deletions examples/php-keywords/expected/Operations/AllCases/Cases/_Case.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php declare(strict_types=1);

namespace Spawnia\Sailor\PhpKeywords\Operations\AllCases\Cases;

/**
* @property string $id
* @property string $__typename
*/
class _Case extends \Spawnia\Sailor\ObjectLike
{
/**
* @param string $id
*/
public static function make($id): self
{
$instance = new self;

if ($id !== self::UNDEFINED) {
$instance->id = $id;
}
$instance->__typename = 'Case';

return $instance;
}

protected function converters(): array
{
static $converters;

return $converters ??= [
'id' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\IDConverter),
'__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter),
];
}

public static function endpoint(): string
{
return 'php-keywords';
}

public static function config(): string
{
return \Safe\realpath(__DIR__ . '/../../../../sailor.php');
}
}
42 changes: 31 additions & 11 deletions examples/php-keywords/sailor.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,37 @@ public function finder(): Finder

public function makeClient(): Client
{
return new MockClient(static fn(): Response => Response::fromStdClass((object) [
'data' => (object) [
'__typename' => 'Query',
'print' => (object) [
'__typename' => 'Switch',
'for' => _abstract::_class,
'int' => 42,
'as' => 69,
],
],
]));
return new MockClient(function (string $query, ?stdClass $variables): Response {
if (str_contains($query, 'print')) {
return Response::fromStdClass((object) [
'data' => (object) [
'__typename' => 'Query',
'print' => (object) [
'__typename' => 'Switch',
'for' => _abstract::_class,
'int' => 42,
'as' => 69,
],
],
]);
}

if (str_contains($query, 'cases')) {
return Response::fromStdClass((object) [
'data' => (object) [
'__typename' => 'Query',
'cases' => [
(object) [
'__typename' => 'Case',
'id' => 'asdf',
],
],
],
]);
}

throw new Exception("Unexpected query: {$query}.");
});
}
},
];
5 changes: 5 additions & 0 deletions examples/php-keywords/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
type Query {
print: Abstract
cases: [Case!]!
}

interface Abstract {
Expand All @@ -18,3 +19,7 @@ enum abstract {
input new {
unset: Float
}

type Case {
id: ID!
}
6 changes: 6 additions & 0 deletions examples/php-keywords/src/ReservedKeywords.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ query Catch {
}
}
}

query AllCases {
cases {
id
}
}
18 changes: 13 additions & 5 deletions examples/php-keywords/src/test.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@
require __DIR__ . '/../vendor/autoload.php';

use Spawnia\Sailor\PhpKeywords\Operations\_Catch;
use Spawnia\Sailor\PhpKeywords\Operations\_Catch\_Print\_Switch;
use Spawnia\Sailor\PhpKeywords\Operations\AllCases;
use Spawnia\Sailor\PhpKeywords\Types\_abstract;

$result = _Catch::execute();

$switch = $result->data->print;
assert($switch instanceof _Switch);
$catchResult = _Catch::execute();

$switch = $catchResult->data->print;
assert($switch instanceof _Catch\_Print\_Switch);
assert($switch->for === _abstract::_class);
assert($switch->int === 42);
assert($switch->as === 69);

$allCasesResult = AllCases::execute();

$cases = $allCasesResult->data->cases;
assert(is_array($cases));

$case1 = $cases[0];
assert($case1 instanceof AllCases\Cases\_Case);
assert($case1->id === 'asdf');
4 changes: 2 additions & 2 deletions src/Client/Log.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public function request(string $query, ?\stdClass $variables = null): Response

/**
* @return Generator<int, array{
* query: string,
* variables: array<string, mixed>|null,
* query: string,
* variables: array<string, mixed>|null,
* }>
*/
public function requests(): \Generator
Expand Down
4 changes: 1 addition & 3 deletions src/Codegen/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace Spawnia\Sailor\Codegen;

/**
* A generated file that should be written to a target.
*/
/** A generated file that should be written to a target. */
class File
{
public string $content;
Expand Down
2 changes: 0 additions & 2 deletions src/Codegen/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,6 @@ protected static function asPhpFile(ClassType $classType, PhpNamespace $namespac
*
* @param array<string, string> $documents
*
* @throws SyntaxError
*
* @return array<string, \GraphQL\Language\AST\DocumentNode>
*/
public static function parseDocuments(array $documents): array
Expand Down
6 changes: 2 additions & 4 deletions src/Codegen/ObjectLikeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
use Nette\PhpGenerator\PhpNamespace;
use Spawnia\Sailor\ObjectLike;

/**
* @phpstan-type PropertyArgs array{string, Type, string, string, mixed}
*/
/** @phpstan-type PropertyArgs array{string, Type, string, string, mixed} */
class ObjectLikeBuilder
{
private bool $isInputType;
Expand All @@ -32,7 +30,7 @@ class ObjectLikeBuilder
public function __construct(string $name, string $namespace, bool $isInputType)
{
$class = new ClassType(
$name,
Escaper::escapeClassName($name),
new PhpNamespace($namespace) // TODO drop escape when min PHP version is 8.0+
);

Expand Down
4 changes: 1 addition & 3 deletions src/Codegen/OperationBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
use Spawnia\Sailor\ObjectLike;
use Spawnia\Sailor\Operation;

/**
* @phpstan-type PropertyArgs array{string, Type, string, string, mixed}
*/
/** @phpstan-type PropertyArgs array{string, Type, string, string, mixed} */
class OperationBuilder
{
private ClassType $class;
Expand Down
4 changes: 1 addition & 3 deletions src/Console/InteractsWithEndpoints.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;

/**
* @mixin Command
*/
/** @mixin Command */
trait InteractsWithEndpoints
{
/** @return array<string, EndpointConfig> */
Expand Down
Loading

0 comments on commit 2416ae1

Please sign in to comment.