Lt Bader
Lt Bader

Reputation: 11

Symfony2 doctrine filter collections

I have got some doctrine entities with each a OneToMany-Relationship: First: Base, Second: Module and Third: ModuleDetails (see below for Details). The setup works perfectly. When fetching a base i get all modules and there associated details.

My Problem is: The details of a module may change over time, so whenever a detail is changed there is a new entry in the DB with a revision-Date set accordingly.

Now I want to fetach a Base with all its Modules and Details, but only the newest revision of Details (or whatever revision i choose), but I am lost on this!

Can I write a custom getter-method for moduleDetails which is only getting those matching a given criteria? I've already read about doctrine Critera-Class but can't get it to work. Any help or hints are very welcome. Thank you very much in advance!

For instance here is are my entities (in short):

Base-Entity

/**
 * @ORM\Entity(repositoryClass="hcs\AlphaBundle\Entity\OfferBaseRepository")
 * @ORM\Table(name="hcs_offerbase")
 * @ORM\HasLifecycleCallbacks
 *
 * @ExclusionPolicy("all")
 */

class OfferBase
{
    /**
      * @ORM\Column(type="integer")
      * @ORM\Id
      * @ORM\GeneratedValue(strategy="AUTO")
      * @Type("integer")
      * @SerializedName("id")
      * @Groups({"list", "detail"})
      *
      * @Expose
    */
    protected $id;
    /**
      * @ORM\OneToMany(targetEntity="ModuleBase", mappedBy="offerbase", cascade={"persist", "merge"})
      * @Type("ArrayCollection<hcs\AlphaBundle\Entity\ModuleBase>")
      * @Assert\Valid
      *
      * @Expose
    */
    protected $category;

Module-Entity:

/**
 * @ORM\Entity(repositoryClass="hcs\AlphaBundle\Entity\ModuleBaseRepository")
 * @ORM\Table(name="hcs_modulebase")
 *
 * @ExclusionPolicy("all")
 */

class ModuleBase
{
    /**
      * @ORM\Column(type="integer")
      * @ORM\Id
      * @ORM\GeneratedValue(strategy="AUTO")
      * @Type("integer")
      * @SerializedName("id")
      *
      * @Expose
    */
    protected $id;

    /**
      * @ORM\ManyToOne(targetEntity="OfferBase", inversedBy="category")
      * @ORM\JoinColumn(name="offerbase_id", referencedColumnName="id")
    */
    protected $offerbase;

    /**
      * @ORM\OneToMany(targetEntity="ModuleCondition", mappedBy="modulebase", cascade={"persist", "merge"})
      * @Type("ArrayCollection<hcs\AlphaBundle\Entity\ModuleCondition>")
      * @Assert\Valid
      *
      * @Expose
    */
    protected $modules;

ModuleDetails-Entity

/**
 * @ORM\Entity(repositoryClass="hcs\AlphaBundle\Entity\ModuleConditionRepository")
 * @ORM\Table(name="hcs_modulecondition")
 * @ORM\HasLifecycleCallbacks
 *
 * @ExclusionPolicy("all")
 */

class ModuleCondition
{
    /**
      * @ORM\Column(type="integer")
      * @ORM\Id
      * @ORM\GeneratedValue(strategy="AUTO")
      * @Type("integer")
      * @SerializedName("id")
      *
      * @Expose
    */
    protected $id;

    /**
      * @ORM\ManyToOne(targetEntity="ModuleBase", inversedBy="modules")
      * @ORM\JoinColumn(name="modulebase_id", referencedColumnName="id")
    */
    protected $modulebase;

EDIT 12.02.2015 Tanks for your comments:

@Wilt: I tried exactly what you proposed in your answer (for testing purpose I used the id as criteria):

So inside my Module-Entity I did:

   /**
     * Get modules
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function setModules()
    {
        $criteria = Criteria::create()
          ->where(Criteria::expr()->gte('id', '1'));

          return $this->details->matching($criteria);
    }

But considering your answer I think i was wrong. I have to use this filter inside my controler after fetching the whole entity from my database and than filter the collection.

Am I right on this?

If I do this, is there a possibility to use the filterd collection for serialising the entity? I use JMS Serializer.

@General This is used for a REST-Api. You can fetch any offers by sending an id(offerbase_id) and get in return the serialized offer and all it's details:

$currentOffer = $this->getDoctrine()->getRepository('myBundle:OfferBase')->find($offerId);

$serializer = $this->get('jms_serializer');
$result = $serializer->serialize($currentOffer, 'json');
return new Response($result);

As a normal user you can only access the latest revision of your offer, but if your user_role allowes it, you can get access to all revisions. I can't do the filtering on the clientside.

Upvotes: 1

Views: 1009

Answers (1)

Wilt
Wilt

Reputation: 44316

There is a whole paragraph on how to do this in the Doctrine documentation 8.8 filter collections.

You can use the Doctrine\Common\Collections\Criteria class and add your criteria using revision dates for filtering the collection.

So something like this:

$criteria = Criteria::create()
    ->where(Criteria::expr()->gte('revision_date', $date));

return $this->details->matching($criteria);

Upvotes: 3

Related Questions