Failed Conditions
Push — perf-tests ( 50942d...2fc93e )
by Adrien
14:53
created

Sheet   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 18
c 3
b 0
f 1
lcom 1
cbo 1
dl 0
loc 146
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getIndex() 0 4 1
A getName() 0 4 1
A setName() 0 16 2
B isNameValid() 0 16 6
A doesContainInvalidCharacters() 0 4 1
A doesStartOrEndWithSingleQuote() 0 7 2
A isNameUnique() 0 10 4
1
<?php
2
3
namespace Box\Spout\Writer\Common;
4
5
use Box\Spout\Common\Helper\StringHelper;
6
use Box\Spout\Writer\Exception\InvalidSheetNameException;
7
8
/**
9
 * Class Sheet
10
 * External representation of a worksheet within a ODS file
11
 *
12
 * @package Box\Spout\Writer\Common
13
 */
14
class Sheet
15
{
16
    const DEFAULT_SHEET_NAME_PREFIX = 'Sheet';
17
18
    /** Sheet name should not exceed 31 characters */
19
    const MAX_LENGTH_SHEET_NAME = 31;
20
21
    /** @var array Invalid characters that cannot be contained in the sheet name */
22
    private static $INVALID_CHARACTERS_IN_SHEET_NAME = ['\\', '/', '?', '*', ':', '[', ']'];
23
24
    /** @var array Associative array [SHEET_INDEX] => [SHEET_NAME] keeping track of sheets' name to enforce uniqueness */
25
    protected static $SHEETS_NAME_USED = [];
26
27
    /** @var int Index of the sheet, based on order in the workbook (zero-based) */
28
    protected $index;
29
30
    /** @var string Name of the sheet */
31
    protected $name;
32
33
    /** @var \Box\Spout\Common\Helper\StringHelper */
34
    protected $stringHelper;
35
36
    /**
37
     * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based)
38
     */
39
    public function __construct($sheetIndex)
40
    {
41
        $this->index = $sheetIndex;
42
        $this->stringHelper = new StringHelper();
43
        $this->setName(self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1));
44
    }
45
46
    /**
47
     * @api
48
     * @return int Index of the sheet, based on order in the workbook (zero-based)
49
     */
50
    public function getIndex()
51
    {
52
        return $this->index;
53
    }
54
55
    /**
56
     * @api
57
     * @return string Name of the sheet
58
     */
59
    public function getName()
60
    {
61
        return $this->name;
62
    }
63
64
    /**
65
     * Sets the name of the sheet. Note that Excel has some restrictions on the name:
66
     *  - it should not be blank
67
     *  - it should not exceed 31 characters
68
     *  - it should not contain these characters: \ / ? * : [ or ]
69
     *  - it should be unique
70
     *
71
     * @api
72
     * @param string $name Name of the sheet
73
     * @return Sheet
74
     * @throws \Box\Spout\Writer\Exception\InvalidSheetNameException If the sheet's name is invalid.
75
     */
76
    public function setName($name)
77
    {
78
        if (!$this->isNameValid($name)) {
79
            $errorMessage = "The sheet's name is invalid. It did not meet at least one of these requirements:\n";
80
            $errorMessage .= " - It should not be blank\n";
81
            $errorMessage .= " - It should not exceed 31 characters\n";
82
            $errorMessage .= " - It should not contain these characters: \\ / ? * : [ or ]\n";
83
            $errorMessage .= " - It should be unique";
84
            throw new InvalidSheetNameException($errorMessage);
85
        }
86
87
        $this->name = $name;
88
        self::$SHEETS_NAME_USED[$this->index] = $name;
89
90
        return $this;
91
    }
92
93
    /**
94
     * Returns whether the given sheet's name is valid.
95
     * @see Sheet::setName for validity rules.
96
     *
97
     * @param string $name
98
     * @return bool TRUE if the name is valid, FALSE otherwise.
99
     */
100
    protected function isNameValid($name)
101
    {
102
        if (!is_string($name)) {
103
            return false;
104
        }
105
106
        $nameLength = $this->stringHelper->getStringLength($name);
107
108
        return (
109
            $nameLength > 0 &&
110
            $nameLength <= self::MAX_LENGTH_SHEET_NAME &&
111
            !$this->doesContainInvalidCharacters($name) &&
112
            $this->isNameUnique($name) &&
113
            !$this->doesStartOrEndWithSingleQuote($name)
114
        );
115
    }
116
117
    /**
118
     * Returns whether the given name contains at least one invalid character.
119
     * @see Sheet::$INVALID_CHARACTERS_IN_SHEET_NAME for the full list.
120
     *
121
     * @param string $name
122
     * @return bool TRUE if the name contains invalid characters, FALSE otherwise.
123
     */
124
    protected function doesContainInvalidCharacters($name)
125
    {
126
        return (str_replace(self::$INVALID_CHARACTERS_IN_SHEET_NAME, '', $name) !== $name);
127
    }
128
129
    /**
130
     * Returns whether the given name starts or ends with a single quote
131
     *
132
     * @param string $name
133
     * @return bool TRUE if the name starts or ends with a single quote, FALSE otherwise.
134
     */
135
    protected function doesStartOrEndWithSingleQuote($name)
136
    {
137
        $startsWithSingleQuote = ($this->stringHelper->getCharFirstOccurrencePosition('\'', $name) === 0);
138
        $endsWithSingleQuote = ($this->stringHelper->getCharLastOccurrencePosition('\'', $name) === ($this->stringHelper->getStringLength($name) - 1));
139
140
        return ($startsWithSingleQuote || $endsWithSingleQuote);
141
    }
142
143
    /**
144
     * Returns whether the given name is unique.
145
     *
146
     * @param string $name
147
     * @return bool TRUE if the name is unique, FALSE otherwise.
148
     */
149
    protected function isNameUnique($name)
150
    {
151
        foreach (self::$SHEETS_NAME_USED as $sheetIndex => $sheetName) {
152
            if ($sheetIndex !== $this->index && $sheetName === $name) {
153
                return false;
154
            }
155
        }
156
157
        return true;
158
    }
159
}
160