Como trabalhar com array de checkboxes opcionais 2

Dando continuidade ao artigo anterior:

http://wbruno.com.br/sql/como-trabalhar-com-array-de-checkboxes-opcionais/

Screen Shot 2015-04-18 at 20.10.45

Iremos escrever enfim, os códigos para fazer esse CRUD com checkboxes.

Lembrando que o intuito do artigo não é ensinar programação orientada a objetos. Então irei deixar o script php o mais simples possível, para que você possa extrair e então montar o seu dentro da sua estrutura/framework.

Listando os opcionais do banco

A listagem dos itens é super trivial:

<?php
  $query = $mysqli->query('SELECT id, name FROM optional');
  while($row = $query->fetch_object()) {
?>
    <label>
      <input type="checkbox" name="optional[]" value="<?php echo $row->id; ?>" />
    <?php echo $row->name; ?></label>
<?php
  }
?>

Apenas conecto no MySQL com a lib mysqli e imprimo um checkbox para cada registro da tabela.

DESCRIBE TABLE optional_vehicle

Ainda não estamos preocupados com trazer os checkboxes marcados, pois precisamos entender como utilizar a tabela optional_vehicle.
Ela faz um relacionamento N:N (um veículo para N opcionais, e 1 opcional para N veículos).

Para inserir nessa tabela, precisamos mais ou menos da seguinte string sql:

INSERT INTO vehicle_optional (id_vehicle, id_optional) VALUES (42, 1),(42 2)

Nessa query acima, estamos inserindo o opcional 1 e 2 para o veículo 42.
Se quisessemos inserir mais o opcional 5, bastaria:

INSERT INTO vehicle_optional (id_vehicle, id_optional) VALUES (42, 1),(42, 2),(42, 5)

Okay ?
Fazer essa string é uma simples maniplação de array. Lembra que o name do checkbox é name=”optional[]” então, no php irá chegar um array:

$_POST['optional'][0], $_POST['optional'][1], $_POST['optional'][2]

Visto isso, vamos montar o INSERT:

  //optional insert
  $values = [];
  foreach($optionals AS $id_optional) {
    $values[] = "({$id}, {$id_optional})";
  }
  $values = implode(',', $values);

  $sql = "INSERT INTO vehicle_optional (id_vehicle, id_optional) VALUES {$values}";
  echo $sql;
  $query = $mysqli->query($sql)or die($mysqli->error);

Simples, não ? a saída do echo $sql, será a string que escrevi acima.
Comecei pelos opcionais para matar logo a sua curiosidade, mas para deixar registrado o INSERT simples do veículo tem apenas as colunas que são atributos da entidade veículo:

  $sql = "INSERT INTO vehicles (id, name, year, model) VALUES(NULL, '{$name}', '{$year}', '{$model}')";
  echo $sql, '<br /><br />';
  $query = $mysqli->query($sql)or die($mysqli->error);

  $id = $mysqli->insert_id;//ultimo id inserido no banco

Os truques

As duas queries acima são bem triviais e você já está mais do que acostumado com elas no seu dia a dia. Só existem 2 truques no server-side para essa modelagem.
O primeiro é:

Delete tudo, depois insira novamente

O comportamento do input type=”checkbox” do html é enviar para o server-side apenas os checkboxes marcados. Então aqueles que não estiverem no estado checked.

Tente imaginar a lógica de atualizar os opcionais de um carro. Ele já possui alguns cadastrados no banco. No submit do formulário você precisa remover os que não foram marcados, inserir os novos e com os que não alteraram não fazer nada. Complexo, não?

Um truque muito mais simples é remover tudo e depois inserir tudo o que vier.

DELETE FROM vehicle_optional WHERE id_vehicle = 42;
INSERT INTO vehicle_optional (id_vehicle, id_optional) VALUES (42, 1),(42, 2),(42, 5);

Marque os checkboxes

Agora precisamos marcar os checkboxes na listagem durante a edição de um registro.
O truque aqui é puramente SQL e se baseia em uma subquery.

SELECT `id`, `name`, (SELECT 'checked' FROM vehicle_optional WHERE id_vehicle = 1 AND id_optional = optional.id) AS `checked` FROM `optional`;

Pense no seguinte:
-> Temos que listar todos os opcionais
Fácil, já tinhamos feito isso.
-> E dizer quem está marcado ou não.
Aqui que entra a subquery.

(SELECT 'checked' FROM vehicle_optional WHERE id_vehicle = 1 AND id_optional = optional.id)

ela vai trazer a string ‘checked’ apelidada como a coluna `checked` AS `checked` apenas nos registros do veiculo id = 1 que tiverem marcados. o/

mysql> SELECT `id`, `name`, (SELECT 'checked' FROM vehicle_optional WHERE id_vehicle = 1 AND id_optional = optional.id) AS `checked` FROM `optional`;
+----+------------------+---------+
| id | name             | checked |
+----+------------------+---------+
|  1 | air_con          | checked |
|  2 | bluetooth        | checked |
|  3 | parking_sensors  | NULL    |
|  4 | escape_motorcyle | NULL    |
|  5 | plasma_cannon    | NULL    |
|  6 | cruise_control   | checked |
|  7 | leather          | NULL    |
|  8 | metallic_paint   | NULL    |
|  9 | electric_locks   | NULL    |
| 10 | xenon_lights     | NULL    |
| 11 | nitro            | NULL    |
| 12 | wings            | NULL    |
+----+------------------+---------+
12 rows in set (0.00 sec)

E então vamos simplesmente imprimir isso no nosso input:

<input type="checkbox" name="optional[]" value="<?php echo $row->id; ?>" <?php echo $row->checked; ?>/>

Mágica.

Código no GitHub

https://github.com/wbruno/examples/tree/gh-pages/checkboxes-opcionais

3 Comments

  1. Augusto César

    maio 10, 2015 at 12:12

    Bruno, você pode me ajudar em um script ajax que faz um carregamento por demanda? Por exemplo: Carregamento de postagens do twitter com aquele loaders. Abraço

  2. Boa tarde meu caro, muito bom o seu post. Poderia me auxiliar na construção para da melhor SQL para o seguinte cenário ?

    Recupere todos os veículos que tenham no mínimo dois opcionais “CD ROM” e “Vidro Eletrico”. Os veículos podem ter outros opcionais, mas estes seriam obrigatórios.

    Desde já grato.

    • Considerando que CD ROM é o 1, e Vidro Elétrico é o 2. Se quiser pesquiser pelo name, ai vc tem que usar mais um JOIN.

      SELECT * FROM vehicles INNER JOIN vehicle_optional ON vehicles.id = vehicle_optional.id_vehicle WHERE id_optional IN(1,2);

Deixe uma resposta

Your email address will not be published.

*