mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-11 02:26:28 +00:00
Merge branch 'master' into Feature_Images-from-string-or-streams
This commit is contained in:
@@ -312,70 +312,6 @@ parameters:
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Address\\:\\:sheetName\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/Address.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchFirstValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchFirstValue\\(\\) has parameter \\$lookupArray with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchFirstValue\\(\\) has parameter \\$lookupValue with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has parameter \\$keySet with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has parameter \\$lookupArray with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has parameter \\$lookupValue with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchSmallestValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchSmallestValue\\(\\) has parameter \\$lookupArray with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchSmallestValue\\(\\) has parameter \\$lookupValue with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:prepareLookupArray\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:prepareLookupArray\\(\\) has parameter \\$lookupArray with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:prepareLookupArray\\(\\) has parameter \\$matchType with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:validateLookupArray\\(\\) has parameter \\$lookupArray with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:validateLookupValue\\(\\) has parameter \\$lookupValue with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:validateMatchType\\(\\) has parameter \\$matchType with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyResultVector\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
|
||||
require __DIR__ . '/../Header.php';
|
||||
|
||||
// Read from Xlsx (.xls) template
|
||||
$helper->log('Load Xlsx template file');
|
||||
$reader = IOFactory::createReader('Xlsx');
|
||||
$spreadsheet = $reader->load(__DIR__ . '/../templates/27template.xlsx');
|
||||
|
||||
// Save
|
||||
$helper->write($spreadsheet, __FILE__);
|
||||
Binary file not shown.
@@ -39,12 +39,11 @@ class ExcelMatch
|
||||
}
|
||||
|
||||
$lookupArray = Functions::flattenArray($lookupArray);
|
||||
$matchType = (int) ($matchType ?? self::MATCHTYPE_LARGEST_VALUE);
|
||||
|
||||
try {
|
||||
// Input validation
|
||||
self::validateLookupValue($lookupValue);
|
||||
self::validateMatchType($matchType);
|
||||
$matchType = self::validateMatchType($matchType);
|
||||
self::validateLookupArray($lookupArray);
|
||||
|
||||
$keySet = array_keys($lookupArray);
|
||||
@@ -87,36 +86,78 @@ class ExcelMatch
|
||||
return ExcelError::NA();
|
||||
}
|
||||
|
||||
private static function matchFirstValue($lookupArray, $lookupValue)
|
||||
/**
|
||||
* @param mixed $lookupValue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function matchFirstValue(array $lookupArray, $lookupValue)
|
||||
{
|
||||
$wildcardLookup = ((bool) preg_match('/([\?\*])/', $lookupValue));
|
||||
$wildcard = WildcardMatch::wildcard($lookupValue);
|
||||
if (is_string($lookupValue)) {
|
||||
$valueIsString = true;
|
||||
$wildcard = WildcardMatch::wildcard($lookupValue);
|
||||
} else {
|
||||
$valueIsString = false;
|
||||
$wildcard = '';
|
||||
}
|
||||
|
||||
$valueIsNumeric = is_int($lookupValue) || is_float($lookupValue);
|
||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||
$typeMatch = ((gettype($lookupValue) === gettype($lookupArrayValue)) ||
|
||||
(is_numeric($lookupValue) && is_numeric($lookupArrayValue)));
|
||||
|
||||
if (
|
||||
$typeMatch && is_string($lookupValue) &&
|
||||
$wildcardLookup && WildcardMatch::compare($lookupArrayValue, $wildcard)
|
||||
$valueIsString
|
||||
&& is_string($lookupArrayValue)
|
||||
) {
|
||||
// wildcard match
|
||||
return $i;
|
||||
} elseif ($lookupArrayValue === $lookupValue) {
|
||||
// exact match
|
||||
return $i;
|
||||
if (WildcardMatch::compare($lookupArrayValue, $wildcard)) {
|
||||
return $i; // wildcard match
|
||||
}
|
||||
} else {
|
||||
if ($lookupArrayValue === $lookupValue) {
|
||||
return $i; // exact match
|
||||
}
|
||||
if (
|
||||
$valueIsNumeric
|
||||
&& (is_float($lookupArrayValue) || is_int($lookupArrayValue))
|
||||
&& $lookupArrayValue == $lookupValue
|
||||
) {
|
||||
return $i; // exact match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function matchLargestValue($lookupArray, $lookupValue, $keySet)
|
||||
/**
|
||||
* @param mixed $lookupValue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function matchLargestValue(array $lookupArray, $lookupValue, array $keySet)
|
||||
{
|
||||
if (is_string($lookupValue)) {
|
||||
if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) {
|
||||
$wildcard = WildcardMatch::wildcard($lookupValue);
|
||||
foreach (array_reverse($lookupArray) as $i => $lookupArrayValue) {
|
||||
if (is_string($lookupArrayValue) && WildcardMatch::compare($lookupArrayValue, $wildcard)) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||
if ($lookupArrayValue === $lookupValue) {
|
||||
return $keySet[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$valueIsNumeric = is_int($lookupValue) || is_float($lookupValue);
|
||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||
$typeMatch = ((gettype($lookupValue) === gettype($lookupArrayValue)) ||
|
||||
(is_numeric($lookupValue) && is_numeric($lookupArrayValue)));
|
||||
|
||||
if ($valueIsNumeric && (is_int($lookupArrayValue) || is_float($lookupArrayValue))) {
|
||||
if ($lookupArrayValue <= $lookupValue) {
|
||||
return array_search($i, $keySet);
|
||||
}
|
||||
}
|
||||
$typeMatch = gettype($lookupValue) === gettype($lookupArrayValue);
|
||||
if ($typeMatch && ($lookupArrayValue <= $lookupValue)) {
|
||||
return array_search($i, $keySet);
|
||||
}
|
||||
@@ -125,21 +166,42 @@ class ExcelMatch
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function matchSmallestValue($lookupArray, $lookupValue)
|
||||
/**
|
||||
* @param mixed $lookupValue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function matchSmallestValue(array $lookupArray, $lookupValue)
|
||||
{
|
||||
$valueKey = null;
|
||||
if (is_string($lookupValue)) {
|
||||
if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) {
|
||||
$wildcard = WildcardMatch::wildcard($lookupValue);
|
||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||
if (is_string($lookupArrayValue) && WildcardMatch::compare($lookupArrayValue, $wildcard)) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$valueIsNumeric = is_int($lookupValue) || is_float($lookupValue);
|
||||
// The basic algorithm is:
|
||||
// Iterate and keep the highest match until the next element is smaller than the searched value.
|
||||
// Return immediately if perfect match is found
|
||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||
$typeMatch = gettype($lookupValue) === gettype($lookupArrayValue);
|
||||
$bothNumeric = $valueIsNumeric && (is_int($lookupArrayValue) || is_float($lookupArrayValue));
|
||||
|
||||
if ($lookupArrayValue === $lookupValue) {
|
||||
// Another "special" case. If a perfect match is found,
|
||||
// the algorithm gives up immediately
|
||||
return $i;
|
||||
} elseif ($typeMatch && $lookupArrayValue >= $lookupValue) {
|
||||
}
|
||||
if ($bothNumeric && $lookupValue == $lookupArrayValue) {
|
||||
return $i; // exact match, as above
|
||||
}
|
||||
if (($typeMatch || $bothNumeric) && $lookupArrayValue >= $lookupValue) {
|
||||
$valueKey = $i;
|
||||
} elseif ($typeMatch && $lookupArrayValue < $lookupValue) {
|
||||
//Excel algorithm gives up immediately if the first element is smaller than the searched value
|
||||
@@ -150,6 +212,9 @@ class ExcelMatch
|
||||
return $valueKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $lookupValue
|
||||
*/
|
||||
private static function validateLookupValue($lookupValue): void
|
||||
{
|
||||
// Lookup_value type has to be number, text, or logical values
|
||||
@@ -158,18 +223,29 @@ class ExcelMatch
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateMatchType($matchType): void
|
||||
/**
|
||||
* @param mixed $matchType
|
||||
*/
|
||||
private static function validateMatchType($matchType): int
|
||||
{
|
||||
// Match_type is 0, 1 or -1
|
||||
if (
|
||||
($matchType !== self::MATCHTYPE_FIRST_VALUE) &&
|
||||
($matchType !== self::MATCHTYPE_LARGEST_VALUE) && ($matchType !== self::MATCHTYPE_SMALLEST_VALUE)
|
||||
) {
|
||||
throw new Exception(ExcelError::NA());
|
||||
// However Excel accepts other numeric values,
|
||||
// including numeric strings and floats.
|
||||
// It seems to just be interested in the sign.
|
||||
if (!is_numeric($matchType)) {
|
||||
throw new Exception(ExcelError::Value());
|
||||
}
|
||||
if ($matchType > 0) {
|
||||
return self::MATCHTYPE_LARGEST_VALUE;
|
||||
}
|
||||
if ($matchType < 0) {
|
||||
return self::MATCHTYPE_SMALLEST_VALUE;
|
||||
}
|
||||
|
||||
return self::MATCHTYPE_FIRST_VALUE;
|
||||
}
|
||||
|
||||
private static function validateLookupArray($lookupArray): void
|
||||
private static function validateLookupArray(array $lookupArray): void
|
||||
{
|
||||
// Lookup_array should not be empty
|
||||
$lookupArraySize = count($lookupArray);
|
||||
@@ -178,7 +254,10 @@ class ExcelMatch
|
||||
}
|
||||
}
|
||||
|
||||
private static function prepareLookupArray($lookupArray, $matchType)
|
||||
/**
|
||||
* @param mixed $matchType
|
||||
*/
|
||||
private static function prepareLookupArray(array $lookupArray, $matchType): array
|
||||
{
|
||||
// Lookup_array should contain only number, text, or logical values, or empty (null) cells
|
||||
foreach ($lookupArray as $i => $value) {
|
||||
|
||||
@@ -763,7 +763,7 @@ class Xlsx extends BaseReader
|
||||
$sheetViewOptions = new SheetViewOptions($docSheet, $xmlSheet);
|
||||
$sheetViewOptions->load($this->getReadDataOnly(), $this->styleReader);
|
||||
|
||||
(new ColumnAndRowAttributes($docSheet, $xmlSheet))
|
||||
(new ColumnAndRowAttributes($docSheet, $xmlSheetNS))
|
||||
->load($this->getReadFilter(), $this->getReadDataOnly());
|
||||
}
|
||||
|
||||
@@ -913,11 +913,13 @@ class Xlsx extends BaseReader
|
||||
$this->readTables($xmlSheet, $docSheet, $dir, $fileWorksheet, $zip);
|
||||
}
|
||||
|
||||
if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
|
||||
foreach ($xmlSheet->mergeCells->mergeCell as $mergeCell) {
|
||||
$mergeRef = (string) $mergeCell['ref'];
|
||||
if ($xmlSheetNS && $xmlSheetNS->mergeCells && $xmlSheetNS->mergeCells->mergeCell && !$this->readDataOnly) {
|
||||
foreach ($xmlSheetNS->mergeCells->mergeCell as $mergeCellx) {
|
||||
/** @scrutinizer ignore-call */
|
||||
$mergeCell = $mergeCellx->attributes();
|
||||
$mergeRef = (string) ($mergeCell['ref'] ?? '');
|
||||
if (strpos($mergeRef, ':') !== false) {
|
||||
$docSheet->mergeCells((string) $mergeCell['ref'], Worksheet::MERGE_CELL_CONTENT_HIDE);
|
||||
$docSheet->mergeCells($mergeRef, Worksheet::MERGE_CELL_CONTENT_HIDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -940,7 +942,10 @@ class Xlsx extends BaseReader
|
||||
}
|
||||
$node->addAttribute('sqref', $item->children(Namespaces::DATA_VALIDATIONS2)->sqref);
|
||||
if (isset($item->formula1)) {
|
||||
$node->addChild('formula1', $item->formula1->children(Namespaces::DATA_VALIDATIONS2)->f);
|
||||
$childNode = $node->addChild('formula1');
|
||||
if ($childNode !== null) { // null should never happen
|
||||
$childNode[0] = (string) $item->formula1->children(Namespaces::DATA_VALIDATIONS2)->f; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1157,14 +1162,21 @@ class Xlsx extends BaseReader
|
||||
}
|
||||
|
||||
// Header/footer images
|
||||
if ($xmlSheet && $xmlSheet->legacyDrawingHF) {
|
||||
if ($xmlSheetNS && $xmlSheetNS->legacyDrawingHF) {
|
||||
$vmlHfRid = '';
|
||||
$vmlHfRidAttr = $xmlSheetNS->legacyDrawingHF->attributes(Namespaces::SCHEMA_OFFICE_DOCUMENT);
|
||||
if ($vmlHfRidAttr !== null && isset($vmlHfRidAttr['id'])) {
|
||||
$vmlHfRid = (string) $vmlHfRidAttr['id'][0];
|
||||
}
|
||||
if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
|
||||
$relsWorksheet = $this->loadZipNoNamespace(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels', Namespaces::RELATIONSHIPS);
|
||||
$vmlRelationship = '';
|
||||
|
||||
foreach ($relsWorksheet->Relationship as $ele) {
|
||||
if ($ele['Type'] == Namespaces::VML) {
|
||||
if ((string) $ele['Type'] == Namespaces::VML && (string) $ele['Id'] === $vmlHfRid) {
|
||||
$vmlRelationship = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1199,20 +1211,23 @@ class Xlsx extends BaseReader
|
||||
$imageData = self::getAttributes($imageData, Namespaces::URN_MSOFFICE);
|
||||
$style = self::toCSSArray((string) $shape['style']);
|
||||
|
||||
$hfImages[(string) $shape['id']] = new HeaderFooterDrawing();
|
||||
if (isset($imageData['title'])) {
|
||||
$hfImages[(string) $shape['id']]->setName((string) $imageData['title']);
|
||||
}
|
||||
if (array_key_exists((string) $imageData['relid'], $drawings)) {
|
||||
$shapeId = (string) $shape['id'];
|
||||
$hfImages[$shapeId] = new HeaderFooterDrawing();
|
||||
if (isset($imageData['title'])) {
|
||||
$hfImages[$shapeId]->setName((string) $imageData['title']);
|
||||
}
|
||||
|
||||
$hfImages[(string) $shape['id']]->setPath('zip://' . File::realpath($filename) . '#' . $drawings[(string) $imageData['relid']], false);
|
||||
$hfImages[(string) $shape['id']]->setResizeProportional(false);
|
||||
$hfImages[(string) $shape['id']]->setWidth($style['width']);
|
||||
$hfImages[(string) $shape['id']]->setHeight($style['height']);
|
||||
if (isset($style['margin-left'])) {
|
||||
$hfImages[(string) $shape['id']]->setOffsetX($style['margin-left']);
|
||||
$hfImages[$shapeId]->setPath('zip://' . File::realpath($filename) . '#' . $drawings[(string) $imageData['relid']], false);
|
||||
$hfImages[$shapeId]->setResizeProportional(false);
|
||||
$hfImages[$shapeId]->setWidth($style['width']);
|
||||
$hfImages[$shapeId]->setHeight($style['height']);
|
||||
if (isset($style['margin-left'])) {
|
||||
$hfImages[$shapeId]->setOffsetX($style['margin-left']);
|
||||
}
|
||||
$hfImages[$shapeId]->setOffsetY($style['margin-top']);
|
||||
$hfImages[$shapeId]->setResizeProportional(true);
|
||||
}
|
||||
$hfImages[(string) $shape['id']]->setOffsetY($style['margin-top']);
|
||||
$hfImages[(string) $shape['id']]->setResizeProportional(true);
|
||||
}
|
||||
|
||||
$docSheet->getHeaderFooter()->setImages($hfImages);
|
||||
@@ -1229,6 +1244,9 @@ class Xlsx extends BaseReader
|
||||
if (substr($drawingFilename, 0, 7) === 'xl//xl/') {
|
||||
$drawingFilename = substr($drawingFilename, 4);
|
||||
}
|
||||
if (substr($drawingFilename, 0, 8) === '/xl//xl/') {
|
||||
$drawingFilename = substr($drawingFilename, 5);
|
||||
}
|
||||
if ($zip->locateName($drawingFilename)) {
|
||||
$relsWorksheet = $this->loadZipNoNamespace($drawingFilename, Namespaces::RELATIONSHIPS);
|
||||
$drawings = [];
|
||||
@@ -1243,10 +1261,10 @@ class Xlsx extends BaseReader
|
||||
}
|
||||
}
|
||||
|
||||
if ($xmlSheet->drawing && !$this->readDataOnly) {
|
||||
if ($xmlSheetNS->drawing && !$this->readDataOnly) {
|
||||
$unparsedDrawings = [];
|
||||
$fileDrawing = null;
|
||||
foreach ($xmlSheet->drawing as $drawing) {
|
||||
foreach ($xmlSheetNS->drawing as $drawing) {
|
||||
$drawingRelId = (string) self::getArrayItem(self::getAttributes($drawing, $xmlNamespaceBase), 'id');
|
||||
$fileDrawing = $drawings[$drawingRelId];
|
||||
$drawingFilename = dirname($fileDrawing) . '/_rels/' . basename($fileDrawing) . '.rels';
|
||||
@@ -1261,7 +1279,13 @@ class Xlsx extends BaseReader
|
||||
$hyperlinks[(string) $ele['Id']] = (string) $ele['Target'];
|
||||
}
|
||||
if ($eleType === "$xmlNamespaceBase/image") {
|
||||
$images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $ele['Target']);
|
||||
$eleTarget = (string) $ele['Target'];
|
||||
if (substr($eleTarget, 0, 4) === '/xl/') {
|
||||
$eleTarget = substr($eleTarget, 1);
|
||||
$images[(string) $ele['Id']] = $eleTarget;
|
||||
} else {
|
||||
$images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $eleTarget);
|
||||
}
|
||||
} elseif ($eleType === "$xmlNamespaceBase/chart") {
|
||||
if ($this->includeCharts) {
|
||||
$eleTarget = (string) $ele['Target'];
|
||||
@@ -2030,7 +2054,10 @@ class Xlsx extends BaseReader
|
||||
|
||||
$unparsedPrinterSettings = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['printerSettings'];
|
||||
foreach ($sheetPrinterSettings as $rId => $printerSettings) {
|
||||
$rId = substr($rId, 3) . 'ps'; // rIdXXX, add 'ps' suffix to avoid identical resource identifier collision with unparsed vmlDrawing
|
||||
$rId = substr($rId, 3); // rIdXXX
|
||||
if (substr($rId, -2) !== 'ps') {
|
||||
$rId = $rId . 'ps'; // rIdXXX, add 'ps' suffix to avoid identical resource identifier collision with unparsed vmlDrawing
|
||||
}
|
||||
$unparsedPrinterSettings[$rId] = [];
|
||||
$unparsedPrinterSettings[$rId]['filePath'] = self::dirAdd("$dir/$fileWorksheet", $printerSettings['Target']);
|
||||
$unparsedPrinterSettings[$rId]['relFilePath'] = (string) $printerSettings['Target'];
|
||||
|
||||
@@ -137,15 +137,19 @@ class ColumnAndRowAttributes extends BaseParserClass
|
||||
{
|
||||
$columnAttributes = [];
|
||||
|
||||
foreach ($worksheetCols->col as $column) {
|
||||
$startColumn = Coordinate::stringFromColumnIndex((int) $column['min']);
|
||||
$endColumn = Coordinate::stringFromColumnIndex((int) $column['max']);
|
||||
++$endColumn;
|
||||
for ($columnAddress = $startColumn; $columnAddress !== $endColumn; ++$columnAddress) {
|
||||
$columnAttributes[$columnAddress] = $this->readColumnRangeAttributes($column, $readDataOnly);
|
||||
foreach ($worksheetCols->col as $columnx) {
|
||||
/** @scrutinizer ignore-call */
|
||||
$column = $columnx->attributes();
|
||||
if ($column !== null) {
|
||||
$startColumn = Coordinate::stringFromColumnIndex((int) $column['min']);
|
||||
$endColumn = Coordinate::stringFromColumnIndex((int) $column['max']);
|
||||
++$endColumn;
|
||||
for ($columnAddress = $startColumn; $columnAddress !== $endColumn; ++$columnAddress) {
|
||||
$columnAttributes[$columnAddress] = $this->readColumnRangeAttributes($column, $readDataOnly);
|
||||
|
||||
if ((int) ($column['max']) == 16384) {
|
||||
break;
|
||||
if ((int) ($column['max']) == 16384) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,23 +157,26 @@ class ColumnAndRowAttributes extends BaseParserClass
|
||||
return $columnAttributes;
|
||||
}
|
||||
|
||||
private function readColumnRangeAttributes(SimpleXMLElement $column, bool $readDataOnly): array
|
||||
private function readColumnRangeAttributes(?SimpleXMLElement $column, bool $readDataOnly): array
|
||||
{
|
||||
$columnAttributes = [];
|
||||
|
||||
if ($column['style'] && !$readDataOnly) {
|
||||
$columnAttributes['xfIndex'] = (int) $column['style'];
|
||||
if ($column !== null) {
|
||||
if (isset($column['style']) && !$readDataOnly) {
|
||||
$columnAttributes['xfIndex'] = (int) $column['style'];
|
||||
}
|
||||
if (isset($column['hidden']) && self::boolean($column['hidden'])) {
|
||||
$columnAttributes['visible'] = false;
|
||||
}
|
||||
if (isset($column['collapsed']) && self::boolean($column['collapsed'])) {
|
||||
$columnAttributes['collapsed'] = true;
|
||||
}
|
||||
if (isset($column['outlineLevel']) && ((int) $column['outlineLevel']) > 0) {
|
||||
$columnAttributes['outlineLevel'] = (int) $column['outlineLevel'];
|
||||
}
|
||||
if (isset($column['width'])) {
|
||||
$columnAttributes['width'] = (float) $column['width'];
|
||||
}
|
||||
}
|
||||
if (self::boolean($column['hidden'])) {
|
||||
$columnAttributes['visible'] = false;
|
||||
}
|
||||
if (self::boolean($column['collapsed'])) {
|
||||
$columnAttributes['collapsed'] = true;
|
||||
}
|
||||
if (((int) $column['outlineLevel']) > 0) {
|
||||
$columnAttributes['outlineLevel'] = (int) $column['outlineLevel'];
|
||||
}
|
||||
$columnAttributes['width'] = (float) $column['width'];
|
||||
|
||||
return $columnAttributes;
|
||||
}
|
||||
@@ -189,21 +196,25 @@ class ColumnAndRowAttributes extends BaseParserClass
|
||||
{
|
||||
$rowAttributes = [];
|
||||
|
||||
foreach ($worksheetRow as $row) {
|
||||
if ($row['ht'] && !$readDataOnly) {
|
||||
$rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
|
||||
}
|
||||
if (self::boolean($row['hidden'])) {
|
||||
$rowAttributes[(int) $row['r']]['visible'] = false;
|
||||
}
|
||||
if (self::boolean($row['collapsed'])) {
|
||||
$rowAttributes[(int) $row['r']]['collapsed'] = true;
|
||||
}
|
||||
if ((int) $row['outlineLevel'] > 0) {
|
||||
$rowAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel'];
|
||||
}
|
||||
if ($row['s'] && !$readDataOnly) {
|
||||
$rowAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s'];
|
||||
foreach ($worksheetRow as $rowx) {
|
||||
/** @scrutinizer ignore-call */
|
||||
$row = $rowx->attributes();
|
||||
if ($row !== null) {
|
||||
if (isset($row['ht']) && !$readDataOnly) {
|
||||
$rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
|
||||
}
|
||||
if (isset($row['hidden']) && self::boolean($row['hidden'])) {
|
||||
$rowAttributes[(int) $row['r']]['visible'] = false;
|
||||
}
|
||||
if (isset($row['collapsed']) && self::boolean($row['collapsed'])) {
|
||||
$rowAttributes[(int) $row['r']]['collapsed'] = true;
|
||||
}
|
||||
if (isset($row['outlineLevel']) && (int) $row['outlineLevel'] > 0) {
|
||||
$rowAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel'];
|
||||
}
|
||||
if (isset($row['s']) && !$readDataOnly) {
|
||||
$rowAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,11 @@ class PageSetup extends BaseParserClass
|
||||
|
||||
$relAttributes = $xmlSheet->pageSetup->attributes(Namespaces::SCHEMA_OFFICE_DOCUMENT);
|
||||
if (isset($relAttributes['id'])) {
|
||||
$unparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'] = (string) $relAttributes['id'];
|
||||
$relid = (string) $relAttributes['id'];
|
||||
if (substr($relid, -2) !== 'ps') {
|
||||
$relid .= 'ps';
|
||||
}
|
||||
$unparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'] = $relid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -294,12 +294,14 @@ class Rels extends WriterPart
|
||||
}
|
||||
|
||||
foreach ($unparsedLoadedData['sheets'][$worksheet->getCodeName()][$relationship] as $rId => $value) {
|
||||
$this->writeRelationship(
|
||||
$objWriter,
|
||||
$rId,
|
||||
$type,
|
||||
$value['relFilePath']
|
||||
);
|
||||
if (substr($rId, 0, 17) !== '_headerfooter_vml') {
|
||||
$this->writeRelationship(
|
||||
$objWriter,
|
||||
$rId,
|
||||
$type,
|
||||
$value['relFilePath']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,25 +3,77 @@
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MatchTest extends TestCase
|
||||
class MatchTest extends AllSetupTeardown
|
||||
{
|
||||
protected function setUp(): void
|
||||
/**
|
||||
* @dataProvider providerMATCH
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $input
|
||||
* @param mixed $type
|
||||
*/
|
||||
public function testMATCH($expectedResult, $input, array $array, $type = null): void
|
||||
{
|
||||
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||
if (is_array($expectedResult)) {
|
||||
$expectedResult = $expectedResult[0];
|
||||
}
|
||||
if ($expectedResult === 'incomplete') {
|
||||
self::markTestIncomplete('Undefined behavior with different results in Excel and PhpSpreadsheet');
|
||||
}
|
||||
$this->mightHaveException($expectedResult);
|
||||
$sheet = $this->getSheet();
|
||||
$maxRow = count($array);
|
||||
$formulaArray = '';
|
||||
for ($row = 1; $row <= $maxRow; ++$row) {
|
||||
$this->setCell("A$row", $array[$row - 1]);
|
||||
$formulaArray = "A1:A$row";
|
||||
}
|
||||
$this->setCell('B1', $input);
|
||||
if ($type === null) {
|
||||
$formula = "=MATCH(B1,$formulaArray)";
|
||||
} else {
|
||||
$formula = "=MATCH(B1, $formulaArray, $type)";
|
||||
}
|
||||
$sheet->getCell('D1')->setValue($formula);
|
||||
|
||||
$result = $sheet->getCell('D1')->getCalculatedValue();
|
||||
self::assertEquals($expectedResult, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerMATCH
|
||||
*
|
||||
* @param mixed $expectedResult
|
||||
* @param mixed $input
|
||||
* @param mixed $type
|
||||
*/
|
||||
public function testMATCH($expectedResult, ...$args): void
|
||||
public function testMATCHLibre($expectedResult, $input, array $array, $type = null): void
|
||||
{
|
||||
$result = LookupRef::MATCH(...$args);
|
||||
$this->setOpenOffice();
|
||||
if (is_array($expectedResult)) {
|
||||
$expectedResult = $expectedResult[1];
|
||||
}
|
||||
if ($expectedResult === 'incomplete') {
|
||||
self::markTestIncomplete('Undefined behavior with different results in Excel and PhpSpreadsheet');
|
||||
}
|
||||
$this->mightHaveException($expectedResult);
|
||||
$sheet = $this->getSheet();
|
||||
$maxRow = count($array);
|
||||
$formulaArray = '';
|
||||
for ($row = 1; $row <= $maxRow; ++$row) {
|
||||
$this->setCell("A$row", $array[$row - 1]);
|
||||
$formulaArray = "A1:A$row";
|
||||
}
|
||||
$this->setCell('B1', $input);
|
||||
if ($type === null) {
|
||||
$formula = "=MATCH(B1,$formulaArray)";
|
||||
} else {
|
||||
$formula = "=MATCH(B1, $formulaArray, $type)";
|
||||
}
|
||||
$sheet->getCell('D1')->setValue($formula);
|
||||
|
||||
$result = $sheet->getCell('D1')->getCalculatedValue();
|
||||
self::assertEquals($expectedResult, $result);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||
|
||||
class Issue1482Test extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $testbook = 'tests/data/Reader/XLSX/issue.1482.xlsx';
|
||||
|
||||
public function testPreliminaries(): void
|
||||
{
|
||||
$file = 'zip://';
|
||||
$file .= self::$testbook;
|
||||
$file .= '#xl/worksheets/sheet.xml';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected namespaced xml tag
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} else {
|
||||
self::assertStringContainsString('<x:drawing r:id="rId1" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" />', $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function testLoadXlsx(): void
|
||||
{
|
||||
$reader = new Xlsx();
|
||||
$spreadsheet = $reader->load(self::$testbook);
|
||||
$sheet = $spreadsheet->getSheet(0);
|
||||
$expectedColWidths = [
|
||||
0.95,
|
||||
7.45,
|
||||
0.6,
|
||||
4.4,
|
||||
5.91,
|
||||
3.92,
|
||||
7.71,
|
||||
2.12,
|
||||
2.56,
|
||||
6.94,
|
||||
9.6,
|
||||
1.82,
|
||||
3.01,
|
||||
8.63,
|
||||
10.37,
|
||||
2.09,
|
||||
];
|
||||
$columnDimensions = $sheet->getColumnDimensions();
|
||||
$actualColWidths = [];
|
||||
foreach ($columnDimensions as $columnDimension) {
|
||||
$actualColWidths[] = $columnDimension->getWidth();
|
||||
}
|
||||
self::assertSame($expectedColWidths, $actualColWidths);
|
||||
$expectedRowHeights = [
|
||||
14.0,
|
||||
7.0,
|
||||
14.0,
|
||||
80.0,
|
||||
234.0,
|
||||
63.0,
|
||||
13.0,
|
||||
19.0,
|
||||
18.0,
|
||||
18.0,
|
||||
18.0,
|
||||
18.0,
|
||||
18.0,
|
||||
18.0,
|
||||
18.0,
|
||||
18.0,
|
||||
];
|
||||
$rowHeights = $sheet->getRowDimensions();
|
||||
$actualRowHeights = [];
|
||||
foreach ($rowHeights as $rowDimension) {
|
||||
$actualRowHeights[] = $rowDimension->getRowHeight();
|
||||
}
|
||||
self::assertSame($expectedRowHeights, $actualRowHeights);
|
||||
$expectedMergeCells = [
|
||||
'B1:E1',
|
||||
'F1:G1',
|
||||
'J1:L1',
|
||||
'M1:N1',
|
||||
'B3:E3',
|
||||
'F3:G3',
|
||||
'B5:O5',
|
||||
'A7:C7',
|
||||
'D7:M7',
|
||||
'A8:B8',
|
||||
'C8:D8',
|
||||
'E8:F8',
|
||||
'G8:H8',
|
||||
'I8:J8',
|
||||
'L8:P8',
|
||||
'A9:B9',
|
||||
'C9:D9',
|
||||
'E9:F9',
|
||||
'G9:H9',
|
||||
'I9:J9',
|
||||
'L9:P9',
|
||||
'A10:B10',
|
||||
'C10:D10',
|
||||
'E10:F10',
|
||||
'G10:H10',
|
||||
'I10:J10',
|
||||
'L10:P10',
|
||||
'A11:B11',
|
||||
'C11:D11',
|
||||
'E11:F11',
|
||||
'G11:H11',
|
||||
'I11:J11',
|
||||
'L11:P11',
|
||||
'A12:B12',
|
||||
'C12:D12',
|
||||
'E12:F12',
|
||||
'G12:H12',
|
||||
'I12:J12',
|
||||
'L12:P12',
|
||||
'A13:B13',
|
||||
'C13:D13',
|
||||
'E13:F13',
|
||||
'G13:H13',
|
||||
'I13:J13',
|
||||
'L13:P13',
|
||||
'A14:B14',
|
||||
'C14:D14',
|
||||
'E14:F14',
|
||||
'G14:H14',
|
||||
'I14:J14',
|
||||
'L14:P14',
|
||||
'A15:B15',
|
||||
'C15:D15',
|
||||
'E15:F15',
|
||||
'G15:H15',
|
||||
'I15:J15',
|
||||
'L15:P15',
|
||||
'A16:B16',
|
||||
'C16:D16',
|
||||
'E16:F16',
|
||||
'G16:H16',
|
||||
'I16:J16',
|
||||
'L16:P16',
|
||||
];
|
||||
self::assertSame($expectedMergeCells, array_keys($sheet->getMergeCells()));
|
||||
|
||||
$drawingCollection = $sheet->getDrawingCollection();
|
||||
self::assertCount(1, $drawingCollection);
|
||||
$drawing = $drawingCollection[0];
|
||||
if ($drawing === null) {
|
||||
self::fail('Unexpected null instead of drawing');
|
||||
} else {
|
||||
self::assertSame('B5', $drawing->getCoordinates());
|
||||
self::assertSame('', $drawing->getCoordinates2());
|
||||
self::assertFalse($drawing->getResizeProportional());
|
||||
self::assertSame(600, $drawing->getWidth());
|
||||
self::assertSame(312, $drawing->getHeight());
|
||||
}
|
||||
// no name, no description, no type
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class Issue3126Test extends TestCase
|
||||
{
|
||||
public function testReloadXlsxWorkbookProperties(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLSX/issue.3126.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$generation1 = $reader->load($filename);
|
||||
$gen1sheet = $generation1->getActiveSheet();
|
||||
$gen1hf = $gen1sheet->getHeaderFooter();
|
||||
$gen1Images = $gen1hf->getImages();
|
||||
self::assertCount(1, $gen1Images);
|
||||
$gen1hfName = array_key_exists('LF', $gen1Images) ? $gen1Images['LF']->getName() : '';
|
||||
self::assertSame('fleche-verte-up-right', $gen1hfName);
|
||||
$pageSetupRel = $generation1->getUnparsedLoadedData()['sheets']['Worksheet']['pageSetupRelId'] ?? '';
|
||||
self::assertSame('rId1ps', $pageSetupRel);
|
||||
$pageSetupPath = $generation1->getUnparsedLoadedData()['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? '';
|
||||
self::assertSame('xl/printerSettings/printerSettings1.bin', $pageSetupPath);
|
||||
|
||||
$generation2Name = File::temporaryFilename();
|
||||
$writer = new XlsxWriter($generation1);
|
||||
$writer->save($generation2Name);
|
||||
$generation1->disconnectWorksheets();
|
||||
$reader2 = new XlsxReader();
|
||||
$generation2 = $reader2->load($generation2Name);
|
||||
$gen2sheet = $generation2->getActiveSheet();
|
||||
$gen2hf = $gen2sheet->getHeaderFooter();
|
||||
$gen2Images = $gen2hf->getImages();
|
||||
self::assertCount(1, $gen2Images);
|
||||
$gen2hfName = array_key_exists('LF', $gen2Images) ? $gen2Images['LF']->getName() : '';
|
||||
self::assertSame('fleche-verte-up-right', $gen2hfName);
|
||||
$pageSetupRel = $generation2->getUnparsedLoadedData()['sheets']['Worksheet']['pageSetupRelId'] ?? '';
|
||||
self::assertSame('rId1ps', $pageSetupRel);
|
||||
$pageSetupPath = $generation2->getUnparsedLoadedData()['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? '';
|
||||
self::assertSame('xl/printerSettings/printerSettings1.bin', $pageSetupPath);
|
||||
|
||||
$generation3Name = File::temporaryFilename();
|
||||
$writer = new XlsxWriter($generation2);
|
||||
$writer->save($generation3Name);
|
||||
$generation2->disconnectWorksheets();
|
||||
$reader3 = new XlsxReader();
|
||||
$generation3 = $reader3->load($generation3Name);
|
||||
$gen3sheet = $generation3->getActiveSheet();
|
||||
$gen3hf = $gen3sheet->getHeaderFooter();
|
||||
$gen3Images = $gen3hf->getImages();
|
||||
self::assertCount(1, $gen3Images);
|
||||
$gen3hfName = array_key_exists('LF', $gen3Images) ? $gen3Images['LF']->getName() : '';
|
||||
self::assertSame('fleche-verte-up-right', $gen3hfName);
|
||||
$pageSetupRel = $generation3->getUnparsedLoadedData()['sheets']['Worksheet']['pageSetupRelId'] ?? '';
|
||||
self::assertSame('rId1ps', $pageSetupRel);
|
||||
$pageSetupPath = $generation3->getUnparsedLoadedData()['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? '';
|
||||
self::assertSame('xl/printerSettings/printerSettings1.bin', $pageSetupPath);
|
||||
|
||||
unlink($generation2Name);
|
||||
unlink($generation3Name);
|
||||
$generation3->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class Issue3145Test extends TestCase
|
||||
{
|
||||
public function testIssue3145(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLSX/issue.3145.xlsx';
|
||||
$reader = IOFactory::createReader('Xlsx');
|
||||
$spreadsheet = $reader->load($filename);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
self::assertEquals('Headline A', $sheet->getCell('A1')->getValue());
|
||||
self::assertEquals('Configdential B', $sheet->getCell('A2')->getValue());
|
||||
self::assertSame('OFFSET(INDIRECT(SUBSTITUTE($A2," ","")),0,0,COUNTA(INDIRECT(SUBSTITUTE($A2," ","")&"Col")),1)', $sheet->getCell('B2')->getDataValidation()->getFormula1());
|
||||
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,18 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'unsorted numeric array still finds match with type 1?' => [
|
||||
2, // Expected
|
||||
2, // Input
|
||||
[2, 0, 4, 3],
|
||||
1,
|
||||
],
|
||||
'unsorted array still finds match with type 1?' => [
|
||||
6,
|
||||
'Amplitude',
|
||||
['Aardvark', 'Apple', 'A~*e', 'A*e', 'A[solve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
1,
|
||||
],
|
||||
// Third argument = 0
|
||||
[
|
||||
1, // Expected
|
||||
@@ -33,12 +45,6 @@ return [
|
||||
[2, 3, 4, 3],
|
||||
1,
|
||||
],
|
||||
[
|
||||
2, // Expected
|
||||
2, // Input
|
||||
[2, 0, 4, 3],
|
||||
1,
|
||||
],
|
||||
[
|
||||
3, // Expected
|
||||
2, // Input
|
||||
@@ -114,10 +120,10 @@ return [
|
||||
1,
|
||||
],
|
||||
// 0s are causing errors, because things like 0 == 'x' is true. Thanks PHP!
|
||||
[
|
||||
'0 does not match x' => [
|
||||
3,
|
||||
'x',
|
||||
[[0], [0], ['x'], ['x'], ['x']],
|
||||
[0, 0, 'x', 'x', 'x'],
|
||||
0,
|
||||
],
|
||||
[
|
||||
@@ -201,12 +207,42 @@ return [
|
||||
[true, false, 'a', 'z', 2, 888],
|
||||
-1,
|
||||
],
|
||||
[
|
||||
'number compared to string type -1' => [
|
||||
'#N/A', // Expected
|
||||
6,
|
||||
['6'],
|
||||
-1,
|
||||
],
|
||||
'number compared to string type 0' => [
|
||||
'#N/A', // Expected
|
||||
6,
|
||||
['6'],
|
||||
0,
|
||||
],
|
||||
'number compared to string type 1' => [
|
||||
'#N/A', // Expected
|
||||
6,
|
||||
['6'],
|
||||
1,
|
||||
],
|
||||
'string compared to number type -1' => [
|
||||
'#N/A', // Expected
|
||||
'6',
|
||||
[6],
|
||||
-1,
|
||||
],
|
||||
'string compared to number type 0' => [
|
||||
'#N/A', // Expected
|
||||
'6',
|
||||
[6],
|
||||
0,
|
||||
],
|
||||
'string compared to number type 1' => [
|
||||
'#N/A', // Expected
|
||||
'6',
|
||||
[6],
|
||||
1,
|
||||
],
|
||||
// expression match
|
||||
[
|
||||
2, // Expected
|
||||
@@ -286,20 +322,38 @@ return [
|
||||
[1, 22, 'aaa'],
|
||||
1,
|
||||
],
|
||||
[
|
||||
'#N/A', // Expected (Invalid match type)
|
||||
'int match type other than 0/1/-1 is accepted' => [
|
||||
3, // Expected (Invalid match type)
|
||||
'abc',
|
||||
[1, 22, 'aaa'],
|
||||
123,
|
||||
],
|
||||
[
|
||||
'float match type is accepted' => [
|
||||
3, // Expected (Invalid match type)
|
||||
'abc',
|
||||
[1, 22, 'aaa'],
|
||||
123.5,
|
||||
],
|
||||
'numeric string match type is accepted' => [
|
||||
3, // Expected (Invalid match type)
|
||||
'abc',
|
||||
[1, 22, 'aaa'],
|
||||
'89.7',
|
||||
],
|
||||
'non-numeric string match type is not accepted' => [
|
||||
'#VALUE!', // Expected (Invalid match type)
|
||||
'abc',
|
||||
[1, 22, 'aaa'],
|
||||
'"x"',
|
||||
],
|
||||
'empty lookup array' => [
|
||||
'#N/A', // Expected (Empty lookup array)
|
||||
'abc',
|
||||
[],
|
||||
1,
|
||||
],
|
||||
[
|
||||
8,
|
||||
'wildcard match 1 with type -1' => [
|
||||
[8, 2], // LibreOffice matches wildcard but shouldn't
|
||||
'A*e',
|
||||
['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
-1,
|
||||
@@ -310,14 +364,22 @@ return [
|
||||
['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
0,
|
||||
],
|
||||
[
|
||||
'#N/A',
|
||||
'A*e',
|
||||
['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
1,
|
||||
'wildcard match with tilde' => [
|
||||
4,
|
||||
'A~*e',
|
||||
['Aardvark', 'Apple', 'A~*e', 'A*e', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
0,
|
||||
],
|
||||
[
|
||||
8,
|
||||
'string with preg_quote escaped character' => [
|
||||
5,
|
||||
'A[solve',
|
||||
['Aardvark', 'Apple', 'A~*e', 'A*e', 'A[solve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
0,
|
||||
],
|
||||
// duplicate test deleted - see 'wildcard with type 1' below
|
||||
// end of deletions
|
||||
'wildcard match 2 with type -1' => [
|
||||
[8, 5],
|
||||
'A?s*e',
|
||||
['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
-1,
|
||||
@@ -328,14 +390,14 @@ return [
|
||||
['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
0,
|
||||
],
|
||||
[
|
||||
'#N/A',
|
||||
'wildcard with type 1' => [
|
||||
['#N/A', 2], // LibreOffice matches wildcard but shouldn't
|
||||
'A*e',
|
||||
['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
1,
|
||||
],
|
||||
[
|
||||
8,
|
||||
'wildcard match 3 with type -1' => [
|
||||
[8, 3], // LibreOffice matches wildcard but shouldn't
|
||||
'*verse',
|
||||
['Obtuse', 'Amuse', 'Obverse', 'Inverse', 'Assurance', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
-1,
|
||||
@@ -358,4 +420,103 @@ return [
|
||||
['abc123fff', 'abc/123fff'],
|
||||
0,
|
||||
],
|
||||
'float lookup int array type0' => [
|
||||
1, // Expected
|
||||
2.0, // Input
|
||||
[2, 3, 4, 5],
|
||||
0,
|
||||
],
|
||||
'int lookup float array type0' => [
|
||||
2, // Expected
|
||||
3, // Input
|
||||
[2, 3.0, 4, 5],
|
||||
0,
|
||||
],
|
||||
'int lookup float array type0 not equal' => [
|
||||
'#N/A', // Expected
|
||||
3, // Input
|
||||
[2, 3.1, 4, 5],
|
||||
0,
|
||||
],
|
||||
'float lookup int array type0 not equal' => [
|
||||
'#N/A', // Expected
|
||||
3.1, // Input
|
||||
[2, 3, 4, 5],
|
||||
0,
|
||||
],
|
||||
'float lookup int array type1 equal' => [
|
||||
1, // Expected
|
||||
2.0, // Input
|
||||
[2, 3, 4, 5],
|
||||
1,
|
||||
],
|
||||
'int lookup float array type1 equal' => [
|
||||
2, // Expected
|
||||
3, // Input
|
||||
[2, 3.0, 4, 5],
|
||||
1,
|
||||
],
|
||||
'float lookup int array type1 less' => [
|
||||
1, // Expected
|
||||
2.5, // Input
|
||||
[2, 3, 4, 5],
|
||||
1,
|
||||
],
|
||||
'int lookup float array type1 less' => [
|
||||
2, // Expected
|
||||
3, // Input
|
||||
[2, 2.9, 4, 5],
|
||||
1,
|
||||
],
|
||||
'float lookup int array type -1 equal' => [
|
||||
4, // Expected
|
||||
2.0, // Input
|
||||
[5, 4, 3, 2],
|
||||
-1,
|
||||
],
|
||||
'int lookup float array type -1 equal' => [
|
||||
3, // Expected
|
||||
3, // Input
|
||||
[5, 4, 3.0, 2],
|
||||
-1,
|
||||
],
|
||||
'float lookup int array type -1 greater' => [
|
||||
2, // Expected
|
||||
3.5, // Input
|
||||
[5, 4, 3, 2],
|
||||
-1,
|
||||
],
|
||||
'int lookup float array type -1 greater' => [
|
||||
2, // Expected
|
||||
3, // Input
|
||||
[5, 4, 2.9, 2],
|
||||
-1,
|
||||
],
|
||||
'default type is type1' => [
|
||||
3, // Expected
|
||||
4, // Input
|
||||
[1, 2, 3, 5],
|
||||
],
|
||||
'same as previous but explicit type1' => [
|
||||
3, // Expected
|
||||
4, // Input
|
||||
[1, 2, 3, 5],
|
||||
],
|
||||
'same as previous but type0 so different result' => [
|
||||
'#N/A', // Expected
|
||||
4, // Input
|
||||
[1, 2, 3, 5],
|
||||
0,
|
||||
],
|
||||
'undefined behavior N/A in Excel 4 in PhpSpreadsheet' => [
|
||||
'incomplete', // Expected
|
||||
4, // Input
|
||||
[8, 6, 3, 1],
|
||||
],
|
||||
'same as previous but type -1 so match' => [
|
||||
2, // Expected
|
||||
4, // Input
|
||||
[8, 6, 3, 1],
|
||||
-1,
|
||||
],
|
||||
];
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user