2

「番地」または「フラット番号」を入力する必要があるカスタムバリデータを作成しましたが、両方 (XOR) は必要ありません。

バリデーターは、両方のフィールドが入力されている場合 (失敗)、または一方が入力されている場合 (合格) に正常に動作します。ただし、両方のフィールドが空の場合、バリデーターはまったく実行されません。

両方の要素の入力フィルター仕様は次のとおりです。

$input = new Input('flat_number');
$input->setRequired(true);
$input->setAllowEmpty(true);
$input->setValue($this->flatNumber);
$input->getValidatorChain()
        ->addValidator(new \Si\Validator\HouseFlatCheck('house_number'))
        ->addValidator(new \Zend\Validator\StringLength(array('max' => 30)));
$input->getFilterChain()->attach($this->defaultFilterChain);
$inputFilter->add($input);

$input = new Input('house_number');
$input->setRequired(true);
$input->setAllowEmpty(true);
$input->setValue($this->houseNumber);
$input->getValidatorChain()
        ->addValidator(new \Si\Validator\HouseFlatCheck('flat_number'))
        ->addValidator(new \Zend\Validator\StringLength(array('max' => 30)));
$input->getFilterChain()->attach($this->defaultFilterChain);
$inputFilter->add($input);

一見すると、フィールドが空で「required」および「allowEmpty」の要件を満たしている場合、バリデーターは実行されません。

両方のフィールドが空であるにもかかわらず、「HouseFlatCheck」バリデーターを 2 つの要素に対して実行する方法はありますか?

4

3 に答える 3

3

これを丸一日調べた後、問題を回避する方法を見つけました。

まず、Zend\InputFilter\BaseInputFilter クラスには isValid() の次のものが含まれています。

public function isValid()
{
    if (null === $this->data) {
        throw new Exception\RuntimeException(sprintf(
            '%s: no data present to validate!',
            __METHOD__
        ));
    }

    $this->validInputs   = array();
    $this->invalidInputs = array();
    $valid               = true;

    $inputs = $this->validationGroup ?: array_keys($this->inputs);
    foreach ($inputs as $name) {
        $input = $this->inputs[$name];
        if (!array_key_exists($name, $this->data)
            || (null === $this->data[$name])
            || (is_string($this->data[$name]) && strlen($this->data[$name]) === 0)
        ) {
            if ($input instanceof InputInterface) {
                // - test if input is required
                if (!$input->isRequired()) {
                    $this->validInputs[$name] = $input;
                    continue;
                }
                // - test if input allows empty
                if ($input->allowEmpty()) {
                    $this->validInputs[$name] = $input;
                    continue;
                }
            }
            // make sure we have a value (empty) for validation
            $this->data[$name] = '';
        }

        if ($input instanceof InputFilterInterface) {
            if (!$input->isValid()) {
                $this->invalidInputs[$name] = $input;
                $valid = false;
                continue;
            }
            $this->validInputs[$name] = $input;
            continue;
        }
        if ($input instanceof InputInterface) {
            if (!$input->isValid($this->data)) {
                // Validation failure
                $this->invalidInputs[$name] = $input;
                $valid = false;

                if ($input->breakOnFailure()) {
                    return false;
                }
                continue;
            }
            $this->validInputs[$name] = $input;
            continue;
        }
    }

    return $valid;
}

私の入力に対して allowEmpty が true だったので、その入力の検証は停止し、配列内の次の入力要素に進みます。入力で allowEmpty を false に変更すると、この問題は解決しますが、「Zend\InputFilter\Input」クラスが isValid() 関数の実行中に次の関数を呼び出すため、別の問題が発生します。

protected function injectNotEmptyValidator()
{
    if ((!$this->isRequired() && $this->allowEmpty()) || $this->notEmptyValidator) {
        return;
    }
    $chain = $this->getValidatorChain();

    // Check if NotEmpty validator is already first in chain
    $validators = $chain->getValidators();
    if (isset($validators[0]['instance'])
        && $validators[0]['instance'] instanceof NotEmpty
    ) {
        $this->notEmptyValidator = true;
        return;
    }

    $chain->prependByName('NotEmpty', array(), true);
    $this->notEmptyValidator = true;
}

フィールドが必須で allowEmpty が false になったため、「NotEmpty」バリデーターがチェーンに自動的に追加されます。それが発見されたら、解決策は簡単でした。カスタム ライブラリに「Input」クラスを作成しました。これは injectNotEmptyValidator 関数をオーバーライドし、何もしないように強制します。

namespace Si\InputFilter;

class Input extends \Zend\InputFilter\Input {
    protected function injectNotEmptyValidator() {
        return;
    }
}

「NotEmpty」がバリデーターチェーンに追加されないという上記のメナを実行すると、XOR バリデーターが正しく実行されます。あとは、修正した Si\InputFilter\Input クラスを使用して、これら 2 つの要素の InputFilter を設定するだけです。

それが役立つことを願っています。

于 2013-01-22T10:46:13.707 に答える
1

これは別の方法で行います。家番号とフラット番号の両方を表す値の配列を受け入れるカスタム入力を作成します。入力には、XORロジックを実行し、存在するものに基づいて適切な検証チェーンを選択するカスタムバリデーターが含まれます。(同様に、フォーム側では、これを複合要素として表します。)

于 2013-01-22T12:19:27.237 に答える