See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard; 4 5 use PhpOffice\PhpSpreadsheet\Calculation\Calculation; 6 use PhpOffice\PhpSpreadsheet\Exception; 7 use PhpOffice\PhpSpreadsheet\Style\Conditional; 8 use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard; 9 10 /** 11 * @method TextValue contains(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) 12 * @method TextValue doesNotContain(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) 13 * @method TextValue doesntContain(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) 14 * @method TextValue beginsWith(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) 15 * @method TextValue startsWith(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) 16 * @method TextValue endsWith(string $value, string $operandValueType = Wizard::VALUE_TYPE_LITERAL) 17 */ 18 class TextValue extends WizardAbstract implements WizardInterface 19 { 20 protected const MAGIC_OPERATIONS = [ 21 'contains' => Conditional::OPERATOR_CONTAINSTEXT, 22 'doesntContain' => Conditional::OPERATOR_NOTCONTAINS, 23 'doesNotContain' => Conditional::OPERATOR_NOTCONTAINS, 24 'beginsWith' => Conditional::OPERATOR_BEGINSWITH, 25 'startsWith' => Conditional::OPERATOR_BEGINSWITH, 26 'endsWith' => Conditional::OPERATOR_ENDSWITH, 27 ]; 28 29 protected const OPERATORS = [ 30 Conditional::OPERATOR_CONTAINSTEXT => Conditional::CONDITION_CONTAINSTEXT, 31 Conditional::OPERATOR_NOTCONTAINS => Conditional::CONDITION_NOTCONTAINSTEXT, 32 Conditional::OPERATOR_BEGINSWITH => Conditional::CONDITION_BEGINSWITH, 33 Conditional::OPERATOR_ENDSWITH => Conditional::CONDITION_ENDSWITH, 34 ]; 35 36 protected const EXPRESSIONS = [ 37 Conditional::OPERATOR_CONTAINSTEXT => 'NOT(ISERROR(SEARCH(%s,%s)))', 38 Conditional::OPERATOR_NOTCONTAINS => 'ISERROR(SEARCH(%s,%s))', 39 Conditional::OPERATOR_BEGINSWITH => 'LEFT(%s,LEN(%s))=%s', 40 Conditional::OPERATOR_ENDSWITH => 'RIGHT(%s,LEN(%s))=%s', 41 ]; 42 43 /** @var string */ 44 protected $operator; 45 46 /** @var string */ 47 protected $operand; 48 49 /** 50 * @var string 51 */ 52 protected $operandValueType; 53 54 public function __construct(string $cellRange) 55 { 56 parent::__construct($cellRange); 57 } 58 59 protected function operator(string $operator): void 60 { 61 if (!isset(self::OPERATORS[$operator])) { 62 throw new Exception('Invalid Operator for Text Value CF Rule Wizard'); 63 } 64 65 $this->operator = $operator; 66 } 67 68 protected function operand(string $operand, string $operandValueType = Wizard::VALUE_TYPE_LITERAL): void 69 { 70 if (is_string($operand)) { 71 $operand = $this->validateOperand($operand, $operandValueType); 72 } 73 74 $this->operand = $operand; 75 $this->operandValueType = $operandValueType; 76 } 77 78 protected function wrapValue(string $value): string 79 { 80 return '"' . $value . '"'; 81 } 82 83 protected function setExpression(): void 84 { 85 $operand = $this->operandValueType === Wizard::VALUE_TYPE_LITERAL 86 ? $this->wrapValue(str_replace('"', '""', $this->operand)) 87 : $this->cellConditionCheck($this->operand); 88 89 if ( 90 $this->operator === Conditional::OPERATOR_CONTAINSTEXT || 91 $this->operator === Conditional::OPERATOR_NOTCONTAINS 92 ) { 93 $this->expression = sprintf(self::EXPRESSIONS[$this->operator], $operand, $this->referenceCell); 94 } else { 95 $this->expression = sprintf(self::EXPRESSIONS[$this->operator], $this->referenceCell, $operand, $operand); 96 } 97 } 98 99 public function getConditional(): Conditional 100 { 101 $this->setExpression(); 102 103 $conditional = new Conditional(); 104 $conditional->setConditionType(self::OPERATORS[$this->operator]); 105 $conditional->setOperatorType($this->operator); 106 $conditional->setText( 107 $this->operandValueType !== Wizard::VALUE_TYPE_LITERAL 108 ? $this->cellConditionCheck($this->operand) 109 : $this->operand 110 ); 111 $conditional->setConditions([$this->expression]); 112 $conditional->setStyle($this->getStyle()); 113 $conditional->setStopIfTrue($this->getStopIfTrue()); 114 115 return $conditional; 116 } 117 118 public static function fromConditional(Conditional $conditional, string $cellRange = 'A1'): WizardInterface 119 { 120 if (!in_array($conditional->getConditionType(), self::OPERATORS, true)) { 121 throw new Exception('Conditional is not a Text Value CF Rule conditional'); 122 } 123 124 $wizard = new self($cellRange); 125 $wizard->operator = (string) array_search($conditional->getConditionType(), self::OPERATORS, true); 126 $wizard->style = $conditional->getStyle(); 127 $wizard->stopIfTrue = $conditional->getStopIfTrue(); 128 129 // Best-guess to try and identify if the text is a string literal, a cell reference or a formula? 130 $wizard->operandValueType = Wizard::VALUE_TYPE_LITERAL; 131 $condition = $conditional->getText(); 132 if (is_string($condition) && array_key_exists($condition, Calculation::$excelConstants)) { 133 $condition = Calculation::$excelConstants[$condition]; 134 } elseif (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '$/i', $condition)) { 135 $wizard->operandValueType = Wizard::VALUE_TYPE_CELL; 136 $condition = self::reverseAdjustCellRef($condition, $cellRange); 137 } elseif ( 138 preg_match('/\(\)/', $condition) || 139 preg_match('/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i', $condition) 140 ) { 141 $wizard->operandValueType = Wizard::VALUE_TYPE_FORMULA; 142 } 143 $wizard->operand = $condition; 144 145 return $wizard; 146 } 147 148 /** 149 * @param string $methodName 150 * @param mixed[] $arguments 151 */ 152 public function __call($methodName, $arguments): self 153 { 154 if (!isset(self::MAGIC_OPERATIONS[$methodName])) { 155 throw new Exception('Invalid Operation for Text Value CF Rule Wizard'); 156 } 157 158 $this->operator(self::MAGIC_OPERATIONS[$methodName]); 159 $this->operand(...$arguments); 160 161 return $this; 162 } 163 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body