You are here

public function DataFetcher::fetchDataBySubPaths in Typed Data API enhancements 8

Fetches data based upon the given sub-paths.

Parameters

\Drupal\Core\TypedData\TypedDataInterface $typed_data: The data from which to select a value.

string[] $sub_paths: A list of sub paths; i.e., a property path separated into its parts.

\Drupal\Core\Render\BubbleableMetadata|null $bubbleable_metadata: (optional) An object to which required bubbleable metadata will be added.

string $langcode: (optional) The language code used to get the argument value if the argument value should be translated. Defaults to NULL.

Return value

\Drupal\Core\TypedData\TypedDataInterface The variable wrapped as typed data.

Throws

\Drupal\Core\TypedData\Exception\MissingDataException Thrown if the data cannot be fetched due to missing data; e.g., unset properties or list items.

\Drupal\typed_data\Exception\InvalidArgumentException Thrown if the given path is not valid for the given data; e.g., a not existing property is referenced.

Overrides DataFetcherInterface::fetchDataBySubPaths

1 call to DataFetcher::fetchDataBySubPaths()
DataFetcher::fetchDataByPropertyPath in src/DataFetcher.php
Fetches data based upon the given property path.

File

src/DataFetcher.php, line 38

Class

DataFetcher
Implementation of the data fetcher service.

Namespace

Drupal\typed_data

Code

public function fetchDataBySubPaths(TypedDataInterface $typed_data, array $sub_paths, BubbleableMetadata $bubbleable_metadata = NULL, $langcode = NULL) {
  $current_selector = [];
  $bubbleable_metadata = $bubbleable_metadata ?: new BubbleableMetadata();
  try {
    foreach ($sub_paths as $name) {
      $current_selector[] = $name;

      // If the current data is just a reference then directly dereference the
      // target.
      if ($typed_data instanceof DataReferenceInterface) {
        $this
          ->addBubbleableMetadata($typed_data, $bubbleable_metadata);
        $typed_data = $typed_data
          ->getTarget();
        if ($typed_data === NULL) {
          throw new MissingDataException("The specified reference is NULL.");
        }
      }

      // Make sure we are using the right language.
      if (isset($langcode) && $typed_data instanceof TranslatableInterface) {
        if ($typed_data
          ->hasTranslation($langcode)) {
          $typed_data = $typed_data
            ->getTranslation($langcode);
        }

        // @todo What if the requested translation does not exist? Currently
        // we just ignore that and continue with the current object.
      }

      // If this is a list but the selector is not an integer, we forward the
      // selection to the first element in the list.
      if ($typed_data instanceof ListInterface && !ctype_digit($name)) {
        $this
          ->addBubbleableMetadata($typed_data, $bubbleable_metadata);
        $typed_data = $typed_data
          ->get(0);
      }

      // Drill down to the next step in the data selector.
      if ($typed_data instanceof ListInterface || $typed_data instanceof ComplexDataInterface) {
        $this
          ->addBubbleableMetadata($typed_data, $bubbleable_metadata);
        $typed_data = $typed_data
          ->get($name);
      }
      else {
        $current_selector_string = implode('.', $current_selector);
        throw new InvalidArgumentException("The parent property is not a list or a complex structure at '{$current_selector_string}'.");
      }

      // If an accessed list item does not exist, $typed_data will be NULL.
      if (!isset($typed_data)) {
        $selector_string = implode('.', $sub_paths);
        $current_selector_string = implode('.', $current_selector);
        throw new MissingDataException("Unable to apply data selector '{$selector_string}' at '{$current_selector_string}'");
      }
    }
    $this
      ->addBubbleableMetadata($typed_data, $bubbleable_metadata);
    return $typed_data;
  } catch (MissingDataException $e) {
    $selector = implode('.', $sub_paths);
    $current_selector = implode('.', $current_selector);
    throw new MissingDataException("Unable to apply data selector '{$selector}' at '{$current_selector}': " . $e
      ->getMessage());
  } catch (\InvalidArgumentException $e) {
    $selector = implode('.', $sub_paths);
    $current_selector = implode('.', $current_selector);
    throw new InvalidArgumentException("Unable to apply data selector '{$selector}' at '{$current_selector}': " . $e
      ->getMessage());
  }
}