Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cell->hasValidValue() - test value on list validation #257

Closed
12 changes: 11 additions & 1 deletion src/PhpSpreadsheet/Cell/Cell.php
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,17 @@ public function setDataValidation(DataValidation $pDataValidation = null)
}

/**
* Does this cell contain a Hyperlink?
* Does this cell contain valid value?
*
* @return bool
*/
public function hasValidValue()
{
return (new CellDataValidator())->isValid($this);
}

/**
* Does this cell contain a Hyperlink?
*
* @throws Exception
*
Expand Down
73 changes: 73 additions & 0 deletions src/PhpSpreadsheet/Cell/CellDataValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Cell;

use PhpOffice\PhpSpreadsheet\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Exception;

class CellDataValidator
{
/**
* Does this cell contain valid value?
*
* @param Cell $cell Cell to check the value
*
* @return bool
*/
public function isValid(Cell $cell)
{
if (!$cell->hasDataValidation()) {
return true;
}

$cellValue = $cell->getValue();
$dataValidation = $cell->getDataValidation();

if (!$dataValidation->getAllowBlank() && ($cellValue === null || $cellValue == '')) {
return false;
}

// TODO: write check on all cases
switch ($dataValidation->getType()) {
case DataValidation::TYPE_LIST:
return $this->isValueInList($cell);
}

return true;
}

/**
* Does this cell contain valid value, based on list?
*
* @param Cell $cell Cell to check the value
*
* @return bool
*/
private function isValueInList(Cell $cell)
{
$cellValue = $cell->getValue();
$dataValidation = $cell->getDataValidation();

$formula1 = $dataValidation->getFormula1();
if (!empty($formula1)) {
if ($formula1[0] === '"') { // inline values list
return in_array(strtolower($cellValue), explode(',', strtolower(trim($formula1, '"'))), true);
} elseif (strpos($formula1, ':') > 0) { // values list cells
$match_formula = '=MATCH(' . $cell->getCoordinate() . ',' . $formula1 . ',0)';

try {
$result = Calculation\Calculation::getInstance(
$cell->getWorksheet()->getParent()
)->calculateFormula($match_formula, $cell->getCoordinate(), $cell);

return $result !== Functions::NA();
} catch (Exception $ex) {
return false;
}
}
}

return true;
}
}
37 changes: 37 additions & 0 deletions tests/PhpSpreadsheetTests/Cell/CellTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit_Framework_TestCase;

class CellTest extends PHPUnit_Framework_TestCase
Expand Down Expand Up @@ -323,4 +324,40 @@ public function providerMergeRangesInCollection()
{
return require 'data/CellMergeRangesInCollection.php';
}

public function testHasValidValue()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$testCell = $sheet->getCell('A1');

$validation = $testCell->getDataValidation();
$validation->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST);

// blank value
$testCell->setValue('');
$validation->setAllowBlank(true);
self::assertEquals(true, $testCell->hasValidValue(), 'cell can be empty');
$validation->setAllowBlank(false);
self::assertEquals(false, $testCell->hasValidValue(), 'cell can not be empty');

// inline list
$validation->setFormula1('"yes,no"');
$testCell->setValue('foo');
self::assertEquals(false, $testCell->hasValidValue(), "cell value ('foo') is not allowed");
$testCell->setValue('yes');
self::assertEquals(true, $testCell->hasValidValue(), "cell value ('yes') has to be allowed");

// list from cells
$sheet->getCell('B1')->setValue(5);
$sheet->getCell('B2')->setValue(6);
$sheet->getCell('B3')->setValue(7);
$testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells
$validation->setFormula1('B1:B3');
$testCell->setValue('10');
self::assertEquals(false, $testCell->hasValidValue(), "cell value ('10') is not allowed");
$testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells
$testCell->setValue('5');
self::assertEquals(true, $testCell->hasValidValue(), "cell value ('5') has to be allowed");
}
}