Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUESTION] MongoDB routes generation #273

Closed
benthE opened this issue Apr 6, 2017 · 6 comments
Closed

[QUESTION] MongoDB routes generation #273

benthE opened this issue Apr 6, 2017 · 6 comments

Comments

@benthE
Copy link

benthE commented Apr 6, 2017

Hey guys !
I'm new to API Platform, and I tried to implement an API with a Mongo database, but I got an issue when I want to generate my routes, It seems not to have taken into account the fact I changed my configuration from a MySQL database to a Mongo one.

Do you have any ideas on how to fix that ?

@soyuka
Copy link
Member

soyuka commented Apr 6, 2017

MongoDB is not yet supported see api-platform/core#461.

@dunglas
Copy link
Member

dunglas commented Apr 12, 2017

Anyway it should not impact the routing. Can you paste the error?

@VeeeneX
Copy link

VeeeneX commented Jun 13, 2017

Example /products

{
  "@context": "/contexts/Product",
  "@id": "/products",
  "@type": "hydra:Collection",
  "hydra:member": [
    [
      {
        "@id": "/products/593bdea59280210007715442",
        "@type": "http://schema.org/Product",
        "name": "ccc",
        "id": "593bdea59280210007715442"
      },
      {
        "@id": "/products/593be02f487dae0007070e12",
        "@type": "http://schema.org/Product",
        "name": "ccc",
        "id": "593be02f487dae0007070e12"
      }
    ]
  ],
  "hydra:totalItems": 1
}

I can't delete the product because there's a html validation for integer. This doesn't work for GET, PUT, DELETE. When I try to create a product I get an error:

