Skip to content

Commit

Permalink
Merge pull request #334 from W0rma/optional-annotations
Browse files Browse the repository at this point in the history
Make doctrine/annotations an optional dependency
  • Loading branch information
goetas authored Oct 31, 2024
2 parents 73fcb54 + 0861943 commit 34396ee
Show file tree
Hide file tree
Showing 45 changed files with 938 additions and 128 deletions.
28 changes: 17 additions & 11 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,37 @@ jobs:
fail-fast: false
matrix:
php-version:
- "7.3"
- "7.4"
- "8.0"
- "8.1"
- "8.2"
- "8.3"
dependencies:
- "highest"
- "lowest"
remove-annotations:
- "yes"
- "no"
symfony-require:
- "^3.0"
- "^4.0"
- "^5.0"
- "^6.0"
include:
- php-version: 8.4
symfony-require: "^5.0"
composer-options: "--ignore-platform-req=php+" # TODO remove once phpspec/prophecy supports PHP 8.4
- php-version: 8.0
symfony-require: "^6.0"
- php-version: 8.1
symfony-require: "^6.0"
- php-version: 8.2
symfony-require: "^6.0"
- php-version: 8.3
symfony-require: "^6.0"
- php-version: 8.4
symfony-require: "^6.0"
composer-options: "--ignore-platform-req=php+" # TODO remove once phpspec/prophecy supports PHP 8.4
- php-version: 8.2
symfony-require: "^7.0"
- php-version: 8.2
symfony-require: "^7.0"
remove-annotations: "yes"
- php-version: 8.3
symfony-require: "^7.0"
- php-version: 8.3
symfony-require: "^7.0"
remove-annotations: "yes"
- php-version: 8.4
symfony-require: "^7.0"
composer-options: "--ignore-platform-req=php+" # TODO remove once phpspec/prophecy supports PHP 8.4
Expand All @@ -65,6 +64,13 @@ jobs:
ini-values: "zend.assertions=1"
tools: "flex"

- name: "Remove remove-annotations if required"
if: "${{ matrix.remove-annotations == 'yes' }}"
env:
SYMFONY_REQUIRE: "${{ matrix.symfony-require }}"
run: |
composer remove --no-update --dev doctrine/annotations
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v2"
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/coding-standards.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
php-version:
- "7.4"
- "8.1"

steps:
- name: "Checkout"
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ This will resolve the latest stable version.

Otherwise, install the library and setup the autoloader yourself.

