Fundamentos do PHP

0/25 aulas0%
projeto

Projeto Final: Gerenciador de Tarefas - Adicionar, Editar e Excluir

Aprenda sobre projeto final: gerenciador de tarefas - adicionar, editar e excluir

90 min
Aula 5 de 5

Projeto Final: Gerenciador de Tarefas - Adicionar, Editar e Excluir

Bem-vindos à sua aula final do módulo de persistência de dados! 🥳 Nesta aula prática, você aplicará todo o conhecimento adquirido para construir um sistema completo de gerenciamento de tarefas. Este projeto não apenas consolidará seu aprendizado sobre PHP e bancos de dados, mas também servirá como uma base sólida para projetos futuros.

🚀 Introdução

O objetivo deste projeto final é desenvolver um Gerenciador de Tarefas simples, mas funcional, utilizando PHP e um banco de dados (SQLite, pela sua simplicidade e portabilidade). Você implementará as operações CRUD (Create, Read, Update, Delete), que são o coração de quase toda aplicação web.

Objetivos de Aprendizagem:

  • Compreender e aplicar o ciclo de vida completo de uma aplicação web baseada em PHP.
  • Dominar as operações CRUD com PDO para interagir com um banco de dados.
  • Implementar formulários HTML para entrada de dados e processamento com PHP.
  • Aplicar boas práticas de segurança, como Prepared Statements, para prevenir SQL Injection.
  • Estruturar um projeto PHP de forma organizada.
  • Realizar validação básica de dados e tratamento de erros.

Tecnologias Utilizadas:

  • PHP: Linguagem de programação backend.
  • PDO (PHP Data Objects): Extensão para acesso a banco de dados.
  • SQLite: Banco de dados leve e baseado em arquivo (alternativamente, você pode usar MySQL/MariaDB).
  • HTML: Para a estrutura da interface do usuário.
  • CSS (básico): Para uma estilização mínima.

🛠️ Configuração do Ambiente e Banco de Dados

Antes de codificar, precisamos configurar nosso ambiente e o banco de dados.

1. Pré-requisitos

Certifique-se de ter:

  • Um servidor web (Apache ou Nginx) com PHP instalado e configurado.
  • PHP 7.4+ (ou superior).
  • A extensão pdo_sqlite (ou pdo_mysql se for usar MySQL) habilitada no seu php.ini.

2. Estrutura do Projeto

Vamos criar uma estrutura de pastas simples para organizar nosso código:

task-manager/
├── public/
│   ├── index.php         // Página principal que lista as tarefas
│   ├── add.php           // Processa a adição de tarefas
│   ├── edit.php          // Processa a edição de tarefas
│   ├── delete.php        // Processa a exclusão de tarefas
│   └── style.css         // Estilos básicos
├── app/
│   └── database.php      // Conexão com o banco de dados
└── db/
    └── tasks.sqlite      // O arquivo do banco de dados SQLite

3. Criação do Banco de Dados e Tabela

Nosso banco de dados será um arquivo SQLite. O PHP pode criar esse arquivo se ele não existir.

app/database.php

Este arquivo será responsável por estabelecer a conexão com o banco de dados e criar a tabela tasks se ela ainda não existir.

<?php
 
// Define o caminho para o arquivo do banco de dados SQLite
define('DB_PATH', __DIR__ . '/../db/tasks.sqlite');
 
try {
    // Cria a conexão PDO
    // Se o arquivo não existir, o SQLite o criará.
    $pdo = new PDO('sqlite:' . DB_PATH);
 
    // Configura o PDO para lançar exceções em caso de erros
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    // Configura o PDO para retornar resultados como objetos (ou array associativo, se preferir PDO::FETCH_ASSOC)
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
 
    // Cria a tabela 'tasks' se ela não existir
    $pdo->exec("
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title VARCHAR(255) NOT NULL,
            description TEXT,
            due_date DATE,
            completed BOOLEAN DEFAULT 0,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        );
    ");
 
    // echo "Conexão com o banco de dados estabelecida e tabela 'tasks' verificada/criada com sucesso!";
 
} catch (PDOException $e) {
    // Em um ambiente de produção, você registraria o erro em um log
    // e mostraria uma mensagem genérica ao usuário.
    die("Erro de conexão com o banco de dados: " . $e->getMessage());
}

