Skip to content

Commit

Permalink
Add a FactoryAdapter
Browse files Browse the repository at this point in the history
  • Loading branch information
J-Ben87 committed Jun 8, 2023
1 parent f56a420 commit c07c499
Show file tree
Hide file tree
Showing 35 changed files with 1,048 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/docker/
/var/
!/var/database/.gitkeep
/vendor/
/.phpcs-cache
/.phpunit.result.cache
Expand Down
20 changes: 18 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,26 @@
"require": {
"php": "^8.1",
"ext-intl": "*",
"symfony/expression-language": "^5.0|^6.0"
"doctrine/collections": "^1.0|^2.0",
"doctrine/inflector": "^2.0",
"symfony/expression-language": "^5.0|^6.0",
"zenstruck/foundry": "^1.31"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"dama/doctrine-test-bundle": "^7.2",
"doctrine/doctrine-bundle": "^2.9",
"doctrine/orm": "^2.15",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.6",
"squizlabs/php_codesniffer": "^3.7",
"symfony/phpunit-bridge": "^6.2"
"symfony/console": "^6.2",
"symfony/dotenv": "^6.2",
"symfony/framework-bundle": "^6.2",
"symfony/phpunit-bridge": "^6.2",
"symfony/runtime": "^6.2",
"symfony/var-dumper": "^6.2",
"symfony/yaml": "^6.2"
},
"autoload": {
"psr-4": {
Expand All @@ -28,6 +41,9 @@
},
"autoload-dev": {
"psr-4": {
"Presta\\BehatEvaluator\\Tests\\Application\\": "tests/Application/src/",
"Presta\\BehatEvaluator\\Tests\\Extension\\": "tests/Extension/",
"Presta\\BehatEvaluator\\Tests\\Integration\\": "tests/Integration/",
"Presta\\BehatEvaluator\\Tests\\Resources\\": "tests/Resources/",
"Presta\\BehatEvaluator\\Tests\\Unit\\": "tests/Unit/"
}
Expand Down
135 changes: 135 additions & 0 deletions docs/adapters/factory_adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# FactoryAdapter

The [FactoryAdapter][1] transforms the input value from a string into the result of a [zenstruck/foundry][2] factory method.

Ex. The string `'<factory("user", "findBy", {"lastname": "Doe"})>'` will be transformed into a collection of user entities having "Doe" for lastname in the database.

## Usage

### Fetch an entity with a simple name

Given there is an entity like:
```php
<?php

namespace App\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class User
{
#[ORM\Column(type: Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue]
public int $id;

#[ORM\Column]
public string $firstname;

#[ORM\Column]
public string $lastname;

#[ORM\Column]
public string $email;
}
```
And there is 1 user whose firstname is "John"
Then the following should be true

```php
<?php

use App\Entity\User;
use Presta\BehatEvaluator\Adapter\FactoryAdapter;

$evaluate = new FactoryAdapter();
$value = $evaluate('<factory("user", {"firstname": "John"})>');

\assert($value instanceof User);
\assert('John' === $value->firstname);
```

### Count entities with a compound name

Given there is an entity like:
```php
<?php

namespace App\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class UserGroup
{
#[ORM\Column(type: Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue]
public int $id;

#[ORM\Column]
public string $name;
}
```
And there are 3 user groups, 1 of which being named "Manager"
Then the following should be true

```php
<?php

use Presta\BehatEvaluator\Adapter\FactoryAdapter;

$evaluate = new FactoryAdapter();
$value = $evaluate('<factory("user group", "count", {"name": "Manager"})>');

\assert(1 === $value);
```

### Get the value of a property of an entity in a sub namespace

Given there is an entity like:
```php
<?php

namespace App\Entity\User;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Role
{
#[ORM\Column(type: Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue]
public int $id;

#[ORM\Column]
public string $name;
}
```
And there is 1 user role named "Admin"
Then the following should be true

```php
<?php

use Presta\BehatEvaluator\Adapter\FactoryAdapter;

$evaluate = new FactoryAdapter();
$value = $evaluate('<factory("user/role", {"name": "Admin"}, "name")>');

\assert('Admin' === $value);
```

---

You may return to the [README][3] or read other [adapters][4] guides.

[1]: ../../src/Adapter/FactoryAdapter.php
[2]: https://github.com/zenstruck/foundry
[3]: ../../README.md
[4]: ../adapters/
20 changes: 20 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
parameters:
ignoreErrors:
-
message: "#^Method Presta\\\\BehatEvaluator\\\\Tests\\\\Application\\\\Kernel\\:\\:getConfigDir\\(\\) is unused\\.$#"
count: 1
path: tests/Application/src/Kernel.php

-
message: "#^Generator expects value type array\\{bool\\|float\\|int\\|string, bool\\|float\\|int\\|string\\}, array\\{array\\|object\\|null, array\\|object\\|null\\} given\\.$#"
count: 1
path: tests/Integration/Adapter/FactoryAdapterTest.php

-
message: "#^Parameter \\#1 \\$excludedTypes of static method Presta\\\\BehatEvaluator\\\\Tests\\\\Integration\\\\Adapter\\\\FactoryAdapterTest\\:\\:unsupportedNonScalarValues\\(\\) expects array\\<int, 'array'\\|'null'\\|'object'\\>, array\\<int, 'array'\\|'bool'\\|'float'\\|'int'\\|'null'\\|'object'\\|'string'\\> given\\.$#"
count: 1
path: tests/Integration/Adapter/FactoryAdapterTest.php

-
message: "#^Parameter \\#1 \\$excludedTypes of static method Presta\\\\BehatEvaluator\\\\Tests\\\\Integration\\\\Adapter\\\\FactoryAdapterTest\\:\\:unsupportedScalarValues\\(\\) expects array\\<int, 'bool'\\|'float'\\|'int'\\|'string'\\>, array\\<int, 'array'\\|'bool'\\|'float'\\|'int'\\|'null'\\|'object'\\|'string'\\> given\\.$#"
count: 1
path: tests/Integration/Adapter/FactoryAdapterTest.php

-
message: "#^Generator expects value type array\\{bool\\|float\\|int\\|string, bool\\|float\\|int\\|string\\}, array\\{array\\|object\\|null, array\\|object\\|null\\} given\\.$#"
count: 1
Expand Down
10 changes: 9 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
bootstrap="vendor/autoload.php"
bootstrap="tests/bootstrap.php"
testdox="true"
>
<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<env name="KERNEL_CLASS" value="Presta\BehatEvaluator\Tests\Application\Kernel" />
<server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_DEPRECATIONS_HELPER" value="max[direct]=0" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="10.1" />
</php>

<testsuites>
<testsuite name="Integration tests">
<directory>tests/Integration</directory>
</testsuite>
<testsuite name="Unit tests">
<directory>tests/Unit</directory>
</testsuite>
Expand All @@ -27,6 +31,10 @@
</include>
</coverage>

<extensions>
<extension class="Presta\BehatEvaluator\Tests\Extension\DatabaseExtension" />
</extensions>

<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
</listeners>
Expand Down
42 changes: 42 additions & 0 deletions src/Adapter/FactoryAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Presta\BehatEvaluator\Adapter;

use Presta\BehatEvaluator\ExpressionLanguage\ExpressionLanguage;

/**
* @example <factory("user", {"email": "john.doe@prestaconcept.net"})>
* @example <factory("user", {"email": "john.doe@prestaconcept.net"}, "id")>
* @example <factory("user", "find", {"email": "john.doe@prestaconcept.net"})>
* @example <factory("user", "find", {"email": "john.doe@prestaconcept.net"}, "id")>
* @example <factory("user/role", "count")>
* @example <factory("rating number", "count")>
*/
final class FactoryAdapter implements AdapterInterface
{
public function __construct(private readonly ExpressionLanguage $expressionLanguage)
{
}

public function __invoke(mixed $value): mixed
{
if (!\is_string($value)) {
return $value;
}

preg_match_all("/<(?<expression>factory\([^)]*\))>/", $value, $matches);

foreach ($matches['expression'] as $expression) {
$evaluated = $this->expressionLanguage->evaluate($expression);
if (!\is_string($evaluated)) {
return $evaluated;
}

$value = str_replace("<$expression>", $evaluated, $value);
}

return $value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Presta\BehatEvaluator\ExpressionLanguage\ArgumentGuesser\Factory;

final class AccessorArgumentGuesser implements ArgumentGuesserInterface
{
public function __invoke(
array|string|null $method,
array|string|null $attributes,
string|null $accessor,
): string|null {
if (null === $method) {
return null;
}

if (\is_string($attributes)) {
return $attributes;
}

return $accessor;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Presta\BehatEvaluator\ExpressionLanguage\ArgumentGuesser\Factory;

/**
* @phpstan-type FactoryAttributes array<string, mixed>
*/
interface ArgumentGuesserInterface
{
/**
* @param FactoryAttributes|string|null $method
* @param FactoryAttributes|string|null $attributes
*/
public function __invoke(string|array|null $method, string|array|null $attributes, string|null $accessor): mixed;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Presta\BehatEvaluator\ExpressionLanguage\ArgumentGuesser\Factory;

final class AttributesArgumentGuesser implements ArgumentGuesserInterface
{
/**
* @return array<string, mixed>|null
*/
public function __invoke(
array|string|null $method,
array|string|null $attributes,
string|null $accessor,
): array|null {
if (\is_array($method)) {
return $method;
}

if (\is_array($attributes)) {
return $attributes;
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Presta\BehatEvaluator\ExpressionLanguage\ArgumentGuesser\Factory;

final class MethodArgumentGuesser implements ArgumentGuesserInterface
{
public function __invoke(array|string|null $method, array|string|null $attributes, string|null $accessor): string
{
if (\is_string($method)) {
return $method;
}

return 'find';
}
}
Loading

0 comments on commit c07c499

Please sign in to comment.