{"@context":"\/contexts\/Error","@type":"hydra:Error","hydra:title":"An error occurred","hydra:description":"Unable to generate an IRI for the item of type \u0022App\\Document\\Product\u0022","trace":[{"namespace":"","short_class":"","class":"","type":"","function":"","file":"\/app\/src\/Bridge\/Symfony\/Routing\/IriConverter.php","line":122,"args":[]},{"namespace":"App\\Bridge\\Symfony\\Routing","short_class":"IriConverter","class":"App\\Bridge\\Symfony\\Routing\\IriConverter","type":"-\u003E","function":"getIriFromItem","file":"\/app\/vendor\/api-platform\/core\/src\/JsonLd\/Serializer\/ItemNormalizer.php","line":71,"args":[["object","App\\Document\\Product"]]},{"namespace":"ApiPlatform\\Core\\JsonLd\\Serializer","short_class":"ItemNormalizer","class":"ApiPlatform\\Core\\JsonLd\\Serializer\\ItemNormalizer","type":"-\u003E","function":"normalize","file":"\/app\/vendor\/symfony\/serializer\/Serializer.php","line":128,"args":[["object","App\\Document\\Product"],["string","jsonld"],["array",{"collection_operation_name":["string","post"],"operation_type":["string","collection"],"resource_class":["string","App\\Document\\Product"],"request_uri":["string","\/products"],"resources":["array",[]],"jsonld_has_context":["boolean",true]}]]},{"namespace":"Symfony\\Component\\Serializer","short_class":"Serializer","class":"Symfony\\Component\\Serializer\\Serializer","type":"-\u003E","function":"normalize","file":"\/app\/vendor\/symfony\/serializer\/Serializer.php","line":101,"args":[["object","App\\Document\\Product"],["string","jsonld"],["array",{"collection_operation_name":["string","post"],"operation_type":["string","collection"],"resource_class":["string","App\\Document\\Product"],"request_uri":["string","\/products"],"resources":["array",[]]}]]},{"namespace":"Symfony\\Component\\Serializer","short_class":"Serializer","class":"Symfony\\Component\\Serializer\\Serializer","type":"-\u003E","function":"serialize","file":"\/app\/vendor\/api-platform\/core\/src\/EventListener\/SerializeListener.php","line":65,"args":[["object","App\\Document\\Product"],["string","jsonld"],["array",{"collection_operation_name":["string","post"],"operation_type":["string","collection"],"resource_class":["string","App\\Document\\Product"],"request_uri":["string","\/products"],"resources":["array",[]]}]]},{"namespace":"ApiPlatform\\Core\\EventListener","short_class":"SerializeListener","class":"ApiPlatform\\Core\\EventListener\\SerializeListener","type":"-\u003E","function":"onKernelView","file":null,"line":null,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"],["string","kernel.view"],["object","Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"]]},{"namespace":"","short_class":"","class":"","type":"","function":"call_user_func","file":"\/app\/vendor\/symfony\/event-dispatcher\/Debug\/WrappedListener.php","line":106,"args":[["array",[["object","ApiPlatform\\Core\\EventListener\\SerializeListener"],["string","onKernelView"]]],["object","Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"],["string","kernel.view"],["object","Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"]]},{"namespace":"Symfony\\Component\\EventDispatcher\\Debug","short_class":"WrappedListener","class":"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener","type":"-\u003E","function":"__invoke","file":null,"line":null,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"],["string","kernel.view"],["object","Symfony\\Component\\EventDispatcher\\EventDispatcher"]]},{"namespace":"","short_class":"","class":"","type":"","function":"call_user_func","file":"\/app\/vendor\/symfony\/event-dispatcher\/EventDispatcher.php","line":212,"args":[["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"],["string","kernel.view"],["object","Symfony\\Component\\EventDispatcher\\EventDispatcher"]]},{"namespace":"Symfony\\Component\\EventDispatcher","short_class":"EventDispatcher","class":"Symfony\\Component\\EventDispatcher\\EventDispatcher","type":"-\u003E","function":"doDispatch","file":"\/app\/vendor\/symfony\/event-dispatcher\/EventDispatcher.php","line":44,"args":[["array",[["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"]]],["string","kernel.view"],["object","Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"]]},{"namespace":"Symfony\\Component\\EventDispatcher","short_class":"EventDispatcher","class":"Symfony\\Component\\EventDispatcher\\EventDispatcher","type":"-\u003E","function":"dispatch","file":"\/app\/vendor\/symfony\/event-dispatcher\/Debug\/TraceableEventDispatcher.php","line":146,"args":[["string","kernel.view"],["object","Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"]]},{"namespace":"Symfony\\Component\\EventDispatcher\\Debug","short_class":"TraceableEventDispatcher","class":"Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher","type":"-\u003E","function":"dispatch","file":"\/app\/vendor\/symfony\/http-kernel\/HttpKernel.php","line":158,"args":[["string","kernel.view"],["object","Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"]]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"HttpKernel","class":"Symfony\\Component\\HttpKernel\\HttpKernel","type":"-\u003E","function":"handleRaw","file":"\/app\/vendor\/symfony\/http-kernel\/HttpKernel.php","line":68,"args":[["object","Symfony\\Component\\HttpFoundation\\Request"],["integer",1]]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"HttpKernel","class":"Symfony\\Component\\HttpKernel\\HttpKernel","type":"-\u003E","function":"handle","file":"\/app\/vendor\/symfony\/http-kernel\/Kernel.php","line":171,"args":[["object","Symfony\\Component\\HttpFoundation\\Request"],["integer",1],["boolean",true]]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"Kernel","class":"Symfony\\Component\\HttpKernel\\Kernel","type":"-\u003E","function":"handle","file":"\/app\/web\/index.php","line":39,"args":[["object","Symfony\\Component\\HttpFoundation\\Request"]]}]}

I'm using flex and this is my composer.json

