Skip to content

Commit a284641

Browse files
committed
Optimize fetching of metadata associations
1 parent 6c0a8e3 commit a284641

File tree

6 files changed

+102
-37
lines changed

6 files changed

+102
-37
lines changed

src/Controller/Dashboard/DashboardPackagesInfoController.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
use CodedMonkey\Dirigent\Attribute\IsGrantedAccess;
66
use CodedMonkey\Dirigent\Attribute\MapPackage;
7+
use CodedMonkey\Dirigent\Doctrine\Entity\Metadata;
78
use CodedMonkey\Dirigent\Doctrine\Entity\Package;
89
use CodedMonkey\Dirigent\Doctrine\Entity\PackageProvideLink;
910
use CodedMonkey\Dirigent\Doctrine\Entity\PackageRequireLink;
1011
use CodedMonkey\Dirigent\Doctrine\Entity\PackageSuggestLink;
1112
use CodedMonkey\Dirigent\Doctrine\Entity\Version;
13+
use CodedMonkey\Dirigent\Doctrine\Repository\MetadataRepository;
1214
use CodedMonkey\Dirigent\EasyAdmin\PackagePaginator;
1315
use Doctrine\ORM\EntityManagerInterface;
1416
use Doctrine\ORM\QueryBuilder;
@@ -44,6 +46,10 @@ public function info(#[MapPackage] Package $package): Response
4446
#[IsGrantedAccess]
4547
public function versionInfo(#[MapPackage] Package $package, #[MapPackage] Version $version): Response
4648
{
49+
/** @var MetadataRepository $metadataRepository */
50+
$metadataRepository = $this->entityManager->getRepository(Metadata::class);
51+
$metadataRepository->fetchMetadataCollections($version->getCurrentMetadata());
52+
4753
$dependentCount = $this->entityManager->getRepository(PackageRequireLink::class)->count(['linkedPackageName' => $package->getName()]);
4854
$implementationCount = $this->entityManager->getRepository(PackageProvideLink::class)->count(['linkedPackageName' => $package->getName(), 'implementation' => true]);
4955
$providerCount = $this->entityManager->getRepository(PackageProvideLink::class)->count(['linkedPackageName' => $package->getName(), 'implementation' => false]);

src/Doctrine/Entity/AbstractMetadataLink.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@ public function getIndex(): int
6767
private function addToCollection(): void
6868
{
6969
$linkType = MetadataLinkType::fromClass(static::class);
70-
$linkType->getMetadataLinks($this->metadata)->add($this);
70+
$linkType->getMetadataLinks($this->metadata, raw: true)->add($this);
7171
}
7272
}

src/Doctrine/Entity/Metadata.php

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
use Composer\Pcre\Preg;
99
use Doctrine\Common\Collections\ArrayCollection;
1010
use Doctrine\Common\Collections\Collection;
11+
use Doctrine\Common\Collections\Criteria;
12+
use Doctrine\Common\Collections\Order;
13+
use Doctrine\Common\Collections\Selectable;
1114
use Doctrine\DBAL\Types\Types;
1215
use Doctrine\ORM\Mapping as ORM;
1316

@@ -98,51 +101,45 @@ class Metadata extends TrackedEntity implements \Stringable
98101
private Package $package;
99102

100103
/**
101-
* @var Collection<int, MetadataRequireLink>
104+
* @var Collection<int, MetadataRequireLink>&Selectable
102105
*/
103106
#[ORM\OneToMany(targetEntity: MetadataRequireLink::class, mappedBy: 'metadata', cascade: ['persist', 'detach'])]
104-
#[ORM\OrderBy(['index' => 'ASC'])]
105107
private Collection $requireLinks;
106108

107109
/**
108-
* @var Collection<int, MetadataDevRequireLink>
110+
* @var Collection<int, MetadataDevRequireLink>&Selectable
109111
*/
110112
#[ORM\OneToMany(targetEntity: MetadataDevRequireLink::class, mappedBy: 'metadata', cascade: ['persist', 'detach'])]
111-
#[ORM\OrderBy(['index' => 'ASC'])]
112113
private Collection $devRequireLinks;
113114

114115
/**
115-
* @var Collection<int, MetadataConflictLink>
116+
* @var Collection<int, MetadataConflictLink>&Selectable
116117
*/
117118
#[ORM\OneToMany(targetEntity: MetadataConflictLink::class, mappedBy: 'metadata', cascade: ['persist', 'detach'])]
118-
#[ORM\OrderBy(['index' => 'ASC'])]
119119
private Collection $conflictLinks;
120120

121121
/**
122-
* @var Collection<int, MetadataProvideLink>
122+
* @var Collection<int, MetadataProvideLink>&Selectable
123123
*/
124124
#[ORM\OneToMany(targetEntity: MetadataProvideLink::class, mappedBy: 'metadata', cascade: ['persist', 'detach'])]
125-
#[ORM\OrderBy(['index' => 'ASC'])]
126125
private Collection $provideLinks;
127126

128127
/**
129-
* @var Collection<int, MetadataReplaceLink>
128+
* @var Collection<int, MetadataReplaceLink>&Selectable
130129
*/
131130
#[ORM\OneToMany(targetEntity: MetadataReplaceLink::class, mappedBy: 'metadata', cascade: ['persist', 'detach'])]
132-
#[ORM\OrderBy(['index' => 'ASC'])]
133131
private Collection $replaceLinks;
134132

135133
/**
136-
* @var Collection<int, MetadataSuggestLink>
134+
* @var Collection<int, MetadataSuggestLink>&Selectable
137135
*/
138136
#[ORM\OneToMany(targetEntity: MetadataSuggestLink::class, mappedBy: 'metadata', cascade: ['persist', 'detach'])]
139-
#[ORM\OrderBy(['index' => 'ASC'])]
140137
private Collection $suggestLinks;
141138

142139
/**
143-
* @var Collection<int, MetadataKeyword>
140+
* @var Collection<int, MetadataKeyword>&Selectable
144141
*/
145-
#[ORM\OneToMany(mappedBy: 'metadata', targetEntity: MetadataKeyword::class, cascade: ['persist', 'detach'])]
142+
#[ORM\OneToMany(targetEntity: MetadataKeyword::class, mappedBy: 'metadata', cascade: ['persist', 'detach'])]
146143
private Collection $keywords;
147144

148145
public function __construct(Version $version)
@@ -416,57 +413,57 @@ public function getPackage(): Package
416413
/**
417414
* @return Collection<int, MetadataRequireLink>
418415
*/
419-
public function getRequireLinks(): Collection
416+
public function getRequireLinks(bool $raw = false): Collection
420417
{
421-
return $this->requireLinks;
418+
return self::getOrderedCollection($this->requireLinks, $raw);
422419
}
423420

424421
/**
425422
* @return Collection<int, MetadataDevRequireLink>
426423
*/
427-
public function getDevRequireLinks(): Collection
424+
public function getDevRequireLinks(bool $raw = false): Collection
428425
{
429-
return $this->devRequireLinks;
426+
return self::getOrderedCollection($this->devRequireLinks, $raw);
430427
}
431428

432429
/**
433430
* @return Collection<int, MetadataConflictLink>
434431
*/
435-
public function getConflictLinks(): Collection
432+
public function getConflictLinks(bool $raw = false): Collection
436433
{
437-
return $this->conflictLinks;
434+
return self::getOrderedCollection($this->conflictLinks, $raw);
438435
}
439436

440437
/**
441438
* @return Collection<int, MetadataProvideLink>
442439
*/
443-
public function getProvideLinks(): Collection
440+
public function getProvideLinks(bool $raw = false): Collection
444441
{
445-
return $this->provideLinks;
442+
return self::getOrderedCollection($this->provideLinks, $raw);
446443
}
447444

448445
/**
449446
* @return Collection<int, MetadataReplaceLink>
450447
*/
451-
public function getReplaceLinks(): Collection
448+
public function getReplaceLinks(bool $raw = false): Collection
452449
{
453-
return $this->replaceLinks;
450+
return self::getOrderedCollection($this->replaceLinks, $raw);
454451
}
455452

456453
/**
457454
* @return Collection<int, MetadataSuggestLink>
458455
*/
459-
public function getSuggestLinks(): Collection
456+
public function getSuggestLinks(bool $raw = false): Collection
460457
{
461-
return $this->suggestLinks;
458+
return self::getOrderedCollection($this->suggestLinks, $raw);
462459
}
463460

464461
/**
465462
* @return Collection<int, MetadataKeyword>
466463
*/
467-
public function getKeywords(): Collection
464+
public function getKeywords(bool $raw = false): Collection
468465
{
469-
return $this->keywords;
466+
return self::getOrderedCollection($this->keywords, $raw);
470467
}
471468

472469
public function hasSource(): bool
@@ -675,4 +672,22 @@ public function toComposerArray(): array
675672

676673
return $data;
677674
}
675+
676+
/**
677+
* Sorts a Doctrine collection by an index field. If the $raw parameter is true, the collection is returned as-is.
678+
*/
679+
private static function getOrderedCollection(Collection&Selectable $collection, bool $raw): Collection
680+
{
681+
if ($raw) {
682+
return $collection;
683+
}
684+
685+
static $criteria = Criteria::create()
686+
->orderBy(['index' => Order::Ascending]);
687+
688+
/** @var Collection $collection */
689+
$collection = $collection->matching($criteria);
690+
691+
return $collection;
692+
}
678693
}

