Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
CardBuilder
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 10
182
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
 setSupportingText
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setUrl
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setIconClass
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setThumbnail
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 / 11
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * CardBuilder.php
4 *
5 * This file is part of the Codex design system, the official design system
6 * for Wikimedia projects. It provides the `Card` class, a builder for constructing
7 * card components using the Codex design system.
8 *
9 * A Card is used to group information and actions related to a single topic.
10 * Cards can be clickable and offer a way to navigate to the content they represent (e.g., Wikipedia articles).
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\Card;
24use Wikimedia\Codex\Component\Thumbnail;
25use Wikimedia\Codex\Renderer\CardRenderer;
26
27/**
28 * CardBuilder
29 *
30 * This class implements the builder pattern to construct instances of Card.
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 CardBuilder {
42
43    /**
44     * The ID for the card.
45     */
46    protected string $id = '';
47
48    /**
49     * The title text displayed on the card.
50     */
51    protected string $title = '';
52
53    /**
54     * The description text displayed on the card.
55     */
56    protected string $description = '';
57
58    /**
59     * Optional supporting text for additional details on the card.
60     */
61    protected string $supportingText = '';
62
63    /**
64     * The URL the card links to, if the card is clickable.
65     */
66    protected string $url = '';
67
68    /**
69     * The CSS class for an optional icon in the card.
70     */
71    protected ?string $iconClass = null;
72
73    /**
74     * The Thumbnail object representing the card's thumbnail.
75     */
76    protected ?Thumbnail $thumbnail = null;
77
78    /**
79     * Additional HTML attributes for the card element.
80     */
81    protected array $attributes = [];
82
83    /**
84     * The renderer instance used to render the card.
85     */
86    protected CardRenderer $renderer;
87
88    /**
89     * Constructor for the Card class.
90     *
91     * @param CardRenderer $renderer The renderer to use for rendering the card.
92     */
93    public function __construct( CardRenderer $renderer ) {
94        $this->renderer = $renderer;
95    }
96
97    /**
98     * Set the card's HTML ID attribute.
99     *
100     * @since 0.1.0
101     * @param string $id The ID for the card element.
102     * @return $this
103     */
104    public function setId( string $id ): self {
105        $this->id = $id;
106
107        return $this;
108    }
109
110    /**
111     * Set the title for the card.
112     *
113     * The title is the primary text displayed on the card, typically representing the main topic
114     * or subject of the card. It is usually rendered in a larger font and is the most prominent
115     * piece of text on the card.
116     *
117     * @since 0.1.0
118     * @param string $title The title text displayed on the card.
119     * @return $this Returns the Card instance for method chaining.
120     */
121    public function setTitle( string $title ): self {
122        if ( trim( $title ) === '' ) {
123            throw new InvalidArgumentException( 'Card title cannot be empty.' );
124        }
125        $this->title = $title;
126
127        return $this;
128    }
129
130    /**
131     * Set the description for the card.
132     *
133     * The description provides additional details about the card's content. It is typically rendered
134     * below the title in a smaller font. The description is optional and can be used to give users
135     * more context about what the card represents.
136     *
137     * @since 0.1.0
138     * @param string $description The description text displayed on the card.
139     * @return $this Returns the Card instance for method chaining.
140     */
141    public function setDescription( string $description ): self {
142        $this->description = $description;
143
144        return $this;
145    }
146
147    /**
148     * Set the supporting text for the card.
149     *
150     * The supporting text is an optional piece of text that can provide additional information
151     * or context about the card. It is typically placed at the bottom of the card, below the
152     * title and description, in a smaller font. This text can be used for subtitles, additional
153     * notes, or other relevant details.
154     *
155     * @since 0.1.0
156     * @param string $supportingText The supporting text displayed on the card.
157     * @return $this Returns the Card instance for method chaining.
158     */
159    public function setSupportingText( string $supportingText ): self {
160        $this->supportingText = $supportingText;
161
162        return $this;
163    }
164
165    /**
166     * Set the URL for the card. If provided, the card will be an `<a>` element.
167     *
168     * This method makes the entire card clickable by wrapping it in an anchor (`<a>`) element,
169     * turning it into a link. This is particularly useful for cards that serve as navigational
170     * elements, leading users to related content, such as articles, profiles, or external pages.
171     *
172     * @since 0.1.0
173     * @param string $url The URL the card should link to.
174     * @return $this Returns the Card instance for method chaining.
175     */
176    public function setUrl( string $url ): self {
177        if ( !filter_var( $url, FILTER_VALIDATE_URL ) ) {
178            throw new InvalidArgumentException( "Invalid URL: $url" );
179        }
180        $this->url = $url;
181
182        return $this;
183    }
184
185    /**
186     * Set the icon class for the card.
187     *
188     * This method specifies a CSS class for an icon to be displayed inside the card.
189     * The icon can be used to visually represent the content or purpose of the card.
190     * It is typically rendered at the top or side of the card, depending on the design.
191     *
192     * @since 0.1.0
193     * @param string $iconClass The CSS class for the icon.
194     * @return $this Returns the Card instance for method chaining.
195     */
196    public function setIconClass( string $iconClass ): self {
197        $this->iconClass = $iconClass;
198
199        return $this;
200    }
201
202    /**
203     * Set the thumbnail for the card.
204     *
205     * This method accepts a `Thumbnail` object, which configures the thumbnail associated with the card.
206     *
207     * Example usage:
208     *     $thumbnail = Thumbnail::setBackgroundImage('https://example.com/image.jpg');
209     *     $card->setThumbnail($thumbnail);
210     *
211     * @since 0.1.0
212     * @param Thumbnail $thumbnail The Thumbnail object.
213     * @return $this Returns the Card instance for method chaining.
214     */
215    public function setThumbnail( Thumbnail $thumbnail ): self {
216        $this->thumbnail = $thumbnail;
217
218        return $this;
219    }
220
221    /**
222     * Set additional HTML attributes for the card element.
223     *
224     * This method allows custom HTML attributes to be added to the card element, such as `id`, `data-*`, `aria-*`,
225     * or any other valid attributes. These attributes can be used to integrate the card with JavaScript, enhance
226     * accessibility, or provide additional metadata.
227     *
228     * The values of these attributes are automatically escaped to prevent XSS vulnerabilities.
229     *
230     * @since 0.1.0
231     * @param array $attributes An associative array of HTML attributes.
232     * @return $this Returns the Card instance for method chaining.
233     */
234    public function setAttributes( array $attributes ): self {
235        foreach ( $attributes as $key => $value ) {
236            $this->attributes[$key] = $value;
237        }
238        return $this;
239    }
240
241    /**
242     * Build and return the Card component object.
243     * This method constructs the immutable Card object with all the properties set via the builder.
244     *
245     * @since 0.1.0
246     * @return Card The constructed Card.
247     */
248    public function build(): Card {
249        return new Card(
250            $this->id,
251            $this->title,
252            $this->description,
253            $this->supportingText,
254            $this->url,
255            $this->iconClass,
256            $this->thumbnail,
257            $this->attributes,
258            $this->renderer
259        );
260    }
261}