1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Style;
4
5use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
6
7class Alignment extends Supervisor
8{
9    // Horizontal alignment styles
10    const HORIZONTAL_GENERAL = 'general';
11    const HORIZONTAL_LEFT = 'left';
12    const HORIZONTAL_RIGHT = 'right';
13    const HORIZONTAL_CENTER = 'center';
14    const HORIZONTAL_CENTER_CONTINUOUS = 'centerContinuous';
15    const HORIZONTAL_JUSTIFY = 'justify';
16    const HORIZONTAL_FILL = 'fill';
17    const HORIZONTAL_DISTRIBUTED = 'distributed'; // Excel2007 only
18
19    // Vertical alignment styles
20    const VERTICAL_BOTTOM = 'bottom';
21    const VERTICAL_TOP = 'top';
22    const VERTICAL_CENTER = 'center';
23    const VERTICAL_JUSTIFY = 'justify';
24    const VERTICAL_DISTRIBUTED = 'distributed'; // Excel2007 only
25
26    // Read order
27    const READORDER_CONTEXT = 0;
28    const READORDER_LTR = 1;
29    const READORDER_RTL = 2;
30
31    // Special value for Text Rotation
32    const TEXTROTATION_STACK_EXCEL = 255;
33    const TEXTROTATION_STACK_PHPSPREADSHEET = -165; // 90 - 255
34
35    /**
36     * Horizontal alignment.
37     *
38     * @var string
39     */
40    protected $horizontal = self::HORIZONTAL_GENERAL;
41
42    /**
43     * Vertical alignment.
44     *
45     * @var string
46     */
47    protected $vertical = self::VERTICAL_BOTTOM;
48
49    /**
50     * Text rotation.
51     *
52     * @var int
53     */
54    protected $textRotation = 0;
55
56    /**
57     * Wrap text.
58     *
59     * @var bool
60     */
61    protected $wrapText = false;
62
63    /**
64     * Shrink to fit.
65     *
66     * @var bool
67     */
68    protected $shrinkToFit = false;
69
70    /**
71     * Indent - only possible with horizontal alignment left and right.
72     *
73     * @var int
74     */
75    protected $indent = 0;
76
77    /**
78     * Read order.
79     *
80     * @var int
81     */
82    protected $readOrder = 0;
83
84    /**
85     * Create a new Alignment.
86     *
87     * @param bool $isSupervisor Flag indicating if this is a supervisor or not
88     *                                       Leave this value at default unless you understand exactly what
89     *                                          its ramifications are
90     * @param bool $isConditional Flag indicating if this is a conditional style or not
91     *                                       Leave this value at default unless you understand exactly what
92     *                                          its ramifications are
93     */
94    public function __construct($isSupervisor = false, $isConditional = false)
95    {
96        // Supervisor?
97        parent::__construct($isSupervisor);
98
99        if ($isConditional) {
100            $this->horizontal = null;
101            $this->vertical = null;
102            $this->textRotation = null;
103        }
104    }
105
106    /**
107     * Get the shared style component for the currently active cell in currently active sheet.
108     * Only used for style supervisor.
109     *
110     * @return Alignment
111     */
112    public function getSharedComponent()
113    {
114        return $this->parent->getSharedComponent()->getAlignment();
115    }
116
117    /**
118     * Build style array from subcomponents.
119     *
120     * @param array $array
121     *
122     * @return array
123     */
124    public function getStyleArray($array)
125    {
126        return ['alignment' => $array];
127    }
128
129    /**
130     * Apply styles from array.
131     *
132     * <code>
133     * $spreadsheet->getActiveSheet()->getStyle('B2')->getAlignment()->applyFromArray(
134     *        [
135     *            'horizontal'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
136     *            'vertical'     => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
137     *            'textRotation' => 0,
138     *            'wrapText'     => TRUE
139     *        ]
140     * );
141     * </code>
142     *
143     * @param array $pStyles Array containing style information
144     *
145     * @return $this
146     */
147    public function applyFromArray(array $pStyles)
148    {
149        if ($this->isSupervisor) {
150            $this->getActiveSheet()->getStyle($this->getSelectedCells())
151                ->applyFromArray($this->getStyleArray($pStyles));
152        } else {
153            if (isset($pStyles['horizontal'])) {
154                $this->setHorizontal($pStyles['horizontal']);
155            }
156            if (isset($pStyles['vertical'])) {
157                $this->setVertical($pStyles['vertical']);
158            }
159            if (isset($pStyles['textRotation'])) {
160                $this->setTextRotation($pStyles['textRotation']);
161            }
162            if (isset($pStyles['wrapText'])) {
163                $this->setWrapText($pStyles['wrapText']);
164            }
165            if (isset($pStyles['shrinkToFit'])) {
166                $this->setShrinkToFit($pStyles['shrinkToFit']);
167            }
168            if (isset($pStyles['indent'])) {
169                $this->setIndent($pStyles['indent']);
170            }
171            if (isset($pStyles['readOrder'])) {
172                $this->setReadOrder($pStyles['readOrder']);
173            }
174        }
175
176        return $this;
177    }
178
179    /**
180     * Get Horizontal.
181     *
182     * @return string
183     */
184    public function getHorizontal()
185    {
186        if ($this->isSupervisor) {
187            return $this->getSharedComponent()->getHorizontal();
188        }
189
190        return $this->horizontal;
191    }
192
193    /**
194     * Set Horizontal.
195     *
196     * @param string $pValue see self::HORIZONTAL_*
197     *
198     * @return $this
199     */
200    public function setHorizontal($pValue)
201    {
202        if ($pValue == '') {
203            $pValue = self::HORIZONTAL_GENERAL;
204        }
205
206        if ($this->isSupervisor) {
207            $styleArray = $this->getStyleArray(['horizontal' => $pValue]);
208            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
209        } else {
210            $this->horizontal = $pValue;
211        }
212
213        return $this;
214    }
215
216    /**
217     * Get Vertical.
218     *
219     * @return string
220     */
221    public function getVertical()
222    {
223        if ($this->isSupervisor) {
224            return $this->getSharedComponent()->getVertical();
225        }
226
227        return $this->vertical;
228    }
229
230    /**
231     * Set Vertical.
232     *
233     * @param string $pValue see self::VERTICAL_*
234     *
235     * @return $this
236     */
237    public function setVertical($pValue)
238    {
239        if ($pValue == '') {
240            $pValue = self::VERTICAL_BOTTOM;
241        }
242
243        if ($this->isSupervisor) {
244            $styleArray = $this->getStyleArray(['vertical' => $pValue]);
245            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
246        } else {
247            $this->vertical = $pValue;
248        }
249
250        return $this;
251    }
252
253    /**
254     * Get TextRotation.
255     *
256     * @return int
257     */
258    public function getTextRotation()
259    {
260        if ($this->isSupervisor) {
261            return $this->getSharedComponent()->getTextRotation();
262        }
263
264        return $this->textRotation;
265    }
266
267    /**
268     * Set TextRotation.
269     *
270     * @param int $pValue
271     *
272     * @return $this
273     */
274    public function setTextRotation($pValue)
275    {
276        // Excel2007 value 255 => PhpSpreadsheet value -165
277        if ($pValue == self::TEXTROTATION_STACK_EXCEL) {
278            $pValue = self::TEXTROTATION_STACK_PHPSPREADSHEET;
279        }
280
281        // Set rotation
282        if (($pValue >= -90 && $pValue <= 90) || $pValue == self::TEXTROTATION_STACK_PHPSPREADSHEET) {
283            if ($this->isSupervisor) {
284                $styleArray = $this->getStyleArray(['textRotation' => $pValue]);
285                $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
286            } else {
287                $this->textRotation = $pValue;
288            }
289        } else {
290            throw new PhpSpreadsheetException('Text rotation should be a value between -90 and 90.');
291        }
292
293        return $this;
294    }
295
296    /**
297     * Get Wrap Text.
298     *
299     * @return bool
300     */
301    public function getWrapText()
302    {
303        if ($this->isSupervisor) {
304            return $this->getSharedComponent()->getWrapText();
305        }
306
307        return $this->wrapText;
308    }
309
310    /**
311     * Set Wrap Text.
312     *
313     * @param bool $pValue
314     *
315     * @return $this
316     */
317    public function setWrapText($pValue)
318    {
319        if ($pValue == '') {
320            $pValue = false;
321        }
322        if ($this->isSupervisor) {
323            $styleArray = $this->getStyleArray(['wrapText' => $pValue]);
324            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
325        } else {
326            $this->wrapText = $pValue;
327        }
328
329        return $this;
330    }
331
332    /**
333     * Get Shrink to fit.
334     *
335     * @return bool
336     */
337    public function getShrinkToFit()
338    {
339        if ($this->isSupervisor) {
340            return $this->getSharedComponent()->getShrinkToFit();
341        }
342
343        return $this->shrinkToFit;
344    }
345
346    /**
347     * Set Shrink to fit.
348     *
349     * @param bool $pValue
350     *
351     * @return $this
352     */
353    public function setShrinkToFit($pValue)
354    {
355        if ($pValue == '') {
356            $pValue = false;
357        }
358        if ($this->isSupervisor) {
359            $styleArray = $this->getStyleArray(['shrinkToFit' => $pValue]);
360            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
361        } else {
362            $this->shrinkToFit = $pValue;
363        }
364
365        return $this;
366    }
367
368    /**
369     * Get indent.
370     *
371     * @return int
372     */
373    public function getIndent()
374    {
375        if ($this->isSupervisor) {
376            return $this->getSharedComponent()->getIndent();
377        }
378
379        return $this->indent;
380    }
381
382    /**
383     * Set indent.
384     *
385     * @param int $pValue
386     *
387     * @return $this
388     */
389    public function setIndent($pValue)
390    {
391        if ($pValue > 0) {
392            if (
393                $this->getHorizontal() != self::HORIZONTAL_GENERAL &&
394                $this->getHorizontal() != self::HORIZONTAL_LEFT &&
395                $this->getHorizontal() != self::HORIZONTAL_RIGHT
396            ) {
397                $pValue = 0; // indent not supported
398            }
399        }
400        if ($this->isSupervisor) {
401            $styleArray = $this->getStyleArray(['indent' => $pValue]);
402            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
403        } else {
404            $this->indent = $pValue;
405        }
406
407        return $this;
408    }
409
410    /**
411     * Get read order.
412     *
413     * @return int
414     */
415    public function getReadOrder()
416    {
417        if ($this->isSupervisor) {
418            return $this->getSharedComponent()->getReadOrder();
419        }
420
421        return $this->readOrder;
422    }
423
424    /**
425     * Set read order.
426     *
427     * @param int $pValue
428     *
429     * @return $this
430     */
431    public function setReadOrder($pValue)
432    {
433        if ($pValue < 0 || $pValue > 2) {
434            $pValue = 0;
435        }
436        if ($this->isSupervisor) {
437            $styleArray = $this->getStyleArray(['readOrder' => $pValue]);
438            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
439        } else {
440            $this->readOrder = $pValue;
441        }
442
443        return $this;
444    }
445
446    /**
447     * Get hash code.
448     *
449     * @return string Hash code
450     */
451    public function getHashCode()
452    {
453        if ($this->isSupervisor) {
454            return $this->getSharedComponent()->getHashCode();
455        }
456
457        return md5(
458            $this->horizontal .
459            $this->vertical .
460            $this->textRotation .
461            ($this->wrapText ? 't' : 'f') .
462            ($this->shrinkToFit ? 't' : 'f') .
463            $this->indent .
464            $this->readOrder .
465            __CLASS__
466        );
467    }
468
469    protected function exportArray1(): array
470    {
471        $exportedArray = [];
472        $this->exportArray2($exportedArray, 'horizontal', $this->getHorizontal());
473        $this->exportArray2($exportedArray, 'indent', $this->getIndent());
474        $this->exportArray2($exportedArray, 'readOrder', $this->getReadOrder());
475        $this->exportArray2($exportedArray, 'shrinkToFit', $this->getShrinkToFit());
476        $this->exportArray2($exportedArray, 'textRotation', $this->getTextRotation());
477        $this->exportArray2($exportedArray, 'vertical', $this->getVertical());
478        $this->exportArray2($exportedArray, 'wrapText', $this->getWrapText());
479
480        return $exportedArray;
481    }
482}
483