From 294e9f5800c184c8937ba1d4bb9b1fc013e13e9b Mon Sep 17 00:00:00 2001 From: Prou Yann Date: Tue, 24 Sep 2019 08:38:53 +0200 Subject: [PATCH 01/61] Feat: add file config nav for website for 2.2 version --- outline.yaml | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 outline.yaml diff --git a/outline.yaml b/outline.yaml new file mode 100644 index 00000000000..ca512b9c4b0 --- /dev/null +++ b/outline.yaml @@ -0,0 +1,73 @@ +chapters: + - title: 'The Distribution: Create Powerful APIs with Ease' + path: distribution + items: + - index + - testing + - title: The API Component + path: core + items: + - index + - getting-started + - design + - operations + - graphql + - filters + - serialization + - validation + - security + - data-providers + - data-persisters + - pagination + - events + - content-negotiation + - performance + - extensions + - swagger + - dto + - file-upload + - default-order + - errors + - external-vocabularies + - operation-path-naming + - extending-jsonld-context + - form-data + - jwt + - angularjs-integration + - fosuser-bundle + - nelmio-api-doc + - configuration + - title: The Schema Generator Component + path: schema-generator + items: + - index + - getting-started + - configuration + - title: The Admin Component + path: admin + items: + - index + - getting-started + - authentication-support + - handling-relations-to-collections + - title: The Client Generator Component + path: client-generator + items: + - index + - react + - vuejs + - troubleshooting + - title: Deployment + path: deployment + items: + - index + - kubernetes + - heroku + - title: Extra + path: extra + items: + - releases + - philosophy + - troubleshooting + - contribution-guides + - conduct From 027c94d041471ad522eb5db82fe837df10a10f79 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Fri, 7 Aug 2020 00:48:23 +0200 Subject: [PATCH 02/61] serialization: fix typo on filename --- core/serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/serialization.md b/core/serialization.md index b338345d1eb..b8c88cf6240 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -553,7 +553,7 @@ services: ```php Date: Thu, 14 Oct 2021 12:00:32 -0400 Subject: [PATCH 03/61] Add multiple format support for resolve entity Add doc to option resolveTargetEntityConfigType option which allows to change the file type to YAML (or other formats eventually). --- schema-generator/configuration.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/schema-generator/configuration.md b/schema-generator/configuration.md index 1dbbdef864d..1459e6c542e 100644 --- a/schema-generator/configuration.md +++ b/schema-generator/configuration.md @@ -456,13 +456,20 @@ mappings. If you set the option `useInterface` to true, the generator will generate an interface corresponding to each generated entity and will use them in relation mappings. -To let PHP Schema generate the XML mapping file usable with Symfony, add the following to your config file: +To let PHP Schema generate the mapping file usable with Symfony, add the following to your config file: ```yaml doctrine: resolveTargetEntityConfigPath: path/to/doctrine.xml ``` +The default mapping file format is XML, but you can change it to YAML with the following option: +```yaml +doctrine: + resolveTargetEntityConfigPath: path/to/doctrine.yaml + resolveTargetEntityConfigType: YAML # Supports XML & YAML +``` + ## Custom Schemas The generator can use your own schema definitions. They must be written in RDFa and follow the format of the [Schema.org's From 9372215b5a146ea2a6ab1e604c768cc890c6b2ed Mon Sep 17 00:00:00 2001 From: lobodol Date: Mon, 24 Jan 2022 10:25:47 +0100 Subject: [PATCH 04/61] fix(doc): path to EventPriorities.php (#1496) --- core/events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/events.md b/core/events.md index 0b512b7785a..3a9612b3309 100644 --- a/core/events.md +++ b/core/events.md @@ -59,7 +59,7 @@ Attribute | Type | Default | Description Registering your own event listeners to add extra logic is convenient. -The [`ApiPlatform\Core\EventListener\EventPriorities`](https://github.com/api-platform/core/blob/main/src/Core/EventListener/EventPriorities.php) class comes with a convenient set of class constants corresponding to commonly used priorities: +The [`ApiPlatform\Core\EventListener\EventPriorities`](https://github.com/api-platform/core/blob/2.6/src/EventListener/EventPriorities.php) class comes with a convenient set of class constants corresponding to commonly used priorities: Constant | Event | Priority | -------------------|-------------------|----------| From 13c8c2a4f2eecd471b33bc3e5a2255a34fe9288c Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Mon, 31 Jan 2022 16:41:15 +0100 Subject: [PATCH 05/61] chore: upgrade super linter (#1500) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 116c42780d8..5c32c320355 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: fetch-depth: 0 - name: Lint - uses: github/super-linter@v3 + uses: github/super-linter@v4 env: VALIDATE_ALL_CODEBASE: false VALIDATE_EDITORCONFIG: false From 45dc2b8eec82f80ecc04d7adaeb4b9ce3933bbe3 Mon Sep 17 00:00:00 2001 From: Lenny4 Date: Mon, 31 Jan 2022 14:22:41 -0400 Subject: [PATCH 06/61] docs: fix broken link kubernetes.md (#1499) --- deployment/kubernetes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index fd560e687c3..34ad2b79aef 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -115,7 +115,7 @@ If you prefer to use a managed DBMS like [Heroku Postgres](https://www.heroku.co --set postgresql.url=pgsql://username:password@host/database?serverVersion=13 Finally, build the `pwa` (client and admin) JavaScript apps and [deploy them on a static -website hosting service](https://create-react-app.dev/docs/deployment/). +site hosting service](https://create-react-app.dev/docs/deployment/). ## Access the container @@ -165,7 +165,7 @@ You have to use the *.image.pullPolicy=Always see the last 3 parameters. ## GitHub Actions Example for deployment -You can find a [complete deploy command for GKE](https://github.com/api-platform/demo/blob/main/.github/workflows/deploy.yml) on the [demo project](https://github.com/api-platform/demo/): +You can find a [complete deploy command for GKE](https://github.com/api-platform/demo/blob/main/.github/workflows/cd.yml) on the [demo project](https://github.com/api-platform/demo/): ## Symfony Messenger From da83f0cc0c4e23adaa817f1731bee091d8c89dab Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Thu, 3 Feb 2022 17:06:55 +0100 Subject: [PATCH 07/61] fix(admin): make sure code is working in TS (#1501) --- .github/linters/.textlintrc | 9 +++++++++ admin/authentication-support.md | 20 +++++++++++++------- admin/components.md | 4 ++-- admin/index.md | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 .github/linters/.textlintrc diff --git a/.github/linters/.textlintrc b/.github/linters/.textlintrc new file mode 100644 index 00000000000..b2ce9c62619 --- /dev/null +++ b/.github/linters/.textlintrc @@ -0,0 +1,9 @@ +{ + "rules": { + "terminology": { + "exclude": [ + "Node(?:js)?" + ] + } + } +} diff --git a/admin/authentication-support.md b/admin/authentication-support.md index ca71266e236..85848936b4b 100644 --- a/admin/authentication-support.md +++ b/admin/authentication-support.md @@ -4,15 +4,19 @@ API Platform Admin delegates the authentication support to React Admin. Refer to [the chapter dedicated to authentication in the React Admin documentation](https://marmelab.com/react-admin/Authentication.html) for more information. -In short, you have to tweak the data provider and the api documentation parser like this: +In short, you have to tweak the data provider and the API documentation parser like this: ```typescript // pwa/pages/admin/index.tsx import Head from "next/head"; import { Redirect, Route } from "react-router-dom"; -import { hydraDataProvider as baseHydraDataProvider, fetchHydra as baseFetchHydra, useIntrospection } from "@api-platform/admin"; -import parseHydraDocumentation from "@api-platform/api-doc-parser/lib/hydra/parseHydraDocumentation"; +import { + fetchHydra as baseFetchHydra, + hydraDataProvider as baseHydraDataProvider, + useIntrospection, +} from "@api-platform/admin"; +import { parseHydraDocumentation } from "@api-platform/api-doc-parser"; import authProvider from "utils/authProvider"; import { ENTRYPOINT } from "config/entrypoint"; @@ -35,10 +39,10 @@ const RedirectToLogin = () => { }; const apiDocumentationParser = async () => { try { - const { api } = await parseHydraDocumentation(ENTRYPOINT, { headers: getHeaders }); - return { api }; + return await parseHydraDocumentation(ENTRYPOINT, { headers: getHeaders }); } catch (result) { - if (result.status !== 401) { + const { api, response, status } = result; + if (status !== 401 || !response) { throw result; } @@ -46,7 +50,9 @@ const apiDocumentationParser = async () => { localStorage.removeItem("token"); return { - api: result.api, + api, + response, + status, customRoutes: [ ], diff --git a/admin/components.md b/admin/components.md index 95849ab0be1..b714bc12e92 100644 --- a/admin/components.md +++ b/admin/components.md @@ -21,12 +21,12 @@ const App = () => ( dataProvider={dataProvider} authProvider={authProvider}> - + ) diff --git a/admin/index.md b/admin/index.md index 309d3427de5..a6dffa4ba06 100644 --- a/admin/index.md +++ b/admin/index.md @@ -8,7 +8,7 @@ for any API supporting [the Hydra Core Vocabulary](http://www.hydra-cg.com/) or API Platform Admin is the perfect companion of APIs created using [the API Platform framework](https://api-platform.com), but also supports APIs written with any other programming language or framework as long as they expose a standard Hydra API documentation. -API Platform Admin is a 100% standalone Single-Page-Application with no coupling to the server part, +API Platform Admin is a 100% standalone Single-Page-Application written in TypeScript with no coupling to the server part, according to the API-first paradigm. API Platform Admin parses the API documentation then uses the awesome [React Admin](https://marmelab.com/react-admin/) From ae7ae1af0e3300d45046c7ea1b794fbe6fbdb890 Mon Sep 17 00:00:00 2001 From: Abdelilah Jabri Date: Thu, 10 Feb 2022 18:08:49 +0100 Subject: [PATCH 08/61] fix: remove extra bracket (#1504) --- core/serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/serialization.md b/core/serialization.md index e7c4f1a5f37..87102100b89 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -726,7 +726,7 @@ class Book * * @var bool */ - #[Groups(["book:output", "admin:input"}])] + #[Groups(["book:output", "admin:input"])] public $active = false; /** From 1d401333d0809d9cdefd34a50a3bd2ce86e2f3c4 Mon Sep 17 00:00:00 2001 From: Takashi Kanemoto Date: Mon, 21 Feb 2022 18:28:08 +0900 Subject: [PATCH 09/61] fix: yaml example code of "Calculated Field" (#1506) --- core/serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/serialization.md b/core/serialization.md index 87102100b89..2d647ab7e3e 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -690,7 +690,7 @@ App\Entity\Greeting: groups: 'greeting:collection:get' name: groups: 'greeting:collection:get' - getSum: + sum: groups: 'greeting:collection:get' ``` From b7a111ee270550ce1ce413ed3c7bb37cf656bb34 Mon Sep 17 00:00:00 2001 From: Mathieu Dumez Date: Thu, 24 Feb 2022 09:50:53 +0100 Subject: [PATCH 10/61] Update serialization.md (#1508) --- core/serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/serialization.md b/core/serialization.md index 2d647ab7e3e..8e2eeb08099 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -180,7 +180,7 @@ use Symfony\Component\Serializer\Annotation\Groups; )] class Book { - #[Groups(["get", "put"]) + #[Groups(["get", "put"])] public $name; #[Groups("get")] From b15e01ecfdbc308ed5b9676d26fd264905a3576d Mon Sep 17 00:00:00 2001 From: Julien Maulny Date: Thu, 24 Feb 2022 16:22:17 +0100 Subject: [PATCH 11/61] docs: add note on using PUT method to upload files (#1509) --- core/file-upload.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/file-upload.md b/core/file-upload.md index 736ac5077d7..038b9782a9d 100644 --- a/core/file-upload.md +++ b/core/file-upload.md @@ -42,6 +42,9 @@ resource (in our case: `Book`). This example will use a custom controller to receive the file. The second example will use a custom `multipart/form-data` decoder to deserialize the resource instead. +**Note**: Uploading files won't work in `PUT` or `PATCH` requests, you must use `POST` method to upload files. +See [the related issue on Symfony](https://github.com/symfony/symfony/issues/9226) and [the related bug in PHP](https://bugs.php.net/bug.php?id=55815) talking about this behavior. + ### Configuring the Resource Receiving the Uploaded File The `MediaObject` resource is implemented like this: From e886bb22d1165fc9b6fdc16c5516aca6f6d29d4b Mon Sep 17 00:00:00 2001 From: Maximilian Reichel Date: Fri, 11 Mar 2022 18:23:05 +0100 Subject: [PATCH 12/61] fix: wrong closing bracket (#1515) --- core/graphql.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index 86522437301..291a2185e27 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -382,7 +382,7 @@ For each resource, three mutations are available: one for creating it (`create`) When updating or deleting a resource, you need to pass the **IRI** of the resource as argument. See [Global Object Identifier](#global-object-identifier) for more information. -### Client Mutation Id +### Client Mutation ID Following the [Relay Input Object Mutations Specification](https://github.com/facebook/relay/blob/v7.1.0/website/spec/Mutations.md#relay-input-object-mutations-specification), you can pass a `clientMutationId` as argument and can ask its value as a field. @@ -584,7 +584,7 @@ You can also pass `clientSubscriptionId` as argument and can ask its value as a In the payload of the subscription, the given fields of the resource will be the fields you subscribe to: if any of these fields is updated, you will be pushed their updated values. -The `mercureUrl` field is the Mercure URL you need to use to [subscribe to the updates](https://mercure.rocks/docs/getting-started#subscribing) on the client side. +The `mercureUrl` field is the Mercure URL you need to use to [subscribe to the updates](https://mercure.rocks/docs/getting-started#subscribing) on the client-side. ### Receiving an Update @@ -1169,7 +1169,7 @@ use Symfony\Component\Serializer\Annotation\Groups; 'normalization_context' => ['groups' => ['collection_query']], 'denormalization_context' => ['groups' => ['mutation']] ] - } + ] )] class Book { From f938287a449386649ce6ac00b51bcaf04c4705da Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Sun, 13 Mar 2022 00:50:48 +0100 Subject: [PATCH 13/61] fix: link in controllers.md (#1516) --- core/controllers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/controllers.md b/core/controllers.md index 6d54f2d515a..75620cbd237 100644 --- a/core/controllers.md +++ b/core/controllers.md @@ -68,7 +68,7 @@ This action will be automatically registered as a service (the service name is t API Platform automatically retrieves the appropriate PHP entity using the data provider then deserializes user data in it, and for `POST`, `PUT` and `PATCH` requests updates the entity with data provided by the user. -**Warning: the `__invoke()` method parameter [MUST be called `$data`](https://symfony.com/doc/current/components/http_kernel.html#getting-the-controller-arguments)**, otherwise, it will not be filled correctly! +**Warning: the `__invoke()` method parameter [MUST be called `$data`](https://symfony.com/doc/current/components/http_kernel.html#4-getting-the-controller-arguments)**, otherwise, it will not be filled correctly! Services (`$bookPublishingHandler` here) are automatically injected thanks to the autowiring feature. You can type-hint any service you need and it will be autowired too. From d4f9e3832dfa351dcc822fc5be2e5971b42a8625 Mon Sep 17 00:00:00 2001 From: Mauro Chojrin Date: Sun, 13 Mar 2022 16:11:34 +0100 Subject: [PATCH 14/61] Bumped up xdebug version to support php 8.1 (#1514) --- distribution/debugging.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distribution/debugging.md b/distribution/debugging.md index aa5529803a1..ee887d30932 100644 --- a/distribution/debugging.md +++ b/distribution/debugging.md @@ -17,7 +17,7 @@ it's recommended to add a custom stage to the end of the `api/Dockerfile`. # api/Dockerfile FROM api_platform_php as api_platform_php_dev -ARG XDEBUG_VERSION=3.0.2 +ARG XDEBUG_VERSION=3.1.3 RUN set -eux; \ apk add --no-cache --virtual .build-deps $PHPIZE_DEPS; \ pecl install xdebug-$XDEBUG_VERSION; \ @@ -94,6 +94,6 @@ $ docker-compose exec php \ php --version PHP … - with Xdebug v3.0.2, Copyright (c) 2002-2021, by Derick Rethans + with Xdebug v3.1.3, Copyright (c) 2002-2021, by Derick Rethans … ``` From 378a37fbb62e021473552dacee76e016d7e0a219 Mon Sep 17 00:00:00 2001 From: Maks Rafalko Date: Sun, 13 Mar 2022 18:17:59 +0300 Subject: [PATCH 15/61] fix: [doc] Update URL to point to the existing page, change `main` to `2.6` branch (#1449) Previous URL leads to 404 --- core/pagination.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pagination.md b/core/pagination.md index d7a6b705801..9acdcf05d58 100644 --- a/core/pagination.md +++ b/core/pagination.md @@ -337,7 +337,7 @@ To know more about cursor-based pagination take a look at [this blog post on med ## Controlling The Behavior of The Doctrine ORM Paginator -The [PaginationExtension](https://github.com/api-platform/core/blob/main/src/Bridge/Doctrine/Orm/Extension/PaginationExtension.php) of API Platform performs some checks on the `QueryBuilder` to guess, in most common cases, the correct values to use when configuring the Doctrine ORM Paginator: +The [PaginationExtension](https://github.com/api-platform/core/blob/2.6/src/Bridge/Doctrine/Orm/Extension/PaginationExtension.php) of API Platform performs some checks on the `QueryBuilder` to guess, in most common cases, the correct values to use when configuring the Doctrine ORM Paginator: * `$fetchJoinCollection` argument: Whether there is a join to a collection-valued association. When set to `true`, the Doctrine ORM Paginator will perform an additional query, in order to get the correct number of results. From f1aea51254df544e8e1e1eaa4a07cf742e17f0c6 Mon Sep 17 00:00:00 2001 From: Daniele Ambrosino Date: Sun, 13 Mar 2022 16:19:48 +0100 Subject: [PATCH 16/61] docs(dataprovider): Use argument binding instead of decoration (#1456) Using classic decoration for the custom Data Persister in services.yaml will replace the core persister. Probably this isn't the most common case scenario; normally you would *add* your custom Data Persister to the chain of persisters instead of replacing it. Use attribute binding instead, as already explained in SymfonyCasts' video. --- core/data-persisters.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/data-persisters.md b/core/data-persisters.md index 07b06acb5be..94079677bae 100644 --- a/core/data-persisters.md +++ b/core/data-persisters.md @@ -142,7 +142,8 @@ Even with service autowiring and autoconfiguration enabled, you must still confi services: # ... App\DataPersister\UserDataPersister: - decorates: 'api_platform.doctrine.orm.data_persister' + bind: + $decorated: '@api_platform.doctrine.orm.data_persister' # Uncomment only if autoconfiguration is disabled #arguments: ['@App\DataPersister\UserDataPersister.inner'] #tags: [ 'api_platform.data_persister' ] From 0bc822a9371df000399d536b35e22175bb60dae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20B?= Date: Sun, 13 Mar 2022 16:22:19 +0100 Subject: [PATCH 17/61] docs: update php type and replace annotations with PHP attributes (#1468) * Replace ORM annotations to PHP attributes * Replace @ORM annotations to PHP attributes * Add #[ORM\Entity] * Correction of #[ORM] attribute * Modification of @ORM\Column to #[ORM\Column] for $email property * Modification of @Assert annotation to #[Assert] attribute * Corrections of PR #1466 * Docs: update PHP types for property + update old annotations with PHP attributes * Correction of typo : insersedBy to inversedBy * Delete unnecessary parenthesis * Remove type float * Modify targetEntity value * Add Question type * Add Answer type * Delete PHPDoc without @var type * Replace PHP attributes outside annotations * Add string type to $content * Remove targetEntity, mappedBy and inversedBy for OneToOne relation * Remove type DateTimeInterface due to validation test Co-authored-by: Antoine Bluchet --- admin/handling-relations.md | 14 ++--- admin/performance.md | 4 +- core/extensions.md | 7 +-- core/file-upload.md | 28 +++------ core/filters.md | 6 +- core/fosuser-bundle.md | 26 +++----- core/getting-started.md | 34 +++------- core/graphql.md | 38 +++-------- core/identifiers.md | 16 ++--- core/json-schema.md | 4 +- core/openapi.md | 20 ++---- core/operations.md | 26 ++------ core/performance.md | 30 +++------ core/push-relations.md | 5 +- core/security.md | 28 +++------ core/serialization.md | 95 ++++++++-------------------- core/subresources.md | 58 ++++++----------- core/validation.md | 101 ++++++++---------------------- distribution/index.md | 86 +++++++++---------------- schema-generator/configuration.md | 44 +++++++------ 20 files changed, 205 insertions(+), 465 deletions(-) diff --git a/admin/handling-relations.md b/admin/handling-relations.md index d569965005d..416966709ca 100644 --- a/admin/handling-relations.md +++ b/admin/handling-relations.md @@ -158,9 +158,7 @@ use Doctrine\ORM\Mapping as ORM; #[ApiResource] class Review { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: 'integer')] + #[ORM\Id, ORM\Column, ORM\GeneratedValue] public ?int $id = null; #[ORM\ManyToOne] @@ -185,17 +183,15 @@ use Doctrine\ORM\Mapping as ORM; #[ApiResource] class Book { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: 'integer')] + #[ORM\Id, ORM\Column, ORM\GeneratedValue] public ?int $id = null; - #[ORM\Column] + #[ORM\Column] #[ApiFilter(SearchFilter::class, strategy: 'ipartial')] public string $title; - #[ORM\OneToMany(targetEntity: Review::class)] - public Collection $reviews; + #[ORM\OneToMany(targetEntity: Review::class, mappedBy: 'book')] + public $reviews; public function __construct() { diff --git a/admin/performance.md b/admin/performance.md index 220e67714f9..118590d52d8 100644 --- a/admin/performance.md +++ b/admin/performance.md @@ -29,9 +29,7 @@ use Doctrine\ORM\Mapping as ORM; #[ApiResource] class Author { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: 'integer')] + #[ORM\Id, ORM\Column, ORM\GeneratedValue] #[ApiFilter(SearchFilter::class, strategy: "exact")] public ?int $id = null; diff --git a/core/extensions.md b/core/extensions.md index 058dfc755c7..ca86e0b7bc8 100644 --- a/core/extensions.md +++ b/core/extensions.md @@ -46,11 +46,8 @@ use ApiPlatform\Core\Annotation\ApiResource; #[ApiResource] class Offer { - /** - * @var User - * @ORM\ManyToOne(targetEntity="User") - */ - public $user; + #[ORM\ManyToOne] + public User $user; //... } diff --git a/core/file-upload.md b/core/file-upload.md index 038b9782a9d..e22cfaeacc1 100644 --- a/core/file-upload.md +++ b/core/file-upload.md @@ -64,9 +64,9 @@ use Symfony\Component\Validator\Constraints as Assert; use Vich\UploaderBundle\Mapping\Annotation as Vich; /** - * @ORM\Entity * @Vich\Uploadable */ +#[ORM\Entity] #[ApiResource( iri: 'http://schema.org/MediaObject', normalizationContext: ['groups' => ['media_object:read']], @@ -99,11 +99,7 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich; )] class MediaObject { - /** - * @ORM\Column(type="integer") - * @ORM\GeneratedValue - * @ORM\Id - */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; #[ApiProperty(iri: 'http://schema.org/contentUrl')] @@ -116,9 +112,7 @@ class MediaObject #[Assert\NotNull(groups: ['media_object_create'])] public ?File $file = null; - /** - * @ORM\Column(nullable=true) - */ + #[ORM\Column(nullable: true)] public ?string $filePath = null; public function getId(): ?int @@ -258,18 +252,14 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Component\HttpFoundation\File\File; use Vich\UploaderBundle\Mapping\Annotation as Vich; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource(iri: 'http://schema.org/Book')] class Book { // ... - /** - * @ORM\ManyToOne(targetEntity=MediaObject::class) - * @ORM\JoinColumn(nullable=true) - */ + #[ORM\ManyToOne(targetEntity: MediaObject::class)] + #[ORM\JoinColumn(nullable: true)] #[ApiProperty(iri: 'http://schema.org/image')] public ?MediaObject $image = null; @@ -361,9 +351,9 @@ use Symfony\Component\Serializer\Annotation\Groups; use Vich\UploaderBundle\Mapping\Annotation as Vich; /** - * @ORM\Entity * @Vich\Uploadable */ +#[ORM\Entity] #[ApiResource( iri: 'http://schema.org/Book', normalizationContext: ['groups' => ['book:read']], @@ -391,9 +381,7 @@ class Book #[Groups(['book:write'])] public ?File $file = null; - /** - * @ORM\Column(nullable=true) - */ + #[ORM\Column(nullable: true)] public ?string $filePath = null; // ... diff --git a/core/filters.md b/core/filters.md index 55c97098ec7..63ce5b23609 100644 --- a/core/filters.md +++ b/core/filters.md @@ -1530,12 +1530,10 @@ use App\Entity\DummyCarColor; #[ApiResource] class DummyCar { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: 'integer')] + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; - #[ORM\Column(type: 'string')] + #[ORM\Column] #[ApiFilter(SearchFilter::class, strategy: 'partial')] public ?string $name = null; diff --git a/core/fosuser-bundle.md b/core/fosuser-bundle.md index dca43bf913f..a518b84adb8 100644 --- a/core/fosuser-bundle.md +++ b/core/fosuser-bundle.md @@ -63,37 +63,29 @@ use FOS\UserBundle\Model\User as BaseUser; use FOS\UserBundle\Model\UserInterface; use Symfony\Component\Serializer\Annotation\Groups; -/** - * @ORM\Entity - * @ORM\Table(name="fos_user") - */ +#[ORM\Entity] +#[ORM\Table(name: 'fos_user')] #[ApiResource( normalizationContext: ["groups" => ["user", "user:read"]], denormalizationContext: ["groups" => ["user", "user:write"]] )] class User extends BaseUser { - /** - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - protected $id; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + protected ?int $id = null; #[Groups("user")] - protected $email; + protected string $email; - /** - * @ORM\Column(type="string", length=255, nullable=true) - */ + #[ORM\Column(nullable: true)] #[Groups("user")] - protected $fullname; + protected string $fullname; #[Groups("user:write")] - protected $plainPassword; + protected string $plainPassword; #[Groups("user")] - protected $username; + protected string $username; public function setFullname(?string $fullname): void { diff --git a/core/getting-started.md b/core/getting-started.md index a92863c4fc7..0abe84bce89 100644 --- a/core/getting-started.md +++ b/core/getting-started.md @@ -47,24 +47,18 @@ use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; use Symfony\Component\Validator\Constraints as Assert; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Product // The class name will be used to name exposed resources { - /** - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - * @ORM\Column(type="integer") - */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; /** * A name property - this description will be available in the API documentation too. * - * @ORM\Column */ + #[ORM\Column] #[Assert\NotBlank] public string $name = ''; @@ -72,8 +66,8 @@ class Product // The class name will be used to name exposed resources /** * @var Offer[]|ArrayCollection * - * @ORM\OneToMany(targetEntity="Offer", mappedBy="product", cascade={"persist"}) */ + #[ORM\OneToMany(targetEntity: Offer::class, mappedBy: 'product', cascade: ['persist'])] public iterable $offers; public function __construct() @@ -117,32 +111,22 @@ use Symfony\Component\Validator\Constraints as Assert; /** * An offer from my shop - this description will be automatically extracted from the PHPDoc to document the API. * - * @ORM\Entity */ +#[ORM\Entity] #[ApiResource(iri: 'http://schema.org/Offer')] class Offer { - /** - * @ORM\Column(type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; - /** - * @ORM\Column(type="text") - */ + #[ORM\Column(type: 'text')] public string $description = ''; - /** - * @ORM\Column(type="float") - */ + #[ORM\Column] #[Assert\Range(minMessage: 'The price must be superior to 0.', min: 0)] public float $price = -1.0; - /** - * @ORM\ManyToOne(targetEntity="Product", inversedBy="offers") - */ + #[ORM\ManyToOne(targetEntity: Product::class, inversedBy: 'offers')] public ?Product $product = null; public function getId(): ?int diff --git a/core/graphql.md b/core/graphql.md index 291a2185e27..b16bde749be 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -1451,9 +1451,7 @@ class Book public $name; - /** - * @ORM\OneToMany(targetEntity="Book") - */ + #[ORM\OneToMany(targetEntity: Book::class)] public $relatedBooks; // ... @@ -1771,9 +1769,9 @@ use Symfony\Component\Validator\Constraints as Assert; use Vich\UploaderBundle\Mapping\Annotation as Vich; /** - * @ORM\Entity * @Vich\Uploadable */ +#[ORM\Entity] #[ApiResource( iri: 'http://schema.org/MediaObject', normalizationContext: [ @@ -1791,37 +1789,21 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich; )] class MediaObject { - /** - * @var int|null - * - * @ORM\Column(type="integer") - * @ORM\GeneratedValue - * @ORM\Id - */ - protected $id; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + protected ?int $id = null; - /** - * @var string|null - * - * @Groups({"media_object_read"}) - */ #[ApiProperty(iri: 'http://schema.org/contentUrl')] - public $contentUrl; + #[Groups(['media_object_read'])] + public ?string $contentUrl = null; /** - * @var File|null - * - * @Assert\NotNull(groups={"media_object_create"}) * @Vich\UploadableField(mapping="media_object", fileNameProperty="filePath") */ - public $file; + #[Assert\NotNull(groups: ['media_object_create'])] + public ?File $file = null; - /** - * @var string|null - * - * @ORM\Column(nullable=true) - */ - public $filePath; + #[ORM\Column(nullable: true)] + public ?string $filePath = null; public function getId(): ?int { diff --git a/core/identifiers.md b/core/identifiers.md index d697293cb43..bbc7d82c156 100644 --- a/core/identifiers.md +++ b/core/identifiers.md @@ -155,26 +155,18 @@ use ApiPlatform\Core\Annotation\ApiProperty; use App\Uuid; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] final class Person { - /** - * @var int - * - * @ORM\Id() - * @ORM\GeneratedValue() - * @ORM\Column(type="integer") - */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] #[ApiProperty(identifier: false)] - private $id; + private ?int $id = null; /** * @var Uuid - * @ORM\Column(type="uuid", unique=true) */ + #[ORM\Column(type: 'uuid', unique: true)] #[ApiProperty(identifier: true)] public $code; diff --git a/core/json-schema.md b/core/json-schema.md index 13bb81888d7..9519709f971 100644 --- a/core/json-schema.md +++ b/core/json-schema.md @@ -49,9 +49,7 @@ use Doctrine\ORM\Mapping as ORM; #[ApiResource] class Greeting { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: "integer")] + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; // [...] diff --git a/core/openapi.md b/core/openapi.md index 005c3e054a3..721d10ffce0 100644 --- a/core/openapi.md +++ b/core/openapi.md @@ -122,24 +122,18 @@ use ApiPlatform\Core\Annotation\ApiProperty; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Product // The class name will be used to name exposed resources { - /** - * @ORM\Column(type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; /** * @param string $name A name property - this description will be available in the API documentation too. * - * @ORM\Column */ + #[ORM\Column] #[Assert\NotBlank] #[ApiProperty( attributes: [ @@ -150,11 +144,9 @@ class Product // The class name will be used to name exposed resources ], ], )] - public $name; + public string $name; - /** - * @ORM\Column - */ + #[ORM\Column(type: "datetime")] #[Assert\DateTime] #[ApiProperty( openapi_context: ["type" => "string", "format" => "date-time"] diff --git a/core/operations.md b/core/operations.md index aa66243e0ca..758d3cb767c 100644 --- a/core/operations.md +++ b/core/operations.md @@ -415,31 +415,19 @@ namespace App\Entity; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] class Place { - /** - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; - /** - * @ORM\Column - */ + #[ORM\Column] private string $name = ''; - /** - * @ORM\Column(type="float") - */ + #[ORM\Column(type: 'float')] private float $latitude = 0; - /** - * @ORM\Column(type="float") - */ + #[ORM\Column(type: 'float')] private float $longitude = 0; // ... @@ -475,9 +463,7 @@ use ApiPlatform\Core\Annotation\ApiResource; use App\Controller\GetWeather; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource( collectionOperations: [ 'get', diff --git a/core/performance.md b/core/performance.md index e52a0139ae3..5d74d685fe9 100644 --- a/core/performance.md +++ b/core/performance.md @@ -163,7 +163,7 @@ database driver. By default Doctrine comes with [lazy loading](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html#by-lazy-loading) - usually a killer time-saving feature but also a performance killer with large applications. Fortunately, Doctrine offers another approach to solve this problem: [eager loading](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/working-with-objects.html#by-eager-loading). -This can easily be enabled for a relation: `@ORM\ManyToOne(fetch="EAGER")`. +This can easily be enabled for a relation: `#[ORM\ManyToOne(fetch: "EAGER")]`. By default in API Platform, we made the choice to force eager loading for all relations, with or without the Doctrine `fetch` attribute. Thanks to the eager loading [extension](extensions.md). The `EagerLoadingExtension` will join every @@ -231,9 +231,7 @@ namespace App\Entity; use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Address { @@ -250,25 +248,18 @@ namespace App\Entity; use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource(forceEager: false)] class User { - /** - * @var Address - * - * @ORM\ManyToOne(targetEntity="Address", fetch="EAGER") - */ - public $address; + #[ORM\ManyToOne(fetch: 'EAGER')] + public Address $address; /** * @var Group[] - * - * @ORM\ManyToMany(targetEntity="Group", inversedBy="users") - * @ORM\JoinTable(name="users_groups") */ + #[ORM\ManyToMany(targetEntity: 'Group', inversedBy: 'users')] + #[ORM\JoinTable(name: 'users_groups')] public $groups; // ... @@ -284,9 +275,7 @@ namespace App\Entity; use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource( forceEager: false, itemOperations: [ @@ -302,9 +291,8 @@ class Group { /** * @var User[] - * - * @ManyToMany(targetEntity="User", mappedBy="groups") */ + #[ORM\ManyToMany(targetEntity: 'User', mappedBy: 'groups')] public $users; // ... diff --git a/core/push-relations.md b/core/push-relations.md index 0a702312d6f..d0159adf15a 100644 --- a/core/push-relations.md +++ b/core/push-relations.md @@ -20,11 +20,8 @@ use ApiPlatform\Core\Annotation\ApiResource; #[ApiResource] class Book { - /** - * @var Author - */ #[ApiProperty(push: true)] - public $author; + public Author $author; // ... } diff --git a/core/security.md b/core/security.md index c22e15a7f2a..ccaee857fce 100644 --- a/core/security.md +++ b/core/security.md @@ -19,8 +19,8 @@ use Symfony\Component\Validator\Constraints as Assert; /** * Secured resource. * - * @ORM\Entity */ + #[ORM\Entity] #[ApiResource( attributes: ["security" => "is_granted('ROLE_USER')"], collectionOperations: [ @@ -34,29 +34,15 @@ use Symfony\Component\Validator\Constraints as Assert; )] class Book { - /** - * @var int - * - * @ORM\Column(type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; - /** - * @var string The title - * - * @ORM\Column - */ + #[ORM\Column] #[Assert\NotBlank] - public $title; + public string $title; - /** - * @var User The owner - * - * @ORM\ManyToOne(targetEntity=User::class) - */ - public $owner; + #[ORM\ManyToOne] + public User $owner; // ... } diff --git a/core/serialization.md b/core/serialization.md index 8e2eeb08099..d1b7151c510 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -466,14 +466,11 @@ use Symfony\Component\Serializer\Annotation\Groups; class Person { #[Groups("person")] - public $name; + public string $name; - /** - * @var Person - */ #[Groups("person")] #[ApiProperty(readableLink: false, writableLink: false)] - public $parent; // This property is now serialized/deserialized as an IRI. + public Person $parent; // This property is now serialized/deserialized as an IRI. // ... } @@ -524,15 +521,11 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Context; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Book { - /** - * @ORM\Column(type="date") - */ + #[ORM\Column] #[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])] public ?\DateTimeInterface $publicationDate = null; } @@ -564,15 +557,11 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Context; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Book { - /** - * @ORM\Column(type="date") - */ + #[ORM\Column] #[Context(normalizationContext: [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])] public ?\DateTimeInterface $publicationDate = null; } @@ -594,15 +583,11 @@ use Symfony\Component\Serializer\Annotation\Context; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Book { - /** - * @ORM\Column(type="date") - */ + #[ORM\Column] #[Groups(["extended"])] #[Context([DateTimeNormalizer::FORMAT_KEY => \DateTime::RFC3339])] #[Context( @@ -630,9 +615,7 @@ use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource( collectionOperations: [ 'get' => ['normalization_context' => ['groups' => 'greeting:collection:get']], @@ -640,27 +623,17 @@ use Symfony\Component\Serializer\Annotation\Groups; )] class Greeting { - /** - * @var int The entity Id - * - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] #[Groups("greeting:collection:get")] - private $id; + private ?int $id = null; private $a = 1; private $b = 2; - /** - * @var string A nice person - * - * @ORM\Column - */ + #[ORM\Column] #[Groups("greeting:collection:get")] - public $name = ''; + public string $name = ''; public function getId(): int { @@ -723,19 +696,15 @@ class Book /** * This field can be managed only by an admin - * - * @var bool */ - #[Groups(["book:output", "admin:input"])] - public $active = false; + #[Groups(["book:output", "admin:input"}])] + public bool $active = false; /** * This field can be managed by any user - * - * @var string */ #[Groups(["book:output", "book:input"])] - public $name; + public string $name; // ... } @@ -1022,17 +991,13 @@ class Book /** * This field can be managed only by an admin - * - * @var bool */ - public $active = false; + public bool $active = false; /** * This field can be managed by any user - * - * @var string */ - public $name; + public string $name; // ... } @@ -1133,27 +1098,17 @@ use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] final class Brand { - /** - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; - /** - * @ORM\ManyToMany(targetEntity="App\Entity\Car", inversedBy="brands") - * @ORM\JoinTable( - * name="CarToBrand", - * joinColumns={@ORM\JoinColumn(name="brand_id", referencedColumnName="id", nullable=false)}, - * inverseJoinColumns={@ORM\JoinColumn(name="car_id", referencedColumnName="id", nullable=false)} - * ) - */ + #[ORM\ManyToMany(targetEntity: Car::class, inversedBy: 'brands')] + #[ORM\JoinTable(name: 'CarToBrand')] + #[ORM\JoinColumn(name: 'brand_id', referencedColumnName: 'id', nullable: false)] + #[ORM\InverseJoinColumn(name: 'car_id', referencedColumnName: 'id', nullable: false)] private $cars; public function __construct() diff --git a/core/subresources.md b/core/subresources.md index 6743fa3e7f0..a8cf695afb8 100644 --- a/core/subresources.md +++ b/core/subresources.md @@ -20,28 +20,18 @@ namespace App\Entity; use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Answer { - /** - * @ORM\Column(type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; - - /** - * @ORM\Column - */ - public $content; - - /** - * @ORM\OneToOne(targetEntity="Question", mappedBy="answer") - */ - public $question; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; + + #[ORM\Column(type: 'text')] + public string $content; + + #[ORM\OneToOne] + public Question $question; public function getId(): ?int { @@ -59,30 +49,20 @@ use ApiPlatform\Core\Annotation\ApiResource; use ApiPlatform\Core\Annotation\ApiSubresource; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource] class Question { - /** - * @ORM\Column(type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; - - /** - * @ORM\Column - */ - public $content; - - /** - * @ORM\OneToOne(targetEntity="Answer", inversedBy="question") - * @ORM\JoinColumn(referencedColumnName="id", unique=true) - */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; + + #[ORM\Column(type: 'text')] + public string $content; + + #[ORM\OneToOne] + #[ORM\JoinColumn(referencedColumnName: 'id', unique: true)] #[ApiSubresource] - public $answer; + public Answer $answer; public function getId(): ?int { diff --git a/core/validation.md b/core/validation.md index a7046eba3d8..c5ce45b6716 100644 --- a/core/validation.md +++ b/core/validation.md @@ -26,34 +26,24 @@ use Symfony\Component\Validator\Constraints as Assert; // Symfony's built-in con /** * A product. * - * @ORM\Entity */ +#[ORM\Entity] #[ApiResource] class Product { - /** - * @var int The id of this product. - * - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - */ - private $id; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; - /** - * @var string The name of the product - * - * @Assert\NotBlank - * @ORM\Column - */ - public $name; + #[ORM\Column] + #[Assert\NotBlank] + public string $name; /** * @var string[] Describe the product * * @MinimalProperties - * @ORM\Column(type="json") */ + #[ORM\Column(type: 'json')] public $properties; // Getters and setters... @@ -141,15 +131,11 @@ use Symfony\Component\Validator\Constraints as Assert; #[ApiResource(attributes: ['validation_groups' => ['a', 'b']])] class Book { - /** - * @Assert\NotBlank(groups={"a"}) - */ - public $name; + #[Assert\NotBlank(groups: ['a'])] + public string $name; - /** - * @Assert\NotNull(groups={"b"}) - */ - public $author; + #[Assert\NotNull(groups: ['b'])] + public string $author; // ... } @@ -189,29 +175,15 @@ use Symfony\Component\Validator\Constraints as Assert; )] class Book { - /** - * @Assert\Uuid - */ + #[Assert\Uuid] private $id; - /** - * @Assert\NotBlank(groups={"postValidation"}) - */ + #[Assert\NotBlank(groups: ['postValidation'])] public $name; - /** - * @Assert\NotNull - * @Assert\Length( - * min = 2, - * max = 50, - * groups={"postValidation"} - * ) - * @Assert\Length( - * min = 2, - * max = 70, - * groups={"putValidation"} - * ) - */ + #[Assert\NotNull] + #[Assert\Length(min: 2, max: 50, groups: ['postValidation'])] + #[Assert\Length(min: 2, max: 70, groups: ['putValidation'])] public $author; // ... @@ -258,14 +230,10 @@ class Book return ['a']; } - /** - * @Assert\NotBlank(groups={"a"}) - */ + #[Assert\NotBlank(groups: ['a'])] public $name; - /** - * @Assert\NotNull(groups={"b"}) - */ + #[Assert\NotNull(groups: ['b'])] public $author; // ... @@ -324,14 +292,10 @@ use Symfony\Component\Validator\Constraints as Assert; #[ApiResource(attributes: ['validation_groups' => AdminGroupsGenerator::class]) class Book { - /** - * @Assert\NotBlank(groups={"a"}) - */ + #[Assert\NotBlank(groups: ['a'])] public $name; - /** - * @Assert\NotNull(groups={"b"}) - */ + #[Assert\NotNull(groups: ['b'])] public $author; // ... @@ -383,9 +347,7 @@ use App\Validator\Two; // classic custom constraint use App\Validator\MySequencedGroup; // the sequence group to use use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] #[ApiResource( collectionOperations: [ 'post' => [ @@ -395,25 +357,18 @@ use Doctrine\ORM\Mapping as ORM; )] class Greeting { - /** - * @var int The entity Id - * - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - */ - private $id; + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; /** - * @var string A nice person - * - * @ORM\Column + * @var A nice person * * I want this "second" validation to be executed after the "first" one even though I wrote them in this order. * @One(groups={"second"}) * @Two(groups={"first"}) */ - public $name = ''; + #[ORM\Column] + public string $name = ''; public function getId(): int { @@ -481,9 +436,7 @@ final class Brand $this->cars = new ArrayCollection(); } - /** - * @Assert\Valid - */ + #[Assert\Valid] public function getCars() { return $this->cars->getValues(); diff --git a/distribution/index.md b/distribution/index.md index 32c2ee4be61..1d230a1fe76 100644 --- a/distribution/index.md +++ b/distribution/index.md @@ -373,67 +373,58 @@ Modify these files as described in these patches: +/** + * A book. + * -+ * @ORM\Entity + */ + #[ORM\Entity] #[ApiResource] class Book { - /** The id of this book. */ + /** + * The id of this book. -+ * -+ * @ORM\Id -+ * @ORM\GeneratedValue -+ * @ORM\Column(type="integer") + */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; - /** The ISBN of this book (or null if doesn't have one). */ + /** + * The ISBN of this book (or null if doesn't have one). -+ * -+ * @ORM\Column(nullable=true) + */ + #[ORM\Column(nullable: true)] public ?string $isbn = null; - /** The title of this book. */ + /** + * The title of this book. -+ * -+ * @ORM\Column + */ + #[ORM\Column] public string $title = ''; - /** The description of this book. */ + /** + * The description of this book. -+ * -+ * @ORM\Column(type="text") + */ + #[ORM\Column(type="text")] public string $description = ''; - /** The author of this book. */ + /** + * The author of this book. -+ * -+ * @ORM\Column + */ + #[ORM\Column] public string $author = ''; - /** The publication date of this book. */ + /** + * The publication date of this book. -+ * -+ * @ORM\Column(type="datetime_immutable") + */ + #[ORM\Column] public ?\DateTimeInterface $publicationDate = null; - /** @var Review[] Available reviews for this book. */ + /** + * @var Review[] Available reviews for this book. -+ * -+ * @ORM\OneToMany(targetEntity="Review", mappedBy="book", cascade={"persist", "remove"}) + */ + #[ORM\OneToMany(mappedBy: 'book', targetEntity: 'Review', cascade: ['persist', 'remove'])] public iterable $reviews; public function __construct() @@ -450,60 +441,51 @@ Modify these files as described in these patches: -/** A review of a book. */ +/** + * A review of a book. -+ * -+ * @ORM\Entity + */ + #[ORM\Entity] #[ApiResource] class Review { - /** The id of this review. */ + /** + * The id of this review. -+ * -+ * @ORM\Id -+ * @ORM\GeneratedValue -+ * @ORM\Column(type="integer") + */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; - /** The rating of this review (between 0 and 5). */ + /** + * The rating of this review (between 0 and 5). -+ * -+ * @ORM\Column(type="smallint") + */ + #[ORM\Column(type: "smallint")] public int $rating = 0; - /** The body of the review. */ + /** + * The body of the review. -+ * -+ * @ORM\Column(type="text") + */ + #[ORM\Column(type: "text")] public string $body = ''; - /** The author of the review. */ + /** + * The author of the review. -+ * -+ * @ORM\Column + */ + #[ORM\Column] public string $author = ''; - /** The date of publication of this review.*/ + /** + * The date of publication of this review. -+ * -+ * @ORM\Column(type="datetime_immutable") + */ + #[ORM\Column] public ?\DateTimeInterface $publicationDate = null; - /** The book this review is about. */ + /** + * The book this review is about. -+ * -+ * @ORM\ManyToOne(targetEntity="Book", inversedBy="reviews") + */ + #[ORM\ManyToOne(targetEntity: "Book", inversedBy: "reviews")] public ?Book $book = null; public function getId(): ?int @@ -640,29 +622,24 @@ Modify the following files as described in these patches: use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; - - * @ORM\Column(nullable=true) - */ + + #[ORM\Column(nullable: true)] + #[Assert\Isbn] - public ?string $isbn = null; - - * @ORM\Column - */ + public ?string $isbn = null; + + #[ORM\Column] + #[Assert\NotBlank] public string $title = ''; - * @ORM\Column(type="text") - */ + #[ORM\Column] + #[Assert\NotBlank] public string $description = ''; - * @ORM\Column - */ + #[ORM\Column] + #[Assert\NotBlank] public string $author = ''; - * @ORM\Column(type="datetime_immutable") - */ + #[ORM\Column] + #[Assert\NotNull] public ?\DateTimeInterface $publicationDate = null; ``` @@ -673,29 +650,24 @@ Modify the following files as described in these patches: use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; - - * @ORM\Column(type="smallint") - */ + + #[ORM\Column(type: 'smallint')] + #[Assert\Range(min: 0, max: 5)] public int $rating = 0; - * @ORM\Column(type="text") - */ + #[ORM\Column(type: 'text')] + #[Assert\NotBlank] public string $body = ''; - * @ORM\Column - */ + #[ORM\Column] + #[Assert\NotBlank] public string $author = ''; - * @ORM\Column(type="datetime_immutable") - */ + #[ORM\Column] + #[Assert\NotNull] public ?\DateTimeInterface $publicationDate = null; - * @ORM\ManyToOne(targetEntity="Book", inversedBy="reviews") - */ + #[ORM\ManyToOne(inverdedBy: 'reviews')] + #[Assert\NotNull] public ?Book $book = null; diff --git a/schema-generator/configuration.md b/schema-generator/configuration.md index 1a32ae56135..36d289397f3 100644 --- a/schema-generator/configuration.md +++ b/schema-generator/configuration.md @@ -155,9 +155,9 @@ The `@Assert\NotNull` constraint is automatically added. /** * The name of the item. * - * @ORM\Column - * @Assert\NotNull */ + #[ORM\Column] + #[Assert\NotNull] private string $name; ``` @@ -182,24 +182,25 @@ Output: ... use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Doctrine\ORM\Mapping as ORM; /** * A person (alive, dead, undead, or fictional). * * @see http://schema.org/Person Documentation on Schema.org * - * @ORM\Entity - * @UniqueEntity("email") * @Iri("http://schema.org/Person") */ +#[ORM\Entity] +#[UniqueEntity('email')] class Person { /** * Email address. * - * @ORM\Column - * @Assert\Email */ + #[ORM\Column] + #[Assert\Email] private string $email; ``` @@ -256,15 +257,18 @@ Output: ... use Symfony\Component\Serializer\Annotation\Groups; +use Doctrine\ORM\Mapping as ORM; +use ApiPlatform\Core\Annotation\ApiProperty; +use ApiPlatform\Core\Annotation\ApiResource; /** * A person (alive, dead, undead, or fictional). * - * @see http://schema.org/Person Documentation on Schema.org + * @see https://schema.org/Person Documentation on Schema.org * - * @ORM\Entity - * @Iri("http://schema.org/Person") */ +#[ORM\Entity] +#[ApiResource(iri: "https://schema.org/Person")] class Person { /** @@ -272,11 +276,11 @@ class Person * * @see https://schema.org/name * - * @ORM\Column(nullable=true) - * @Assert\Type(type="string") - * @Iri("https://schema.org/name") - * @Groups({"public"}) */ + #[ORM\Column(nullable: true) + #[Assert\Type(type: 'string')] + #[Groups(['public'])] + #[ApiProperty(iri: 'https://schema.org/name')] private string $name; ``` @@ -310,16 +314,18 @@ Output: ... use Doctrine\ORM\Mapping as ORM; +use ApiPlatform\Core\Annotation\ApiProperty; +use ApiPlatform\Core\Annotation\ApiResource; /** * Any offered product or service. * - * @see http://schema.org/Product Documentation on Schema.org + * @see https://schema.org/Product Documentation on Schema.org * - * @ORM\Entity - * @ApiResource(iri="http://schema.org/Product") - * @UniqueEntity("gtin13s") */ +#[ORM\Entity] +#[ApiResource(iri: 'https://schema.org/Product')] +#[UniqueEntity('gtin13s')] class Product { /** @@ -327,9 +333,9 @@ class Product * * @see http://schema.org/weight * - * @ORM\Embedded(class="App\Entity\QuantitativeValue", columnPrefix="weight_") - * @ApiProperty(iri="http://schema.org/weight") */ + #[ORM\Embedded(class: QuantitativeValue::class, columnPrefix: 'weight_')] + #[ApiProperty(iri: 'https://schema.org/weight')] private ?QuantitativeValue $weight = null; ``` From dfc88c1ac518ec784bf221778a15756932760f60 Mon Sep 17 00:00:00 2001 From: Maks Rafalko Date: Sun, 13 Mar 2022 18:22:57 +0300 Subject: [PATCH 18/61] docs: Add information about how to significantly improve the test suite (#1472) * docs: Add information about how to significantly improve the test suite Hi, this iPR adds an inromation for the page about `JWT` authentication about how to make the tests fast. The issue boils down to the very slow password hashers that are used in tests by default. Each time we start a new project, or review the current one, we have to do it, because tests are extremely slow. This is only one of the many optimizations available for the end developer, but let's start here. Other ones are listed in by blog post: https://maks-rafalko.github.io/blog/2021-11-21/symfony-tests-performance/#using-more-simple-password-hasher * Update wording in core/jwt.md Co-authored-by: Alan Poulain Co-authored-by: Alan Poulain --- core/jwt.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/core/jwt.md b/core/jwt.md index d3d6d954d7b..352ea4f88b5 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -344,3 +344,26 @@ class AuthenticationTest extends ApiTestCase ``` Refer to [Testing the API](../distribution/testing.md) for more information about testing API Platform. + +### Improving Tests Suite Speed + +Since now we have a `JWT` authentication, functional tests require us to log in each time we want to test an API endpoint. This is where [Password Hashers](https://symfony.com/doc/current/security/passwords.html) come into play. + +Hashers are used for 2 reasons: + +1. To generate a hash for a raw password (`self::$container->get('security.user_password_hasher')->hashPassword($user, '$3CR3T')`) +2. To verify a password during authentication + +While hashing and verifying 1 password is quite a fast operation, doing it hundreds or even thousands of times in a tests suite becomes a bottleneck, because reliable hashing algorithms are slow by their nature. + +To significantly improve the test suite speed, we can use more simple password hasher specifically for the `test` environment. + +```yaml +# override in api/config/packages/test/security.yaml for test env +security: + password_hashers: + App\Entity\User: + algorithm: md5 + encode_as_base64: false + iterations: 0 +``` From 5bbb16e82e7cce5e3dce0588fbeabd274a98978e Mon Sep 17 00:00:00 2001 From: xavren Date: Sun, 13 Mar 2022 16:25:30 +0100 Subject: [PATCH 19/61] docs(security): update ApiProperty variables (#1351) Co-authored-by: Antoine Bluchet --- core/security.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/security.md b/core/security.md index ccaee857fce..f7809a61be7 100644 --- a/core/security.md +++ b/core/security.md @@ -103,8 +103,7 @@ In this example: Available variables are: * `user`: the current logged in object, if any -* `object`: the current resource, or collection of resources for collection operations -* `request` (only at the resource level): the current request +* `object`: the current resource class during denormalization, the current resource during normalization, or collection of resources for collection operations Access control checks in the `security` attribute are always executed before the [denormalization step](serialization.md). It means than for `PUT` or `PATCH` requests, `object` doesn't contain the value submitted by the user, but values currently stored in [the persistence layer](data-persisters.md). From 9b4901005f798313e7f753ea4a596cbe0de45b33 Mon Sep 17 00:00:00 2001 From: Mourad Boufarguine Date: Tue, 29 Mar 2022 15:03:53 +0200 Subject: [PATCH 20/61] fix: diff of Doctrine annotations (#1521) --- .github/linters/.textlintrc | 3 +- distribution/index.md | 108 +++++++++++------------------------- 2 files changed, 33 insertions(+), 78 deletions(-) diff --git a/.github/linters/.textlintrc b/.github/linters/.textlintrc index b2ce9c62619..9a594e1278c 100644 --- a/.github/linters/.textlintrc +++ b/.github/linters/.textlintrc @@ -2,7 +2,8 @@ "rules": { "terminology": { "exclude": [ - "Node(?:js)?" + "Node(?:js)?", + "web[- ]?site(s)?" ] } } diff --git a/distribution/index.md b/distribution/index.md index 1d230a1fe76..ff39dc06bc4 100644 --- a/distribution/index.md +++ b/distribution/index.md @@ -339,8 +339,8 @@ The framework also use these metadata to serialize and deserialize data from JSO For the sake of simplicity, in this example we used public properties (except for the id, see below). API Platform (as well as Symfony and Doctrine) also supports accessor methods (getters/setters), use them if you want to. -We used a private property and a getter for the id to enforce the fact that it is read only (we will let the DBMS generating it). API Platform also has first-grade support for UUIDs. [You should -probably use them instead of auto-incremented ids](https://www.clever-cloud.com/blog/engineering/2015/05/20/why-auto-increment-is-a-terrible-idea/). +We used a private property and a getter for the ID to enforce the fact that it is read only (we will let the DBMS generating it). API Platform also has first-grade support for UUIDs. [You should +probably use them instead of auto-incremented IDs](https://www.clever-cloud.com/blog/engineering/2015/05/20/why-auto-increment-is-a-terrible-idea/). Because API Platform provides all the infrastructure for us, our API is almost ready! @@ -369,62 +369,37 @@ Modify these files as described in these patches: use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\ORM\Mapping as ORM; --/** A book. */ -+/** -+ * A book. -+ * -+ */ - #[ORM\Entity] + /** A book. */ ++#[ORM\Entity] #[ApiResource] class Book { -- /** The id of this book. */ -+ /** -+ * The id of this book. -+ */ - #[ORM\Id, ORM\Column, ORM\GeneratedValue] + /** The id of this book. */ ++ #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; -- /** The ISBN of this book (or null if doesn't have one). */ -+ /** -+ * The ISBN of this book (or null if doesn't have one). -+ */ - #[ORM\Column(nullable: true)] + /** The ISBN of this book (or null if doesn't have one). */ ++ #[ORM\Column(nullable: true)] public ?string $isbn = null; -- /** The title of this book. */ -+ /** -+ * The title of this book. -+ */ - #[ORM\Column] + /** The title of this book. */ ++ #[ORM\Column] public string $title = ''; -- /** The description of this book. */ -+ /** -+ * The description of this book. -+ */ - #[ORM\Column(type="text")] + /** The description of this book. */ ++ #[ORM\Column(type: "text")] public string $description = ''; -- /** The author of this book. */ -+ /** -+ * The author of this book. -+ */ - #[ORM\Column] + /** The author of this book. */ ++ #[ORM\Column] public string $author = ''; -- /** The publication date of this book. */ -+ /** -+ * The publication date of this book. -+ */ - #[ORM\Column] + /** The publication date of this book. */ ++ #[ORM\Column(type: "datetime")] public ?\DateTimeInterface $publicationDate = null; -- /** @var Review[] Available reviews for this book. */ -+ /** -+ * @var Review[] Available reviews for this book. -+ */ - #[ORM\OneToMany(mappedBy: 'book', targetEntity: 'Review', cascade: ['persist', 'remove'])] + /** @var Review[] Available reviews for this book. */ ++ #[ORM\OneToMany(mappedBy: 'book', targetEntity: 'Review', cascade: ['persist', 'remove'])] public iterable $reviews; public function __construct() @@ -438,54 +413,33 @@ Modify these files as described in these patches: use ApiPlatform\Core\Annotation\ApiResource; +use Doctrine\ORM\Mapping as ORM; --/** A review of a book. */ -+/** -+ * A review of a book. -+ */ - #[ORM\Entity] + /** A review of a book. */ ++#[ORM\Entity] #[ApiResource] class Review { -- /** The id of this review. */ -+ /** -+ * The id of this review. -+ */ + /** The id of this review. */ #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; -- /** The rating of this review (between 0 and 5). */ -+ /** -+ * The rating of this review (between 0 and 5). -+ */ - #[ORM\Column(type: "smallint")] + /** The rating of this review (between 0 and 5). */ ++ #[ORM\Column(type: "smallint")] public int $rating = 0; -- /** The body of the review. */ -+ /** -+ * The body of the review. -+ */ - #[ORM\Column(type: "text")] + /** The body of the review. */ ++ #[ORM\Column(type: "text")] public string $body = ''; -- /** The author of the review. */ -+ /** -+ * The author of the review. -+ */ - #[ORM\Column] + /** The author of the review. */ ++ #[ORM\Column] public string $author = ''; -- /** The date of publication of this review.*/ -+ /** -+ * The date of publication of this review. -+ */ - #[ORM\Column] + /** The date of publication of this review.*/ ++ #[ORM\Column(type: "datetime")] public ?\DateTimeInterface $publicationDate = null; -- /** The book this review is about. */ -+ /** -+ * The book this review is about. -+ */ - #[ORM\ManyToOne(targetEntity: "Book", inversedBy: "reviews")] + /** The book this review is about. */ ++ #[ORM\ManyToOne(targetEntity: "Book", inversedBy: "reviews")] public ?Book $book = null; public function getId(): ?int From 0a088a5da4bbf96bb4fe03ae6d42f548116d35e4 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Wed, 13 Apr 2022 16:13:52 -0300 Subject: [PATCH 21/61] feat(doc): add description of how to validate item delete operations (#1527) --- core/validation.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/core/validation.md b/core/validation.md index c5ce45b6716..ea433db8bfa 100644 --- a/core/validation.md +++ b/core/validation.md @@ -377,6 +377,89 @@ class Greeting } ``` +## Validating Delete Operations + +By default, validation rules that are specified on the API resource are not evaluated during DELETE operations. You need to trigger the validation in your code, if needed. + +Assume that you have the following entity that uses a custom delete validator: + +```php + [ + 'validation_groups' => ['deleteValidation'] + ] + ] +)] +#[AssertCanDelete(groups: ['deleteValidation'])] +class MyEntity +{ + #[ORM\Id, ORM\Column, ORM\GeneratedValue] + private ?int $id = null; + + #[ORM\Column] + public string $name = ''; +} +``` + +Create a data persister, which decorates the default data persister, where you will trigger the validation: + +```php +decoratedDoctrineDataPersister->persist($data); + } + + public function remove($data): void { + $this->validator->validate( + $data, + ['groups' => ['deleteValidation']] + ); + $this->decoratedDoctrineDataPersister->remove($data); + } + + public function supports($data): bool { + return $data instanceof MyEntity; + } +} +``` + +Register the new data persister in `api/config/services.yaml`: + +```yaml +# api/config/services.yaml +services: + _defaults: + bind: + $decoratedDoctrineDataPersister: '@api_platform.doctrine.orm.data_persister' +``` + ## Error Levels and Payload Serialization As stated in the [Symfony documentation](https://symfony.com/doc/current/validation/severity.html), you can use the payload field to define error levels. From a2c23b653ea9b6feccc1ddb5f294c0294a9a2bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 14 Apr 2022 11:03:05 +0200 Subject: [PATCH 22/61] feat: modernize getting started (#1529) --- distribution/index.md | 52 +++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/distribution/index.md b/distribution/index.md index ff39dc06bc4..805a0da2fd3 100644 --- a/distribution/index.md +++ b/distribution/index.md @@ -10,7 +10,7 @@ ## Introduction -API Platform contains [a **PHP** library (Core)](../core/index.md) to create fully featured hypermedia (or [GraphQL](../core/graphql.md)) web APIs supporting industry-leading standards: [JSON-LD](https://json-ld.org/) with [Hydra](https://www.hydra-cg.com/), [OpenAPI](../core/swagger.md)... +API Platform contains [a **PHP** library (Core)](../core/index.md) to create fully featured hypermedia (or [GraphQL](../core/graphql.md)) web APIs supporting industry-leading standards: [JSON-LD](https://json-ld.org) with [Hydra](https://www.hydra-cg.com), [OpenAPI](../core/swagger.md)... API Platform also provides ambitious **JavaScript** tools to create web and mobile applications based on the most popular frontend technologies in a snap. These tools parse the documentation of the API (or of any other API supporting Hydra or OpenAPI). @@ -43,7 +43,7 @@ API Platform uses these model classes to expose and document a web API having a * hypermedia/[HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) and content negotiation support ([JSON-LD](https://json-ld.org) and [Hydra](https://www.hydra-cg.com/), [JSON:API](https://jsonapi.org/), [HAL](https://tools.ietf.org/html/draft-kelly-json-hal-08)...) * [GraphQL support](../core/graphql.md) * Nice UI and machine-readable documentations ([Swagger UI/OpenAPI](https://swagger.io), [GraphiQL](https://github.com/graphql/graphiql)...) -* authentication ([Basic HTTP](https://en.wikipedia.org/wiki/Basic_access_authentication), cookies as well as [JWT](https://jwt.io/) and [OAuth](https://oauth.net/) through extensions) +* authentication ([Basic HTTP](https://en.wikipedia.org/wiki/Basic_access_authentication), cookies as well as [JWT](../core/jwt.md) and [OAuth](https://oauth.net) through extensions) * [CORS headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) * security checks and headers (tested against [OWASP recommendations](https://www.owasp.org/index.php/REST_Security_Cheat_Sheet)) * [invalidation-based HTTP caching](../core/performance.md) @@ -141,7 +141,7 @@ That being said, keep in mind that API Platform is 100% independent of the persi best suit(s) your needs (including NoSQL databases or remote web services) by implementing the [right interfaces](../core/data-providers.md). API Platform even supports using several persistence systems together in the same project. -### Using Symfony and Composer +### Using Symfony CLI Alternatively, the API Platform server component can also be installed directly on a local machine. **This method is recommended only for users who want full control over the directory structure and the installed @@ -153,12 +153,12 @@ The rest of this tutorial assumes that you have installed API Platform using the next section if it's your case. API Platform has an official Symfony Flex recipe. It means that you can easily install it from any Symfony -application using [Composer](https://getcomposer.org/): +application using [the Symfony binary](https://symfony.com/download): Create a new Symfony project: ```console -composer create-project symfony/skeleton bookshop-api +symfony new bookshop-api ``` Enter the project directory: @@ -170,20 +170,20 @@ cd bookshop-api Install the API Platform's server component in this skeleton: ```console -composer require api +symfony composer require api ``` Then, create the database and its schema: ```console -bin/console doctrine:database:create -bin/console doctrine:schema:create +symfony console doctrine:database:create +symfony console doctrine:schema:create ``` And start the built-in PHP server: ```console -php -S 127.0.0.1:8000 -t public +symfony serve ``` All JavaScript components are also [available as standalone libraries](https://github.com/api-platform?language=javascript) @@ -202,7 +202,7 @@ You'll need to add a security exception in your browser to accept the self-signe for this container when installing the framework. Later you will probably replace this welcome screen by the homepage of your Next.js application. If you don't plan to create -a Progressive Web App, you can remove the `pwa/` directory and the related lines in `docker-compose*.yaml` (don't do it +a Progressive Web App, you can remove the `pwa/` directory as well as the related lines in `docker-compose*.yml` and in `api/docker/caddy/Caddyfile` (don't do it now, we'll use this container later in this tutorial). Click on the "API" button, or go to `https://localhost/docs/`: @@ -269,7 +269,7 @@ class Book public string $author = ''; /** The publication date of this book. */ - public ?\DateTimeInterface $publicationDate = null; + public ?\DateTimeImmutable $publicationDate = null; /** @var Review[] Available reviews for this book. */ public iterable $reviews; @@ -311,7 +311,7 @@ class Review public string $author = ''; /** The date of publication of this review.*/ - public ?\DateTimeInterface $publicationDate = null; + public ?\DateTimeImmutable $publicationDate = null; /** The book this review is about. */ public ?Book $book = null; @@ -387,7 +387,7 @@ Modify these files as described in these patches: public string $title = ''; /** The description of this book. */ -+ #[ORM\Column(type: "text")] ++ #[ORM\Column(type: 'text')] public string $description = ''; /** The author of this book. */ @@ -395,11 +395,11 @@ Modify these files as described in these patches: public string $author = ''; /** The publication date of this book. */ -+ #[ORM\Column(type: "datetime")] ++ #[ORM\Column] public ?\DateTimeInterface $publicationDate = null; /** @var Review[] Available reviews for this book. */ -+ #[ORM\OneToMany(mappedBy: 'book', targetEntity: 'Review', cascade: ['persist', 'remove'])] ++ #[ORM\OneToMany(targetEntity: Review::class, mappedBy: 'book', cascade: ['persist', 'remove'])] public iterable $reviews; public function __construct() @@ -419,15 +419,15 @@ Modify these files as described in these patches: class Review { /** The id of this review. */ - #[ORM\Id, ORM\Column, ORM\GeneratedValue] ++ #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; /** The rating of this review (between 0 and 5). */ -+ #[ORM\Column(type: "smallint")] ++ #[ORM\Column(type: 'smallint')] public int $rating = 0; /** The body of the review. */ -+ #[ORM\Column(type: "text")] ++ #[ORM\Column(type: 'text')] public string $body = ''; /** The author of the review. */ @@ -435,11 +435,11 @@ Modify these files as described in these patches: public string $author = ''; /** The date of publication of this review.*/ -+ #[ORM\Column(type: "datetime")] - public ?\DateTimeInterface $publicationDate = null; ++ #[ORM\Column] + public ?\DateTimeImmutable $publicationDate = null; /** The book this review is about. */ -+ #[ORM\ManyToOne(targetEntity: "Book", inversedBy: "reviews")] ++ #[ORM\ManyToOne(inversedBy: 'reviews')] public ?Book $book = null; public function getId(): ?int @@ -585,7 +585,7 @@ Modify the following files as described in these patches: + #[Assert\NotBlank] public string $title = ''; - #[ORM\Column] + #[ORM\Column(type: 'text')] + #[Assert\NotBlank] public string $description = ''; @@ -593,9 +593,9 @@ Modify the following files as described in these patches: + #[Assert\NotBlank] public string $author = ''; - #[ORM\Column] + #[ORM\Column] + #[Assert\NotNull] - public ?\DateTimeInterface $publicationDate = null; + public ?\DateTimeImmutable $publicationDate = null; ``` `api/src/Entity/Review.php` @@ -619,9 +619,9 @@ Modify the following files as described in these patches: #[ORM\Column] + #[Assert\NotNull] - public ?\DateTimeInterface $publicationDate = null; + public ?\DateTimeImmutable $publicationDate = null; - #[ORM\ManyToOne(inverdedBy: 'reviews')] + #[ORM\ManyToOne(inversedBy: 'reviews')] + #[Assert\NotNull] public ?Book $book = null; From 2e985457d85ec5768ffa2483b5296328b7156fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 14 Apr 2022 11:03:30 +0200 Subject: [PATCH 23/61] feat: explain how to enable Server Push with Caddy (#1530) --- core/push-relations.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/push-relations.md b/core/push-relations.md index d0159adf15a..9ed529713cc 100644 --- a/core/push-relations.md +++ b/core/push-relations.md @@ -7,7 +7,7 @@ API Platform leverages this capability by pushing relations of a resource to clients. **Note:** We strongly recommend using [Vulcain](https://vulcain.rocks) instead of this feature. -Vulcain is faster, cleaner, more flexible, and is supported out of the box in the API Platform distribution. +Vulcain is faster, cleaner, more flexible, and is supported out of the box in [the API Platform distribution](../distribution/index.md). ```php Date: Thu, 14 Apr 2022 14:08:40 +0200 Subject: [PATCH 24/61] fix: datetime type in distribution/index.md --- distribution/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/index.md b/distribution/index.md index 805a0da2fd3..843459fa0a3 100644 --- a/distribution/index.md +++ b/distribution/index.md @@ -396,7 +396,7 @@ Modify these files as described in these patches: /** The publication date of this book. */ + #[ORM\Column] - public ?\DateTimeInterface $publicationDate = null; + public ?\DateTimeImmutable $publicationDate = null; /** @var Review[] Available reviews for this book. */ + #[ORM\OneToMany(targetEntity: Review::class, mappedBy: 'book', cascade: ['persist', 'remove'])] From 1556702558837745e93faa0cb68a61fbe1c0b922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 15 Apr 2022 15:32:49 +0200 Subject: [PATCH 25/61] feat: explain how to configure Caddy (#1531) * feat: explain how to configure Caddy * Update caddy.md * Update caddy.md --- distribution/caddy.md | 35 +++++++++++++++++++++++++++++++++++ distribution/index.md | 2 +- outline.yaml | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 distribution/caddy.md diff --git a/distribution/caddy.md b/distribution/caddy.md new file mode 100644 index 00000000000..5243589af17 --- /dev/null +++ b/distribution/caddy.md @@ -0,0 +1,35 @@ +# Configuring the Caddy Web Server + +[The API Platform distribution](index.md) is shipped with [the Caddy web server](https://caddyserver.com). +The build contains the [Mercure](../core/mercure.md) and the [Vulcain](https://vulcain.rocks) Caddy modules. + +Caddy is positioned in front of the web API and of the Progressive Web App. +It routes requests to either service depending on the value of the `Accept` HTTP header or the extension +of the requested file. + +Using the same domain to serve the API and the PWA [improves performance by preventing unnecessary CORS preflight requests +and encourages embracing the REST principles](https://dunglas.fr/2022/01/preventing-cors-preflight-requests-using-content-negotiation/). + +By default, requests having an `Accept` request header containing the `text/html` media type are routed to the Next.js application, +except for some paths known to be resources served by the API (e.g. the Swagger UI documentation, static files provided by bundles...). +Other requests are routed to the API. + +Sometimes, you may want to let the PHP application generate HTML responses. +For instance, when you create your own Symfony controllers serving HTML pages, +or when using bundles such as EasyAdmin or SonataAdmin. + +To do so, you have to tweak the rules used to route the requests. +Open `api-platform/api/docker/caddy/Caddyfile` and modify the expression. +You can use [any CEL (Common Expression Language) expression](https://caddyserver.com/docs/caddyfile/matchers#expression) supported by Caddy. + +For instance, if you want to route all requests to a path starting with `/admin` to the API, modify the existing expression like this: + +```patch +# Matches requests for HTML documents, for static files and for Next.js files, +# except for known API paths and paths with extensions handled by API Platform +@pwa expression `( + {header.Accept}.matches("\\btext/html\\b") +- && !{path}.matches("(?i)(?:^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") ++ && !{path}.matches("(?i)(?:^/admin|^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") + ) +``` diff --git a/distribution/index.md b/distribution/index.md index 843459fa0a3..d81eab290e1 100644 --- a/distribution/index.md +++ b/distribution/index.md @@ -91,7 +91,7 @@ This starts the following services: | Name | Description | |----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| caddy | [Caddy web server](https://caddyserver.com) with the [Mercure](../core/mercure.md) (real-time and async) and [Vulcain](https://vulcain.rocks) (relations preloading) modules | +| caddy | [Caddy web server](caddy.md) with the [Mercure](../core/mercure.md) (real-time and async) and [Vulcain](https://vulcain.rocks) (relations preloading) modules | | php | The API with PHP 8, Composer and sensitive configs | | pwa | Next.js webapp with API Platform Admin and Client Generator preinstalled | | database | PostgreSQL database server | diff --git a/outline.yaml b/outline.yaml index e1f333a984f..8579f4ddcef 100644 --- a/outline.yaml +++ b/outline.yaml @@ -5,6 +5,7 @@ chapters: - index - testing - debugging + - caddy - title: The API Component path: core items: From b872156b51826bc9410015c74902eab90c794c12 Mon Sep 17 00:00:00 2001 From: Matt Holt Date: Fri, 15 Apr 2022 14:22:48 -0600 Subject: [PATCH 26/61] Update caddy.md (#1532) --- distribution/caddy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/caddy.md b/distribution/caddy.md index 5243589af17..b6fa7a22f69 100644 --- a/distribution/caddy.md +++ b/distribution/caddy.md @@ -31,5 +31,5 @@ For instance, if you want to route all requests to a path starting with `/admin` {header.Accept}.matches("\\btext/html\\b") - && !{path}.matches("(?i)(?:^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") + && !{path}.matches("(?i)(?:^/admin|^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") - ) + )` ``` From dbdd48d99fe69725725f05e2f5d7b0829ca8e5e4 Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Mon, 25 Apr 2022 12:42:37 +0200 Subject: [PATCH 27/61] Update jwt.md --- core/jwt.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/jwt.md b/core/jwt.md index 352ea4f88b5..cbbe61983ae 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -154,6 +154,18 @@ security: - { path: ^/, roles: IS_AUTHENTICATED_FULLY } ``` +### Be sure to have lexik_jwt_authentication configured on your user_identity_field + +```yaml +# api/config/packages/lexik_jwt_authentication.yaml +lexik_jwt_authentication: + secret_key: '%env(resolve:JWT_SECRET_KEY)%' + public_key: '%env(resolve:JWT_PUBLIC_KEY)%' + pass_phrase: '%env(JWT_PASSPHRASE)%' + + user_identity_field: email # Or the field you have setted using make:user +``` + ## Documenting the Authentication Mechanism with Swagger/Open API Want to test the routes of your JWT-authentication-protected API? From 27c3040f5c1733d31781b1163842747e09c4de9b Mon Sep 17 00:00:00 2001 From: Lhoir Simon Date: Thu, 5 May 2022 17:16:19 +0200 Subject: [PATCH 28/61] Update filters.md The example of custom orm filter used swagger attribute in the description. Openapi replaced swagger in OpenApiFactory:getFiltersParameters --- core/filters.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/filters.md b/core/filters.md index 63ce5b23609..b20c315f1b1 100644 --- a/core/filters.md +++ b/core/filters.md @@ -1215,10 +1215,12 @@ final class RegexpFilter extends AbstractContextAwareFilter 'property' => $property, 'type' => Type::BUILTIN_TYPE_STRING, 'required' => false, - 'swagger' => [ - 'description' => 'Filter using a regex. This will appear in the Swagger documentation!', - 'name' => 'Custom name to use in the Swagger documentation', - 'type' => 'Will appear below the name in the Swagger documentation', + 'description' => 'Filter using a regex. This will appear in the OpenApi documentation!', + 'openapi' => [ + 'example' => 'Custom example that will be in the documentation and be the default value of the sandbox', + 'allowReserved' => false,// if true, query parameters will be not percent-encoded + 'allowEmptyValue' => true, + 'explode' => false, // to be true, the type must be Type::BUILTIN_TYPE_ARRAY, ?product=blue,green will be ?product=blue&product=green ], ]; } From 19494b518e2fbae589197c4a0fb574796c272829 Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Wed, 11 May 2022 10:58:33 +0200 Subject: [PATCH 29/61] Fix convertType signature --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index b16bde749be..ef21d26de2c 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -1644,7 +1644,7 @@ final class TypeConverter implements TypeConverterInterface /** * {@inheritdoc} */ - public function convertType(Type $type, bool $input, ?string $queryName, ?string $mutationName, string $resourceClass, string $rootResource, ?string $property, int $depth) + public function convertType(Type $type, bool $input, ?string $queryName, ?string $mutationName, ?string $subscriptionName, string $resourceClass, string $rootResource, ?string $property, int $depth); { if ('publicationDate' === $property && Book::class === $resourceClass From cd0ae4bbea7458744c4f6586ffcd812fbc34d1da Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Wed, 11 May 2022 11:00:20 +0200 Subject: [PATCH 30/61] Update graphql.md --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index ef21d26de2c..2ec18362663 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -1644,7 +1644,7 @@ final class TypeConverter implements TypeConverterInterface /** * {@inheritdoc} */ - public function convertType(Type $type, bool $input, ?string $queryName, ?string $mutationName, ?string $subscriptionName, string $resourceClass, string $rootResource, ?string $property, int $depth); + public function convertType(Type $type, bool $input, ?string $queryName, ?string $mutationName, ?string $subscriptionName, string $resourceClass, string $rootResource, ?string $property, int $depth) { if ('publicationDate' === $property && Book::class === $resourceClass From bb9c22fd5c3bf15be60585b8aaa4403a5bc2fb36 Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Wed, 11 May 2022 11:05:44 +0200 Subject: [PATCH 31/61] Update graphql.md --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index 2ec18362663..09050acb2a4 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -1652,7 +1652,7 @@ final class TypeConverter implements TypeConverterInterface return 'DateTime'; } - return $this->defaultTypeConverter->convertType($type, $input, $queryName, $mutationName, $resourceClass, $rootResource, $property, $depth); + return $this->defaultTypeConverter->convertType($type, $input, $queryName, $mutationName, $subscriptionName, $resourceClass, $rootResource, $property, $depth); } /** From 9383470b43ba3867f517902a345ac9918c1e37d3 Mon Sep 17 00:00:00 2001 From: Bizley Date: Wed, 25 May 2022 00:21:47 +0200 Subject: [PATCH 32/61] Update serialization.md (#1552) --- core/serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/serialization.md b/core/serialization.md index d1b7151c510..7c0e317be20 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -697,7 +697,7 @@ class Book /** * This field can be managed only by an admin */ - #[Groups(["book:output", "admin:input"}])] + #[Groups(["book:output", "admin:input"])] public bool $active = false; /** From 29ecc0b3c7e8cf61420bbcbcb6af512402b3068e Mon Sep 17 00:00:00 2001 From: Tuen Lee Date: Fri, 3 Jun 2022 16:32:12 +0200 Subject: [PATCH 33/61] Update testing.md (#1555) Change getContainer as a function instead of variable --- distribution/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/testing.md b/distribution/testing.md index 89db4e2ebaf..df745cf77a1 100644 --- a/distribution/testing.md +++ b/distribution/testing.md @@ -207,7 +207,7 @@ publicationDate: This value should not be null.', $this->assertResponseStatusCodeSame(204); $this->assertNull( // Through the container, you can access all your services from the tests, including the ORM, the mailer, remote API clients... - static::$container->get('doctrine')->getRepository(Book::class)->findOneBy(['isbn' => '9781344037075']) + static::getContainer()->get('doctrine')->getRepository(Book::class)->findOneBy(['isbn' => '9781344037075']) ); } From 7d16498b82447cd6e1657d9508b599dc9743855f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Grabski-Gradzi=C5=84ski?= Date: Sat, 11 Jun 2022 00:29:58 +0200 Subject: [PATCH 34/61] Documentation fix for subresource custom path. I was having problems with adding custom path name for subresource operation. I've followed suggestions from [this comment](https://github.com/api-platform/api-platform/issues/1581#issuecomment-1098064070) and it worked fine, so I am proposing a change to the documentation. --- core/subresources.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/subresources.md b/core/subresources.md index a8cf695afb8..0844592d1dd 100644 --- a/core/subresources.md +++ b/core/subresources.md @@ -178,7 +178,7 @@ may use `bin/console debug:router`. ## Using Custom Paths -You can control the path of subresources with the `path` option of the `subresourceOperations` parameter: +You can control the path of subresources with the `path` option of the `subresourceOperations` parameter. Notice that you don't have to use the prefix `api_questions_` because it's an operation name: ```php [ + 'answer_get_subresource' => [ 'method' => 'GET', 'path' => '/questions/{id}/all-answers', ], From d994b83b8124aee1617aca2f5677e676424bb9a6 Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Tue, 5 Jul 2022 10:55:36 +0200 Subject: [PATCH 35/61] fix: code links --- core/data-persisters.md | 4 ++-- core/data-providers.md | 12 ++++++------ core/openapi.md | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/data-persisters.md b/core/data-persisters.md index 94079677bae..0cb61ae9011 100644 --- a/core/data-persisters.md +++ b/core/data-persisters.md @@ -22,7 +22,7 @@ persist data for a given resource will be used. ## Creating a Custom Data Persister -To create a data persister, you have to implement the [`ContextAwareDataPersisterInterface`](https://github.com/api-platform/core/blob/main/src/DataPersister/ContextAwareDataPersisterInterface.php). +To create a data persister, you have to implement the [`ContextAwareDataPersisterInterface`](https://github.com/api-platform/core/blob/2.6/src/DataPersister/ContextAwareDataPersisterInterface.php). This interface defines only 3 methods: * `persist`: to create or update the given data @@ -71,7 +71,7 @@ services: #tags: [ 'api_platform.data_persister' ] ``` -Note that if you don't need any `$context` in your data persister's methods, you can implement the [`DataPersisterInterface`](https://github.com/api-platform/core/blob/main/src/DataPersister/DataPersisterInterface.php) instead. +Note that if you don't need any `$context` in your data persister's methods, you can implement the [`DataPersisterInterface`](https://github.com/api-platform/core/blob/2.6/src/DataPersister/DataPersisterInterface.php) instead. ## Decorating the Built-In Data Persisters diff --git a/core/data-providers.md b/core/data-providers.md index 0d0e8023832..2380f55fc21 100644 --- a/core/data-providers.md +++ b/core/data-providers.md @@ -13,13 +13,13 @@ retrieve data for a given resource will be used. For a given resource, you can implement two kinds of interface: -* the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/main/src/Core/DataProvider/CollectionDataProviderInterface.php) +* the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/2.6/src/DataProvider/CollectionDataProviderInterface.php) is used when fetching a collection. -* the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/main/src/Core/DataProvider/ItemDataProviderInterface.php) +* the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/2.6/src/DataProvider/ItemDataProviderInterface.php) is used when fetching items. Both implementations can also implement a third, optional, interface called -['RestrictedDataProviderInterface'](https://github.com/api-platform/core/blob/main/src/Core/DataProvider/RestrictedDataProviderInterface.php) +['RestrictedDataProviderInterface'](https://github.com/api-platform/core/blob/2.6/src/DataProvider/RestrictedDataProviderInterface.php) if you want to limit their effects to a single resource or operation. In the following examples we will create custom data providers for an entity class called `App\Entity\BlogPost`. @@ -27,9 +27,9 @@ Note, that if your entity is not Doctrine-related, you need to flag the identifi ## Custom Collection Data Provider -First, your `BlogPostCollectionDataProvider` has to implement the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/main/src/Core/DataProvider/CollectionDataProviderInterface.php): +First, your `BlogPostCollectionDataProvider` has to implement the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/2.6/src/DataProvider/CollectionDataProviderInterface.php): -The `getCollection` method must return an `array`, a `Traversable` or a [`ApiPlatform\Core\DataProvider\PaginatorInterface`](https://github.com/api-platform/core/blob/main/src/Core/DataProvider/PaginatorInterface.php) instance. +The `getCollection` method must return an `array`, a `Traversable` or a [`ApiPlatform\Core\DataProvider\PaginatorInterface`](https://github.com/api-platform/core/blob/2.6/src/DataProvider/PaginatorInterface.php) instance. If no data is available, you should return an empty array. ```php @@ -79,7 +79,7 @@ You can find a full working example in the [API Platform's demo application](htt ## Custom Item Data Provider -The process is similar for item data providers. Create a `BlogPostItemDataProvider` implementing the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/main/src/Core/DataProvider/ItemDataProviderInterface.php) +The process is similar for item data providers. Create a `BlogPostItemDataProvider` implementing the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/2.6/src/DataProvider/ItemDataProviderInterface.php) interface: The `getItem` method can return `null` if no result has been found. diff --git a/core/openapi.md b/core/openapi.md index 721d10ffce0..170770f0de6 100644 --- a/core/openapi.md +++ b/core/openapi.md @@ -474,7 +474,7 @@ As described [in the Symfony documentation](https://symfony.com/doc/current/temp ``` -You may want to copy the [one shipped with API Platform](https://github.com/api-platform/core/blob/main/src/Bridge/Symfony/Bundle/Resources/views/SwaggerUi/index.html.twig) and customize it. +You may want to copy the [one shipped with API Platform](https://github.com/api-platform/core/blob/2.6/src/Bridge/Symfony/Bundle/Resources/views/SwaggerUi/index.html.twig) and customize it. ## Compatibility Layer with Amazon API Gateway From ba15d2ca3025d17b916c49e3361c58e3586b530d Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Tue, 5 Jul 2022 11:07:12 +0200 Subject: [PATCH 36/61] chore: lint --- core/openapi.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/openapi.md b/core/openapi.md index 170770f0de6..fa3467ecbba 100644 --- a/core/openapi.md +++ b/core/openapi.md @@ -436,7 +436,9 @@ Change `/docs` to the URI you wish Swagger to be accessible on. ## Using a custom Asset Package in Swagger UI -Sometimes you may want to use a different [Asset Package](https://symfony.com/doc/current/reference/configuration/framework.html#packages) for the Swagger UI. In this way you'll have more fine-grained control over the asset url generations. This is useful i.e. if you want to use different base path, base url or asset versioning strategy. +Sometimes you may want to use a different [Asset Package](https://symfony.com/doc/current/reference/configuration/framework.html#packages) for the Swagger UI. +In this way you'll have more fine-grained control over the asset URL generations. +This is useful i.e. if you want to use different base path, base URL or asset versioning strategy. Specify a custom asset package name: @@ -482,7 +484,7 @@ You may want to copy the [one shipped with API Platform](https://github.com/api- API Platform provides a way to be compatible with Amazon API Gateway. To enable API Gateway compatibility on your OpenAPI docs, add `api_gateway=true` as query parameter: `http://www.example.com/docs.json?api_gateway=true`. -The flag `--api-gateway` is also available through the command line. +The flag `--api-gateway` is also available through the command-line. ## OAuth From 95c7535532c803a80ec5c1729f8fc3071db0113a Mon Sep 17 00:00:00 2001 From: Thomas Fortin Date: Tue, 19 Jul 2022 09:13:16 +0200 Subject: [PATCH 37/61] Fix JWT authentication test file with static container (#1565) * Fix JWT authentication test file with static container * Remove the last residue of previous code to get static container --- core/jwt.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/core/jwt.md b/core/jwt.md index 352ea4f88b5..0f92e01a3ad 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -120,7 +120,7 @@ security: # https://symfony.com/doc/current/security.html#c-hashing-passwords password_hashers: App\Entity\User: 'auto' - + # https://symfony.com/doc/current/security/authenticator_manager.html enable_authenticator_manager: true # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers @@ -280,11 +280,11 @@ And register this service in `config/services.yaml`: ```yaml # api/config/services.yaml services: - # ... + # ... App\OpenApi\JwtDecorator: decorates: 'api_platform.openapi.factory' - arguments: ['@.inner'] + arguments: ['@.inner'] ``` ## Testing @@ -308,14 +308,15 @@ class AuthenticationTest extends ApiTestCase public function testLogin(): void { $client = self::createClient(); + $container = self::getContainer(); $user = new User(); $user->setEmail('test@example.com'); $user->setPassword( - self::$container->get('security.user_password_hasher')->hashPassword($user, '$3CR3T') + $container->get('security.user_password_hasher')->hashPassword($user, '$3CR3T') ); - $manager = self::$container->get('doctrine')->getManager(); + $manager = $container->get('doctrine')->getManager(); $manager->persist($user); $manager->flush(); @@ -351,7 +352,7 @@ Since now we have a `JWT` authentication, functional tests require us to log in Hashers are used for 2 reasons: -1. To generate a hash for a raw password (`self::$container->get('security.user_password_hasher')->hashPassword($user, '$3CR3T')`) +1. To generate a hash for a raw password (`$container->get('security.user_password_hasher')->hashPassword($user, '$3CR3T')`) 2. To verify a password during authentication While hashing and verifying 1 password is quite a fast operation, doing it hundreds or even thousands of times in a tests suite becomes a bottleneck, because reliable hashing algorithms are slow by their nature. From 3ddeb9cd20c5e9513522dd4474c5c530ebfaa80c Mon Sep 17 00:00:00 2001 From: des1roer Date: Tue, 19 Jul 2022 12:29:42 +0500 Subject: [PATCH 38/61] Update jwt.md (#1559) https://stackoverflow.com/a/69801383/4601822 Added correct code for JWT (Bearer) auth in Swagger UI --- core/jwt.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/jwt.md b/core/jwt.md index 0f92e01a3ad..26a9b6429a2 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -165,7 +165,7 @@ Want to test the routes of your JWT-authentication-protected API? api_platform: swagger: api_keys: - apiKey: + JWT: name: Authorization type: header ``` @@ -238,6 +238,13 @@ final class JwtDecorator implements OpenApiFactoryInterface ], ]); + $schemas = $openApi->getComponents()->getSecuritySchemes() ?? []; + $schemas['JWT'] = new ArrayObject([ + 'type' => 'http', + 'scheme' => 'bearer', + 'bearerFormat' => 'JWT', + ]); + $pathItem = new Model\PathItem( ref: 'JWT Token', post: new Model\Operation( From 51d2a9f672b55a73ffeb6e8b3e768aadc3e98798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Grabski-Gradzi=C5=84ski?= Date: Tue, 19 Jul 2022 12:19:12 +0200 Subject: [PATCH 39/61] Update core/subresources.md Co-authored-by: Vincent --- core/subresources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/subresources.md b/core/subresources.md index 0844592d1dd..9a98c384aa1 100644 --- a/core/subresources.md +++ b/core/subresources.md @@ -178,7 +178,7 @@ may use `bin/console debug:router`. ## Using Custom Paths -You can control the path of subresources with the `path` option of the `subresourceOperations` parameter. Notice that you don't have to use the prefix `api_questions_` because it's an operation name: +You can control the path of subresources with the `path` option of the `subresourceOperations` parameter. ```php Date: Wed, 20 Jul 2022 09:54:09 +0200 Subject: [PATCH 40/61] docs: replace http://schema.org by https://schema.org --- admin/handling-relations.md | 4 ++-- admin/index.md | 2 +- admin/schema.org.md | 10 ++++----- core/extending-jsonld-context.md | 4 ++-- core/external-vocabularies.md | 32 ++++++++++++++--------------- core/file-upload.md | 14 ++++++------- core/getting-started.md | 6 +++--- core/graphql.md | 4 ++-- core/mongodb.md | 2 +- core/pagination.md | 2 +- core/serialization.md | 6 +++--- core/url-generation-strategy.md | 4 ++-- core/validation.md | 28 ++++++++++++------------- extra/philosophy.md | 2 +- schema-generator/configuration.md | 8 ++++---- schema-generator/getting-started.md | 4 ++-- 16 files changed, 66 insertions(+), 66 deletions(-) diff --git a/admin/handling-relations.md b/admin/handling-relations.md index 416966709ca..85e311ae94c 100644 --- a/admin/handling-relations.md +++ b/admin/handling-relations.md @@ -62,11 +62,11 @@ For instance, if your API returns: "hydra:member": [ { "@id": "/books/07b90597-542e-480b-a6bf-5db223c761aa", - "@type": "http://schema.org/Book", + "@type": "https://schema.org/Book", "title": "War and Peace", "author": { "@id": "/authors/d7a133c1-689f-4083-8cfc-afa6d867f37d", - "@type": "http://schema.org/Author", + "@type": "https://schema.org/Author", "firstName": "Leo", "lastName": "Tolstoi" } diff --git a/admin/index.md b/admin/index.md index a6dffa4ba06..1c14c69ebe5 100644 --- a/admin/index.md +++ b/admin/index.md @@ -21,7 +21,7 @@ You can **customize everything** by using provided React Admin and [Material UI] * Automatically generates an admin interface for all the resources of the API thanks to hypermedia features of Hydra * Generates 'list', 'create', 'show', and 'edit' screens, as well as a delete button * Generates suitable inputs and fields according to the API doc (e.g. number HTML input for numbers, checkbox for booleans, selectbox for relationships...) -* Generates suitable inputs and fields according to Schema.org types if available (e.g. email field for `http://schema.org/email`) +* Generates suitable inputs and fields according to Schema.org types if available (e.g. email field for `https://schema.org/email`) * Handles relationships * Supports pagination * Supports filters and ordering diff --git a/admin/schema.org.md b/admin/schema.org.md index f2c16792df6..fd2e4151f93 100644 --- a/admin/schema.org.md +++ b/admin/schema.org.md @@ -12,12 +12,12 @@ The following examples will use [API Platform Core](../core/) to create such API By default, IRIs of related objects are displayed in lists and forms. However, it is often more user-friendly to display a string representation of the resource (such as its name) instead of its ID. -To configure which property should be shown to represent your entity, map the property containing the name of the object with the `http://schema.org/name` type: +To configure which property should be shown to represent your entity, map the property containing the name of the object with the `https://schema.org/name` type: ```php // api/src/Entity/Person.php -#[ApiProperty(iri: "http://schema.org/name")] +#[ApiProperty(iri: "https://schema.org/name")] private $name; ``` @@ -27,8 +27,8 @@ Besides, it is also possible to use the documentation to customize some fields a The following Schema.org types are currently supported by API Platform Admin: -* `http://schema.org/email`: the field will be rendered using the `` React Admin component -* `http://schema.org/url`: the field will be rendered using the `` React Admin component -* `http://schema.org/identifier`: the field will be formatted properly in inputs +* `https://schema.org/email`: the field will be rendered using the `` React Admin component +* `https://schema.org/url`: the field will be rendered using the `` React Admin component +* `https://schema.org/identifier`: the field will be formatted properly in inputs Note: if you already use validation on your properties, the semantics are already configured correctly (see [the correspondence table](../core/validation.md#open-vocabulary-generated-from-validation-metadata))! diff --git a/core/extending-jsonld-context.md b/core/extending-jsonld-context.md index 30679f643d6..5e8d17445ee 100644 --- a/core/extending-jsonld-context.md +++ b/core/extending-jsonld-context.md @@ -17,13 +17,13 @@ namespace App\Entity; use ApiPlatform\Core\Annotation\ApiProperty; use ApiPlatform\Core\Annotation\ApiResource; -#[ApiResource(iri: "http://schema.org/Book")] +#[ApiResource(iri: "https://schema.org/Book")] class Book { // ... #[ApiProperty( - iri: "http://schema.org/name", + iri: "https://schema.org/name", attributes: [ "jsonld_context" => [ "@id" => "http://yourcustomid.com", diff --git a/core/external-vocabularies.md b/core/external-vocabularies.md index 7b8ba2dbe04..98079a1d0c2 100644 --- a/core/external-vocabularies.md +++ b/core/external-vocabularies.md @@ -14,12 +14,12 @@ namespace App\Entity; use ApiPlatform\Core\Annotation\ApiProperty; use ApiPlatform\Core\Annotation\ApiResource; -#[ApiResource(iri: "http://schema.org/Book")] +#[ApiResource(iri: "https://schema.org/Book")] class Book { // ... - #[ApiProperty(iri: "http://schema.org/name")] + #[ApiProperty(iri: "https://schema.org/name")] public $name; // ... @@ -58,17 +58,17 @@ Built-in mapping is: Constraints | Schema.org type | ---------------------------------------------------- |-----------------------------------| -`Symfony\Component\Validator\Constraints\Url` | `http://schema.org/url` | -`Symfony\Component\Validator\Constraints\Email` | `http://schema.org/email` | -`Symfony\Component\Validator\Constraints\Uuid` | `http://schema.org/identifier` | -`Symfony\Component\Validator\Constraints\CardScheme` | `http://schema.org/identifier` | -`Symfony\Component\Validator\Constraints\Bic` | `http://schema.org/identifier` | -`Symfony\Component\Validator\Constraints\Iban` | `http://schema.org/identifier` | -`Symfony\Component\Validator\Constraints\Date` | `http://schema.org/Date` | -`Symfony\Component\Validator\Constraints\DateTime` | `http://schema.org/DateTime` | -`Symfony\Component\Validator\Constraints\Time` | `http://schema.org/Time` | -`Symfony\Component\Validator\Constraints\Image` | `http://schema.org/image` | -`Symfony\Component\Validator\Constraints\File` | `http://schema.org/MediaObject` | -`Symfony\Component\Validator\Constraints\Currency` | `http://schema.org/priceCurrency` | -`Symfony\Component\Validator\Constraints\Isbn` | `http://schema.org/isbn` | -`Symfony\Component\Validator\Constraints\Issn` | `http://schema.org/issn` | +`Symfony\Component\Validator\Constraints\Url` | `https://schema.org/url` | +`Symfony\Component\Validator\Constraints\Email` | `https://schema.org/email` | +`Symfony\Component\Validator\Constraints\Uuid` | `https://schema.org/identifier` | +`Symfony\Component\Validator\Constraints\CardScheme` | `https://schema.org/identifier` | +`Symfony\Component\Validator\Constraints\Bic` | `https://schema.org/identifier` | +`Symfony\Component\Validator\Constraints\Iban` | `https://schema.org/identifier` | +`Symfony\Component\Validator\Constraints\Date` | `https://schema.org/Date` | +`Symfony\Component\Validator\Constraints\DateTime` | `https://schema.org/DateTime` | +`Symfony\Component\Validator\Constraints\Time` | `https://schema.org/Time` | +`Symfony\Component\Validator\Constraints\Image` | `https://schema.org/image` | +`Symfony\Component\Validator\Constraints\File` | `https://schema.org/MediaObject` | +`Symfony\Component\Validator\Constraints\Currency` | `https://schema.org/priceCurrency` | +`Symfony\Component\Validator\Constraints\Isbn` | `https://schema.org/isbn` | +`Symfony\Component\Validator\Constraints\Issn` | `https://schema.org/issn` | diff --git a/core/file-upload.md b/core/file-upload.md index e22cfaeacc1..02260e20c69 100644 --- a/core/file-upload.md +++ b/core/file-upload.md @@ -68,7 +68,7 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich; */ #[ORM\Entity] #[ApiResource( - iri: 'http://schema.org/MediaObject', + iri: 'https://schema.org/MediaObject', normalizationContext: ['groups' => ['media_object:read']], itemOperations: ['get'], collectionOperations: [ @@ -102,7 +102,7 @@ class MediaObject #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; - #[ApiProperty(iri: 'http://schema.org/contentUrl')] + #[ApiProperty(iri: 'https://schema.org/contentUrl')] #[Groups(['media_object:read'])] public ?string $contentUrl = null; @@ -215,7 +215,7 @@ your data, you will get a response looking like this: ```json { - "@type": "http://schema.org/MediaObject", + "@type": "https://schema.org/MediaObject", "@id": "/media_objects/", "contentUrl": "" } @@ -253,14 +253,14 @@ use Symfony\Component\HttpFoundation\File\File; use Vich\UploaderBundle\Mapping\Annotation as Vich; #[ORM\Entity] -#[ApiResource(iri: 'http://schema.org/Book')] +#[ApiResource(iri: 'https://schema.org/Book')] class Book { // ... #[ORM\ManyToOne(targetEntity: MediaObject::class)] #[ORM\JoinColumn(nullable: true)] - #[ApiProperty(iri: 'http://schema.org/image')] + #[ApiProperty(iri: 'https://schema.org/image')] public ?MediaObject $image = null; // ... @@ -355,7 +355,7 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich; */ #[ORM\Entity] #[ApiResource( - iri: 'http://schema.org/Book', + iri: 'https://schema.org/Book', normalizationContext: ['groups' => ['book:read']], denormalizationContext: ['groups' => ['book:write']], collectionOperations: [ @@ -371,7 +371,7 @@ class Book { // ... - #[ApiProperty(iri: 'http://schema.org/contentUrl')] + #[ApiProperty(iri: 'https://schema.org/contentUrl')] #[Groups(['book:read'])] public ?string $contentUrl = null; diff --git a/core/getting-started.md b/core/getting-started.md index 0abe84bce89..719a016a4a3 100644 --- a/core/getting-started.md +++ b/core/getting-started.md @@ -113,7 +113,7 @@ use Symfony\Component\Validator\Constraints as Assert; * */ #[ORM\Entity] -#[ApiResource(iri: 'http://schema.org/Offer')] +#[ApiResource(iri: 'https://schema.org/Offer')] class Offer { #[ORM\Id, ORM\Column, ORM\GeneratedValue] @@ -175,7 +175,7 @@ resources: App\Entity\Offer: shortName: 'Offer' # optional description: 'An offer from my shop' # optional - iri: 'http://schema.org/Offer' # optional + iri: 'https://schema.org/Offer' # optional attributes: # optional pagination_items_per_page: 25 # optional ``` @@ -193,7 +193,7 @@ resources: class="App\Entity\Offer" shortName="Offer" description="An offer from my shop" - iri="http://schema.org/Offer" + iri="https://schema.org/Offer" /> ``` diff --git a/core/graphql.md b/core/graphql.md index 09050acb2a4..5bb5cb5d1f3 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -1773,7 +1773,7 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich; */ #[ORM\Entity] #[ApiResource( - iri: 'http://schema.org/MediaObject', + iri: 'https://schema.org/MediaObject', normalizationContext: [ 'groups' => ['media_object_read'] ], @@ -1792,7 +1792,7 @@ class MediaObject #[ORM\Id, ORM\Column, ORM\GeneratedValue] protected ?int $id = null; - #[ApiProperty(iri: 'http://schema.org/contentUrl')] + #[ApiProperty(iri: 'https://schema.org/contentUrl')] #[Groups(['media_object_read'])] public ?string $contentUrl = null; diff --git a/core/mongodb.md b/core/mongodb.md index 56c11d8da90..f65a9ce5911 100644 --- a/core/mongodb.md +++ b/core/mongodb.md @@ -170,7 +170,7 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ODM\Document */ -#[ApiResource(iri: "http://schema.org/Offer")] +#[ApiResource(iri: "https://schema.org/Offer")] class Offer { /** diff --git a/core/pagination.md b/core/pagination.md index 9acdcf05d58..4dba8e2a4bf 100644 --- a/core/pagination.md +++ b/core/pagination.md @@ -20,7 +20,7 @@ is returned. It's a valid JSON(-LD) document containing items of the requested p "hydra:member": [ { "@id": "/books/1", - "@type": "http://schema.org/Book", + "@type": "https://schema.org/Book", "name": "My awesome book" }, { diff --git a/core/serialization.md b/core/serialization.md index 7c0e317be20..76592905fcd 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -537,7 +537,7 @@ In the above example, you will receive the book's data like this: { "@context": "/contexts/Book", "@id": "/books/3", - "@type": "http://schema.org/Book", + "@type": "https://schema.org/Book", "publicationDate": "1989-06-16" } ``` @@ -1074,8 +1074,8 @@ The JSON output will now include the embedded context: "@context": { "@vocab": "http://localhost:8000/apidoc#", "hydra": "http://www.w3.org/ns/hydra/core#", - "name": "http://schema.org/name", - "author": "http://schema.org/author" + "name": "https://schema.org/name", + "author": "https://schema.org/author" }, "@id": "/books/62", "@type": "Book", diff --git a/core/url-generation-strategy.md b/core/url-generation-strategy.md index ed164738194..0e6b78b8ea8 100644 --- a/core/url-generation-strategy.md +++ b/core/url-generation-strategy.md @@ -12,7 +12,7 @@ For instance, in JSON-LD, you will get a collection like this: "hydra:member": [ { "@id": "/books/1", - "@type": "http://schema.org/Book", + "@type": "https://schema.org/Book", "name": "My awesome book" } ], @@ -83,7 +83,7 @@ For the above configuration, the collection will be like this: "hydra:member": [ { "@id": "http://example.com/books/1", - "@type": "http://schema.org/Book", + "@type": "https://schema.org/Book", "name": "My awesome book" } ], diff --git a/core/validation.md b/core/validation.md index ea433db8bfa..73c9301b5ee 100644 --- a/core/validation.md +++ b/core/validation.md @@ -535,20 +535,20 @@ The following validation constraints are covered: Constraints | Vocabulary | --------------------------------------------------------------------------------------|-----------------------------------| -[`Url`](https://symfony.com/doc/current/reference/constraints/Url.html) | `http://schema.org/url` | -[`Email`](https://symfony.com/doc/current/reference/constraints/Email.html) | `http://schema.org/email` | -[`Uuid`](https://symfony.com/doc/current/reference/constraints/Uuid.html) | `http://schema.org/identifier` | -[`CardScheme`](https://symfony.com/doc/current/reference/constraints/CardScheme.html) | `http://schema.org/identifier` | -[`Bic`](https://symfony.com/doc/current/reference/constraints/Bic.html) | `http://schema.org/identifier` | -[`Iban`](https://symfony.com/doc/current/reference/constraints/Iban.html) | `http://schema.org/identifier` | -[`Date`](https://symfony.com/doc/current/reference/constraints/Date.html) | `http://schema.org/Date` | -[`DateTime`](https://symfony.com/doc/current/reference/constraints/DateTime.html) | `http://schema.org/DateTime` | -[`Time`](https://symfony.com/doc/current/reference/constraints/Time.html) | `http://schema.org/Time` | -[`Image`](https://symfony.com/doc/current/reference/constraints/Image.html) | `http://schema.org/image` | -[`File`](https://symfony.com/doc/current/reference/constraints/File.html) | `http://schema.org/MediaObject` | -[`Currency`](https://symfony.com/doc/current/reference/constraints/Currency.html) | `http://schema.org/priceCurrency` | -[`Isbn`](https://symfony.com/doc/current/reference/constraints/Isbn.html) | `http://schema.org/isbn` | -[`Issn`](https://symfony.com/doc/current/reference/constraints/Issn.html) | `http://schema.org/issn` | +[`Url`](https://symfony.com/doc/current/reference/constraints/Url.html) | `https://schema.org/url` | +[`Email`](https://symfony.com/doc/current/reference/constraints/Email.html) | `https://schema.org/email` | +[`Uuid`](https://symfony.com/doc/current/reference/constraints/Uuid.html) | `https://schema.org/identifier` | +[`CardScheme`](https://symfony.com/doc/current/reference/constraints/CardScheme.html) | `https://schema.org/identifier` | +[`Bic`](https://symfony.com/doc/current/reference/constraints/Bic.html) | `https://schema.org/identifier` | +[`Iban`](https://symfony.com/doc/current/reference/constraints/Iban.html) | `https://schema.org/identifier` | +[`Date`](https://symfony.com/doc/current/reference/constraints/Date.html) | `https://schema.org/Date` | +[`DateTime`](https://symfony.com/doc/current/reference/constraints/DateTime.html) | `https://schema.org/DateTime` | +[`Time`](https://symfony.com/doc/current/reference/constraints/Time.html) | `https://schema.org/Time` | +[`Image`](https://symfony.com/doc/current/reference/constraints/Image.html) | `https://schema.org/image` | +[`File`](https://symfony.com/doc/current/reference/constraints/File.html) | `https://schema.org/MediaObject` | +[`Currency`](https://symfony.com/doc/current/reference/constraints/Currency.html) | `https://schema.org/priceCurrency` | +[`Isbn`](https://symfony.com/doc/current/reference/constraints/Isbn.html) | `https://schema.org/isbn` | +[`Issn`](https://symfony.com/doc/current/reference/constraints/Issn.html) | `https://schema.org/issn` | ## Specification property restrictions diff --git a/extra/philosophy.md b/extra/philosophy.md index d32176e0337..e2be4516ef2 100644 --- a/extra/philosophy.md +++ b/extra/philosophy.md @@ -6,7 +6,7 @@ In 25 years of PHP, the web changed dramatically and is now evolving faster than [full-JavaScript Progressive Web Apps](https://en.wikipedia.org/wiki/Progressive_web_application) **are becoming the standard**. * [Internet users spend more time on their mobile devices than on desktops](https://www.broadbandsearch.net/blog/mobile-desktop-internet-usage-statistics): having a mobile-first website is mandatory and **native mobile apps are a must-have**. * [The semantic web](https://en.wikipedia.org/wiki/Semantic_Web) and **especially [Linked Data](https://en.wikipedia.org/wiki/Linked_data) - is a reality**: with the [Schema.org](http://schema.org/) initiative and new open web standards such as [JSON-LD](http://json-ld.org/), + is a reality**: with the [Schema.org](https://schema.org/) initiative and new open web standards such as [JSON-LD](http://json-ld.org/), search engines (among a bunch of other services and software) consume structured and machine-readable data at web scale. Not exposing such data decrease interoperability and search engine ranking/efficiency (think rich snippets). * HTTP/2 and HTTP/3 [dramatically improve the performance of web applications](https://vulcain.rocks) thanks to multiplexing, Server Push and their other new capabilities. diff --git a/schema-generator/configuration.md b/schema-generator/configuration.md index 36d289397f3..51e896b5146 100644 --- a/schema-generator/configuration.md +++ b/schema-generator/configuration.md @@ -187,9 +187,9 @@ use Doctrine\ORM\Mapping as ORM; /** * A person (alive, dead, undead, or fictional). * - * @see http://schema.org/Person Documentation on Schema.org + * @see https://schema.org/Person Documentation on Schema.org * - * @Iri("http://schema.org/Person") + * @Iri("https://schema.org/Person") */ #[ORM\Entity] #[UniqueEntity('email')] @@ -331,7 +331,7 @@ class Product /** * the weight of the product or person * - * @see http://schema.org/weight + * @see https://schema.org/weight * */ #[ORM\Embedded(class: QuantitativeValue::class, columnPrefix: 'weight_')] @@ -560,7 +560,7 @@ config: format: null # Example: rdfxml # Namespace of the vocabulary to import - vocabularyNamespace: 'http://schema.org/' # Example: 'http://www.w3.org/ns/activitystreams#' + vocabularyNamespace: 'https://schema.org/' # Example: 'http://www.w3.org/ns/activitystreams#' # OWL relation files containing cardinality information in the GoodRelations format relations: # Example: 'https://purl.org/goodrelations/v1.owl' diff --git a/schema-generator/getting-started.md b/schema-generator/getting-started.md index bfa7ae30125..d4f67550fe0 100644 --- a/schema-generator/getting-started.md +++ b/schema-generator/getting-started.md @@ -26,8 +26,8 @@ Then, write a simple YAML config file similar to the following. Here we will generate a data model for an address book with the following data: -* a [`Person`](http://schema.org/Person) which inherits from [`Thing`](http://schema.org/Thing) -* a [`PostalAddress`](http://schema.org/PostalAddress) which inherits from [`ContactPoint`](http://schema.org/ContactPoint), which itself inherits from [`StructuredValue`](http://schema.org/StructuredValue), etc. +* a [`Person`](https://schema.org/Person) which inherits from [`Thing`](https://schema.org/Thing) +* a [`PostalAddress`](https://schema.org/PostalAddress) which inherits from [`ContactPoint`](https://schema.org/ContactPoint), which itself inherits from [`StructuredValue`](https://schema.org/StructuredValue), etc. ```yaml # api/config/schema.yaml From b0261b9c49cd20b7a51595d3fccb3670b0cbdd1f Mon Sep 17 00:00:00 2001 From: Vincent Chalamon Date: Wed, 20 Jul 2022 10:14:38 +0200 Subject: [PATCH 41/61] fix: textlint --- core/mongodb.md | 2 +- extra/philosophy.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mongodb.md b/core/mongodb.md index f65a9ce5911..f03115499ad 100644 --- a/core/mongodb.md +++ b/core/mongodb.md @@ -203,7 +203,7 @@ class Offer } ``` -When defining references, always use the id for storing them instead of the native [DBRef](https://docs.mongodb.com/manual/reference/database-references/#dbrefs). +When defining references, always use the ID for storing them instead of the native [DBRef](https://docs.mongodb.com/manual/reference/database-references/#dbrefs). It allows API Platform to manage [filtering on nested properties](filters.md#apifilter-annotation) by using [lookups](https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/). ## Filtering diff --git a/extra/philosophy.md b/extra/philosophy.md index e2be4516ef2..8a762c8c3c9 100644 --- a/extra/philosophy.md +++ b/extra/philosophy.md @@ -29,7 +29,7 @@ API Platform makes modern development easy and fun again: be understood by any compliant client such as your apps but also search engines (JSON-LD with Schema.org vocabulary). This API is the central and unique entry point to access and modify data. It also encapsulates the whole business logic. * [Then **create as many clients as you want using frontend technologies you love**](../client-generator/index.md): a JavaScript - webapp built in React or in Vue querying the API but also a native iOS or Android app, or even a desktop application. Clients + webapp built with React or with Vue querying the API but also a native iOS or Android app, or even a desktop application. Clients only display data and forms. See also [the general design](../core/design.md) of the framework. From 471a93dc1b30641e53e99541513306390dd7ba8b Mon Sep 17 00:00:00 2001 From: Julien Date: Wed, 20 Jul 2022 12:09:20 +0200 Subject: [PATCH 42/61] add: [DOC] Custom Subresources Data Provider examples (#1454) * add: Custom Subresources Data Provider examples I added exemple to help user to custom the subreshttps://github.com/api-platform/core/issues/2321#issuecomment-437357871 It would be nice to set a trace in the official doc. * changes for the review * add the listing top SubresourceDataProviderInterface * Update core/data-providers.md * Update core/data-providers.md * Update core/data-providers.md * Update core/data-providers.md * Update core/data-providers.md * Update core/data-providers.md Co-authored-by: Vincent --- core/data-providers.md | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/core/data-providers.md b/core/data-providers.md index 2380f55fc21..bf08d623820 100644 --- a/core/data-providers.md +++ b/core/data-providers.md @@ -17,6 +17,8 @@ For a given resource, you can implement two kinds of interface: is used when fetching a collection. * the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/2.6/src/DataProvider/ItemDataProviderInterface.php) is used when fetching items. +* the [`SubresourceDataProviderInterface`](https://github.com/api-platform/core/blob/2.6/src/DataProvider/SubresourceDataProviderInterface.php) + is used when fetching items. Both implementations can also implement a third, optional, interface called ['RestrictedDataProviderInterface'](https://github.com/api-platform/core/blob/2.6/src/DataProvider/RestrictedDataProviderInterface.php) @@ -126,6 +128,49 @@ services: You can find a full working example in the [API Platform's demo application](https://github.com/api-platform/demo/blob/main/api/src/DataProvider/TopBookItemDataProvider.php). +## Custom Subresources Data Provider + +You can add custom logic or update subresources data provider with the SubresourceDataProviderInterface . + +```php +subresourceDataProvider->getSubresource($resourceClass, $identifiers, $context, $operationName); + // write your own logic + + return blogPosts; + } +} +``` + +Declare the service in your services configuration: + +```yaml +# api/config/services.yaml +services: + # ... + 'App\DataProvider\BlogPostSubresourceDataProvider': + arguments: + - '@api_platform.doctrine.orm.default.subresource_data_provider' +``` + ## Injecting the Serializer in an `ItemDataProvider` In some cases, you may need to inject the `Serializer` in your `DataProvider`. There are no issues with the From b8e425477dbeda153c55b3bd51807da09b8c4256 Mon Sep 17 00:00:00 2001 From: optior <18595399+optior@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:12:02 +0200 Subject: [PATCH 43/61] Add empty security option to remove security of authentication endpoint (#1335) --- core/jwt.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core/jwt.md b/core/jwt.md index 00f2f2c9604..d0ebe071618 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -285,6 +285,7 @@ final class JwtDecorator implements OpenApiFactoryInterface ], ]), ), + security: [], ), ); $openApi->getPaths()->addPath('/authentication_token', $pathItem); From c9de0763f637df4a429afa3e390a003984d10a67 Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Wed, 20 Jul 2022 12:14:48 +0200 Subject: [PATCH 44/61] Fix default oauth token configuration (#1310) --- core/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/configuration.md b/core/configuration.md index bfdc87c1bfd..825a1a21ca2 100644 --- a/core/configuration.md +++ b/core/configuration.md @@ -160,11 +160,11 @@ api_platform: # The OAuth flow grant type. flow: 'application' - # The OAuth token URL. - tokenUrl: '/oauth/v2/token' + # The OAuth token URL. Make sure to check the specification tokenUrl is not needed for an implicit flow. + tokenUrl: '' # The OAuth authentication URL. - authorizationUrl: '/oauth/v2/auth' + authorizationUrl: '' # The OAuth scopes. scopes: [] From 17976650d0c386e472aed42a04f799c17c10bdd6 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Wed, 20 Jul 2022 07:28:20 -0300 Subject: [PATCH 45/61] feat(doc): use snake case names on operation sub options (#1536) * feat(doc): use snake case names on operation sub options * Apply suggestions from code review Co-authored-by: Vincent --- core/operations.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/core/operations.md b/core/operations.md index 758d3cb767c..2c11a7fae0d 100644 --- a/core/operations.md +++ b/core/operations.md @@ -351,6 +351,89 @@ App\Entity\Book: In all these examples, the `method` attribute is omitted because it matches the operation name. +When specifying sub options, you must always use snake case as demonstrated below with the `denormalization_context` option on the `put` operation: + +[codeSelector] + +```php + [ + 'denormalization_context' => [ + 'groups' => ['item:put'], + 'swagger_definition_name' => 'put', + ], + ], + 'delete', + ], + ], + denormalizationContext: [ + 'groups' => ['item:post'], + 'swagger_definition_name' => 'post', + ], +)] +class Book +{ + //... +} +``` + +```yaml +# api/config/api_platform/resources.yaml +App\Entity\Book: + itemOperations: + get: ~ + put: + denormalization_context: + groups: ['item:put'] + swagger_definition_name: 'put', + delete: ~ + denormalizationContext: + groups: ['item:post'] + swagger_definition_name: 'post' +``` + +```xml + + + + + + + + + + + item:put + + put + + + + + + + item:post + + post + + + +``` + +[/codeSelector] + ## Prefixing All Routes of All Operations Sometimes it's also useful to put a whole resource into its own "namespace" regarding the URI. Let's say you want to From 17af024e10fa819e8caaab13c54cea4ccf09100b Mon Sep 17 00:00:00 2001 From: Guillem Fondin <46321667+guillemfondin@users.noreply.github.com> Date: Wed, 20 Jul 2022 12:32:38 +0200 Subject: [PATCH 46/61] Update serialization.md (#1463) * Update serialization.md Change `denormalize` method example in 'Decorating a Serializer and Adding Extra Data' part to match with the signature of `DenormalizerInterface` * Update core/serialization.md Co-authored-by: Vincent --- core/serialization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/serialization.md b/core/serialization.md index 76592905fcd..caaaca3034a 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -958,9 +958,9 @@ final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, return $this->decorated->supportsDenormalization($data, $type, $format); } - public function denormalize($data, $class, $format = null, array $context = []) + public function denormalize($data, string $type, string $format = null, array $context = []) { - return $this->decorated->denormalize($data, $class, $format, $context); + return $this->decorated->denormalize($data, $type, $format, $context); } public function setSerializer(SerializerInterface $serializer) From f03ae21671b5e9797f71b86e1308e72b9ff43ac0 Mon Sep 17 00:00:00 2001 From: Nathan <99896288+Hapy17@users.noreply.github.com> Date: Wed, 27 Jul 2022 23:36:25 +0200 Subject: [PATCH 47/61] Update jwt.md (#1580) Add a missing backslash line230 --- core/jwt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jwt.md b/core/jwt.md index d0ebe071618..ad1e6c0862a 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -251,7 +251,7 @@ final class JwtDecorator implements OpenApiFactoryInterface ]); $schemas = $openApi->getComponents()->getSecuritySchemes() ?? []; - $schemas['JWT'] = new ArrayObject([ + $schemas['JWT'] = new \ArrayObject([ 'type' => 'http', 'scheme' => 'bearer', 'bearerFormat' => 'JWT', From 37a70805e83bcc850a94b2f23bf6e2d08ac7b072 Mon Sep 17 00:00:00 2001 From: Laurent Cns <99896434+LaurentCNS@users.noreply.github.com> Date: Wed, 27 Jul 2022 23:36:45 +0200 Subject: [PATCH 48/61] Update jwt.md (#1582) From 8e36f48e8ff26cefe3e19e374bc5f0c2726edd07 Mon Sep 17 00:00:00 2001 From: Pinchon Karim Date: Tue, 2 Aug 2022 22:12:19 +0200 Subject: [PATCH 49/61] docs(jwt): fix broken links (#1586) --- core/jwt.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/jwt.md b/core/jwt.md index ad1e6c0862a..2ebeb678f3a 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -42,7 +42,7 @@ The keys should not be checked in to the repository (i.e. it's in `api/.gitignor only pass signature validation against the same pair of keys it was signed with. This is especially relevant in a production environment, where you don't want to accidentally invalidate all your clients' tokens at every deployment. -For more information, refer to [the bundle's documentation](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/index.md) +For more information, refer to [the bundle's documentation](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/2.x/Resources/doc/index.rst) or read a [general introduction to JWT here](https://jwt.io/introduction/). We're not done yet! Let's move on to configuring the Symfony SecurityBundle for JWT authentication. @@ -105,7 +105,7 @@ authentication_token: ``` If you want to avoid loading the `User` entity from database each time a JWT token needs to be authenticated, you may consider using -the [database-less user provider](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/8-jwt-user-provider.md) provided by LexikJWTAuthenticationBundle. However, it means you will have to fetch the `User` entity from the database yourself as needed (probably through the Doctrine EntityManager). +the [database-less user provider](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/2.x/Resources/doc/8-jwt-user-provider.rst) provided by LexikJWTAuthenticationBundle. However, it means you will have to fetch the `User` entity from the database yourself as needed (probably through the Doctrine EntityManager). Refer to the section on [Security](security.md) to learn how to control access to API resources and operations. You may also want to [configure Swagger UI for JWT authentication](#documenting-the-authentication-mechanism-with-swaggeropen-api). @@ -189,8 +189,8 @@ The "Authorize" button will automatically appear in Swagger UI. ### Adding a New API Key All you have to do is configure the API key in the `value` field. -By default, [only the authorization header mode is enabled](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/index.md#2-use-the-token) in LexikJWTAuthenticationBundle. -You must set the [JWT token](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/index.md#1-obtain-the-token) as below and click on the "Authorize" button. +By default, [only the authorization header mode is enabled](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/2.x/Resources/doc/index.rst#2-use-the-token) in LexikJWTAuthenticationBundle. +You must set the [JWT token](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/2.x/Resources/doc/index.rst#1-obtain-the-token) as below and click on the "Authorize" button. `Bearer MY_NEW_TOKEN` From 99dc4b0be430b6de935a061d42b978f8033fc666 Mon Sep 17 00:00:00 2001 From: mfe-a5sys <87469153+mfe-a5sys@users.noreply.github.com> Date: Fri, 26 Aug 2022 10:39:08 +0200 Subject: [PATCH 50/61] fix: add missing double quotes in GraphQL example (#1596) --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index 5bb5cb5d1f3..bc51d5b3766 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -503,7 +503,7 @@ Your custom mutations will be available like this: } mutation { - withCustomArgsMutationBook(input: {sendMail: true, clientMutationId: "myId}) { + withCustomArgsMutationBook(input: {sendMail: true, clientMutationId: "myId"}) { book { title } From 794ca9e11f8ce4a8fe6e09d9270ece6166ee4b33 Mon Sep 17 00:00:00 2001 From: Romain Herault Date: Mon, 16 Oct 2023 18:23:45 +0200 Subject: [PATCH 51/61] fix: missing paragraph close tag (#1813) --- core/extending-jsonld-context.md | 2 +- core/filters.md | 2 +- core/jwt.md | 4 ++++ core/security.md | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/extending-jsonld-context.md b/core/extending-jsonld-context.md index 80547eeb028..2ccf20c3685 100644 --- a/core/extending-jsonld-context.md +++ b/core/extending-jsonld-context.md @@ -2,7 +2,7 @@ ## JSON-LD -

