Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SelectRenderer
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 4
110
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 render
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 prepareOptions
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 prepareOptGroups
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * SelectRenderer.php
4 *
5 * This file is part of the Codex PHP library, which provides a PHP-based interface for creating
6 * UI components consistent with the Codex design system.
7 *
8 * The `SelectRenderer` class leverages the `TemplateParser` and `Sanitizer` utilities to ensure the
9 * component object is rendered according to Codex design system standards.
10 *
11 * @category Renderer
12 * @package  Codex\Renderer
13 * @since    0.1.0
14 * @author   Doğu Abaris <abaris@null.net>
15 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
16 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
17 */
18
19namespace Wikimedia\Codex\Renderer;
20
21use InvalidArgumentException;
22use Wikimedia\Codex\Component\Option;
23use Wikimedia\Codex\Component\Select;
24use Wikimedia\Codex\Contract\Renderer\IRenderer;
25use Wikimedia\Codex\Parser\TemplateParser;
26use Wikimedia\Codex\Traits\AttributeResolver;
27use Wikimedia\Codex\Utility\Sanitizer;
28
29/**
30 * SelectRenderer is responsible for rendering the HTML markup
31 * for a Select component using a Mustache template.
32 *
33 * This class uses the `TemplateParser` and `Sanitizer` utilities to manage
34 * the template rendering process, ensuring that the component object's HTML
35 * output adheres to the Codex design system's standards.
36 *
37 * @category Renderer
38 * @package  Codex\Renderer
39 * @since    0.1.0
40 * @author   Doğu Abaris <abaris@null.net>
41 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
42 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
43 */
44class SelectRenderer implements IRenderer {
45
46    /**
47     * Use the AttributeResolver trait
48     */
49    use AttributeResolver;
50
51    /**
52     * The sanitizer instance used for content sanitization.
53     */
54    private Sanitizer $sanitizer;
55
56    /**
57     * The template parser instance.
58     */
59    private TemplateParser $templateParser;
60
61    /**
62     * Constructor to initialize the SelectRenderer with a sanitizer and a template parser.
63     *
64     * @since 0.1.0
65     * @param Sanitizer $sanitizer The sanitizer instance used for content sanitization.
66     * @param TemplateParser $templateParser The template parser instance.
67     */
68    public function __construct( Sanitizer $sanitizer, TemplateParser $templateParser ) {
69        $this->sanitizer = $sanitizer;
70        $this->templateParser = $templateParser;
71    }
72
73    /**
74     * Renders the HTML for a select dropdown component.
75     *
76     * Uses the provided Select component to generate HTML markup adhering to the Codex design system.
77     *
78     * @since 0.1.0
79     * @param Select $component The Select object to render.
80     * @return string The rendered HTML string for the component.
81     */
82    public function render( $component ): string {
83        if ( !$component instanceof Select ) {
84            throw new InvalidArgumentException( "Expected instance of Select, got " . get_class( $component ) );
85        }
86
87        $selectData = [
88            'id' => $this->sanitizer->sanitizeText( $component->getId() ),
89            'isDisabled' => $component->isDisabled(),
90            'selectedOption' => $component->getSelectedOption(),
91            'attributes' => $this->resolve( $this->sanitizer->sanitizeAttributes( $component->getAttributes() ) ),
92            'options' => $this->prepareOptions( $component ),
93            'optGroups' => $this->prepareOptGroups( $component ),
94        ];
95
96        return $this->templateParser->processTemplate( 'select', $selectData );
97    }
98
99    /**
100     * Prepare options for rendering.
101     *
102     * @since 0.1.0
103     * @param Select $object The Select component object.
104     * @return array An array of sanitized option data for rendering.
105     */
106    private function prepareOptions( Select $object ): array {
107        $options = [];
108        foreach ( $object->getOptions() as $option ) {
109            if ( !$option instanceof Option ) {
110                throw new InvalidArgumentException( "Expected instance of Option in options" );
111            }
112            $options[] = [
113                'value' => $this->sanitizer->sanitizeText( $option->getValue() ),
114                'text' => $this->sanitizer->sanitizeText( $option->getText() ),
115                'isSelected' => $option->isSelected(),
116            ];
117        }
118
119        return $options;
120    }
121
122    /**
123     * Prepare optGroups for rendering.
124     *
125     * @since 0.1.0
126     * @param Select $object The Select component object containing optGroups.
127     * @return array Prepared array of optGroups with their respective options for rendering.
128     */
129    private function prepareOptGroups( Select $object ): array {
130        $optGroups = [];
131        foreach ( $object->getOptGroups() as $label => $groupOptions ) {
132            $group = [
133                'label' => $this->sanitizer->sanitizeText( $label ),
134                'options' => [],
135            ];
136            foreach ( $groupOptions as $option ) {
137                if ( !$option instanceof Option ) {
138                    throw new InvalidArgumentException( "Expected instance of Option in optGroups" );
139                }
140                $group['options'][] = [
141                    'value' => $this->sanitizer->sanitizeText( $option->getValue() ),
142                    'text' => $this->sanitizer->sanitizeText( $option->getText() ),
143                    'isSelected' => $option->isSelected(),
144                ];
145            }
146            $optGroups[] = $group;
147        }
148
149        return $optGroups;
150    }
151}