Passed
Pull Request — master (#115)
by Dmitriy
14:06
created

ViewRenderer::getName()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 15
rs 10
1
<?php
2
3
namespace App;
4
5
use Psr\Http\Message\ResponseInterface;
6
use Yiisoft\Aliases\Aliases;
7
use Yiisoft\Strings\Inflector;
8
use Yiisoft\View\ViewContextInterface;
9
use Yiisoft\View\WebView;
10
use Yiisoft\Yii\Web\Data\DataResponseFactoryInterface;
11
use Yiisoft\Yii\Web\User\User;
12
13
final class ViewRenderer implements ViewContextInterface
14
{
15
    protected ?string $name = null;
16
    protected DataResponseFactoryInterface $responseFactory;
17
    protected User $user;
18
19
    private Aliases $aliases;
20
    private WebView $view;
21
    private string $layout;
22
    private ?string $viewPath = null;
23
    private ?string $viewBasePath = null;
24
25
    public function __construct(
26
        DataResponseFactoryInterface $responseFactory,
27
        User $user,
28
        Aliases $aliases,
29
        WebView $view
30
    )
31
    {
32
        $this->responseFactory = $responseFactory;
33
        $this->user = $user;
34
        $this->aliases = $aliases;
35
        $this->view = $view;
36
        $this->layout = '@views/layout/main';
37
    }
38
39
    public function getViewPath(): string
40
    {
41
        if ($this->viewPath !== null) {
42
            return $this->viewPath;
43
        }
44
45
        if ($this->viewBasePath !== null) {
46
            return $this->aliases->get($this->viewBasePath) . '/' . $this->name;
47
        }
48
49
        return $this->aliases->get('@views') . '/' . $this->name;
50
    }
51
52
    public function render(string $view, array $parameters = []): ResponseInterface
53
    {
54
        $contentRenderer = fn() => $this->renderProxy($view, $parameters);
55
56
        return $this->responseFactory->createResponse($contentRenderer);
57
    }
58
59
    public function renderPartial(string $view, array $parameters = []): ResponseInterface
60
    {
61
        $content = $this->view->render($view, $parameters, $this);
62
63
        return $this->responseFactory->createResponse($content);
64
    }
65
66
    public function withController(object $controller): self
67
    {
68
        $new = clone $this;
69
        $new->name = $this->getName($controller);
70
71
        return $new;
72
    }
73
74
    public function withControllerName(string $name): self
75
    {
76
        $new = clone $this;
77
        $new->name = $name;
78
79
        return $new;
80
    }
81
82
    public function withViewPath(string $viewPath): self
83
    {
84
        $new = clone $this;
85
        $new->viewPath = $viewPath;
86
87
        return $new;
88
    }
89
90
    public function withViewBasePath(string $viewBasePath): self
91
    {
92
        $new = clone $this;
93
        $new->viewBasePath = $viewBasePath;
94
95
        return $new;
96
    }
97
98
    public function withLayout(string $layout): self
99
    {
100
        $new = clone $this;
101
        $new->layout = $layout;
102
103
        return $new;
104
    }
105
106
    private function renderProxy(string $view, array $parameters = []): string
107
    {
108
        $content = $this->view->render($view, $parameters, $this);
109
        $user = $this->user->getIdentity();
110
        $layout = $this->findLayoutFile($this->aliases->get($this->layout));
111
112
        if ($layout === null) {
0 ignored issues
show
introduced by
The condition $layout === null is always false.
Loading history...
113
            return $content;
114
        }
115
        return $this->view->renderFile(
116
            $layout,
117
            [
118
                'content' => $content,
119
                'user' => $user,
120
            ],
121
            $this
122
        );
123
    }
124
125
    private function findLayoutFile(?string $file): ?string
126
    {
127
        if ($file === null) {
128
            return null;
129
        }
130
131
        if (pathinfo($file, PATHINFO_EXTENSION) !== '') {
132
            return $file;
133
        }
134
135
        return $file . '.' . $this->view->getDefaultExtension();
136
    }
137
138
    /**
139
     * Returns the controller name. Name should be converted to "id" case.
140
     * Method returns classname without `controller` on the ending.
141
     * If namespace is not contain `controller` or `controllers`
142
     * then returns only classname without `controller` on the ending
143
     * else returns all subnamespaces from `controller` (or `controllers`) to the end
144
     *
145
     * @return string
146
     * @example App\Controller\FooBar\BazController -> foo-bar/baz
147
     * @example App\Controllers\FooBar\BazController -> foo-bar/baz
148
     * @example Path\To\File\BlogController -> blog
149
     * @see Inflector::camel2id()
150
     */
151
    private function getName(object $controller): string
152
    {
153
        if ($this->name !== null) {
154
            return $this->name;
155
        }
156
157
        $regexp = '/((?<=controller\\\|s\\\)(?:[\w\\\]+)|(?:[a-z]+))controller/iuU';
158
        if (!preg_match($regexp, get_class($controller), $m) || empty($m[1])) {
159
            throw new \RuntimeException('Cannot detect controller name');
160
        }
161
162
        $inflector = new Inflector();
163
        $name = str_replace('\\', '/', $m[1]);
164
165
        return $inflector->camel2id($name);
166
    }
167
}
168