Completed
Pull Request — 8.x-3.x (#1028)
by
unknown
08:03
created

QueryRouteEnhancer::applies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\graphql\Routing;
4
5
use Drupal\Component\Utility\NestedArray;
6
use Drupal\Core\Routing\EnhancerInterface;
7
use Drupal\graphql\GraphQL\QueryProvider\QueryProviderInterface;
8
use Drupal\graphql\Utility\JsonHelper;
9
use GraphQL\Server\Helper;
10
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
11
use Symfony\Component\HttpFoundation\Request;
12
use Symfony\Component\Routing\Route;
13
14
class QueryRouteEnhancer implements EnhancerInterface {
15
16
  /**
17
   * {@inheritdoc}
18
   */
19
  public function enhance(array $defaults, Request $request) {
20
    $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
21
    if ($route->hasDefault('_graphql')) {
22
      $helper = new Helper();
23
      $method = $request->getMethod();
24
      $body = $this->extractBody($request);
25
      $query = $this->extractQuery($request);
26
      $operations = $helper->parseRequestParams($method, $body, $query);
27
28
      // By default we assume a 'single' request. This is going to fail in the
29
      // graphql processor due to a missing query string but at least provides
30
      // the right format for the client to act upon.
31
      return $defaults + [
32
        '_controller' => $defaults['_graphql']['single'],
33
        'operations' => $operations,
34
      ];
35
    }
36
  }
37
38
  /**
39
   * Extracts the query parameters from a request.
40
   *
41
   * @param \Symfony\Component\HttpFoundation\Request $request
42
   *   The http request object.
43
   *
44
   * @return array
45
   *   The normalized query parameters.
46
   */
47
  protected function extractQuery(Request $request) {
48
    return JsonHelper::decodeParams($request->query->all());
49
  }
50
51
  /**
52
   * Extracts the body parameters from a request.
53
   *
54
   * @param \Symfony\Component\HttpFoundation\Request $request
55
   *   The http request object.
56
   *
57
   * @return array
58
   *   The normalized body parameters.
59
   */
60
  protected function extractBody(Request $request) {
61
    $values = [];
62
63
    // Extract the request content.
64
    if ($content = json_decode($request->getContent(), TRUE)) {
65
      $values = array_merge($values, JsonHelper::decodeParams($content));
66
    }
67
68
    if (stripos($request->headers->get('content-type'), 'multipart/form-data') !== FALSE) {
69
      return $this->extractMultipart($request, $values);
70
    }
71
72
    return $values;
73
  }
74
75
  /**
76
   * Handles file uploads from multipart/form-data requests.
77
   *
78
   * @return array
79
   *   The query parameters with added file uploads.
80
   */
81
  protected function extractMultipart(Request $request, $values) {
82
    // The request body parameters might contain file upload mutations. We treat
83
    // them according to the graphql multipart request specification.
84
    //
85
    // @see https://github.com/jaydenseric/graphql-multipart-request-spec#server
86
    if ($body = JsonHelper::decodeParams($request->request->all())) {
87
      // Flatten the operations array if it exists.
88
      $operations = isset($body['operations']) && is_array($body['operations']) ? $body['operations'] : [];
89
      $values = array_merge($values, $body, $operations);
90
    }
91
92
    // According to the graphql multipart request specification, uploaded files
93
    // are referenced to variable placeholders in a map. Here, we resolve this
94
    // map by assigning the uploaded files to the corresponding variables.
95
    if (!empty($values['map']) && is_array($values['map']) && $files = $request->files->all()) {
96
      foreach ($files as $key => $file) {
97
        if (!isset($values['map'][$key])) {
98
          continue;
99
        }
100
101
        $paths = (array) $values['map'][$key];
102
        foreach ($paths as $path) {
103
          $path = explode('.', $path);
104
105
          if (NestedArray::keyExists($values, $path)) {
106
            NestedArray::setValue($values, $path, $file);
107
          }
108
        }
109
      }
110
    }
111
112
    return $values;
113
  }
114
115
116
}
117