Merge 83b44eca2751cbb1d91c3d350df6a829ca51d6aa into 5d4166196ad5bcde89f7316d273ef13eff144666
This commit is contained in:
commit
9e83cc38b1
69
src/Spout/Writer/XLSX/Helper/SizeCalculator.php
Normal file
69
src/Spout/Writer/XLSX/Helper/SizeCalculator.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Box\Spout\Writer\XLSX\Helper;
|
||||
|
||||
class SizeCalculator
|
||||
{
|
||||
/** @var SizeCollection */
|
||||
private $sizeCollection;
|
||||
|
||||
/** @var array */
|
||||
private $characterSizes;
|
||||
|
||||
/**
|
||||
* SizeCalculator constructor.
|
||||
*
|
||||
* @param SizeCollection $sizeCollection
|
||||
*/
|
||||
public function __construct(SizeCollection $sizeCollection)
|
||||
{
|
||||
$this->sizeCollection = $sizeCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the estimated width of a cell value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int $fontSize
|
||||
* @return float
|
||||
*/
|
||||
public function getCellWidth($value, $fontSize)
|
||||
{
|
||||
$width = 1;
|
||||
foreach ($this->getSingleCharacterArray($value) as $character) {
|
||||
if (isset($this->characterSizes[$character])) {
|
||||
$width += $this->characterSizes[$character];
|
||||
} elseif (strlen($character)) {
|
||||
$width += 0.1 * $fontSize;
|
||||
}
|
||||
}
|
||||
|
||||
return $width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set proper font sizes by font.
|
||||
*
|
||||
* @param string $fontName
|
||||
* @param string $fontSize
|
||||
*/
|
||||
public function setFont($fontName, $fontSize)
|
||||
{
|
||||
$this->characterSizes = $this->sizeCollection->get($fontName, $fontSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split value into individual characters.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
private function getSingleCharacterArray($value)
|
||||
{
|
||||
if (mb_strlen($value) == strlen($value)) {
|
||||
return str_split($value);
|
||||
}
|
||||
|
||||
return preg_split('~~u', $value, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
}
|
88
src/Spout/Writer/XLSX/Helper/SizeCollection.php
Normal file
88
src/Spout/Writer/XLSX/Helper/SizeCollection.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Box\Spout\Writer\XLSX\Helper;
|
||||
|
||||
/**
|
||||
* SizeCollection to build and hold widths & heights of individual characters.
|
||||
*/
|
||||
class SizeCollection
|
||||
{
|
||||
/** Constant for default character size. */
|
||||
const BASE_SIZE = 12;
|
||||
|
||||
/** @var array Contains character widths/heights for each font & size. */
|
||||
private $sizes = array();
|
||||
|
||||
/**
|
||||
* SizeCollection constructor to read character sizes from csv.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$fh = fopen(dirname(__FILE__) . '/size_collection.csv', 'r');
|
||||
$head = fgetcsv($fh);
|
||||
unset($head[0], $head[1]);
|
||||
|
||||
while ($row = fgetcsv($fh)) {
|
||||
$this->addSizesToCollection($head, $row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return character sizes for given font name.
|
||||
*
|
||||
* @param string $fontName
|
||||
* @param int $fontSize
|
||||
* @return array
|
||||
*/
|
||||
public function get($fontName, $fontSize)
|
||||
{
|
||||
if (isset($this->sizes[$fontName][$fontSize])) {
|
||||
return $this->sizes[$fontName][$fontSize];
|
||||
}
|
||||
|
||||
return $this->calculate($fontName, $fontSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate character widths based on font name and size.
|
||||
*
|
||||
* @param string $fontName
|
||||
* @param int $fontSize
|
||||
* @return array
|
||||
*/
|
||||
private function calculate($fontName, $fontSize)
|
||||
{
|
||||
foreach ($this->getBaseSizes($fontName) as $character => $size) {
|
||||
$size = round($size / self::BASE_SIZE * $fontSize, 3);
|
||||
$this->sizes[$fontName][$fontSize][$character] = $size;
|
||||
}
|
||||
return $this->sizes[$fontName][$fontSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get character base widths by font name or default.
|
||||
*
|
||||
* @param string $fontName
|
||||
* @return array
|
||||
*/
|
||||
private function getBaseSizes($fontName)
|
||||
{
|
||||
if (isset($this->sizes[$fontName])) {
|
||||
return $this->sizes[$fontName][self::BASE_SIZE];
|
||||
}
|
||||
return $this->sizes['Calibri'][self::BASE_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add character widths for a single font.
|
||||
*
|
||||
* @param array $keys
|
||||
* @param array $values
|
||||
*/
|
||||
private function addSizesToCollection(array $keys, array $values)
|
||||
{
|
||||
$fontName = array_shift($values);
|
||||
$fontSize = array_shift($values);
|
||||
$this->sizes[$fontName][$fontSize] = array_combine($keys, $values);
|
||||
}
|
||||
}
|
8
src/Spout/Writer/XLSX/Helper/size_collection.csv
Normal file
8
src/Spout/Writer/XLSX/Helper/size_collection.csv
Normal file
@ -0,0 +1,8 @@
|
||||
font,size,height," ",!,"""",#,$,%,&,',(,),*,+,",",-,.,/,0,1,2,3,4,5,6,7,8,9,:,;,<,=,>,?,@,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,[,"\\",],^,_,`,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,{,|,},~,,€,,‚,ƒ,„,…,†,‡,ˆ,‰,Š,‹,Œ,,Ž,,,‘,’,“,”,•,–,—,˜,™,š,›,œ,,ž,Ÿ, ,¡,¢,£,¤,¥,¦,§,¨,©,ª,«,¬,,®,¯,°,±,²,³,´,µ,¶,·,¸,¹,º,»,¼,½,¾,¿,À,Á,Â,Ã,Ä,Å,Æ,Ç,È,É,Ê,Ë,Ì,Í,Î,Ï,Ð,Ñ,Ò,Ó,Ô,Õ,Ö,×,Ø,Ù,Ú,Û,Ü,Ý,Þ,ß,à,á,â,ã,ä,å,æ,ç,è,é,ê,ë,ì,í,î,ï,ð,ñ,ò,ó,ô,õ,ö,÷,ø,ù,ú,û,ü,ý,þ,ÿ
|
||||
Arial,12,16,0.559,0.547,0.795,1.180,1.180,1.801,1.429,0.435,0.683,0.683,0.807,1.180,0.547,0.683,0.547,0.571,1.180,1.019,1.180,1.180,1.180,1.180,1.180,1.180,1.180,1.180,0.547,0.547,1.180,1.180,1.180,1.180,2.050,1.441,1.404,1.540,1.528,1.404,1.292,1.553,1.528,0.547,1.043,1.416,1.168,1.665,1.528,1.553,1.404,1.553,1.540,1.416,1.304,1.528,1.429,1.925,1.429,1.429,1.304,0.559,1.068,0.559,1.056,1.205,0.671,1.180,1.168,1.056,1.168,1.180,0.571,1.168,1.155,0.534,0.559,1.043,0.534,1.665,1.155,1.180,1.168,1.168,0.683,1.056,0.571,1.155,1.056,1.553,1.056,1.056,1.056,0.683,0.534,0.683,1.180,1.503,1.193,1.503,0.547,1.180,0.683,2.025,1.180,1.180,0.696,2.050,1.416,0.683,2.037,1.503,1.304,1.503,1.503,0.534,0.547,0.683,0.683,0.795,1.193,2.050,0.696,2.012,1.056,0.683,1.925,1.503,1.056,1.429,0.509,0.658,1.180,1.180,1.180,1.193,0.534,1.180,0.683,1.553,0.807,1.155,1.180,0.683,1.553,1.205,0.795,1.180,0.696,0.696,0.671,1.155,1.180,0.658,0.683,0.671,0.807,1.155,1.689,1.689,1.689,1.280,1.441,1.441,1.441,1.441,1.441,1.441,2.050,1.540,1.404,1.404,1.404,1.404,0.559,0.559,0.584,0.571,1.553,1.528,1.553,1.553,1.553,1.553,1.553,1.168,1.553,1.528,1.528,1.528,1.528,1.429,1.404,1.292,1.180,1.180,1.180,1.180,1.180,1.180,1.801,1.056,1.180,1.180,1.180,1.180,0.559,0.559,0.584,0.571,1.180,1.155,1.180,1.180,1.180,1.180,1.180,1.180,1.280,1.155,1.155,1.155,1.155,1.056,1.168,1.056
|
||||
Calibri,12,14,0.559,0.634,0.783,1.056,1.031,1.416,1.404,0.522,0.658,0.658,1.019,1.043,0.534,0.658,0.522,0.807,1.031,1.019,1.031,1.031,1.031,1.031,1.031,1.031,1.031,1.031,0.522,0.534,1.031,1.043,1.031,0.907,1.776,1.180,1.155,1.168,1.280,1.031,0.907,1.280,1.280,0.522,0.671,1.031,0.919,1.652,1.280,1.404,1.031,1.416,1.155,0.907,1.043,1.280,1.180,1.764,1.056,1.043,1.043,0.658,1.553,0.658,1.043,1.056,0.658,1.031,1.031,0.907,1.031,1.031,0.671,1.043,1.031,0.522,0.547,0.907,0.522,1.516,1.031,1.031,1.031,1.031,0.671,0.907,0.671,1.031,0.907,1.416,0.907,0.907,0.783,0.671,0.857,0.671,1.043,1.056,1.056,1.056,0.534,0.708,0.907,1.404,1.019,1.019,0.795,2.161,0.907,0.658,1.776,1.056,1.043,1.056,1.056,0.534,0.534,0.907,0.907,1.019,1.056,1.776,0.907,1.404,0.907,0.658,1.776,1.056,0.795,1.043,0.509,0.634,1.031,1.031,1.056,1.043,0.969,1.031,0.770,1.652,0.783,1.031,1.043,0.658,1.031,0.783,0.671,1.043,0.671,0.671,0.658,1.155,1.155,0.522,0.658,0.547,0.907,1.031,1.292,1.416,1.416,0.907,1.180,1.180,1.180,1.180,1.180,1.180,1.540,1.168,1.031,1.031,1.031,1.031,0.534,0.534,0.559,0.559,1.292,1.280,1.404,1.404,1.404,1.404,1.404,1.043,1.404,1.280,1.280,1.280,1.280,1.043,1.031,1.031,1.031,1.031,1.031,1.031,1.031,1.031,1.528,0.907,1.031,1.031,1.031,1.031,0.547,0.547,0.571,0.547,1.031,1.031,1.031,1.031,1.031,1.031,1.031,1.043,1.031,1.031,1.031,1.031,1.031,0.907,1.031,0.907
|
||||
Georgia,12,15,0.559,0.658,0.919,1.292,1.280,1.677,1.441,0.435,0.807,0.807,1.043,1.292,0.559,0.807,0.547,1.043,1.304,0.919,1.180,1.180,1.180,1.056,1.180,1.068,1.292,1.180,0.658,0.658,1.280,1.292,1.280,1.043,1.901,1.453,1.304,1.317,1.553,1.317,1.304,1.553,1.677,0.807,1.056,1.441,1.304,1.925,1.565,1.553,1.304,1.553,1.441,1.180,1.304,1.553,1.441,2.062,1.441,1.329,1.304,0.795,2.050,0.795,1.280,1.329,1.006,1.056,1.193,0.944,1.180,1.056,0.708,1.056,1.180,0.683,0.696,1.180,0.683,1.801,1.193,1.180,1.180,1.193,0.932,0.932,0.807,1.180,1.081,1.578,1.056,1.081,0.932,0.932,0.758,0.932,1.292,2.000,1.317,2.000,0.559,1.093,0.919,1.652,1.043,1.043,1.031,2.422,1.180,0.907,2.050,2.000,1.304,2.000,2.000,0.547,0.559,0.919,0.919,0.795,1.304,1.789,1.031,1.925,0.932,0.907,1.677,2.000,0.932,1.329,0.509,0.658,1.168,1.304,1.155,1.329,0.758,1.056,1.031,1.925,1.043,1.155,1.292,0.807,1.925,1.329,0.919,1.292,1.043,1.031,1.006,1.180,1.056,0.547,1.006,1.031,1.056,1.155,2.161,2.174,2.161,1.043,1.453,1.453,1.453,1.453,1.453,1.453,2.062,1.317,1.317,1.317,1.317,1.317,0.807,0.807,0.807,0.807,1.553,1.565,1.553,1.553,1.553,1.553,1.553,1.280,1.553,1.553,1.553,1.553,1.553,1.329,1.304,1.180,1.056,1.056,1.056,1.056,1.056,1.056,1.553,0.944,1.056,1.056,1.056,1.056,0.683,0.683,0.696,0.696,1.168,1.193,1.180,1.180,1.180,1.180,1.180,1.292,1.180,1.180,1.180,1.180,1.180,1.081,1.193,1.081
|
||||
"Segoe UI",12,16,0.559,0.658,0.795,1.193,1.155,1.677,1.677,0.534,0.671,0.671,0.932,1.404,0.435,0.795,0.435,0.832,1.168,1.155,1.168,1.155,1.180,1.155,1.168,1.168,1.168,1.168,0.435,0.435,1.379,1.404,1.379,0.919,1.901,1.317,1.168,1.304,1.416,1.043,1.043,1.416,1.404,0.559,0.795,1.180,1.043,1.776,1.528,1.553,1.168,1.553,1.292,1.168,1.068,1.404,1.304,1.925,1.193,1.180,1.180,0.671,1.578,0.671,1.404,0.932,0.559,1.056,1.168,0.932,1.180,1.056,0.696,1.180,1.155,0.534,0.571,1.043,0.534,1.776,1.155,1.180,1.168,1.180,0.795,0.932,0.696,1.155,1.056,1.553,0.944,1.056,0.932,0.683,0.534,0.683,1.404,1.292,1.168,1.292,0.547,1.168,0.807,1.528,0.807,0.807,0.807,2.422,1.168,0.683,1.925,1.292,1.180,1.292,1.292,0.435,0.435,0.807,0.807,0.907,1.056,2.050,0.696,1.540,0.932,0.683,1.925,1.292,0.932,1.180,0.509,0.658,1.155,1.168,1.180,1.180,0.534,0.919,0.919,1.776,0.807,1.056,1.404,0.795,1.776,0.932,0.807,1.404,0.807,0.795,0.671,1.168,0.932,0.435,0.447,0.783,0.932,1.056,1.901,1.913,1.913,0.919,1.317,1.317,1.317,1.317,1.317,1.317,1.801,1.304,1.043,1.043,1.043,1.043,0.559,0.571,0.584,0.584,1.429,1.528,1.553,1.553,1.553,1.553,1.553,1.379,1.553,1.404,1.404,1.404,1.404,1.180,1.168,1.168,1.056,1.056,1.056,1.056,1.056,1.056,1.677,0.932,1.056,1.056,1.056,1.056,0.559,0.559,0.584,0.584,1.180,1.155,1.180,1.180,1.180,1.180,1.180,1.404,1.193,1.155,1.155,1.155,1.155,1.056,1.168,1.056
|
||||
Tahoma,12,16,0.683,0.658,0.807,1.528,1.168,2.037,1.441,0.435,0.807,0.807,1.168,1.528,0.671,0.807,0.658,0.820,1.180,1.155,1.180,1.168,1.180,1.168,1.180,1.180,1.180,1.180,0.770,0.795,1.516,1.528,1.528,1.056,1.901,1.317,1.180,1.304,1.416,1.168,1.056,1.416,1.404,0.807,0.919,1.180,1.043,1.540,1.404,1.429,1.168,1.429,1.304,1.180,1.205,1.404,1.317,1.814,1.193,1.205,1.180,0.795,1.565,0.795,1.528,1.193,1.130,1.056,1.168,0.944,1.168,1.056,0.696,1.168,1.155,0.534,0.683,1.056,0.534,1.665,1.155,1.180,1.168,1.168,0.795,0.932,0.696,1.155,1.056,1.553,1.056,1.056,0.932,1.043,0.758,1.056,1.528,2.000,1.193,2.000,0.460,1.193,0.832,1.652,1.155,1.155,1.155,2.795,1.180,0.795,2.050,2.000,1.180,2.000,2.000,0.447,0.447,0.820,0.820,0.932,1.193,1.938,1.155,1.789,0.932,0.795,1.925,2.000,0.932,1.205,0.621,0.658,1.168,1.180,1.180,1.180,0.758,1.168,1.143,1.925,1.043,1.180,1.528,0.807,1.925,1.193,1.043,1.528,1.031,1.031,1.118,1.168,1.168,0.770,1.130,1.031,1.056,1.168,2.025,2.037,2.025,1.043,1.317,1.317,1.317,1.317,1.317,1.317,1.938,1.304,1.168,1.168,1.168,1.168,0.807,0.807,0.820,0.807,1.429,1.404,1.429,1.429,1.429,1.429,1.429,1.528,1.429,1.404,1.404,1.404,1.404,1.205,1.168,1.168,1.056,1.056,1.056,1.056,1.056,1.056,1.801,0.944,1.056,1.056,1.056,1.056,0.571,0.559,0.584,0.571,1.180,1.155,1.180,1.180,1.180,1.180,1.180,1.528,1.180,1.155,1.155,1.155,1.155,1.056,1.168,1.056
|
||||
"Times New Roman",12,16,0.559,0.658,0.907,1.056,1.056,1.677,1.553,0.435,0.683,0.683,1.031,1.180,0.559,0.683,0.534,0.571,1.056,1.031,1.056,1.043,1.056,1.043,1.056,1.056,1.056,1.056,0.547,0.547,1.180,1.180,1.180,0.932,1.925,1.553,1.416,1.429,1.540,1.304,1.180,1.553,1.553,0.683,0.820,1.553,1.304,1.801,1.565,1.540,1.180,1.540,1.429,1.168,1.304,1.553,1.553,1.925,1.553,1.553,1.304,0.671,1.068,0.683,1.056,1.081,0.671,0.944,1.068,0.932,1.068,0.932,0.708,1.056,1.056,0.571,0.584,1.068,0.571,1.565,1.056,1.056,1.068,1.056,0.696,0.807,0.571,1.056,1.056,1.553,1.056,1.056,0.932,1.019,0.410,1.019,1.180,1.516,1.068,1.516,0.671,1.056,0.932,2.025,1.056,1.031,0.683,2.050,1.168,0.683,1.801,1.516,1.304,1.516,1.516,0.547,0.547,0.932,0.932,0.795,1.081,2.075,0.696,2.050,0.807,0.683,1.553,1.516,0.932,1.553,0.509,0.658,1.043,1.056,1.056,1.056,0.410,1.031,0.683,1.553,0.584,1.056,1.180,0.683,1.553,1.081,0.807,1.180,0.683,0.683,0.671,1.168,0.957,0.658,0.658,0.658,0.683,1.056,1.540,1.540,1.553,0.932,1.553,1.553,1.553,1.553,1.553,1.553,1.814,1.429,1.304,1.304,1.304,1.304,0.683,0.683,0.683,0.683,1.540,1.565,1.540,1.540,1.540,1.540,1.540,1.155,1.540,1.553,1.553,1.553,1.553,1.553,1.180,1.056,0.944,0.944,0.944,0.944,0.944,0.944,1.429,0.932,0.932,0.932,0.932,0.932,0.571,0.571,0.571,0.571,1.056,1.056,1.056,1.056,1.056,1.056,1.056,1.180,1.056,1.056,1.056,1.056,1.056,1.056,1.068,1.056
|
||||
Verdana,12,15,0.807,0.770,0.919,1.652,1.292,2.161,1.565,0.547,0.919,0.907,1.280,1.652,0.783,0.919,0.770,0.944,1.292,1.267,1.292,1.280,1.304,1.292,1.292,1.292,1.304,1.304,0.882,0.907,1.640,1.652,1.640,1.155,2.025,1.429,1.416,1.429,1.540,1.292,1.168,1.553,1.528,0.907,0.919,1.416,1.168,1.652,1.528,1.665,1.292,1.665,1.429,1.416,1.304,1.528,1.429,2.050,1.429,1.304,1.429,0.907,1.814,0.907,1.652,1.329,1.230,1.292,1.292,1.056,1.292,1.292,0.820,1.292,1.280,0.547,0.807,1.180,0.534,2.025,1.280,1.292,1.292,1.292,0.919,1.056,0.807,1.280,1.180,1.677,1.180,1.180,1.056,1.280,0.882,1.280,1.652,2.000,1.304,2.000,0.571,1.317,0.944,1.652,1.280,1.280,1.255,3.031,1.416,0.907,2.174,2.000,1.429,2.000,2.000,0.571,0.559,0.944,0.932,1.155,1.280,2.025,1.280,2.012,1.056,0.907,2.037,2.000,1.056,1.304,0.733,0.770,1.280,1.292,1.292,1.304,0.882,1.280,1.255,2.025,1.155,1.280,1.652,0.919,2.025,1.329,1.155,1.652,1.155,1.155,1.230,1.280,1.280,0.770,1.242,1.143,1.168,1.292,2.025,2.037,2.037,1.168,1.429,1.429,1.429,1.429,1.429,1.429,2.037,1.429,1.292,1.292,1.292,1.292,0.919,0.907,0.919,0.919,1.553,1.528,1.665,1.665,1.665,1.665,1.665,1.627,1.665,1.528,1.528,1.528,1.528,1.304,1.292,1.292,1.292,1.292,1.292,1.292,1.292,1.292,1.925,1.056,1.292,1.292,1.292,1.292,0.559,0.559,0.584,0.571,1.292,1.280,1.292,1.292,1.292,1.292,1.292,1.652,1.292,1.280,1.280,1.280,1.280,1.180,1.292,1.180
|
|
@ -5,6 +5,8 @@ namespace Box\Spout\Writer\XLSX\Internal;
|
||||
use Box\Spout\Writer\Common\Internal\AbstractWorkbook;
|
||||
use Box\Spout\Writer\XLSX\Helper\FileSystemHelper;
|
||||
use Box\Spout\Writer\XLSX\Helper\SharedStringsHelper;
|
||||
use Box\Spout\Writer\XLSX\Helper\SizeCalculator;
|
||||
use Box\Spout\Writer\XLSX\Helper\SizeCollection;
|
||||
use Box\Spout\Writer\XLSX\Helper\StyleHelper;
|
||||
use Box\Spout\Writer\Common\Sheet;
|
||||
|
||||
@ -26,6 +28,9 @@ class Workbook extends AbstractWorkbook
|
||||
/** @var bool Whether inline or shared strings should be used */
|
||||
protected $shouldUseInlineStrings;
|
||||
|
||||
/** @var bool Determine whether cell widths and heights should be calculated */
|
||||
protected $shouldUseCellAutosizing;
|
||||
|
||||
/** @var \Box\Spout\Writer\XLSX\Helper\FileSystemHelper Helper to perform file system operations */
|
||||
protected $fileSystemHelper;
|
||||
|
||||
@ -35,23 +40,29 @@ class Workbook extends AbstractWorkbook
|
||||
/** @var \Box\Spout\Writer\XLSX\Helper\StyleHelper Helper to apply styles */
|
||||
protected $styleHelper;
|
||||
|
||||
/** @var \Box\Spout\Writer\XLSX\Helper\SizeCalculator To calculate cell sizes */
|
||||
protected $sizeCalculator;
|
||||
|
||||
/**
|
||||
* @param string $tempFolder
|
||||
* @param bool $shouldUseInlineStrings
|
||||
* @param bool $shouldUseCellAutosizing
|
||||
* @param bool $shouldCreateNewSheetsAutomatically
|
||||
* @param \Box\Spout\Writer\Style\Style $defaultRowStyle
|
||||
* @throws \Box\Spout\Common\Exception\IOException If unable to create at least one of the base folders
|
||||
*/
|
||||
public function __construct($tempFolder, $shouldUseInlineStrings, $shouldCreateNewSheetsAutomatically, $defaultRowStyle)
|
||||
public function __construct($tempFolder, $shouldUseInlineStrings, $shouldUseCellAutosizing, $shouldCreateNewSheetsAutomatically, $defaultRowStyle)
|
||||
{
|
||||
parent::__construct($shouldCreateNewSheetsAutomatically, $defaultRowStyle);
|
||||
|
||||
$this->shouldUseInlineStrings = $shouldUseInlineStrings;
|
||||
$this->shouldUseCellAutosizing = $shouldUseCellAutosizing;
|
||||
|
||||
$this->fileSystemHelper = new FileSystemHelper($tempFolder);
|
||||
$this->fileSystemHelper->createBaseFilesAndFolders();
|
||||
|
||||
$this->styleHelper = new StyleHelper($defaultRowStyle);
|
||||
$this->sizeCalculator = new SizeCalculator(new SizeCollection());
|
||||
|
||||
// This helper will be shared by all sheets
|
||||
$xlFolder = $this->fileSystemHelper->getXlFolder();
|
||||
@ -86,7 +97,15 @@ class Workbook extends AbstractWorkbook
|
||||
$sheet = new Sheet($newSheetIndex, $this->internalId);
|
||||
|
||||
$worksheetFilesFolder = $this->fileSystemHelper->getXlWorksheetsFolder();
|
||||
$worksheet = new Worksheet($sheet, $worksheetFilesFolder, $this->sharedStringsHelper, $this->styleHelper, $this->shouldUseInlineStrings);
|
||||
$worksheet = new Worksheet(
|
||||
$sheet,
|
||||
$worksheetFilesFolder,
|
||||
$this->sharedStringsHelper,
|
||||
$this->styleHelper,
|
||||
$this->sizeCalculator,
|
||||
$this->shouldUseInlineStrings,
|
||||
$this->shouldUseCellAutosizing
|
||||
);
|
||||
$this->worksheets[] = $worksheet;
|
||||
|
||||
return $worksheet;
|
||||
@ -99,6 +118,7 @@ class Workbook extends AbstractWorkbook
|
||||
*
|
||||
* @param resource $finalFilePointer Pointer to the XLSX that will be created
|
||||
* @return void
|
||||
* @throws \Box\Spout\Common\Exception\IOException
|
||||
*/
|
||||
public function close($finalFilePointer)
|
||||
{
|
||||
@ -126,6 +146,7 @@ class Workbook extends AbstractWorkbook
|
||||
* Deletes the root folder created in the temp folder and all its contents.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Box\Spout\Common\Exception\IOException
|
||||
*/
|
||||
protected function cleanupTempFolder()
|
||||
{
|
||||
|
@ -3,10 +3,12 @@
|
||||
namespace Box\Spout\Writer\XLSX\Internal;
|
||||
|
||||
use Box\Spout\Common\Exception\InvalidArgumentException;
|
||||
use Box\Spout\Writer\Common\Internal\WorksheetInterface;
|
||||
use Box\Spout\Writer\XLSX\Helper\SizeCalculator;
|
||||
use Box\Spout\Writer\Common\Helper\CellHelper;
|
||||
use Box\Spout\Common\Exception\IOException;
|
||||
use Box\Spout\Common\Helper\StringHelper;
|
||||
use Box\Spout\Writer\Common\Helper\CellHelper;
|
||||
use Box\Spout\Writer\Common\Internal\WorksheetInterface;
|
||||
use Box\Spout\Writer\Style\Style;
|
||||
|
||||
/**
|
||||
* Class Worksheet
|
||||
@ -45,32 +47,52 @@ EOD;
|
||||
/** @var bool Whether inline or shared strings should be used */
|
||||
protected $shouldUseInlineStrings;
|
||||
|
||||
/** @var bool Determine whether cell widths should be calculated */
|
||||
protected $shouldUseCellAutosizing;
|
||||
|
||||
/** @var \Box\Spout\Common\Escaper\XLSX Strings escaper */
|
||||
protected $stringsEscaper;
|
||||
|
||||
/** @var \Box\Spout\Common\Helper\StringHelper String helper */
|
||||
protected $stringHelper;
|
||||
|
||||
/** @var \Box\Spout\Writer\XLSX\Helper\SizeCalculator */
|
||||
protected $sizeCalculator;
|
||||
|
||||
/** @var Resource Pointer to the sheet data file (e.g. xl/worksheets/sheet1.xml) */
|
||||
protected $sheetFilePointer;
|
||||
|
||||
/** @var int Index of the last written row */
|
||||
protected $lastWrittenRowIndex = 0;
|
||||
|
||||
/** @var array Holds the column widths for cell sizing */
|
||||
protected $columnWidths = [];
|
||||
|
||||
/**
|
||||
* @param \Box\Spout\Writer\Common\Sheet $externalSheet The associated "external" sheet
|
||||
* @param string $worksheetFilesFolder Temporary folder where the files to create the XLSX will be stored
|
||||
* @param \Box\Spout\Writer\XLSX\Helper\SharedStringsHelper $sharedStringsHelper Helper for shared strings
|
||||
* @param \Box\Spout\Writer\XLSX\Helper\StyleHelper Helper to work with styles
|
||||
* @param \Box\Spout\Writer\XLSX\Helper\SizeCalculator $sizeCalculator To calculate cell sizes
|
||||
* @param bool $shouldUseInlineStrings Whether inline or shared strings should be used
|
||||
* @param bool $shouldUseCellAutosizing Whether cell sizes should be calculated or not
|
||||
* @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
|
||||
*/
|
||||
public function __construct($externalSheet, $worksheetFilesFolder, $sharedStringsHelper, $styleHelper, $shouldUseInlineStrings)
|
||||
{
|
||||
public function __construct(
|
||||
$externalSheet,
|
||||
$worksheetFilesFolder,
|
||||
$sharedStringsHelper,
|
||||
$styleHelper,
|
||||
$sizeCalculator,
|
||||
$shouldUseInlineStrings,
|
||||
$shouldUseCellAutosizing
|
||||
) {
|
||||
$this->externalSheet = $externalSheet;
|
||||
$this->sharedStringsHelper = $sharedStringsHelper;
|
||||
$this->styleHelper = $styleHelper;
|
||||
$this->sizeCalculator = $sizeCalculator;
|
||||
$this->shouldUseInlineStrings = $shouldUseInlineStrings;
|
||||
$this->shouldUseCellAutosizing = $shouldUseCellAutosizing;
|
||||
|
||||
/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
|
||||
$this->stringsEscaper = \Box\Spout\Common\Escaper\XLSX::getInstance();
|
||||
@ -81,7 +103,8 @@ EOD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the worksheet to accept data
|
||||
* Prepares the worksheet to accept data and preserves free space at the beginning
|
||||
* of the sheet file to prepend header xml and optional column size data.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Box\Spout\Common\Exception\IOException If the sheet data file cannot be opened for writing
|
||||
@ -91,7 +114,8 @@ EOD;
|
||||
$this->sheetFilePointer = fopen($this->worksheetFilePath, 'w');
|
||||
$this->throwIfSheetFilePointerIsNotAvailable();
|
||||
|
||||
fwrite($this->sheetFilePointer, self::SHEET_XML_FILE_HEADER);
|
||||
$spaceToPreserve = $this->shouldUseCellAutosizing ? 1024 * 1024 : 512;
|
||||
fwrite($this->sheetFilePointer, str_repeat(' ', $spaceToPreserve));
|
||||
fwrite($this->sheetFilePointer, '<sheetData>');
|
||||
}
|
||||
|
||||
@ -184,8 +208,12 @@ EOD;
|
||||
|
||||
$rowXML = '<row r="' . $rowIndex . '" spans="1:' . $numCells . '">';
|
||||
|
||||
if ($this->shouldUseCellAutosizing) {
|
||||
$this->sizeCalculator->setFont($style->getFontName(), $style->getFontSize());
|
||||
}
|
||||
|
||||
foreach($dataRow as $cellValue) {
|
||||
$rowXML .= $this->getCellXML($rowIndex, $cellNumber, $cellValue, $style->getId());
|
||||
$rowXML .= $this->getCellXML($rowIndex, $cellNumber, $cellValue, $style);
|
||||
$cellNumber++;
|
||||
}
|
||||
|
||||
@ -200,18 +228,19 @@ EOD;
|
||||
/**
|
||||
* Build and return xml for a single cell.
|
||||
*
|
||||
* @param int $rowIndex
|
||||
* @param int $cellNumber
|
||||
* @param int $rowIndex
|
||||
* @param int $cellNumber
|
||||
* @param mixed $cellValue
|
||||
* @param int $styleId
|
||||
* @param Style $style Style to be applied to the row. NULL means use default style.
|
||||
*
|
||||
* @return string
|
||||
* @throws InvalidArgumentException If the given value cannot be processed
|
||||
*/
|
||||
private function getCellXML($rowIndex, $cellNumber, $cellValue, $styleId)
|
||||
private function getCellXML($rowIndex, $cellNumber, $cellValue, Style $style)
|
||||
{
|
||||
$columnIndex = CellHelper::getCellIndexFromColumnIndex($cellNumber);
|
||||
$cellXML = '<c r="' . $columnIndex . $rowIndex . '"';
|
||||
$cellXML .= ' s="' . $styleId . '"';
|
||||
$cellXML .= ' s="' . $style->getId() . '"';
|
||||
|
||||
if (CellHelper::isNonEmptyString($cellValue)) {
|
||||
$cellXML .= $this->getCellXMLFragmentForNonEmptyString($cellValue);
|
||||
@ -220,7 +249,7 @@ EOD;
|
||||
} else if (CellHelper::isNumeric($cellValue)) {
|
||||
$cellXML .= '><v>' . $cellValue . '</v></c>';
|
||||
} else if (empty($cellValue)) {
|
||||
if ($this->styleHelper->shouldApplyStyleOnEmptyCell($styleId)) {
|
||||
if ($this->styleHelper->shouldApplyStyleOnEmptyCell($style->getId())) {
|
||||
$cellXML .= '/>';
|
||||
} else {
|
||||
// don't write empty cells that do no need styling
|
||||
@ -231,6 +260,8 @@ EOD;
|
||||
throw new InvalidArgumentException('Trying to add a value with an unsupported type: ' . gettype($cellValue));
|
||||
}
|
||||
|
||||
$this->updateColumnWidth($cellNumber, $cellValue, $style);
|
||||
|
||||
return $cellXML;
|
||||
}
|
||||
|
||||
@ -257,6 +288,48 @@ EOD;
|
||||
return $cellXMLFragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the width of the current cellNumber, if cell autosizing is enabled
|
||||
* and the width of the current value exceeds a previously calculated one.
|
||||
*
|
||||
* @param int $cellNumber
|
||||
* @param string $cellValue
|
||||
* @param Style $style
|
||||
*/
|
||||
private function updateColumnWidth($cellNumber, $cellValue, $style)
|
||||
{
|
||||
if ($this->shouldUseCellAutosizing) {
|
||||
$cellWidth = $this->sizeCalculator->getCellWidth($cellValue, $style->getFontSize());
|
||||
if (!isset($this->columnWidths[$cellNumber]) || $cellWidth > $this->columnWidths[$cellNumber]) {
|
||||
$this->columnWidths[$cellNumber] = $cellWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return writable <cols> xml string, if column widths have been
|
||||
* calculated or custom widths have been set.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getColsXML()
|
||||
{
|
||||
if (0 === count($this->columnWidths)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$colsXml = '<cols>';
|
||||
$colTemplate = '<col min="%d" max="%d" width="%s" customWidth="1"/>';
|
||||
|
||||
foreach ($this->columnWidths as $columnIndex => $columnWidth) {
|
||||
$colsXml .= sprintf($colTemplate, $columnIndex+1, $columnIndex+1, $columnWidth);
|
||||
}
|
||||
|
||||
$colsXml .= '</cols>';
|
||||
|
||||
return $colsXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the worksheet
|
||||
*
|
||||
@ -268,8 +341,12 @@ EOD;
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite($this->sheetFilePointer, '</sheetData>');
|
||||
fwrite($this->sheetFilePointer, '</worksheet>');
|
||||
fwrite($this->sheetFilePointer, '</sheetData></worksheet>');
|
||||
rewind($this->sheetFilePointer);
|
||||
|
||||
fwrite($this->sheetFilePointer, self::SHEET_XML_FILE_HEADER);
|
||||
fwrite($this->sheetFilePointer, $this->getColsXML());
|
||||
|
||||
fclose($this->sheetFilePointer);
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
namespace Box\Spout\Writer\XLSX;
|
||||
|
||||
use Box\Spout\Writer\AbstractMultiSheetsWriter;
|
||||
use Box\Spout\Writer\Style\StyleBuilder;
|
||||
use Box\Spout\Writer\XLSX\Internal\Workbook;
|
||||
use Box\Spout\Writer\Style\StyleBuilder;
|
||||
|
||||
/**
|
||||
* Class Writer
|
||||
@ -27,6 +27,9 @@ class Writer extends AbstractMultiSheetsWriter
|
||||
/** @var bool Whether inline or shared strings should be used - inline string is more memory efficient */
|
||||
protected $shouldUseInlineStrings = true;
|
||||
|
||||
/** @var bool Determine whether cell widths should be calculated */
|
||||
protected $shouldUseCellAutosizing = false;
|
||||
|
||||
/** @var Internal\Workbook The workbook for the XLSX file */
|
||||
protected $book;
|
||||
|
||||
@ -64,6 +67,22 @@ class Writer extends AbstractMultiSheetsWriter
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable automated calculation of cell sizes to fit the contents of a cell value.
|
||||
*
|
||||
* @api
|
||||
* @param bool $shouldUseCellAutosizing
|
||||
* @return Writer
|
||||
* @throws \Box\Spout\Writer\Exception\WriterAlreadyOpenedException If the writer was already opened
|
||||
*/
|
||||
public function setShouldUseCellAutosizing($shouldUseCellAutosizing)
|
||||
{
|
||||
$this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
|
||||
|
||||
$this->shouldUseCellAutosizing = $shouldUseCellAutosizing;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the write and sets the current sheet pointer to a new sheet.
|
||||
*
|
||||
@ -74,7 +93,13 @@ class Writer extends AbstractMultiSheetsWriter
|
||||
{
|
||||
if (!$this->book) {
|
||||
$tempFolder = ($this->tempFolder) ? : sys_get_temp_dir();
|
||||
$this->book = new Workbook($tempFolder, $this->shouldUseInlineStrings, $this->shouldCreateNewSheetsAutomatically, $this->defaultRowStyle);
|
||||
$this->book = new Workbook(
|
||||
$tempFolder,
|
||||
$this->shouldUseInlineStrings,
|
||||
$this->shouldUseCellAutosizing,
|
||||
$this->shouldCreateNewSheetsAutomatically,
|
||||
$this->defaultRowStyle
|
||||
);
|
||||
$this->book->addNewSheetAndMakeItCurrent();
|
||||
}
|
||||
}
|
||||
@ -98,6 +123,7 @@ class Writer extends AbstractMultiSheetsWriter
|
||||
* @return void
|
||||
* @throws \Box\Spout\Writer\Exception\WriterNotOpenedException If the book is not created yet
|
||||
* @throws \Box\Spout\Common\Exception\IOException If unable to write data
|
||||
* @throws \Box\Spout\Writer\Exception\WriterException
|
||||
*/
|
||||
protected function addRowToWriter(array $dataRow, $style)
|
||||
{
|
||||
@ -120,8 +146,8 @@ class Writer extends AbstractMultiSheetsWriter
|
||||
|
||||
/**
|
||||
* Closes the writer, preventing any additional writing.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Box\Spout\Common\Exception\IOException
|
||||
*/
|
||||
protected function closeWriter()
|
||||
{
|
||||
|
36
tests/Spout/Writer/XLSX/Helper/SizeCalculatorTest.php
Normal file
36
tests/Spout/Writer/XLSX/Helper/SizeCalculatorTest.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Box\Spout\Writer\XLSX\Helper;
|
||||
|
||||
/**
|
||||
* Class SizeCalculatorTest
|
||||
* Simple unit tests only.
|
||||
*/
|
||||
class SizeCalculatorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSetFontShouldCallSizeCollectionGetter()
|
||||
{
|
||||
$fontName = 'Arial';
|
||||
$fontSize = 12;
|
||||
|
||||
$sizeCollectionMock = $this->getSizeCollectionMock();
|
||||
$sizeCollectionMock->expects(self::once())->method('get')->with($fontName, $fontSize);
|
||||
|
||||
$sizeCalculator = new SizeCalculator($sizeCollectionMock);
|
||||
$sizeCalculator->setFont($fontName, $fontSize);
|
||||
}
|
||||
|
||||
public function testGetCellWidthShouldReturnValueGreaterThanOneForNonEmptyString()
|
||||
{
|
||||
$sizeCalculator = new SizeCalculator($this->getSizeCollectionMock());
|
||||
self::assertGreaterThan(1, $sizeCalculator->getCellWidth('a', 12));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject|SizeCollection
|
||||
*/
|
||||
private function getSizeCollectionMock()
|
||||
{
|
||||
return $this->getMockBuilder('Box\Spout\Writer\XLSX\Helper\SizeCollection')->disableOriginalConstructor()->getMock();
|
||||
}
|
||||
}
|
31
tests/Spout/Writer/XLSX/Helper/SizeCollectionTest.php
Normal file
31
tests/Spout/Writer/XLSX/Helper/SizeCollectionTest.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Box\Spout\Writer\XLSX\Helper;
|
||||
|
||||
/**
|
||||
* Class SizeCollectionTest
|
||||
* Integration tests.
|
||||
*/
|
||||
class SizeCollectionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testGetShouldReturnArrayWithAsciiCharacterSizes()
|
||||
{
|
||||
$collection = new SizeCollection();
|
||||
self::assertGreaterThan(200, count($collection->get('Arial', '12')));
|
||||
}
|
||||
|
||||
public function testGetWithBiggerFontSizeShouldReturnArrayWithGreaterSum()
|
||||
{
|
||||
$collection = new SizeCollection();
|
||||
self::assertGreaterThan(
|
||||
array_sum($collection->get('Arial', '12')),
|
||||
array_sum($collection->get('Arial', '13'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testNonExistingFontShouldStillReturnArrayWithSizes()
|
||||
{
|
||||
$collection = new SizeCollection();
|
||||
self::assertGreaterThan(200, count($collection->get('MeNoFont', '12')));
|
||||
}
|
||||
}
|
@ -78,6 +78,21 @@ class WriterTest extends \PHPUnit_Framework_TestCase
|
||||
$writer->setShouldUseInlineStrings(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Box\Spout\Writer\Exception\WriterAlreadyOpenedException
|
||||
*/
|
||||
public function testSetShouldUseCellAutosizingShouldThrowExceptionIfCalledAfterOpeningWriter()
|
||||
{
|
||||
$fileName = 'file_that_wont_be_written.xlsx';
|
||||
$filePath = $this->getGeneratedResourcePath($fileName);
|
||||
|
||||
/** @var \Box\Spout\Writer\XLSX\Writer $writer */
|
||||
$writer = WriterFactory::create(Type::XLSX);
|
||||
$writer->openToFile($filePath);
|
||||
|
||||
$writer->setShouldUseCellAutosizing(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Box\Spout\Writer\Exception\WriterAlreadyOpenedException
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user