Completed
Push — master ( 4a6546...7f8b95 )
by Adrien
02:30
created

SheetIterator::isActiveSheet()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 4
cp 1
rs 9.6666
c 0
b 0
f 0
cc 3
eloc 4
nc 3
nop 3
crap 3
1
<?php
2
3
namespace Box\Spout\Reader\ODS;
4
5
use Box\Spout\Common\Exception\IOException;
6
use Box\Spout\Reader\Exception\XMLProcessingException;
7
use Box\Spout\Reader\IteratorInterface;
8
use Box\Spout\Reader\ODS\Helper\SettingsHelper;
9
use Box\Spout\Reader\Wrapper\XMLReader;
10
11
/**
12
 * Class SheetIterator
13
 * Iterate over ODS sheet.
14
 *
15
 * @package Box\Spout\Reader\ODS
16
 */
17
class SheetIterator implements IteratorInterface
18
{
19
    const CONTENT_XML_FILE_PATH = 'content.xml';
20
21
    /** Definition of XML nodes name and attribute used to parse sheet data */
22
    const XML_NODE_TABLE = 'table:table';
23
    const XML_ATTRIBUTE_TABLE_NAME = 'table:name';
24
25
    /** @var string $filePath Path of the file to be read */
26
    protected $filePath;
27
28
    /** @var \Box\Spout\Reader\ODS\ReaderOptions Reader's current options */
29
    protected $options;
30
31
    /** @var XMLReader The XMLReader object that will help read sheet's XML data */
32
    protected $xmlReader;
33
34
    /** @var \Box\Spout\Common\Escaper\ODS Used to unescape XML data */
35
    protected $escaper;
36
37
    /** @var bool Whether there are still at least a sheet to be read */
38
    protected $hasFoundSheet;
39
40
    /** @var int The index of the sheet being read (zero-based) */
41
    protected $currentSheetIndex;
42
43
    /** @var string The name of the sheet that was defined as active */
44
    protected $activeSheetName;
45
46
    /**
47
     * @param string $filePath Path of the file to be read
48
     * @param \Box\Spout\Reader\ODS\ReaderOptions $options Reader's current options
49
     * @throws \Box\Spout\Reader\Exception\NoSheetsFoundException If there are no sheets in the file
50
     */
51 90
    public function __construct($filePath, $options)
52
    {
53 90
        $this->filePath = $filePath;
54 90
        $this->options = $options;
55 90
        $this->xmlReader = new XMLReader();
56
57
        /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
58 90
        $this->escaper = \Box\Spout\Common\Escaper\ODS::getInstance();
59
60 90
        $settingsHelper = new SettingsHelper();
61 90
        $this->activeSheetName = $settingsHelper->getActiveSheetName($filePath);
62 90
    }
63
64
    /**
65
     * Rewind the Iterator to the first element
66
     * @link http://php.net/manual/en/iterator.rewind.php
67
     *
68
     * @return void
69
     * @throws \Box\Spout\Common\Exception\IOException If unable to open the XML file containing sheets' data
70
     */
71 90
    public function rewind()
72
    {
73 90
        $this->xmlReader->close();
74
75 90
        if ($this->xmlReader->openFileInZip($this->filePath, self::CONTENT_XML_FILE_PATH) === false) {
76 3
            $contentXmlFilePath = $this->filePath . '#' . self::CONTENT_XML_FILE_PATH;
77 3
            throw new IOException("Could not open \"{$contentXmlFilePath}\".");
78
        }
79
80
        try {
81 87
            $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE);
82 87
        } catch (XMLProcessingException $exception) {
83 3
           throw new IOException("The content.xml file is invalid and cannot be read. [{$exception->getMessage()}]");
84
       }
85
86 84
        $this->currentSheetIndex = 0;
87 84
    }
88
89
    /**
90
     * Checks if current position is valid
91
     * @link http://php.net/manual/en/iterator.valid.php
92
     *
93
     * @return bool
94
     */
95 84
    public function valid()
96
    {
97 84
        return $this->hasFoundSheet;
98
    }
99
100
    /**
101
     * Move forward to next element
102
     * @link http://php.net/manual/en/iterator.next.php
103
     *
104
     * @return void
105
     */
106 81
    public function next()
107
    {
108 81
        $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE);
109
110 81
        if ($this->hasFoundSheet) {
111 15
            $this->currentSheetIndex++;
112 15
        }
113 81
    }
114
115
    /**
116
     * Return the current element
117
     * @link http://php.net/manual/en/iterator.current.php
118
     *
119
     * @return \Box\Spout\Reader\ODS\Sheet
120
     */
121 84
    public function current()
122
    {
123 84
        $escapedSheetName = $this->xmlReader->getAttribute(self::XML_ATTRIBUTE_TABLE_NAME);
124 84
        $sheetName = $this->escaper->unescape($escapedSheetName);
125 84
        $isActiveSheet = $this->isActiveSheet($sheetName, $this->currentSheetIndex, $this->activeSheetName);
126
127 84
        return new Sheet($this->xmlReader, $this->currentSheetIndex, $sheetName, $isActiveSheet, $this->options);
128
    }
129
130
    /**
131
     * Returns whether the current sheet was defined as the active one
132
     *
133
     * @param string $sheetName Name of the current sheet
134
     * @param int $sheetIndex Index of the current sheet
135
     * @param string|null Name of the sheet that was defined as active or NULL if none defined
136
     * @return bool Whether the current sheet was defined as the active one
137
     */
138 84
    private function isActiveSheet($sheetName, $sheetIndex, $activeSheetName)
139
    {
140
        // The given sheet is active if its name matches the defined active sheet's name
141
        // or if no information about the active sheet was found, it defaults to the first sheet.
142
        return (
143 84
            ($activeSheetName === null && $sheetIndex === 0) ||
144 45
            ($activeSheetName === $sheetName)
145 84
        );
146
    }
147
148
    /**
149
     * Return the key of the current element
150
     * @link http://php.net/manual/en/iterator.key.php
151
     *
152
     * @return int
153
     */
154 72
    public function key()
155
    {
156 72
        return $this->currentSheetIndex + 1;
157
    }
158
159
    /**
160
     * Cleans up what was created to iterate over the object.
161
     *
162
     * @return void
163
     */
164 81
    public function end()
165
    {
166 81
        $this->xmlReader->close();
167 81
    }
168
}
169