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

[Eloquent] Add basic data provider / persister #4197

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
56 changes: 56 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ jobs:
composer remove --dev --no-interaction --no-progress --no-update --ansi \
doctrine/mongodb-odm \
doctrine/mongodb-odm-bundle \
- name: Remove Eloquent
if: startsWith(matrix.php, '7.1')
run: |
composer remove --dev --no-interaction --no-progress --no-update --ansi \
wouterj/eloquent-bundle \
- name: Set Composer platform config
if: (startsWith(matrix.php, '8.0'))
run: |
Expand Down Expand Up @@ -233,6 +238,11 @@ jobs:
composer remove --dev --no-interaction --no-progress --no-update --ansi \
doctrine/mongodb-odm \
doctrine/mongodb-odm-bundle \
- name: Remove Eloquent
if: startsWith(matrix.php, '7.1')
run: |
composer remove --dev --no-interaction --no-progress --no-update --ansi \
wouterj/eloquent-bundle \
- name: Update project dependencies
run: composer update --no-interaction --no-progress --ansi
- name: Require Symfony components
Expand Down Expand Up @@ -596,6 +606,52 @@ jobs:
- name: Run Behat tests
run: vendor/bin/behat --out=std --format=progress --profile=elasticsearch --no-interaction

eloquent:
name: Behat (PHP ${{ matrix.php }}) (${{ matrix.app_env }})
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
matrix:
php:
- '7.4'
app_env:
- 'eloquent'
- 'eloquent_mapped'
fail-fast: false
env:
APP_ENV: ${{ matrix.app_env }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: pecl, composer
extensions: intl, bcmath, curl, openssl, mbstring, pdo_sqlite
coverage: none
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 Uid
run: composer require symfony/uid --dev --no-interaction --no-progress --ansi
- name: Install PHPUnit
run: vendor/bin/simple-phpunit --version
- name: Clear test app cache
run: tests/Fixtures/app/console cache:clear --ansi
- name: Run Behat tests
run: vendor/bin/behat --out=std --format=progress --profile=${{ matrix.app_env == 'eloquent' && 'eloquent' || 'eloquent-mapped' }} --no-interaction

phpunit-no-deprecations:
name: PHPUnit (PHP ${{ matrix.php }}) (no deprecations)
runs-on: ubuntu-latest
Expand Down
29 changes: 29 additions & 0 deletions behat.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,35 @@ elasticsearch:
filters:
tags: '@elasticsearch'

eloquent:
suites:
default: false
eloquent: &eloquent-suite
contexts:
- 'ApiPlatform\Core\Tests\Behat\CommandContext'
- 'ApiPlatform\Core\Tests\Behat\DoctrineContext'
- 'ApiPlatform\Core\Tests\Behat\GraphqlContext'
- 'ApiPlatform\Core\Tests\Behat\JsonContext'
- 'ApiPlatform\Core\Tests\Behat\HydraContext'
- 'ApiPlatform\Core\Tests\Behat\OpenApiContext'
- 'ApiPlatform\Core\Tests\Behat\HttpCacheContext'
- 'ApiPlatform\Core\Tests\Behat\JsonApiContext'
- 'ApiPlatform\Core\Tests\Behat\JsonHalContext'
- 'ApiPlatform\Core\Tests\Behat\MercureContext'
- 'ApiPlatform\Core\Tests\Behat\XmlContext'
- 'Behat\MinkExtension\Context\MinkContext'
- 'behatch:context:rest'
filters:
tags: '@eloquent&&~@!eloquent'

eloquent-mapped:
suites:
default: false
eloquent:
<<: *eloquent-suite
filters:
tags: '@eloquent_mapped&&~@!eloquent_mapped'

default-coverage:
suites:
default: &default-coverage-suite
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"friends-of-behat/mink-extension": "^2.2",
"friends-of-behat/symfony-extension": "^2.1",
"guzzlehttp/guzzle": "^6.0 || ^7.0",
"illuminate/database": "^5.8 || ^6.20 || ^7.30 || ^8.36",
"jangregor/phpstan-prophecy": "^0.8",
"justinrainbow/json-schema": "^5.2.1",
"phpdocumentor/reflection-docblock": "^3.0 || ^4.0 || ^5.1",
Expand Down Expand Up @@ -82,7 +83,8 @@
"symfony/web-profiler-bundle": "^4.4 || ^5.1",
"symfony/yaml": "^3.4 || ^4.4 || ^5.1",
"twig/twig": "^1.42.3 || ^2.12 || ^3.0",
"webonyx/graphql-php": "^14.0"
"webonyx/graphql-php": "^14.0",
"wouterj/eloquent-bundle": "^2.0"
},
"conflict": {
"doctrine/common": "<2.7",
Expand Down
2 changes: 2 additions & 0 deletions features/main/circular_reference.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@!eloquent
@!eloquent_mapped
Feature: Circular references handling
In order to handle circular references
As a developer
Expand Down
2 changes: 2 additions & 0 deletions features/main/composite.feature
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@!mongodb
@!eloquent
@!eloquent_mapped
Feature: Retrieve data with Composite identifiers
In order to retrieve relations with composite identifiers
As a client software developer
Expand Down
4 changes: 4 additions & 0 deletions features/main/crud.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@eloquent
@eloquent_mapped
Feature: Create-Retrieve-Update-Delete
In order to use an hypermedia API
As a client software developer
Expand Down Expand Up @@ -101,6 +103,8 @@ Feature: Create-Retrieve-Update-Delete
When I send a "GET" request to "/dummies/42"
Then the response status code should be 404

@!eloquent
@!eloquent_mapped
Scenario: Get a collection
When I send a "GET" request to "/dummies"
Then the response status code should be 200
Expand Down
2 changes: 2 additions & 0 deletions features/main/custom_identifier.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@eloquent
@eloquent_mapped
Feature: Using custom identifier on resource
In order to use an hypermedia API
As a client software developer
Expand Down
2 changes: 2 additions & 0 deletions features/main/patch.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@eloquent
@eloquent_mapped
Feature: Sending PATCH requets
As a client software developer
I need to be able to send partial updates
Expand Down
12 changes: 11 additions & 1 deletion features/main/relation.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@eloquent
@eloquent_mapped
Feature: Relations support
In order to use a hypermedia API
As a client software developer
Expand Down Expand Up @@ -79,6 +81,8 @@ Feature: Relations support
"""

@!mongodb
@!eloquent
@!eloquent_mapped
Scenario: Create a friend relationship
When I add "Content-Type" header equal to "application/ld+json"
And I send a "POST" request to "/related_to_dummy_friends" with body:
Expand Down Expand Up @@ -109,6 +113,8 @@ Feature: Relations support
"""

@!mongodb
@!eloquent
@!eloquent_mapped
Scenario: Get the relationship
When I send a "GET" request to "/related_to_dummy_friends/dummyFriend=1;relatedDummy=1"
And the response status code should be 200
Expand Down Expand Up @@ -396,6 +402,8 @@ Feature: Relations support
}
"""

@!eloquent
@!eloquent_mapped
Scenario: Issue #1222
Given there are people having pets
When I add "Content-Type" header equal to "application/ld+json"
Expand Down Expand Up @@ -429,6 +437,8 @@ Feature: Relations support
}
"""

