Как проверить параметр UUID перед запросом SQL для запроса «GET item» в API-платформе? - PullRequest
1 голос
/ 06 августа 2020

Использование:

  • PostgreSQL 11 с uuid_generate_v4 типом
  • Symfony 4.4.11
  • Платформа Api 2.5.6

У меня есть сущность со следующим идентификатором:

/**
 * @ORM\Entity(repositoryClass="App\Repository\ContractRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Contract
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="UUID")
     * @ORM\Column(name="id", type="guid", unique=true)
     */
    private $id;
[...]

Я генерирую следующий маршрут с помощью платформы Api:

App\Entity\Contract:
  itemOperations:
    get:

Итак, я получаю сгенерированный маршрут, например /contracts/{id}

В настоящее время, если я сделаю /contracts/TEST, он попытается выполнить запрос SQL с «TEST» в предложении where, и поэтому потерпит неудачу как 500.

Я хотел бы предотвратить такое поведение, заявив, что параметр {id} - это UUID_v4, и вернет 400, если нет.

1 Ответ

2 голосов
/ 07 августа 2020

Это поведение специфично для СУБД c, поэтому вам нужно добавить свой собственный logi c.

Компонент API-Platform, который извлекает сущность с идентификатором, - это ItemDataProviderInterface .

  1. Сначала я объявлю новое исключение MalformedUuidException.
  2. Затем я конвертирую это исключение в ошибку 400 .
  3. Наконец, я создам новую реализацию ItemDataProviderInterface, обернув ORM и добавив несколько проверок к идентификатору:
class ContractDataProvider implements RestrictedDataProviderInterface, ItemDataProviderInterface
{
    /** @var ItemDataProviderInterface */
    private $realDataProvider;

    public function __construct(ItemDataProviderInterface $realDataProvider)
    {
        $this->realDataProvider = $realDataProvider;
    }

    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
    {
        $uuidPattern = '/^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/i';
        if (preg_match($uuidPattern, $id) === 1) {
            return $this->realDataProvider->getItem($resourceClass, ['id' => $id], $operationName, $context);
        } else {
            throw new MalformedUuidException("the given ID \"$id\" is not a valid UUID.");
        }
    }

    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return $resourceClass === Contract::class;
    }
}
# config/services.yaml
    App\DataProvider\ContractDataProvider:
        arguments:
            $realDataProvider: '@api_platform.doctrine.orm.default.item_data_provider'

Однако обратите внимание, что контракт метода getItem() не указывает исключение MalformedUuidException, поэтому эта реализация нарушает принцип подстановки Лискова.

Рассмотрите возможность возврата значения null вместо этого и удовлетворитесь ошибкой 404.

...