Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Field
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 11
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLabel
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isFieldset
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFields
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAttributes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setId
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setLabel
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setIsFieldset
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setFields
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 setAttributes
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare( strict_types = 1 );
3
4/**
5 * Field.php
6 *
7 * This file is part of the Codex design system, the official design system for Wikimedia projects.
8 * It contains the definition and implementation of the `Field` class, responsible for managing
9 * the behavior and properties of the corresponding component.
10 *
11 * @category Component
12 * @package  Codex\Component
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\Component;
20
21use Wikimedia\Codex\Contract\Component;
22use Wikimedia\Codex\Renderer\FieldRenderer;
23
24/**
25 * Field
26 *
27 * @category Component
28 * @package  Codex\Component
29 * @since    0.1.0
30 * @author   Doğu Abaris <abaris@null.net>
31 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
32 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
33 */
34class Field extends Component {
35    private string $id = '';
36
37    public function __construct(
38        FieldRenderer $renderer,
39        private ?Label $label,
40        private bool $isFieldset,
41        private array $fields,
42        private array $attributes
43    ) {
44        foreach ( $this->fields as $field ) {
45            if ( is_string( $field ) ) {
46                trigger_error(
47                    "Passing raw HTML strings to setFields() is deprecated and will be removed in 1.0.0. " .
48                    "Please use HtmlSnippet objects instead.",
49                    E_USER_DEPRECATED
50                );
51            }
52        }
53        parent::__construct( $renderer );
54    }
55
56    /**
57     * Get the fieldset or div's HTML ID attribute.
58     *
59     * This method returns the ID assigned to the fieldset or div element. The ID is useful for targeting
60     * the field with JavaScript, CSS, or for accessibility purposes.
61     *
62     * @since 0.1.0
63     * @return string The ID of the fieldset or div element.
64     */
65    public function getId(): string {
66        return $this->id;
67    }
68
69    /**
70     * Get the label of the field.
71     *
72     * This method returns the label object associated with the field. The label provides a descriptive
73     * name that helps users understand the purpose of the field.
74     *
75     * @since 0.1.0
76     * @return ?Label The label of the field.
77     */
78    public function getLabel(): ?Label {
79        return $this->label;
80    }
81
82    /**
83     * Check if the fields are wrapped in a fieldset with a legend.
84     *
85     * This method returns a boolean indicating whether the fields are wrapped in a `<fieldset>`
86     * element with a `<legend>`. If false, the fields are wrapped in a `<div>` with a `<label>`.
87     *
88     * @since 0.1.0
89     * @return bool True if the fields are wrapped in a fieldset, false otherwise.
90     */
91    public function isFieldset(): bool {
92        return $this->isFieldset;
93    }
94
95    /**
96     * Get the fields included within the fieldset or div.
97     *
98     * This method returns an array of fields (as HTML strings) that are included
99     * within the fieldset or div.
100     *
101     * @since 0.1.0
102     * @return array<Component|HtmlSnippet|string> The fields included in the fieldset or div.
103     */
104    public function getFields(): array {
105        return $this->fields;
106    }
107
108    /**
109     * Get the additional HTML attributes for the fieldset or div element.
110     *
111     * This method returns an associative array of additional HTML attributes
112     * that are applied to the fieldset or div element.
113     *
114     * @since 0.1.0
115     * @return array The additional attributes as an array.
116     */
117    public function getAttributes(): array {
118        return $this->attributes;
119    }
120
121    /**
122     * Set the label's HTML ID attribute.
123     *
124     * @deprecated Use setAttributes() to set the ID
125     * @since 0.1.0
126     * @param string $id The ID for the field element.
127     * @return $this
128     */
129    public function setId( string $id ): self {
130        $this->id = $id;
131
132        return $this;
133    }
134
135    /**
136     * Set the label for the field.
137     *
138     * This method accepts a Label object which provides a descriptive label for the field.
139     *
140     * @since 0.1.0
141     * @param Label $label The Label object for the field.
142     * @return $this Returns the Checkbox instance for method chaining.
143     */
144    public function setLabel( Label $label ): self {
145        $this->label = $label;
146
147        return $this;
148    }
149
150    /**
151     * Set whether the fields should be wrapped in a fieldset with a legend.
152     *
153     * When set to `true`, this method wraps the fields in a `<fieldset>` element with a `<legend>`.
154     * If set to `false`, the fields are wrapped in a `<div>` with a `<label>` instead.
155     *
156     * @since 0.1.0
157     * @param bool $isFieldset Whether to wrap fields in a fieldset.
158     * @return $this Returns the Field instance for method chaining.
159     */
160    public function setIsFieldset( bool $isFieldset ): self {
161        $this->isFieldset = $isFieldset;
162
163        return $this;
164    }
165
166    /**
167     * Set the fields within the fieldset.
168     *
169     * This method accepts an array of fields to be included within the fieldset or a `<div>`.
170     * It allows grouping of related fields together under a common legend or label for better organization.
171     *
172     * Fields may be Component objects, HtmlSnippet objects, or raw HTML strings. Passing in strings
173     * is deprecated and will be removed in 1.0.0.
174     *
175     * @since 0.1.0
176     * @param array<Component|HtmlSnippet|string> $fields The array of fields to include in the fieldset.
177     * @return $this Returns the Field instance for method chaining.
178     */
179    public function setFields( array $fields ): self {
180        foreach ( $fields as $field ) {
181            if ( is_string( $field ) ) {
182                trigger_error(
183                    "Passing raw HTML strings to setFields() is deprecated and will be removed in 1.0.0. " .
184                    "Please use HtmlSnippet objects instead.",
185                    E_USER_DEPRECATED
186                );
187            }
188        }
189        $this->fields = $fields;
190
191        return $this;
192    }
193
194    /**
195     * Set additional HTML attributes for the fieldset or div element.
196     *
197     * This method allows custom HTML attributes to be added to the fieldset or div element, such as `id`, `data-*`,
198     * `aria-*`, or any other valid attributes. These attributes can be used to further customize the fieldset or div,
199     * enhance accessibility, or provide additional metadata.
200     *
201     * The values of these attributes are automatically escaped to prevent XSS vulnerabilities.
202     *
203     * Example usage:
204     *
205     *     $field->setAttributes([
206     *         'id' => 'user-info-fieldset',
207     *         'data-category' => 'user-data',
208     *         'aria-labelledby' => 'legend-user-info'
209     *     ]);
210     *
211     * @since 0.1.0
212     * @param array $attributes An associative array of HTML attributes.
213     * @return $this Returns the Field instance for method chaining.
214     */
215    public function setAttributes( array $attributes ): self {
216        foreach ( $attributes as $key => $value ) {
217            $this->attributes[$key] = $value;
218        }
219
220        return $this;
221    }
222}