Explicação:

  • define('DB_PATH', __DIR__ . '/../db/tasks.sqlite');: Define o caminho absoluto para o arquivo do banco de dados.
  • new PDO('sqlite:' . DB_PATH);: Instancia um objeto PDO, conectando ao SQLite.
  • $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);: Essencial para depuração e tratamento de erros. Faz com que o PDO lance PDOException em caso de erro, o que podemos capturar com um bloco try-catch.
  • $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);: Define que, por padrão, os resultados das consultas serão retornados como objetos anônimos, facilitando o acesso às propriedades ($task->title).
  • $pdo->exec(...): Executa uma instrução SQL que não retorna resultados (como CREATE TABLE, INSERT, UPDATE, DELETE).

➕ Adicionar Tarefas (Create)

Vamos criar um formulário para que o usuário possa adicionar novas tarefas.

1. Formulário HTML (public/index.php - parte inicial)

O formulário de adição pode ficar na página principal ou em uma página separada. Para este projeto, vamos mantê-lo na index.php para simplicidade.

<?php
require_once '../app/database.php'; // Inclui o arquivo de conexão com o DB
 
// Lógica para adicionar tarefa será aqui, depois do require_once
// ...
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Gerenciador de Tarefas</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>Gerenciador de Tarefas</h1>
 
        <div class="add-task">
            <h2>Adicionar Nova Tarefa</h2>
            <form action="add.php" method="POST">
                <label for="title">Título:</label>
                <input type="text" id="title" name="title" required>
 
                <label for="description">Descrição:</label>
                <textarea id="description" name="description"></textarea>
 
                <label for="due_date">Data de Vencimento:</label>
                <input type="date" id="due_date" name="due_date">
 
                <button type="submit">Adicionar Tarefa</button>
            </form>
        </div>
 
        <hr>
 
        <h2>Minhas Tarefas</h2>
        <div class="task-list">
            <?php
            // Lógica para listar tarefas virá aqui
            // ...
            ?>
        </div>
    </div>
</body>
</html>

2. Processamento da Adição (public/add.php)

Este arquivo receberá os dados do formulário e os inserirá no banco de dados.

<?php
require_once '../app/database.php';
 
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = trim($_POST['title'] ?? '');
    $description = trim($_POST['description'] ?? '');
    $dueDate = $_POST['due_date'] ?? null;
 
    // Validação básica
    if (empty($title)) {
        echo "<p style='color: red;'>O título da tarefa é obrigatório!</p>";
        // Em um projeto real, você redirecionaria com uma mensagem de erro na sessão.
        exit;
    }
 
    try {
        // Prepara a query SQL com placeholders para segurança (Prepared Statements)
        $stmt = $pdo->prepare("INSERT INTO tasks (title, description, due_date) VALUES (:title, :description, :due_date)");
 
        // Bind dos parâmetros
        $stmt->bindParam(':title', $title);
        $stmt->bindParam(':description', $description);
        $stmt->bindParam(':due_date', $dueDate);
 
        // Executa a query
        $stmt->execute();
 
        // Redireciona de volta para a página principal após a inserção
        header('Location: index.php');
        exit;
 
    } catch (PDOException $e) {
        echo "<p style='color: red;'>Erro ao adicionar tarefa: " . $e->getMessage() . "</p>";
        // Log do erro
    }
} else {
    // Se a requisição não for POST, redireciona para a página principal
    header('Location: index.php');
    exit;
}

Explicação:

  • $_SERVER['REQUEST_METHOD'] === 'POST': Verifica se a requisição foi feita via método POST (envio de formulário).
  • trim($_POST['title'] ?? '');: Pega o valor do campo title, remove espaços em branco extras e usa o operador ?? (null coalescing) para evitar erros se a chave não existir.
  • Validação: if (empty($title)): Uma validação mínima para garantir que o título não esteja vazio.
  • $stmt = $pdo->prepare(...): Prepara a query SQL. Os :title, :description, :due_date são placeholders nomeados. Esta é uma prática de segurança essencial para prevenir SQL Injection.
  • $stmt->bindParam(...): Associa os valores das variáveis PHP aos placeholders na query preparada.
  • $stmt->execute(): Executa a query preparada com os valores vinculados.
  • header('Location: index.php'); exit;: Redireciona o navegador para a index.php após a operação bem-sucedida. O exit; é crucial para garantir que nenhum código adicional seja executado após o redirecionamento.

