Completed
Push — master ( 8d26c4...37e57c )
by Radu
03:30
created

AbstractClientRequest::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
rs 10
1
<?php
2
namespace WebServCo\Api;
3
4
use WebServCo\Api\JsonApi\Document;
5
use WebServCo\Api\Exceptions\ApiException;
6
7
abstract class AbstractClientRequest
8
{
9
    protected $allowMultipleDataObjects;
10
    protected $request;
11
    protected $processRequestData;
12
    protected $requestData;
13
14
    const MSG_TPL_INVALID = 'Invalid data: %s';
15
    const MSG_TPL_MAXIMUM_LENGTH = 'Maximum length exceeded: %s (%s)';
16
    const MSG_TPL_REQUIRED = 'Missing required data: %s';
17
18
    public function __construct(
19
        \WebServCo\Framework\Interfaces\RequestInterface $request
20
    ) {
21
        $this->allowMultipleDataObjects = false;
22
        $this->request = $request;
23
        $requestMethod = $this->request->getMethod();
24
        if (in_array($requestMethod, [\WebServCo\Framework\Http\Method::POST])) {
25
            $this->processRequestData = true;
26
            $this->requestData = json_decode($this->request->getBody(), true);
27
        }
28
    }
29
30
    protected function throwInvalidException($item)
31
    {
32
        throw new ApiException(sprintf(self::MSG_TPL_INVALID, $item));
33
    }
34
35
    protected function throwMaximumLengthException($item, $maximumLength)
36
    {
37
        throw new ApiException(sprintf(self::MSG_TPL_MAXIMUM_LENGTH, $item, $maximumLength));
38
    }
39
40
    protected function throwRequiredException($item)
41
    {
42
        throw new ApiException(sprintf(self::MSG_TPL_REQUIRED, $item));
43
    }
44
45
    protected function verify()
46
    {
47
        $this->verifyContentType();
48
        if ($this->processRequestData) {
49
            $this->verifyRequestData();
50
        }
51
        return true;
52
    }
53
54
    protected function verifyContentType()
55
    {
56
        $contentType = $this->request->getContentType();
57
        $parts = explode(';', (string) $contentType);
58
        if ($parts[0] != Document::CONTENT_TYPE) {
59
            throw new \WebServCo\Framework\Exceptions\UnsupportedMediaTypeException(
60
                sprintf('Unsupported content type: %s.', (string) $contentType)
61
            );
62
        }
63
        return true;
64
    }
65
66
    protected function verifyRequestData()
67
    {
68
        if (!is_array($this->requestData)) {
69
            $this->throwInvalidException('root object');
70
        }
71
        foreach (['jsonapi', 'data'] as $item) {
72
            if (!isset($this->requestData[$item])) {
73
                $this->throwRequiredException($item);
74
            }
75
        }
76
        if (!isset($this->requestData['jsonapi']['version'])) {
77
            $this->throwRequiredException('jsonapi.version');
78
        }
79
        if ($this->requestData['jsonapi']['version'] != Document::VERSION) {
80
            throw new ApiException(
81
                sprintf('Unsupported JSON API version: %s', $this->requestData['jsonapi']['version'])
82
            );
83
        }
84
        if (!is_array($this->requestData['data'])) {
85
            $this->throwInvalidException('data');
86
        }
87
        $key = key($this->requestData['data']);
88
        if (0 === $key) { //multiple data objects
89
            if (!$this->allowMultipleDataObjects) {
90
                throw new ApiException('Multiple data objects not allowed for this endpoint');
91
            }
92
            foreach ($this->requestData['data'] as $item) {
93
                $this->verifyData($item);
94
            }
95
        } else { // single data object
96
            $this->verifyData($this->requestData['data']);
97
        }
98
        $this->verifyMeta();
99
100
        return true;
101
    }
102
103
    protected function verifyData($data)
104
    {
105
        foreach (['type', 'attributes'] as $item) {
106
            if (!isset($data[$item])) {
107
                $this->throwRequiredException(sprintf('data.%s', $item));
108
            }
109
        }
110
        if (empty($data['type'])) {
111
            $this->throwRequiredException('data.type');
112
        }
113
        if (!is_array($data['attributes'])) {
114
            $this->throwInvalidException('data.attributes');
115
        }
116
117
        return true;
118
    }
119
120
    protected function verifyMeta()
121
    {
122
        if (isset($this->requestData['meta'])) { // meta is optional
123
            if (!is_array($this->requestData['meta'])) {
124
                $this->throwInvalidException('meta');
125
            }
126
        }
127
    }
128
}
129