Como tornar o trabalho chamativo do CodeIgniter para caixas de seleção que são deixadas vazias, bug de validação de formulário personalizado

8

Eu tenho um problema com minhas regras de validação de formulário (em um arquivo de configuração separado). Isso ocorre com caixas de seleção.

Para organizar minhas regras de validação, criei um arquivo de biblioteca chamado validation_rules . Esta biblioteca contém todos os meus retornos de chamada personalizados, como valid_date etc. Para poder chamar essas regras, eu carrego a biblioteca e, em seguida, uso a seguinte configuração:

array(
    'field' => 'terms',
    'label' => 'lang:reg_lbl_terms',
    'rules' => array(array('terms_accepted', array($ci->validation_rules, 'terms_accepted')))
    ),

Onde $ci é uma referência ao CodeIgniter ( $this ).

Agora, isso funciona bem para a maioria dos tipos de entrada, mas não funciona para caixas de seleção deixadas vazias, provavelmente porque não são postadas.

No entanto, quando eu abandono minha biblioteca e simplesmente adiciono o retorno de chamada ao controlador, tudo funciona bem com a seguinte configuração:

array(
    'field' => 'terms',
    'label' => 'lang:reg_lbl_terms',
    'rules' => array('callback_terms_accepted')
    ),

Além disso, quando adiciono as regras required em qualquer lugar na matriz rules (ou string), a regra required é chamada (retornando false, pois a caixa de seleção não está marcada), mas todas as outras regras são completamente ignorado.

Isso deve ser um bug no CodeIgniter, certo? Alguém tem uma solução ou solução alternativa? Claro que isso é uma opção, mas eu realmente não gosto disso.

Documentação relevante: link

Editar: Caixa de verificação PHP / HTML:

<?php
$data = array(
    'name'    => 'terms',
    'value'   => 'true'
);
echo form_checkbox($data);
// Results in: <input type="checkbox" name="terms" value="true">
// No set_value() is used.
?>
    
por Wouter Florijn 08.09.2015 в 14:09
fonte

3 respostas

0

Tudo bem, consegui corrigir meu problema. A questão aqui era que eu suspeitava de um bug no CodeIgniter relacionado a callables especificamente.

NOTA: Esse bug parece ter sido corrigido no CI 3.0.1+. Eu estava executando a versão 3.0.0.

O problema

O problema é que a biblioteca Form_validation tem um trecho de código na função _execute que verifica se há uma regra required ou um conjunto de regras de retorno de chamada para um campo que não é postado. Isso se aplica a caixas de seleção, pois elas não fazem parte da matriz $_POST quando deixadas vazias. Este é o código que causa o problema:

$callback = FALSE;
if ( ! in_array('required', $rules) && ($postdata === NULL OR $postdata === ''))
{
    // Before we bail out, does the rule contain a callback?
    foreach ($rules as &$rule)
    {
        if (is_string($rule))
        {
            if (strncmp($rule, 'callback_', 9) === 0)
            {
                $callback = TRUE;
                $rules = array(1 => $rule);
                break;
            }
        }
        elseif (is_callable($rule))
        {
            $callback = TRUE;
            $rules = array(1 => $rule);
            break;
        }
    }

    if ( ! $callback)
    {
        return;
    }
}

Esse código é usado para pular a validação inteiramente para um campo, se não for necessário ou tiver um retorno de chamada. No entanto , os desenvolvedores de CI cometeram o erro de verificar retornos de chamada com is_callable . Isso, claro, é bom para callables normais que são estruturados assim:

array($this->some_model_or_library, 'function_name')

Mas , o CodeIgniter permite que você nomeie seu retorno de chamada para definir erros de validação para ele da seguinte forma:

array('my_callback_function', array($this->some_model_or_library, 'function_name'))
Não é novidade que is_callable retorne false quando aplicado a essa matriz e, portanto, a validação é ignorada.

Documentos relevantes: link

A solução

Pessoalmente, não vi o uso do código acima mencionado, porque nunca quero pular a validação quando um campo não é postado. Resolvi o problema criando uma classe MY_Form_validation e substituindo a função _execute , simplesmente substituindo o código por:

$callback = TRUE;

É claro que uma solução um pouco mais conservadora seria verificar matrizes multidimensionais e aplicar is_callable ao elemento apropriado da seguinte forma:

if (is_callable($rule)                            // Original check.
|| (is_array($callback) && is_array($callback[1]) // Check if the callback is an array and contains an array as second element.
&& is_callable($callback[1]))                     // Check if the second element is a callable.
    
por Wouter Florijn 03.12.2015 / 15:29
fonte
2

Você pode criar suas regras em um arquivo form_validation dentro de / config

application / config / form_validation.php

$config = array(
    'controller/method' => array(
        array('field'=>'', 'label'=>'', 'rules'=>'required|acceptTerms')
        array('field'=>'another', 'label'=>'', 'rules'=>'required')
    ),
);

Observe o controller/method da chave, o Codeigniter usará isso se você não definir especificamente dentro da função form_validation de chamada.

Um exemplo disso seria assim

application / controllers / Shop

class Shop extends CI_Controller
{
    public function __construct(){ parent::__construct(); }

    public function index()
    {
        // Show the Purchase Form
        // in some view
        return $this->load->view();
    }

    public function purchase()
    {
        // notice we don't pass any params to the run() function
        // codeigniter will look inside application/config/form_validation/$config
        // for any matching key, ie: shop/purchase

        if(!$this->form_validation->run()){ 
            // If validation fails, show the form again
            // and stop the method from executing any further
            return $this->index();
        }
    }
}

Para validar se as caixas de seleção estiverem definidas, procuramos a palavra-chave on

application / libraries / MY_Form_validation.php

class MY_Form_validation extends CI_Form_validation
{
    public function __construct($config)
    {
        parent::__construct( $config );
    }

    public function acceptTerms( $field )
    {
        $this->set_error('acceptTerms', 'your error message');

        return (bool) $field == 'on';
    }
}
    
por Philip 17.09.2015 / 20:33
fonte
0
$terms = $this->input->post('terms');
var_dump((int)$checked); //Just to see the value, then remove this line.
if((int)$checked == 1) {
  //Checked = True
} else {
  //Checked = False
}

Verificarei o sinalizador necessário e edite esta resposta.

Editar: Em vez de apenas required , tente usar required|isset e, quando executar callback_terms_accepted, faça algo assim:

function terms_accepted($value) {
  if (isset($checked)) {
    return true;
  } else {
    $this->form_validation->set_message('terms_accepted', 'Error message');
    return false;
  }
}

Isso deve fazer o truque.

Mais uma vez, espero que ajude a acasalar.

    
por Bob Rosset 16.09.2015 / 05:41
fonte