diff --git a/core/configuration.md b/core/configuration.md index 29bb8a83102..4576aef0258 100644 --- a/core/configuration.md +++ b/core/configuration.md @@ -27,6 +27,14 @@ api_platform: # Allow using plain IDs for JSON format allow_plain_identifiers: false + doctrine: + # To enable or disable Doctrine ORM support. + enabled: true + + doctrine_mongodb_odm: + # To enable or disable Doctrine MongoDB ODM support. + enabled: false + eager_loading: # To enable or disable eager loading. enabled: true diff --git a/core/data-persisters.md b/core/data-persisters.md index 41be9014e72..0872a9ebdd9 100644 --- a/core/data-persisters.md +++ b/core/data-persisters.md @@ -7,10 +7,11 @@ process](serialization.md). A data persister using [Doctrine ORM](http://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/2.6/reference/basic-mapping.html). +A [Doctrine MongoDB ODM](https://www.doctrine-project.org/projects/mongodb-odm.html) data persister is also included and can be enabled by following the [MongoDB documentation](mongodb.md). However, you may want to: -* store data to other persistence layers (ElasticSearch, MongoDB, external web services...) +* store data to other persistence layers (ElasticSearch, external web services...) * not publicly expose the internal model mapped with the database through the API * use a separate model for [read operations](data-providers.md) and for updates by implementing patterns such as [CQRS](https://martinfowler.com/bliki/CQRS.html) diff --git a/core/events.md b/core/events.md index b2db6c57a1b..550b9029143 100644 --- a/core/events.md +++ b/core/events.md @@ -68,7 +68,7 @@ feature](http://symfony.com/doc/current/components/dependency_injection/autowiri Alternatively, [the subscriber must be registered manually](http://symfony.com/doc/current/components/http_kernel/introduction.html#creating-an-event-listener). -[Doctrine events](http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#reference-events-lifecycle-events) +Doctrine events ([ORM](http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#reference-events-lifecycle-events), [MongoDB ODM](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/events.html#lifecycle-events)) are also available (if you use it) if you want to hook at the object lifecycle events. Built-in event listeners are: diff --git a/core/extensions.md b/core/extensions.md index ac6e957e1f1..e61a69cf4e7 100644 --- a/core/extensions.md +++ b/core/extensions.md @@ -2,7 +2,7 @@ API Platform Core provides a system to extend queries on items and collections. -Extensions are specific to Doctrine and Elasticsearch-PHP, and therefore, the Doctrine ORM support or the Elasticsearch +Extensions are specific to Doctrine and Elasticsearch-PHP, and therefore, the Doctrine ORM / MongoDB ODM support or the Elasticsearch reading support must be enabled to use this feature. If you use custom providers it's up to you to implement your own extension system or not. @@ -152,6 +152,19 @@ security: - { path: ^/users, roles: IS_AUTHENTICATED_FULLY } ``` +## Custom Doctrine MongoDB ODM Extension + +Creating custom extensions is the same as Doctrine ORM. + +The interfaces are: +* `ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationItemExtensionInterface` and `ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationCollectionExtensionInterface` to add stages to the [aggregation builder](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/aggregation-builder.html). +* `ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationResultItemExtensionInterface` and `ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationResultCollectionExtensionInterface` to return a result. + +The tags are `api_platform.doctrine.mongodb.aggregation_extension.item` and `api_platform.doctrine.mongodb.aggregation_extension.collection`. + +The custom extensions receive the [aggregation builder](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/aggregation-builder.html), +used to execute [complex operations on data](https://docs.mongodb.com/manual/aggregation/). + ## Custom Elasticsearch Extension Currently only extensions querying for a collection of items through a [search request](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html) diff --git a/core/filters.md b/core/filters.md index a1c1b846145..6ab7994f589 100644 --- a/core/filters.md +++ b/core/filters.md @@ -1,7 +1,7 @@ # Filters -API Platform Core provides a generic system to apply filters on collections. Useful filters for the Doctrine ORM are provided -with the library. You can also create custom filters that would fit your specific needs. +API Platform Core provides a generic system to apply filters on collections. Useful filters for the Doctrine ORM and +MongoDB ODM are provided with the library. You can also create custom filters that would fit your specific needs. You can also add filtering support to your custom [data providers](data-providers.md) by implementing interfaces provided by the library. @@ -10,7 +10,7 @@ By default, all filters are disabled. They must be enabled explicitly. When a filter is enabled, it is automatically documented as a `hydra:search` property in the collection response. It also automatically appears in the [NelmioApiDoc documentation](nelmio-api-doc.md) if it is available. -## Doctrine ORM Filters +## Doctrine ORM and MongoDB ODM Filters ### Basic Knowledge @@ -117,10 +117,13 @@ Learn more on how the [ApiFilter annotation](filters.md#apifilter-annotation) wo For the sake of consistency, we're using the annotation in the below documentation. +For MongoDB ODM, all the filters are in the namespace `ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter`. The filter +services all begin with `api_platform.doctrine_mongodb.odm`. + ### Search Filter -If Doctrine ORM support is enabled, adding filters is as easy as registering a filter service in the `api/config/services.yaml` -file and adding an attribute to your resource configuration. +If Doctrine ORM or MongoDB ODM support is enabled, adding filters is as easy as registering a filter service in the +`api/config/services.yaml` file and adding an attribute to your resource configuration. The search filter supports `exact`, `partial`, `start`, `end`, and `word_start` matching strategies: @@ -330,7 +333,7 @@ It will return all offers with `sold` equals `1`. ### Range Filter -The range filter allows you to filter by a value Lower than, Greater than, Lower than or equal, Greater than or equal and between two values. +The range filter allows you to filter by a value lower than, greater than, lower than or equal, greater than or equal and between two values. Syntax: `?property[]=value` @@ -622,7 +625,7 @@ class Tweet #### Using a Custom Order Query Parameter Name -A conflict will occur if `order` is also the name of a property with the term filter enabled. Luckily, the query +A conflict will occur if `order` is also the name of a property with the term filter enabled. Luckily, the query parameter name to use is configurable: ```yaml @@ -810,21 +813,20 @@ If you want to include some properties of the nested "author" document, use: `/b ## Creating Custom Filters -Custom filters can be written by implementing the `ApiPlatform\Core\Api\FilterInterface` -interface. +Custom filters can be written by implementing the `ApiPlatform\Core\Api\FilterInterface` interface. -API Platform provides a convenient way to create Doctrine ORM filters. If you use [custom data providers](data-providers.md), +API Platform provides a convenient way to create Doctrine ORM and MongoDB ODM filters. If you use [custom data providers](data-providers.md), you can still create filters by implementing the previously mentioned interface, but - as API Platform isn't aware of your persistence system's internals - you have to create the filtering logic by yourself. ### Creating Custom Doctrine ORM Filters -Doctrine filters have access to the HTTP request (Symfony's `Request` object) and to the `QueryBuilder` instance used to +Doctrine ORM filters have access to the context created from the HTTP request and to the `QueryBuilder` instance used to retrieve data from the database. They are only applied to collections. If you want to deal with the DQL query generated -to retrieve items, or don't need to access the HTTP request, [extensions](extensions.md) are the way to go. +to retrieve items, [extensions](extensions.md) are the way to go. A Doctrine ORM filter is basically a class implementing the `ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\FilterInterface`. -API Platform includes a convenient abstract class implementing this interface and providing utility methods: `ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter` +API Platform includes a convenient abstract class implementing this interface and providing utility methods: `ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter`. In the following example, we create a class to filter a collection by applying a regexp to a property. The `REGEXP` DQL function used in this example can be found in the [`DoctrineExtensions`](https://github.com/beberlei/DoctrineExtensions) @@ -902,7 +904,7 @@ it can also be enabled for some properties: # api/config/services.yaml services: 'App\Filter\RegexpFilter': - arguments: [ '@doctrine', '@request_stack', '@?logger', { email: ~, anOtherProperty: ~ } ] + arguments: [ '@doctrine', ~, '@?logger', { email: ~, anOtherProperty: ~ } ] # Uncomment only if autoconfiguration isn't enabled #tags: [ 'api_platform.filter' ] ``` @@ -952,6 +954,15 @@ class Offer You can now enable this filter using URLs like `http://example.com/offers?regexp_email=^[FOO]`. This new filter will also appear in Swagger and Hydra documentations. +### Creating Custom Doctrine MongoDB ODM Filters + +Doctrine MongoDB ODM filters have access to the context created from the HTTP request and to the [aggregation builder](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/aggregation-builder.html) +instance used to retrieve data from the database and to execute [complex operations on data](https://docs.mongodb.com/manual/aggregation/). +They are only applied to collections. If you want to deal with the aggregation pipeline generated to retrieve items, [extensions](extensions.md) are the way to go. + +A Doctrine MongoDB ODM filter is basically a class implementing the `ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface`. +API Platform includes a convenient abstract class implementing this interface and providing utility methods: `ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\AbstractFilter`. + ### Creating Custom Elasticsearch Filters Elasticsearch filters have access to the context created from the HTTP request and to the Elasticsearch query clause. @@ -963,9 +974,9 @@ A constant score query filter is basically a class implementing the `ApiPlatform and the `ApiPlatform\Core\Bridge\Elasticsearch\DataProvider\Filter\FilterInterface`. API Platform includes a convenient abstract class implementing this last interface and providing utility methods: `ApiPlatform\Core\Bridge\Elasticsearch\DataProvider\Filter\AbstractFilter`. -### Using Doctrine Filters +### Using Doctrine ORM Filters -Doctrine features [a filter system](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/filters.html) that allows the developer to add SQL to the conditional clauses of queries, regardless the place where the SQL is generated (e.g. from a DQL query, or by loading associated entities). +Doctrine ORM features [a filter system](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/filters.html) that allows the developer to add SQL to the conditional clauses of queries, regardless the place where the SQL is generated (e.g. from a DQL query, or by loading associated entities). These are applied on collections and items, so are incredibly useful. The following information, specific to Doctrine filters in Symfony, is based upon [a great article posted on Michaƫl Perrin's blog](http://blog.michaelperrin.fr/2014/12/05/doctrine-filters/). diff --git a/core/fosuser-bundle.md b/core/fosuser-bundle.md index 1b1442e090c..ea282188884 100644 --- a/core/fosuser-bundle.md +++ b/core/fosuser-bundle.md @@ -39,6 +39,7 @@ api_platform: ## Creating a `User` Entity with Serialization Groups Here's an example of declaration of a [Doctrine ORM User class](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/index.rst#a-doctrine-orm-user-class). +There's also an example for a [Doctrine MongoDB ODM](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/index.rst#b-mongodb-user-class). You need to use serialization groups to hide some properties like `plainPassword` (only in read) and `password`. The properties shown are handled with the [`normalization_context`](serialization.md#normalization), while the properties you can modify are handled with [`denormalization_context`](serialization.md#denormalization). diff --git a/core/getting-started.md b/core/getting-started.md index 5f866b8a65c..075ceb4af3a 100644 --- a/core/getting-started.md +++ b/core/getting-started.md @@ -6,6 +6,7 @@ If you are starting a new project, the easiest way to get API Platform up is to It ships with the API Platform Core library integrated with [the Symfony framework](https://symfony.com), [the schema generator](../schema-generator/), [Doctrine ORM](http://www.doctrine-project.org), [Elasticsearch-PHP](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html), [NelmioCorsBundle](https://github.com/nelmio/NelmioCorsBundle) and [Behat](http://behat.org). +[Doctrine MongoDB ODM](https://www.doctrine-project.org/projects/mongodb-odm.html) can also be enabled by following the [MongoDB documentation](mongodb.md). Basically, it is a Symfony edition packaged with the best tools to develop a REST API and sensible default settings. Alternatively, you can use [Composer](http://getcomposer.org) to install the standalone bundle in an existing Symfony Flex diff --git a/core/index.md b/core/index.md index 052ce3e57b7..0dd7469e86b 100644 --- a/core/index.md +++ b/core/index.md @@ -22,7 +22,7 @@ Here is the fully featured REST API you'll get in minutes: * [Automatic CRUD](operations.md) * Hypermedia (JSON-LD and HAL) * Machine-readable documentation of the API in the Hydra and [Swagger/Open API](swagger.md) formats, - guessed from PHPDoc, Serializer, Validator and Doctrine ORM metadata + guessed from PHPDoc, Serializer, Validator and Doctrine ORM / MongoDB ODM metadata * Nice human-readable documentation built with Swagger UI (including a sandbox) and/or ReDoc * [Pagination](pagination.md) * A bunch of [filters](filters.md) diff --git a/core/mongodb.md b/core/mongodb.md new file mode 100644 index 00000000000..ceccdc6ee45 --- /dev/null +++ b/core/mongodb.md @@ -0,0 +1,221 @@ +# MongoDB Support + +## Overview + +[MongoDB](https://www.mongodb.com/) is one of the most popular NoSQL document-oriented database, used for its high +write load (useful for analytics or IoT) and high availability (easy to set replica sets with automatic failover). It +can also shard the database easily for horizontal scalability and has a powerful query language for doing aggregation, +text search or geospatial queries. + +API Platform uses [Doctrine MongoDB ODM 2](https://www.doctrine-project.org/projects/mongodb-odm.html) and in particular +its [aggregation builder](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/aggregation-builder.html) +to leverage all the possibilities of the database. + +Doctrine MongoDB ODM 2 relies on the [mongodb](https://secure.php.net/manual/en/set.mongodb.php) PHP extension and not +the legacy [mongo](https://secure.php.net/manual/en/book.mongo.php) extension. + +## Enabling MongoDB support + +If the mongodb PHP extension is not installed yet, [install it beforehand](https://secure.php.net/manual/en/mongodb.installation.pecl.php). + +If you are using the [API Platform Distribution](../distribution/index.md), modify the Dockerfile to add the extension: + +```diff + // api/Dockerfile + + ... + pecl install \ + apcu-${APCU_VERSION} \ ++ mongodb \ + ; \ + ... + docker-php-ext-enable \ + apcu \ + opcache \ ++ mongodb \ + ; \ + ... +``` + +Then rebuild the `php` image: + +```bash +docker-compose build php +``` + +Add a MongoDB image to the docker-compose file: + +```yaml +# docker-compose.yml + +# ... + db-mongodb: + # In production, you may want to use a managed database service + image: mongo + environment: + - MONGO_INITDB_DATABASE=api + - MONGO_INITDB_ROOT_USERNAME=api-platform + # You should definitely change the password in production + - MONGO_INITDB_ROOT_PASSWORD=!ChangeMe! + volumes: + - db-data:/var/lib/mongodb/data:rw + # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! + # - ./docker/db/data:/var/lib/mongodb/data:rw + ports: + - "27017:27017" +# ... +``` + +Once the extension is installed, to enable the MongoDB support, require the [Doctrine MongoDB ODM bundle](https://github.com/doctrine/DoctrineMongoDBBundle) +package using Composer: + +```bash +docker-compose exec php composer req doctrine/mongodb-odm-bundle:^4.0.0@beta doctrine/mongodb-odm:^2.0.0@beta +``` + +Execute the contrib recipe to have it already configured. + +Change the MongoDB environment variables to match your Docker image: + +``` +# api/.env + +MONGODB_URL=mongodb://api-platform:!ChangeMe!@db-mongodb +MONGODB_DB=api +``` + +Change the configuration of API Platform to add the right mapping path: + +```yaml +# api/config/packages/api_platform.yaml + +api_platform: + # ... + + mapping: + paths: ['%kernel.project_dir%/src/Entity', '%kernel.project_dir%/src/Document'] + + # ... +``` + +## Creating documents + +Creating resources mapped to MongoDB documents is as simple as creating entities: + +```php +offers = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function addOffer(Offer $offer): void + { + $offer->product = $this; + $this->offers->add($offer); + } + + public function removeOffer(Offer $offer): void + { + $offer->product = null; + $this->offers->removeElement($offer); + } + + // ... +} +``` + +```php +