1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Console\Helper;
13
14use Symfony\Component\Console\Exception\InvalidArgumentException;
15use Symfony\Component\Console\Exception\LogicException;
16
17/**
18 * Defines the styles for a Table.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 * @author Саша Стаменковић <umpirsky@gmail.com>
22 * @author Dany Maillard <danymaillard93b@gmail.com>
23 */
24class TableStyle
25{
26    private $paddingChar = ' ';
27    private $horizontalOutsideBorderChar = '-';
28    private $horizontalInsideBorderChar = '-';
29    private $verticalOutsideBorderChar = '|';
30    private $verticalInsideBorderChar = '|';
31    private $crossingChar = '+';
32    private $crossingTopRightChar = '+';
33    private $crossingTopMidChar = '+';
34    private $crossingTopLeftChar = '+';
35    private $crossingMidRightChar = '+';
36    private $crossingBottomRightChar = '+';
37    private $crossingBottomMidChar = '+';
38    private $crossingBottomLeftChar = '+';
39    private $crossingMidLeftChar = '+';
40    private $crossingTopLeftBottomChar = '+';
41    private $crossingTopMidBottomChar = '+';
42    private $crossingTopRightBottomChar = '+';
43    private $headerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
44    private $footerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
45    private $cellHeaderFormat = '<info>%s</info>';
46    private $cellRowFormat = '%s';
47    private $cellRowContentFormat = ' %s ';
48    private $borderFormat = '%s';
49    private $padType = \STR_PAD_RIGHT;
50
51    /**
52     * Sets padding character, used for cell padding.
53     *
54     * @return $this
55     */
56    public function setPaddingChar(string $paddingChar)
57    {
58        if (!$paddingChar) {
59            throw new LogicException('The padding char must not be empty.');
60        }
61
62        $this->paddingChar = $paddingChar;
63
64        return $this;
65    }
66
67    /**
68     * Gets padding character, used for cell padding.
69     *
70     * @return string
71     */
72    public function getPaddingChar()
73    {
74        return $this->paddingChar;
75    }
76
77    /**
78     * Sets horizontal border characters.
79     *
80     * <code>
81     * ╔═══════════════╤══════════════════════════╤══════════════════╗
82     * 1 ISBN          2 Title                    │ Author           ║
83     * ╠═══════════════╪══════════════════════════╪══════════════════╣
84     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║
85     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║
86     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║
87     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║
88     * ╚═══════════════╧══════════════════════════╧══════════════════╝
89     * </code>
90     */
91    public function setHorizontalBorderChars(string $outside, string $inside = null): self
92    {
93        $this->horizontalOutsideBorderChar = $outside;
94        $this->horizontalInsideBorderChar = $inside ?? $outside;
95
96        return $this;
97    }
98
99    /**
100     * Sets vertical border characters.
101     *
102     * <code>
103     * ╔═══════════════╤══════════════════════════╤══════════════════╗
104     * ║ ISBN          │ Title                    │ Author           ║
105     * ╠═══════1═══════╪══════════════════════════╪══════════════════╣
106     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║
107     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║
108     * ╟───────2───────┼──────────────────────────┼──────────────────╢
109     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║
110     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║
111     * ╚═══════════════╧══════════════════════════╧══════════════════╝
112     * </code>
113     */
114    public function setVerticalBorderChars(string $outside, string $inside = null): self
115    {
116        $this->verticalOutsideBorderChar = $outside;
117        $this->verticalInsideBorderChar = $inside ?? $outside;
118
119        return $this;
120    }
121
122    /**
123     * Gets border characters.
124     *
125     * @internal
126     */
127    public function getBorderChars(): array
128    {
129        return [
130            $this->horizontalOutsideBorderChar,
131            $this->verticalOutsideBorderChar,
132            $this->horizontalInsideBorderChar,
133            $this->verticalInsideBorderChar,
134        ];
135    }
136
137    /**
138     * Sets crossing characters.
139     *
140     * Example:
141     * <code>
142     * 1═══════════════2══════════════════════════2══════════════════3
143     * ║ ISBN          │ Title                    │ Author           ║
144     * 8'══════════════0'═════════════════════════0'═════════════════4'
145     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║
146     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║
147     * 8───────────────0──────────────────────────0──────────────────4
148     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║
149     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║
150     * 7═══════════════6══════════════════════════6══════════════════5
151     * </code>
152     *
153     * @param string      $cross          Crossing char (see #0 of example)
154     * @param string      $topLeft        Top left char (see #1 of example)
155     * @param string      $topMid         Top mid char (see #2 of example)
156     * @param string      $topRight       Top right char (see #3 of example)
157     * @param string      $midRight       Mid right char (see #4 of example)
158     * @param string      $bottomRight    Bottom right char (see #5 of example)
159     * @param string      $bottomMid      Bottom mid char (see #6 of example)
160     * @param string      $bottomLeft     Bottom left char (see #7 of example)
161     * @param string      $midLeft        Mid left char (see #8 of example)
162     * @param string|null $topLeftBottom  Top left bottom char (see #8' of example), equals to $midLeft if null
163     * @param string|null $topMidBottom   Top mid bottom char (see #0' of example), equals to $cross if null
164     * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null
165     */
166    public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): self
167    {
168        $this->crossingChar = $cross;
169        $this->crossingTopLeftChar = $topLeft;
170        $this->crossingTopMidChar = $topMid;
171        $this->crossingTopRightChar = $topRight;
172        $this->crossingMidRightChar = $midRight;
173        $this->crossingBottomRightChar = $bottomRight;
174        $this->crossingBottomMidChar = $bottomMid;
175        $this->crossingBottomLeftChar = $bottomLeft;
176        $this->crossingMidLeftChar = $midLeft;
177        $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;
178        $this->crossingTopMidBottomChar = $topMidBottom ?? $cross;
179        $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;
180
181        return $this;
182    }
183
184    /**
185     * Sets default crossing character used for each cross.
186     *
187     * @see {@link setCrossingChars()} for setting each crossing individually.
188     */
189    public function setDefaultCrossingChar(string $char): self
190    {
191        return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
192    }
193
194    /**
195     * Gets crossing character.
196     *
197     * @return string
198     */
199    public function getCrossingChar()
200    {
201        return $this->crossingChar;
202    }
203
204    /**
205     * Gets crossing characters.
206     *
207     * @internal
208     */
209    public function getCrossingChars(): array
210    {
211        return [
212            $this->crossingChar,
213            $this->crossingTopLeftChar,
214            $this->crossingTopMidChar,
215            $this->crossingTopRightChar,
216            $this->crossingMidRightChar,
217            $this->crossingBottomRightChar,
218            $this->crossingBottomMidChar,
219            $this->crossingBottomLeftChar,
220            $this->crossingMidLeftChar,
221            $this->crossingTopLeftBottomChar,
222            $this->crossingTopMidBottomChar,
223            $this->crossingTopRightBottomChar,
224        ];
225    }
226
227    /**
228     * Sets header cell format.
229     *
230     * @return $this
231     */
232    public function setCellHeaderFormat(string $cellHeaderFormat)
233    {
234        $this->cellHeaderFormat = $cellHeaderFormat;
235
236        return $this;
237    }
238
239    /**
240     * Gets header cell format.
241     *
242     * @return string
243     */
244    public function getCellHeaderFormat()
245    {
246        return $this->cellHeaderFormat;
247    }
248
249    /**
250     * Sets row cell format.
251     *
252     * @return $this
253     */
254    public function setCellRowFormat(string $cellRowFormat)
255    {
256        $this->cellRowFormat = $cellRowFormat;
257
258        return $this;
259    }
260
261    /**
262     * Gets row cell format.
263     *
264     * @return string
265     */
266    public function getCellRowFormat()
267    {
268        return $this->cellRowFormat;
269    }
270
271    /**
272     * Sets row cell content format.
273     *
274     * @return $this
275     */
276    public function setCellRowContentFormat(string $cellRowContentFormat)
277    {
278        $this->cellRowContentFormat = $cellRowContentFormat;
279
280        return $this;
281    }
282
283    /**
284     * Gets row cell content format.
285     *
286     * @return string
287     */
288    public function getCellRowContentFormat()
289    {
290        return $this->cellRowContentFormat;
291    }
292
293    /**
294     * Sets table border format.
295     *
296     * @return $this
297     */
298    public function setBorderFormat(string $borderFormat)
299    {
300        $this->borderFormat = $borderFormat;
301
302        return $this;
303    }
304
305    /**
306     * Gets table border format.
307     *
308     * @return string
309     */
310    public function getBorderFormat()
311    {
312        return $this->borderFormat;
313    }
314
315    /**
316     * Sets cell padding type.
317     *
318     * @return $this
319     */
320    public function setPadType(int $padType)
321    {
322        if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], true)) {
323            throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
324        }
325
326        $this->padType = $padType;
327
328        return $this;
329    }
330
331    /**
332     * Gets cell padding type.
333     *
334     * @return int
335     */
336    public function getPadType()
337    {
338        return $this->padType;
339    }
340
341    public function getHeaderTitleFormat(): string
342    {
343        return $this->headerTitleFormat;
344    }
345
346    public function setHeaderTitleFormat(string $format): self
347    {
348        $this->headerTitleFormat = $format;
349
350        return $this;
351    }
352
353    public function getFooterTitleFormat(): string
354    {
355        return $this->footerTitleFormat;
356    }
357
358    public function setFooterTitleFormat(string $format): self
359    {
360        $this->footerTitleFormat = $format;
361
362        return $this;
363    }
364}
365