Reputation: 2611
I am strugling with my Symfony PersistentCollection
- in a result set of query findByOne()
executed on a repository. I need to find one or more elements by specific value within a PersistentCollection
, ie withing other entity that has relation to the other.
I have a RuleSet
entity with relation to SrcFile
entity.
On a RuleSetRepository
I call method findOneBy(['id' => 1)
to find RuleSet ID=1.
This returns an object RuleSet
that has srcFiles: PersistentCollection
.
Now what I need is to get specific object from that collection. I know there is a method getIterator()
I can loop through all the result in the collection and make condition to find wher file.kind == 'master', but...
Is there any better way how to access/find/search within the PersistentCollection using buildin method?
//...
// dump of acctual result of
dump($grsr->findOneBy(['id' => 1)]);
// dumped data (shortened version):
ProfileUController.php on line 118:
RuleSet {#1509 ▼
-id: 1
-srcFiles: PersistentCollection {#1507 ▼
-snapshot: array:5 [ …5]
-owner: RuleSet {#1509}
-association: array:15 [ …15]
-em: EntityManager {#975 …11}
-backRefFieldName: "ruleset"
-typeClass: ClassMetadata {#1230 …}
-isDirty: false
#collection: ArrayCollection {#1481 ▼
-elements: array:5 [▼
0 => SrcFile {#1573 ▶}
1 => SrcFile {#1734 ▶}
//...
]
}
#initialized: true
}
}
Upvotes: 0
Views: 1610
Reputation: 1130
What you are looking for is Doctrine Criteria
, which allows you to filter a Collection
. It is smart enough to filter at the database level if the collection objects aren't in memory yet.
Here's a quick example:
$ruleSet = $grsr->findOneBy(['id' => 1]);
$criteria = Criteria::create();
// Criteria to find SrcFiles where kind = 'master'
$criteria->where(Criteria::expr()->eq('kind', 'master');
// return only the srcFiles matching criteria
$ruleSet->srcFiles->matching($criteria);
I prefer to create helper methods on my entity, as I think it's a little cleaner. This is up to you, but I would do something like this on the RuleSet
entity:
public function getMasterFiles()
{
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('kind', 'master'));
// assuming you have a getter named getSrcFiles for the srcFiles association
return $this->getSrcFiles()->matching($criteria);
}
Then you can do something like this (and you don't have to duplicate the code every time we need the master files):
$ruleSet = $grsr->findOneBy(['id' => 1]);
$ruleSet->getMasterFiles();
Update
If you need to filter on nested collections, you have to use the filter
method:
public function getMasterFiles()
{
return $this->getSrcFiles()->filter(function(SrcFile $srcFile) {
// if callback returns true, then object is included in result
return ($srcFile->getKind() === 'master' && $srcFile->getSrcSheet()->getName() === 'MainData');
});
}
The filter
method is more flexible, but it is always done on the objects after they are fetched from the database. This usually isn't a big deal, but can affect performance. The other option is a custom repository method, but I prefer to use helper methods on the entities. It feels more ORMish to me.
Upvotes: 2