• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ICanBoogie / View / 4113892126

pending completion
4113892126

push

github

Olivier Laviale
View overhaul

45 of 45 new or added lines in 4 files covered. (100.0%)

68 of 88 relevant lines covered (77.27%)

1.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.83
/lib/View.php
1
<?php
2

3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
namespace ICanBoogie\View;
13

14
use ArrayAccess;
15
use ICanBoogie\OffsetNotDefined;
16
use ICanBoogie\Render\Renderer;
17
use ICanBoogie\Render\RenderOptions;
18
use JsonSerializable;
19
use Stringable;
20

21
use function array_key_exists;
22
use function array_merge;
23
use function array_reverse;
24
use function assert;
25
use function is_string;
26

27
/**
28
 * A view.
29
 *
30
 * @implements ArrayAccess<string, mixed>
31
 */
32
class View implements ArrayAccess, JsonSerializable, Stringable
33
{
34
    public const LOCAL_CONTENT = 'content';
35
    public const LOCAL_VIEW = 'view';
36

37
    /**
38
     * The content to render.
39
     */
40
    public mixed $content = null;
41

42
    /**
43
     * The name of the template that should render the content.
44
     */
45
    public string $template;
46

47
    /**
48
     * The name of the layout that should decorate the content.
49
     */
50
    public ?string $layout = null;
51

52
    /**
53
     * View's variables.
54
     *
55
     * @var array<string, mixed>
56
     */
57
    public array $locals = [];
58

59
    public function __construct(
60
        public readonly Renderer $renderer,
61
    ) {
62
    }
8✔
63

64
    public function __toString(): string
65
    {
66
        return $this->render();
×
67
    }
68

69
    /**
70
     * @inheritdoc
71
     *
72
     * @return array{ content: mixed, template: string, layout: ?string, locals: array<string, mixed> }
73
     */
74
    public function jsonSerialize(): array
75
    {
76
        return [
1✔
77

78
            'content' => $this->content,
1✔
79
            'template' => $this->template,
1✔
80
            'layout' => $this->layout,
1✔
81
            'locals' => $this->locals
1✔
82

83
        ];
1✔
84
    }
85

86
    /**
87
     * @param string $offset
88
     */
89
    public function offsetExists(mixed $offset): bool
90
    {
91
        assert(is_string($offset));
92

93
        return array_key_exists($offset, $this->locals);
3✔
94
    }
95

96
    /**
97
     * @param string $offset
98
     *
99
     * @throws OffsetNotDefined if the offset is not defined.
100
     */
101
    public function offsetGet(mixed $offset): mixed
102
    {
103
        assert(is_string($offset));
104

105
        if (!$this->offsetExists($offset)) {
2✔
106
            throw new OffsetNotDefined([ $offset, $this ]);
1✔
107
        }
108

109
        return $this->locals[$offset];
1✔
110
    }
111

112
    /**
113
     * @param string $offset
114
     */
115
    public function offsetSet(mixed $offset, mixed $value): void
116
    {
117
        assert(is_string($offset));
118

119
        $this->locals[$offset] = $value;
3✔
120
    }
121

122
    /**
123
     * @param string $offset
124
     */
125
    public function offsetUnset(mixed $offset): void
126
    {
127
        assert(is_string($offset));
128

129
        unset($this->locals[$offset]);
1✔
130
    }
131

132
    /**
133
     * Assign multiple variables.
134
     *
135
     * @param array<string, mixed> $locals
136
     *
137
     * @return $this
138
     */
139
    public function assign(array $locals): self
140
    {
141
        $this->locals = array_merge($this->locals, $locals);
2✔
142

143
        return $this;
2✔
144
    }
145

146
    /**
147
     * Additional layout templates to decorate the rendered content with.
148
     *
149
     * @var string[]
150
     */
151
    private array $decorators = [];
152

153
    /**
154
     * Add a template to decorate the content with.
155
     */
156
    public function decorate_with(string $template): void
157
    {
158
        $this->decorators[] = $template;
1✔
159
    }
160

161
    private function decorate(mixed $content): string
162
    {
163
        $decorators = array_reverse($this->decorators);
1✔
164

165
        foreach ($decorators as $template) {
1✔
166
            $content = $this->renderer->render(
1✔
167
                $content,
1✔
168
                new RenderOptions(layout: $template)
1✔
169
            );
1✔
170
        }
171

172
        assert(is_string($content));
173

174
        return $content;
1✔
175
    }
176

177
    /**
178
     * Render the content with template, layout, and decorators.
179
     */
180
    public function render(): string
181
    {
182
        return $this->decorate(
1✔
183
            $this->renderer->render(
1✔
184
                $this->content,
1✔
185
                new RenderOptions(
1✔
186
                    template: $this->template,
1✔
187
                    layout: $this->layout,
1✔
188
                    locals: [
1✔
189
                        self::LOCAL_CONTENT => $this->content,
1✔
190
                        self::LOCAL_VIEW => $this,
1✔
191
                    ] + $this->locals,
1✔
192
                )
1✔
193
            )
1✔
194
        );
1✔
195
    }
196

197
    /**
198
     * Render the content with a simple partial template.
199
     *
200
     * @param array<string, mixed> $locals
201
     */
202
    public function partial(mixed $content, string $template, array $locals = []): string
203
    {
204
        return $this->renderer->render(
1✔
205
            $content,
1✔
206
            new RenderOptions(
1✔
207
                partial: $template,
1✔
208
                locals: [
1✔
209
                    self::LOCAL_VIEW => $this,
1✔
210
                ] + $locals
1✔
211
            )
1✔
212
        );
1✔
213
    }
214
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc