Completed
Pull Request — 8.x-3.x (#448)
by Sebastian
03:12
created

QueryRouteEnhancer::extractParams()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 8
nc 2
nop 1
dl 0
loc 12
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\graphql\Routing;
4
5
use Drupal\Core\Routing\Enhancer\RouteEnhancerInterface;
6
use Drupal\graphql\QueryProvider\QueryProviderInterface;
7
use Symfony\Component\HttpFoundation\Request;
8
use Symfony\Component\Routing\Route;
9
10
class QueryRouteEnhancer implements RouteEnhancerInterface {
11
12
  const SINGLE = 'single';
13
  const BATCH = 'batch';
14
15
  /**
16
   * The query provider service.
17
   *
18
   * @var \Drupal\graphql\QueryProvider\QueryProviderInterface
19
   */
20
  protected $queryProvider;
21
22
  /**
23
   * QueryRouteEnhancer constructor.
24
   *
25
   * @param \Drupal\graphql\QueryProvider\QueryProviderInterface $queryProvider
26
   *   The query provider service.
27
   */
28
  public function __construct(QueryProviderInterface $queryProvider) {
29
    $this->queryProvider = $queryProvider;
30
  }
31
32
33
  /**
34
   * {@inheritdoc}
35
   */
36
  public function applies(Route $route) {
37
    return $route->hasDefault('_graphql');
38
  }
39
40
  /**
41
   * {@inheritdoc}
42
   */
43
  public function enhance(array $defaults, Request $request) {
44
    if (!empty($defaults['_controller'])) {
45
      return $defaults;
46
    }
47
48
    $params = $this->extractParams($request);
49
    if ($enhanced = $this->enhanceSingle($defaults, $params, $request)) {
50
      return $enhanced;
51
    }
52
53
    if ($enhanced = $this->enhanceBatch($defaults, $params, $request)) {
54
      return $enhanced;
55
    }
56
57
    // By default we assume a 'single' request. This is going to fail in the
58
    // graphql processor due to a missing query string but at least provides
59
    // the right format for the client to act upon.
60
    return $defaults + [
61
      '_controller' => $defaults['_graphql']['single'],
62
    ];
63
  }
64
65
  /**
66
   * Attempts to enhance the request as a batch query.
67
   *
68
   * @param array $defaults
69
   *   The controller defaults.
70
   * @param array $params
71
   *   The query parameters.
72
   * @param \Symfony\Component\HttpFoundation\Request $request
73
   *   The request object.
74
   *
75
   * @return array|bool
76
   *   The enhanced controller defaults.
77
   */
78
  protected function enhanceBatch(array $defaults, array $params, Request $request) {
79
    // PHP 5.5.x does not yet support the ARRAY_FILTER_USE_KEYS constant.
80
    $keys = array_filter(array_keys($params), function($index) {
81
      return is_numeric($index);
82
    });
83
84
    $queries = array_intersect_key($params, array_flip($keys));
85
    if (!isset($queries[0])) {
86
      return FALSE;
87
    }
88
89
    if (array_keys($queries) !== range(0, count($queries) - 1)) {
90
      // If this is not a continuously numeric array, don't do anything.
91
      return FALSE;
92
    }
93
94
    return $defaults + [
95
      '_controller' => $defaults['_graphql']['multiple'],
96
      'queries' => $queries,
97
      'type' => static::BATCH,
98
    ];
99
  }
100
101
  /**
102
   * Attempts to enhance the request as a single query.
103
   *
104
   * @param array $defaults
105
   *   The controller defaults.
106
   * @param array $params
107
   *   The query parameters.
108
   * @param \Symfony\Component\HttpFoundation\Request $request
109
   *   The request object.
110
   *
111
   * @return array|boolean
112
   *   The enhanced controller defaults.
113
   */
114
  protected function enhanceSingle(array $defaults, array $params, Request $request) {
115
    $values = $params + [
116
      'query' => empty($params['query']) ? $this->queryProvider->getQuery($params) : $params['query'],
117
      'variables' => [],
118
    ];
119
120
    if (empty($values['query'])) {
121
      return FALSE;
122
    }
123
124
    return $defaults + [
125
      '_controller' => $defaults['_graphql']['single'],
126
      'query' => $values['query'] ?: '',
127
      'variables' => $values['variables'] ?: [],
128
      'persisted' => empty($params['query']),
129
      'type' => static::SINGLE,
130
    ];
131
  }
132
133
  /**
134
   * Extract an associative array of query parameters from the request.
135
   *
136
   * If the given request does not have any POST body content it uses the GET
137
   * query parameters instead.
138
   *
139
   * @param \Symfony\Component\HttpFoundation\Request $request
140
   *   The request object.
141
   *
142
   * @return array
143
   *   An associative array of query parameters.
144
   */
145
  protected function extractParams(Request $request) {
146
    $values = ($content = $request->getContent()) ? json_decode($content, TRUE) : $request->query->all();
147
148
    return array_map(function($value) {
149
      if (!is_string($value)) {
150
        return $value;
151
      }
152
153
      $decoded = json_decode($value, TRUE);
154
      return ($decoded != $value) && $decoded ? $decoded : $value;
155
    }, $values ?: []);
156
  }
157
158
}
159