Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

patch: drop DoctrineAnnotations #677

Merged
merged 8 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"require": {
"php": ">=8.1",
"ext-json": "*",
"doctrine/annotations": "^1.14 || ^2.0",
"composer/package-versions-deprecated": "^1.8",
"phpdocumentor/reflection-docblock": "^4.3 || ^5.0",
"phpdocumentor/type-resolver": "^1.4",
Expand Down
269 changes: 57 additions & 212 deletions src/AnnotationReader.php

Large diffs are not rendered by default.

35 changes: 15 additions & 20 deletions src/Annotations/Autowire.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,36 @@
use function ltrim;

/**
* Use this annotation to autowire a service from the container into a given parameter of a field/query/mutation.
*
* @Annotation
* @Target({"METHOD", "ANNOTATION"})
* @Attributes({
* @Attribute("for", type = "string"),
* @Attribute("identifier", type = "string")
* })
* Use this attribute to autowire a service from the container into a given parameter of a field/query/mutation.
*/
#[Attribute(Attribute::TARGET_PARAMETER)]
class Autowire implements ParameterAnnotationInterface
{
/** @var string|null */
private $for;
/** @var string|null */
private $identifier;

/** @param array<string, mixed>|string $identifier */
public function __construct(array|string $identifier = [])
private string|null $for = null;
private string|null $identifier = null;

/** @param array<string, mixed>|string $params */
public function __construct(
array|string $params = [],
string|null $for = null,
string|null $identifier = null,
)
{
$values = $identifier;
$values = $params;
if (is_string($values)) {
$this->identifier = $values;
} else {
$this->identifier = $values['identifier'] ?? $values['value'] ?? null;
if (isset($values['for'])) {
$this->for = ltrim($values['for'], '$');
$this->identifier = $identifier ?? $values['identifier'] ?? $values['value'] ?? null;
if (isset($values['for']) || $for !== null) {
$this->for = ltrim($for ?? $values['for'], '$');
}
}
}

public function getTarget(): string
{
if ($this->for === null) {
throw new BadMethodCallException('The @Autowire annotation must be passed a target. For instance: "@Autowire(for="$myService")"');
throw new BadMethodCallException('The #[Autowire] attribute must be passed a target. For instance: "#[Autowire(for: "$myService")]"');
}
return $this->for;
}
Expand Down
13 changes: 3 additions & 10 deletions src/Annotations/Decorate.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,13 @@
use function is_string;

/**
* Methods with this annotation are decorating an input type when the input type is resolved.
* Methods with this attribute are decorating an input type when the input type is resolved.
* This is meant to be used only when the input type is provided by a third-party library and you want to modify it.
*
* @Annotation
* @Target({"METHOD"})
* @Attributes({
* @Attribute("inputTypeName", type = "string"),
* })
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Decorate
{
/** @var string */
private $inputTypeName;
private string $inputTypeName;

/**
* @param array<string, mixed>|string $inputTypeName
Expand All @@ -36,7 +29,7 @@ public function __construct(array|string $inputTypeName = [])
if (is_string($values)) {
$this->inputTypeName = $values;
} elseif (! isset($values['value']) && ! isset($values['inputTypeName'])) {
throw new BadMethodCallException('The @Decorate annotation must be passed an input type. For instance: "@Decorate("MyInputType")"');
throw new BadMethodCallException('The #[Decorate] attribute must be passed an input type. For instance: "#[Decorate("MyInputType")]"');
} else {
$this->inputTypeName = $values['value'] ?? $values['inputTypeName'];
}
Expand Down
4 changes: 2 additions & 2 deletions src/Annotations/Exceptions/ClassNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ public static function couldNotFindClass(string $className): self

public static function wrapException(self $e, string $className): self
{
return new self($e->getMessage() . " defined in @Type annotation of class '" . $className . "'");
return new self($e->getMessage() . " defined in #[Type] attribute of class '" . $className . "'");
}

public static function wrapExceptionForExtendTag(self $e, string $className): self
{
return new self($e->getMessage() . " defined in @ExtendType annotation of class '" . $className . "'");
return new self($e->getMessage() . " defined in #[ExtendType] attribute of class '" . $className . "'");
}
}
7 changes: 1 addition & 6 deletions src/Annotations/Exceptions/InvalidParameterException.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@

class InvalidParameterException extends BadMethodCallException
{
public static function parameterNotFound(string $parameter, string $annotationClass, ReflectionMethod $reflectionMethod): self
{
return new self(sprintf('Parameter "%s" declared in annotation "%s" of method "%s::%s()" does not exist.', $parameter, $annotationClass, $reflectionMethod->getDeclaringClass()->getName(), $reflectionMethod->getName()));
}

public static function parameterNotFoundFromSourceField(string $parameter, string $annotationClass, ReflectionMethod $reflectionMethod): self
{
return new self(sprintf('Could not find parameter "%s" declared in annotation "%s". This annotation is itself declared in a SourceField annotation targeting resolver "%s::%s()".', $parameter, $annotationClass, $reflectionMethod->getDeclaringClass()->getName(), $reflectionMethod->getName()));
return new self(sprintf('Could not find parameter "%s" declared in annotation "%s". This annotation is itself declared in a SourceField attribute targeting resolver "%s::%s()".', $parameter, $annotationClass, $reflectionMethod->getDeclaringClass()->getName(), $reflectionMethod->getName()));
}
}
11 changes: 2 additions & 9 deletions src/Annotations/ExtendType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,7 @@
use function ltrim;

/**
* The ExtendType annotation must be put in a GraphQL type class docblock and is used to add additional fields to the underlying PHP class.
*
* @Annotation
* @Target({"CLASS"})
* @Attributes({
* @Attribute("class", type = "string"),
* @Attribute("name", type = "string"),
* })
* The ExtendType attribute must be put in a GraphQL type class docblock and is used to add additional fields to the underlying PHP class.
*/
#[Attribute(Attribute::TARGET_CLASS)]
class ExtendType
Expand All @@ -41,7 +34,7 @@ public function __construct(array $attributes = [], string|null $class = null, s
$this->name = $name ?? $attributes['name'] ?? null;
$this->class = $className;
if (! $this->class && ! $this->name) {
throw new BadMethodCallException('In annotation @ExtendType, missing one of the compulsory parameter "class" or "name".');
throw new BadMethodCallException('In attribute #[ExtendType], missing one of the compulsory parameter "class" or "name".');
}
}

Expand Down
9 changes: 1 addition & 8 deletions src/Annotations/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@

/**
* Factories are methods used to declare GraphQL input types.
*
* @Annotation
* @Target({"METHOD"})
* @Attributes({
* @Attribute("name", type = "string"),
* @Attribute("default", type = "bool")
* })
*/
#[Attribute(Attribute::TARGET_METHOD)]
class Factory
Expand All @@ -33,7 +26,7 @@ public function __construct(array $attributes = [], string|null $name = null, bo
$this->default = $default ?? $attributes['default'] ?? ! isset($attributes['name']);

if ($this->name === null && $this->default === false) {
throw new GraphQLRuntimeException('A @Factory that has "default=false" attribute must be given a name (i.e. add a name="FooBarInput" attribute).');
throw new GraphQLRuntimeException('A #[Factory] that has "default=false" attribute must be given a name (i.e. add a name="FooBarInput" attribute).');
}
}

Expand Down
12 changes: 3 additions & 9 deletions src/Annotations/FailWith.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@
use function array_key_exists;
use function is_array;

/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
* @Attributes({
* @Attribute("value", type = "mixed"),
* @Attribute("mode", type = "string")
* })
*/
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)]
class FailWith implements MiddlewareAnnotationInterface
{
Expand All @@ -35,8 +27,10 @@ public function __construct(mixed $values = [], mixed $value = '__fail__with__ma
$this->value = $value;
} elseif (is_array($values) && array_key_exists('value', $values)) {
$this->value = $values['value'];
} elseif (! is_array($values)) {
$this->value = $values;
} else {
throw new BadMethodCallException('The @FailWith annotation must be passed a defaultValue. For instance: "@FailWith(null)"');
throw new BadMethodCallException('The #[FailWith] attribute must be passed a defaultValue. For instance: "#[FailWith(null)]"');
}
}

Expand Down
12 changes: 0 additions & 12 deletions src/Annotations/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,6 @@

use const E_USER_DEPRECATED;

/**
* @Annotation
* @Target({"PROPERTY", "METHOD"})
* @Attributes({
* @Attribute("name", type = "string"),
* @Attribute("outputType", type = "string"),
* @Attribute("prefetchMethod", type = "string"),
* @Attribute("for", type = "string[]"),
* @Attribute("description", type = "string"),
* @Attribute("inputType", type = "string"),
* })
*/
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Field extends AbstractRequest
{
Expand Down
5 changes: 1 addition & 4 deletions src/Annotations/HideIfUnauthorized.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
use Attribute;

/**
* Fields/Queries/Mutations annotated with this annotation will be hidden from the schema if the user is not logged
* Fields/Queries/Mutations annotated with this attribute will be hidden from the schema if the user is not logged
* or has no right associated.
*
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*/
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)]
class HideIfUnauthorized implements MiddlewareAnnotationInterface
Expand Down
19 changes: 6 additions & 13 deletions src/Annotations/HideParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,28 @@
use function ltrim;

