Skip to content
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
18 changes: 9 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/doctrine-orm": "^4.2.6",
"api-platform/symfony": "^4.2.6",
"doctrine/dbal": "^3.10.3",
"api-platform/doctrine-orm": "^4.2.8",
"api-platform/symfony": "^4.2.8",
"doctrine/dbal": "^3.10.4",
"doctrine/doctrine-bundle": "^2.18.1",
"doctrine/orm": "^3.5.7",
"doctrine/orm": "^3.5.8",
"nelmio/cors-bundle": "^2.6",
"phpdocumentor/reflection-docblock": "^5.6.4",
"phpdocumentor/reflection-docblock": "^5.6.5",
"phpstan/phpdoc-parser": "^2.3",
"symfony/asset": "7.4.*",
"symfony/console": "7.4.*",
Expand Down Expand Up @@ -83,14 +83,14 @@
},
"require-dev": {
"dama/doctrine-test-bundle": "^8.4",
"justinrainbow/json-schema": "^6.6.1",
"phpunit/phpunit": "^12.4.4",
"justinrainbow/json-schema": "^6.6.3",
"phpunit/phpunit": "^12.4.5",
"symfony/browser-kit": "7.4.*",
"symfony/css-selector": "7.4.*",
"symfony/debug-bundle": "7.4.*",
"symfony/http-client": "7.4.*",
"symfony/maker-bundle": "^1.65",
"symfony/monolog-bundle": "^3.10",
"symfony/maker-bundle": "^1.65.1",
"symfony/monolog-bundle": "^3.11",
"symfony/stopwatch": "7.4.*",
"symfony/web-profiler-bundle": "7.4.*"
}
Expand Down
759 changes: 379 additions & 380 deletions composer.lock

Large diffs are not rendered by default.

36 changes: 25 additions & 11 deletions config/reference.php
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,11 @@
* ...<mixed>
* },
* }
* @psalm-type MakerConfig = array{
* root_namespace?: scalar|null, // Default: "App"
* generate_final_classes?: bool, // Default: true
* generate_final_entities?: bool, // Default: false
* }
* @psalm-type WebProfilerConfig = array{
* toolbar?: bool|array{ // Profiler toolbar configuration
* enabled?: bool, // Default: false
Expand All @@ -1558,9 +1563,11 @@
* handlers?: array<string, array{ // Default: []
* type: scalar|null,
* id?: scalar|null,
* enabled?: bool, // Default: true
* priority?: scalar|null, // Default: 0
* level?: scalar|null, // Default: "DEBUG"
* bubble?: bool, // Default: true
* interactive_only?: bool, // Default: false
* app_name?: scalar|null, // Default: null
* fill_extra_context?: bool, // Default: false
* include_stacktraces?: bool, // Default: false
Expand Down Expand Up @@ -1606,6 +1613,7 @@
* include_extra?: scalar|null, // Default: false
* icon_emoji?: scalar|null, // Default: null
* webhook_url?: scalar|null,
* exclude_fields?: list<scalar|null>,
* team?: scalar|null,
* notify?: scalar|null, // Default: false
* nickname?: scalar|null, // Default: "Monolog"
Expand Down Expand Up @@ -1638,6 +1646,7 @@
* disable_notification?: bool|null, // Default: null
* split_long_messages?: bool, // Default: false
* delay_between_messages?: bool, // Default: false
* topic?: int, // Default: null
* factor?: int, // Default: 1
* tags?: list<scalar|null>,
* console_formater_options?: mixed, // Deprecated: "monolog.handlers..console_formater_options.console_formater_options" is deprecated, use "monolog.handlers..console_formater_options.console_formatter_options" instead.
Expand All @@ -1649,6 +1658,7 @@
* hostname?: scalar|null,
* port?: scalar|null, // Default: 12201
* chunk_size?: scalar|null, // Default: 1420
* encoder?: "json"|"compressed_json",
* },
* mongo?: string|array{
* id?: scalar|null,
Expand All @@ -1659,8 +1669,17 @@
* database?: scalar|null, // Default: "monolog"
* collection?: scalar|null, // Default: "logs"
* },
* mongodb?: string|array{
* id?: scalar|null, // ID of a MongoDB\Client service
* uri?: scalar|null,
* username?: scalar|null,
* password?: scalar|null,
* database?: scalar|null, // Default: "monolog"
* collection?: scalar|null, // Default: "logs"
* },
* elasticsearch?: string|array{
* id?: scalar|null,
* hosts?: list<scalar|null>,
* host?: scalar|null,
* port?: scalar|null, // Default: 9200
* transport?: scalar|null, // Default: "Http"
Expand Down Expand Up @@ -1706,24 +1725,19 @@
* },
* }>,
* }
* @psalm-type DamaDoctrineTestConfig = array{
* enable_static_connection?: mixed, // Default: true
* enable_static_meta_data_cache?: bool, // Default: true
* enable_static_query_cache?: bool, // Default: true
* connection_keys?: list<mixed>,
* }
* @psalm-type MakerConfig = array{
* root_namespace?: scalar|null, // Default: "App"
* generate_final_classes?: bool, // Default: true
* generate_final_entities?: bool, // Default: false
* }
* @psalm-type DebugConfig = array{
* max_items?: int, // Max number of displayed items past the first level, -1 means no limit. // Default: 2500
* min_depth?: int, // Minimum tree depth to clone all the items, 1 is default. // Default: 1
* max_string_length?: int, // Max length of displayed strings, -1 means no limit. // Default: -1
* dump_destination?: scalar|null, // A stream URL where dumps should be written to. // Default: null
* theme?: "dark"|"light", // Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light". // Default: "dark"
* }
* @psalm-type DamaDoctrineTestConfig = array{
* enable_static_connection?: mixed, // Default: true
* enable_static_meta_data_cache?: bool, // Default: true
* enable_static_query_cache?: bool, // Default: true
* connection_keys?: list<mixed>,
* }
* @psalm-type ConfigType = array{
* imports?: ImportsConfig,
* parameters?: ParametersConfig,
Expand Down
15 changes: 15 additions & 0 deletions src/Api/Dto/AuthorCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace App\Api\Dto;

use App\Entity\Author as AuthorEntity;
use Symfony\Component\ObjectMapper\Attribute\Map;

#[Map(source: AuthorEntity::class)]
final class AuthorCollection
{
public int $id;
public string $fullname;
}
3 changes: 3 additions & 0 deletions src/Api/Dto/BookCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace App\Api\Dto;

use App\Api\Resource\Author as AuthorResource;
use App\Entity\Book as BookEntity;
use Symfony\Component\ObjectMapper\Attribute\Map;

Expand All @@ -16,4 +17,6 @@ final class BookCollection
public string $name;

public string $isbn;

public AuthorResource $author;
}
17 changes: 17 additions & 0 deletions src/Api/Dto/CreateAuthor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace App\Api\Dto;