📋 Listar Tarefas (Read)

Agora, vamos exibir as tarefas cadastradas na página principal.

public/index.php (continuação)

Adicione a lógica de listagem de tarefas na seção div class="task-list" da index.php:

<?php
// ... (código anterior da index.php) ...
 
// Lógica para listar tarefas
try {
    $stmt = $pdo->query("SELECT id, title, description, due_date, completed FROM tasks ORDER BY created_at DESC");
    $tasks = $stmt->fetchAll(); // Pega todas as tarefas como objetos
} catch (PDOException $e) {
    echo "<p style='color: red;'>Erro ao carregar tarefas: " . $e->getMessage() . "</p>";
    $tasks = []; // Garante que $tasks seja um array mesmo em caso de erro
}
 
// ... (HTML anterior) ...
?>
        <hr>
 
        <h2>Minhas Tarefas</h2>
        <div class="task-list">
            <?php if (empty($tasks)): ?>
                <p>Nenhuma tarefa cadastrada ainda. Que tal adicionar uma?</p>
            <?php else: ?>
                <?php foreach ($tasks as $task): ?>
                    <div class="task-item <?= $task->completed ? 'completed' : '' ?>">
                        <h3><?= htmlspecialchars($task->title) ?></h3>
                        <?php if (!empty($task->description)): ?>
                            <p><?= nl2br(htmlspecialchars($task->description)) ?></p>
                        <?php endif; ?>
                        <?php if (!empty($task->due_date)): ?>
                            <p>Vencimento: <?= htmlspecialchars(date('d/m/Y', strtotime($task->due_date))) ?></p>
                        <?php endif; ?>
                        <div class="task-actions">
                            <a href="edit.php?id=<?= $task->id ?>" class="button edit">Editar</a>
                            <a href="delete.php?id=<?= $task->id ?>" class="button delete" onclick="return confirm('Tem certeza que deseja excluir esta tarefa?');">Excluir</a>
                            <!-- Adicionar botão para marcar como concluída/não concluída (desafio) -->
                        </div>
                    </div>
                <?php endforeach; ?>
            <?php endif; ?>
        </div>
    </div>
</body>
</html>

Explicação:

  • $stmt = $pdo->query(...): Para consultas SELECT simples que não precisam de parâmetros dinâmicos, query() pode ser usado. No entanto, para maior consistência e segurança, prepare() e execute() são sempre recomendados, mesmo para SELECT sem parâmetros externos.
  • $tasks = $stmt->fetchAll();: Recupera todas as linhas do conjunto de resultados como um array de objetos (devido ao PDO::FETCH_OBJ configurado).
  • foreach ($tasks as $task):: Itera sobre cada tarefa e exibe seus detalhes.
  • <?= htmlspecialchars($task->title) ?>: IMPORTANTE! Use htmlspecialchars() sempre que exibir dados vindos do banco de dados (ou de entrada do usuário) em HTML para prevenir ataques de Cross-Site Scripting (XSS).
  • nl2br(): Converte quebras de linha (\n) em <br> tags HTML para exibir descrições formatadas.
  • href="edit.php?id=<?= $task->id ?>": Cria links para as páginas de edição e exclusão, passando o id da tarefa via URL (GET parameter).

✏️ Editar Tarefas (Update)

A edição de tarefas envolve duas etapas:

  1. Exibir um formulário pré-preenchido com os dados da tarefa a ser editada.
  2. Processar o envio do formulário para atualizar os dados no banco.

public/edit.php

<?php
require_once '../app/database.php';
 
$taskId = $_GET['id'] ?? null;
$task = null;
$errorMessage = '';
 
// 1. Carregar a tarefa para preencher o formulário
if ($taskId) {
    try {
        $stmt = $pdo->prepare("SELECT id, title, description, due_date, completed FROM tasks WHERE id = :id");
        $stmt->bindParam(':id', $taskId, PDO::PARAM_INT);
        $stmt->execute();
        $task = $stmt->fetch(); // Pega apenas uma tarefa
        
        if (!$task) {
            $errorMessage = "Tarefa não encontrada.";
        }
    } catch (PDOException $e) {
        $errorMessage = "Erro ao carregar tarefa: " . $e->getMessage();
    }
} else {
    $errorMessage = "ID da tarefa não fornecido.";
}
 
