Representation   B
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 90.83%

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 8
dl 0
loc 266
ccs 99
cts 109
cp 0.9083
rs 8.2857
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A create() 0 4 1
B handleExposureSettingsFromHttpMethod() 0 27 6
B getDeterminedRepresentation() 0 20 5
A handlePullExposureConfiguration() 0 13 1
A handlePushExposureConfiguration() 0 16 1
A getRepresentationClasses() 0 6 3
B searchAndValidateRepresentations() 0 22 6
A matchRepresentation() 0 16 4
B determineRepresentationByHttpMethod() 0 21 7
A getRepresentationClassName() 0 13 4
1
<?php
2
/**
3
 * This file is part of the Drest package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author Lee Davis
9
 * @copyright Copyright (c) Lee Davis <@leedavis81>
10
 * @link https://github.com/leedavis81/drest/blob/master/LICENSE
11
 * @license http://opensource.org/licenses/MIT The MIT X License (MIT)
12
 */
13
namespace Drest\Manager;
14
15
use Drest\EntityManagerRegistry;
16
use Drest\Mapping\RouteMetaData;
17
use Drest\Configuration;
18
use Drest\Query\ExposeFields;
19
use DrestCommon\Representation\RepresentationException;
20
use DrestCommon\Representation\UnableToMatchRepresentationException;
21
use DrestCommon\Representation\AbstractRepresentation;
22
use DrestCommon\Request\Request;
23
24
class Representation
25
{
26
27
    /**
28
     * Drest configuration object - referenced to same instance used in Manager
29
     * @var Configuration $config
30
     */
31
    protected $config;
32
33
    /**
34
     * A request instance for inspection
35
     * Reset on each getDeterminedRepresentation()
36
     * @var Request $request
37
     */
38
    protected $request;
39
40
    /**
41
     * Doctrine Entity Manager Registry
42
     * @var EntityManagerRegistry $emr
43
     */
44
    protected $emr;
45
46
    /**
47
     * @param Configuration $config
48
     */
49 31
    public function __construct(Configuration &$config)
50
    {
51 31
        $this->config = &$config;
52 31
    }
53
54
    /**
55
     * Static call to create a representation instance
56
     * @param Configuration $config
57
     * @return Representation
58
     */
59 31
    public static function create(Configuration &$config)
60
    {
61 31
        return new self($config);
62
    }
63
64
    /**
65
     * @param Request $request
66
     * @param RouteMetaData $route
67
     * @param EntityManagerRegistry $emr
68
     * @return AbstractRepresentation
69
     */
70 25
    public function handleExposureSettingsFromHttpMethod($request, $route, EntityManagerRegistry $emr)
71
    {
72 25
        $this->emr = $emr;
73 25
        $this->request = $request;
74
75 25
        $representation = $this->getDeterminedRepresentation($request, $route);
76
77
        // If expose setting lookup isn't disabled, determine it
78 25
        if (!$route->isExposeDisabled())
0 ignored issues
show
Bug introduced by
It seems like $route is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
79 25
        {
80 25
            switch ($request->getHttpMethod())
81
            {
82
                // Match on content option
83 25
                case Request::METHOD_GET:
84 18
                    $this->handlePullExposureConfiguration($route);
85 18
                    break;
86
                // Match on content-type
87 7
                case Request::METHOD_POST:
88 7
                case Request::METHOD_PUT:
89 7
                case Request::METHOD_PATCH:
90 3
                    $representation = $this->handlePushExposureConfiguration($route, $representation);
91 3
                    break;
92 25
            }
93 25
        }
94
95 25
        return $representation;
96
    }
97
98
    /**
99
     * Detect an instance of a representation class using a matched route, or default representation classes
100
     * @param  Request                      $request
101
     * @param  RouteMetaData                $route
102
     * @throws UnableToMatchRepresentationException
103
     * @throws RepresentationException              - if unable to instantiate a representation object from config settings
104
     * @return AbstractRepresentation               $representation
105
     */
106 26
    public function getDeterminedRepresentation(Request $request, RouteMetaData &$route = null)
107
    {
108 26
        $this->request = $request;
109
110 26
        if (($representations = $this->getRepresentationClasses($route)) === []) {
111
            $name = (is_null($route)) ? '"unknown name"' : $route->getName();
112
            $className = (is_null($route)) ? '"unknown class"' : $route->getClassMetaData()->getClassName();
113
            throw RepresentationException::noRepresentationsSetForRoute(
114
                $name,
115
                $className
116
            );
117
        }
118
119 26
        if (($representation = $this->searchAndValidateRepresentations($representations)) !== null) {
120 26
            return $representation;
121
        }
122
123
        // We have no representation instances from either annotations or config object
124
        throw UnableToMatchRepresentationException::noMatch();
125
    }
126
127
128
    /**
129
     * Handle a pull requests' exposure configuration (GET)
130
     * @param RouteMetaData          $route (referenced object)
131
     */
132 18
    protected function handlePullExposureConfiguration(RouteMetaData &$route)
133
    {
134 18
        $route->setExpose(
135 18
            ExposeFields::create($route)
136 18
                ->configureExposeDepth(
137 18
                    $this->emr,
138 18
                    $this->config->getExposureDepth(),
139 18
                    $this->config->getExposureRelationsFetchType()
140 18
                )
141 18
                ->configurePullRequest($this->config->getExposeRequestOptions(), $this->request)
142 18
                ->toArray()
143 18
        );
144 18
    }
145
146
    /**
147
     * Handle a push requests' exposure configuration (POST/PUT/PATCH)
148
     * @param  RouteMetaData          $route          - the matched route
149
     * @param  AbstractRepresentation $representation - the representation class to be used
150
     * @return AbstractRepresentation $representation
151
     */
152 3
    protected function handlePushExposureConfiguration(RouteMetaData $route, AbstractRepresentation $representation)
153
    {
154 3
        $representation = $representation::createFromString($this->request->getBody());
155
        // Write the filtered expose data
156 3
        $representation->write(
157 3
            ExposeFields::create($route)
158 3
                ->configureExposeDepth(
159 3
                    $this->emr,
160 3
                    $this->config->getExposureDepth(),
161 3
                    $this->config->getExposureRelationsFetchType()
162 3
                )
163 3
                ->configurePushRequest($representation->toArray())
164 3
        );
165
166 3
        return $representation;
167
    }
168
169
    /**
170
     * Get representation options. Determined from route or config
171
     * @param RouteMetaData|null $route
172
     * @return array
173
     */
174 26
    protected function getRepresentationClasses(RouteMetaData &$route = null)
175
    {
176 26
        return (is_null($route) || [] === $route->getClassMetaData()->getRepresentations())
177 26
            ? $this->config->getDefaultRepresentations()
178 26
            : $route->getClassMetaData()->getRepresentations();
179
    }
180
181
182
    /**
183
     * Iterate through an array of representations and return a match
184
     * @param array $representations
185
     * @return AbstractRepresentation|null
186
     * @throws RepresentationException
187
     * @throws UnableToMatchRepresentationException
188
     */
189 26
    protected function searchAndValidateRepresentations(array $representations)
190
    {
191 26
        $representationObjects = [];
192 26
        foreach ($representations as $representation) {
193 26
            if (($representationObj = $this->matchRepresentation($representation, $representationObjects)) instanceof AbstractRepresentation)
194 26
            {
195 17
                return $representationObj;
196
            }
197 22
        }
198
199
        // For get requests with "415 for no media match" set on, throw an exception
200 9
        if ($this->request->getHttpMethod() == Request::METHOD_GET && $this->config->get415ForNoMediaMatchSetting()) {
201
            throw UnableToMatchRepresentationException::noMatch();
202
        }
203
204
        // Return the first instantiated representation instance
205 9
        if (isset($representationObjects[0])) {
206 9
            return $representationObjects[0];
207
        }
208
209
        return null;
210
    }
211
212
213
    /**
214
     * Attempt to match a representation
215
     *
216
     * @param AbstractRepresentation|string $representation
217
     * @param array $representationObjects
218
     * @return AbstractRepresentation|null
219
     * @throws RepresentationException
220
     */
221 26
    protected function matchRepresentation($representation, array &$representationObjects)
222
    {
223 26
        if (!is_object($representation)) {
224 26
            $className = $this->getRepresentationClassName($representation);
225 26
            $representationObjects[] = $representation = new $className();
226 26
        }
227 26
        if (!$representation instanceof AbstractRepresentation) {
228
            throw RepresentationException::representationMustBeInstanceOfDrestRepresentation();
229
        }
230
231 26
        if (($representation = $this->determineRepresentationByHttpMethod($representation, $this->config->getDetectContentOptions())) !== null)
232 26
        {
233 17
            return $representation;
234
        }
235 22
        return null;
236
    }
237
238
    /**
239
     * Determine the representation by inspecting the HTTP method
240
     * @param AbstractRepresentation $representation
241
     * @param array $detectContentOptions - Eg array(self::DETECT_CONTENT_HEADER => 'Accept')
242
     * @return AbstractRepresentation|null
243
     */
244 26
    protected function determineRepresentationByHttpMethod(AbstractRepresentation $representation, array $detectContentOptions = [])
245
    {
246 26
        switch ($this->request->getHttpMethod()) {
247
            // Match on content option
248 26
            case Request::METHOD_GET:
249
                // This representation matches the required media type requested by the client
250 19
                if ($representation->isExpectedContent($detectContentOptions, $this->request)) {
251 16
                    return $representation;
252
                }
253 16
                break;
254
            // Match on content-type
255 7
            case Request::METHOD_POST:
256 7
            case Request::METHOD_PUT:
257 7
            case Request::METHOD_PATCH:
258 3
                if ($representation->getContentType() === $this->request->getHeaders('Content-Type')) {
259 1
                    return $representation;
260
                }
261 2
                break;
262 22
        }
263 22
        return null;
264
    }
265
266
267
    /**
268
     * Get's the representation class name.
269
     * Removes any root NS chars
270
     * Falls back to a DrestCommon Representation lookup
271
     *
272
     * @param string $representation
273
     * @return string
274
     * @throws RepresentationException
275
     */
276 26
    protected function getRepresentationClassName($representation)
277
    {
278 26
        $className = (strstr($representation, '\\') !== false)
279 26
            ? '\\' . ltrim($representation, '\\')
280 26
            : $representation;
281 26
        $className = (!class_exists($className))
282 26
            ? '\\DrestCommon\\Representation\\' . ltrim($className, '\\')
283 26
            : $className;
284 26
        if (!class_exists($className)) {
285
            throw RepresentationException::unknownRepresentationClass($representation);
286
        }
287 26
        return $className;
288
    }
289
}