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

ViewRenderer   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 49
c 2
b 0
f 0
dl 0
loc 127
rs 10
wmc 16

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getViewPath() 0 3 1
A __construct() 0 12 1
A renderPartial() 0 5 1
A render() 0 5 1
A withLayout() 0 6 1
A renderProxy() 0 16 2
A getName() 0 15 4
A findLayoutFile() 0 11 3
A withControllerName() 0 6 1
A withController() 0 6 1
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
23
    public function __construct(
24
        DataResponseFactoryInterface $responseFactory,
25
        User $user,
26
        Aliases $aliases,
27
        WebView $view
28
    )
29
    {
30
        $this->responseFactory = $responseFactory;
31
        $this->user = $user;
32
        $this->aliases = $aliases;
33
        $this->view = $view;
34
        $this->layout = $aliases->get('@views') . '/layout/main';
35
    }
36
37
    public function getViewPath(): string
38
    {
39
        return $this->aliases->get('@views') . '/' . $this->name;
40
    }
41
42
    public function render(string $view, array $parameters = []): ResponseInterface
43
    {
44
        $contentRenderer = fn() => $this->renderProxy($view, $parameters);
45
46
        return $this->responseFactory->createResponse($contentRenderer);
47
    }
48
49
    public function renderPartial(string $view, array $parameters = []): ResponseInterface
50
    {
51
        $content = $this->view->render($view, $parameters, $this);
52
53
        return $this->responseFactory->createResponse($content);
54
    }
55
56
    public function withController(object $controller): self
57
    {
58
        $new = clone $this;
59
        $new->name = $this->getName($controller);
60
61
        return $new;
62
    }
63
64
    public function withControllerName(string $name): self
65
    {
66
        $new = clone $this;
67
        $new->name = $name;
68
69
        return $new;
70
    }
71
72
    public function withLayout(string $layout): self
73
    {
74
        $new = clone $this;
75
        $new->layout = $layout;
76
77
        return $new;
78
    }
79
80
    private function renderProxy(string $view, array $parameters = []): string
81
    {
82
        $content = $this->view->render($view, $parameters, $this);
83
        $user = $this->user->getIdentity();
84
        $layout = $this->findLayoutFile($this->layout);
85
86
        if ($layout === null) {
0 ignored issues
show
introduced by
The condition $layout === null is always false.
Loading history...
87
            return $content;
88
        }
89
        return $this->view->renderFile(
90
            $layout,
91
            [
92
                'content' => $content,
93
                'user' => $user,
94
            ],
95
            $this
96
        );
97
    }
98
99
    private function findLayoutFile(?string $file): ?string
100
    {
101
        if ($file === null) {
102
            return null;
103
        }
104
105
        if (pathinfo($file, PATHINFO_EXTENSION) !== '') {
106
            return $file;
107
        }
108
109
        return $file . '.' . $this->view->getDefaultExtension();
110
    }
111
112
    /**
113
     * Returns the controller name. Name should be converted to "id" case.
114
     * Method returns classname without `controller` on the ending.
115
     * If namespace is not contain `controller` or `controllers`
116
     * then returns only classname without `controller` on the ending
117
     * else returns all subnamespaces from `controller` (or `controllers`) to the end
118
     *
119
     * @return string
120
     * @example App\Controller\FooBar\BazController -> foo-bar/baz
121
     * @example App\Controllers\FooBar\BazController -> foo-bar/baz
122
     * @example Path\To\File\BlogController -> blog
123
     * @see Inflector::camel2id()
124
     */
125
    private function getName(object $controller): string
126
    {
127
        if ($this->name !== null) {
128
            return $this->name;
129
        }
130
131
        $regexp = '/((?<=controller\\\|s\\\)(?:[\w\\\]+)|(?:[a-z]+))controller/iuU';
132
        if (!preg_match($regexp, get_class($controller), $m) || empty($m[1])) {
133
            throw new \RuntimeException('Cannot detect controller name');
134
        }
135
136
        $inflector = new Inflector();
137
        $name = str_replace('\\', '/', $m[1]);
138
139
        return $inflector->camel2id($name);
140
    }
141
}
142