// 2. Processar o formulário de edição
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $taskId) {
    $title = trim($_POST['title'] ?? '');
    $description = trim($_POST['description'] ?? '');
    $dueDate = $_POST['due_date'] ?? null;
    $completed = isset($_POST['completed']) ? 1 : 0; // Checkbox value
 
    if (empty($title)) {
        $errorMessage = "O título da tarefa é obrigatório!";
    } else {
        try {
            $stmt = $pdo->prepare("UPDATE tasks SET title = :title, description = :description, due_date = :due_date, completed = :completed WHERE id = :id");
            $stmt->bindParam(':title', $title);
            $stmt->bindParam(':description', $description);
            $stmt->bindParam(':due_date', $dueDate);
            $stmt->bindParam(':completed', $completed, PDO::PARAM_INT);
            $stmt->bindParam(':id', $taskId, PDO::PARAM_INT);
            $stmt->execute();
 
            header('Location: index.php');
            exit;
 
        } catch (PDOException $e) {
            $errorMessage = "Erro ao atualizar tarefa: " . $e->getMessage();
        }
    }
}
 
// Se a tarefa não foi encontrada ou ID não foi fornecido e não houve POST, redireciona
if (!$task && empty($errorMessage) && $_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: index.php');
    exit;
}
 
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Editar Tarefa</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>Editar Tarefa</h1>
 
        <?php if (!empty($errorMessage)): ?>
            <p style="color: red;"><?= htmlspecialchars($errorMessage) ?></p>
            <?php if (!$task): // Se não há tarefa, não mostra o formulário ?>
                <p><a href="index.php">Voltar para a lista de tarefas</a></p>
            <?php endif; ?>
        <?php endif; ?>
 
        <?php if ($task): ?>
            <form action="edit.php?id=<?= $task->id ?>" method="POST">
                <label for="title">Título:</label>
                <input type="text" id="title" name="title" value="<?= htmlspecialchars($task->title) ?>" required>
 
                <label for="description">Descrição:</label>
                <textarea id="description" name="description"><?= htmlspecialchars($task->description) ?></textarea>
 
                <label for="due_date">Data de Vencimento:</label>
                <input type="date" id="due_date" name="due_date" value="<?= htmlspecialchars($task->due_date) ?>">
 
                <div class="checkbox-group">
                    <input type="checkbox" id="completed" name="completed" <?= $task->completed ? 'checked' : '' ?>>
                    <label for="completed">Tarefa Concluída</label>
                </div>
 
                <button type="submit">Atualizar Tarefa</button>
                <a href="index.php" class="button secondary">Cancelar</a>
            </form>
        <?php endif; ?>
    </div>
</body>
</html>

