Completed
Push — 1.x ( abde83...7c6f23 )
by Akihito
13s
created

HalRenderer   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 96.3%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 6
dl 0
loc 120
ccs 52
cts 54
cp 0.963
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A render() 0 15 3
A renderHal() 0 11 1
A valuateElements() 0 16 4
A isDifferentSchema() 0 4 1
A getHal() 0 11 2
A valuate() 0 16 4
A updateHeaders() 0 7 2
1
<?php
2
/**
3
 * This file is part of the BEAR.Package package.
4
 *
5
 * @license http://opensource.org/licenses/MIT MIT
6
 */
7
namespace BEAR\Package\Provide\Representation;
8
9
use BEAR\Resource\AbstractRequest;
10
use BEAR\Resource\AbstractUri;
11
use BEAR\Resource\Annotation\Link;
12
use BEAR\Resource\RenderInterface;
13
use BEAR\Resource\ResourceInterface;
14
use BEAR\Resource\ResourceObject;
15
use Doctrine\Common\Annotations\Reader;
16
use Nocarrier\Hal;
17
18
/**
19
 * HAL(Hypertext Application Language) renderer
20
 */
21
class HalRenderer implements RenderInterface
22
{
23
    /**
24
     * @var Reader
25
     */
26
    private $reader;
27
28
    /**
29
     * @var ResourceInterface
30
     */
31
    private $resource;
32
33
    /**
34
     * @var HalLink
35
     */
36
    private $link;
37
38 14
    public function __construct(Reader $reader, ResourceInterface $resource, HalLink $link)
39
    {
40 14
        $this->reader = $reader;
41 14
        $this->resource = $resource;
42 14
        $this->link = $link;
43 14
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48 12
    public function render(ResourceObject $ro)
49
    {
50 12
        if ($ro->view) {
51 1
            return $ro->view;
52
        }
53 11
        $method = 'on' . ucfirst($ro->uri->method);
54 11
        if (! method_exists($ro, $method)) {
55
            $ro->view = ''; // no view for OPTIONS request
56
57
            return '';
58
        }
59 11
        $annotations = $this->reader->getMethodAnnotations(new \ReflectionMethod($ro, $method));
60
61 11
        return $this->renderHal($ro, $annotations);
62
    }
63
64 11
    private function renderHal(ResourceObject $ro, $annotations) : string
65
    {
66 11
        list($ro, $body) = $this->valuate($ro);
67
        /* @var $annotations Link[] */
68
        /* @var $ro ResourceObject */
69 11
        $hal = $this->getHal($ro->uri, $body, $annotations);
70 11
        $ro->view = $hal->asJson(true) . PHP_EOL;
71 11
        $this->updateHeaders($ro);
72
73 11
        return $ro->view;
74
    }
75
76 9
    private function valuateElements(ResourceObject &$ro)
77
    {
78 9
        foreach ($ro->body as $key => &$embeded) {
79 9
            if ($embeded instanceof AbstractRequest) {
80 2
                $isDefferentSchema = $this->isDifferentSchema($ro, $embeded->resourceObject);
81 2
                if ($isDefferentSchema === true) {
82 1
                    $ro->body['_embedded'][$key] = $embeded()->body;
83 1
                    unset($ro->body[$key]);
84 1
                    continue;
85
                }
86 1
                unset($ro->body[$key]);
87 1
                $view = $this->render($embeded());
88 9
                $ro->body['_embedded'][$key] = json_decode($view);
89
            }
90
        }
91 9
    }
92
93
    /**
94
     * Return "is different schema" (page <-> app)
95
     */
96 2
    private function isDifferentSchema(ResourceObject $parentRo, ResourceObject $childRo) : bool
97
    {
98 2
        return $parentRo->uri->scheme . $parentRo->uri->host !== $childRo->uri->scheme . $childRo->uri->host;
99
    }
100
101 11
    private function getHal(AbstractUri $uri, array $body, array $annotations) : Hal
102
    {
103 11
        $query = $uri->query ? '?' . http_build_query($uri->query) : '';
104 11
        $path = $uri->path . $query;
105 11
        $selfLink = $this->link->getReverseLink($path);
106
107 11
        $hal = new Hal($selfLink, $body);
108 11
        $hal = $this->link->addHalLink($body, $annotations, $hal);
109
110 11
        return $hal;
111
    }
112
113
    /**
114
     * @return array [ResourceObject, array]
115
     */
116 11
    private function valuate(ResourceObject $ro) : array
117
    {
118
        // evaluate all request in body.
119 11
        if (is_array($ro->body)) {
120 9
            $this->valuateElements($ro);
121
        }
122
        // HAL
123 11
        $body = $ro->body ?: [];
124 11
        if (is_scalar($body)) {
125 1
            $body = ['value' => $body];
126
127 1
            return [$ro, $body];
128
        }
129
130 10
        return[$ro, (array) $body];
131
    }
132
133 11
    private function updateHeaders(ResourceObject $ro)
134
    {
135 11
        $ro->headers['content-type'] = 'application/hal+json';
136 11
        if (isset($ro->headers['Location'])) {
137 3
            $ro->headers['Location'] = $this->link->getReverseLink($ro->headers['Location']);
138
        }
139 11
    }
140
}
141