JSON-LD screencast
Watch the JSON-LD screencast
+

JSON-LD screencast
Watch the JSON-LD screencast

API Platform Core provides the possibility to extend the JSON-LD context of properties. This allows you to describe JSON-LD-typed values, inverse properties using the `@reverse` keyword and you can even overwrite the `@id` property this way. Everything you define diff --git a/core/filters.md b/core/filters.md index 407e14c4add..5f37268c21b 100644 --- a/core/filters.md +++ b/core/filters.md @@ -12,7 +12,7 @@ By default, all filters are disabled. They must be enabled explicitly. When a filter is enabled, it automatically appears in the [OpenAPI](swagger.md) and [GraphQL](graphql.md) documentations. It is also automatically documented as a `hydra:search` property for JSON-LD responses. -

Filtering and Searching screencast
Watch the Filtering & Searching screencast
+

Filtering and Searching screencast
Watch the Filtering & Searching screencast

## Doctrine ORM and MongoDB ODM Filters diff --git a/core/jwt.md b/core/jwt.md index 30e17876041..787215373b3 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -12,10 +12,13 @@ API Platform allows to easily add a JWT-based authentication to your API using [ We begin by installing the bundle: +``` $ docker-compose exec php composer require jwt-auth +``` Then we need to generate the public and private keys used for signing JWT tokens. If you're using the [API Platform distribution](../distribution/index.md), you may run this from the project's root directory: +``` $ docker-compose exec php sh -c ' set -e apk add openssl @@ -26,6 +29,7 @@ Then we need to generate the public and private keys used for signing JWT tokens setfacl -R -m u:www-data:rX -m u:"$(whoami)":rwX config/jwt setfacl -dR -m u:www-data:rX -m u:"$(whoami)":rwX config/jwt ' +``` Note that the `setfacl` command relies on the `acl` package. This is installed by default when using the API Platform docker distribution but may need be installed in your working environment in order to execute the `setfacl` command. diff --git a/core/security.md b/core/security.md index c543fa62334..d59ad4d1714 100644 --- a/core/security.md +++ b/core/security.md @@ -4,7 +4,7 @@ The API Platform security layer is built on top of the [Symfony Security compone All its features, including [global access control directives](http://symfony.com/doc/current/book/security.html#securing-url-patterns-access-control) are supported. API Platform also provides convenient [access control expressions](https://symfony.com/doc/current/expressions.html#security-complex-access-controls-with-expressions) which you can apply at resource and operation level. -

