Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
33.33% covered (danger)
33.33%
9 / 27
11.11% covered (danger)
11.11%
1 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
AccordionBuilder
33.33% covered (danger)
33.33%
9 / 27
11.11% covered (danger)
11.11%
1 / 9
46.85
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
 setId
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setTitle
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setDescription
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setContentText
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setContentHtml
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setOpen
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setAttributes
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 build
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * AccordionBuilder.php
4 *
5 * This file is part of the Codex design system, the official design system
6 * for Wikimedia projects. It provides the `Accordion` class, a builder for constructing
7 * accordion components using the Codex design system.
8 *
9 * An Accordion is an expandable and collapsible section of content, often featured in a
10 * vertically stacked list with other Accordions. Accordions are commonly used to organize
11 * content into collapsed sections, making the interface easier to navigate.
12 *
13 * @category Builder
14 * @package  Codex\Builder
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\Builder;
22
23use InvalidArgumentException;
24use Wikimedia\Codex\Component\Accordion;
25use Wikimedia\Codex\Component\HtmlSnippet;
26use Wikimedia\Codex\Renderer\AccordionRenderer;
27
28/**
29 * AccordionBuilder
30 *
31 * This class implements the builder pattern to construct instances of Accordion.
32 * It provides a fluent interface for setting various properties and building the
33 * final immutable object with predefined configurations and immutability.
34 *
35 * @category Builder
36 * @package  Codex\Builder
37 * @since    0.1.0
38 * @author   Doğu Abaris <abaris@null.net>
39 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
40 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
41 */
42class AccordionBuilder {
43
44    /**
45     * The ID for the accordion.
46     */
47    protected string $id = '';
48
49    /**
50     * The accordion's header title.
51     */
52    protected string $title = '';
53
54    /**
55     * Additional text under the title.
56     */
57    protected string $description = '';
58
59    /**
60     * The content shown when the accordion is expanded.
61     */
62    protected string $content = '';
63
64    /**
65     * Determines if the accordion is expanded by default.
66     */
67    protected bool $isOpen = false;
68
69    /**
70     * Additional HTML attributes for the <details> element.
71     */
72    protected array $attributes = [];
73
74    /**
75     * The renderer instance used to render the accordion.
76     */
77    protected AccordionRenderer $renderer;
78
79    /**
80     * Constructor for the Accordion class.
81     *
82     * @param AccordionRenderer $renderer The renderer to use for rendering the accordion.
83     */
84    public function __construct( AccordionRenderer $renderer ) {
85        $this->renderer = $renderer;
86    }
87
88    /**
89     * Set the accordion's HTML ID attribute.
90     *
91     * @since 0.1.0
92     * @param string $id The ID for the accordion element.
93     * @return $this
94     */
95    public function setId( string $id ): self {
96        $this->id = $id;
97
98        return $this;
99    }
100
101    /**
102     * Set the title for the accordion header.
103     *
104     * This method specifies the title text that appears in the accordion's header section.
105     * The title serves as the main clickable element that users interact with to expand or collapse
106     * the accordion content. The title is rendered inside a `<span>` element with the class
107     * `cdx-accordion__header__title`, which is nested within an `<h3>` header inside the `<summary>` element.
108     *
109     * The title should be concise yet descriptive enough to give users a clear understanding
110     * of the content they will see when the accordion is expanded.
111     *
112     * @since 0.1.0
113     * @param string $title The title text to be displayed in the accordion header.
114     * @return $this Returns the Accordion instance for method chaining.
115     */
116    public function setTitle( string $title ): self {
117        if ( trim( $title ) === '' ) {
118            throw new InvalidArgumentException( 'Title cannot be empty.' );
119        }
120        $this->title = $title;
121
122        return $this;
123    }
124
125    /**
126     * Set the description for the accordion header.
127     *
128     * The description is an optional text that provides additional context or details about the accordion's content.
129     * This text is displayed beneath the title in the header section and is wrapped in a `<span>` element with
130     * the class `cdx-accordion__header__description`. This description is particularly useful when the title alone
131     * does not fully convey the nature of the accordion's content.
132     *
133     * This method is especially helpful for making the accordion more accessible and informative,
134     * allowing users to understand the content before deciding to expand it.
135     *
136     * @since 0.1.0
137     * @param string $description The description text to be displayed in the accordion header.
138     * @return $this Returns the Accordion instance for method chaining.
139     */
140    public function setDescription( string $description ): self {
141        $this->description = $description;
142
143        return $this;
144    }
145
146    /**
147     * Set the content for the accordion body as plain text.
148     *
149     * This method defines plain text content that will be safely escaped before rendering.
150     * It should be used when the content does not contain any HTML markup and needs to be treated strictly as text.
151     *
152     * @since 0.1.0
153     * @param string $content The plain text content to be displayed inside the accordion.
154     * @param-taint $content escapes_html
155     * @return $this Returns the Accordion instance for method chaining.
156     */
157    public function setContentText( string $content ): self {
158        $this->content = $content;
159
160        return $this;
161    }
162
163    /**
164     * Set the content for the accordion body as HTML.
165     *
166     * This method defines HTML content by passing an `HtmlSnippet` object. The content
167     * will be rendered as-is without escaping, ensuring the correct HTML output.
168     *
169     * @since 0.1.0
170     * @param HtmlSnippet $content The HTML content to be displayed inside the accordion.
171     * @param-taint $content exec_html
172     * @return $this Returns the Accordion instance for method chaining.
173     */
174    public function setContentHtml( HtmlSnippet $content ): self {
175        $this->content = (string)$content;
176
177        return $this;
178    }
179
180    /**
181     * Set whether the accordion should be open by default.
182     *
183     * By default, accordions are rendered in a collapsed state. However, setting this property to `true`
184     * will cause the accordion to be expanded when the page initially loads. This adds the `open` attribute
185     * to the `<details>` element, making the content visible without interaction.
186     *
187     * This feature is useful in scenarios where critical content needs to be immediately visible, without requiring
188     * any action to expand the accordion.
189     *
190     * @since 0.1.0
191     * @param bool $isOpen Indicates whether the accordion should be open by default.
192     * @return $this Returns the Accordion instance for method chaining.
193     */
194    public function setOpen( bool $isOpen ): self {
195        $this->isOpen = $isOpen;
196
197        return $this;
198    }
199
200    /**
201     * Set additional HTML attributes for the `<details>` element.
202     *
203     * This method allows custom attributes to be added to the `<details>` element, such as `id`, `class`, `data-*`,
204     * `role`, or any other valid HTML attributes. These attributes can be used to further customize the accordion
205     * behavior, integrate it with JavaScript, or enhance accessibility.
206     *
207     * The values of these attributes are automatically escaped to prevent XSS vulnerabilities.
208     *
209     * Example usage:
210     *
211     *     $accordion->setAttributes([
212     *         'id' => 'some-id',
213     *         'data-toggle' => 'collapse'
214     *     ]);
215     *
216     * @since 0.1.0
217     * @param array $attributes An associative array of HTML attributes.
218     * @return $this Returns the Accordion instance for method chaining.
219     */
220    public function setAttributes( array $attributes ): self {
221        foreach ( $attributes as $key => $value ) {
222            $this->attributes[$key] = $value;
223        }
224        return $this;
225    }
226
227    /**
228     * Build and return the Accordion component object.
229     * This method constructs the immutable Accordion object with all the properties set via the builder.
230     *
231     * @since 0.1.0
232     * @return Accordion The constructed Accordion.
233     */
234    public function build(): Accordion {
235        return new Accordion(
236            $this->id,
237            $this->title,
238            $this->description,
239            $this->content,
240            $this->isOpen,
241            $this->attributes,
242            $this->renderer
243        );
244    }
245}