Completed
Pull Request — master (#716)
by
unknown
02:50
created

WriterAbstract::openToMemory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 6
cp 0
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Box\Spout\Writer;
4
5
use Box\Spout\Common\Creator\HelperFactory;
6
use Box\Spout\Common\Entity\Row;
7
use Box\Spout\Common\Entity\Style\Style;
8
use Box\Spout\Common\Exception\InvalidArgumentException;
9
use Box\Spout\Common\Exception\IOException;
10
use Box\Spout\Common\Exception\SpoutException;
11
use Box\Spout\Common\Helper\GlobalFunctionsHelper;
12
use Box\Spout\Common\Manager\OptionsManagerInterface;
13
use Box\Spout\Writer\Common\Entity\Options;
14
use Box\Spout\Writer\Exception\WriterAlreadyOpenedException;
15
use Box\Spout\Writer\Exception\WriterNotOpenedException;
16
17
/**
18
 * Class WriterAbstract
19
 *
20
 * @abstract
21
 */
22
abstract class WriterAbstract implements WriterInterface
23
{
24
    /** @var string Path to the output file */
25
    protected $outputFilePath;
26
27
    /** @var resource Pointer to the file/stream we will write to */
28
    protected $filePointer;
29
30
    /** @var bool Indicates whether the writer has been opened or not */
31
    protected $isWriterOpened = false;
32
33
    /** @var GlobalFunctionsHelper Helper to work with global functions */
34
    protected $globalFunctionsHelper;
35
36
    /** @var HelperFactory $helperFactory */
37
    protected $helperFactory;
38
39
    /** @var OptionsManagerInterface Writer options manager */
40
    protected $optionsManager;
41
42
    /** @var string Content-Type value for the header - to be defined by child class */
43
    protected static $headerContentType;
44
45
    /**
46
     * @param OptionsManagerInterface $optionsManager
47
     * @param GlobalFunctionsHelper $globalFunctionsHelper
48
     * @param HelperFactory $helperFactory
49
     */
50 105
    public function __construct(
51
        OptionsManagerInterface $optionsManager,
52
        GlobalFunctionsHelper $globalFunctionsHelper,
53
        HelperFactory $helperFactory
54
    ) {
55 105
        $this->optionsManager = $optionsManager;
56 105
        $this->globalFunctionsHelper = $globalFunctionsHelper;
57 105
        $this->helperFactory = $helperFactory;
58 105
    }
59
60
    /**
61
     * Opens the streamer and makes it ready to accept data.
62
     *
63
     * @throws IOException If the writer cannot be opened
64
     * @return void
65
     */
66
    abstract protected function openWriter();
67
68
    /**
69
     * Adds a row to the currently opened writer.
70
     *
71
     * @param Row $row The row containing cells and styles
72
     * @throws WriterNotOpenedException If the workbook is not created yet
73
     * @throws IOException If unable to write data
74
     * @return void
75
     */
76
    abstract protected function addRowToWriter(Row $row);
77
78
    /**
79
     * Closes the streamer, preventing any additional writing.
80
     *
81
     * @return void
82
     */
83
    abstract protected function closeWriter();
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 2
    public function setDefaultRowStyle(Style $defaultStyle)
89
    {
90 2
        $this->optionsManager->setOption(Options::DEFAULT_ROW_STYLE, $defaultStyle);
91
92 2
        return $this;
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 90
    public function openToFile($outputFilePath)
99
    {
100 90
        $this->outputFilePath = $outputFilePath;
101
102 90
        $this->filePointer = $this->globalFunctionsHelper->fopen($this->outputFilePath, 'wb+');
103 90
        $this->throwIfFilePointerIsNotAvailable();
104
105 87
        $this->openWriter();
106 87
        $this->isWriterOpened = true;
107
108 87
        return $this;
109
    }
110
111
    /**
112
     * @codeCoverageIgnore
113
     * {@inheritdoc}
114
     */
115
    public function openToBrowser($outputFileName)
116
    {
117
        $this->outputFilePath = $this->globalFunctionsHelper->basename($outputFileName);
118
119
        $this->filePointer = $this->globalFunctionsHelper->fopen('php://output', 'w');
120
        $this->throwIfFilePointerIsNotAvailable();
121
122
        // Clear any previous output (otherwise the generated file will be corrupted)
123
        // @see https://github.com/box/spout/issues/241
124
        $this->globalFunctionsHelper->ob_end_clean();
125
126
        // Set headers
127
        $this->globalFunctionsHelper->header('Content-Type: ' . static::$headerContentType);
128
        $this->globalFunctionsHelper->header('Content-Disposition: attachment; filename="' . $this->outputFilePath . '"');
129
130
        /*
131
         * When forcing the download of a file over SSL,IE8 and lower browsers fail
132
         * if the Cache-Control and Pragma headers are not set.
133
         *
134
         * @see http://support.microsoft.com/KB/323308
135
         * @see https://github.com/liuggio/ExcelBundle/issues/45
136
         */
137
        $this->globalFunctionsHelper->header('Cache-Control: max-age=0');
138
        $this->globalFunctionsHelper->header('Pragma: public');
139
140
        $this->openWriter();
141
        $this->isWriterOpened = true;
142
143
        return $this;
144
    }
145
    
146
    public function openToMemory()
147
    {
148
        $this->filePointer = $this->globalFunctionsHelper->fopen('php://temp', 'r+');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->globalFunctionsHe...pen('php://temp', 'r+') can also be of type boolean. However, the property $filePointer is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
149
        $this->throwIfFilePointerIsNotAvailable();
150
151
        $this->openWriter();
152
        $this->isWriterOpened = true;
153
154
        return $this;
155
    }
156
157
    public function closeAndGetStream()
158
    {
159
        if (!$this->isWriterOpened) {
160
            return;
161
        }
162
163
        $this->closeWriter();
164
165
        $this->isWriterOpened = false;
166
167
        rewind($this->filePointer);
168
169
        return $this->filePointer;
170
    }
171
172
    /**
173
     * Checks if the pointer to the file/stream to write to is available.
174
     * Will throw an exception if not available.
175
     *
176
     * @throws IOException If the pointer is not available
177
     * @return void
178
     */
179 90
    protected function throwIfFilePointerIsNotAvailable()
180
    {
181 90
        if (!$this->filePointer) {
182 3
            throw new IOException('File pointer has not be opened');
183
        }
184 87
    }
185
186
    /**
187
     * Checks if the writer has already been opened, since some actions must be done before it gets opened.
188
     * Throws an exception if already opened.
189
     *
190
     * @param string $message Error message
191
     * @throws WriterAlreadyOpenedException If the writer was already opened and must not be.
192
     * @return void
193
     */
194 54
    protected function throwIfWriterAlreadyOpened($message)
195
    {
196 54
        if ($this->isWriterOpened) {
197 5
            throw new WriterAlreadyOpenedException($message);
198
        }
199 49
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204 85
    public function addRow(Row $row)
205
    {
206 85
        if ($this->isWriterOpened) {
207
            try {
208 75
                $this->addRowToWriter($row);
209 4
            } catch (SpoutException $e) {
210
                // if an exception occurs while writing data,
211
                // close the writer and remove all files created so far.
212 4
                $this->closeAndAttemptToCleanupAllFiles();
213
214
                // re-throw the exception to alert developers of the error
215 75
                throw $e;
216
            }
217
        } else {
218 10
            throw new WriterNotOpenedException('The writer needs to be opened before adding row.');
219
        }
220
221 73
        return $this;
222
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227 71
    public function addRows(array $rows)
228
    {
229 71
        foreach ($rows as $row) {
230 71
            if (!$row instanceof Row) {
231 2
                $this->closeAndAttemptToCleanupAllFiles();
232 2
                throw new InvalidArgumentException('The input should be an array of Row');
233
            }
234
235 69
            $this->addRow($row);
236
        }
237
238 63
        return $this;
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     */
244 81
    public function close()
245
    {
246 81
        if (!$this->isWriterOpened) {
247 1
            return;
248
        }
249
250 80
        $this->closeWriter();
251
252 80
        if (\is_resource($this->filePointer)) {
253 80
            $this->globalFunctionsHelper->fclose($this->filePointer);
254
        }
255
256 80
        $this->isWriterOpened = false;
257 80
    }
258
259
    /**
260
     * Closes the writer and attempts to cleanup all files that were
261
     * created during the writing process (temp files & final file).
262
     *
263
     * @return void
264
     */
265 6
    private function closeAndAttemptToCleanupAllFiles()
266
    {
267
        // close the writer, which should remove all temp files
268 6
        $this->close();
269
270
        // remove output file if it was created
271 6
        if ($this->globalFunctionsHelper->file_exists($this->outputFilePath)) {
272 5
            $outputFolderPath = \dirname($this->outputFilePath);
273 5
            $fileSystemHelper = $this->helperFactory->createFileSystemHelper($outputFolderPath);
274 5
            $fileSystemHelper->deleteFile($this->outputFilePath);
275
        }
276 6
    }
277
}
278