Skip to content

Filtering by a relation's property #944

@ymarillet

Description

@ymarillet

Hi,

This is affecting version 2.0.1 to current (2.0.3)

Having the following entities:

<?php

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation as Serializer;

/**
 * @ApiResource(
 *     attributes={
 *          "normalization_context"={"groups"={"foo"}},
 *          "filters"={"foo.search_filter"}
 *     }
 * )
 * @ORM\Entity
 */
class Foo
{
    /**
     * @var int The entity Id
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @var string Something else
     *
     * @ORM\OneToMany(targetEntity="Bar", mappedBy="foo")
     *
     * @Serializer\Groups({"foo"})
     */
    private $bars;

    public function __construct()
    {
        $this->bars = new ArrayCollection();
    }

    public function getId()
    {
        return $this->id;
    }

    /**
     * @return string
     */
    public function getBars()
    {
        return $this->bars;
    }

    /**
     * @param string $bars
     * @return static
     */
    public function setBars($bars)
    {
        $this->bars = $bars;
        return $this;
    }
}
<?php

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource
 * @ORM\Entity
 */
class Bar
{
    /**
     * @var int The entity Id
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @var Foo
     *
     * @ORM\ManyToOne(targetEntity="Foo", inversedBy="bars")
     * @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
     * @Assert\NotBlank
     */
    private $foo;

    /**
     * @var string
     *
     * @ORM\Column(nullable=false)
     * @Assert\NotBlank
     *
     * @Serializer\Groups({"foo"})
     */
    private $prop = '';

    public function getId()
    {
        return $this->id;
    }

    /**
     * @return Foo|null
     */
    public function getFoo()
    {
        return $this->foo;
    }

    /**
     * @param Foo $foo
     * @return static
     */
    public function setFoo(Foo $foo)
    {
        $this->foo = $foo;
        return $this;
    }

    /**
     * @return string
     */
    public function getProp()
    {
        return $this->prop;
    }

    /**
     * @param string $prop
     * @return static
     */
    public function setProp($prop)
    {
        $this->prop = $prop;
        return $this;
    }
}

Services defined as:

services:
  app.entity.filter.foo:
      parent:    'api_platform.doctrine.orm.search_filter'
      arguments:
          - { bars.prop: 'ipartial' }
      tags:
          - { name: 'api_platform.filter', id: 'foo.search_filter' }

Having the following data:

AppBundle\Entity\Foo:
  foo1:
    id: 1
    bars: ["@bar1", "@bar2"]
  
AppBundle\Entity\Bar:
  bar1:
    id: 1
    prop: "toto"
    foo: "@foo1"
  bar2:
    id: 2
    prop: "tata"
    foo: "@foo1"

Having set the proper filters in order to run that simple query:
http://localhost/foos?bar.prop=toto

Will result:

{
  "@context": "/contexts/Foo",
  "@id": "/foos",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/foos/1",
      "@type": "Foo",
      "bars": [
        {
          "@id": "/bars/1",
          "@type": "Bar",
          "prop": "toto"
        }
      ]
    }
  ],
  "hydra:totalItems": 1,
  "...otherProps...": "...otherValues...."
}

I understand that the second Bar attached to foo1 gets filtered through the doctrine query, but since we're on the Foo endpoint:

  • is it still a valid behaviour ?
  • if so, how to tell api-platform/doctrine to fetch all relations upon filtering on them ?

Regards,
Yohann

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions