3

Assuming I have two entities:

  • entity A: locations
  • entity B: images

one location owns several images ( one-to-many ). The images might have a property type. I often come to a use case, where i need to filter images by type. At the moment I do it through lifecycle callbacks like you'll see in the following example:

    /**
     * This functions sets all images when the entity is loaded
     *
     * @ORM\PostLoad
     */
    public function onPostLoadSetImages($eventArgs)
    {
        $this->recommendedForIcons = new ArrayCollection();
        $this->whatYouGetImages    = new ArrayCollection();

        foreach ($this->getImages() as $image) {

            if ('background-image' === $image->getType()->getSlug()) {
                $this->backgroundImage = $image;
            } elseif ('product-icon' === $image->getType()->getSlug()) {
                $this->mainIcon = $image;
            } elseif ('product-image' === $image->getType()->getSlug()) {
                $this->productImage = $image;
            } elseif ('recommended-icon' === $image->getType()->getSlug()) {
                $this->recommendedForIcons->add($image);
            } elseif ('what-you-get-image' === $image->getType()->getSlug()) {
                $this->whatYouGetImages->add($image);
            } elseif ('productshoot-fullcolour' === $image->getType()->getSlug()) {
                $this->productImageFullColor = $image;
            } elseif ('product-overview' === $image->getType()->getSlug()) {
                $this->productOverviewImage = $image;
            }

        }

    }

I am wondering if it is possible to search for an element in a doctrine array collection and not for the key or the element itself only.

Thank you.

Jared Farrish
  • 48,585
  • 17
  • 95
  • 104
smartius
  • 633
  • 3
  • 10
  • 24
  • Well, a couple low-hanging fruit: `$slug = $image->getType()->getSlug();` Then you can: `if ('background-image' == $slug)`, cutting down quite a bit of repetitive accessing. – Jared Farrish Dec 06 '15 at 21:38
  • yeah thanks, its just a rough example. the question itself is if there is amore elegant way to filter the array collection :) – smartius Dec 06 '15 at 22:13

2 Answers2

6

You can filter an ArrayCollection with a callback function. As Example, you can implements a method in your entity like:

 public  function  getWhatYouGetImages()
 {
    return $this->getImages()->filter(
        function ($image)  {
            return  ('what-you-get-image' === $image->getType()->getSlug());
        }
    );
}

I suggest to take a look at Doctrine Criteria also, as described in this answer. I can't propose an example for this because I don't know about the getType()->getSlug() on the Image entity.

Hope this help

Community
  • 1
  • 1
Matteo
  • 37,680
  • 11
  • 100
  • 115
  • well a criteria wont make sense since i want to access the images through my entity without running an additional query. – smartius Dec 06 '15 at 22:14
  • 1
    A predicate doesn't need to return an object it is enough to return `true` or `false`, so you shouldn't return `$image` here. – Wilt Jan 28 '16 at 15:48
  • I noticed because @user1987373 suddenly accepted your answer instead of mince :( – Wilt Jan 28 '16 at 15:52
  • Hi @Wilt our code works both, i think only because i post the answer before yours – Matteo Jan 28 '16 at 15:54
3

The ArrayCollection class has a filter method that takes a predicate (a closure) as an argument. That means you can do this:

$predicate = function($image){
    'background-image' === $image->getType()->getSlug()    
}

$images = $this->getImages();
$elements = $images->filter($predicate);

$elements holds now all elements from images that satisfy the predicate.

Internally it does something very similar to your solution; loop all elements and checks the callback...

Wilt
  • 41,477
  • 12
  • 152
  • 203