2
respostas

[Bug] PHP não recebe os dados do formulário HTML e do input checkbox

Estou com uma aplicação PHP (versão 8.1) que lista, cadastra e também deleta múltiplos produtos. O problema é que a remoção dos produtos não está funcionando, pois o form não é enviado ao PHP (não chega na superglobal $_POST ou $_REQUEST). O que estou tentando fazer é que o id dos produtos seja enviado ao PHP para ser tratado no controller para fazer a remoção em massa dos produtos selecionados. O que acontece é que quando faço o submit do form, o log do php -S mostra que fez uma request, com o código 302. Daí nenhum dado é enviado.

Olhando na aba Network do navegador lá no Inspecionar Elemento, o payload mostra que até consegue selecionar os ids dos respectivos inputs checkbox, porém não são enviados ao PHP.

<?php
  $this->layout('layout');
?><header class="bg-dark">
    <nav class="navbar">
      <h1 id="page_name"><a href="/">Product List<span>.</span></a></h1>
      <ul class="navbar-nav flex-row">
        <li class="nav-item">
          <a id="product_adder" class="nav-link" href="/add-product">Add product</a>
        </li>
        <li class="nav-item">
          <button
            class="btn btn-danger"
            id="submit-button"
            form="delete_form"
            >
            Mass Delete
          </button>
        </li>
      </ul>
    </nav>
  </header>

<main>
  <form action="" id="delete_form" method="POST" enctype="multipart/form-data">
    <div class="row w-100 mx-0 justify-content-center">
      <?php foreach($productList as $product): ?>
        <div class="card mx-2 mt-3" style="width: 18rem;">
          <div class="card-body mt">
            <input type="checkbox" name="deleteId[]" value=<?= $product['id'];?> >
            <ul class="list-group list-group-flush">
              <li class="list-group-item text-center"><?= $product['sku']; ?></li>
              <li class="list-group-item text-center"><?= $product['name']; ?></li>
              <li class="list-group-item text-center"><?= $product['price']; ?></li>
              <li class="list-group-item text-center"><?= $product['attribute']; ?></li>
            </ul>
          </div>
        </div>
      <?php endforeach; ?>
    </div>
  </form>
</main>

routes.php:

<?php

use App\Product\Controller\{
  ListProductController,
  ProductFormController,
  NewProductController,
  DeleteProductController,
};

return [
  'GET|/' => ListProductController::class,
  'GET|/add-product' => ProductFormController::class,
  'POST|/add-product' => NewProductController::class,
  'POST|/delete' => DeleteProductController::class,
];

index.php:

<?php

require_once __DIR__ . '/../vendor/autoload.php';

$config = require_once __DIR__ . '/../credentials.php';

$routes = require_once __DIR__ . '/../config/routes.php';

/** @var \Psr\Container\ContainerInterface $diContainer */

$diContainer = require_once __DIR__ . '/../config/dependencies.php';

$pathInfo = $_SERVER['PATH_INFO'] ?? '/';
$httpMethod = $_SERVER['REQUEST_METHOD'];

var_dump($_POST);

$key = "$httpMethod|$pathInfo";

if (array_key_exists($key, $routes)) {
  $controllerClass = $routes[$key];

  $controller = $diContainer->get($controllerClass);
}

$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();

$creator = new \Nyholm\Psr7Server\ServerRequestCreator(
    $psr17Factory, // ServerRequestFactory
    $psr17Factory, // UriFactory
    $psr17Factory, // UploadedFileFactory
    $psr17Factory  // StreamFactory
);

$request = $creator->fromGlobals();

$response = $controller->handle($request);

http_response_code($response->getStatusCode());
foreach ($response->getHeaders() as $name => $values) {
    foreach ($values as $value) {
        header (sprintf('%s: %s', $name, $value), false);
    }
}

echo $response->getBody();

script.js:

$(function () {
  changeRespectiveClassFields();
  selectInputCheckboxValues();
});

function selectInputCheckboxValues() {
  $("#delete_form").submit(function (event) {
    event.preventDefault();

    const options = [];
    $("input[type='checkbox']:checked").each(function () {
      options.push($(this).val());
    });

    const optionsChecked = options;
    console.log(optionsChecked);

    $.ajax({
      url: "/delete",
      type: "POST",
      data: { deleteId: optionsChecked },
      success: function (response) {
        console.log(response);
      },
    });
  });
}

function changeRespectiveClassFields() {
  const fields = {
    dvd: "#dvd-fields",
    furniture: "#furniture-fields",
    book: "#book-fields",
  };

  $("#productType").change(function () {
    const selectedType = $(this).val();
    $(".hidden-field").val(selectedType);
    $("#dvd-fields, #furniture-fields, #book-fields").hide();
    $(fields[selectedType]).show();
  });
}
2 respostas

Aqui estão alguns passos que podem te ajudar:

Verifique a implementação de DeleteProductController para garantir que esteja excluindo corretamente os produtos com base nos IDs enviados.

Certifique-se de que o DeleteProductController retorne uma resposta com um código de status adequado e uma mensagem de corpo. Por exemplo, você pode retornar uma resposta JSON com uma mensagem de sucesso ou erro.

Verifique se o arquivo routes.php define a rota correta para a ação de exclusão. A rota deve ser definida como 'POST|/delete' => DeleteProductController::class.

Verifique se a solicitação AJAX está sendo enviada corretamente do arquivo script.js. Você pode usar instruções console.log para depurar e ver se a solicitação está sendo enviada e se está retornando algum erro.

Certifique-se de que o arquivo index.php esteja tratando adequadamente a solicitação e retornando a resposta correta. Você também pode adicionar algumas instruções console.log para depurar esse arquivo também.

Fala, Fernando. O problema é o seguinte, necessariamente:

  • Os ids não estão nem chegando no controller, esse que é o problema. O id tem que chegar por meio da superglobal $_REQUEST ou $_POST;
  • Somente a operação de deletar não funciona. A listagem e a criação de produtos funcionam normalmente;
  • Sim, ao que parece, vai para a rota correta. O log do php -S dá em 'POST|/delete'. O problema é que está indo como uma requisição em código 302;
  • A requisição AJAX parece estar sendo corretamente enviada sim. Na aba network consta no request body/payload os ids dos inputs selecionados;
  • O index.php está em pleno funcionamento, pois funciona nas outras rotas de criar e listar. O que está puxando um pouco é essa questão de deletar, pois o <form> parece não estar enviando os dados corretamente.

Alguns prints da request no browser:

Dados da requisição

Payload da requisição