Completed
Pull Request — 1.x (#214)
by Yuu
03:24 queued 55s
created

HalRenderer::getReverseMatchedLink()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
ccs 4
cts 4
cp 1
rs 9.4285
cc 3
eloc 8
nc 4
nop 1
crap 3
1
<?php
2
/**
3
 * This file is part of the BEAR.Resource package
4
 *
5
 * @license http://opensource.org/licenses/MIT MIT
6
 */
7
namespace BEAR\Package\Provide\Representation;
8
9
use BEAR\Resource\AbstractUri;
10
use BEAR\Resource\Annotation\Link;
11
use BEAR\Resource\RenderInterface;
12
use BEAR\Resource\RequestInterface;
13
use BEAR\Resource\ResourceObject;
14
use BEAR\Resource\Uri;
15
use BEAR\Sunday\Extension\Router\RouterInterface;
16
use Doctrine\Common\Annotations\Reader;
17
use Nocarrier\Hal;
18
19
/**
20
 * HAL(Hypertext Application Language) renderer
21
 */
22
class HalRenderer implements RenderInterface
23
{
24
    /**
25
     * @var Reader
26
     */
27
    private $reader;
28
29
    /**
30
     * @var RouterInterface
31
     */
32
    private $router;
33
34
    /**
35
     * @param Reader          $reader
36
     * @param RouterInterface $router
37
     */
38 6
    public function __construct(Reader $reader, RouterInterface $router)
39
    {
40 6
        $this->reader = $reader;
41 6
        $this->router = $router;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47 4
    public function render(ResourceObject $ro)
48
    {
49
        list($ro, $body) = $this->valuate($ro);
50
51
        $method = 'on' . ucfirst($ro->uri->method);
52
        $hasMethod = method_exists($ro, $method);
53 4
        if (! $hasMethod) {
54 1
            $ro->view = ''; // OPTIONS request no view
55
56 1
            return '';
57
        }
58
        $annotations = ($hasMethod) ? $this->reader->getMethodAnnotations(new \ReflectionMethod($ro, $method)) : [];
59
        /* @var $annotations Link[] */
60
        /* @var $ro ResourceObject */
61
        $hal = $this->getHal($ro->uri, $body, $annotations);
62
        $ro->view = $hal->asJson(true) . PHP_EOL;
63 3
        $ro->headers['content-type'] = 'application/hal+json';
64
65 3
        return $ro->view;
66 4
    }
67
68
    /**
69
     * @param \BEAR\Resource\ResourceObject $ro
70
     */
71 2
    private function valuateElements(ResourceObject &$ro)
72
    {
73 2
        foreach ($ro->body as $key => &$element) {
74
            if ($element instanceof RequestInterface) {
75 1
                unset($ro->body[$key]);
76
                $view = $this->render($element());
77
                $ro->body['_embedded'][$key] = json_decode($view);
78
            }
79
        }
80
    }
81
82
    /**
83
     * @param Uri   $uri
84
     * @param array $body
85
     * @param array $annotations
86
     *
87
     * @return Hal
88
     */
89 3
    private function getHal(AbstractUri $uri, array $body, array $annotations)
90
    {
91 1
        $query = $uri->query ? '?' . http_build_query($uri->query) : '';
92 3
        $path = $uri->path . $query;
93
        $selfLink = $this->getReverseMatchedLink($path);
94
        $hal = new Hal($selfLink, $body);
95
        $this->getHalLink($body, $annotations, $hal);
96
97 3
        return $hal;
98 3
    }
99
100
    /**
101
     * @param string $uri
102
     *
103
     * @return mixed
104
     */
105 1
    private function getReverseMatchedLink($uri)
106
    {
107
        $urlParts = parse_url($uri);
108 1
        $routeName = $urlParts['path'];
109 1
        isset($urlParts['query']) ? parse_str($urlParts['query'], $value) : $value = [];
110
        $reverseUri = $this->router->generate($routeName, (array) $value);
111
        if (is_string($reverseUri)) {
112
            return $reverseUri;
113
        }
114
115 1
        return $uri;
116
    }
117
118
    /**
119
     * @param ResourceObject $ro
120
     *
121
     * @return array [ResourceObject, array]
122
     */
123 4
    private function valuate(ResourceObject $ro)
124
    {
125
        // evaluate all request in body.
126
        if (is_array($ro->body)) {
127
            $this->valuateElements($ro);
128
        }
129
        // HAL
130 4
        $body = $ro->body ?: [];
131
        if (is_scalar($body)) {
132 1
            $body = ['value' => $body];
133
134 1
            return [$ro, $body];
135
        }
136
137 3
        return[$ro, (array) $body];
138 4
    }
139
140
    /**
141
     * @param array $body
142
     * @param array $links
143
     * @param Hal   $hal
144
     *
145
     * @internal param Uri $uri
146
     */
147 1
    private function getHalLink(array $body, array $links, Hal $hal)
148
    {
149
        foreach ($links as $link) {
150 1
            if (! $link instanceof Link) {
151 1
                continue;
152
            }
153
            $uri = uri_template($link->href, $body);
154
            $reverseUri = $this->getReverseMatchedLink($uri);
155
            $hal->addLink($link->rel, $reverseUri);
156 1
        }
157
    }
158
}
159