{
    "type": "project",
    "license": "proprietary",
    "require": {
        "php": "^7.1.3",
        "alcaeus/mongo-php-adapter": "^1.1@dev",
        "api-platform/api-pack": "^2.1@dev",
        "doctrine/mongodb-odm": "^1.0.5",
        "doctrine/mongodb-odm-bundle": "^3.0",
        "symfony/console": "^3.3",
        "symfony/flex": "^1.0",
        "symfony/framework-bundle": "^3.3",
        "symfony/monolog-bundle": "^3.0@dev",
        "symfony/web-server-bundle": "^4.0@dev",
        "symfony/yaml": "^3.3"
    },
    "minimum-stability": "dev",
    "require-dev": {
        "symfony/dotenv": "^3.3"
    },
    "provide" : {
        "ext-mongo": "*"
    },
    "config": {
        "preferred-install": {
            "*": "dist"
        },
        "sort-packages": true
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "scripts": {
        "auto-scripts": {
            "make cache-warmup": "script",
            "assets:install --symlink --relative %WEB_DIR%": "symfony-cmd"
        },
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    },
    "conflict": {
        "symfony/symfony": "*",
        "symfony/twig-bundle": "<3.3",
        "symfony/debug": "<3.3"
    },
    "extra": {
        "symfony": {
            "id": "01BJ7D0KCZK3WQP9ZRYVBSH55B",
            "allow-contrib": "true"
        }
    }
}

And my container.yml

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    locale: 'en'

services:
    api_platform.iri_converter:
        public: false
        class: "App\\Bridge\\Symfony\\Routing\\IriConverter"
        arguments: ['@api_platform.metadata.property.name_collection_factory', '@api_platform.metadata.property.metadata_factory', '@api_platform.item_data_provider', '@api_platform.route_name_resolver', '@api_platform.router', '@api_platform.property_accessor']
        tags: [{ name: 'api_platform.iri_converter', id: 'api_platform.iri_converter' }]

    product.collection_data_provider:
        class: 'App\DataProvider\ProductCollectionDataProvider'
        arguments:
            $managerRegistry: "@doctrine_mongodb.odm.document_manager"
        public: true
        autowire: true
        tags:
            -  { name: 'api_platform.collection_data_provider', priority: 2 }

Working DataCollection with ODM

<?php
/**
 * @author     veeenex <veeenex@gmail.com>
 * @created_at 10.6.2017 0:47
 */

namespace App\DataProvider;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Core\Exception\RuntimeException;
use App\Document\Product;
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use Doctrine\ODM\MongoDB\DocumentManager;

final class ProductCollectionDataProvider implements CollectionDataProviderInterface
{
    private $managerRegistry;
    private $collectionExtensions;

    /**
     * @param \Doctrine\ODM\MongoDB\DocumentManager $managerRegistry
     * @param QueryCollectionExtensionInterface[]                                     $collectionExtensions
     */
    public function __construct(DocumentManager $managerRegistry, array $collectionExtensions = [])
    {
        $this->managerRegistry = $managerRegistry;
        $this->collectionExtensions = $collectionExtensions;
    }

    public function getCollection(string $resourceClass, string $operationName = null)
    {
        if (Product::class !== $resourceClass) {
            throw new ResourceClassNotSupportedException();
        }

        $repository = $this->managerRegistry->getRepository("App:Product");
        if (!method_exists($repository, 'createQueryBuilder')) {
            throw new RuntimeException('The repository class must have a "createQueryBuilder" method.');
        }

        $queryBuilder = $repository->createQueryBuilder('o');
        $queryNameGenerator = new QueryNameGenerator();
        foreach ($this->collectionExtensions as $extension) {
            $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName);

            if ($extension instanceof QueryResultCollectionExtensionInterface && $extension->supportsResult($resourceClass, $operationName)) {
                return $extension->getResult($queryBuilder);
            }
        }

        return [$repository->findAll()];
    }
}

@dunglas
Copy link
Member

dunglas commented Jun 13, 2017

Can you try to remove the cache using rm -Rf var/cache/*?
Why do you need a custom api_platform.iri_converter service?

@VeeeneX
Copy link

VeeeneX commented Jun 14, 2017

I'm still getting the error Unable to generate an IRI for the item of type App\Document\Product, so I need to have custom IriConverter because I can't get identifier from ODM Product.

@Simperfit
Copy link
Contributor

@VeeeneX if you still have an issue, or if you found something to fix this, please feel free to comment this issue.

If you have some time to help us finish the mongodb support feel free to look at it ;).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants