private function loadMap()

in src/symbols/PhutilClassMapQuery.php [205:308]


  private function loadMap() {
    $ancestor = $this->ancestorClass;
    if (!strlen($ancestor)) {
      throw new PhutilInvalidStateException('setAncestorClass');
    }

    if (!class_exists($ancestor) && !interface_exists($ancestor)) {
      throw new Exception(
        pht(
          'Trying to execute a class map query for descendants of class '.
          '"%s", but no such class or interface exists.',
          $ancestor));
    }

    $expand = $this->expandMethod;
    $filter = $this->filterMethod;
    $unique = $this->uniqueMethod;
    $sort = $this->sortMethod;

    if (strlen($expand)) {
      if (!strlen($unique)) {
        throw new Exception(
          pht(
            'Trying to execute a class map query for descendants of class '.
            '"%s", but the query specifies an "expand method" ("%s") without '.
            'specifying a "unique method". Class maps which support expansion '.
            'must have unique keys.',
            $ancestor,
            $expand));
      }
    }

    $objects = id(new PhutilSymbolLoader())
      ->setAncestorClass($ancestor)
      ->loadObjects();

    // Apply the "expand" mechanism, if it is configured.
    if (strlen($expand)) {
      $list = array();
      foreach ($objects as $object) {
        foreach (call_user_func(array($object, $expand)) as $instance) {
          $list[] = $instance;
        }
      }
    } else {
      $list = $objects;
    }

    // Apply the "unique" mechanism, if it is configured.
    if (strlen($unique)) {
      $map = array();
      foreach ($list as $object) {
        $key = call_user_func(array($object, $unique));

        if ($key === null && $this->filterNull) {
          continue;
        }

        if (empty($map[$key])) {
          $map[$key] = $object;
          continue;
        }

        throw new Exception(
          pht(
            'Two objects (of classes "%s" and "%s", descendants of ancestor '.
            'class "%s") returned the same key from "%s" ("%s"), but each '.
            'object in this class map must be identified by a unique key.',
            get_class($object),
            get_class($map[$key]),
            $ancestor,
            $unique.'()',
            $key));
      }
    } else {
      $map = $list;
    }

    // Apply the "filter" mechanism, if it is configured.
    if (strlen($filter)) {
      $map = mfilter($map, $filter);
    }

    // Apply the "sort" mechanism, if it is configured.
    if (strlen($sort)) {
      if ($map) {
        // The "sort" method may return scalars (which we want to sort with
        // "msort()"), or may return PhutilSortVector objects (which we want
        // to sort with "msortv()").
        $item = call_user_func(array(head($map), $sort));

        // Since we may be early in the stack, use a string to avoid triggering
        // autoload in old versions of PHP.
        $vector_class = 'PhutilSortVector';
        if ($item instanceof $vector_class) {
          $map = msortv($map, $sort);
        } else {
          $map = msort($map, $sort);
        }
      }
    }

    return $map;
  }