Completed
Push — master ( 71a6f6...e9cd7a )
by Adrien
9s
created

SharedStringsHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

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