@!eloquent
@!eloquent_mapped
Scenario: Eager load relations should not be duplicated
Given there is an order with same customer and recipient
When I add "Content-Type" header equal to "application/ld+json"
Expand Down Expand Up @@ -534,7 +544,7 @@ Feature: Relations support
"pattern": "^An error occurred$"
},
"hydra:description": {
"pattern": "^Expected IRI or document for resource \"ApiPlatform\\\\Core\\\\Tests\\\\Fixtures\\\\TestBundle\\\\(Document|Entity)\\\\RelatedDummy\", \"integer\" given.$"
"pattern": "^Expected IRI or document for resource \"ApiPlatform\\\\Core\\\\Tests\\\\Fixtures\\\\TestBundle\\\\(Document|Entity|Models|Resource)\\\\RelatedDummy\", \"integer\" given.$"
}
},
"required": [
Expand Down
1 change: 1 addition & 0 deletions features/main/validation.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@eloquent_mapped
Feature: Using validations groups
As a client software developer
I need to be able to use validation groups
Expand Down
7 changes: 7 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ parameters:
- src/Bridge/NelmioApiDoc/*
- tests/Bridge/NelmioApiDoc/*
- src/Bridge/FosUser/*
# Laravel migrations
- tests/Fixtures/app/migrations
# BC layer
- tests/Bridge/Symfony/Bundle/DependencyInjection/Compiler/AnnotationFilterPassTest.php
- tests/Annotation/ApiResourceTest.php
Expand Down Expand Up @@ -114,3 +116,8 @@ parameters:
-
message: "#Call to function method_exists\\(\\) with ApiPlatform\\\\Core\\\\JsonApi\\\\Serializer\\\\ItemNormalizer and 'setCircularReferenc…' will always evaluate to false\\.#"
path: tests/JsonApi/Serializer/ItemNormalizerTest.php

# Expected, Eloquent dynamic properties
-
message: '#Access to an undefined property ApiPlatform\\Core\\Tests\\Fixtures\\TestBundle\\Models\\[a-zA-Z0-9_]+::\$[a-zA-Z0-9_]+.#'
path: tests/Behat/DoctrineContext.php
7 changes: 5 additions & 2 deletions src/Annotation/ApiProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
* @Attribute("push", type="bool"),
* @Attribute("security", type="string"),
* @Attribute("securityPostDenormalize", type="string"),
* @Attribute("swaggerContext", type="array")
* @Attribute("swaggerContext", type="array"),
* @Attribute("virtual", type="bool")
* )
*/
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_PARAMETER)]
Expand Down Expand Up @@ -114,6 +115,7 @@ final class ApiProperty
* @param string $security
* @param array $swaggerContext
* @param string $securityPostDenormalize
* @param bool $virtual
*
* @throws InvalidArgumentException
*/
Expand All @@ -139,7 +141,8 @@ public function __construct(
?bool $push = null,
?string $security = null,
?array $swaggerContext = null,
?string $securityPostDenormalize = null
?string $securityPostDenormalize = null,
?bool $virtual = null
) {
if (!\is_array($description)) { // @phpstan-ignore-line Doctrine annotations support
[$publicProperties, $configurableAttributes] = self::getConfigMetadata();
Expand Down
3 changes: 3 additions & 0 deletions src/Annotation/ApiResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* @Attribute("cacheHeaders", type="array"),
* @Attribute("collectionOperations", type="array"),
* @Attribute("compositeIdentifier", type="bool"),
* @Attribute("dataModel", type="string"),
* @Attribute("denormalizationContext", type="array"),
* @Attribute("deprecationReason", type="string"),
* @Attribute("description", type="string"),
Expand Down Expand Up @@ -138,6 +139,7 @@ final class ApiResource
* @param array $itemOperations https://api-platform.com/docs/core/operations
* @param array $subresourceOperations https://api-platform.com/docs/core/subresources
* @param array $cacheHeaders https://api-platform.com/docs/core/performance/#setting-custom-http-cache-headers
* @param string $dataModel
* @param array $denormalizationContext https://api-platform.com/docs/core/serialization/#using-serialization-groups
* @param string $deprecationReason https://api-platform.com/docs/core/deprecations/#deprecating-resource-classes-operations-and-properties
* @param bool $elasticsearch https://api-platform.com/docs/core/elasticsearch/
Expand Down Expand Up @@ -189,6 +191,7 @@ public function __construct(
// attributes
?array $attributes = null,
?array $cacheHeaders = null,
?string $dataModel = null,
?array $denormalizationContext = null,
?string $deprecationReason = null,
?bool $elasticsearch = null,
Expand Down
41 changes: 41 additions & 0 deletions src/Bridge/Eloquent/BuilderFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?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\Core\Bridge\Eloquent;

use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Builder as SchemaBuilder;

/**
* Create a query or a schema builder from an Eloquent model.
*
* @experimental
*
* @author Alan Poulain <contact@alanpoulain.eu>
*/
final class BuilderFactory implements BuilderFactoryInterface
{
public function getQueryBuilder(string $modelClass): QueryBuilder
{
return $modelClass::query();
}

public function getSchemaBuilder(string $modelClass): SchemaBuilder
{
/** @var Model $model */
$model = new $modelClass();

return $model->getConnection()->getSchemaBuilder();
}
}
38 changes: 38 additions & 0 deletions src/Bridge/Eloquent/BuilderFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?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\Core\Bridge\Eloquent;

use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Builder as SchemaBuilder;

/**
* Create a query or a schema builder from an Eloquent model.
*
* @experimental
*
* @author Alan Poulain <contact@alanpoulain.eu>
*/
interface BuilderFactoryInterface
{
/**
* @param class-string<Model> $modelClass
*/
public function getQueryBuilder(string $modelClass): QueryBuilder;

/**
* @param class-string<Model> $modelClass
*/
public function getSchemaBuilder(string $modelClass): SchemaBuilder;
}
Loading