You are here

protected function JsonPathReplacer::extractTokenReplacements in Subrequests 8.2

Same name and namespace in other branches
  1. 3.x src/JsonPathReplacer.php \Drupal\subrequests\JsonPathReplacer::extractTokenReplacements()

Extracts the token replacements for a given subrequest.

Given a subrequest there can be N tokens to be replaced. Each token can result in an list of values to be replaced. Each token may refer to many subjects, if the subrequest referenced in the token ended up spawning multiple responses. This function detects the tokens and finds the replacements for each token. Then returns a data structure that contains a list of replacements. Each item contains all the replacement needed to get a response for the initial request, given a particular subject for a particular JSONPath replacement.

@returns array The structure containing a list of replacements for a subject response and a replacement candidate.

Parameters

\Drupal\subrequests\Subrequest $subrequest: The subrequest that contains the tokens.

string $token_location: Indicates if we are dealing with body or URI replacements.

\Symfony\Component\HttpFoundation\Response[] pool: The collection of prior responses available for use with JSONPath.

1 call to JsonPathReplacer::extractTokenReplacements()
JsonPathReplacer::replaceItem in src/JsonPathReplacer.php
Searches for JSONPath tokens in the request and replaces it with the values from previous responses.

File

src/JsonPathReplacer.php, line 253

Class

JsonPathReplacer

Namespace

Drupal\subrequests

Code

protected function extractTokenReplacements(Subrequest $subrequest, $token_location, array $pool) {

  // Turn the subject into a string.
  $regexp_subject = $token_location === 'body' ? Json::encode($subrequest->body) : $subrequest->uri;

  // First find all the replacements to do. Use a regular expression to detect
  // cases like "…{{req1.body@$.data.attributes.seasons..id}}…"
  $found = $this
    ->findTokens($regexp_subject);

  // Make sure that duplicated tokens in the same location are treated as the
  // same thing.
  $found = array_values(array_reduce($found, function ($carry, $match) {
    $carry[$match[0]] = $match;
    return $carry;
  }, []));

  // Then calculate the replacements we will need to return.
  $reducer = function ($token_replacements, $match) use ($pool) {

    // Remove the .body part at the end since we only support the body
    // replacement at this moment.
    $provided_id = preg_replace('/\\.body$/', '', $match[1]);

    // Calculate what are the subjects to execute the JSONPath against.
    $subjects = array_filter($pool, function (Response $response) use ($provided_id) {

      // The response is considered a subject if it matches the content ID or
      // it is a generated copy based of that content ID.
      $pattern = sprintf('/%s(#.*)?/', preg_quote($provided_id));
      $content_id = $this
        ->getContentId($response);
      return preg_match($pattern, $content_id);
    });
    if (count($subjects) === 0) {
      $candidates = array_map(function ($response) {
        $candidate = $this
          ->getContentId($response);
        return preg_replace('/#.*/', '', $candidate);
      }, $pool);
      throw new BadRequestHttpException(sprintf('Unable to find specified request for a replacement %s. Candidates are [%s].', $provided_id, implode(', ', $candidates)));
    }

    // Find the replacements for this match given a subject. If there is more
    // than one response object (a subject) for a given subrequest, then we
    // generate one parallel subrequest per subject.
    foreach ($subjects as $subject) {
      $this
        ->addReplacementsForSubject($match, $subject, $provided_id, $token_replacements);
    }
    return $token_replacements;
  };
  return array_reduce($found, $reducer, []);
}