throwIfSharedStringsFilePointerIsNotAvailable()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.0625
1
<?php
2
3
namespace Box\Spout\Writer\XLSX\Manager;
4
5
use Box\Spout\Common\Exception\IOException;
6
use Box\Spout\Common\Helper\Escaper;
7
8
/**
9
 * Class SharedStringsManager
10
 * This class provides functions to write shared strings
11
 */
12
class SharedStringsManager
13
{
14
    const SHARED_STRINGS_FILE_NAME = 'sharedStrings.xml';
15
16
    const SHARED_STRINGS_XML_FILE_FIRST_PART_HEADER = <<<'EOD'
17
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
18
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
19
EOD;
20
21
    /**
22
     * This number must be really big so that the no generated file will have more strings than that.
23
     * If the strings number goes above, characters will be overwritten in an unwanted way and will corrupt the file.
24
     */
25
    const DEFAULT_STRINGS_COUNT_PART = 'count="9999999999999" uniqueCount="9999999999999"';
26
27
    /** @var resource Pointer to the sharedStrings.xml file */
28
    protected $sharedStringsFilePointer;
29
30
    /** @var int Number of shared strings already written */
31
    protected $numSharedStrings = 0;
32
33
    /** @var Escaper\XLSX Strings escaper */
34
    protected $stringsEscaper;
35
36
    /**
37
     * @param string $xlFolder Path to the "xl" folder
38
     * @param Escaper\XLSX $stringsEscaper Strings escaper
39
     */
40 43
    public function __construct($xlFolder, $stringsEscaper)
41
    {
42 43
        $sharedStringsFilePath = $xlFolder . '/' . self::SHARED_STRINGS_FILE_NAME;
43 43
        $this->sharedStringsFilePointer = \fopen($sharedStringsFilePath, 'w');
44
45 43
        $this->throwIfSharedStringsFilePointerIsNotAvailable();
46
47
        // the headers is split into different parts so that we can fseek and put in the correct count and uniqueCount later
48 43
        $header = self::SHARED_STRINGS_XML_FILE_FIRST_PART_HEADER . ' ' . self::DEFAULT_STRINGS_COUNT_PART . '>';
49 43
        \fwrite($this->sharedStringsFilePointer, $header);
50
51 43
        $this->stringsEscaper = $stringsEscaper;
52 43
    }
53
54
    /**
55
     * Checks if the book has been created. Throws an exception if not created yet.
56
     *
57
     * @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
58
     * @return void
59
     */
60 43
    protected function throwIfSharedStringsFilePointerIsNotAvailable()
61
    {
62 43
        if (!$this->sharedStringsFilePointer) {
63
            throw new IOException('Unable to open shared strings file for writing.');
64
        }
65 43
    }
66
67
    /**
68
     * Writes the given string into the sharedStrings.xml file.
69
     * Starting and ending whitespaces are preserved.
70
     *
71
     * @param string $string
72
     * @return int ID of the written shared string
73
     */
74 3
    public function writeString($string)
75
    {
76 3
        \fwrite($this->sharedStringsFilePointer, '<si><t xml:space="preserve">' . $this->stringsEscaper->escape($string) . '</t></si>');
77 3
        $this->numSharedStrings++;
78
79
        // Shared string ID is zero-based
80 3
        return ($this->numSharedStrings - 1);
81
    }
82
83
    /**
84
     * Finishes writing the data in the sharedStrings.xml file and closes the file.
85
     *
86
     * @return void
87
     */
88 39
    public function close()
89
    {
90 39
        if (!\is_resource($this->sharedStringsFilePointer)) {
91
            return;
92
        }
93
94 39
        \fwrite($this->sharedStringsFilePointer, '</sst>');
95
96
        // Replace the default strings count with the actual number of shared strings in the file header
97 39
        $firstPartHeaderLength = \strlen(self::SHARED_STRINGS_XML_FILE_FIRST_PART_HEADER);
98 39
        $defaultStringsCountPartLength = \strlen(self::DEFAULT_STRINGS_COUNT_PART);
99
100
        // Adding 1 to take into account the space between the last xml attribute and "count"
101 39
        \fseek($this->sharedStringsFilePointer, $firstPartHeaderLength + 1);
102 39
        \fwrite($this->sharedStringsFilePointer, \sprintf("%-{$defaultStringsCountPartLength}s", 'count="' . $this->numSharedStrings . '" uniqueCount="' . $this->numSharedStrings . '"'));
103
104 39
        \fclose($this->sharedStringsFilePointer);
105 39
    }
106
}
107