Completed
Push — develop_3.0 ( cc9a0b...7ec0f5 )
by Adrien
02:58
created

SharedStringsManager::writeString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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