src/Doctrine/Entity/MetadataKeyword.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function __construct(
3232
$this->keyword = $keyword;
3333
$this->index = $index;
3434

35-
$this->metadata->getKeywords()->add($this);
35+
$this->metadata->getKeywords(raw: true)->add($this);
3636
}
3737

3838
public function getId(): ?int

src/Doctrine/Repository/MetadataRepository.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace CodedMonkey\Dirigent\Doctrine\Repository;
44

55
use CodedMonkey\Dirigent\Doctrine\Entity\Metadata;
6+
use CodedMonkey\Dirigent\Entity\MetadataLinkType;
67
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
78
use Doctrine\Persistence\ManagerRegistry;
89

@@ -39,6 +40,49 @@ public function remove(Metadata $entity, bool $flush = false): void
3940
}
4041
}
4142

43+
/**
44+
* Initializes all link and keyword collections for the given metadata.
45+
*/
46+
public function fetchMetadataCollections(Metadata ...$metadata): void
47+
{
48+
if ([] === $metadata) {
49+
return;
50+
}
51+
52+
$metadataCollection = $metadata;
53+
54+
foreach (MetadataLinkType::cases() as $linkType) {
55+
$association = match ($linkType) {
56+
MetadataLinkType::Require => 'requireLinks',
57+
MetadataLinkType::DevRequire => 'devRequireLinks',
58+
MetadataLinkType::Conflict => 'conflictLinks',
59+
MetadataLinkType::Provide => 'provideLinks',
60+
MetadataLinkType::Replace => 'replaceLinks',
61+
MetadataLinkType::Suggest => 'suggestLinks',
62+
};
63+
64+
$this->getEntityManager()->createQueryBuilder()
65+
->select('metadata', $association)
66+
->from(Metadata::class, 'metadata')
67+
->leftJoin("metadata.$association", $association)
68+
->where('metadata IN (:metadata)')
69+
->setParameter('metadata', $metadataCollection)
70+
->getQuery()
71+
->getResult();
72+
}
73+
74+
$this->getEntityManager()->createQueryBuilder()
75+
->select('metadata', 'keywords')
76+
->from(Metadata::class, 'metadata')
77+
->leftJoin('metadata.keywords', 'keywords')
78+
->leftJoin('keywords.keyword', 'keyword')
79+
->addSelect('keyword')
80+
->where('metadata IN (:metadata)')
81+
->setParameter('metadata', $metadataCollection)
82+
->getQuery()
83+
->getResult();
84+
}
85+
4286
public function getNextRevision(Metadata $metadata): int
4387
{
4488
$version = $metadata->getVersion();

src/Entity/MetadataLinkType.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,16 @@ public function getComposerPackageLinks(PackageInterface $package): array
6666
/**
6767
* @return Collection<int, AbstractMetadataLink>
6868
*/
69-
public function getMetadataLinks(Metadata $metadata): Collection
69+
public function getMetadataLinks(Metadata $metadata, bool $raw = false): Collection
7070
{
7171
/** @var Collection<int, AbstractMetadataLink> $collection */
7272
$collection = match ($this) {
73-
self::Require => $metadata->getRequireLinks(),
74-
self::DevRequire => $metadata->getDevRequireLinks(),
75-
self::Conflict => $metadata->getConflictLinks(),
76-
self::Provide => $metadata->getProvideLinks(),
77-
self::Replace => $metadata->getReplaceLinks(),
78-
self::Suggest => $metadata->getSuggestLinks(),
73+
self::Require => $metadata->getRequireLinks($raw),
74+
self::DevRequire => $metadata->getDevRequireLinks($raw),
75+
self::Conflict => $metadata->getConflictLinks($raw),
76+
self::Provide => $metadata->getProvideLinks($raw),
77+
self::Replace => $metadata->getReplaceLinks($raw),
78+
self::Suggest => $metadata->getSuggestLinks($raw),
7979
};
8080

8181
return $collection;

0 commit comments

Comments
 (0)