ActionColumnRenderer::renderBody()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 40
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 28
c 1
b 0
f 0
dl 0
loc 40
ccs 29
cts 29
cp 1
rs 8.8497
cc 6
nc 4
nop 3
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\DataView\Column;
6
7
use Closure;
8
use InvalidArgumentException;
9
use Yiisoft\Html\Html;
10
use Yiisoft\Router\CurrentRoute;
11
use Yiisoft\Router\UrlGeneratorInterface;
12
use Yiisoft\Yii\DataView\Column\Base\Cell;
13
use Yiisoft\Yii\DataView\Column\Base\GlobalContext;
14
use Yiisoft\Yii\DataView\Column\Base\DataContext;
15
16
final class ActionColumnRenderer implements ColumnRendererInterface
17
{
18 15
    public function __construct(
19
        private UrlGeneratorInterface $urlGenerator,
20
        private CurrentRoute $currentRoute,
21
    ) {
22 15
    }
23
24
    public function renderColumn(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell
25
    {
26
        $this->checkColumn($column);
27
        return $cell->addAttributes($column->getColumnAttributes());
28
    }
29
30 15
    public function renderHeader(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell
31
    {
32 15
        $this->checkColumn($column);
33 15
        return $cell
34 15
            ->content($column->getHeader() ?? 'Actions')
35 15
            ->addAttributes($column->getHeaderAttributes());
36
    }
37
38 15
    public function renderFilter(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell
39
    {
40 15
        return null;
41
    }
42
43 15
    public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell
44
    {
45 15
        $this->checkColumn($column);
46
47 15
        $contentSource = $column->getContent();
48
49 15
        if ($contentSource !== null) {
50 2
            $content = (string)(is_callable($contentSource) ? $contentSource($context) : $contentSource);
51
        } else {
52 13
            $buttons = empty($column->getButtons()) ? $this->getDefaultButtons() : $column->getButtons();
53 13
            $content = preg_replace_callback(
54 13
                '/{([\w\-\/]+)}/',
55 13
                function (array $matches) use ($column, $buttons, $context): string {
56 13
                    $name = $matches[1];
57
58
                    if (
59 13
                        $this->isVisibleButton(
60 13
                            $column,
61 13
                            $name,
62 13
                            $context->getData(),
63 13
                            $context->getKey(),
64 13
                            $context->getIndex()
65 13
                        ) &&
66 13
                        isset($buttons[$name])
67
                    ) {
68 13
                        $url = $this->createUrl($column, $name, $context->getData(), $context->getKey());
69 13
                        return (string)$buttons[$name]($url);
70
                    }
71
72 1
                    return '';
73 13
                },
74 13
                $column->getTemplate()
75 13
            );
76 13
            $content = trim($content);
77
        }
78
79 15
        return $cell
80 15
            ->addAttributes($column->getBodyAttributes())
81 15
            ->content(PHP_EOL . $content . PHP_EOL)
82 15
            ->encode(false);
83
    }
84
85 1
    public function renderFooter(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell
86
    {
87 1
        $this->checkColumn($column);
88
89 1
        if ($column->getFooter() !== null) {
90 1
            $cell = $cell->content($column->getFooter());
91
        }
92
93 1
        return $cell->addAttributes($column->getFooterAttributes());
94
    }
95
96 13
    private function createUrl(ActionColumn $column, string $action, array|object $data, mixed $key): string
97
    {
98 13
        if ($column->getUrlCreator() !== null) {
99 1
            return (string) ($column->getUrlCreator())($action, $data, $key);
100
        }
101
102 12
        $primaryKey = $column->getPrimaryKey();
103 12
        $routeName = $column->getRouteName();
104
105 12
        if ($primaryKey !== '') {
106 12
            $key = $data[$primaryKey] ?? $key;
107
        }
108
109 12
        $currentRouteName = $this->currentRoute->getName() ?? '';
110
111 12
        $route = $routeName === null
112 12
            ? $currentRouteName . '/' . $action
113
            : $routeName . '/' . $action;
114
115
116 12
        $urlParamsConfig = array_merge(
117 12
            $column->getUrlParamsConfig(),
118 12
            is_array($key) ? $key : [$primaryKey => $key]
119 12
        );
120
121 12
        if ($column->getUrlArguments() !== null) {
122
            /** @psalm-var array<string,string> */
123 1
            $urlArguments = array_merge($column->getUrlArguments(), $urlParamsConfig);
124 1
            $urlQueryParameters = [];
125
        } else {
126 11
            $urlArguments = [];
127 11
            $urlQueryParameters = array_merge($column->getUrlQueryParameters(), $urlParamsConfig);
128
        }
129
130 12
        return $this->urlGenerator->generate($route, $urlArguments, $urlQueryParameters);
131
    }
132
133 13
    private function isVisibleButton(
134
        ActionColumn $column,
135
        string $name,
136
        array|object $data,
137
        mixed $key,
138
        int $index
139
    ): bool {
140 13
        $visibleButtons = $column->getVisibleButtons();
141
142 13
        if (empty($visibleButtons)) {
143 11
            return true;
144
        }
145
146 2
        $visibleValue = $visibleButtons[$name] ?? false;
147 2
        if (is_bool($visibleValue)) {
148 2
            return $visibleValue;
149
        }
150
151
        /** @var bool */
152 1
        return $visibleValue($data, $key, $index);
153
    }
154
155
    /**
156
     * Initializes the default button rendering callback for single button.
157
     * @psalm-return array<string,Closure>
158
     */
159 12
    private function getDefaultButtons(): array
160
    {
161 12
        return [
162 12
            'view' => static fn(string $url): string => Html::a(
163 12
                Html::span('🔎'),
164 12
                $url,
165 12
                [
166 12
                    'name' => 'view',
167 12
                    'role' => 'button',
168 12
                    'style' => 'text-decoration: none!important;',
169 12
                    'title' => 'View',
170 12
                ],
171 12
            )->render(),
172 12
            'update' => static fn(string $url): string => Html::a(
173 12
                Html::span('✎'),
174 12
                $url,
175 12
                [
176 12
                    'name' => 'update',
177 12
                    'role' => 'button',
178 12
                    'style' => 'text-decoration: none!important;',
179 12
                    'title' => 'Update',
180 12
                ],
181 12
            )->render(),
182 12
            'delete' => static fn(string $url): string => Html::a(
183 12
                Html::span('❌'),
184 12
                $url,
185 12
                [
186 12
                    'name' => 'delete',
187 12
                    'role' => 'button',
188 12
                    'style' => 'text-decoration: none!important;',
189 12
                    'title' => 'Delete',
190 12
                ],
191 12
            )->render(),
192 12
        ];
193
    }
194
195
    /**
196
     * @psalm-assert ActionColumn $column
197
     */
198 15
    private function checkColumn(ColumnInterface $column): void
199
    {
200 15
        if (!$column instanceof ActionColumn) {
201
            throw new InvalidArgumentException(
202
                sprintf(
203
                    'Expected "%s", but "%s" given.',
204
                    self::class,
205
                    $column::class
206
                )
207
            );
208
        }
209
    }
210
}
211