association-1.0.0-alpha2/src/AssociationNegotiator.php
src/AssociationNegotiator.php
<?php namespace Drupal\association; use Drupal\association\Entity\AssociationInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Routing\RouteMatchInterface; /** * Tagged service collector for entity association resolution handling. */ class AssociationNegotiator implements AssociationNegotiatorInterface { /** * The entity association discovered for the current route match. * * Most of the route based calls are going to be searching for the entity * association of the current route, and since this shouldn't change for the * route it's possible to keep this result instead of repetitive resolutions. * * @var \Drupal\association\Entity\AssociationInterface|false */ private $defaultRouteAssoc = NULL; /** * Current discovered associations discovered by entities. * * Associations are keyed by the "{$entity_type_id}:{$entity_id}" they * were discovered by. * * @var \Drupal\association\Entity\AssociationInterface[] */ private $byEntityCache = []; /** * The current route match. * * @var \Drupal\Core\Routing\RouteMatchInterface */ protected $routeMatch; /** * List of association negotiators keyed by priority. * * @var array */ protected $negotiators = []; /** * A flat sorted list of association negotiatorss. * * @var \Drupal\association\AssociationNegotiatorInterface[] */ private $sorted; /** * Create a new instance of the AssociationNegotiator service collector. * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The current route match, to be used as a default when a route match * is not provided during calls to the static::byRoute() method. */ public function __construct(RouteMatchInterface $route_match) { $this->routeMatch = $route_match; } /** * Reset the internal discovery caches and allow changes to get recomputed. */ public function resetCaches() { $this->defaultRouteAssoc = NULL; $this->byEntityCache = []; } /** * Sort and flatten the current list of negotiators if static::sorted is NULL. * * @return \Drupal\association\AssociationNegotiatorInterface[] * The sorted and flattened list of AssociationNegotiatorInterface handlers. */ protected function getSorted() { if (!isset($this->sorted)) { ksort($this->negotiators); // Merge all priority arrays into a single sorted array. $this->sorted = array_reduce($this->negotiators, 'array_merge', []); } return $this->sorted; } /** * Add more negotiator services by priority to the resolution stack. * * @param \Drupal\association\AssociationNegotiatorInterface $negotiator * A association negotiator to add to the list of negotiators. * @param int $priority * The priority of the negotiator being added. Lower numbers have a higher * priority. Priorities of less than 0, will trigger before the default, and * priorities higher than 1, will trigger after the default. * * @return \Drupal\association\AssociationNegotiatorInterface * Return itself to allow for chaining. */ public function addNegotiator(AssociationNegotiatorInterface $negotiator, $priority = 0) { $this->negotiators[$priority][] = $negotiator; $this->sorted = NULL; return $this; } /** * {@inheritdoc} */ public function byRoute(RouteMatchInterface $route_match = NULL): ?AssociationInterface { // If using the current route match, then attempt to use the default. if (!$route_match || $route_match === $this->routeMatch) { if (!isset($this->defaultRouteAssoc)) { $this->defaultRouteAssoc = FALSE; foreach ($this->getSorted() as $negotiator) { if ($assoc = $negotiator->byRoute($this->routeMatch)) { $this->defaultRouteAssoc = $assoc; break; } } } return $this->defaultRouteAssoc ?: NULL; } else { foreach ($this->getSorted() as $negotiator) { if ($association = $negotiator->byRoute($route_match)) { return $association; } } } return NULL; } /** * {@inheritdoc} */ public function byEntity(EntityInterface $entity): ?AssociationInterface { $cacheKey = $entity->getEntityTypeId() . ':' . $entity->id(); if (!isset($this->byEntityCache[$cacheKey])) { $this->byEntityCache[$cacheKey] = FALSE; foreach ($this->getSorted() as $negotiator) { if ($association = $negotiator->byEntity($entity)) { $this->byEntityCache[$cacheKey] = $association; break; } } } return $this->byEntityCache[$cacheKey] ?: NULL; } }