API Plateform - Пользовательский фильтр по среднему рейтингу - PullRequest
0 голосов
/ 23 сентября 2018

В настоящее время я обнаруживаю API-Plateform с Symfony, и я хочу создать собственный фильтр.

Я создал объекты, описанные в документации: у меня есть объект Book иПросмотрите сущность, и я хочу, чтобы мой пользовательский фильтр возвращал книги со средним рейтингом, превосходящим или равным данному значению.

Мне удалось сделать следующее в своем классе BookRepository:

// src/Repository/BookRepository.php

/**
* @return Book[] Returns an array of Book objects
*/
public function findWithAverageRating($value)
{
    /*
     * HERE IS THE EQUIVALENT IN SQL :
     *
     * SELECT book.id, book.title, AVG(review.rating) AS average_rating 
     * FROM book INNER JOIN review 
     * ON book.id = review.book_id 
     * GROUP BY book.id 
     * HAVING AVG(review.rating) >= 3
     */
    $qb = $this->createQueryBuilder('b')
        ->join('b.reviews', 'r');
    $qb->having($qb->expr()->avg('r.rating').' >= :rating')
        ->setParameter('rating', $value)
        ->orderBy('b.id', 'ASC') 
        ->groupBy('b.id') 
    ;

    // var_dump($qb->getQuery()->getSql());
    return $qb->getQuery()->getResult();
}

СейчасЯ хочу сделать следующее как Api Filter, но следующее возвращает все книги:

// src/Filter/RatingFilter.php
namespace App\Filter;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;

final class RatingFilter extends AbstractContextAwareFilter
{
    protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
    {
        // otherwise filter is applied to order and page as well
        if (
            !$this->isPropertyEnabled($property, $resourceClass) ||
            !$this->isPropertyMapped($property, $resourceClass)
        ) {
            return;
        }

        $parameterName = $queryNameGenerator->generateParameterName($property); // Generate a unique parameter name to avoid collisions with other filters

        $queryBuilder->join('o.reviews', 'r');
        $queryBuilder->having($queryBuilder->expr()->avg('r.%s').' >= :%s', $property, $parameterName)
            ->setParameter($parameterName, $value)
            // ->orderBy('b.id', 'ASC') 
            // ->groupBy('b.id') 
        ;
    }

    // This function is only used to hook in documentation generators (supported by Swagger and Hydra)
    public function getDescription(string $resourceClass): array
    {
        if (!$this->properties) {
            return [];
        }

        $description = [];
        foreach ($this->properties as $property => $strategy) {
            $description["rating_$property"] = [
                'property' => $property,
                'type' => 'string',
                'required' => false,
                'swagger' => [
                    'description' => 'Filter by average rating (rating goes from 0 to 5).',
                    'name' => 'averageRatingMoreThan',
                    'type' => 'number',
                ],
            ];
        }

        return $description;
    }
}

Я включил фильтр в своей сущности Book и установил его в свойстве «reviews» (это немне это кажется чрезвычайно логичным, но если я не установлю его для свойства, фильтр не появится в моем API):

 * @ApiFilter(RatingFilter::class, properties={"reviews"})

Затем я проверил свой фильтр, чтобы получить книги со средним рейтингом 3 илиподробнее.

Только 4 из 10 книг имеют средний рейтинг более 3/5. Но API возвращает все мои книги.

curl -X GET "http://127.0.0.1:8000/api/books?averageRatingMoreThan=3" -H  "accept: application/ld+json"

Любое указание, почемуэто работает в моем репозитории бно не как фильтр, пожалуйста?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...