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