Collecteurs et cibles
phil/references-bundleUn collecteur
Un ReferenceCollector trouve vers quoi pointe un genre de source. Le champ est l'endroit où se trouve le lien : une
propriété, un chemin dans un document JSON — blocks.2.image —, fait de lettres, de chiffres, de _, ., :, - et
de crochets.
final readonly class PageReferences implements ReferenceCollector
{
public function supports(object $source): bool { return $source instanceof Page; }
public function sourceOf(object $source): ResourceReference { return ResourceReference::of('page', $source->id); }
public function collect(object $source): iterable
{
foreach ($source->blocks as $index => $block) {
if (isset($block['image'])) {
yield new Link('blocks.'.$index.'.image', ResourceReference::of('image', $block['image']));
}
}
}
}
Une cible
Un ReferenceTarget connaît un genre de ressource qu'utilisent les autres : si une ressource existe encore, et quelle
référence correspond à un objet. Sans cible, un genre ne voit jamais une suppression refusée ni ses liens rompus
vérifiés.
final readonly class ImageReferences implements ReferenceTarget
{
public function kind(): string { return 'image'; }
public function exists(string $id): bool { return null !== $this->images->find($id); }
public function referenceOf(object $resource): ?ResourceReference
{
return $resource instanceof Image ? ResourceReference::of('image', $resource->id) : null;
}
}
Avec l'autoconfiguration, le bundle trouve les deux.
Ce que fait un flush
Avec track_entities, ReferenceTrackingListener surveille les flush de sa connexion :
- avant le flush, une cible encore utilisée par une source qui reste refuse sa suppression :
StillReferenced, et le flush est annulé. Une source supprimée dans le même flush ne compte pas ; - après le flush, une source insérée ou mise à jour voit ses liens collectés de nouveau, une source supprimée les voit oubliés, dans l'ordre des flush. Seuls les liens qui ont changé sont écrits : une source enregistrée sans changement de ses liens coûte une lecture.
La référence d'une source supprimée est lue avant le flush, pendant que son identifiant est connu : Doctrine vide un
identifiant généré une fois la ligne supprimée. Un flush qui échoue ferme son gestionnaire d'entités, et ce qu'il
aurait enregistré disparaît avec lui. Vider le gestionnaire d'entités, ou le kernel.reset du conteneur entre les
messages d'un worker, le fait aussi disparaître.
Appelez References::assertUnused() avant de supprimer, pour montrer un message à la personne plutôt qu'un flush
annulé ; l'écouteur est le filet de sécurité. Pour des sources qui ne sont pas des entités Doctrine, appelez
vous-même refresh() et forget().