use App\Entity\Author as AuthorEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\ObjectMapper\Attribute\Map;

#[Map(target: AuthorEntity::class)]
final class CreateAuthor
{
#[Assert\NotBlank]
#[Assert\Length(max: 255)]
public string $fullname;
}
17 changes: 17 additions & 0 deletions src/Api/Dto/UpdateAuthor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace App\Api\Dto;

use App\Entity\Author as AuthorEntity;
use Symfony\Component\ObjectMapper\Attribute\Map;
use Symfony\Component\Validator\Constraints as Assert;

#[Map(target: AuthorEntity::class)]
final class UpdateAuthor
{
#[Assert\NotBlank]
#[Assert\Length(max: 255)]
public string $fullname;
}
52 changes: 52 additions & 0 deletions src/Api/Resource/Author.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace App\Api\Resource;

use ApiPlatform\Doctrine\Orm\Filter\PartialSearchFilter;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\QueryParameter;
use App\Api\Dto\AuthorCollection;
use App\Api\Dto\CreateAuthor;
use App\Api\Dto\UpdateAuthor;
use App\Entity\Author as AuthorEntity;
use Doctrine\Common\Collections\Collection;

#[ApiResource(
operations: [
new Get(
uriTemplate: '/authors/{id}',
uriVariables: ['id'],
),
new GetCollection(
uriTemplate: '/authors',
output: AuthorCollection::class,
parameters: [
'fullname' => new QueryParameter(
filter: new PartialSearchFilter(),
property: 'fullname',
),
],
),
new Patch(
uriTemplate: '/authors/{id}',
uriVariables: ['id'],
input: UpdateAuthor::class,
),
new Post(
uriTemplate: '/authors',
input: CreateAuthor::class,
),
],
stateOptions: new Options(entityClass: AuthorEntity::class),
jsonStream: true,
)]
class Author
{
public int $id;
public string $fullname;
}
10 changes: 6 additions & 4 deletions src/Api/Resource/Book.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
use Symfony\Component\Validator\Constraints\Isbn;

#[ApiResource(
stateOptions: new Options(entityClass: BookEntity::class),
jsonStream: true,
operations: [
new Get(
uriTemplate: '/books/{id}',
Expand All @@ -35,8 +33,8 @@
output: BookCollection::class,
parameters: [
'name' => new QueryParameter(
property: 'title',
filter: new PartialSearchFilter(),
property: 'title',
),
'isbn' => new QueryParameter(
filter: new ExactFilter(),
Expand All @@ -56,11 +54,13 @@
new Post(
uriTemplate: '/books/{id}/discount',
uriVariables: ['id'],
status: 200,
input: DiscountBook::class,
processor: DiscountBookProcessor::class,
status: 200,
),
],
stateOptions: new Options(entityClass: BookEntity::class),
jsonStream: true,
)]
#[Map(source: BookEntity::class)]
final class Book
Expand All @@ -77,6 +77,8 @@ final class Book
#[Map(transform: [self::class, 'formatPrice'])]
public string $price;

public Author $author;

public static function formatPrice(mixed $price, object $source): int|string
{
if ($source instanceof BookEntity) {
Expand Down
23 changes: 23 additions & 0 deletions src/Entity/Author.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Entity;

use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity]
class Author
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public private(set) int $id;

#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[Assert\Length(max: 255)]
public string $fullname;
}
3 changes: 3 additions & 0 deletions src/Entity/Book.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ class Book
#[ORM\Column]
#[Assert\PositiveOrZero]
public int $price;

#[ORM\ManyToOne(targetEntity: Author::class)]
public Author $author;
}
3 changes: 2 additions & 1 deletion src/State/DiscountBookProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Api\Dto\DiscountBook;
use App\Api\Resource\Book;
use App\ApiResource\DiscountBook;
use App\Entity\Book as BookEntity;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\ObjectMapper\ObjectMapperInterface;
Expand Down