Completed
Push — hal-link ( 2c1f46 )
by Akihito
02:27
created

HalRenderer::getReverseMatchedLink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Resource;
6
7
use BEAR\Resource\Annotation\Link;
8
use Doctrine\Common\Annotations\Reader;
9
use function is_array;
10
use Nocarrier\Hal;
11
12
class HalRenderer implements RenderInterface
13
{
14
    /**
15
     * @var Reader
16
     */
17
    private $reader;
18
19
    /**
20
     * @var HalLink
21
     */
22
    private $link;
23
24
    public function __construct(Reader $reader, HalLink $link)
25
    {
26
        $this->reader = $reader;
27
        $this->link = $link;
28
    }
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function render(ResourceObject $ro)
34
    {
35
        $this->renderHal($ro);
36
        $this->updateHeaders($ro);
37
38
        return (string) $ro->view;
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     *
44
     * @throws \RuntimeException
45
     */
46
    public function renderHal(ResourceObject $ro)
47
    {
48
        [$ro, $body] = $this->valuate($ro);
0 ignored issues
show
Bug introduced by
The variable $body does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
49
        $method = 'on' . ucfirst($ro->uri->method);
50
        $hasMethod = method_exists($ro, $method);
51
        $annotations = $hasMethod ? $this->reader->getMethodAnnotations(new \ReflectionMethod($ro, $method)) : [];
52
        /* @var $annotations Link[] */
53
        $hal = $this->getHal($ro->uri, $body, $annotations);
54
        $ro->view = $hal->asJson(true) . PHP_EOL;
55
        $ro->headers['Content-Type'] = 'application/hal+json';
56
    }
57
58
    private function valuateElements(ResourceObject $ro)
59
    {
60
        foreach ($ro->body as $key => &$embeded) {
61
            if ($embeded instanceof AbstractRequest) {
62
                // @codeCoverageIgnoreStart
63
                if ($this->isDifferentSchema($ro, $embeded->resourceObject)) {
64
                    $ro->body['_embedded'][$key] = $embeded()->body;
65
                    unset($ro->body[$key]);
66
67
                    continue;
68
                }
69
                // @codeCoverageIgnoreEnd
70
                unset($ro->body[$key]);
71
                $view = $this->render($embeded());
72
                $ro->body['_embedded'][$key] = json_decode($view);
73
            }
74
        }
75
    }
76
77
    /**
78
     * @codeCoverageIgnore
79
     */
80
    private function isDifferentSchema(ResourceObject $parentRo, ResourceObject $childRo) : bool
81
    {
82
        return $parentRo->uri->scheme . $parentRo->uri->host !== $childRo->uri->scheme . $childRo->uri->host;
83
    }
84
85
    private function getReverseMatchedLink(string $uri) : string
86
    {
87
        return $uri;
88
    }
89
90
    private function getHal(AbstractUri $uri, array $body, array $annotations) : Hal
91
    {
92
        $query = $uri->query ? '?' . http_build_query($uri->query) : '';
93
        $path = $uri->path . $query;
94
        $selfLink = $this->getReverseMatchedLink($path);
95
        $hal = new Hal($selfLink, $body);
96
97
        return $this->link->addHalLink($body, $annotations, $hal);
98
    }
99
100
    private function valuate(ResourceObject $ro) : array
101
    {
102
        $ro->body = is_array($ro->body) ? $ro->body : ['value' => $ro->body];
103
        // evaluate all request in body.
104
        $this->valuateElements($ro);
105
106
        return [$ro, $ro->body];
107
    }
108
109
    private function updateHeaders(ResourceObject $ro)
110
    {
111
        $ro->headers['content-type'] = 'application/hal+json';
112
        if (isset($ro->headers['Location'])) {
113
            $ro->headers['Location'] = $this->link->getReverseLink($ro->headers['Location']);
114
        }
115
    }
116
}
117