Explicação:

  • $taskId = $_GET['id'] ?? null;: Obtém o ID da tarefa da URL.
  • A primeira parte do script carrega a tarefa do banco de dados usando SELECT ... WHERE id = :id.
  • $stmt->fetch(): Recupera uma única linha do resultado.
  • value="<?= htmlspecialchars($task->title) ?>": Os campos do formulário são pré-preenchidos com os dados existentes da tarefa.
  • <?= $task->completed ? 'checked' : '' ?>: Marca o checkbox "Tarefa Concluída" se completed for 1.
  • A segunda parte do script (if ($_SERVER['REQUEST_METHOD'] === 'POST' ...) processa o envio do formulário, atualizando os dados com um UPDATE ... WHERE id = :id.
  • PDO::PARAM_INT: É uma boa prática especificar o tipo de dado para bindParam para IDs inteiros.

🗑️ Excluir Tarefas (Delete)

A exclusão é a operação CRUD mais simples, mas deve ser feita com cautela.

public/delete.php

<?php
require_once '../app/database.php';
 
$taskId = $_GET['id'] ?? null;
 
if ($taskId) {
    try {
        // Prepara a query de exclusão
        $stmt = $pdo->prepare("DELETE FROM tasks WHERE id = :id");
        $stmt->bindParam(':id', $taskId, PDO::PARAM_INT);
        $stmt->execute();
 
        // Redireciona de volta para a página principal
        header('Location: index.php');
        exit;
 
    } catch (PDOException $e) {
        echo "<p style='color: red;'>Erro ao excluir tarefa: " . $e->getMessage() . "</p>";
        // Em um ambiente real, você logaria o erro e redirecionaria com uma mensagem amigável.
    }
} else {
    echo "<p style='color: red;'>ID da tarefa não fornecido para exclusão.</p>";
}
 
// Se não houve redirecionamento por algum motivo, garante que o usuário volte
echo '<p><a href="index.php">Voltar para a lista de tarefas</a></p>';

Explicação:

  • Obtém o id da tarefa a ser excluída da URL.
  • Utiliza um DELETE FROM tasks WHERE id = :id com Prepared Statements para segurança.
  • Redireciona para a index.php após a exclusão bem-sucedida.
  • A confirmação via onclick="return confirm('...');" no link da index.php é uma medida simples de segurança para evitar exclusões acidentais.

🧩 Integração e Boas Práticas

Estrutura de Pastas e Separação de Responsabilidades

  • public/: Contém todos os arquivos acessíveis diretamente pelo navegador (HTML, CSS, JS, e os scripts PHP que interagem com o usuário). É a "raiz" do seu site.
  • app/: Contém a lógica de negócio e arquivos de configuração que NÃO devem ser acessados diretamente pelo navegador (como database.php).
  • db/: Armazena o arquivo do banco de dados SQLite.

Manter essa separação (conhecida como "Document Root Protection" ou "Front Controller Pattern" em frameworks) é uma boa prática de segurança.

Tratamento de Erros e Depuração

  • PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION: Permite que o PDO lance exceções em caso de erro, que podem ser capturadas por blocos try-catch. Isso é muito melhor do que o modo padrão que apenas retorna false.
  • error_reporting(E_ALL); ini_set('display_errors', 1);: Em desenvolvimento, use estas linhas no topo dos seus scripts (ou no php.ini) para ver todos os erros. Em produção, desabilite display_errors e configure o log de erros.

Prevenção de SQL Injection

  • Prepared Statements (PDO prepare() e execute()): Você usou isso em todas as operações CRUD. É a maneira mais eficaz de prevenir SQL Injection, pois separa a lógica SQL dos dados, garantindo que os dados sejam tratados como valores, e não como parte da instrução SQL.

Redirecionamentos

  • header('Location: ...'); exit;: Sempre use exit; após um header('Location: ...'); para garantir que o script pare de executar imediatamente e o redirecionamento ocorra.

Validação de Entrada

  • Você implementou validação básica (empty(), trim()). Para um projeto real, você usaria validação mais robusta (tamanho máximo, tipo de dados, formatos específicos como e-mail ou data).

public/style.css (Exemplo básico)

body {
    font-family: sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 20px;
    background-color: #f4f4f4;
    color: #333;
}
 
.container {
    max-width: 800px;
    margin: 20px auto;
    background: #fff;
    padding: 30px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
 
h1, h2 {
    color: #0056b3;
    text-align: center;
    margin-bottom: 20px;
}
 
form {
    display: flex;
    flex-direction: column;
    gap: 15px;
    margin-bottom: 30px;
}
 
label {
    font-weight: bold;
    margin-bottom: 5px;
}
 
input[type="text"],
input[type="date"],
textarea {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 1rem;
    width: 100%;
    box-sizing: border-box; /* Garante que padding não aumente a largura total */
}
 
textarea {
    resize: vertical;
    min-height: 80px;
}
 
button[type="submit"], .button {
    background-color: #007bff;
    color: white;
    padding: 10px 15px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 1rem;
    text-decoration: none;
    text-align: center;
    display: inline-block;
    transition: background-color 0.3s ease;
}
 
button[type="submit"]:hover, .button:hover {
    background-color: #0056b3;
}
 
.button.edit {
    background-color: #ffc107;
    color: #333;
}
 
.button.edit:hover {
    background-color: #e0a800;
}
 
.button.delete {
    background-color: #dc3545;
}
 
.button.delete:hover {
    background-color: #c82333;
}
 
.button.secondary {
    background-color: #6c757d;
    margin-left: 10px;
}
 
.button.secondary:hover {
    background-color: #5a6268;
}
 
.task-list {
    display: flex;
    flex-direction: column;
    gap: 20px;
}
 
.task-item {
    background: #f9f9f9;
    border: 1px solid #eee;
    padding: 15px;
    border-radius: 6px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
 
.task-item h3 {
    margin: 0;
    color: #007bff;
}
 
.task-item p {
    margin: 0;
}
 
.task-item.completed {
    background-color: #e6ffe6; /* Fundo verde claro */
    border-color: #a3e6a3;
    opacity: 0.7;
}
 
.task-item.completed h3 {
    text-decoration: line-through;
    color: #6c757d;
}
 
.task-actions {
    display: flex;
    gap: 10px;
    margin-top: 10px;
}
 
.checkbox-group {
    display: flex;
    align-items: center;
    gap: 10px;
}

🎯 Desafios e Melhorias (Exercícios)

Este projeto é uma base. Aqui estão alguns desafios para você ir além e aprimorar suas habilidades:

Task List 📝

  • Validação de Entrada Aprimorada:
    • Verifique o comprimento mínimo e máximo para o título.
    • Garanta que a data de vencimento seja uma data válida e não seja no passado (a menos que seja permitido).
    • Exiba mensagens de erro mais amigáveis para o usuário no próprio formulário, talvez usando variáveis de sessão para persistir mensagens após redirecionamentos.
  • Marcação de Tarefas como Concluídas/Não Concluídas:
    • Adicione um botão ou checkbox na lista de tarefas para alternar o status completed (0 ou 1) sem precisar ir para a página de edição. Isso envolveria um novo script PHP (toggle_complete.php) que recebe o ID da tarefa e atualiza o status.
  • Filtros e Busca:
    • Adicione um campo de busca para filtrar tarefas por título ou descrição.
    • Adicione filtros para mostrar apenas tarefas "concluídas", "pendentes" ou "todas".
    • Isso exigirá modificações na query SELECT na index.php.
  • Paginação:
    • Se você tiver muitas tarefas, a lista pode ficar longa. Implemente paginação para exibir um número limitado de tarefas por página.
  • Mensagens Flash (Sessão):
    • Ao invés de echo mensagens de erro ou sucesso diretamente, use sessões ($_SESSION) para armazená-las e exibi-las após um redirecionamento. Exemplo: $_SESSION['success_message'] = 'Tarefa adicionada com sucesso!'; header('Location: index.php'); exit;. Na index.php, você verificaria isset($_SESSION['success_message']) e a exibiria.
  • Estilização Avançada:
    • Melhore o CSS para deixar a interface mais agradável e responsiva.
    • Considere usar um framework CSS como Bootstrap ou Tailwind CSS para acelerar o design.
  • Confirmação de Exclusão com JavaScript:
    • Em vez de onclick="return confirm(...)", implemente uma caixa de diálogo de confirmação mais amigável usando JavaScript.
  • Refatoração com Funções/Classes:
    • Para projetos maiores, você pode começar a organizar seu código em funções ou até mesmo classes para o banco de dados (TaskRepository) ou para a lógica de negócio.

📝 Resumo e Próximos Passos

Parabéns! 🎉 Você acabou de construir seu primeiro projeto CRUD completo em PHP puro. Você aplicou conceitos fundamentais de:

  • Conexão com banco de dados usando PDO.
  • Execução de operações CRUD (Create, Read, Update, Delete).
  • Interação com formulários HTML.
  • Prevenção de SQL Injection com Prepared Statements.
  • Boas práticas de organização de código e segurança básica.

Este projeto é um marco importante no seu aprendizado de PHP. A partir daqui, você pode explorar:

  1. Frameworks PHP: Laravel, Symfony, CodeIgniter, etc., que fornecem uma estrutura e ferramentas para construir aplicações maiores e mais complexas de forma mais eficiente e segura.
  2. Padrões de Projeto: MVC (Model-View-Controller) é um padrão comum em frameworks que ajuda a organizar o código.
  3. Segurança Web: Aprofundar-se em tópicos como autenticação, autorização, CSRF, XSS, etc.
  4. APIs RESTful: Construir APIs com PHP para que outras aplicações (front-ends em JavaScript, aplicativos móveis) possam interagir com seus dados.

Continue praticando, experimentando e construindo! O mundo do desenvolvimento web é vasto e cheio de oportunidades. Boa sorte! 💪

© 2025 Escola All Dev. Todos os direitos reservados.

Projeto Final: Gerenciador de Tarefas - Adicionar, Editar e Excluir - Fundamentos do PHP | escola.all.dev.br