Security screencast
Watch the Security screencast
+

Security screencast
Watch the Security screencast

[codeSelector] ```php From dd33139f45948619121531fd3332e205f8649355 Mon Sep 17 00:00:00 2001 From: Romain Herault Date: Mon, 16 Oct 2023 18:23:52 +0200 Subject: [PATCH 52/61] fix(kubernetes): missing code blocks (#1812) --- deployment/kubernetes.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 82a047b14c5..83d9d4a1e29 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -18,26 +18,33 @@ package manager) chart to deploy in a wink on any of these platforms. 1. Build the PHP and Nginx Docker images: +``` docker build -t gcr.io/test-api-platform/php -t gcr.io/test-api-platform/php:latest api docker build -t gcr.io/test-api-platform/nginx -t gcr.io/test-api-platform/nginx:latest -f api/Dockerfile.nginx api docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/varnish:latest -f api/Dockerfile.varnish api +``` 2. Push your images to your Docker registry, example with [Google Container Registry](https://cloud.google.com/container-registry/): +``` gcloud docker -- push gcr.io/test-api-platform/php gcloud docker -- push gcr.io/test-api-platform/nginx gcloud docker -- push gcr.io/test-api-platform/varnish +``` ## Deploying Firstly you need to update helm dependencies by running: +``` helm dependency update ./api/helm/api +``` You are now ready to deploy the API! Deploy your API to the container: +``` helm install ./api/helm/api --namespace=baz --name baz \ --set php.repository=gcr.io/test-api-platform/php \ --set nginx.repository=gcr.io/test-api-platform/nginx \ @@ -45,22 +52,27 @@ Deploy your API to the container: --set postgresql.postgresPassword=MyPgPassword \ --set postgresql.persistence.enabled=true \ --set corsAllowOrigin='^https?://[a-z\]*\.mywebsite.com$' +``` If you prefer to use a managed DBMS like [Heroku Postgres](https://www.heroku.com/postgres) or [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/) (recommended): +``` helm install --name api ./api/helm/api \ # ... --set postgresql.enabled=false \ --set postgresql.url=pgsql://username:password@host/database?serverVersion=9.6 +``` If you want to use a managed Varnish such as [Fastly](https://www.fastly.com) for the invalidation cache mechanism provided by API Platform: +``` helm install --name api ./api/helm/api \ # ... --set varnish.enabled=false \ --set varnish.url=https://myvarnish.com +``` Finally, build the `client` and `admin` JavaScript apps and [deploy them on a static website hosting service](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#deployment). @@ -69,5 +81,7 @@ website hosting service](https://github.com/facebookincubator/create-react-app/b Before running your application for the first time, be sure to create the database schema: +``` PHP_POD=$(kubectl --namespace=bar get pods -l app=php -o jsonpath="{.items[0].metadata.name}") kubectl --namespace=bar exec -it $PHP_POD -- bin/console doctrine:schema:create +``` \ No newline at end of file From a8ae4b4ecf793a3716e571f1c348d89d3316657f Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 19 Oct 2023 11:15:26 +0200 Subject: [PATCH 53/61] cs: add backticks --- deployment/kubernetes.md | 51 +++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 192ef45ca49..cdb7cd40acf 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -18,24 +18,30 @@ package manager) chart to deploy in a wink on any of these platforms. 1. Build the PHP and Nginx Docker images: - docker build -t gcr.io/test-api-platform/php -t gcr.io/test-api-platform/php:latest api --target api_platform_php - docker build -t gcr.io/test-api-platform/nginx -t gcr.io/test-api-platform/nginx:latest api --target api_platform_nginx - docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/varnish:latest api --target api_platform_varnish +``` +docker build -t gcr.io/test-api-platform/php -t gcr.io/test-api-platform/php:latest api --target api_platform_php +docker build -t gcr.io/test-api-platform/nginx -t gcr.io/test-api-platform/nginx:latest api --target api_platform_nginx +docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/varnish:latest api --target api_platform_varnish +``` 2. Push your images to your Docker registry, example with [Google Container Registry](https://cloud.google.com/container-registry/): - Docker client versions <= 18.03: - - gcloud docker -- push gcr.io/test-api-platform/php - gcloud docker -- push gcr.io/test-api-platform/nginx - gcloud docker -- push gcr.io/test-api-platform/varnish - - Docker client versions > 18.03: - - gcloud auth configure-docker - docker push gcr.io/test-api-platform/php - docker push gcr.io/test-api-platform/nginx - docker push gcr.io/test-api-platform/varnish +Docker client versions <= 18.03: + +``` +gcloud docker -- push gcr.io/test-api-platform/php +gcloud docker -- push gcr.io/test-api-platform/nginx +gcloud docker -- push gcr.io/test-api-platform/varnish +``` + +Docker client versions > 18.03: + +``` +gcloud auth configure-docker +docker push gcr.io/test-api-platform/php +docker push gcr.io/test-api-platform/nginx +docker push gcr.io/test-api-platform/varnish +``` ## Deploying @@ -89,19 +95,22 @@ Before running your application for the first time, be sure to create the databa ``` PHP_POD=$(kubectl --namespace=bar get pods -l app=php -o jsonpath="{.items[0].metadata.name}") kubectl --namespace=bar exec -it $PHP_POD -- bin/console doctrine:schema:create +``` ## Tiller RBAC Issue We noticed that some tiller RBAC trouble occurred, you generally can resolve it running: - kubectl create serviceaccount --namespace kube-system tiller - serviceaccount "tiller" created +``` +kubectl create serviceaccount --namespace kube-system tiller + serviceaccount "tiller" created - kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller - clusterrolebinding "tiller-cluster-rule" created +kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller + clusterrolebinding "tiller-cluster-rule" created - kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}' - deployment "tiller-deploy" patched +kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}' + deployment "tiller-deploy" patched +``` Please, see the [related issue](https://github.com/kubernetes/helm/issues/3130) for further details / informations You can also take a look to the [related documentation](https://github.com/kubernetes/helm/blob/master/docs/rbac.md) From 3339e2927068bd3a68d808099c251110bac1586c Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 19 Oct 2023 11:20:24 +0200 Subject: [PATCH 54/61] cs: add backticks --- deployment/kubernetes.md | 124 ++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 48 deletions(-) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 34ad2b79aef..ab86cc93964 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -29,29 +29,37 @@ Change the name "test-api-platform" to your Google project ID (not the project n [Quickstart Google Cloud](https://cloud.google.com/sdk/docs/quickstart?hl=de) If you do not have gcloud yet, install it with these command. - curl https://sdk.cloud.google.com | bash +``` +curl https://sdk.cloud.google.com | bash +``` #### 1. Build the PHP and Caddy Docker images and tag them Versioning: The 0.1.0 is the version. This value should be the same as the attribute `appVersion` in `Chart.yaml`. Infos for [Google Container pulling and pushing](https://cloud.google.com/container-registry/docs/pushing-and-pulling) - docker build -t gcr.io/test-api-platform/php:0.1.0 -t gcr.io/test-api-platform/php:latest api --target api_platform_php - docker build -t gcr.io/test-api-platform/caddy:0.1.0 -t gcr.io/test-api-platform/caddy:latest api --target api_platform_caddy - docker build -t gcr.io/test-api-platform/pwa:0.1.0 -t gcr.io/test-api-platform/pwa:latest pwa --target api_platform_pwa_prod +``` +docker build -t gcr.io/test-api-platform/php:0.1.0 -t gcr.io/test-api-platform/php:latest api --target api_platform_php +docker build -t gcr.io/test-api-platform/caddy:0.1.0 -t gcr.io/test-api-platform/caddy:latest api --target api_platform_caddy +docker build -t gcr.io/test-api-platform/pwa:0.1.0 -t gcr.io/test-api-platform/pwa:latest pwa --target api_platform_pwa_prod +``` #### 2. Push your images to your Docker registry - gcloud auth configure-docker - docker push gcr.io/test-api-platform/php - docker push gcr.io/test-api-platform/caddy - docker push gcr.io/test-api-platform/pwa +``` +gcloud auth configure-docker +docker push gcr.io/test-api-platform/php +docker push gcr.io/test-api-platform/caddy +docker push gcr.io/test-api-platform/pwa +``` Optional push the version images: - docker push gcr.io/test-api-platform/php:0.1.0 - docker push gcr.io/test-api-platform/caddy:0.1.0 - docker push gcr.io/test-api-platform/pwa:0.1.0 +``` +docker push gcr.io/test-api-platform/php:0.1.0 +docker push gcr.io/test-api-platform/caddy:0.1.0 +docker push gcr.io/test-api-platform/pwa:0.1.0 +``` The result should look similar to these images. @@ -62,35 +70,43 @@ The result should look similar to these images. ### 1. Check the Helm version - helm version +``` +helm version +``` If you are using version 2.x follow this [guide to migrate Helm to v3](https://helm.sh/docs/topics/v2_v3_migration/#helm) ### 2. Firstly you need to update helm dependencies by running - helm dependency update ./helm/api-platform +``` +helm dependency update ./helm/api-platform +``` This will create a folder helm/api-platform/charts/ and add all dependencies there. Actual this is [bitnami/postgresql](https://bitnami.com/stack/postgresql/helm), a file postgresql-[VERSION].tgz is created. ### 3. Optional: If you made changes to the Helm chart, check if its format is correct - helm lint ./helm/api-platform +``` +helm lint ./helm/api-platform +``` ### 4. Deploy your API to the container - helm upgrade main ./helm/api-platform --namespace=default --create-namespace --wait \ - --install \ - --set "php.image.repository=gcr.io/test-api-platform/php" \ - --set php.image.tag=latest \ - --set "caddy.image.repository=gcr.io/test-api-platform/caddy" \ - --set caddy.image.tag=latest \ - --set "pwa.image.repository=gcr.io/test-api-platform/pwa" \ - --set pwa.image.tag=latest \ - --set php.appSecret='!ChangeMe!' \ - --set postgresql.postgresqlPassword='!ChangeMe!' \ - --set postgresql.persistence.enabled=true \ - --set "corsAllowOrigin=^https?:\/\/[a-z]*\.mywebsite.com$" +``` +helm upgrade main ./helm/api-platform --namespace=default --create-namespace --wait \ + --install \ + --set "php.image.repository=gcr.io/test-api-platform/php" \ + --set php.image.tag=latest \ + --set "caddy.image.repository=gcr.io/test-api-platform/caddy" \ + --set caddy.image.tag=latest \ + --set "pwa.image.repository=gcr.io/test-api-platform/pwa" \ + --set pwa.image.tag=latest \ + --set php.appSecret='!ChangeMe!' \ + --set postgresql.postgresqlPassword='!ChangeMe!' \ + --set postgresql.persistence.enabled=true \ + --set "corsAllowOrigin=^https?:\/\/[a-z]*\.mywebsite.com$" +``` The `"` are necessary for Windows. Use ^ on Windows instead of \ to split commands into multiple lines. You can add the parameter `--dry-run` to check upfront if anything is correct. @@ -109,10 +125,12 @@ get access on your local machine to the deploy. See image below. If you prefer to use a managed DBMS like [Heroku Postgres](https://www.heroku.com/postgres) or [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/) (recommended): - helm upgrade api-platform ./helm/api-platform \ - # ... - --set postgresql.enabled=false \ - --set postgresql.url=pgsql://username:password@host/database?serverVersion=13 +``` +helm upgrade api-platform ./helm/api-platform \ + # ... + --set postgresql.enabled=false \ + --set postgresql.url=pgsql://username:password@host/database?serverVersion=13 +``` Finally, build the `pwa` (client and admin) JavaScript apps and [deploy them on a static site hosting service](https://create-react-app.dev/docs/deployment/). @@ -122,8 +140,10 @@ site hosting service](https://create-react-app.dev/docs/deployment/). You can access the php container of the pod with the following command. In this example the symfony console is called. - CADDY_PHP_POD=$(kubectl --namespace=default get pods -l app.kubernetes.io/name=api-platform -o jsonpath="{.items[0].metadata.name}") - kubectl --namespace=default exec -it $CADDY_PHP_POD -c api-platform-php -- bin/console +``` +CADDY_PHP_POD=$(kubectl --namespace=default get pods -l app.kubernetes.io/name=api-platform -o jsonpath="{.items[0].metadata.name}") +kubectl --namespace=default exec -it $CADDY_PHP_POD -c api-platform-php -- bin/console +``` ## Caution for system architecture @@ -148,7 +168,8 @@ You can upgrade with the same command from the installation and pass all paramet Infos about [best practices for tagging images for kubernetes](https://kubernetes.io/docs/concepts/containers/images/) You have to use the *.image.pullPolicy=Always see the last 3 parameters. - helm upgrade api-platform ./helm/api-platform --namespace=default \ +``` +helm upgrade api-platform ./helm/api-platform --namespace=default \ --set "php.image.repository=gcr.io/test-api-platform/php" \ --set php.image.tag=latest \ --set "caddy.image.repository=gcr.io/test-api-platform/caddy" \ @@ -162,6 +183,7 @@ You have to use the *.image.pullPolicy=Always see the last 3 parameters. --set php.image.pullPolicy=Always \ --set caddy.image.pullPolicy=Always \ --set pwa.image.pullPolicy=Always +``` ## GitHub Actions Example for deployment @@ -175,24 +197,30 @@ Start by creating a new template for the queue-worker-deployment. The `deploymen Add the following lines under `containers` to overwrite the command. - command: - {{ range .Values.queue_worker.command }} - - {{ . | quote }} - {{ end }} - args: - {{ range .Values.queue_worker.commandArgs }} - - {{ . | quote }} - {{ end }} +``` +command: +{{ range .Values.queue_worker.command }} + - {{ . | quote }} +{{ end }} +args: +{{ range .Values.queue_worker.commandArgs }} + - {{ . | quote }} +{{ end }} +``` Here is an example on how to use it from your `values.yaml`: - command: ['bin/console'] - commandArgs: ['messenger:consume', 'async', '--memory-limit=100M'] +``` +command: ['bin/console'] +commandArgs: ['messenger:consume', 'async', '--memory-limit=100M'] +``` The `readinessProbe` and the `livenessProble` can not use the default `docker-healthcheck` but should test if the command is running. - readinessProbe: - exec: - command: ["/bin/sh", "-c", "/bin/ps -ef | grep messenger:consume | grep -v grep"] - initialDelaySeconds: 120 - periodSeconds: 3 +``` +readinessProbe: + exec: + command: ["/bin/sh", "-c", "/bin/ps -ef | grep messenger:consume | grep -v grep"] + initialDelaySeconds: 120 + periodSeconds: 3 +``` From c6b87fc9d975a63d2994dfb2e75d876da3e4225a Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 19 Oct 2023 13:58:48 +0200 Subject: [PATCH 55/61] lint --- deployment/kubernetes.md | 62 ++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 83d9d4a1e29..da01f114c6b 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -18,60 +18,60 @@ package manager) chart to deploy in a wink on any of these platforms. 1. Build the PHP and Nginx Docker images: -``` - docker build -t gcr.io/test-api-platform/php -t gcr.io/test-api-platform/php:latest api - docker build -t gcr.io/test-api-platform/nginx -t gcr.io/test-api-platform/nginx:latest -f api/Dockerfile.nginx api - docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/varnish:latest -f api/Dockerfile.varnish api +```console +docker build -t gcr.io/test-api-platform/php -t gcr.io/test-api-platform/php:latest api +docker build -t gcr.io/test-api-platform/nginx -t gcr.io/test-api-platform/nginx:latest -f api/Dockerfile.nginx api +docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/varnish:latest -f api/Dockerfile.varnish api ``` 2. Push your images to your Docker registry, example with [Google Container Registry](https://cloud.google.com/container-registry/): -``` - gcloud docker -- push gcr.io/test-api-platform/php - gcloud docker -- push gcr.io/test-api-platform/nginx - gcloud docker -- push gcr.io/test-api-platform/varnish +```console +gcloud docker -- push gcr.io/test-api-platform/php +gcloud docker -- push gcr.io/test-api-platform/nginx +gcloud docker -- push gcr.io/test-api-platform/varnish ``` ## Deploying Firstly you need to update helm dependencies by running: -``` - helm dependency update ./api/helm/api +```console +helm dependency update ./api/helm/api ``` You are now ready to deploy the API! Deploy your API to the container: -``` - helm install ./api/helm/api --namespace=baz --name baz \ - --set php.repository=gcr.io/test-api-platform/php \ - --set nginx.repository=gcr.io/test-api-platform/nginx \ - --set secret=MyAppSecretKey \ - --set postgresql.postgresPassword=MyPgPassword \ - --set postgresql.persistence.enabled=true \ - --set corsAllowOrigin='^https?://[a-z\]*\.mywebsite.com$' +```console +helm install ./api/helm/api --namespace=baz --name baz \ + --set php.repository=gcr.io/test-api-platform/php \ + --set nginx.repository=gcr.io/test-api-platform/nginx \ + --set secret=MyAppSecretKey \ + --set postgresql.postgresPassword=MyPgPassword \ + --set postgresql.persistence.enabled=true \ + --set corsAllowOrigin='^https?://[a-z\]*\.mywebsite.com$' ``` If you prefer to use a managed DBMS like [Heroku Postgres](https://www.heroku.com/postgres) or [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/) (recommended): -``` - helm install --name api ./api/helm/api \ - # ... - --set postgresql.enabled=false \ - --set postgresql.url=pgsql://username:password@host/database?serverVersion=9.6 +```console +helm install --name api ./api/helm/api \ + # ... + --set postgresql.enabled=false \ + --set postgresql.url=pgsql://username:password@host/database?serverVersion=9.6 ``` If you want to use a managed Varnish such as [Fastly](https://www.fastly.com) for the invalidation cache mechanism provided by API Platform: -``` - helm install --name api ./api/helm/api \ - # ... - --set varnish.enabled=false \ - --set varnish.url=https://myvarnish.com +```console +helm install --name api ./api/helm/api \ + # ... + --set varnish.enabled=false \ + --set varnish.url=https://myvarnish.com ``` Finally, build the `client` and `admin` JavaScript apps and [deploy them on a static @@ -81,7 +81,7 @@ website hosting service](https://github.com/facebookincubator/create-react-app/b Before running your application for the first time, be sure to create the database schema: +```console +PHP_POD=$(kubectl --namespace=bar get pods -l app=php -o jsonpath="{.items[0].metadata.name}") +kubectl --namespace=bar exec -it $PHP_POD -- bin/console doctrine:schema:create ``` - PHP_POD=$(kubectl --namespace=bar get pods -l app=php -o jsonpath="{.items[0].metadata.name}") - kubectl --namespace=bar exec -it $PHP_POD -- bin/console doctrine:schema:create -``` \ No newline at end of file From 28166d1417ed409bf0f1c54366dd99f7280bcf3e Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 19 Oct 2023 14:00:40 +0200 Subject: [PATCH 56/61] lint --- deployment/kubernetes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index dccfc3d1380..6ef46342538 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -18,7 +18,7 @@ package manager) chart to deploy in a wink on any of these platforms. 1. Build the PHP and Nginx Docker images: -``` +```console docker build -t gcr.io/test-api-platform/php -t gcr.io/test-api-platform/php:latest api --target api_platform_php docker build -t gcr.io/test-api-platform/nginx -t gcr.io/test-api-platform/nginx:latest api --target api_platform_nginx docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/varnish:latest api --target api_platform_varnish @@ -28,7 +28,7 @@ docker build -t gcr.io/test-api-platform/varnish -t gcr.io/test-api-platform/var Docker client versions <= 18.03: -``` +```console gcloud docker -- push gcr.io/test-api-platform/php gcloud docker -- push gcr.io/test-api-platform/nginx gcloud docker -- push gcr.io/test-api-platform/varnish @@ -36,7 +36,7 @@ gcloud docker -- push gcr.io/test-api-platform/varnish Docker client versions > 18.03: -``` +```console gcloud auth configure-docker docker push gcr.io/test-api-platform/php docker push gcr.io/test-api-platform/nginx @@ -104,7 +104,7 @@ kubectl --namespace=bar exec -it $PHP_POD -- bin/console doctrine:schema:create We noticed that some tiller RBAC trouble occurred, you generally can resolve it running: -``` +```console kubectl create serviceaccount --namespace kube-system tiller serviceaccount "tiller" created From e8b998ea1f0ffeef5349962c00e4dd7abb97dca7 Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 19 Oct 2023 14:06:15 +0200 Subject: [PATCH 57/61] lint --- deployment/kubernetes.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 9b7a671990e..2c7a2f68176 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -29,7 +29,7 @@ Change the name "test-api-platform" to your Google project ID (not the project n [Quickstart Google Cloud](https://cloud.google.com/sdk/docs/quickstart?hl=de) If you do not have gcloud yet, install it with these command. -``` +```console curl https://sdk.cloud.google.com | bash ``` @@ -38,7 +38,7 @@ curl https://sdk.cloud.google.com | bash Versioning: The 0.1.0 is the version. This value should be the same as the attribute `appVersion` in `Chart.yaml`. Infos for [Google Container pulling and pushing](https://cloud.google.com/container-registry/docs/pushing-and-pulling) -``` +```console docker build -t gcr.io/test-api-platform/php:0.1.0 -t gcr.io/test-api-platform/php:latest api --target api_platform_php docker build -t gcr.io/test-api-platform/caddy:0.1.0 -t gcr.io/test-api-platform/caddy:latest api --target api_platform_caddy docker build -t gcr.io/test-api-platform/pwa:0.1.0 -t gcr.io/test-api-platform/pwa:latest pwa --target api_platform_pwa_prod @@ -55,7 +55,7 @@ docker push gcr.io/test-api-platform/pwa Optional push the version images: -``` +```console docker push gcr.io/test-api-platform/php:0.1.0 docker push gcr.io/test-api-platform/caddy:0.1.0 docker push gcr.io/test-api-platform/pwa:0.1.0 @@ -70,7 +70,7 @@ The result should look similar to these images. ### 1. Check the Helm version -``` +```console helm version ``` @@ -78,7 +78,7 @@ If you are using version 2.x follow this [guide to migrate Helm to v3](https://h ### 2. Firstly you need to update helm dependencies by running -``` +```console helm dependency update ./helm/api-platform ``` @@ -87,13 +87,13 @@ Actual this is [bitnami/postgresql](https://bitnami.com/stack/postgresql/helm), ### 3. Optional: If you made changes to the Helm chart, check if its format is correct -``` +```console helm lint ./helm/api-platform ``` ### 4. Deploy your API to the container -``` +```console helm upgrade main ./helm/api-platform --namespace=default --create-namespace --wait \ --install \ --set "php.image.repository=gcr.io/test-api-platform/php" \ @@ -125,7 +125,7 @@ get access on your local machine to the deploy. See image below. If you prefer to use a managed DBMS like [Heroku Postgres](https://www.heroku.com/postgres) or [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/) (recommended): -``` +```console helm upgrade api-platform ./helm/api-platform \ # ... --set postgresql.enabled=false \ @@ -140,7 +140,7 @@ site hosting service](https://create-react-app.dev/docs/deployment/). You can access the php container of the pod with the following command. In this example the symfony console is called. -``` +```console CADDY_PHP_POD=$(kubectl --namespace=default get pods -l app.kubernetes.io/name=api-platform -o jsonpath="{.items[0].metadata.name}") kubectl --namespace=default exec -it $CADDY_PHP_POD -c api-platform-php -- bin/console ``` @@ -171,7 +171,6 @@ You have to use the *.image.pullPolicy=Always see the last 3 parameters. ```console PHP_POD=$(kubectl --namespace=bar get pods -l app=php -o jsonpath="{.items[0].metadata.name}") kubectl --namespace=bar exec -it $PHP_POD -- bin/console doctrine:schema:create -``` helm upgrade api-platform ./helm/api-platform --namespace=default \ --set "php.image.repository=gcr.io/test-api-platform/php" \ --set php.image.tag=latest \ @@ -200,7 +199,7 @@ Start by creating a new template for the queue-worker-deployment. The `deploymen Add the following lines under `containers` to overwrite the command. -``` +```yaml command: {{ range .Values.queue_worker.command }} - {{ . | quote }} @@ -213,14 +212,14 @@ args: Here is an example on how to use it from your `values.yaml`: -``` +```yaml command: ['bin/console'] commandArgs: ['messenger:consume', 'async', '--memory-limit=100M'] ``` The `readinessProbe` and the `livenessProble` can not use the default `docker-healthcheck` but should test if the command is running. -``` +```yaml readinessProbe: exec: command: ["/bin/sh", "-c", "/bin/ps -ef | grep messenger:consume | grep -v grep"] From f386b50f66f307be85bcc99151baa09226f972d9 Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 19 Oct 2023 15:13:22 +0200 Subject: [PATCH 58/61] mdx fixes --- core/mercure.md | 2 +- deployment/kubernetes.md | 2 +- deployment/traefik.md | 2 +- extra/contribution-guides.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/mercure.md b/core/mercure.md index 3cda83f2927..1238a64c5eb 100644 --- a/core/mercure.md +++ b/core/mercure.md @@ -4,7 +4,7 @@ API Platform can automatically push the modified version of the resources expose > *Mercure* is a protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast, reliable and battery-efficient way. It is especially useful to publish real-time updates of resources served through web APIs, to reactive web and mobile apps. > -> — +> —[https://mercure.rocks](https://mercure.rocks) API Platform detects changes made to your Doctrine entities, and sends the updated resources to the Mercure hub. Then, the Mercure hub dispatches the updates to all connected clients using [Server-sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). diff --git a/deployment/kubernetes.md b/deployment/kubernetes.md index 2c7a2f68176..31fca52dd2a 100644 --- a/deployment/kubernetes.md +++ b/deployment/kubernetes.md @@ -152,7 +152,7 @@ there is probably a problem with the system architecture. `standard_init_linux.go:211: exec user process caused "exec format error` Build the images with the same system architecture as the cluster runs. Example: Building with Mac M1 with arm64 leads to problems. Most cluster will run with x86_64. -Solution: +Solution: [https://blog.jaimyn.dev/how-to-build-multi-architecture-docker-images-on-an-m1-mac](https://blog.jaimyn.dev/how-to-build-multi-architecture-docker-images-on-an-m1-mac) ## Updates diff --git a/deployment/traefik.md b/deployment/traefik.md index 18d5df85f12..f7f625fe3a4 100644 --- a/deployment/traefik.md +++ b/deployment/traefik.md @@ -2,7 +2,7 @@ > An open-source reverse proxy and load balancer for HTTP and TCP-based applications that is easy, dynamic, automatic, fast, full-featured, production proven, provides metrics and integrates with every major cluster technology. > -> — +> —[https://traefik.io](https://traefik.io) ## Basic Implementation diff --git a/extra/contribution-guides.md b/extra/contribution-guides.md index 951fe0e510b..ed84b118074 100644 --- a/extra/contribution-guides.md +++ b/extra/contribution-guides.md @@ -7,4 +7,4 @@ **To report a security issue, please refer to [the dedicated document](security.md).** -

