init commit
This commit is contained in:
98
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Address.php
vendored
Normal file
98
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Address.php
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
|
||||
class Address
|
||||
{
|
||||
public const ADDRESS_ABSOLUTE = 1;
|
||||
public const ADDRESS_COLUMN_RELATIVE = 2;
|
||||
public const ADDRESS_ROW_RELATIVE = 3;
|
||||
public const ADDRESS_RELATIVE = 4;
|
||||
|
||||
public const REFERENCE_STYLE_A1 = true;
|
||||
public const REFERENCE_STYLE_R1C1 = false;
|
||||
|
||||
/**
|
||||
* ADDRESS.
|
||||
*
|
||||
* Creates a cell address as text, given specified row and column numbers.
|
||||
*
|
||||
* Excel Function:
|
||||
* =ADDRESS(row, column, [relativity], [referenceStyle], [sheetText])
|
||||
*
|
||||
* @param mixed $row Row number (integer) to use in the cell reference
|
||||
* @param mixed $column Column number (integer) to use in the cell reference
|
||||
* @param mixed $relativity Integer flag indicating the type of reference to return
|
||||
* 1 or omitted Absolute
|
||||
* 2 Absolute row; relative column
|
||||
* 3 Relative row; absolute column
|
||||
* 4 Relative
|
||||
* @param mixed $referenceStyle A logical (boolean) value that specifies the A1 or R1C1 reference style.
|
||||
* TRUE or omitted ADDRESS returns an A1-style reference
|
||||
* FALSE ADDRESS returns an R1C1-style reference
|
||||
* @param mixed $sheetName Optional Name of worksheet to use
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function cell($row, $column, $relativity = 1, $referenceStyle = true, $sheetName = '')
|
||||
{
|
||||
$row = Functions::flattenSingleValue($row);
|
||||
$column = Functions::flattenSingleValue($column);
|
||||
$relativity = ($relativity === null) ? 1 : Functions::flattenSingleValue($relativity);
|
||||
$referenceStyle = ($referenceStyle === null) ? true : Functions::flattenSingleValue($referenceStyle);
|
||||
$sheetName = Functions::flattenSingleValue($sheetName);
|
||||
|
||||
if (($row < 1) || ($column < 1)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
$sheetName = self::sheetName($sheetName);
|
||||
|
||||
if ((!is_bool($referenceStyle)) || $referenceStyle === self::REFERENCE_STYLE_A1) {
|
||||
return self::formatAsA1($row, $column, $relativity, $sheetName);
|
||||
}
|
||||
|
||||
return self::formatAsR1C1($row, $column, $relativity, $sheetName);
|
||||
}
|
||||
|
||||
private static function sheetName(string $sheetName)
|
||||
{
|
||||
if ($sheetName > '') {
|
||||
if (strpos($sheetName, ' ') !== false || strpos($sheetName, '[') !== false) {
|
||||
$sheetName = "'{$sheetName}'";
|
||||
}
|
||||
$sheetName .= '!';
|
||||
}
|
||||
|
||||
return $sheetName;
|
||||
}
|
||||
|
||||
private static function formatAsA1(int $row, int $column, int $relativity, string $sheetName): string
|
||||
{
|
||||
$rowRelative = $columnRelative = '$';
|
||||
if (($relativity == self::ADDRESS_COLUMN_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) {
|
||||
$columnRelative = '';
|
||||
}
|
||||
if (($relativity == self::ADDRESS_ROW_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) {
|
||||
$rowRelative = '';
|
||||
}
|
||||
$column = Coordinate::stringFromColumnIndex($column);
|
||||
|
||||
return "{$sheetName}{$columnRelative}{$column}{$rowRelative}{$row}";
|
||||
}
|
||||
|
||||
private static function formatAsR1C1(int $row, int $column, int $relativity, string $sheetName): string
|
||||
{
|
||||
if (($relativity == self::ADDRESS_COLUMN_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) {
|
||||
$column = "[{$column}]";
|
||||
}
|
||||
if (($relativity == self::ADDRESS_ROW_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) {
|
||||
$row = "[{$row}]";
|
||||
}
|
||||
|
||||
return "{$sheetName}R{$row}C{$column}";
|
||||
}
|
||||
}
|
||||
198
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
vendored
Normal file
198
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Internal\WildcardMatch;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
|
||||
|
||||
class ExcelMatch
|
||||
{
|
||||
public const MATCHTYPE_SMALLEST_VALUE = -1;
|
||||
public const MATCHTYPE_FIRST_VALUE = 0;
|
||||
public const MATCHTYPE_LARGEST_VALUE = 1;
|
||||
|
||||
/**
|
||||
* MATCH.
|
||||
*
|
||||
* The MATCH function searches for a specified item in a range of cells
|
||||
*
|
||||
* Excel Function:
|
||||
* =MATCH(lookup_value, lookup_array, [match_type])
|
||||
*
|
||||
* @param mixed $lookupValue The value that you want to match in lookup_array
|
||||
* @param mixed $lookupArray The range of cells being searched
|
||||
* @param mixed $matchType The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below.
|
||||
* If match_type is 1 or -1, the list has to be ordered.
|
||||
*
|
||||
* @return int|string The relative position of the found item
|
||||
*/
|
||||
public static function MATCH($lookupValue, $lookupArray, $matchType = self::MATCHTYPE_LARGEST_VALUE)
|
||||
{
|
||||
$lookupArray = Functions::flattenArray($lookupArray);
|
||||
$lookupValue = Functions::flattenSingleValue($lookupValue);
|
||||
$matchType = ($matchType === null)
|
||||
? self::MATCHTYPE_LARGEST_VALUE
|
||||
: (int) Functions::flattenSingleValue($matchType);
|
||||
|
||||
try {
|
||||
// Input validation
|
||||
self::validateLookupValue($lookupValue);
|
||||
self::validateMatchType($matchType);
|
||||
self::validateLookupArray($lookupArray);
|
||||
|
||||
$keySet = array_keys($lookupArray);
|
||||
if ($matchType == self::MATCHTYPE_LARGEST_VALUE) {
|
||||
// If match_type is 1 the list has to be processed from last to first
|
||||
$lookupArray = array_reverse($lookupArray);
|
||||
$keySet = array_reverse($keySet);
|
||||
}
|
||||
|
||||
$lookupArray = self::prepareLookupArray($lookupArray, $matchType);
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
// MATCH() is not case sensitive, so we convert lookup value to be lower cased if it's a string type.
|
||||
if (is_string($lookupValue)) {
|
||||
$lookupValue = StringHelper::strToLower($lookupValue);
|
||||
}
|
||||
|
||||
$valueKey = null;
|
||||
switch ($matchType) {
|
||||
case self::MATCHTYPE_LARGEST_VALUE:
|
||||
$valueKey = self::matchLargestValue($lookupArray, $lookupValue, $keySet);
|
||||
|
||||
break;
|
||||
case self::MATCHTYPE_FIRST_VALUE:
|
||||
$valueKey = self::matchFirstValue($lookupArray, $lookupValue);
|
||||
|
||||
break;
|
||||
case self::MATCHTYPE_SMALLEST_VALUE:
|
||||
default:
|
||||
$valueKey = self::matchSmallestValue($lookupArray, $lookupValue);
|
||||
}
|
||||
|
||||
if ($valueKey !== null) {
|
||||
return ++$valueKey;
|
||||
}
|
||||
|
||||
// Unsuccessful in finding a match, return #N/A error value
|
||||
return Functions::NA();
|
||||
}
|
||||
|
||||
private static function matchFirstValue($lookupArray, $lookupValue)
|
||||
{
|
||||
$wildcardLookup = ((bool) preg_match('/([\?\*])/', $lookupValue));
|
||||
$wildcard = WildcardMatch::wildcard($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)
|
||||
) {
|
||||
// wildcard match
|
||||
return $i;
|
||||
} elseif ($lookupArrayValue === $lookupValue) {
|
||||
// exact match
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function matchLargestValue($lookupArray, $lookupValue, $keySet)
|
||||
{
|
||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||
$typeMatch = ((gettype($lookupValue) === gettype($lookupArrayValue)) ||
|
||||
(is_numeric($lookupValue) && is_numeric($lookupArrayValue)));
|
||||
|
||||
if ($typeMatch && ($lookupArrayValue <= $lookupValue)) {
|
||||
return array_search($i, $keySet);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function matchSmallestValue($lookupArray, $lookupValue)
|
||||
{
|
||||
$valueKey = null;
|
||||
|
||||
// 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);
|
||||
|
||||
if ($lookupArrayValue === $lookupValue) {
|
||||
// Another "special" case. If a perfect match is found,
|
||||
// the algorithm gives up immediately
|
||||
return $i;
|
||||
} elseif ($typeMatch && $lookupArrayValue >= $lookupValue) {
|
||||
$valueKey = $i;
|
||||
} elseif ($typeMatch && $lookupArrayValue < $lookupValue) {
|
||||
//Excel algorithm gives up immediately if the first element is smaller than the searched value
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $valueKey;
|
||||
}
|
||||
|
||||
private static function validateLookupValue($lookupValue): void
|
||||
{
|
||||
// Lookup_value type has to be number, text, or logical values
|
||||
if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) {
|
||||
throw new Exception(Functions::NA());
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateMatchType($matchType): void
|
||||
{
|
||||
// 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(Functions::NA());
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateLookupArray($lookupArray): void
|
||||
{
|
||||
// Lookup_array should not be empty
|
||||
$lookupArraySize = count($lookupArray);
|
||||
if ($lookupArraySize <= 0) {
|
||||
throw new Exception(Functions::NA());
|
||||
}
|
||||
}
|
||||
|
||||
private static function prepareLookupArray($lookupArray, $matchType)
|
||||
{
|
||||
// Lookup_array should contain only number, text, or logical values, or empty (null) cells
|
||||
foreach ($lookupArray as $i => $value) {
|
||||
// check the type of the value
|
||||
if ((!is_numeric($value)) && (!is_string($value)) && (!is_bool($value)) && ($value !== null)) {
|
||||
throw new Exception(Functions::NA());
|
||||
}
|
||||
// Convert strings to lowercase for case-insensitive testing
|
||||
if (is_string($value)) {
|
||||
$lookupArray[$i] = StringHelper::strToLower($value);
|
||||
}
|
||||
if (
|
||||
($value === null) &&
|
||||
(($matchType == self::MATCHTYPE_LARGEST_VALUE) || ($matchType == self::MATCHTYPE_SMALLEST_VALUE))
|
||||
) {
|
||||
unset($lookupArray[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $lookupArray;
|
||||
}
|
||||
}
|
||||
43
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Formula.php
vendored
Normal file
43
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Formula.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
|
||||
class Formula
|
||||
{
|
||||
/**
|
||||
* FORMULATEXT.
|
||||
*
|
||||
* @param mixed $cellReference The cell to check
|
||||
* @param Cell $pCell The current cell (containing this formula)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function text($cellReference = '', ?Cell $pCell = null)
|
||||
{
|
||||
if ($pCell === null) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellReference, $matches);
|
||||
|
||||
$cellReference = $matches[6] . $matches[7];
|
||||
$worksheetName = trim($matches[3], "'");
|
||||
$worksheet = (!empty($worksheetName))
|
||||
? $pCell->getWorksheet()->getParent()->getSheetByName($worksheetName)
|
||||
: $pCell->getWorksheet();
|
||||
|
||||
if (
|
||||
$worksheet === null ||
|
||||
!$worksheet->cellExists($cellReference) ||
|
||||
!$worksheet->getCell($cellReference)->isFormula()
|
||||
) {
|
||||
return Functions::NA();
|
||||
}
|
||||
|
||||
return $worksheet->getCell($cellReference)->getValue();
|
||||
}
|
||||
}
|
||||
116
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php
vendored
Normal file
116
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
|
||||
|
||||
class HLookup extends LookupBase
|
||||
{
|
||||
/**
|
||||
* HLOOKUP
|
||||
* The HLOOKUP function searches for value in the top-most row of lookup_array and returns the value
|
||||
* in the same column based on the index_number.
|
||||
*
|
||||
* @param mixed $lookupValue The value that you want to match in lookup_array
|
||||
* @param mixed $lookupArray The range of cells being searched
|
||||
* @param mixed $indexNumber The row number in table_array from which the matching value must be returned.
|
||||
* The first row is 1.
|
||||
* @param mixed $notExactMatch determines if you are looking for an exact match based on lookup_value
|
||||
*
|
||||
* @return mixed The value of the found cell
|
||||
*/
|
||||
public static function lookup($lookupValue, $lookupArray, $indexNumber, $notExactMatch = true)
|
||||
{
|
||||
$lookupValue = Functions::flattenSingleValue($lookupValue);
|
||||
$indexNumber = Functions::flattenSingleValue($indexNumber);
|
||||
$notExactMatch = ($notExactMatch === null) ? true : Functions::flattenSingleValue($notExactMatch);
|
||||
$lookupArray = self::convertLiteralArray($lookupArray);
|
||||
|
||||
try {
|
||||
$indexNumber = self::validateIndexLookup($lookupArray, $indexNumber);
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$f = array_keys($lookupArray);
|
||||
$firstRow = reset($f);
|
||||
if ((!is_array($lookupArray[$firstRow])) || ($indexNumber > count($lookupArray))) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
$firstkey = $f[0] - 1;
|
||||
$returnColumn = $firstkey + $indexNumber;
|
||||
$firstColumn = array_shift($f);
|
||||
$rowNumber = self::hLookupSearch($lookupValue, $lookupArray, $firstColumn, $notExactMatch);
|
||||
|
||||
if ($rowNumber !== null) {
|
||||
// otherwise return the appropriate value
|
||||
return $lookupArray[$returnColumn][Coordinate::stringFromColumnIndex($rowNumber)];
|
||||
}
|
||||
|
||||
return Functions::NA();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $lookupValue The value that you want to match in lookup_array
|
||||
* @param mixed $column The column to look up
|
||||
* @param mixed $notExactMatch determines if you are looking for an exact match based on lookup_value
|
||||
*/
|
||||
private static function hLookupSearch($lookupValue, array $lookupArray, $column, $notExactMatch): ?int
|
||||
{
|
||||
$lookupLower = StringHelper::strToLower($lookupValue);
|
||||
|
||||
$rowNumber = null;
|
||||
foreach ($lookupArray[$column] as $rowKey => $rowData) {
|
||||
// break if we have passed possible keys
|
||||
$bothNumeric = is_numeric($lookupValue) && is_numeric($rowData);
|
||||
$bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData);
|
||||
$cellDataLower = StringHelper::strToLower($rowData);
|
||||
|
||||
if (
|
||||
$notExactMatch &&
|
||||
(($bothNumeric && $rowData > $lookupValue) || ($bothNotNumeric && $cellDataLower > $lookupLower))
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
$rowNumber = self::checkMatch(
|
||||
$bothNumeric,
|
||||
$bothNotNumeric,
|
||||
$notExactMatch,
|
||||
Coordinate::columnIndexFromString($rowKey),
|
||||
$cellDataLower,
|
||||
$lookupLower,
|
||||
$rowNumber
|
||||
);
|
||||
}
|
||||
|
||||
return $rowNumber;
|
||||
}
|
||||
|
||||
private static function convertLiteralArray(array $lookupArray): array
|
||||
{
|
||||
if (array_key_exists(0, $lookupArray)) {
|
||||
$lookupArray2 = [];
|
||||
$row = 0;
|
||||
foreach ($lookupArray as $arrayVal) {
|
||||
++$row;
|
||||
if (!is_array($arrayVal)) {
|
||||
$arrayVal = [$arrayVal];
|
||||
}
|
||||
$arrayVal2 = [];
|
||||
foreach ($arrayVal as $key2 => $val2) {
|
||||
$index = Coordinate::stringFromColumnIndex($key2 + 1);
|
||||
$arrayVal2[$index] = $val2;
|
||||
}
|
||||
$lookupArray2[$row] = $arrayVal2;
|
||||
}
|
||||
$lookupArray = $lookupArray2;
|
||||
}
|
||||
|
||||
return $lookupArray;
|
||||
}
|
||||
}
|
||||
74
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Helpers.php
vendored
Normal file
74
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Helpers.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Cell\AddressHelper;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\DefinedName;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class Helpers
|
||||
{
|
||||
public const CELLADDRESS_USE_A1 = true;
|
||||
|
||||
public const CELLADDRESS_USE_R1C1 = false;
|
||||
|
||||
private static function convertR1C1(string &$cellAddress1, ?string &$cellAddress2, bool $a1): string
|
||||
{
|
||||
if ($a1 === self::CELLADDRESS_USE_R1C1) {
|
||||
$cellAddress1 = AddressHelper::convertToA1($cellAddress1);
|
||||
if ($cellAddress2) {
|
||||
$cellAddress2 = AddressHelper::convertToA1($cellAddress2);
|
||||
}
|
||||
}
|
||||
|
||||
return $cellAddress1 . ($cellAddress2 ? ":$cellAddress2" : '');
|
||||
}
|
||||
|
||||
private static function adjustSheetTitle(string &$sheetTitle, ?string $value): void
|
||||
{
|
||||
if ($sheetTitle) {
|
||||
$sheetTitle .= '!';
|
||||
if (stripos($value ?? '', $sheetTitle) === 0) {
|
||||
$sheetTitle = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function extractCellAddresses(string $cellAddress, bool $a1, Worksheet $sheet, string $sheetName = ''): array
|
||||
{
|
||||
$cellAddress1 = $cellAddress;
|
||||
$cellAddress2 = null;
|
||||
$namedRange = DefinedName::resolveName($cellAddress1, $sheet, $sheetName);
|
||||
if ($namedRange !== null) {
|
||||
$workSheet = $namedRange->getWorkSheet();
|
||||
$sheetTitle = ($workSheet === null) ? '' : $workSheet->getTitle();
|
||||
$value = preg_replace('/^=/', '', $namedRange->getValue());
|
||||
self::adjustSheetTitle($sheetTitle, $value);
|
||||
$cellAddress1 = $sheetTitle . $value;
|
||||
$cellAddress = $cellAddress1;
|
||||
$a1 = self::CELLADDRESS_USE_A1;
|
||||
}
|
||||
if (strpos($cellAddress, ':') !== false) {
|
||||
[$cellAddress1, $cellAddress2] = explode(':', $cellAddress);
|
||||
}
|
||||
$cellAddress = self::convertR1C1($cellAddress1, $cellAddress2, $a1);
|
||||
|
||||
return [$cellAddress1, $cellAddress2, $cellAddress];
|
||||
}
|
||||
|
||||
public static function extractWorksheet(string $cellAddress, Cell $pCell): array
|
||||
{
|
||||
$sheetName = '';
|
||||
if (strpos($cellAddress, '!') !== false) {
|
||||
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||
$sheetName = trim($sheetName, "'");
|
||||
}
|
||||
|
||||
$worksheet = ($sheetName !== '')
|
||||
? $pCell->getWorksheet()->getParent()->getSheetByName($sheetName)
|
||||
: $pCell->getWorksheet();
|
||||
|
||||
return [$cellAddress, $worksheet, $sheetName];
|
||||
}
|
||||
}
|
||||
40
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Hyperlink.php
vendored
Normal file
40
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Hyperlink.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
|
||||
class Hyperlink
|
||||
{
|
||||
/**
|
||||
* HYPERLINK.
|
||||
*
|
||||
* Excel Function:
|
||||
* =HYPERLINK(linkURL, [displayName])
|
||||
*
|
||||
* @param mixed $linkURL Expect string. Value to check, is also the value returned when no error
|
||||
* @param mixed $displayName Expect string. Value to return when testValue is an error condition
|
||||
* @param Cell $pCell The cell to set the hyperlink in
|
||||
*
|
||||
* @return mixed The value of $displayName (or $linkURL if $displayName was blank)
|
||||
*/
|
||||
public static function set($linkURL = '', $displayName = null, ?Cell $pCell = null)
|
||||
{
|
||||
$linkURL = ($linkURL === null) ? '' : Functions::flattenSingleValue($linkURL);
|
||||
$displayName = ($displayName === null) ? '' : Functions::flattenSingleValue($displayName);
|
||||
|
||||
if ((!is_object($pCell)) || (trim($linkURL) == '')) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
if ((is_object($displayName)) || trim($displayName) == '') {
|
||||
$displayName = $linkURL;
|
||||
}
|
||||
|
||||
$pCell->getHyperlink()->setUrl($linkURL);
|
||||
$pCell->getHyperlink()->setTooltip($displayName);
|
||||
|
||||
return $displayName;
|
||||
}
|
||||
}
|
||||
97
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php
vendored
Normal file
97
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class Indirect
|
||||
{
|
||||
/**
|
||||
* Determine whether cell address is in A1 (true) or R1C1 (false) format.
|
||||
*
|
||||
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1,
|
||||
* but can be provided as numeric which is cast to bool
|
||||
*/
|
||||
private static function a1Format($a1fmt): bool
|
||||
{
|
||||
$a1fmt = Functions::flattenSingleValue($a1fmt);
|
||||
if ($a1fmt === null) {
|
||||
return Helpers::CELLADDRESS_USE_A1;
|
||||
}
|
||||
if (is_string($a1fmt)) {
|
||||
throw new Exception(Functions::VALUE());
|
||||
}
|
||||
|
||||
return (bool) $a1fmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert cellAddress to string, verify not null string.
|
||||
*
|
||||
* @param array|string $cellAddress
|
||||
*/
|
||||
private static function validateAddress($cellAddress): string
|
||||
{
|
||||
$cellAddress = Functions::flattenSingleValue($cellAddress);
|
||||
if (!is_string($cellAddress) || !$cellAddress) {
|
||||
throw new Exception(Functions::REF());
|
||||
}
|
||||
|
||||
return $cellAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* INDIRECT.
|
||||
*
|
||||
* Returns the reference specified by a text string.
|
||||
* References are immediately evaluated to display their contents.
|
||||
*
|
||||
* Excel Function:
|
||||
* =INDIRECT(cellAddress, bool) where the bool argument is optional
|
||||
*
|
||||
* @param array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula)
|
||||
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1,
|
||||
* but can be provided as numeric which is cast to bool
|
||||
* @param Cell $pCell The current cell (containing this formula)
|
||||
*
|
||||
* @return array|string An array containing a cell or range of cells, or a string on error
|
||||
*/
|
||||
public static function INDIRECT($cellAddress, $a1fmt, Cell $pCell)
|
||||
{
|
||||
try {
|
||||
$a1 = self::a1Format($a1fmt);
|
||||
$cellAddress = self::validateAddress($cellAddress);
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
[$cellAddress, $worksheet, $sheetName] = Helpers::extractWorksheet($cellAddress, $pCell);
|
||||
|
||||
[$cellAddress1, $cellAddress2, $cellAddress] = Helpers::extractCellAddresses($cellAddress, $a1, $pCell->getWorkSheet(), $sheetName);
|
||||
|
||||
if (
|
||||
(!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress1, $matches)) ||
|
||||
(($cellAddress2 !== null) && (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress2, $matches)))
|
||||
) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
return self::extractRequiredCells($worksheet, $cellAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract range values.
|
||||
*
|
||||
* @return mixed Array of values in range if range contains more than one element.
|
||||
* Otherwise, a single value is returned.
|
||||
*/
|
||||
private static function extractRequiredCells(?Worksheet $worksheet, string $cellAddress)
|
||||
{
|
||||
return Calculation::getInstance($worksheet !== null ? $worksheet->getParent() : null)
|
||||
->extractCellRange($cellAddress, $worksheet, false);
|
||||
}
|
||||
}
|
||||
105
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php
vendored
Normal file
105
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
class Lookup
|
||||
{
|
||||
/**
|
||||
* LOOKUP
|
||||
* The LOOKUP function searches for value either from a one-row or one-column range or from an array.
|
||||
*
|
||||
* @param mixed $lookupValue The value that you want to match in lookup_array
|
||||
* @param mixed $lookupVector The range of cells being searched
|
||||
* @param null|mixed $resultVector The column from which the matching value must be returned
|
||||
*
|
||||
* @return mixed The value of the found cell
|
||||
*/
|
||||
public static function lookup($lookupValue, $lookupVector, $resultVector = null)
|
||||
{
|
||||
$lookupValue = Functions::flattenSingleValue($lookupValue);
|
||||
|
||||
if (!is_array($lookupVector)) {
|
||||
return Functions::NA();
|
||||
}
|
||||
$hasResultVector = isset($resultVector);
|
||||
$lookupRows = self::rowCount($lookupVector);
|
||||
$lookupColumns = self::columnCount($lookupVector);
|
||||
// we correctly orient our results
|
||||
if (($lookupRows === 1 && $lookupColumns > 1) || (!$hasResultVector && $lookupRows === 2 && $lookupColumns !== 2)) {
|
||||
$lookupVector = LookupRef\Matrix::transpose($lookupVector);
|
||||
$lookupRows = self::rowCount($lookupVector);
|
||||
$lookupColumns = self::columnCount($lookupVector);
|
||||
}
|
||||
|
||||
$resultVector = self::verifyResultVector($lookupVector, $resultVector);
|
||||
|
||||
if ($lookupRows === 2 && !$hasResultVector) {
|
||||
$resultVector = array_pop($lookupVector);
|
||||
$lookupVector = array_shift($lookupVector);
|
||||
}
|
||||
|
||||
if ($lookupColumns !== 2) {
|
||||
$lookupVector = self::verifyLookupValues($lookupVector, $resultVector);
|
||||
}
|
||||
|
||||
return VLookup::lookup($lookupValue, $lookupVector, 2);
|
||||
}
|
||||
|
||||
private static function verifyLookupValues(array $lookupVector, array $resultVector): array
|
||||
{
|
||||
foreach ($lookupVector as &$value) {
|
||||
if (is_array($value)) {
|
||||
$k = array_keys($value);
|
||||
$key1 = $key2 = array_shift($k);
|
||||
++$key2;
|
||||
$dataValue1 = $value[$key1];
|
||||
} else {
|
||||
$key1 = 0;
|
||||
$key2 = 1;
|
||||
$dataValue1 = $value;
|
||||
}
|
||||
|
||||
$dataValue2 = array_shift($resultVector);
|
||||
if (is_array($dataValue2)) {
|
||||
$dataValue2 = array_shift($dataValue2);
|
||||
}
|
||||
$value = [$key1 => $dataValue1, $key2 => $dataValue2];
|
||||
}
|
||||
unset($value);
|
||||
|
||||
return $lookupVector;
|
||||
}
|
||||
|
||||
private static function verifyResultVector(array $lookupVector, $resultVector)
|
||||
{
|
||||
if ($resultVector === null) {
|
||||
$resultVector = $lookupVector;
|
||||
}
|
||||
|
||||
$resultRows = self::rowCount($resultVector);
|
||||
$resultColumns = self::columnCount($resultVector);
|
||||
|
||||
// we correctly orient our results
|
||||
if ($resultRows === 1 && $resultColumns > 1) {
|
||||
$resultVector = LookupRef\Matrix::transpose($resultVector);
|
||||
}
|
||||
|
||||
return $resultVector;
|
||||
}
|
||||
|
||||
private static function rowCount(array $dataArray): int
|
||||
{
|
||||
return count($dataArray);
|
||||
}
|
||||
|
||||
private static function columnCount(array $dataArray): int
|
||||
{
|
||||
$rowKeys = array_keys($dataArray);
|
||||
$row = array_shift($rowKeys);
|
||||
|
||||
return count($dataArray[$row]);
|
||||
}
|
||||
}
|
||||
48
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php
vendored
Normal file
48
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
|
||||
abstract class LookupBase
|
||||
{
|
||||
protected static function validateIndexLookup($lookup_array, $index_number)
|
||||
{
|
||||
// index_number must be a number greater than or equal to 1
|
||||
if (!is_numeric($index_number) || $index_number < 1) {
|
||||
throw new Exception(Functions::VALUE());
|
||||
}
|
||||
|
||||
// index_number must be less than or equal to the number of columns in lookup_array
|
||||
if ((!is_array($lookup_array)) || (empty($lookup_array))) {
|
||||
throw new Exception(Functions::REF());
|
||||
}
|
||||
|
||||
return (int) $index_number;
|
||||
}
|
||||
|
||||
protected static function checkMatch(
|
||||
bool $bothNumeric,
|
||||
bool $bothNotNumeric,
|
||||
$notExactMatch,
|
||||
int $rowKey,
|
||||
string $cellDataLower,
|
||||
string $lookupLower,
|
||||
?int $rowNumber
|
||||
): ?int {
|
||||
// remember the last key, but only if datatypes match
|
||||
if ($bothNumeric || $bothNotNumeric) {
|
||||
// Spreadsheets software returns first exact match,
|
||||
// we have sorted and we might have broken key orders
|
||||
// we want the first one (by its initial index)
|
||||
if ($notExactMatch) {
|
||||
$rowNumber = $rowKey;
|
||||
} elseif (($cellDataLower == $lookupLower) && (($rowNumber === null) || ($rowKey < $rowNumber))) {
|
||||
$rowNumber = $rowKey;
|
||||
}
|
||||
}
|
||||
|
||||
return $rowNumber;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
|
||||
class LookupRefValidations
|
||||
{
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function validateInt($value): int
|
||||
{
|
||||
if (!is_numeric($value)) {
|
||||
if (Functions::isError($value)) {
|
||||
throw new Exception($value);
|
||||
}
|
||||
|
||||
throw new Exception(Functions::VALUE());
|
||||
}
|
||||
|
||||
return (int) floor((float) $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function validatePositiveInt($value, bool $allowZero = true): int
|
||||
{
|
||||
$value = self::validateInt($value);
|
||||
|
||||
if (($allowZero === false && $value <= 0) || $value < 0) {
|
||||
throw new Exception(Functions::VALUE());
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
110
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php
vendored
Normal file
110
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
|
||||
class Matrix
|
||||
{
|
||||
/**
|
||||
* TRANSPOSE.
|
||||
*
|
||||
* @param array|mixed $matrixData A matrix of values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function transpose($matrixData)
|
||||
{
|
||||
$returnMatrix = [];
|
||||
if (!is_array($matrixData)) {
|
||||
$matrixData = [[$matrixData]];
|
||||
}
|
||||
|
||||
$column = 0;
|
||||
foreach ($matrixData as $matrixRow) {
|
||||
$row = 0;
|
||||
foreach ($matrixRow as $matrixCell) {
|
||||
$returnMatrix[$row][$column] = $matrixCell;
|
||||
++$row;
|
||||
}
|
||||
++$column;
|
||||
}
|
||||
|
||||
return $returnMatrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* INDEX.
|
||||
*
|
||||
* Uses an index to choose a value from a reference or array
|
||||
*
|
||||
* Excel Function:
|
||||
* =INDEX(range_array, row_num, [column_num], [area_num])
|
||||
*
|
||||
* @param mixed $matrix A range of cells or an array constant
|
||||
* @param mixed $rowNum The row in the array or range from which to return a value.
|
||||
* If row_num is omitted, column_num is required.
|
||||
* @param mixed $columnNum The column in the array or range from which to return a value.
|
||||
* If column_num is omitted, row_num is required.
|
||||
*
|
||||
* TODO Provide support for area_num, currently not supported
|
||||
*
|
||||
* @return mixed the value of a specified cell or array of cells
|
||||
*/
|
||||
public static function index($matrix, $rowNum = 0, $columnNum = 0)
|
||||
{
|
||||
$rowNum = ($rowNum === null) ? 0 : Functions::flattenSingleValue($rowNum);
|
||||
$columnNum = ($columnNum === null) ? 0 : Functions::flattenSingleValue($columnNum);
|
||||
|
||||
try {
|
||||
$rowNum = LookupRefValidations::validatePositiveInt($rowNum);
|
||||
$columnNum = LookupRefValidations::validatePositiveInt($columnNum);
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
if (!is_array($matrix) || ($rowNum > count($matrix))) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
$rowKeys = array_keys($matrix);
|
||||
$columnKeys = @array_keys($matrix[$rowKeys[0]]);
|
||||
|
||||
if ($columnNum > count($columnKeys)) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
if ($columnNum === 0) {
|
||||
return self::extractRowValue($matrix, $rowKeys, $rowNum);
|
||||
}
|
||||
|
||||
$columnNum = $columnKeys[--$columnNum];
|
||||
if ($rowNum === 0) {
|
||||
return array_map(
|
||||
function ($value) {
|
||||
return [$value];
|
||||
},
|
||||
array_column($matrix, $columnNum)
|
||||
);
|
||||
}
|
||||
$rowNum = $rowKeys[--$rowNum];
|
||||
|
||||
return $matrix[$rowNum][$columnNum];
|
||||
}
|
||||
|
||||
private static function extractRowValue(array $matrix, array $rowKeys, int $rowNum)
|
||||
{
|
||||
if ($rowNum === 0) {
|
||||
return $matrix;
|
||||
}
|
||||
|
||||
$rowNum = $rowKeys[--$rowNum];
|
||||
$row = $matrix[$rowNum];
|
||||
if (is_array($row)) {
|
||||
return [$rowNum => $row];
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
136
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php
vendored
Normal file
136
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class Offset
|
||||
{
|
||||
/**
|
||||
* OFFSET.
|
||||
*
|
||||
* Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells.
|
||||
* The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and
|
||||
* the number of columns to be returned.
|
||||
*
|
||||
* Excel Function:
|
||||
* =OFFSET(cellAddress, rows, cols, [height], [width])
|
||||
*
|
||||
* @param null|string $cellAddress The reference from which you want to base the offset.
|
||||
* Reference must refer to a cell or range of adjacent cells;
|
||||
* otherwise, OFFSET returns the #VALUE! error value.
|
||||
* @param mixed $rows The number of rows, up or down, that you want the upper-left cell to refer to.
|
||||
* Using 5 as the rows argument specifies that the upper-left cell in the
|
||||
* reference is five rows below reference. Rows can be positive (which means
|
||||
* below the starting reference) or negative (which means above the starting
|
||||
* reference).
|
||||
* @param mixed $columns The number of columns, to the left or right, that you want the upper-left cell
|
||||
* of the result to refer to. Using 5 as the cols argument specifies that the
|
||||
* upper-left cell in the reference is five columns to the right of reference.
|
||||
* Cols can be positive (which means to the right of the starting reference)
|
||||
* or negative (which means to the left of the starting reference).
|
||||
* @param mixed $height The height, in number of rows, that you want the returned reference to be.
|
||||
* Height must be a positive number.
|
||||
* @param mixed $width The width, in number of columns, that you want the returned reference to be.
|
||||
* Width must be a positive number.
|
||||
*
|
||||
* @return array|int|string An array containing a cell or range of cells, or a string on error
|
||||
*/
|
||||
public static function OFFSET($cellAddress = null, $rows = 0, $columns = 0, $height = null, $width = null, ?Cell $pCell = null)
|
||||
{
|
||||
$rows = Functions::flattenSingleValue($rows);
|
||||
$columns = Functions::flattenSingleValue($columns);
|
||||
$height = Functions::flattenSingleValue($height);
|
||||
$width = Functions::flattenSingleValue($width);
|
||||
|
||||
if ($cellAddress === null || $cellAddress === '') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!is_object($pCell)) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
[$cellAddress, $worksheet] = self::extractWorksheet($cellAddress, $pCell);
|
||||
|
||||
$startCell = $endCell = $cellAddress;
|
||||
if (strpos($cellAddress, ':')) {
|
||||
[$startCell, $endCell] = explode(':', $cellAddress);
|
||||
}
|
||||
[$startCellColumn, $startCellRow] = Coordinate::coordinateFromString($startCell);
|
||||
[$endCellColumn, $endCellRow] = Coordinate::coordinateFromString($endCell);
|
||||
|
||||
$startCellRow += $rows;
|
||||
$startCellColumn = Coordinate::columnIndexFromString($startCellColumn) - 1;
|
||||
$startCellColumn += $columns;
|
||||
|
||||
if (($startCellRow <= 0) || ($startCellColumn < 0)) {
|
||||
return Functions::REF();
|
||||
}
|
||||
|
||||
$endCellColumn = self::adjustEndCellColumnForWidth($endCellColumn, $width, $startCellColumn, $columns);
|
||||
$startCellColumn = Coordinate::stringFromColumnIndex($startCellColumn + 1);
|
||||
|
||||
$endCellRow = self::adustEndCellRowForHeight($height, $startCellRow, $rows, $endCellRow);
|
||||
|
||||
if (($endCellRow <= 0) || ($endCellColumn < 0)) {
|
||||
return Functions::REF();
|
||||
}
|
||||
$endCellColumn = Coordinate::stringFromColumnIndex($endCellColumn + 1);
|
||||
|
||||
$cellAddress = "{$startCellColumn}{$startCellRow}";
|
||||
if (($startCellColumn != $endCellColumn) || ($startCellRow != $endCellRow)) {
|
||||
$cellAddress .= ":{$endCellColumn}{$endCellRow}";
|
||||
}
|
||||
|
||||
return self::extractRequiredCells($worksheet, $cellAddress);
|
||||
}
|
||||
|
||||
private static function extractRequiredCells(?Worksheet $worksheet, string $cellAddress)
|
||||
{
|
||||
return Calculation::getInstance($worksheet !== null ? $worksheet->getParent() : null)
|
||||
->extractCellRange($cellAddress, $worksheet, false);
|
||||
}
|
||||
|
||||
private static function extractWorksheet($cellAddress, Cell $pCell): array
|
||||
{
|
||||
$sheetName = '';
|
||||
if (strpos($cellAddress, '!') !== false) {
|
||||
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||
$sheetName = trim($sheetName, "'");
|
||||
}
|
||||
|
||||
$worksheet = ($sheetName !== '')
|
||||
? $pCell->getWorksheet()->getParent()->getSheetByName($sheetName)
|
||||
: $pCell->getWorksheet();
|
||||
|
||||
return [$cellAddress, $worksheet];
|
||||
}
|
||||
|
||||
private static function adjustEndCellColumnForWidth(string $endCellColumn, $width, int $startCellColumn, $columns)
|
||||
{
|
||||
$endCellColumn = Coordinate::columnIndexFromString($endCellColumn) - 1;
|
||||
if (($width !== null) && (!is_object($width))) {
|
||||
$endCellColumn = $startCellColumn + (int) $width - 1;
|
||||
} else {
|
||||
$endCellColumn += (int) $columns;
|
||||
}
|
||||
|
||||
return $endCellColumn;
|
||||
}
|
||||
|
||||
private static function adustEndCellRowForHeight($height, int $startCellRow, $rows, $endCellRow): int
|
||||
{
|
||||
if (($height !== null) && (!is_object($height))) {
|
||||
$endCellRow = $startCellRow + (int) $height - 1;
|
||||
} else {
|
||||
$endCellRow += (int) $rows;
|
||||
}
|
||||
|
||||
return $endCellRow;
|
||||
}
|
||||
}
|
||||
209
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php
vendored
Normal file
209
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class RowColumnInformation
|
||||
{
|
||||
/**
|
||||
* Test if cellAddress is null or whitespace string.
|
||||
*
|
||||
* @param null|array|string $cellAddress A reference to a range of cells
|
||||
*/
|
||||
private static function cellAddressNullOrWhitespace($cellAddress): bool
|
||||
{
|
||||
return $cellAddress === null || (!is_array($cellAddress) && trim($cellAddress) === '');
|
||||
}
|
||||
|
||||
private static function cellColumn(?Cell $pCell): int
|
||||
{
|
||||
return ($pCell !== null) ? (int) Coordinate::columnIndexFromString($pCell->getColumn()) : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* COLUMN.
|
||||
*
|
||||
* Returns the column number of the given cell reference
|
||||
* If the cell reference is a range of cells, COLUMN returns the column numbers of each column
|
||||
* in the reference as a horizontal array.
|
||||
* If cell reference is omitted, and the function is being called through the calculation engine,
|
||||
* then it is assumed to be the reference of the cell in which the COLUMN function appears;
|
||||
* otherwise this function returns 1.
|
||||
*
|
||||
* Excel Function:
|
||||
* =COLUMN([cellAddress])
|
||||
*
|
||||
* @param null|array|string $cellAddress A reference to a range of cells for which you want the column numbers
|
||||
*
|
||||
* @return int|int[]
|
||||
*/
|
||||
public static function COLUMN($cellAddress = null, ?Cell $pCell = null)
|
||||
{
|
||||
if (self::cellAddressNullOrWhitespace($cellAddress)) {
|
||||
return self::cellColumn($pCell);
|
||||
}
|
||||
|
||||
if (is_array($cellAddress)) {
|
||||
foreach ($cellAddress as $columnKey => $value) {
|
||||
$columnKey = preg_replace('/[^a-z]/i', '', $columnKey);
|
||||
|
||||
return (int) Coordinate::columnIndexFromString($columnKey);
|
||||
}
|
||||
|
||||
return self::cellColumn($pCell);
|
||||
}
|
||||
|
||||
$cellAddress = $cellAddress ?? '';
|
||||
if ($pCell != null) {
|
||||
[,, $sheetName] = Helpers::extractWorksheet($cellAddress, $pCell);
|
||||
[,, $cellAddress] = Helpers::extractCellAddresses($cellAddress, true, $pCell->getWorksheet(), $sheetName);
|
||||
}
|
||||
[, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||
if (strpos($cellAddress, ':') !== false) {
|
||||
[$startAddress, $endAddress] = explode(':', $cellAddress);
|
||||
$startAddress = preg_replace('/[^a-z]/i', '', $startAddress);
|
||||
$endAddress = preg_replace('/[^a-z]/i', '', $endAddress);
|
||||
|
||||
return range(
|
||||
(int) Coordinate::columnIndexFromString($startAddress),
|
||||
(int) Coordinate::columnIndexFromString($endAddress)
|
||||
);
|
||||
}
|
||||
|
||||
$cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress);
|
||||
|
||||
return (int) Coordinate::columnIndexFromString($cellAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* COLUMNS.
|
||||
*
|
||||
* Returns the number of columns in an array or reference.
|
||||
*
|
||||
* Excel Function:
|
||||
* =COLUMNS(cellAddress)
|
||||
*
|
||||
* @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells
|
||||
* for which you want the number of columns
|
||||
*
|
||||
* @return int|string The number of columns in cellAddress, or a string if arguments are invalid
|
||||
*/
|
||||
public static function COLUMNS($cellAddress = null)
|
||||
{
|
||||
if (self::cellAddressNullOrWhitespace($cellAddress)) {
|
||||
return 1;
|
||||
}
|
||||
if (!is_array($cellAddress)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
reset($cellAddress);
|
||||
$isMatrix = (is_numeric(key($cellAddress)));
|
||||
[$columns, $rows] = Calculation::getMatrixDimensions($cellAddress);
|
||||
|
||||
if ($isMatrix) {
|
||||
return $rows;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
private static function cellRow(?Cell $pCell): int
|
||||
{
|
||||
return ($pCell !== null) ? $pCell->getRow() : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ROW.
|
||||
*
|
||||
* Returns the row number of the given cell reference
|
||||
* If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference
|
||||
* as a vertical array.
|
||||
* If cell reference is omitted, and the function is being called through the calculation engine,
|
||||
* then it is assumed to be the reference of the cell in which the ROW function appears;
|
||||
* otherwise this function returns 1.
|
||||
*
|
||||
* Excel Function:
|
||||
* =ROW([cellAddress])
|
||||
*
|
||||
* @param null|array|string $cellAddress A reference to a range of cells for which you want the row numbers
|
||||
*
|
||||
* @return int|mixed[]|string
|
||||
*/
|
||||
public static function ROW($cellAddress = null, ?Cell $pCell = null)
|
||||
{
|
||||
if (self::cellAddressNullOrWhitespace($cellAddress)) {
|
||||
return self::cellRow($pCell);
|
||||
}
|
||||
|
||||
if (is_array($cellAddress)) {
|
||||
foreach ($cellAddress as $rowKey => $rowValue) {
|
||||
foreach ($rowValue as $columnKey => $cellValue) {
|
||||
return (int) preg_replace('/\D/', '', $rowKey);
|
||||
}
|
||||
}
|
||||
|
||||
return self::cellRow($pCell);
|
||||
}
|
||||
|
||||
$cellAddress = $cellAddress ?? '';
|
||||
if ($pCell !== null) {
|
||||
[,, $sheetName] = Helpers::extractWorksheet($cellAddress, $pCell);
|
||||
[,, $cellAddress] = Helpers::extractCellAddresses($cellAddress, true, $pCell->getWorksheet(), $sheetName);
|
||||
}
|
||||
[, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||
if (strpos($cellAddress, ':') !== false) {
|
||||
[$startAddress, $endAddress] = explode(':', $cellAddress);
|
||||
$startAddress = preg_replace('/\D/', '', $startAddress);
|
||||
$endAddress = preg_replace('/\D/', '', $endAddress);
|
||||
|
||||
return array_map(
|
||||
function ($value) {
|
||||
return [$value];
|
||||
},
|
||||
range($startAddress, $endAddress)
|
||||
);
|
||||
}
|
||||
[$cellAddress] = explode(':', $cellAddress);
|
||||
|
||||
return (int) preg_replace('/\D/', '', $cellAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* ROWS.
|
||||
*
|
||||
* Returns the number of rows in an array or reference.
|
||||
*
|
||||
* Excel Function:
|
||||
* =ROWS(cellAddress)
|
||||
*
|
||||
* @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells
|
||||
* for which you want the number of rows
|
||||
*
|
||||
* @return int|string The number of rows in cellAddress, or a string if arguments are invalid
|
||||
*/
|
||||
public static function ROWS($cellAddress = null)
|
||||
{
|
||||
if (self::cellAddressNullOrWhitespace($cellAddress)) {
|
||||
return 1;
|
||||
}
|
||||
if (!is_array($cellAddress)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
reset($cellAddress);
|
||||
$isMatrix = (is_numeric(key($cellAddress)));
|
||||
[$columns, $rows] = Calculation::getMatrixDimensions($cellAddress);
|
||||
|
||||
if ($isMatrix) {
|
||||
return $columns;
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
46
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Selection.php
vendored
Normal file
46
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/Selection.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
|
||||
class Selection
|
||||
{
|
||||
/**
|
||||
* CHOOSE.
|
||||
*
|
||||
* Uses lookup_value to return a value from the list of value arguments.
|
||||
* Use CHOOSE to select one of up to 254 values based on the lookup_value.
|
||||
*
|
||||
* Excel Function:
|
||||
* =CHOOSE(index_num, value1, [value2], ...)
|
||||
*
|
||||
* @param mixed ...$chooseArgs Data values
|
||||
*
|
||||
* @return mixed The selected value
|
||||
*/
|
||||
public static function choose(...$chooseArgs)
|
||||
{
|
||||
$chosenEntry = Functions::flattenArray(array_shift($chooseArgs));
|
||||
$entryCount = count($chooseArgs) - 1;
|
||||
|
||||
if (is_array($chosenEntry)) {
|
||||
$chosenEntry = array_shift($chosenEntry);
|
||||
}
|
||||
if (is_numeric($chosenEntry)) {
|
||||
--$chosenEntry;
|
||||
} else {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
$chosenEntry = floor($chosenEntry);
|
||||
if (($chosenEntry < 0) || ($chosenEntry > $entryCount)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
if (is_array($chooseArgs[$chosenEntry])) {
|
||||
return Functions::flattenArray($chooseArgs[$chosenEntry]);
|
||||
}
|
||||
|
||||
return $chooseArgs[$chosenEntry];
|
||||
}
|
||||
}
|
||||
105
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php
vendored
Normal file
105
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
|
||||
|
||||
class VLookup extends LookupBase
|
||||
{
|
||||
/**
|
||||
* VLOOKUP
|
||||
* The VLOOKUP function searches for value in the left-most column of lookup_array and returns the value
|
||||
* in the same row based on the index_number.
|
||||
*
|
||||
* @param mixed $lookupValue The value that you want to match in lookup_array
|
||||
* @param mixed $lookupArray The range of cells being searched
|
||||
* @param mixed $indexNumber The column number in table_array from which the matching value must be returned.
|
||||
* The first column is 1.
|
||||
* @param mixed $notExactMatch determines if you are looking for an exact match based on lookup_value
|
||||
*
|
||||
* @return mixed The value of the found cell
|
||||
*/
|
||||
public static function lookup($lookupValue, $lookupArray, $indexNumber, $notExactMatch = true)
|
||||
{
|
||||
$lookupValue = Functions::flattenSingleValue($lookupValue);
|
||||
$indexNumber = Functions::flattenSingleValue($indexNumber);
|
||||
$notExactMatch = ($notExactMatch === null) ? true : Functions::flattenSingleValue($notExactMatch);
|
||||
|
||||
try {
|
||||
$indexNumber = self::validateIndexLookup($lookupArray, $indexNumber);
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$f = array_keys($lookupArray);
|
||||
$firstRow = array_pop($f);
|
||||
if ((!is_array($lookupArray[$firstRow])) || ($indexNumber > count($lookupArray[$firstRow]))) {
|
||||
return Functions::REF();
|
||||
}
|
||||
$columnKeys = array_keys($lookupArray[$firstRow]);
|
||||
$returnColumn = $columnKeys[--$indexNumber];
|
||||
$firstColumn = array_shift($columnKeys);
|
||||
|
||||
if (!$notExactMatch) {
|
||||
uasort($lookupArray, ['self', 'vlookupSort']);
|
||||
}
|
||||
|
||||
$rowNumber = self::vLookupSearch($lookupValue, $lookupArray, $firstColumn, $notExactMatch);
|
||||
|
||||
if ($rowNumber !== null) {
|
||||
// return the appropriate value
|
||||
return $lookupArray[$rowNumber][$returnColumn];
|
||||
}
|
||||
|
||||
return Functions::NA();
|
||||
}
|
||||
|
||||
private static function vlookupSort($a, $b)
|
||||
{
|
||||
reset($a);
|
||||
$firstColumn = key($a);
|
||||
$aLower = StringHelper::strToLower($a[$firstColumn]);
|
||||
$bLower = StringHelper::strToLower($b[$firstColumn]);
|
||||
|
||||
if ($aLower == $bLower) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($aLower < $bLower) ? -1 : 1;
|
||||
}
|
||||
|
||||
private static function vLookupSearch($lookupValue, $lookupArray, $column, $notExactMatch)
|
||||
{
|
||||
$lookupLower = StringHelper::strToLower($lookupValue);
|
||||
|
||||
$rowNumber = null;
|
||||
foreach ($lookupArray as $rowKey => $rowData) {
|
||||
$bothNumeric = is_numeric($lookupValue) && is_numeric($rowData[$column]);
|
||||
$bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData[$column]);
|
||||
$cellDataLower = StringHelper::strToLower($rowData[$column]);
|
||||
|
||||
// break if we have passed possible keys
|
||||
if (
|
||||
$notExactMatch &&
|
||||
(($bothNumeric && ($rowData[$column] > $lookupValue)) ||
|
||||
($bothNotNumeric && ($cellDataLower > $lookupLower)))
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
$rowNumber = self::checkMatch(
|
||||
$bothNumeric,
|
||||
$bothNotNumeric,
|
||||
$notExactMatch,
|
||||
$rowKey,
|
||||
$cellDataLower,
|
||||
$lookupLower,
|
||||
$rowNumber
|
||||
);
|
||||
}
|
||||
|
||||
return $rowNumber;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user