Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
FieldRenderer
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 2
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 render
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2declare( strict_types = 1 );
3
4/**
5 * FieldRenderer.php
6 *
7 * This file is part of the Codex PHP library, which provides a PHP-based interface for creating
8 * UI components consistent with the Codex design system.
9 *
10 * The `FieldRenderer` class leverages the `TemplateParser` and `Sanitizer` utilities to ensure the
11 * component object is rendered according to Codex design system standards.
12 *
13 * @category Renderer
14 * @package  Codex\Renderer
15 * @since    0.1.0
16 * @author   Doğu Abaris <abaris@null.net>
17 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
18 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
19 */
20
21namespace Wikimedia\Codex\Renderer;
22
23use InvalidArgumentException;
24use Wikimedia\Codex\Component\Field;
25use Wikimedia\Codex\Component\HtmlSnippet;
26use Wikimedia\Codex\Contract\Component;
27use Wikimedia\Codex\Contract\ILocalizer;
28use Wikimedia\Codex\Contract\Renderer;
29use Wikimedia\Codex\Parser\TemplateParser;
30use Wikimedia\Codex\Utility\Codex;
31use Wikimedia\Codex\Utility\Sanitizer;
32
33/**
34 * FieldRenderer is responsible for rendering the HTML markup
35 * for a Field component using a Mustache template.
36 *
37 * This class uses the `TemplateParser` and `Sanitizer` utilities to manage
38 * the template rendering process, ensuring that the component object's HTML
39 * output adheres to the Codex design system's standards.
40 *
41 * @category Renderer
42 * @package  Codex\Renderer
43 * @since    0.1.0
44 * @author   Doğu Abaris <abaris@null.net>
45 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
46 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
47 */
48class FieldRenderer extends Renderer {
49
50    /**
51     * Constructor to initialize the FieldRenderer with a sanitizer and a template parser.
52     *
53     * @since 0.1.0
54     * @param Sanitizer $sanitizer The sanitizer instance used for content sanitization.
55     * @param TemplateParser $templateParser The template parser instance.
56     * @param ILocalizer $localizer The localizer instance used for i18n messages.
57     * @param Codex $codex The Codex instance for creating other components.
58     */
59    public function __construct(
60        Sanitizer $sanitizer,
61        private readonly TemplateParser $templateParser,
62        private readonly ILocalizer $localizer,
63        private readonly Codex $codex
64    ) {
65        parent::__construct( $sanitizer );
66    }
67
68    /**
69     * Renders the HTML for a field component.
70     *
71     * Uses the provided Field component to generate HTML markup adhering to the Codex design system.
72     *
73     * @since 0.1.0
74     * @param Component $component The Field component to render.
75     * @return string The rendered HTML string for the component.
76     */
77    public function render( Component $component ): string {
78        if ( !$component instanceof Field ) {
79            throw new InvalidArgumentException( "Expected instance of Field, got " . get_class( $component ) );
80        }
81
82        $label = $component->getLabel();
83        $labelData = null;
84
85        if ( $label ) {
86            $labelData = [
87                'id' => $label->getId(),
88                'isLegend' => $component->isFieldset(),
89                'inputId' => $label->getInputId(),
90                'labelText-html' => $this->sanitizer->sanitizeText( $label->getLabelText() ),
91                'optionalFlag' => $label->isOptional() ?
92                    $this->localizer->msg( 'cdx-label-optional-flag' ) :
93                    null,
94                'isVisuallyHidden' => $label->isVisuallyHidden(),
95                'description-html' => $this->sanitizer->sanitizeText( $label->getDescription() ),
96                'descriptionId' => $label->getDescriptionId(),
97                'icon' => $label->getIconClass(),
98                'isDisabled' => $label->isDisabled(),
99                'extraClasses' => $this->getExtraClasses( $label->getAttributes() ),
100                'attributes' => $this->getOtherAttributes( $label->getAttributes() ),
101            ];
102        }
103
104        $fieldData = [
105            'id' => $component->getId(),
106            'isFieldset' => $component->isFieldset(),
107            'fields-html' => array_map( static function ( $field ) {
108                if ( $field instanceof Component ) {
109                    return $field->getHtml();
110                }
111                if ( $field instanceof HtmlSnippet ) {
112                    return $field->getContent();
113                }
114                // Raw strings are deprecated; deprecation warning is thrown in Field.php
115                return $field;
116            }, $component->getFields() ),
117            'extraClasses' => $this->getExtraClasses( $component->getAttributes() ),
118            'attributes' => $this->getOtherAttributes( $component->getAttributes() ),
119            'label' => $labelData,
120        ];
121
122        return $this->templateParser->processTemplate( 'field', $fieldData );
123    }
124}