JWT screencast
Watch the Contributing back to Symfony screencast (free-

+

JWT screencast
Watch the Contributing back to Symfony screencast (free)

From bec51871c59b41e27149670082423aefa9713b1a Mon Sep 17 00:00:00 2001 From: soyuka Date: Fri, 24 Nov 2023 10:18:05 +0100 Subject: [PATCH 59/61] fix: symfony cast image url --- core/content-negotiation.md | 2 +- core/data-persisters.md | 4 ++-- core/extending-jsonld-context.md | 4 ++-- core/extending.md | 2 +- core/filters.md | 2 +- core/fosuser-bundle.md | 2 +- core/getting-started.md | 2 +- core/index.md | 2 +- core/jwt.md | 2 +- core/openapi.md | 2 +- core/operations.md | 2 +- core/pagination.md | 2 +- core/security.md | 2 +- core/serialization.md | 8 ++++---- core/subresources.md | 2 +- core/testing.md | 2 +- core/validation.md | 2 +- deployment/index.md | 2 +- distribution/debugging.md | 2 +- distribution/index.md | 2 +- distribution/testing.md | 2 +- extra/contribution-guides.md | 2 +- 22 files changed, 27 insertions(+), 27 deletions(-) diff --git a/core/content-negotiation.md b/core/content-negotiation.md index 0c74118b166..e505b0b0960 100644 --- a/core/content-negotiation.md +++ b/core/content-negotiation.md @@ -9,7 +9,7 @@ Using the raw JSON or raw XML formats is discouraged, prefer using JSON-LD inste API Platform also supports [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) the JSON:API [`PATCH`](https://tools.ietf.org/html/rfc5789) formats, as well as [Problem Details (RFC 7807)](https://tools.ietf.org/html/rfc7807), Hydra and JSON:API error formats. -

Formats screencast
Watch the Formats screencast

+

Formats screencast
Watch the Formats screencast

API Platform Core will automatically detect the best resolving format depending on: diff --git a/core/data-persisters.md b/core/data-persisters.md index 0cb61ae9011..b46b1c9705b 100644 --- a/core/data-persisters.md +++ b/core/data-persisters.md @@ -5,7 +5,7 @@ classes called **data persisters**. Data persisters receive an instance of the c the `#[ApiResource]` attribute). This instance contains data submitted by the client during [the deserialization process](serialization.md). -

Data Persister screencast
Watch the Data Persister screencast

+

Data Persister screencast
Watch the Data Persister screencast

A data persister using [Doctrine ORM](https://www.doctrine-project.org/projects/orm.html) is included with the library and is enabled by default. It is able to persist and delete objects that are also mapped as [Doctrine entities](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/basic-mapping.html). @@ -75,7 +75,7 @@ Note that if you don't need any `$context` in your data persister's methods, you ## Decorating the Built-In Data Persisters -

Data Persister Decoration screencast
Watch the Data Persister Decoration screencast

+

Data Persister Decoration screencast
Watch the Data Persister Decoration screencast

If you want to execute custom business logic before or after persistence, this can be achieved by [decorating](https://symfony.com/doc/current/service_container/service_decoration.html) the built-in data persisters. diff --git a/core/extending-jsonld-context.md b/core/extending-jsonld-context.md index 023b4920509..d6d56a967c0 100644 --- a/core/extending-jsonld-context.md +++ b/core/extending-jsonld-context.md @@ -2,7 +2,7 @@ ## JSON-LD -

JSON-LD screencast
Watch the JSON-LD screencast

+

JSON-LD screencast
Watch the JSON-LD screencast

API Platform Core provides the possibility to extend the JSON-LD context of properties. This allows you to describe JSON-LD-typed values, inverse properties using the `@reverse` keyword and you can even overwrite the `@id` property this way. Everything you define @@ -66,7 +66,7 @@ Note that you do not have to provide the `@id` attribute. If you do not provide ## Hydra -

Hydra screencast
Watch the Hydra screencast

+

Hydra screencast
Watch the Hydra screencast

It's also possible to replace the Hydra context used by the documentation generator: diff --git a/core/extending.md b/core/extending.md index 84450d8aaa8..745df61bbde 100644 --- a/core/extending.md +++ b/core/extending.md @@ -35,4 +35,4 @@ For instance, if you want to send a mail after a resource has been persisted, bu To replace existing API Platform services with your decorators, [check out how to decorate services](https://symfony.com/doc/current/service_container/service_decoration.html). -

Service Decoration screencast
Watch the Service Decoration screencast

+

Service Decoration screencast
Watch the Service Decoration screencast

diff --git a/core/filters.md b/core/filters.md index 3198d11c2d8..1cc31e986fb 100644 --- a/core/filters.md +++ b/core/filters.md @@ -12,7 +12,7 @@ By default, all filters are disabled. They must be enabled explicitly. When a filter is enabled, it automatically appears in the [OpenAPI](swagger.md) and [GraphQL](graphql.md) documentations. It is also automatically documented as a `hydra:search` property for JSON-LD responses. -

Filtering and Searching screencast
Watch the Filtering & Searching screencast

+

Filtering and Searching screencast
Watch the Filtering & Searching screencast

## Doctrine ORM and MongoDB ODM Filters diff --git a/core/fosuser-bundle.md b/core/fosuser-bundle.md index a518b84adb8..4bead8cee94 100644 --- a/core/fosuser-bundle.md +++ b/core/fosuser-bundle.md @@ -9,7 +9,7 @@ instead of using this bundle. API Platform Core is shipped with a bridge for [FOSUserBundle](https://github.com/FriendsOfSymfony/FOSUserBundle). If the FOSUser bundle is enabled, this bridge will use its `UserManager` to create, update and delete user resources. -

User Entity screencast
Watch the User Entity screencast

+

User Entity screencast
Watch the User Entity screencast

## Installing the Bundle diff --git a/core/getting-started.md b/core/getting-started.md index 719a016a4a3..0bac68320ec 100644 --- a/core/getting-started.md +++ b/core/getting-started.md @@ -28,7 +28,7 @@ and what [JSON-LD](http://json-ld.org/) and [Hydra](http://www.hydra-cg.com/) fo ## Mapping the Entities -

Create an API Resource screencast
Watch the Create an API Resource screencast

+

Create an API Resource screencast
Watch the Create an API Resource screencast

API Platform Core is able to automatically expose entities mapped as "API resources" through a REST API supporting CRUD operations. diff --git a/core/index.md b/core/index.md index 260a3facb0b..ca71f7a02bf 100644 --- a/core/index.md +++ b/core/index.md @@ -42,6 +42,6 @@ This bundle is extensively tested (unit and functional). The [`Fixtures/` direct ## Screencasts -

SymfonyCasts, API Platform screencasts

+

SymfonyCasts, API Platform screencasts

The easiest and funniest way to learn how to use API Platform is to watch [the more than 60 screencasts available on SymfonyCasts](https://symfonycasts.com/tracks/rest?cid=apip#api-platform)! diff --git a/core/jwt.md b/core/jwt.md index 2ebeb678f3a..87b20607ed7 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -7,7 +7,7 @@ The tokens are signed by the server's key, so the server is able to verify that API Platform allows to easily add a JWT-based authentication to your API using [LexikJWTAuthenticationBundle](https://github.com/lexik/LexikJWTAuthenticationBundle). -

JWT screencast
Watch the LexikJWTAuthenticationBundle screencast

+

JWT screencast
Watch the LexikJWTAuthenticationBundle screencast

## Installing LexikJWTAuthenticationBundle diff --git a/core/openapi.md b/core/openapi.md index fa3467ecbba..b4979420df1 100644 --- a/core/openapi.md +++ b/core/openapi.md @@ -4,7 +4,7 @@ API Platform natively support the [OpenAPI](https://www.openapis.org/) API speci ![Screenshot](../distribution/images/swagger-ui-1.png) -

OpenAPI screencast
Watch the OpenAPI screencast

+

OpenAPI screencast
Watch the OpenAPI screencast

The specification of the API is available at the `/docs.json` path. By default, OpenAPI v3 is used. diff --git a/core/operations.md b/core/operations.md index 2c11a7fae0d..a044c33b5af 100644 --- a/core/operations.md +++ b/core/operations.md @@ -3,7 +3,7 @@ API Platform Core relies on the concept of operations. Operations can be applied to a resource exposed by the API. From an implementation point of view, an operation is a link between a resource, a route and its related controller. -

Operations screencast
Watch the Operations screencast

+

Operations screencast
Watch the Operations screencast

API Platform automatically registers typical [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations and describes them in the exposed documentation (Hydra and Swagger). It also creates and registers routes corresponding diff --git a/core/pagination.md b/core/pagination.md index 4dba8e2a4bf..8b1d2a1b258 100644 --- a/core/pagination.md +++ b/core/pagination.md @@ -1,6 +1,6 @@ # Pagination -

Pagination screencast
Watch the Pagination screencast

+

Pagination screencast
Watch the Pagination screencast

API Platform Core has native support for paged collections. Pagination is enabled by default for all collections. Each collection contains 30 items per page. diff --git a/core/security.md b/core/security.md index c73c41be7f1..5632de660bd 100644 --- a/core/security.md +++ b/core/security.md @@ -4,7 +4,7 @@ The API Platform security layer is built on top of the [Symfony Security compone All its features, including [global access control directives](http://symfony.com/doc/current/book/security.html#securing-url-patterns-access-control) are supported. API Platform also provides convenient [access control expressions](https://symfony.com/doc/current/expressions.html#security-complex-access-controls-with-expressions) which you can apply at resource and operation level. -

Security screencast
Watch the Security screencast

+

Security screencast
Watch the Security screencast

[codeSelector] diff --git a/core/serialization.md b/core/serialization.md index 61ed52fe4a0..974f6a55df0 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -4,7 +4,7 @@ API Platform embraces and extends the Symfony Serializer Component to transform PHP entities in (hypermedia) API responses. -

Serializer screencast
Watch the Serializer screencast

+

Serializer screencast
Watch the Serializer screencast

The main serialization process has two stages: @@ -32,7 +32,7 @@ JSON-LD, or JavaScript Object Notation for Linked Data, is a method of encoding ## The Serialization Context, Groups and Relations -

Serialization Groups screencast
Watch the Serialization Groups screencast

+

Serialization Groups screencast
Watch the Serialization Groups screencast

API Platform allows you to specify the `$context` variable used by the Symfony Serializer. This variable is an associative array that has a handy `groups` key allowing you to choose which attributes of the resource are exposed during the normalization (read) and denormalization (write) processes. It relies on the [serialization (and deserialization) groups](https://symfony.com/doc/current/components/serializer.html#attributes-groups) @@ -221,7 +221,7 @@ Refer to the [operations](operations.md) documentation to learn more. ## Embedding Relations -

Relations screencast
Watch the Relations screencast

+

Relations screencast
Watch the Relations screencast

By default, the serializer provided with API Platform represents relations between objects using [dereferenceable IRIs](https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier). They allow you to retrieve details for related objects by issuing extra HTTP requests. However, for performance reasons, it is sometimes preferable to avoid forcing the client to issue extra HTTP requests. @@ -671,7 +671,7 @@ App\Entity\Greeting: ## Changing the Serialization Context Dynamically -

Context Builder & Service Decoration screencast
Watch the Context Builder & Service Decoration screencast

+

Context Builder & Service Decoration screencast
Watch the Context Builder & Service Decoration screencast

Let's imagine a resource where most fields can be managed by any user, but some can be managed only by admin users: diff --git a/core/subresources.md b/core/subresources.md index 9a98c384aa1..970f10922c1 100644 --- a/core/subresources.md +++ b/core/subresources.md @@ -3,7 +3,7 @@ A subresource is a collection or an item that belongs to another resource. API Platform makes it easy to create such operations. -

Subresources screencast
Watch the Subresources screencast

+

Subresources screencast
Watch the Subresources screencast

The starting point of a subresource must be a relation on an existing resource. For example, let's create two entities (Question, Answer) and set up a subresource so that `/question/42/answer` gives us diff --git a/core/testing.md b/core/testing.md index a5234fe88f8..80aea918ff0 100644 --- a/core/testing.md +++ b/core/testing.md @@ -3,7 +3,7 @@ API Platform Core provides a set of useful utilities dedicated to API testing. For an overview of how to test an API Platform app, be sure to read [the testing cookbook first](../distribution/testing.md). -

Test and Assertions screencast
Watch the API Tests & Assertions screencast

+

Test and Assertions screencast
Watch the API Tests & Assertions screencast

## The Test HttpClient diff --git a/core/validation.md b/core/validation.md index 73c9301b5ee..087d31a079a 100644 --- a/core/validation.md +++ b/core/validation.md @@ -4,7 +4,7 @@ API Platform takes care of validating the data sent to the API by the client (us By default, the framework relies on [the powerful Symfony Validator Component](http://symfony.com/doc/current/validation.html) for this task, but you can replace it with your preferred validation library such as [the PHP filter extension](https://www.php.net/manual/en/intro.filter.php) if you want to. -

Validation screencast
Watch the Validation screencast

+

Validation screencast
Watch the Validation screencast

## Validating Submitted Data diff --git a/deployment/index.md b/deployment/index.md index cac63909614..b8dc3b07f48 100644 --- a/deployment/index.md +++ b/deployment/index.md @@ -9,7 +9,7 @@ If you want to play with a local Kubernetes cluster, read [how to deploy an API If you don't want to use Docker, keep in mind that the server application of API Platform is a standard Symfony project, while the Progressive Web Application is a standard Next.js project: -

JWT screencast
Watch the Animated Deployment with Ansistrano screencast

+

JWT screencast
Watch the Animated Deployment with Ansistrano screencast

* [Deploying the Symfony application](https://symfony.com/doc/current/deployment.html) * [Deploying the Next.js application](https://nextjs.org/docs/deployment) diff --git a/distribution/debugging.md b/distribution/debugging.md index ee887d30932..6f3bc63b1ab 100644 --- a/distribution/debugging.md +++ b/distribution/debugging.md @@ -1,6 +1,6 @@ # Debugging -

API Platform debugging screencast
Watch the Debugging API Platform screencast

+

API Platform debugging screencast
Watch the Debugging API Platform screencast

## Xdebug diff --git a/distribution/index.md b/distribution/index.md index d81eab290e1..5d05fe5df11 100644 --- a/distribution/index.md +++ b/distribution/index.md @@ -795,6 +795,6 @@ and [browse it online](https://demo.api-platform.com). ## Screencasts -

SymfonyCasts, API Platform screencasts

+

SymfonyCasts, API Platform screencasts

The easiest and funniest way to learn how to use API Platform is to watch [the more than 60 screencasts available on SymfonyCasts](https://symfonycasts.com/tracks/rest?cid=apip#api-platform)! diff --git a/distribution/testing.md b/distribution/testing.md index df745cf77a1..a67cb6cdbd4 100644 --- a/distribution/testing.md +++ b/distribution/testing.md @@ -7,7 +7,7 @@ API Platform provides a set of helpful testing utilities to write unit tests, fu Let's learn how to use them! -

Tests and Assertions screencast
Watch the Tests & Assertions screencast

+

Tests and Assertions screencast
Watch the Tests & Assertions screencast

In this article you'll learn how to use: diff --git a/extra/contribution-guides.md b/extra/contribution-guides.md index ed84b118074..a3b4af1d9a2 100644 --- a/extra/contribution-guides.md +++ b/extra/contribution-guides.md @@ -7,4 +7,4 @@ **To report a security issue, please refer to [the dedicated document](security.md).** -

JWT screencast
Watch the Contributing back to Symfony screencast (free)

+

JWT screencast
Watch the Contributing back to Symfony screencast (free)

From bc6bbab6d911a3b3ce1e152fe1715dbf1ba72664 Mon Sep 17 00:00:00 2001 From: soyuka Date: Mon, 18 Dec 2023 21:48:16 +0100 Subject: [PATCH 60/61] fix: use html for code-selector --- core/content-negotiation.md | 4 +-- core/controllers.md | 16 ++++----- core/data-providers.md | 4 +-- core/default-order.md | 16 ++++----- core/deprecations.md | 4 +-- core/dto.md | 8 ++--- core/extending-jsonld-context.md | 4 +-- core/filters.md | 60 ++++++++++++++++---------------- core/getting-started.md | 4 +-- core/graphql.md | 4 +-- core/identifiers.md | 8 ++--- core/messenger.md | 4 +-- core/openapi.md | 8 ++--- core/operations.md | 24 ++++++------- core/security.md | 20 +++++------ core/serialization.md | 40 ++++++++++----------- core/subresources.md | 8 ++--- core/url-generation-strategy.md | 4 +-- 18 files changed, 120 insertions(+), 120 deletions(-) diff --git a/core/content-negotiation.md b/core/content-negotiation.md index e505b0b0960..e17d732275b 100644 --- a/core/content-negotiation.md +++ b/core/content-negotiation.md @@ -122,7 +122,7 @@ this configuration might disable the `json` or the `html` on this resource for e You can specify different accepted formats at operation level too, it's especially convenient for to configure formats available for the `PATCH` method: -[codeSelector] + ```php ``` -[/codeSelector] + ## Supporting Custom Formats diff --git a/core/controllers.md b/core/controllers.md index 75620cbd237..93a73cd6b6f 100644 --- a/core/controllers.md +++ b/core/controllers.md @@ -82,7 +82,7 @@ the client. The routing has not been configured yet because we will add it at the resource configuration level: -[codeSelector] + ```php ``` -[/codeSelector] + It is mandatory to set the `method`, `path` and `controller` attributes. They allow API Platform to configure the routing path and the associated controller respectively. @@ -147,7 +147,7 @@ the associated controller respectively. You may want different serialization groups for your custom operations. Just configure the proper `normalization_context` and/or `denormalization_context` in your operation: -[codeSelector] + ```php ``` -[/codeSelector] + ## Retrieving the Entity If you want to bypass the automatic retrieval of the entity in your custom operation, you can set `"read"=false` in the operation attribute: -[codeSelector] + ```php ``` -[/codeSelector] + This way, it will skip the `ReadListener`. You can do the same for some other built-in listeners. See [Built-in Event Listeners](events.md#built-in-event-listeners) for more information. @@ -301,7 +301,7 @@ for `book_post_discontinuation` when neither `method` nor `route_name` attribute First, let's create your resource configuration: -[codeSelector] + ```php ``` -[/codeSelector] + API Platform will automatically map this `post_publication` operation to the route `book_post_publication`. Let's create a custom action and its related route using annotations: diff --git a/core/data-providers.md b/core/data-providers.md index bf08d623820..5377c0bc5d6 100644 --- a/core/data-providers.md +++ b/core/data-providers.md @@ -215,7 +215,7 @@ API Platform provides a few extensions that you can reuse in your custom DataPro Note that there are a few kinds of extensions which are detailed in [their own chapter of the documentation](extensions.md). Because extensions are tagged services, you can use the [injection of tagged services](https://symfony.com/blog/new-in-symfony-3-4-simpler-injection-of-tagged-services): -[codeSelector] + ```yaml services: @@ -232,7 +232,7 @@ services: ``` -[/codeSelector] + Your data provider will now have access to the core extensions, here is an example on how to use them: diff --git a/core/default-order.md b/core/default-order.md index b47a8c1cb8b..a5df6ad574a 100644 --- a/core/default-order.md +++ b/core/default-order.md @@ -5,7 +5,7 @@ API Platform Core provides an easy way to override the default order of items in By default, items in the collection are ordered in ascending (ASC) order by their resource identifier(s). If you want to customize this order, you must add an `order` attribute on your ApiResource annotation: -[codeSelector] + ```php This `order` attribute is used as an array: the key defines the order field, the values defines the direction. If you only specify the key, `ASC` direction will be used as default. For example, to order by `foo` & `bar`: -[codeSelector] + ```php It's also possible to configure the default order on an association property: -[codeSelector] + ```php Another possibility is to apply the default order for a specific collection operation, which will override the global default order configuration. -[codeSelector] + ```php #[ApiResource( @@ -161,4 +161,4 @@ App\Entity\Book: name: ASC ``` -[/codeSelector] + diff --git a/core/deprecations.md b/core/deprecations.md index da03d33e32d..92f7fe802cb 100644 --- a/core/deprecations.md +++ b/core/deprecations.md @@ -67,7 +67,7 @@ class Parchment It's also possible to deprecate a single property: -[codeSelector] + ```php * With JSON-lD / Hydra, [an `owl:deprecated` annotation property](https://www.w3.org/TR/owl2-syntax/#Annotation_Properties) will be added to the appropriate data structure * With Swagger / OpenAPI, [a `deprecated` property](https://swagger.io/docs/specification/2-0/paths-and-operations/) will be added diff --git a/core/dto.md b/core/dto.md index 739e1df9a58..504449365e8 100644 --- a/core/dto.md +++ b/core/dto.md @@ -9,7 +9,7 @@ However, it's sometimes useful to use a specific class to represent the input or For a given resource class, you may want to have a different representation of this class as input (write) or output (read). To do so, a resource can take an input and/or an output class: -[codeSelector] + ```php ``` -[/codeSelector] + The `input` attribute is used during [the deserialization process](serialization.md), when transforming the user-provided data to a resource instance. Similarly, the `output` attribute is used during [the serialization process](serialization.md). This class represents how the `Book` resource will be represented in the `Response`. @@ -357,7 +357,7 @@ will be skipped. If `output` is `false`, the serialization process will be skipp `input` and `output` attributes can be set on a per operation basis: -[codeSelector] + ```php ``` -[/codeSelector] + ## Input/Output Metadata diff --git a/core/extending-jsonld-context.md b/core/extending-jsonld-context.md index d6d56a967c0..41b944021ca 100644 --- a/core/extending-jsonld-context.md +++ b/core/extending-jsonld-context.md @@ -70,7 +70,7 @@ Note that you do not have to provide the `@id` attribute. If you do not provide It's also possible to replace the Hydra context used by the documentation generator: -[codeSelector] + ```php ``` -[/codeSelector] + diff --git a/core/filters.md b/core/filters.md index 1cc31e986fb..77aa1e6b60d 100644 --- a/core/filters.md +++ b/core/filters.md @@ -42,7 +42,7 @@ to a Resource in two ways: We're linking the filter `offer.date_filter` with the resource like this: - [codeSelector] + ```php ``` - [/codeSelector] + 2. By using the `#[ApiFilter]` attribute. @@ -145,7 +145,7 @@ Syntax: `?property[]=foo&property[]=bar` In the following example, we will see how to allow the filtering of a list of e-commerce offers: -[codeSelector] + ```php `http://localhost:8000/api/offers?price=10` will return all offers with a price being exactly `10`. `http://localhost:8000/api/offers?description=shirt` will return all offers with a description containing the word "shirt". @@ -195,7 +195,7 @@ Filters can be combined together: `http://localhost:8000/api/offers?price=10&des It is possible to filter on relations too, if `Offer` has a `Product` relation: -[codeSelector] + ```php With this service definition, it is possible to find all offers belonging to the product identified by a given IRI. Try the following: `http://localhost:8000/api/offers?product=/api/products/12`. @@ -256,7 +256,7 @@ The `after` and `before` filters will filter including the value whereas `strict Like others filters, the date filter must be explicitly enabled: -[codeSelector] + ```php Given that the collection endpoint is `/offers`, you can filter offers by date with the following query: `/offers?createdAt[after]=2018-03-19`. @@ -317,7 +317,7 @@ Always include items | `ApiPlatform\Core\Bridge\Doctrine\Orm\Fil For instance, exclude entries with a property value of `null` with the following service definition: -[codeSelector] + ```php ### Boolean Filter @@ -368,7 +368,7 @@ Syntax: `?property=` Enable the filter: -[codeSelector] + ```php Given that the collection endpoint is `/offers`, you can filter offers with the following query: `/offers?isAvailableGenericallyInMyCountry=true`. @@ -423,7 +423,7 @@ Syntax: `?property=` Enable the filter: -[codeSelector] + ```php Given that the collection endpoint is `/offers`, you can filter offers with the following query: `/offers?sold=1`. @@ -478,7 +478,7 @@ Syntax: `?property[]=value` Enable the filter: -[codeSelector] + ```php Given that the collection endpoint is `/offers`, you can filter the price with the following query: `/offers?price[between]=12.99..15.99`. @@ -538,7 +538,7 @@ Previous syntax (deprecated): `?property[exists]=` Enable the filter: -[codeSelector] + ```php Given that the collection endpoint is `/offers`, you can filter offers on nullable field with the following query: `/offers?exists[transportFees]=true`. @@ -605,7 +605,7 @@ Syntax: `?order[property]=` Enable the filter: -[codeSelector] + ```php Given that the collection endpoint is `/offers`, you can filter offers by name in ascending order and then by ID in descending order with the following query: `/offers?order[name]=desc&order[id]=asc`. @@ -656,7 +656,7 @@ order with the following query: `/offers?order[name]=desc&order[id]=asc`. By default, whenever the query does not specify the direction explicitly (e.g.: `/offers?order[name]&order[id]`), filters will not be applied unless you configure a default order direction to use: -[codeSelector] + ```php #### Comparing with Null Values @@ -712,7 +712,7 @@ Consider items as largest | `ApiPlatform\Core\Bridge\Doctrine\Orm\Fil For instance, treat entries with a property value of `null` as the smallest, with the following service definition: -[codeSelector] + ```php #### Using a Custom Order Query Parameter Name @@ -772,7 +772,7 @@ api_platform: Sometimes, you need to be able to perform filtering based on some linked resources (on the other side of a relation). All built-in filters support nested properties using the dot (`.`) syntax, e.g.: -[codeSelector] + ```php The above allows you to find offers by their respective product's color: `http://localhost:8000/api/offers?product.color=red`, or order offers by the product's release date: `http://localhost:8000/api/offers?order[product.releaseDate]=desc` @@ -835,7 +835,7 @@ As we have seen in previous examples, properties where filters can be applied mu care about security and performance (e.g. an API with restricted access), it is also possible to enable built-in filters for all properties: -[codeSelector] + ```php **Note: Filters on nested properties must still be enabled explicitly, in order to keep things sane.** @@ -902,7 +902,7 @@ Syntax: `?order[property]=` Enable the filter: -[codeSelector] + ```php Given that the collection endpoint is `/tweets`, you can filter tweets by id and date in ascending or descending order: `/tweets?order[id]=asc&order[date]=desc`. diff --git a/core/getting-started.md b/core/getting-started.md index 0bac68320ec..504f12d9e0d 100644 --- a/core/getting-started.md +++ b/core/getting-started.md @@ -166,7 +166,7 @@ It is also possible to override the naming convention using [operation path nami As an alternative to annotations, you can map entity classes using YAML or XML: -[codeSelector] + ```yaml # api/config/api_platform/resources.yaml @@ -198,7 +198,7 @@ resources: ``` -[/codeSelector] + If you prefer to use YAML or XML files instead of annotations, you must configure API Platform to load the appropriate files: diff --git a/core/graphql.md b/core/graphql.md index bc51d5b3766..1d93c98402b 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -1249,7 +1249,7 @@ final class ErrorHandler implements ErrorHandlerInterface Then register the service: -[codeSelector] + ```yaml # api/config/services.yaml @@ -1291,7 +1291,7 @@ return function(ContainerConfigurator $configurator) { }; ``` -[/codeSelector] + ### Formatting Exceptions and Errors diff --git a/core/identifiers.md b/core/identifiers.md index bbc7d82c156..27b8f7b52af 100644 --- a/core/identifiers.md +++ b/core/identifiers.md @@ -9,7 +9,7 @@ To help with your development experience, we introduced an identifier normalizat Let's say you have the following class, which is identified by a `UUID` type. In this example, `UUID` is not a simple string but an object with many attributes. -[codeSelector] + ```php ``` -[/codeSelector] + Once registered as an `ApiResource`, having an existing person, it will be accessible through the following URL: `/people/110e8400-e29b-11d4-a716-446655440000`. Note that the property identifying our resource is named `code`. @@ -123,7 +123,7 @@ final class UuidNormalizer implements DenormalizerInterface Tag this service as an `api_platform.identifier.denormalizer`: -[codeSelector] + ```yaml services: @@ -138,7 +138,7 @@ services: ``` -[/codeSelector] + Your `PersonDataProvider` will now work as expected! diff --git a/core/messenger.md b/core/messenger.md index 6c9e475ff5d..36460835882 100644 --- a/core/messenger.md +++ b/core/messenger.md @@ -20,7 +20,7 @@ docker-compose exec php \ Set the `messenger` attribute to `true`, and API Platform will automatically dispatch the API Resource instance as a message using the message bus provided by the Messenger Component. The following example allows you to create a new `Person` in an asynchronous manner: -[codeSelector] + ```php Because the `messenger` attribute is `true`, when a `POST` is handled by API Platform, the corresponding instance of the `Person` will be dispatched. diff --git a/core/openapi.md b/core/openapi.md index b4979420df1..3133b3d2a50 100644 --- a/core/openapi.md +++ b/core/openapi.md @@ -109,7 +109,7 @@ The impact on the swagger-ui is the following: Sometimes you may want to change the information included in your OpenAPI documentation. The following configuration will give you total control over your OpenAPI definitions: -[codeSelector] + ```php ``` -[/codeSelector] + This will produce the following Swagger documentation: @@ -293,7 +293,7 @@ class User You also have full control over both built-in and custom operations documentation. -[codeSelector] + ```php ``` -[/codeSelector] + ![Impact on Swagger UI](../distribution/images/swagger-ui-2.png) diff --git a/core/operations.md b/core/operations.md index a044c33b5af..2ae06575c8f 100644 --- a/core/operations.md +++ b/core/operations.md @@ -68,7 +68,7 @@ empty list of operations is provided, all operations are disabled. If the operation's name matches a supported HTTP methods (`GET`, `POST`, `PUT`, `PATCH` or `DELETE`), the corresponding `method` property will be automatically added. -[codeSelector] + ```php ``` -[/codeSelector] + The previous example can also be written with an explicit method definition: -[codeSelector] + ```php ``` -[/codeSelector] + API Platform Core is smart enough to automatically register the applicable Symfony route referencing a built-in CRUD action just by specifying the method name as key, or by checking the explicitly configured HTTP method. If you do not want to allow access to the resource item (i.e. you don't want a `GET` item operation), instead of omitting it altogether, you should instead declare a `GET` item operation which returns HTTP 404 (Not Found), so that the resource item can still be identified by an IRI. For example: -[codeSelector] + ```php ``` -[/codeSelector] + ## Configuring Operations @@ -255,7 +255,7 @@ The URL, the method and the default status code (among other options) can be con In the next example, both `GET` and `POST` operations are registered with custom URLs. Those will override the URLs generated by default. In addition to that, we require the `id` parameter in the URL of the `GET` operation to be an integer, and we configure the status code generated after successful `POST` request to be `301`: -[codeSelector] + ```php ``` -[/codeSelector] + In all these examples, the `method` attribute is omitted because it matches the operation name. When specifying sub options, you must always use snake case as demonstrated below with the `denormalization_context` option on the `put` operation: -[codeSelector] + ```php ``` -[/codeSelector] + ## Prefixing All Routes of All Operations @@ -440,7 +440,7 @@ Sometimes it's also useful to put a whole resource into its own "namespace" rega put everything that's related to a `Book` into the `library` so that URIs become `library/book/{id}`. In that case you don't need to override all the operations to set the path but configure the `route_prefix` attribute for the whole entity instead: -[codeSelector] + ```php ``` -[/codeSelector] + Alternatively, the more verbose attribute syntax can be used: `#[ApiResource(attributes: ["route_prefix" => "/library"])]`. diff --git a/core/security.md b/core/security.md index 5632de660bd..a09e8981226 100644 --- a/core/security.md +++ b/core/security.md @@ -6,7 +6,7 @@ API Platform also provides convenient [access control expressions](https://symfo

Security screencast
Watch the Security screencast

-[codeSelector] + ```php Resource signature can be modified at the property level as well: -[codeSelector] + ```php class Book @@ -91,7 +91,7 @@ App\Entity\Book: security: 'is_granted("ROLE_ADMIN")' ``` -[/codeSelector] + In this example: @@ -113,7 +113,7 @@ It means than for `PUT` or `PATCH` requests, `object` doesn't contain the value In some cases, it might be useful to execute a security after the denormalization step. To do so, use the `security_post_denormalize` attribute: -[codeSelector] + ```php This time, the `object` variable contains data that have been extracted from the HTTP request body during the denormalization process. However, the object is not persisted yet. @@ -164,7 +164,7 @@ In order to give the current `object` to your voter, use the expression `is_gran For example: -[codeSelector] + ```php Please note that if you use both `attributes={"security"="..` and then `"post" = { "security_post_denormalize" = "...`, the `security` on top level is called first, and after `security_post_denormalize`. This could lead to unwanted behaviour, so avoid using both of them simultaneously. If you need to use `security_post_denormalize`, consider adding `security` for the other operations instead of the global one. @@ -280,7 +280,7 @@ You can change it by configuring the `security_message` attribute or the `securi For example: -[codeSelector] + ```php ## Filtering Collection According to the Current User Permissions diff --git a/core/serialization.md b/core/serialization.md index 974f6a55df0..33df9fda592 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -74,7 +74,7 @@ It is simple to specify what groups to use in the API system: 1. Add the normalization context and denormalization context attributes to the resource, and specify which groups to use. Here you see that we add `read` and `write`, respectively. You can use any group names you wish. 2. Apply the groups to properties in the object. -[codeSelector] + ```php Alternatively, you can use the more verbose syntax: @@ -158,7 +158,7 @@ level ignored. In the following example we use different serialization groups for the `GET` and `PUT` operations: -[codeSelector] + ```php The `name` and `author` properties will be included in the document generated during a `GET` operation because the configuration defined at the resource level is inherited. However the document generated when a `PUT` request will be received will only @@ -247,7 +247,7 @@ response through the use of serialization groups. By using the following seriali a JSON representation of the author is embedded in the book response. As soon as any of the author's attributes is in the `book` group, the author will be embedded. -[codeSelector] + ```php -[codeSelector] + ```php The generated JSON using previous settings is below: @@ -347,7 +347,7 @@ Instead of embedding relations in the main HTTP response, you may want [to "push It is also possible to embed a relation in `PUT`, `PATCH` and `POST` requests. To enable that feature, set the serialization groups the same way as normalization. For example: -[codeSelector] + ```php The following rules apply when denormalizing embedded relations: @@ -386,7 +386,7 @@ You can specify as many embedded relation levels as you want. It is a common problem to have entities that reference other entities of the same type: -[codeSelector] + ```php The problem here is that the **$parent** property become automatically an embedded object. Besides, the property won't be shown on the OpenAPI view. To force the **$parent** property to be used as an IRI, add an **#[ApiProperty(readableLink: false, writableLink: false)]** annotation: -[codeSelector] + ```php ## Property Normalization Context @@ -602,7 +602,7 @@ class Book Sometimes you need to expose calculated fields. This can be done by leveraging the groups. This time not on a property, but on a method. -[codeSelector] + ```php ## Changing the Serialization Context Dynamically @@ -675,7 +675,7 @@ App\Entity\Greeting: Let's imagine a resource where most fields can be managed by any user, but some can be managed only by admin users: -[codeSelector] + ```php All entry points are the same for all users, so we should find a way to detect if the authenticated user is an admin, and if so dynamically add the `admin:input` value to deserialization groups in the `$context` array. @@ -1040,7 +1040,7 @@ an IRI. A client that uses JSON-LD must send a second HTTP request to retrieve i You can configure API Platform to embed the JSON-LD context in the root document by adding the `jsonld_embed_context` attribute to the `#[ApiResource]` annotation: -[codeSelector] + ```php The JSON output will now include the embedded context: diff --git a/core/subresources.md b/core/subresources.md index 970f10922c1..efda2a79359 100644 --- a/core/subresources.md +++ b/core/subresources.md @@ -9,7 +9,7 @@ The starting point of a subresource must be a relation on an existing resource. For example, let's create two entities (Question, Answer) and set up a subresource so that `/question/42/answer` gives us the answer to the question 42: -[codeSelector] + ```php Note that all we had to do is to set up `#[ApiSubresource]` on the `Question::answer` relation. Because the `answer` is a to-one relation, we know that this subresource is an item. Therefore the response will look like this: @@ -109,7 +109,7 @@ Note: only for `GET` operations are supported at the moment You may want custom groups on subresources, you can set `normalization_context` or `denormalization_context` on that operation. To do so, add a `subresourceOperations` node. For example: -[codeSelector] + ```php ``` -[/codeSelector] + In the previous examples, the `method` attribute is mandatory, because the operation name doesn't match a supported HTTP method. diff --git a/core/url-generation-strategy.md b/core/url-generation-strategy.md index 0e6b78b8ea8..fedb9780a97 100644 --- a/core/url-generation-strategy.md +++ b/core/url-generation-strategy.md @@ -33,7 +33,7 @@ api_platform: It can also be configured only for a specific resource: -[codeSelector] + ```php ``` -[/codeSelector] + For the above configuration, the collection will be like this: From f46ed0521c251e9ee8a0fc50bee3a156f0e9297c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20H=C3=A9bert?= Date: Tue, 24 Sep 2024 10:49:01 +0200 Subject: [PATCH 61/61] fix (images): Use relative links for the symfonycast player --- core/content-negotiation.md | 2 +- core/data-persisters.md | 4 ++-- core/extending-jsonld-context.md | 4 ++-- core/extending.md | 2 +- core/filters.md | 2 +- core/fosuser-bundle.md | 2 +- core/getting-started.md | 2 +- core/index.md | 2 +- core/jwt.md | 2 +- core/openapi.md | 2 +- core/operations.md | 2 +- core/pagination.md | 2 +- core/security.md | 2 +- core/serialization.md | 8 ++++---- core/subresources.md | 2 +- core/testing.md | 2 +- core/validation.md | 2 +- deployment/index.md | 2 +- distribution/debugging.md | 2 +- distribution/index.md | 2 +- distribution/testing.md | 2 +- extra/contribution-guides.md | 2 +- 22 files changed, 27 insertions(+), 27 deletions(-) diff --git a/core/content-negotiation.md b/core/content-negotiation.md index e17d732275b..8f6bc08fb85 100644 --- a/core/content-negotiation.md +++ b/core/content-negotiation.md @@ -9,7 +9,7 @@ Using the raw JSON or raw XML formats is discouraged, prefer using JSON-LD inste API Platform also supports [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) the JSON:API [`PATCH`](https://tools.ietf.org/html/rfc5789) formats, as well as [Problem Details (RFC 7807)](https://tools.ietf.org/html/rfc7807), Hydra and JSON:API error formats. -

Formats screencast
Watch the Formats screencast

+

Formats screencast
Watch the Formats screencast

API Platform Core will automatically detect the best resolving format depending on: diff --git a/core/data-persisters.md b/core/data-persisters.md index b46b1c9705b..0cb61ae9011 100644 --- a/core/data-persisters.md +++ b/core/data-persisters.md @@ -5,7 +5,7 @@ classes called **data persisters**. Data persisters receive an instance of the c the `#[ApiResource]` attribute). This instance contains data submitted by the client during [the deserialization process](serialization.md). -

Data Persister screencast
Watch the Data Persister screencast

+

Data Persister screencast
Watch the Data Persister screencast

A data persister using [Doctrine ORM](https://www.doctrine-project.org/projects/orm.html) is included with the library and is enabled by default. It is able to persist and delete objects that are also mapped as [Doctrine entities](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/basic-mapping.html). @@ -75,7 +75,7 @@ Note that if you don't need any `$context` in your data persister's methods, you ## Decorating the Built-In Data Persisters -

Data Persister Decoration screencast
Watch the Data Persister Decoration screencast

+

Data Persister Decoration screencast
Watch the Data Persister Decoration screencast

If you want to execute custom business logic before or after persistence, this can be achieved by [decorating](https://symfony.com/doc/current/service_container/service_decoration.html) the built-in data persisters. diff --git a/core/extending-jsonld-context.md b/core/extending-jsonld-context.md index 41b944021ca..74fb29fccaa 100644 --- a/core/extending-jsonld-context.md +++ b/core/extending-jsonld-context.md @@ -2,7 +2,7 @@ ## JSON-LD -

JSON-LD screencast
Watch the JSON-LD screencast

+

JSON-LD screencast
Watch the JSON-LD screencast

API Platform Core provides the possibility to extend the JSON-LD context of properties. This allows you to describe JSON-LD-typed values, inverse properties using the `@reverse` keyword and you can even overwrite the `@id` property this way. Everything you define @@ -66,7 +66,7 @@ Note that you do not have to provide the `@id` attribute. If you do not provide ## Hydra -

Hydra screencast
Watch the Hydra screencast

+

Hydra screencast
Watch the Hydra screencast

It's also possible to replace the Hydra context used by the documentation generator: diff --git a/core/extending.md b/core/extending.md index 745df61bbde..84450d8aaa8 100644 --- a/core/extending.md +++ b/core/extending.md @@ -35,4 +35,4 @@ For instance, if you want to send a mail after a resource has been persisted, bu To replace existing API Platform services with your decorators, [check out how to decorate services](https://symfony.com/doc/current/service_container/service_decoration.html). -

Service Decoration screencast
Watch the Service Decoration screencast

+

Service Decoration screencast
Watch the Service Decoration screencast

diff --git a/core/filters.md b/core/filters.md index 77aa1e6b60d..3f6d1397b4a 100644 --- a/core/filters.md +++ b/core/filters.md @@ -12,7 +12,7 @@ By default, all filters are disabled. They must be enabled explicitly. When a filter is enabled, it automatically appears in the [OpenAPI](swagger.md) and [GraphQL](graphql.md) documentations. It is also automatically documented as a `hydra:search` property for JSON-LD responses. -

Filtering and Searching screencast
Watch the Filtering & Searching screencast

+

Filtering and Searching screencast
Watch the Filtering & Searching screencast

## Doctrine ORM and MongoDB ODM Filters diff --git a/core/fosuser-bundle.md b/core/fosuser-bundle.md index 4bead8cee94..a518b84adb8 100644 --- a/core/fosuser-bundle.md +++ b/core/fosuser-bundle.md @@ -9,7 +9,7 @@ instead of using this bundle. API Platform Core is shipped with a bridge for [FOSUserBundle](https://github.com/FriendsOfSymfony/FOSUserBundle). If the FOSUser bundle is enabled, this bridge will use its `UserManager` to create, update and delete user resources. -

User Entity screencast
Watch the User Entity screencast

+

User Entity screencast
Watch the User Entity screencast

## Installing the Bundle diff --git a/core/getting-started.md b/core/getting-started.md index 504f12d9e0d..dc516e8afd1 100644 --- a/core/getting-started.md +++ b/core/getting-started.md @@ -28,7 +28,7 @@ and what [JSON-LD](http://json-ld.org/) and [Hydra](http://www.hydra-cg.com/) fo ## Mapping the Entities -

Create an API Resource screencast
Watch the Create an API Resource screencast

+

Create an API Resource screencast
Watch the Create an API Resource screencast

API Platform Core is able to automatically expose entities mapped as "API resources" through a REST API supporting CRUD operations. diff --git a/core/index.md b/core/index.md index ca71f7a02bf..260a3facb0b 100644 --- a/core/index.md +++ b/core/index.md @@ -42,6 +42,6 @@ This bundle is extensively tested (unit and functional). The [`Fixtures/` direct ## Screencasts -

SymfonyCasts, API Platform screencasts

+

SymfonyCasts, API Platform screencasts

The easiest and funniest way to learn how to use API Platform is to watch [the more than 60 screencasts available on SymfonyCasts](https://symfonycasts.com/tracks/rest?cid=apip#api-platform)! diff --git a/core/jwt.md b/core/jwt.md index 87b20607ed7..2ebeb678f3a 100644 --- a/core/jwt.md +++ b/core/jwt.md @@ -7,7 +7,7 @@ The tokens are signed by the server's key, so the server is able to verify that API Platform allows to easily add a JWT-based authentication to your API using [LexikJWTAuthenticationBundle](https://github.com/lexik/LexikJWTAuthenticationBundle). -

JWT screencast
Watch the LexikJWTAuthenticationBundle screencast

+

JWT screencast
Watch the LexikJWTAuthenticationBundle screencast

## Installing LexikJWTAuthenticationBundle diff --git a/core/openapi.md b/core/openapi.md index 3133b3d2a50..75d98c58d29 100644 --- a/core/openapi.md +++ b/core/openapi.md @@ -4,7 +4,7 @@ API Platform natively support the [OpenAPI](https://www.openapis.org/) API speci ![Screenshot](../distribution/images/swagger-ui-1.png) -

OpenAPI screencast
Watch the OpenAPI screencast

+

OpenAPI screencast
Watch the OpenAPI screencast

The specification of the API is available at the `/docs.json` path. By default, OpenAPI v3 is used. diff --git a/core/operations.md b/core/operations.md index 2ae06575c8f..13d9f79a986 100644 --- a/core/operations.md +++ b/core/operations.md @@ -3,7 +3,7 @@ API Platform Core relies on the concept of operations. Operations can be applied to a resource exposed by the API. From an implementation point of view, an operation is a link between a resource, a route and its related controller. -

Operations screencast
Watch the Operations screencast

+

Operations screencast
Watch the Operations screencast

API Platform automatically registers typical [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations and describes them in the exposed documentation (Hydra and Swagger). It also creates and registers routes corresponding diff --git a/core/pagination.md b/core/pagination.md index 8b1d2a1b258..4dba8e2a4bf 100644 --- a/core/pagination.md +++ b/core/pagination.md @@ -1,6 +1,6 @@ # Pagination -

Pagination screencast
Watch the Pagination screencast

+

Pagination screencast
Watch the Pagination screencast

API Platform Core has native support for paged collections. Pagination is enabled by default for all collections. Each collection contains 30 items per page. diff --git a/core/security.md b/core/security.md index a09e8981226..5ec8b3318d1 100644 --- a/core/security.md +++ b/core/security.md @@ -4,7 +4,7 @@ The API Platform security layer is built on top of the [Symfony Security compone All its features, including [global access control directives](http://symfony.com/doc/current/book/security.html#securing-url-patterns-access-control) are supported. API Platform also provides convenient [access control expressions](https://symfony.com/doc/current/expressions.html#security-complex-access-controls-with-expressions) which you can apply at resource and operation level. -

Security screencast
Watch the Security screencast

+

Security screencast
Watch the Security screencast

diff --git a/core/serialization.md b/core/serialization.md index 33df9fda592..9333fa0a9e3 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -4,7 +4,7 @@ API Platform embraces and extends the Symfony Serializer Component to transform PHP entities in (hypermedia) API responses. -

Serializer screencast
Watch the Serializer screencast

+

Serializer screencast
Watch the Serializer screencast

The main serialization process has two stages: @@ -32,7 +32,7 @@ JSON-LD, or JavaScript Object Notation for Linked Data, is a method of encoding ## The Serialization Context, Groups and Relations -

Serialization Groups screencast
Watch the Serialization Groups screencast

+

Serialization Groups screencast
Watch the Serialization Groups screencast

API Platform allows you to specify the `$context` variable used by the Symfony Serializer. This variable is an associative array that has a handy `groups` key allowing you to choose which attributes of the resource are exposed during the normalization (read) and denormalization (write) processes. It relies on the [serialization (and deserialization) groups](https://symfony.com/doc/current/components/serializer.html#attributes-groups) @@ -221,7 +221,7 @@ Refer to the [operations](operations.md) documentation to learn more. ## Embedding Relations -

Relations screencast
Watch the Relations screencast

+

Relations screencast
Watch the Relations screencast

By default, the serializer provided with API Platform represents relations between objects using [dereferenceable IRIs](https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier). They allow you to retrieve details for related objects by issuing extra HTTP requests. However, for performance reasons, it is sometimes preferable to avoid forcing the client to issue extra HTTP requests. @@ -671,7 +671,7 @@ App\Entity\Greeting: ## Changing the Serialization Context Dynamically -

Context Builder & Service Decoration screencast
Watch the Context Builder & Service Decoration screencast

+

Context Builder & Service Decoration screencast
Watch the Context Builder & Service Decoration screencast

Let's imagine a resource where most fields can be managed by any user, but some can be managed only by admin users: diff --git a/core/subresources.md b/core/subresources.md index efda2a79359..4834d86380e 100644 --- a/core/subresources.md +++ b/core/subresources.md @@ -3,7 +3,7 @@ A subresource is a collection or an item that belongs to another resource. API Platform makes it easy to create such operations. -

Subresources screencast
Watch the Subresources screencast

+

Subresources screencast
Watch the Subresources screencast

The starting point of a subresource must be a relation on an existing resource. For example, let's create two entities (Question, Answer) and set up a subresource so that `/question/42/answer` gives us diff --git a/core/testing.md b/core/testing.md index 80aea918ff0..a5234fe88f8 100644 --- a/core/testing.md +++ b/core/testing.md @@ -3,7 +3,7 @@ API Platform Core provides a set of useful utilities dedicated to API testing. For an overview of how to test an API Platform app, be sure to read [the testing cookbook first](../distribution/testing.md). -

Test and Assertions screencast
Watch the API Tests & Assertions screencast

+

Test and Assertions screencast
Watch the API Tests & Assertions screencast

## The Test HttpClient diff --git a/core/validation.md b/core/validation.md index 087d31a079a..73c9301b5ee 100644 --- a/core/validation.md +++ b/core/validation.md @@ -4,7 +4,7 @@ API Platform takes care of validating the data sent to the API by the client (us By default, the framework relies on [the powerful Symfony Validator Component](http://symfony.com/doc/current/validation.html) for this task, but you can replace it with your preferred validation library such as [the PHP filter extension](https://www.php.net/manual/en/intro.filter.php) if you want to. -

Validation screencast
Watch the Validation screencast

+

Validation screencast
Watch the Validation screencast

## Validating Submitted Data diff --git a/deployment/index.md b/deployment/index.md index b8dc3b07f48..cac63909614 100644 --- a/deployment/index.md +++ b/deployment/index.md @@ -9,7 +9,7 @@ If you want to play with a local Kubernetes cluster, read [how to deploy an API If you don't want to use Docker, keep in mind that the server application of API Platform is a standard Symfony project, while the Progressive Web Application is a standard Next.js project: -

JWT screencast
Watch the Animated Deployment with Ansistrano screencast

+

JWT screencast
Watch the Animated Deployment with Ansistrano screencast

* [Deploying the Symfony application](https://symfony.com/doc/current/deployment.html) * [Deploying the Next.js application](https://nextjs.org/docs/deployment) diff --git a/distribution/debugging.md b/distribution/debugging.md index 6f3bc63b1ab..ee887d30932 100644 --- a/distribution/debugging.md +++ b/distribution/debugging.md @@ -1,6 +1,6 @@ # Debugging -

API Platform debugging screencast
Watch the Debugging API Platform screencast

+

API Platform debugging screencast
Watch the Debugging API Platform screencast

## Xdebug diff --git a/distribution/index.md b/distribution/index.md index 5d05fe5df11..d81eab290e1 100644 --- a/distribution/index.md +++ b/distribution/index.md @@ -795,6 +795,6 @@ and [browse it online](https://demo.api-platform.com). ## Screencasts -

SymfonyCasts, API Platform screencasts

+

SymfonyCasts, API Platform screencasts

The easiest and funniest way to learn how to use API Platform is to watch [the more than 60 screencasts available on SymfonyCasts](https://symfonycasts.com/tracks/rest?cid=apip#api-platform)! diff --git a/distribution/testing.md b/distribution/testing.md index a67cb6cdbd4..df745cf77a1 100644 --- a/distribution/testing.md +++ b/distribution/testing.md @@ -7,7 +7,7 @@ API Platform provides a set of helpful testing utilities to write unit tests, fu Let's learn how to use them! -

Tests and Assertions screencast
Watch the Tests & Assertions screencast

+

Tests and Assertions screencast
Watch the Tests & Assertions screencast

In this article you'll learn how to use: diff --git a/extra/contribution-guides.md b/extra/contribution-guides.md index a3b4af1d9a2..ed84b118074 100644 --- a/extra/contribution-guides.md +++ b/extra/contribution-guides.md @@ -7,4 +7,4 @@ **To report a security issue, please refer to [the dedicated document](security.md).** -

JWT screencast
Watch the Contributing back to Symfony screencast (free)

+

JWT screencast
Watch the Contributing back to Symfony screencast (free)