Completed
Push — master ( b04f33...04484f )
by Oscar
02:21
created

JsonValidator::fromFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use JsonSchema\Validator;
6
use Psr\Http\Message\ResponseInterface;
7
use Psr\Http\Message\ServerRequestInterface;
8
9
class JsonValidator
10
{
11
    /** @var \stdClass */
12
    private $schema;
13
14
    /**
15
     * JsonSchema constructor.
16
     * Consider using one of the following factories instead of invoking the controller directly:
17
     *  - JsonValidator::fromFile()
18
     *  - JsonValidator::fromEncodedString()
19
     *  - JsonValidator::fromDecodedObject()
20
     *  - JsonValidator::fromArray()
21
     *
22
     * @param \stdClass $schema A JSON-decoded object-representation of the schema.
23
     */
24
    public function __construct(\stdClass $schema)
25
    {
26
        $this->schema = $schema;
27
    }
28
29
    /**
30
     * @param \stdClass $schema
31
     * @return static|callable
32
     */
33
    public static function fromDecodedObject(\stdClass $schema)
34
    {
35
        return new static($schema);
36
    }
37
38
    /**
39
     * @param \SplFileObject $file
40
     * @return static|callable
41
     */
42
    public static function fromFile(\SplFileObject $file)
43
    {
44
        $schema = (object)[
45
            '$ref' => $file->getPathname(),
46
        ];
47
48
        return new static($schema);
49
    }
50
51
    /**
52
     * @param string $json
53
     * @return static|callable
54
     */
55
    public static function fromEncodedString($json)
56
    {
57
        return static::fromDecodedObject(json_decode($json, false));
58
    }
59
60
    /**
61
     * @param array $json
62
     * @return static|callable
63
     */
64
    public static function fromArray(array $json)
65
    {
66
        return static::fromEncodedString(json_encode($json, JSON_UNESCAPED_SLASHES));
67
    }
68
69
    /**
70
     * Execute the middleware.
71
     *
72
     * @param ServerRequestInterface $request
73
     * @param ResponseInterface $response
74
     * @param callable $next
75
     *
76
     * @return ResponseInterface
77
     * @throws \RuntimeException
78
     * @throws \InvalidArgumentException
79
     * @throws \JsonSchema\Exception\ExceptionInterface
80
     */
81
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
82
    {
83
        $value = $request->getParsedBody();
84
        if (!is_object($value)) {
85
            return $this->invalidateResponse(
86
                $response,
87
                sprintf('Parsed body must be an object. Type %s is invalid.', gettype($value))
88
            );
89
        }
90
91
        $validator = new Validator();
92
        $validator->check($value, $this->schema);
93
94
        if (!$validator->isValid()) {
95
            return $this->invalidateResponse(
96
                $response,
97
                'Unprocessable Entity',
98
                [
99
                    'Content-Type' => 'application/json',
100
                ],
101
                json_encode($validator->getErrors(), JSON_UNESCAPED_SLASHES)
102
            );
103
        }
104
105
        return $next($request, $response);
106
    }
107
108
    /**
109
     * @param ResponseInterface $response
110
     * @param string $reason
111
     * @param string[] $headers
112
     * @param string|null $body
113
     *
114
     * @return ResponseInterface
115
     * @throws \RuntimeException
116
     * @throws \InvalidArgumentException
117
     */
118
    private function invalidateResponse(ResponseInterface $response, $reason, array $headers = [], $body = null)
119
    {
120
        $response = $response->withStatus(422, $reason);
121
122
        foreach ($headers as $name => $value) {
123
            $response = $response->withHeader($name, $value);
124
        }
125
126
        if ($body !== null) {
127
            $stream = $response->getBody();
128
            $stream->write($body);
129
        }
130
131
        return $response;
132
    }
133
}
134