tablepress
/
libraries
/
vendor
/
PhpSpreadsheet
/
Style
/
ConditionalFormatting
/
Wizard
/
CellValue.php
CellValue.php in TablePress – Tables in WordPress made easy 3.4, at libraries/vendor/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/CellValue.php
| 1 | <?php |
| 2 | |
| 3 | namespace TablePress\PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard; |
| 4 | |
| 5 | use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Calculation; |
| 6 | use TablePress\PhpOffice\PhpSpreadsheet\Exception; |
| 7 | use TablePress\PhpOffice\PhpSpreadsheet\Style\Conditional; |
| 8 | use TablePress\PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\CellMatcher; |
| 9 | use TablePress\PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard; |
| 10 | |
| 11 | /** |
| 12 | * @method CellValue equals($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 13 | * @method CellValue notEquals($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 14 | * @method CellValue greaterThan($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 15 | * @method CellValue greaterThanOrEqual($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 16 | * @method CellValue lessThan($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 17 | * @method CellValue lessThanOrEqual($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 18 | * @method CellValue between($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 19 | * @method CellValue notBetween($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 20 | * @method CellValue and($value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) |
| 21 | */ |
| 22 | class CellValue extends WizardAbstract implements WizardInterface |
| 23 | { |
| 24 | protected const MAGIC_OPERATIONS = [ |
| 25 | 'equals' => Conditional::OPERATOR_EQUAL, |
| 26 | 'notEquals' => Conditional::OPERATOR_NOTEQUAL, |
| 27 | 'greaterThan' => Conditional::OPERATOR_GREATERTHAN, |
| 28 | 'greaterThanOrEqual' => Conditional::OPERATOR_GREATERTHANOREQUAL, |
| 29 | 'lessThan' => Conditional::OPERATOR_LESSTHAN, |
| 30 | 'lessThanOrEqual' => Conditional::OPERATOR_LESSTHANOREQUAL, |
| 31 | 'between' => Conditional::OPERATOR_BETWEEN, |
| 32 | 'notBetween' => Conditional::OPERATOR_NOTBETWEEN, |
| 33 | ]; |
| 34 | |
| 35 | protected const SINGLE_OPERATORS = CellMatcher::COMPARISON_OPERATORS; |
| 36 | |
| 37 | protected const RANGE_OPERATORS = CellMatcher::COMPARISON_RANGE_OPERATORS; |
| 38 | |
| 39 | protected string $operator = Conditional::OPERATOR_EQUAL; |
| 40 | |
| 41 | /** @var array<int|string> */ |
| 42 | protected array $operand = [0]; |
| 43 | |
| 44 | /** |
| 45 | * @var string[] |
| 46 | */ |
| 47 | protected array $operandValueType = []; |
| 48 | |
| 49 | public function __construct(string $cellRange) |
| 50 | { |
| 51 | parent::__construct($cellRange); |
| 52 | } |
| 53 | |
| 54 | protected function operator(string $operator): void |
| 55 | { |
| 56 | if ((!isset(self::SINGLE_OPERATORS[$operator])) && (!isset(self::RANGE_OPERATORS[$operator]))) { |
| 57 | // should not happen - compareKeys confirms |
| 58 | throw new Exception('Invalid Operator for Cell Value CF Rule Wizard 1'); // @codeCoverageIgnore |
| 59 | } |
| 60 | |
| 61 | $this->operator = $operator; |
| 62 | } |
| 63 | |
| 64 | /** |
| 65 | * @param mixed $operand |
| 66 | */ |
| 67 | protected function operand(int $index, $operand, string $operandValueType = Wizard::VALUE_TYPE_LITERAL): void |
| 68 | { |
| 69 | if (is_string($operand)) { |
| 70 | $operand = $this->validateOperand($operand, $operandValueType); |
| 71 | } |
| 72 | |
| 73 | $this->operand[$index] = $operand; //* @phpstan-ignore assign.propertyType (I don't know what is needed) |
| 74 | $this->operandValueType[$index] = $operandValueType; |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * @param mixed $value value to be wrapped |
| 79 | * @return float|int|string */ |
| 80 | protected function wrapValue($value, string $operandValueType) |
| 81 | { |
| 82 | if (!is_numeric($value) && !is_bool($value) && null !== $value) { |
| 83 | if ($operandValueType === Wizard::VALUE_TYPE_LITERAL) { |
| 84 | return '"' . str_replace('"', '""', $value) . '"'; |
| 85 | } |
| 86 | |
| 87 | return $this->cellConditionCheck($value); |
| 88 | } |
| 89 | |
| 90 | if (null === $value) { |
| 91 | $value = 'NULL'; |
| 92 | } elseif (is_bool($value)) { |
| 93 | $value = $value ? 'TRUE' : 'FALSE'; |
| 94 | } |
| 95 | |
| 96 | return $value; |
| 97 | } |
| 98 | |
| 99 | public function getConditional(): Conditional |
| 100 | { |
| 101 | if (!isset(self::RANGE_OPERATORS[$this->operator])) { |
| 102 | unset($this->operand[1], $this->operandValueType[1]); |
| 103 | } |
| 104 | $values = array_map([$this, 'wrapValue'], $this->operand, $this->operandValueType); |
| 105 | |
| 106 | $conditional = new Conditional(); |
| 107 | $conditional->setConditionType(Conditional::CONDITION_CELLIS); |
| 108 | $conditional->setOperatorType($this->operator); |
| 109 | $conditional->setConditions($values); |
| 110 | $conditional->setStyle($this->getStyle()); |
| 111 | $conditional->setStopIfTrue($this->getStopIfTrue()); |
| 112 | |
| 113 | return $conditional; |
| 114 | } |
| 115 | |
| 116 | protected static function unwrapString(string $condition): string |
| 117 | { |
| 118 | if ((str_starts_with($condition, '"')) && (str_starts_with(strrev($condition), '"'))) { |
| 119 | $condition = (string) substr($condition, 1, -1); |
| 120 | } |
| 121 | |
| 122 | return str_replace('""', '"', $condition); |
| 123 | } |
| 124 | |
| 125 | public static function fromConditional(Conditional $conditional, string $cellRange = 'A1'): WizardInterface |
| 126 | { |
| 127 | if ($conditional->getConditionType() !== Conditional::CONDITION_CELLIS) { |
| 128 | throw new Exception('Conditional is not a Cell Value CF Rule conditional'); |
| 129 | } |
| 130 | |
| 131 | $wizard = new self($cellRange); |
| 132 | $wizard->style = $conditional->getStyle(); |
| 133 | $wizard->stopIfTrue = $conditional->getStopIfTrue(); |
| 134 | |
| 135 | $wizard->operator = $conditional->getOperatorType(); |
| 136 | $conditions = $conditional->getConditions(); |
| 137 | foreach ($conditions as $index => $condition) { |
| 138 | // Best-guess to try and identify if the text is a string literal, a cell reference or a formula? |
| 139 | $operandValueType = Wizard::VALUE_TYPE_LITERAL; |
| 140 | if (is_string($condition)) { |
| 141 | if (Calculation::keyInExcelConstants($condition)) { |
| 142 | $condition = Calculation::getExcelConstants($condition); |
| 143 | } elseif (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '$/i', $condition)) { |
| 144 | $operandValueType = Wizard::VALUE_TYPE_CELL; |
| 145 | $condition = self::reverseAdjustCellRef($condition, $cellRange); |
| 146 | } elseif ( |
| 147 | preg_match('/\(\)/', $condition) |
| 148 | || preg_match('/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i', $condition) |
| 149 | ) { |
| 150 | $operandValueType = Wizard::VALUE_TYPE_FORMULA; |
| 151 | $condition = self::reverseAdjustCellRef($condition, $cellRange); |
| 152 | } else { |
| 153 | $condition = self::unwrapString($condition); |
| 154 | } |
| 155 | } |
| 156 | $wizard->operand($index, $condition, $operandValueType); |
| 157 | } |
| 158 | |
| 159 | return $wizard; |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | * @param mixed[] $arguments |
| 164 | */ |
| 165 | public function __call(string $methodName, array $arguments): self |
| 166 | { |
| 167 | if ($methodName === 'and') { |
| 168 | if (!isset(self::RANGE_OPERATORS[$this->operator])) { |
| 169 | throw new Exception('AND Value is only appropriate for range operators'); |
| 170 | } |
| 171 | |
| 172 | $this->operand(1, ...$arguments); |
| 173 | |
| 174 | return $this; |
| 175 | } |
| 176 | |
| 177 | if (!isset(self::MAGIC_OPERATIONS[$methodName])) { |
| 178 | throw new Exception('Invalid Operator for Cell Value CF Rule Wizard'); |
| 179 | } |
| 180 | |
| 181 | $this->operator(self::MAGIC_OPERATIONS[$methodName]); |
| 182 | //$this->operand(0, ...$arguments); |
| 183 | if (count($arguments) < 2) { |
| 184 | $this->operand(0, $arguments[0]); |
| 185 | } else { |
| 186 | /** @var string */ |
| 187 | $arg1 = $arguments[1]; |
| 188 | $this->operand(0, $arguments[0], $arg1); |
| 189 | } |
| 190 | |
| 191 | return $this; |
| 192 | } |
| 193 | |
| 194 | /** @internal */ |
| 195 | public static function compareKeys(): bool |
| 196 | { |
| 197 | $retVal = true; |
| 198 | $array = array_merge(array_keys(self::SINGLE_OPERATORS), array_keys(self::RANGE_OPERATORS)); |
| 199 | foreach ($array as $value) { |
| 200 | $retVal = $retVal && in_array($value, self::MAGIC_OPERATIONS, true); |
| 201 | } |
| 202 | |
| 203 | return $retVal; |
| 204 | } |
| 205 | } |
| 206 |