/**
* Use this annotation to tell GraphQLite to ignore a parameter and not expose it as an input parameter.
* Use this attribute to tell GraphQLite to ignore a parameter and not expose it as an input parameter.
* This is only possible if the parameter has a default value.
*
* @Annotation
* @Target({"METHOD", "ANNOTATION"})
* @Attributes({
* @Attribute("for", type = "string")
* })
*/
#[Attribute(Attribute::TARGET_PARAMETER)]
class HideParameter implements ParameterAnnotationInterface
{
/** @var string */
private $for;
private string|null $for = null;

/** @param array<string, mixed> $values */
public function __construct(array $values = [])
public function __construct(array $values = [], string|null $for = null)
{
if (! isset($values['for'])) {
if (! isset($values['for']) && $for === null) {
return;
}

$this->for = ltrim($values['for'], '$');
$this->for = ltrim($for ?? $values['for'], '$');
}

public function getTarget(): string
{
if ($this->for === null) {
throw new BadMethodCallException('The @HideParameter annotation must be passed a target. For instance: "@HideParameter(for="$myParameterToHide")"');
throw new BadMethodCallException('The #[HideParameter] attribute must be passed a target. For instance: "#[HideParameter(for: "$myParameterToHide")]"');
}
return $this->for;
}
Expand Down
12 changes: 3 additions & 9 deletions src/Annotations/InjectUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,8 @@
use function ltrim;

/**
* Use this annotation to tell GraphQLite to inject the current logged user as an input parameter.
* Use this attribute to tell GraphQLite to inject the current logged user as an input parameter.
* If the parameter is not nullable, the user MUST be logged to access the resource.
*
* @Annotation
* @Target({"METHOD", "ANNOTATION"})
* @Attributes({
* @Attribute("for", type = "string")
* })
*/
#[Attribute(Attribute::TARGET_PARAMETER)]
class InjectUser implements ParameterAnnotationInterface
Expand All @@ -26,7 +20,7 @@ class InjectUser implements ParameterAnnotationInterface
private $for;

/** @param array<string, mixed> $values */
public function __construct(array $values = [])
public function __construct(array|null $values = [])
{
if (! isset($values['for'])) {
return;
Expand All @@ -38,7 +32,7 @@ public function __construct(array $values = [])
public function getTarget(): string
{
if ($this->for === null) {
throw new BadMethodCallException('The @InjectUser annotation must be passed a target. For instance: "@InjectUser(for="$user")"');
throw new BadMethodCallException('The #[InjectUser] attribute must be passed a target. For instance: "#[InjectUser(for: "$user")]"');
}
return $this->for;
}
Expand Down
21 changes: 6 additions & 15 deletions src/Annotations/Input.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,8 @@
use RuntimeException;

/**
* The Input annotation must be put in a GraphQL input type class docblock and is used to map to the underlying PHP class
* The Input attribute must be put in a GraphQL input type class docblock and is used to map to the underlying PHP class
* this is exposed via this input type.
*
* @Annotation
* @Target({"CLASS"})
* @Attributes({
* @Attribute("name", type = "string"),
* @Attribute("default", type = "bool"),
* @Attribute("description", type = "string"),
* @Attribute("update", type = "bool"),
* })
*/
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class Input implements TypeInterface
Expand Down Expand Up @@ -56,16 +47,16 @@ public function __construct(
public function getClass(): string
{
if ($this->class === null) {
throw new RuntimeException('Empty class for @Input annotation. You MUST create the Input annotation object using the GraphQLite AnnotationReader');
throw new RuntimeException('Empty class for #[Input] attribute. You MUST create the Input attribute object using the GraphQLite AnnotationReader');
}

return $this->class;
}

/** @param class-string<object> $class */
public function setClass(string $class): void
/** @param class-string<object> $className */
public function setClass(string $className): void
{
$this->class = $class;
$this->class = $className;
}

/**
Expand Down Expand Up @@ -103,7 +94,7 @@ public function isUpdate(): bool

/**
* By default there isn't support for defining the type outside
* This is used by the @Type annotation with the "external" attribute.
* This is used by the #[Type] attribute with the "external" attribute.
*/
public function isSelfType(): bool
{
Expand Down
4 changes: 0 additions & 4 deletions src/Annotations/Logged.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@

use Attribute;

/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*/
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)]
class Logged implements MiddlewareAnnotationInterface
{
Expand Down
Loading
Loading