Completed
Pull Request — 8.x-3.x (#525)
by Philipp
02:28
created

QueryRouteEnhancer::extractMultipart()   C

Complexity

Conditions 11
Paths 10

Size

Total Lines 33
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 14
nc 10
nop 2
dl 0
loc 33
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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