Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 57 |
|
0.00% |
0 / 19 |
CRAP | |
0.00% |
0 / 1 |
TableBuilder | |
0.00% |
0 / 57 |
|
0.00% |
0 / 19 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setId | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setCaption | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setHideCaption | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setColumns | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setData | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setUseRowHeaders | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setShowVerticalBorders | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setSort | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setPaginate | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setTotalRows | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setPaginationPosition | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setAttributes | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
setPager | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setFooter | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setHeaderContent | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setCurrentSortColumn | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setCurrentSortDirection | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
build | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * TableBuilder.php |
4 | * |
5 | * This file is part of the Codex design system, the official design system |
6 | * for Wikimedia projects. It provides the `Table` class, a builder for constructing |
7 | * table components using the Codex design system. |
8 | * |
9 | * Tables are used to arrange data in rows and columns, facilitating the comparison, |
10 | * analysis, and management of information. |
11 | * |
12 | * @category Builder |
13 | * @package Codex\Builder |
14 | * @since 0.1.0 |
15 | * @author Doğu Abaris <abaris@null.net> |
16 | * @license https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later |
17 | * @link https://doc.wikimedia.org/codex/main/ Codex Documentation |
18 | */ |
19 | |
20 | namespace Wikimedia\Codex\Builder; |
21 | |
22 | use Wikimedia\Codex\Component\Pager; |
23 | use Wikimedia\Codex\Component\Table; |
24 | use Wikimedia\Codex\Renderer\TableRenderer; |
25 | |
26 | /** |
27 | * TableBuilder |
28 | * |
29 | * This class implements the builder pattern to construct instances of Table. |
30 | * It provides a fluent interface for setting various properties and building the |
31 | * final immutable object with predefined configurations and immutability. |
32 | * |
33 | * @category Builder |
34 | * @package Codex\Builder |
35 | * @since 0.1.0 |
36 | * @author Doğu Abaris <abaris@null.net> |
37 | * @license https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later |
38 | * @link https://doc.wikimedia.org/codex/main/ Codex Documentation |
39 | */ |
40 | class TableBuilder { |
41 | |
42 | /** |
43 | * Sort direction for ascending order. |
44 | */ |
45 | public const SORT_ASCENDING = 'asc'; |
46 | |
47 | /** |
48 | * Sort direction for descending order. |
49 | */ |
50 | public const SORT_DESCENDING = 'desc'; |
51 | |
52 | /** |
53 | * The ID for the table. |
54 | */ |
55 | protected string $id = ''; |
56 | |
57 | /** |
58 | * Caption for the table. |
59 | */ |
60 | protected string $caption = ''; |
61 | |
62 | /** |
63 | * Flag to hide or show the caption. |
64 | */ |
65 | protected bool $hideCaption = false; |
66 | |
67 | /** |
68 | * Content for the table header. |
69 | */ |
70 | protected ?string $headerContent = null; |
71 | |
72 | /** |
73 | * Array of columns in the table. |
74 | */ |
75 | protected array $columns = []; |
76 | |
77 | /** |
78 | * Array of data rows in the table. |
79 | */ |
80 | protected array $data = []; |
81 | |
82 | /** |
83 | * Flag to use row headers. |
84 | */ |
85 | protected bool $useRowHeaders = false; |
86 | |
87 | /** |
88 | * Sorting configuration. |
89 | */ |
90 | protected array $sort = []; |
91 | |
92 | /** |
93 | * Currently sorted column. |
94 | */ |
95 | protected ?string $currentSortColumn = null; |
96 | |
97 | /** |
98 | * Current sort direction. |
99 | */ |
100 | protected string $currentSortDirection = self::SORT_ASCENDING; |
101 | |
102 | /** |
103 | * Flag to show vertical borders. |
104 | */ |
105 | protected bool $showVerticalBorders = false; |
106 | |
107 | /** |
108 | * Array of additional attributes. |
109 | */ |
110 | protected array $attributes = []; |
111 | |
112 | /** |
113 | * Flag to enable pagination. |
114 | */ |
115 | protected bool $paginate = false; |
116 | |
117 | /** |
118 | * Total number of rows for pagination. |
119 | */ |
120 | protected int $totalRows = 0; |
121 | |
122 | /** |
123 | * Position of the pagination controls ('top', 'bottom', or 'both'). |
124 | */ |
125 | protected string $paginationPosition = 'bottom'; |
126 | |
127 | /** |
128 | * Pager object for handling pagination. |
129 | */ |
130 | protected ?Pager $pager = null; |
131 | |
132 | /** |
133 | * Content for the table footer. |
134 | */ |
135 | protected ?string $footer = null; |
136 | |
137 | /** |
138 | * The renderer instance used to render the table. |
139 | */ |
140 | protected TableRenderer $renderer; |
141 | |
142 | /** |
143 | * Constructor for the TableBuilder class. |
144 | * |
145 | * @param TableRenderer $renderer The renderer to use for rendering the table. |
146 | */ |
147 | public function __construct( TableRenderer $renderer ) { |
148 | $this->renderer = $renderer; |
149 | } |
150 | |
151 | /** |
152 | * Set the Table HTML ID attribute. |
153 | * |
154 | * @since 0.1.0 |
155 | * @param string $id The ID for the Table element. |
156 | * @return $this |
157 | */ |
158 | public function setId( string $id ): self { |
159 | $this->id = $id; |
160 | |
161 | return $this; |
162 | } |
163 | |
164 | /** |
165 | * Set the caption for the table. |
166 | * |
167 | * The caption provides a description of the table's contents and purpose. It is essential for accessibility |
168 | * as it helps screen readers convey the context of the table to users. To visually hide the caption while |
169 | * keeping it accessible, use the `setHideCaption()` method. |
170 | * |
171 | * Example usage: |
172 | * |
173 | * $table->setCaption('Article List'); |
174 | * |
175 | * @since 0.1.0 |
176 | * @param string $caption The caption text to be displayed above the table. |
177 | * @return $this Returns the Table instance for method chaining. |
178 | */ |
179 | public function setCaption( string $caption ): self { |
180 | $this->caption = $caption; |
181 | |
182 | return $this; |
183 | } |
184 | |
185 | /** |
186 | * Set whether to hide the caption. |
187 | * |
188 | * If set to true, the caption will be visually hidden but still accessible to screen readers. |
189 | * |
190 | * @since 0.1.0 |
191 | * @param bool $hideCaption Indicates if the caption should be visually hidden. |
192 | * @return $this Returns the Table instance for method chaining. |
193 | */ |
194 | public function setHideCaption( bool $hideCaption ): self { |
195 | $this->hideCaption = $hideCaption; |
196 | |
197 | return $this; |
198 | } |
199 | |
200 | /** |
201 | * Set the columns for the table. |
202 | * |
203 | * Each column is defined by an associative array with attributes such as 'id', 'label', 'sortable', etc. |
204 | * |
205 | * Example usage: |
206 | * |
207 | * $table->setColumns([ |
208 | * ['id' => 'title', 'label' => 'Title', 'sortable' => true], |
209 | * ['id' => 'creation_date', 'label' => 'Creation Date', 'sortable' => false] |
210 | * ]); |
211 | * |
212 | * @since 0.1.0 |
213 | * @param array $columns An array of columns, where each column is an associative array containing column |
214 | * attributes. |
215 | * @return $this Returns the Table instance for method chaining. |
216 | */ |
217 | public function setColumns( array $columns ): self { |
218 | $this->columns = $columns; |
219 | |
220 | return $this; |
221 | } |
222 | |
223 | /** |
224 | * Set the data for the table. |
225 | * |
226 | * The data array should correspond to the columns defined. Each row is an associative array where keys match |
227 | * column IDs. |
228 | * |
229 | * Example usage: |
230 | * |
231 | * $table->setData([ |
232 | * ['title' => 'Mercury', 'creation_date' => '2024-01-01'], |
233 | * ['title' => 'Venus', 'creation_date' => '2024-01-02'], |
234 | * ]); |
235 | * |
236 | * @since 0.1.0 |
237 | * @param array $data An array of data to be displayed in the table, where each row is an associative array with |
238 | * keys matching column IDs. |
239 | * @return $this Returns the Table instance for method chaining. |
240 | */ |
241 | public function setData( array $data ): self { |
242 | $this->data = $data; |
243 | |
244 | return $this; |
245 | } |
246 | |
247 | /** |
248 | * Set whether to use row headers. |
249 | * |
250 | * If enabled, the first column of the table will be treated as row headers. This is useful for accessibility |
251 | * and to provide additional context for each row. |
252 | * |
253 | * @since 0.1.0 |
254 | * @param bool $useRowHeaders Indicates if row headers should be used. |
255 | * @return $this Returns the Table instance for method chaining. |
256 | */ |
257 | public function setUseRowHeaders( bool $useRowHeaders ): self { |
258 | $this->useRowHeaders = $useRowHeaders; |
259 | |
260 | return $this; |
261 | } |
262 | |
263 | /** |
264 | * Set whether to show vertical borders between columns. |
265 | * |
266 | * Vertical borders can help distinguish between columns, especially in tables with many columns. |
267 | * |
268 | * @since 0.1.0 |
269 | * @param bool $showVerticalBorders Indicates if vertical borders should be displayed between columns. |
270 | * @return $this Returns the Table instance for method chaining. |
271 | */ |
272 | public function setShowVerticalBorders( bool $showVerticalBorders ): self { |
273 | $this->showVerticalBorders = $showVerticalBorders; |
274 | |
275 | return $this; |
276 | } |
277 | |
278 | /** |
279 | * Set the sort order for the table. |
280 | * |
281 | * This method defines the initial sort order for the table. The array should contain |
282 | * column IDs as keys and sort directions ('asc' or 'desc') as values. |
283 | * |
284 | * Example usage: |
285 | * |
286 | * $table->setSort([ |
287 | * 'column1' => 'asc', |
288 | * 'column2' => 'desc' |
289 | * ]); |
290 | * |
291 | * @since 0.1.0 |
292 | * @param array $sort An associative array of column IDs and their respective sort directions ('asc' or 'desc'). |
293 | * @return $this Returns the Table instance for method chaining. |
294 | */ |
295 | public function setSort( array $sort ): self { |
296 | $this->sort = $sort; |
297 | |
298 | return $this; |
299 | } |
300 | |
301 | /** |
302 | * Set whether the table should be paginated. |
303 | * |
304 | * If enabled, pagination controls will be added to the table, allowing users to navigate through multiple pages of |
305 | * data. |
306 | * |
307 | * @since 0.1.0 |
308 | * @param bool $paginate Indicates if the table should be paginated. |
309 | * @return $this Returns the Table instance for method chaining. |
310 | */ |
311 | public function setPaginate( bool $paginate ): self { |
312 | $this->paginate = $paginate; |
313 | |
314 | return $this; |
315 | } |
316 | |
317 | /** |
318 | * Set the total number of rows in the table. |
319 | * |
320 | * This value is used in conjunction with pagination to calculate the total number of pages and to display the |
321 | * current range of rows. |
322 | * |
323 | * @since 0.1.0 |
324 | * @param int $totalRows The total number of rows in the table. |
325 | * @return $this Returns the Table instance for method chaining. |
326 | */ |
327 | public function setTotalRows( int $totalRows ): self { |
328 | $this->totalRows = $totalRows; |
329 | |
330 | return $this; |
331 | } |
332 | |
333 | /** |
334 | * Set the position of the pagination controls. |
335 | * |
336 | * The pagination controls can be displayed at the top, bottom, or both top and bottom of the table. |
337 | * |
338 | * @since 0.1.0 |
339 | * @param string $paginationPosition The position of the pagination controls ('top', 'bottom', 'both'). |
340 | * @return $this Returns the Table instance for method chaining. |
341 | */ |
342 | public function setPaginationPosition( string $paginationPosition ): self { |
343 | $this->paginationPosition = $paginationPosition; |
344 | |
345 | return $this; |
346 | } |
347 | |
348 | /** |
349 | * Set additional HTML attributes for the table element. |
350 | * |
351 | * This method allows custom HTML attributes to be added to the `<table>` element, such as `id`, `class`, |
352 | * or `data-*` attributes. These attributes are automatically escaped to prevent XSS vulnerabilities. |
353 | * |
354 | * Example usage: |
355 | * |
356 | * $table->setAttributes(['class' => 'custom-table-class', 'data-info' => 'additional-info']); |
357 | * |
358 | * @since 0.1.0 |
359 | * @param array $attributes An associative array of HTML attributes to be added to the `<table>` element. |
360 | * |
361 | * @return $this Returns the Table instance for method chaining. |
362 | */ |
363 | public function setAttributes( array $attributes ): self { |
364 | foreach ( $attributes as $key => $value ) { |
365 | $this->attributes[$key] = $value; |
366 | } |
367 | return $this; |
368 | } |
369 | |
370 | /** |
371 | * Set the Pager instance for the table. |
372 | * |
373 | * The Pager instance provides pagination controls for the table. If set, pagination controls will be rendered |
374 | * according to the settings. |
375 | * |
376 | * @since 0.1.0 |
377 | * @param Pager $pager The Pager instance. |
378 | * @return $this Returns the Table instance for method chaining. |
379 | */ |
380 | public function setPager( Pager $pager ): self { |
381 | $this->pager = $pager; |
382 | |
383 | return $this; |
384 | } |
385 | |
386 | /** |
387 | * Set the footer content for the table. |
388 | * |
389 | * The footer is an optional section that can contain additional information or actions related to the table. |
390 | * |
391 | * @since 0.1.0 |
392 | * @param string $footer The footer content. |
393 | * @return $this Returns the Table instance for method chaining. |
394 | */ |
395 | public function setFooter( string $footer ): self { |
396 | $this->footer = $footer; |
397 | |
398 | return $this; |
399 | } |
400 | |
401 | /** |
402 | * Set the header content for the table. |
403 | * |
404 | * This method allows custom content to be added to the table's header, such as actions or additional text. |
405 | * |
406 | * Example usage: |
407 | * |
408 | * $table->setHeaderContent('Custom Actions'); |
409 | * |
410 | * @since 0.1.0 |
411 | * @param string $headerContent The content to be displayed in the table header. |
412 | * @return $this Returns the Table instance for method chaining. |
413 | */ |
414 | public function setHeaderContent( string $headerContent ): self { |
415 | $this->headerContent = $headerContent; |
416 | |
417 | return $this; |
418 | } |
419 | |
420 | /** |
421 | * Set the current sort column. |
422 | * |
423 | * This method specifies which column is currently being used for sorting the table data. |
424 | * The column with this ID will be marked as sorted in the table header. |
425 | * |
426 | * Example usage: |
427 | * |
428 | * $table->setCurrentSortColumn('title'); |
429 | * |
430 | * @since 0.1.0 |
431 | * @param string $currentSortColumn The ID of the column used for sorting. |
432 | * |
433 | * @return $this Returns the Table instance for method chaining. |
434 | */ |
435 | public function setCurrentSortColumn( string $currentSortColumn ): self { |
436 | $this->currentSortColumn = $currentSortColumn; |
437 | |
438 | return $this; |
439 | } |
440 | |
441 | /** |
442 | * Set the current sort direction. |
443 | * |
444 | * This method specifies the direction for sorting the table data. Acceptable values are 'asc' for ascending |
445 | * and 'desc' for descending. The method validates these values to ensure they are correct. |
446 | * |
447 | * Example usage: |
448 | * |
449 | * $table->setCurrentSortDirection('asc'); |
450 | * |
451 | * @since 0.1.0 |
452 | * @param string $currentSortDirection The sort direction ('asc' or 'desc'). |
453 | * |
454 | * @return $this Returns the Table instance for method chaining. |
455 | */ |
456 | public function setCurrentSortDirection( string $currentSortDirection ): self { |
457 | if ( $currentSortDirection === self::SORT_ASCENDING || $currentSortDirection === self::SORT_DESCENDING ) { |
458 | $this->currentSortDirection = $currentSortDirection; |
459 | } |
460 | |
461 | return $this; |
462 | } |
463 | |
464 | /** |
465 | * Build and return the Table component object. |
466 | * This method constructs the immutable Table object with all the properties set via the builder. |
467 | * |
468 | * @since 0.1.0 |
469 | * @return Table The constructed Table. |
470 | */ |
471 | public function build(): Table { |
472 | return new Table( |
473 | $this->id, |
474 | $this->caption, |
475 | $this->hideCaption, |
476 | $this->columns, |
477 | $this->data, |
478 | $this->useRowHeaders, |
479 | $this->headerContent, |
480 | $this->sort, |
481 | $this->currentSortColumn, |
482 | $this->currentSortDirection, |
483 | $this->showVerticalBorders, |
484 | $this->attributes, |
485 | $this->paginate, |
486 | $this->totalRows, |
487 | $this->paginationPosition, |
488 | $this->pager, |
489 | $this->footer, |
490 | $this->renderer |
491 | ); |
492 | } |
493 | } |