PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

Invalid Operation for Text Value CF Rule Wizard

Error message

Invalid Operation for Text Value CF Rule Wizard

What it means

TextValue's magic methods come from a fixed MAGIC_OPERATIONS map: contains, doesNotContain (alias doesntContain), beginsWith (alias startsWith) and endsWith. Each takes the text operand plus an optional operand-type hint. Any other name - includes(), containsText(), like(), matches() - throws Invalid Operation because __call finds no key.

Source

Thrown at src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/TextValue.php:146

            $condition = self::reverseAdjustCellRef($condition, $cellRange);
        } elseif (
            preg_match('/\(\)/', $condition)
            || preg_match('/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i', $condition)
        ) {
            $wizard->operandValueType = Wizard::VALUE_TYPE_FORMULA;
        }
        $wizard->operand = $condition;

        return $wizard;
    }

    /**
     * @param mixed[] $arguments
     */
    public function __call(string $methodName, array $arguments): self
    {
        if (!isset(self::MAGIC_OPERATIONS[$methodName])) {
            throw new Exception('Invalid Operation for Text Value CF Rule Wizard');
        }

        $this->operator(self::MAGIC_OPERATIONS[$methodName]);
        //$this->operand(...$arguments);
        if (count($arguments) < 2) {
            /** @var string */
            $arg0 = $arguments[0];
            $this->operand($arg0);
        } else {
            /** @var string */
            $arg0 = $arguments[0];
            /** @var string */
            $arg1 = $arguments[1];
            $this->operand($arg0, $arg1);
        }

        return $this;
    }

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Use only contains, doesNotContain, doesntContain, beginsWith, startsWith, endsWith
  2. Validate dynamic method names against that list before invoking
  3. Catch PhpSpreadsheetException around dynamic calls
  4. For substring patterns not expressible as contains/beginsWith/endsWith, use an Expression rule with SEARCH()

Example fix

// before
$textWizard = (new Wizard('A1:E10'))->newRule(Wizard::TEXT_VALUE);
$textWizard->includes('foo');   // throws

// after
$textWizard->contains('foo');   // or doesNotContain/doesntContain/beginsWith/startsWith/endsWith
Defensive patterns

Strategy: validation

Validate before calling

$allowed = ['contains', 'doesNotContain', 'doesntContain', 'beginsWith', 'startsWith', 'endsWith'];
$method = $config['textOperator'];
if (!in_array($method, $allowed, true)) {
    throw new InvalidArgumentException('Unknown TextValue operator: ' . $method);
}
$wizard->$method($text);

Try / catch

use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;

try {
    $textWizard->$method($text);
} catch (PhpSpreadsheetException $e) {
    throw new InvalidArgumentException('Invalid TextValue operator: ' . $method, 0, $e);
}

Prevention

When it happens

Trigger: ->includes('foo'); ->like('foo'); ->containsText('foo') (the Excel operator name, not the wizard method); names outside the six supported aliases.

Common situations: Translating SQL LIKE or collection contains() vocabulary into CF rules; developers using Excel's operator names instead of the wizard's method names; dynamic invocation from configuration.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/0ea2b53f3bd0a8c6. Report an issue: GitHub.