If you want to use [**annotations**](#annotations) for configuration you need
to install the `doctrine/annotations` package:

```sh
composer require doctrine/annotations
```

If your app uses PHP 8.1 or higher it is recommended to use native PHP
attributes.
In this case you don't need to install the Doctrine package.

### Working With Symfony

There is a bundle for that! Install the
Expand Down
12 changes: 6 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@
}
],
"require": {
"php": "^7.2 | ^8.0",
"doctrine/annotations": "^1.13.2 || ^2.0",
"php": "^8.1",
"jms/metadata": "^2.0",
"jms/serializer": "^3.18.2",
"symfony/expression-language": "~3.0 || ~4.0 || ~5.0 || ~6.0 || ~7.0"
"symfony/expression-language": "^3.4.47 || ~4.0 || ~5.0 || ~6.0 || ~7.0"
},
"require-dev": {
"phpunit/phpunit": "^7 | ^9.5.10",
"phpunit/phpunit": "^9.5.10",
"doctrine/annotations": "^1.13.2 || ^2.0",
"doctrine/coding-standard": "^12.0",
"doctrine/persistence": "^1.3.4 | ^2.0 | ^3.0",
"pagerfanta/core": "^2.4 || ^3.0",
"phpdocumentor/type-resolver": "^1.5.1",
"phpspec/prophecy-phpunit": "^2.0.1",
"phpspec/prophecy": "^1.16",
"symfony/routing": "~3.0 || ~4.0 || ~5.0 || ~6.0 || ~7.0",
"symfony/yaml": "~3.0 || ~4.0 || ~5.0 || ~6.0 || ~7.0",
"symfony/routing": "^3.4.47 || ~4.0 || ~5.0 || ~6.0 || ~7.0",
"symfony/yaml": "^3.4.47 || ~4.0 || ~5.0 || ~6.0 || ~7.0",
"twig/twig": "^1.43 || ^2.13 || ^3.0"
},
"suggest": {
Expand Down
9 changes: 9 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingTraversableTypeHintSpecification"/>
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification"/>
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification"/>

<!-- TODO Apply sniffs if possible -->
<exclude name="SlevomatCodingStandard.Classes.RequireConstructorPropertyPromotion.RequiredConstructorPropertyPromotion"/>
<exclude name="SlevomatCodingStandard.TypeHints.UnionTypeHintFormat.DisallowedShortNullable"/>
<exclude name="SlevomatCodingStandard.Functions.RequireTrailingCommaInDeclaration.MissingTrailingComma"/>
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint"/>
<exclude name="SlevomatCodingStandard.TypeHints.UnionTypeHintFormat.DisallowedShortNullable"/>
<exclude name="SlevomatCodingStandard.Classes.ModernClassNameReference.ClassNameReferencedViaFunctionCall"/>
<exclude name="SlevomatCodingStandard.Exceptions.RequireNonCapturingCatch.NonCapturingCatchRequired"/>
</rule>

<rule ref="SlevomatCodingStandard.ControlStructures.RequireYodaComparison"/>
Expand Down
5 changes: 3 additions & 2 deletions src/Configuration/Annotation/Embedded.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ class Embedded
public $exclusion = null;

/**
* @param string|array $content
* @param array|string|null $values
* @param array|string|null $content
*/
public function __construct(array $values = [], $content = null, ?string $type = null, ?string $xmlElementName = null, ?Exclusion $exclusion = null)
public function __construct($values = [], $content = null, ?string $type = null, ?string $xmlElementName = null, ?Exclusion $exclusion = null)
{
$this->loadAnnotationParameters(get_defined_vars());
}
Expand Down
5 changes: 4 additions & 1 deletion src/Configuration/Annotation/Exclusion.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ final class Exclusion
*/
public $excludeIf = null;

public function __construct(array $values = [], ?array $groups = null, ?string $sinceVersion = null, ?string $untilVersion = null, ?int $maxDepth = null, ?string $excludeIf = null)
/**
* @param array|null $values
*/
public function __construct($values = [], ?array $groups = null, ?string $sinceVersion = null, ?string $untilVersion = null, ?int $maxDepth = null, ?string $excludeIf = null)
{
$this->loadAnnotationParameters(get_defined_vars());
}
Expand Down
3 changes: 2 additions & 1 deletion src/Configuration/Annotation/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ final class Relation
public $exclusion = null;

/**
* @param array|string|null $values
* @param string|Route $href
* @param string|Embedded $embedded
*/
public function __construct(array $values = [], ?string $name = null, $href = null, $embedded = null, array $attributes = [], ?Exclusion $exclusion = null)
public function __construct($values = [], ?string $name = null, $href = null, $embedded = null, array $attributes = [], ?Exclusion $exclusion = null)
{
$this->loadAnnotationParameters(get_defined_vars());
}
Expand Down
5 changes: 4 additions & 1 deletion src/Configuration/Annotation/RelationProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ class RelationProvider
*/
public $name;

public function __construct(array $values = [], ?string $name = null)
/**
* @param array|string|null $values
*/
public function __construct($values = [], ?string $name = null)
{
$this->loadAnnotationParameters(get_defined_vars());
}
Expand Down
3 changes: 2 additions & 1 deletion src/Configuration/Annotation/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ class Route
public $generator = null;

/**
* @param array|string|null $values
* @param array|string $parameters
* @param bool|string $absolute
*/
public function __construct(array $values = [], ?string $name = null, $parameters = null, $absolute = false, ?string $generator = null)
public function __construct($values = [], ?string $name = null, $parameters = null, $absolute = false, ?string $generator = null)
{
$this->loadAnnotationParameters(get_defined_vars());
}
Expand Down
27 changes: 13 additions & 14 deletions src/HateoasBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\Common\Annotations\FileCacheReader;
use Hateoas\Configuration\Metadata\ConfigurationExtensionInterface;
use Hateoas\Configuration\Metadata\Driver\AnnotationDriver;
use Hateoas\Configuration\Metadata\Driver\AttributeDriver;
use Hateoas\Configuration\Metadata\Driver\ExtensionDriver;
use Hateoas\Configuration\Metadata\Driver\XmlDriver;
use Hateoas\Configuration\Metadata\Driver\YamlDriver;
Expand Down Expand Up @@ -385,33 +386,31 @@ public function replaceMetadataDir(string $dir, string $namespacePrefix = ''): H

private function buildMetadataFactory(): MetadataFactoryInterface
{
$expressionEvaluator = $this->getExpressionEvaluator();

$typeParser = new Parser();

$annotationReader = $this->annotationReader;
$drivers = [new AttributeDriver($expressionEvaluator, $this->chainProvider, $typeParser)];

if (null === $annotationReader) {
if (null === $annotationReader && class_exists(AnnotationReader::class)) {
$annotationReader = new AnnotationReader();

if (null !== $this->cacheDir) {
$this->createDir($this->cacheDir . '/annotations');
$annotationReader = new FileCacheReader($annotationReader, $this->cacheDir . '/annotations', $this->debug);
}
}

$expressionEvaluator = $this->getExpressionEvaluator();

$typeParser = new Parser();
$drivers[] = new AnnotationDriver($annotationReader, $expressionEvaluator, $this->chainProvider, $typeParser);
}

if (!empty($this->metadataDirs)) {
$fileLocator = new FileLocator($this->metadataDirs);
$metadataDriver = new DriverChain([
new YamlDriver($fileLocator, $expressionEvaluator, $this->chainProvider, $typeParser),
new XmlDriver($fileLocator, $expressionEvaluator, $this->chainProvider, $typeParser),
new AnnotationDriver($annotationReader, $expressionEvaluator, $this->chainProvider, $typeParser),
]);
} else {
$metadataDriver = new AnnotationDriver($annotationReader, $expressionEvaluator, $this->chainProvider, $typeParser);
$fileLocator = new FileLocator($this->metadataDirs);
$drivers[] = new YamlDriver($fileLocator, $expressionEvaluator, $this->chainProvider, $typeParser);
$drivers[] = new XmlDriver($fileLocator, $expressionEvaluator, $this->chainProvider, $typeParser);
}

$metadataDriver = new ExtensionDriver($metadataDriver, $this->configurationExtensions);
$metadataDriver = new ExtensionDriver(new DriverChain($drivers), $this->configurationExtensions);
$metadataFactory = new MetadataFactory($metadataDriver, null, $this->debug);
$metadataFactory->setIncludeInterfaces($this->includeInterfaceMetadata);

Expand Down
7 changes: 7 additions & 0 deletions src/Representation/AbstractSegmentedRepresentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/**
* @Serializer\ExclusionPolicy("all")
*/
#[Serializer\ExclusionPolicy('all')]
abstract class AbstractSegmentedRepresentation extends RouteAwareRepresentation
{
/**
Expand All @@ -18,6 +19,9 @@ abstract class AbstractSegmentedRepresentation extends RouteAwareRepresentation
*
* @var int
*/
#[Serializer\Expose]
#[Serializer\Type('integer')]
#[Serializer\XmlAttribute]
private $limit;

/**
Expand All @@ -27,6 +31,9 @@ abstract class AbstractSegmentedRepresentation extends RouteAwareRepresentation
*
* @var int
*/
#[Serializer\Expose]
#[Serializer\Type('integer')]
#[Serializer\XmlAttribute]
private $total;

/**
Expand Down
8 changes: 8 additions & 0 deletions src/Representation/CollectionRepresentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
* embedded = @Hateoas\Embedded("expr(object.getResources())")
* )
*/
#[Serializer\ExclusionPolicy('all')]
#[Serializer\XmlRoot('collection')]
#[Hateoas\Relation(
'items',
embedded: new Hateoas\Embedded(
content: 'expr(object.getResources())',
),
)]
class CollectionRepresentation
{
/**
Expand Down
46 changes: 46 additions & 0 deletions src/Representation/OffsetRepresentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,50 @@
* )
* )
*/
#[Serializer\ExclusionPolicy('all')]
#[Serializer\XmlRoot('collection')]
#[Serializer\AccessorOrder(order: 'custom', custom: ['offset', 'limit', 'total'])]
#[Hateoas\Relation(
'first',
href: new Hateoas\Route(
'expr(object.getRoute())',
parameters: 'expr(object.getParameters(0))',
absolute: 'expr(object.isAbsolute())',
),
)]
#[Hateoas\Relation(
'last',
href: new Hateoas\Route(
'expr(object.getRoute())',
parameters: 'expr(object.getParameters((object.getTotal() - 1) - (object.getTotal() - 1) % object.getLimit()))',
absolute: 'expr(object.isAbsolute())',
),
exclusion: new Hateoas\Exclusion(
excludeIf: 'expr(object.getTotal() === null)',
)
)]
#[Hateoas\Relation(
'next',
href: new Hateoas\Route(
name: 'expr(object.getRoute())',
parameters: 'expr(object.getParameters(object.getOffset() + object.getLimit()))',
absolute: 'expr(object.isAbsolute())'
),
exclusion: new Hateoas\Exclusion(
excludeIf: 'expr(object.getTotal() !== null && (object.getOffset() + object.getLimit()) >= object.getTotal())',
),
)]
#[Hateoas\Relation(
'previous',
href: new Hateoas\Route(
'expr(object.getRoute())',
parameters: 'expr(object.getParameters((object.getOffset() > object.getLimit()) ? object.getOffset() - object.getLimit() : 0))',
absolute: 'expr(object.isAbsolute())',
),
exclusion: new Hateoas\Exclusion(
excludeIf: 'expr(! object.getOffset())',
),
)]
class OffsetRepresentation extends AbstractSegmentedRepresentation
{
/**
Expand All @@ -62,6 +106,8 @@ class OffsetRepresentation extends AbstractSegmentedRepresentation
*
* @var int
*/
#[Serializer\Expose]
#[Serializer\XmlAttribute]
private $offset;

/**
Expand Down
Loading

0 comments on commit 34396ee

Please sign in to comment.