You are here

PluginEngine.php in Crumbs, the Breadcrumbs suite 7.2

File

lib/PluginSystem/PluginEngine.php
View source
<?php

class crumbs_PluginSystem_PluginEngine {

  /**
   * @var crumbs_PluginSystem_PluginBag
   */
  protected $pluginBag;

  /**
   * @var crumbs_Router
   */
  protected $router;

  /**
   * @var crumbs_Container_WeightMap
   */
  protected $weightMap;

  /**
   * @param crumbs_PluginSystem_PluginBag $pluginBag
   * @param crumbs_Router $router
   * @param crumbs_Container_WeightMap $weightMap
   */
  function __construct($pluginBag, $router, $weightMap) {
    $this->pluginBag = $pluginBag;
    $this->router = $router;
    $this->weightMap = $weightMap;
  }

  /**
   * Ask applicable plugins to "decorate" (alter) the breadcrumb.
   *
   * @param array $breadcrumb
   */
  function decorateBreadcrumb($breadcrumb) {
    $iterator = $this->pluginBag
      ->getDecorateBreadcrumbPlugins();
    foreach ($iterator as $plugin_key => $plugin) {
      if (!method_exists($plugin, 'decorateBreadcrumb')) {

        // This means the code has changed, without the cache being cleared.
        // It is the user's responsibility to clear the cache.
        // Until then, we simply ignore and move on.
        continue;
      }
      $plugin
        ->decorateBreadcrumb($breadcrumb);
    }
  }

  /**
   * Invoke all relevant plugins to find the parent for a given path.
   *
   * @param string $path
   * @param array $item
   *
   * @return mixed|null
   */
  function findParent($path, $item) {
    $iterator = $this->pluginBag
      ->getRoutePluginMethodIterator('findParent', $item['route']);
    $result = $this
      ->find($iterator, array(
      $path,
      $item,
    ), TRUE);
    return $result;
  }

  /**
   * Invoke all relevant plugins to find all possible parents for a given path.
   *
   * @param string $path
   * @param array $item
   *
   * @return string[]
   */
  function findAllParents($path, $item) {
    $plugin_methods = $this->pluginBag
      ->getRoutePluginMethodIterator('findParent', $item['route']);
    return $this
      ->findAll($plugin_methods, array(
      $path,
      $item,
    ), TRUE);
  }

  /**
   * @param string $parent_raw
   *
   * @return string
   */
  protected function processFindParent($parent_raw) {
    if ($this->router
      ->urlIsExternal($parent_raw)) {

      // Always discard external paths.
      return NULL;
    }
    return $this->router
      ->getNormalPath($parent_raw);
  }

  /**
   * Invoke all relevant plugins to find the title for a given path.
   *
   * @param string $path
   * @param array $item
   * @param array $breadcrumb
   *
   * @return mixed|null
   */
  function findTitle($path, $item, $breadcrumb) {
    $plugin_methods = $this->pluginBag
      ->getRoutePluginMethodIterator('findTitle', $item['route']);
    $result = $this
      ->find($plugin_methods, array(
      $path,
      $item,
      $breadcrumb,
    ), FALSE);
    return $result;
  }

  /**
   * Invoke all relevant plugins to find all possible titles for a given path.
   *
   * @param string $path
   * @param array $item
   * @param array $breadcrumb
   *
   * @return string[]
   */
  function findAllTitles($path, $item, $breadcrumb) {
    $plugin_methods = $this->pluginBag
      ->getRoutePluginMethodIterator('findTitle', $item['route']);
    return $this
      ->findAll($plugin_methods, array(
      $path,
      $item,
      $breadcrumb,
    ), FALSE);
  }

  /**
   * Invoke all relevant plugins to find title or parent for a given path.
   *
   * @param crumbs_PluginSystem_PluginMethodIterator $iterator
   * @param array $args
   *   Parameter values to pass to plugin methods.
   * @param bool $processFindParent
   *
   * @return mixed|null
   */
  protected function find($iterator, $args, $processFindParent = FALSE) {
    $best_candidate = NULL;
    $best_candidate_weight = 999999;
    $best_candidate_key = NULL;
    foreach ($iterator as $plugin_key => $position) {
      if (!$position instanceof crumbs_PluginSystem_PluginMethodIteratorPosition) {
        continue;
      }
      if ($position
        ->isMultiPlugin()) {
        $localWeightMap = $this->weightMap
          ->localWeightMap($plugin_key);
        if ($best_candidate_weight <= $localWeightMap
          ->smallestValue()) {
          return $best_candidate;
        }
        $candidates = $position
          ->invokeFinderMethod($args);
        if (empty($candidates)) {
          continue;
        }
        foreach ($candidates as $candidate_key => $candidate_raw) {
          if (!isset($candidate_raw)) {
            continue;
          }
          $candidate_weight = $localWeightMap
            ->valueAtKey($candidate_key);
          if (FALSE === $candidate_weight) {
            continue;
          }
          if ($best_candidate_weight <= $candidate_weight) {
            continue;
          }
          if ($processFindParent) {
            $candidate = $this
              ->processFindParent($candidate_raw);
            if (!isset($candidate)) {
              continue;
            }
          }
          else {
            $candidate = $candidate_raw;
          }
          $best_candidate = $candidate;
          $best_candidate_weight = $candidate_weight;
        }
      }
      elseif ($position
        ->isMonoPlugin()) {
        $candidate_weight = $this->weightMap
          ->valueAtKey($plugin_key);
        if ($best_candidate_weight <= $candidate_weight) {
          return $best_candidate;
        }
        $candidate_raw = $position
          ->invokeFinderMethod($args);
        if (!isset($candidate_raw)) {
          continue;
        }
        $candidate = $processFindParent ? $this
          ->processFindParent($candidate_raw) : $candidate_raw;
        if (isset($candidate)) {
          $best_candidate = $candidate;
          $best_candidate_weight = $candidate_weight;
        }
      }
    }
    return $best_candidate;
  }

  /**
   * Invoke all relevant plugins to find title or parent for a given path.
   *
   * @param crumbs_PluginSystem_PluginMethodIterator $iterator
   * @param array $args
   *   Parameter values to pass to plugin methods.
   * @param bool $processFindParent
   *
   * @return mixed|null
   */
  protected function findAll($iterator, $args, $processFindParent = FALSE) {
    $all_candidates = array();

    /**
     * @var string $plugin_key
     * @var crumbs_PluginSystem_PluginMethodIteratorPosition $position
     */
    foreach ($iterator as $plugin_key => $position) {
      if ($position
        ->isMultiPlugin()) {

        // That's a crumbs_MultiPlugin
        $candidates = $position
          ->invokeFinderMethod($args);
        if (empty($candidates)) {
          continue;
        }
        foreach ($candidates as $candidate_key => $candidate) {
          if (!isset($candidate)) {
            continue;
          }
          if ($processFindParent) {
            $candidate = $this
              ->processFindParent($candidate);
            if (!isset($candidate)) {
              continue;
            }
          }
          $all_candidates["{$plugin_key}.{$candidate_key}"] = $candidate;
        }
      }
      else {

        // That's a crumbs_MonoPlugin
        $candidate = $position
          ->invokeFinderMethod($args);
        if (!isset($candidate)) {
          continue;
        }
        if ($processFindParent) {
          $candidate = $this
            ->processFindParent($candidate);
          if (!isset($candidate)) {
            continue;
          }
        }
        $all_candidates[$plugin_key] = $candidate;
      }
    }
    return $all_candidates;
  }

}