Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
MessageBuilder
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 9
132
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
 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
 setType
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setInline
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setHeading
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
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * MessageBuilder.php
4 *
5 * This file is part of the Codex design system, the official design system
6 * for Wikimedia projects. It provides the `Message` class, a builder for constructing
7 * message components using the Codex design system.
8 *
9 * A Message provides system feedback for users. Messages can be provided as a prominently-displayed
10 * banner with a longer explanation, or as inline validation feedback.
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
20namespace Wikimedia\Codex\Builder;
21
22use InvalidArgumentException;
23use Wikimedia\Codex\Component\HtmlSnippet;
24use Wikimedia\Codex\Component\Message;
25use Wikimedia\Codex\Renderer\MessageRenderer;
26
27/**
28 * MessageBuilder
29 *
30 * This class implements the builder pattern to construct instances of Message.
31 * It provides a fluent interface for setting various properties and building the
32 * final immutable object with predefined configurations and immutability.
33 *
34 * @category Builder
35 * @package  Codex\Builder
36 * @since    0.1.0
37 * @author   Doğu Abaris <abaris@null.net>
38 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
39 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
40 */
41class MessageBuilder {
42
43    /**
44     * The valid status types for messages.
45     */
46    private const STATUS_TYPES = [
47        'notice',
48        'warning',
49        'error',
50        'success',
51    ];
52
53    /**
54     * The ID for the Message.
55     */
56    protected string $id = '';
57
58    /**
59     * The content displayed inside the message box.
60     */
61    protected string $content = '';
62
63    /**
64     * The type of the message (e.g., 'notice', 'warning', 'error', 'success').
65     */
66    protected string $type = 'notice';
67
68    /**
69     * Whether the message box should be displayed inline.
70     */
71    protected bool $inline = false;
72
73    /**
74     * The heading displayed at the top of the message content.
75     */
76    protected string $heading = '';
77
78    /**
79     * The CSS class name for the icon.
80     */
81    protected string $iconClass = '';
82
83    /**
84     * Additional HTML attributes for the message box.
85     */
86    protected array $attributes = [];
87
88    /**
89     * The renderer instance used to render the message.
90     */
91    protected MessageRenderer $renderer;
92
93    /**
94     * Constructor for the Message class.
95     *
96     * @param MessageRenderer $renderer The renderer to use for rendering the message.
97     */
98    public function __construct( MessageRenderer $renderer ) {
99        $this->renderer = $renderer;
100    }
101
102    /**
103     * Set the Message's HTML ID attribute.
104     *
105     * @since 0.1.0
106     * @param string $id The ID for the Message element.
107     * @return $this
108     */
109    public function setId( string $id ): self {
110        $this->id = $id;
111
112        return $this;
113    }
114
115    /**
116     * Set the content of the message box as plain text.
117     *
118     * This method specifies the text content that will be displayed inside the message box.
119     * The content will be escaped for security purposes.
120     *
121     * @since 0.1.0
122     * @param string $content The plain text content to be displayed inside the message box.
123     * @param-taint $content escapes_html
124     * @return $this Returns the Message instance for method chaining.
125     */
126    public function setContentText( string $content ): self {
127        $this->content = $content;
128
129        return $this;
130    }
131
132    /**
133     * Set the content of the message box as HTML.
134     *
135     * This method accepts an `HtmlSnippet` object, which contains HTML content to be displayed
136     * inside the message box without escaping.
137     *
138     * @since 0.1.0
139     * @param HtmlSnippet $content The HTML content to be displayed inside the message box.
140     * @param-taint $content exec_html
141     * @return $this Returns the Message instance for method chaining.
142     */
143    public function setContentHtml( HtmlSnippet $content ): self {
144        $this->content = $content;
145
146        return $this;
147    }
148
149    /**
150     * Set the type of the message box.
151     *
152     * This method sets the visual style of the message box based on its type.
153     * The type can be one of the following:
154     * - 'notice': For general information.
155     * - 'warning': For cautionary information.
156     * - 'error': For error messages.
157     * - 'success': For success messages.
158     *
159     * The type is applied as a CSS class (`cdx-message--{type}`) to the message element.
160     *
161     * @since 0.1.0
162     * @param string $type The type of message (e.g., 'notice', 'warning', 'error', 'success').
163     * @return $this Returns the Message instance for method chaining.
164     */
165    public function setType( string $type ): self {
166        if ( !in_array( $type, self::STATUS_TYPES, true ) ) {
167            throw new InvalidArgumentException( "Invalid message type: $type" );
168        }
169        $this->type = $type;
170
171        return $this;
172    }
173
174    /**
175     * Set the inline display of the message box.
176     *
177     * This method determines whether the message box should be displayed inline,
178     * without padding, background color, or border. Inline messages are typically used for
179     * validation feedback or brief notifications within the flow of content.
180     *
181     * @since 0.1.0
182     * @param bool $inline Whether the message box should be displayed inline.
183     * @return $this Returns the Message instance for method chaining.
184     */
185    public function setInline( bool $inline ): self {
186        $this->inline = $inline;
187
188        return $this;
189    }
190
191    /**
192     * Set the heading of the message box.
193     *
194     * This method sets a heading for the message box, which will be displayed prominently at the top of the message
195     * content. The heading helps to quickly convey the primary purpose or topic of the message.
196     *
197     * Example usage:
198     *
199     *     $message->setHeading('Error: Invalid Input');
200     *
201     * @since 0.1.0
202     * @param string $heading The heading text to be displayed inside the message box.
203     * @return $this Returns the Message instance for method chaining.
204     */
205    public function setHeading( string $heading ): self {
206        $this->heading = $heading;
207
208        return $this;
209    }
210
211    /**
212     * Set additional HTML attributes for the message box.
213     *
214     * This method allows custom HTML attributes to be added to the outer `<div>` element of the message box,
215     * such as `id`, `data-*`, `aria-*`, or any other valid attributes. These attributes can be used to
216     * enhance accessibility or integrate with JavaScript.
217     *
218     * The values of these attributes are automatically escaped to prevent XSS vulnerabilities.
219     *
220     * Example usage:
221     *
222     *     $message->setAttributes([
223     *         'id' => 'error-message',
224     *         'data-type' => 'error',
225     *     ]);
226     *
227     * @since 0.1.0
228     * @param array $attributes An associative array of HTML attributes.
229     * @return $this Returns the Message instance for method chaining.
230     */
231    public function setAttributes( array $attributes ): self {
232        foreach ( $attributes as $key => $value ) {
233            $this->attributes[$key] = $value;
234        }
235        return $this;
236    }
237
238    /**
239     * Build and return the Message component object.
240     * This method constructs the immutable Message object with all the properties set via the builder.
241     *
242     * @since 0.1.0
243     * @return Message The constructed Message.
244     */
245    public function build(): Message {
246        return new Message(
247            $this->id,
248            $this->content,
249            $this->type,
250            $this->inline,
251            $this->heading,
252            $this->iconClass,
253            $this->attributes,
254            $this->renderer
255        );
256    }
257
258}