imper86 / elastica-api-data-provider-bundle

ApiPlatform data provider for FOSElasticaBundle
MIT License
0 stars 3 forks source link

Basic Documentation / Example #1

Open tacman opened 4 years ago

tacman commented 4 years ago

Can you provide some documentation on how to use this bundle?

I'm hoping that I can use the bundle to populate an index with API Platform JSON, can you explain how to do that?

Thanks.

imper86 commented 4 years ago

Hi! This bundle will not help you populate elasticsearch index of your app. It works with FOS ElasticaBundle, and gives you ApiPlatform's DataProvider to read data from your elasticsearch indexes.

So, if you don't know FOS Elastica Bundle you should start with it.

Then, if you want to fetch & filter your elasticsearch data with your API you can start to use my bundle. It's very simple. If you want some api resource to use my DataProvider you can implement ElasticaCollectionAwareInterface in your entity/dto.

After installing the bundle you will also have access to compatible api platform filters. List of them you can simply check with ./bin/console debug:container imper86_elastica_api To use them you should extend them in services.yaml, just like that:

services:
    app.product.term_filter:
        parent: 'imper86_elastica_api.term_filter'
        tags: ['api_platform.filter']
        autoconfigure: false
        autowire: false
        arguments:
            $properties:
                type: ~
                translations.slug: ~
                translations.locale: ~
                parent.id: ~
                collectionId: ~
                attributes.attribute.id: ~
                attributes.options.id: ~

Last thing you can do with this bundle is creating custom DataProvider extensions. Example of simple custom extension:

use App\Common\EntityInterface\UserAwareInterface;
use App\Entity\User\UserInterface;
use Elastica\Query;
use Imper86\ElasticaApiDataProviderBundle\DataProvider\Extension\ExtensionInterface;
use Symfony\Component\Security\Core\Security;

class UserAwareExtension implements ExtensionInterface
{
    /**
     * @var Security
     */
    private Security $security;

    public function __construct(Security $security)
    {
        $this->security = $security;
    }

    public function applyToCollection(Query $query, string $resourceClass, string $operationName, array $context)
    {
        if (!is_a($resourceClass, UserAwareInterface::class, true)) {
            return;
        }

        if ($this->security->isGranted('ROLE_ADMIN')) {
            return;
        }

        /** @var UserInterface|null $user */
        $user = $this->security->getUser();
        /** @var Query\BoolQuery $boolQuery */
        $boolQuery = $query->getQuery();

        if (!$user) {
            throw new \RuntimeException('Using this extension should be excluded for anonymous users');
        }

        $boolQuery->addFilter(new Query\Term(['user.id' => $user->getId()]));
    }
}

To make this work you must add 'imper86_elastica_api.data_provider_extension' tag to such service in services.yaml. Just like that:

App\Service\ApiPlatform\Extension\UserAwareExtension:
        tags: ['imper86_elastica_api.data_provider_extension']

I hope this helps :). Maybe I'll write some real documentation for this bundle, but I'm not sure if FOS Elastica bundle will be maintained. It still does not support ElasticSearch 7. and Symfony 5.. If it will not be updated my bundle will be useless :)

tacman commented 4 years ago

Thanks. I've given up on FOSElastica, hundreds of unanswered issues. I've been using my fork for Symfony 5, but ES 5 is at end of life, and no signs of an update of FOSElasticBundle. I found your bundle while researching alternatives.

So I'm working with directly with ruflin/elastica, and have a very basic search working. Elastica is so powerful, but there's a learning curve!

imper86 commented 4 years ago

FOSElasticaBundle works with ES6, so it's not that bad :) I have a new bundle in my plans, which will be DataProvider for elasticsearch-php, but I don't need it yet, since I'm still using ES6 :)