Skip to content

Commit

Permalink
Merge 8d1c4f0 into 821a077
Browse files Browse the repository at this point in the history
  • Loading branch information
alanpoulain committed Dec 22, 2021
2 parents 821a077 + 8d1c4f0 commit 55cd7b5
Show file tree
Hide file tree
Showing 21 changed files with 476 additions and 78 deletions.
64 changes: 61 additions & 3 deletions .github/workflows/ci.yml
Expand Up @@ -856,8 +856,6 @@ jobs:
run: rm -Rf tests/Fixtures/app/var/cache/*
- name: Convert annotations to attributes
run: |
tests/Fixtures/app/console api:rector:upgrade tests/Fixtures/TestBundle/Document --transform-apisubresource -s -n
tests/Fixtures/app/console api:rector:upgrade tests/Fixtures/TestBundle/Document --annotation-to-api-resource -s -n
tests/Fixtures/app/console api:rector:upgrade tests/Fixtures/TestBundle/Entity --transform-apisubresource -s -n
tests/Fixtures/app/console api:rector:upgrade tests/Fixtures/TestBundle/Entity --annotation-to-api-resource -s -n
- name: Clear test app cache
Expand Down Expand Up @@ -897,7 +895,67 @@ jobs:
name: openapi-docs-php${{ matrix.php }}
path: build/out/openapi
continue-on-error: true


behat-rector-upgrade-mongodb:
name: Behat (PHP ${{ matrix.php }}) (Rector / MongoDB)
runs-on: ubuntu-latest
env:
APP_ENV: mongodb
MONGODB_URL: mongodb://localhost:27017
timeout-minutes: 20
strategy:
matrix:
php:
- '8.0'
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Check
run: |
sudo systemctl start mongod.service
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: pecl, composer
extensions: intl, bcmath, curl, openssl, mbstring, mongodb
ini-values: memory_limit=-1
- name: Get composer cache directory
id: composercache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composercache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Update project dependencies
run: composer update --no-interaction --no-progress --ansi
- name: Require Symfony components and Rector dependencies
run: composer require symfony/uid rector/rector:0.12.5 --dev --no-interaction --no-progress --ansi
- name: Install PHPUnit
run: vendor/bin/simple-phpunit --version
- name: Clear test app cache
run: rm -Rf tests/Fixtures/app/var/cache/*
- name: Convert annotations to attributes
run: |
tests/Fixtures/app/console api:rector:upgrade tests/Fixtures/TestBundle/Document --transform-apisubresource -s -n
tests/Fixtures/app/console api:rector:upgrade tests/Fixtures/TestBundle/Document --annotation-to-api-resource -s -n
- name: Clear test app cache
run: rm -Rf tests/Fixtures/app/var/cache/*
- name: Run Behat tests
run: |
mkdir -p build/logs/behat
vendor/bin/behat --out=std --format=progress --format=junit --out=build/logs/behat/junit --profile=mongodb --no-interaction
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v1
with:
name: behat-logs-php${{ matrix.php }}
path: build/logs/behat
continue-on-error: true

windows-phpunit:
name: Windows PHPUnit (PHP ${{ matrix.php }}) (SQLite)
runs-on: windows-latest
Expand Down
12 changes: 10 additions & 2 deletions src/Api/IdentifiersExtractor.php
Expand Up @@ -117,8 +117,12 @@ private function resolveIdentifierValue($identifierValue, string $parameterName)
throw new RuntimeException('No identifier value found, did you forgot to persist the entity?');
}

if (is_scalar($identifierValue)) {
return $identifierValue;
}

// TODO: php 8 remove method_exists
if (is_scalar($identifierValue) || method_exists($identifierValue, '__toString') || $identifierValue instanceof \Stringable) {
if (method_exists($identifierValue, '__toString') || $identifierValue instanceof \Stringable) {
return (string) $identifierValue;
}

Expand All @@ -132,7 +136,11 @@ private function resolveIdentifierValue($identifierValue, string $parameterName)
if (1 === \count($relatedLinks)) {
$identifierValue = $this->getIdentifierValue($identifierValue, $relatedResourceClass, current($relatedLinks)->getIdentifiers()[0], $parameterName);

if ($identifierValue instanceof \Stringable || is_scalar($identifierValue) || method_exists($identifierValue, '__toString')) {
if (is_scalar($identifierValue)) {
return $identifierValue;
}

if ($identifierValue instanceof \Stringable || method_exists($identifierValue, '__toString')) {
return (string) $identifierValue;
}
}
Expand Down
Expand Up @@ -181,7 +181,11 @@ protected function resolveAttributes($items): array
foreach ($values as $attribute => $value) {
[$updatedAttribute, $updatedValue] = $this->getKeyValue(str_replace('"', '', $camelCaseToSnakeCaseNameConverter->normalize($attribute)), $value);
if ($attribute !== $updatedAttribute) {
$values[$updatedAttribute] = $updatedValue;
if (isset($values[$updatedAttribute])) {
$values[$updatedAttribute] = array_merge($values[$updatedAttribute], $updatedValue);
} else {
$values[$updatedAttribute] = $updatedValue;
}
unset($values[$attribute]);
}
}
Expand Down
33 changes: 23 additions & 10 deletions src/Core/Bridge/Rector/Service/SubresourceTransformer.php
Expand Up @@ -15,6 +15,7 @@

use ApiPlatform\Util\Inflector;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as ODMClassMetadata;
use Doctrine\ODM\MongoDB\Mapping\Driver\AnnotationDriver as ODMAnnotationDriver;
use Doctrine\ODM\MongoDB\Mapping\MappingException as ODMMappingException;
use Doctrine\ORM\Mapping\ClassMetadata;
Expand Down Expand Up @@ -43,7 +44,7 @@ public function toUriVariables(array $subresourceMetadata): array
foreach (array_reverse($subresourceMetadata['identifiers']) as $identifier => $identifiedBy) {
[$fromClass, $fromIdentifier, $fromPathVariable] = $identifiedBy;
$fromClassMetadata = $this->getDoctrineMetadata($fromClass);
$fromClassMetadataAssociationMappings = $fromClassMetadata->getAssociationMappings();
$fromClassMetadataAssociationMappings = $fromClassMetadata->associationMappings;

$uriVariables[$identifier] = [
'from_class' => $fromClass,
Expand All @@ -62,7 +63,8 @@ public function toUriVariables(array $subresourceMetadata): array
$toClass = $fromClass;

if (isset($fromProperty, $fromClassMetadataAssociationMappings[$fromProperty])) {
if ($fromClassMetadataAssociationMappings[$fromProperty]['type'] & ClassMetadataInfo::TO_MANY && isset($fromClassMetadataAssociationMappings[$fromProperty]['mappedBy'])) {
$type = $fromClassMetadataAssociationMappings[$fromProperty]['type'];
if (((class_exists(ODMClassMetadata::class) && ODMClassMetadata::MANY === $type) || (\is_int($type) && $type & ClassMetadataInfo::TO_MANY)) && isset($fromClassMetadataAssociationMappings[$fromProperty]['mappedBy'])) {
$uriVariables[$identifier]['to_property'] = $fromClassMetadataAssociationMappings[$fromProperty]['mappedBy'];
$fromProperty = $identifier;
continue;
Expand All @@ -75,8 +77,26 @@ public function toUriVariables(array $subresourceMetadata): array
return array_reverse($uriVariables);
}

private function getDoctrineMetadata(string $class): ClassMetadata
/**
* @return ODMClassMetadata|ClassMetadata
*/
private function getDoctrineMetadata(string $class)
{
if ($this->odmMetadataFactory && class_exists(ODMClassMetadata::class)) {
$isDocument = true;
$metadata = new ODMClassMetadata($class);

try {
$this->odmMetadataFactory->loadMetadataForClass($class, $metadata);
} catch (ODMMappingException $e) {
$isDocument = false;
}

if ($isDocument) {
return $metadata;
}
}

$metadata = new ClassMetadata($class);
$metadata->initializeReflection(new RuntimeReflectionService());

Expand All @@ -87,13 +107,6 @@ private function getDoctrineMetadata(string $class): ClassMetadata
} catch (MappingException $e) {
}

try {
if ($this->odmMetadataFactory) {
$this->odmMetadataFactory->loadMetadataForClass($class, $metadata);
}
} catch (ODMMappingException $e) {
}

return $metadata;
}
}
4 changes: 2 additions & 2 deletions src/Core/Bridge/Symfony/Bundle/Command/RectorCommand.php
Expand Up @@ -173,7 +173,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
passthru($command);
}

$output->write('Migration successful.');
$output->writeln('Migration successful.');

return Command::SUCCESS;
}
Expand Down Expand Up @@ -269,7 +269,7 @@ private function transformApiSubresource(string $src, OutputInterface $output)
private function isThereSubresources($io, $output): bool
{
if ($io->confirm('Do you have any @ApiSubresource or #[ApiSubresource] left in your code ?')) {
$output->write('You will not be able to convert them afterwards. Please run the command "Transform @ApiSubresource to alternate resources" first.');
$output->writeln('You will not be able to convert them afterwards. Please run the command "Transform @ApiSubresource to alternate resources" first.');

return true;
}
Expand Down
69 changes: 69 additions & 0 deletions src/Doctrine/Common/State/LinksHandlerTrait.php
@@ -0,0 +1,69 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Doctrine\Common\State;

use ApiPlatform\Exception\RuntimeException;
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Operation;

trait LinksHandlerTrait
{
/**
* @param Operation|GraphQlOperation $operation
*
* @return Link[]
*/
private function getLinks(string $resourceClass, $operation, array $context): array
{
$links = ($operation instanceof GraphQlOperation ? $operation->getLinks() : $operation->getUriVariables()) ?? [];

if ($linkClass = $context['linkClass'] ?? false) {
$newLinks = [];

foreach ($links as $link) {
if ($linkClass === $link->getFromClass()) {
$newLinks[] = $link;
}
}

$operation = $this->resourceMetadataCollectionFactory->create($linkClass)->getOperation($operation->getName());
foreach ($operation instanceof GraphQlOperation ? $operation->getLinks() : $operation->getUriVariables() as $link) {
if ($resourceClass === $link->getToClass()) {
$newLinks[] = $link;
}
}

if (!$newLinks) {
throw new RuntimeException(sprintf('The class "%s" cannot be retrieved from "%s".', $resourceClass, $linkClass));
}

$links = $newLinks;
}

return $links;
}

private function getIdentifierValue(array &$identifiers, string $name = null)
{
if (isset($identifiers[$name])) {
$value = $identifiers[$name];
unset($identifiers[$name]);

return $value;
}

return array_shift($identifiers);
}
}
Expand Up @@ -11,7 +11,7 @@

declare(strict_types=1);

namespace ApiPlatform\Doctrine\Orm\State;
namespace ApiPlatform\Doctrine\Common\State;

use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Util\ClassInfoTrait;
Expand Down
10 changes: 10 additions & 0 deletions src/Doctrine/Odm/State/CollectionProvider.php
Expand Up @@ -17,6 +17,7 @@
use ApiPlatform\Doctrine\Odm\Extension\AggregationResultCollectionExtensionInterface;
use ApiPlatform\Exception\OperationNotFoundException;
use ApiPlatform\Exception\RuntimeException;
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\State\ProviderInterface;
use Doctrine\ODM\MongoDB\DocumentManager;
Expand All @@ -29,6 +30,8 @@
*/
final class CollectionProvider implements ProviderInterface
{
use LinksHandlerTrait;

private $resourceMetadataCollectionFactory;
private $managerRegistry;
private $collectionExtensions;
Expand All @@ -55,6 +58,9 @@ public function provide(string $resourceClass, array $identifiers = [], ?string
}

$aggregationBuilder = $repository->createAggregationBuilder();

$this->handleLinks($aggregationBuilder, $identifiers, $context, $resourceClass, $operationName);

foreach ($this->collectionExtensions as $extension) {
$extension->applyToCollection($aggregationBuilder, $resourceClass, $operationName, $context);

Expand Down Expand Up @@ -83,6 +89,10 @@ public function supports(string $resourceClass, array $identifiers = [], ?string

$operation = $context['operation'] ?? $this->resourceMetadataCollectionFactory->create($resourceClass)->getOperation($operationName);

if ($operation instanceof GraphQlOperation) {
return true;
}

return $operation->isCollection() ?? false;
}
}
8 changes: 4 additions & 4 deletions src/Doctrine/Odm/State/ItemProvider.php
Expand Up @@ -32,6 +32,8 @@
*/
final class ItemProvider implements ProviderInterface
{
use LinksHandlerTrait;

private $resourceMetadataCollectionFactory;
private $managerRegistry;
private $itemExtensions;
Expand All @@ -53,7 +55,7 @@ public function provide(string $resourceClass, array $identifiers = [], ?string

$fetchData = $context['fetch_data'] ?? true;
if (!$fetchData) {
return $manager->getReference($resourceClass, $identifiers);
return $manager->getReference($resourceClass, reset($identifiers));
}

/** @var ObjectRepository $repository */
Expand All @@ -64,9 +66,7 @@ public function provide(string $resourceClass, array $identifiers = [], ?string

$aggregationBuilder = $repository->createAggregationBuilder();

foreach ($identifiers as $propertyName => $value) {
$aggregationBuilder->match()->field($propertyName)->equals($value);
}
$this->handleLinks($aggregationBuilder, $identifiers, $context, $resourceClass, $operationName);

foreach ($this->itemExtensions as $extension) {
$extension->applyToItem($aggregationBuilder, $resourceClass, $identifiers, $operationName, $context);
Expand Down

0 comments on commit 55cd7b5

Please sign in to comment.