Skip to content

[Filters] Some filters have issues with their actual operation, OpenAPI output, and Hydra output #7654

@ttskch

Description

@ttskch

API Platform version(s) affected: 4.2.11

For example:

#[GetCollection(
    parameters: [
        ':property' => new QueryParameter(
            filter: new PartialSearchFilter(),
            properties: ['title', 'comments.content'],
        ),
        'query' => new QueryParameter(
            filter: new FreeTextQueryFilter(new PartialSearchFilter()),
            properties: ['title', 'comments.content'],
        ),
        'date' => new QueryParameter(
            filter: new DateFilter(),
        ),
        'published' => new QueryParameter(
            filter: new BooleanFilter(),
        ),
        'numeric[id]' => new QueryParameter(
            filter: new NumericFilter(),
            property: 'id',
        ),
        'id' => new QueryParameter(
            filter: new RangeFilter(),
        ),
        'exists[:property]' => new QueryParameter(
            filter: new ExistsFilter(),
            properties: ['content', 'comments'],
        ),
        'order[:property]' => new QueryParameter(
            filter: new OrderFilter(),
            properties: ['id', 'date'],
        ),
    ],
)]
#[ORM\Entity(repositoryClass: ArticleRepository::class)]
class Article
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $title = null;

    #[ORM\Column(type: Types::TEXT)]
    private ?string $content = null;

    #[ORM\Column(type: Types::DATE_MUTABLE)]
    private ?\DateTime $date = null;

    #[ORM\Column(nullable: true)]
    private ?bool $published = null;

    /**
     * @var Collection<int, Comment>
     */
    #[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'article', orphanRemoval: true)]
    private Collection $comments;

    // ...
}

This code has the following problems:

Actual behavior

  • Cannot search by ?comments.content
  • Searching by ?query results in [Semantical Error] line 0, col 92 near 'content) LIKE': Error: Class App\\Entity\\Article has no field or association named comments.content
  • Cannot search by ?exists[content]

OpenAPI Doc

Details

  • title is not output, only title[] is output.
  • The type of title[] is string instead of array<string>.
  • Neither comments.content nor comments.content[] is output.
  • id[between] is not output.

Hydra search.template field

{
    "search": {
    "template": "/api/articles{?date,published,numeric[id],id,title,exists[content],exists[comments],order[id],order[date]}"
    }
}
  • date[after], date[before], date[strictly_after], date[strictly_before] are not output, only date is output.
  • id[gt], id[lt], id[gte], id[lte], id[between] are not output, only id is output.

Even with a few small tweaks like this...

diff --git a/src/Entity/Article.php b/src/Entity/Article.php
index 8a0b47e..eb00cc0 100644
--- a/src/Entity/Article.php
+++ b/src/Entity/Article.php
@@ -20,9 +20,12 @@ use Doctrine\ORM\Mapping as ORM;
 
 #[GetCollection(
     parameters: [
-        ':property' => new QueryParameter(
+        'title' => new QueryParameter(
             filter: new PartialSearchFilter(),
-            properties: ['title', 'comments.content'],
+        ),
+        'comments.content' => new QueryParameter(
+            filter: new PartialSearchFilter(),
+            property: 'comments.content',
         ),
         'query' => new QueryParameter(
             filter: new FreeTextQueryFilter(new PartialSearchFilter()),
@@ -41,9 +44,13 @@ use Doctrine\ORM\Mapping as ORM;
         'id' => new QueryParameter(
             filter: new RangeFilter(),
         ),
-        'exists[:property]' => new QueryParameter(
+        'exists[content]' => new QueryParameter(
+            filter: new ExistsFilter(),
+            property: 'content',
+        ),
+        'exists[comments]' => new QueryParameter(
             filter: new ExistsFilter(),
-            properties: ['content', 'comments'],
+            property: 'comments',
         ),
         'order[:property]' => new QueryParameter(
             filter: new OrderFilter(),
Details
#[GetCollection(
    parameters: [
        'title' => new QueryParameter(
            filter: new PartialSearchFilter(),
        ),
        'comments.content' => new QueryParameter(
            filter: new PartialSearchFilter(),
            property: 'comments.content',
        ),
        'query' => new QueryParameter(
            filter: new FreeTextQueryFilter(new PartialSearchFilter()),
            properties: ['title', 'comments.content'],
        ),
        'date' => new QueryParameter(
            filter: new DateFilter(),
        ),
        'published' => new QueryParameter(
            filter: new BooleanFilter(),
        ),
        'numeric[id]' => new QueryParameter(
            filter: new NumericFilter(),
            property: 'id',
        ),
        'id' => new QueryParameter(
            filter: new RangeFilter(),
        ),
        'exists[content]' => new QueryParameter(
            filter: new ExistsFilter(),
            property: 'content',
        ),
        'exists[comments]' => new QueryParameter(
            filter: new ExistsFilter(),
            property: 'comments',
        ),
        'order[:property]' => new QueryParameter(
            filter: new OrderFilter(),
            properties: ['id', 'date'],
        ),
    ],
)]
#[ORM\Entity(repositoryClass: ArticleRepository::class)]
class Article
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $title = null;

    #[ORM\Column(type: Types::TEXT)]
    private ?string $content = null;

    #[ORM\Column(type: Types::DATE_MUTABLE)]
    private ?\DateTime $date = null;

    #[ORM\Column(nullable: true)]
    private ?bool $published = null;

    /**
     * @var Collection<int, Comment>
     */
    #[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'article', orphanRemoval: true)]
    private Collection $comments;

    // ...
}

This code has the following problems:

Coding

  • Specifying property: 'comments.content' explicitly is required, otherwise ApiPlatform\\Doctrine\\Orm\\Util\\QueryNameGenerator::generateParameterName(): Argument #1 ($name) must be of type string, null given, called in /path/to/project/vendor/api-platform/doctrine-orm/Filter/PartialSearchFilter.php on line 37 will occur, even though the key is comments.content.

Actual behavior

  • Searching by ?comments.content results in [Semantical Error] line 0, col 58 near 'content) LIKE': Error: Class App\\Entity\\Article has no field or association named comments.content
  • Searching by ?query results in [Semantical Error] line 0, col 92 near 'content) LIKE': Error: Class App\\Entity\\Article has no field or association named comments.content
  • Cannot search by ?exists[content]

OpenAPI Doc

Details

  • title is not output, only title[] is output.
  • The type of title[] is string instead of array<string>.
  • comments.content is not output, only comments.content[] is output.
  • The type of comments.content[] is string instead of array<string>.
  • id[between] is not output.

Hydra search.template field

{
  "search": {
    "template": "/api/articles{?title,comments.content,date,published,numeric[id],id,exists[content],exists[comments],order[id],order[date]}"
  }
}
  • date[after], date[before], date[strictly_after], date[strictly_before] are not output, only date is output.
  • id[gt], id[lt], id[gte], id[lte], id[between] are not output, only id is output.

Reproducer

https://github.com/ttskch/api-platform-core-7654

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions