Fundamentos do PHP

0/25 aulas0%
projeto

Projeto Final: Gerenciador de Tarefas - Estrutura e Listagem

Aprenda sobre projeto final: gerenciador de tarefas - estrutura e listagem

90 min
Aula 4 de 5

Projeto Final: Gerenciador de Tarefas - Estrutura e Listagem

Olá, futuro dev PHP! 👋 Chegamos ao módulo final do nosso curso, onde todo o conhecimento adquirido será posto em prática. Prepare-se para construir seu primeiro projeto completo: um Gerenciador de Tarefas! 🚀

Nesta aula, focaremos nos pilares iniciais do projeto: a estrutura de diretórios e a listagem de tarefas a partir de um banco de dados. Vamos aplicar as melhores práticas de organização e persistência de dados que aprendemos.


1. Introdução ao Projeto Final: Gerenciador de Tarefas

O Gerenciador de Tarefas será uma aplicação web simples, mas funcional, que permitirá aos usuários:

  • ✅ Adicionar novas tarefas
  • 📝 Visualizar todas as tarefas
  • ✏️ Editar tarefas existentes
  • 🗑️ Excluir tarefas
  • 🔄 Marcar tarefas como concluídas/pendentes

Nesta primeira etapa, nosso objetivo é:

  1. Definir uma estrutura de projeto organizada.
  2. Configurar a conexão com o banco de dados (MySQL/MariaDB).
  3. Criar a tabela de tarefas no banco de dados.
  4. Implementar a lógica para listar todas as tarefas existentes.

Vamos garantir que desde o início, nosso código seja limpo, modular e fácil de manter.


2. Estrutura do Projeto e Persistência de Dados

2.1. Estrutura de Diretórios 🌳

Uma boa estrutura de projeto é crucial para a manutenibilidade e escalabilidade. Vamos adotar uma estrutura comum em projetos PHP, separando as preocupações:

  • public/: Contém o ponto de entrada da aplicação (index.php) e todos os arquivos acessíveis diretamente pelo navegador (CSS, JS, imagens).
  • src/: Onde fica a lógica principal da sua aplicação (classes, funções, modelos).
    • src/Repository/: Classes responsáveis pela interação com o banco de dados (CRUD).
    • src/Model/: Classes que representam as entidades do seu domínio (ex: Task).
  • config/: Arquivos de configuração (banco de dados, variáveis de ambiente).
  • views/: Arquivos de template (HTML com PHP) que exibem a interface do usuário.
  • database/: Scripts SQL para criação do banco de dados e tabelas.
  • vendor/: (Opcional, mas recomendado) Se você usar Composer, é onde as dependências serão instaladas.
.
├── public/
│   └── index.php
│   └── css/
│       └── style.css
├── src/
│   ├── Model/
│   │   └── Task.php
│   └── Repository/
│       └── TaskRepository.php
├── config/
│   └── database.php
├── views/
│   └── tasks/
│       └── list.php
│   └── partials/
│       └── header.php
│       └── footer.php
├── database/
│   └── schema.sql
└── .env (ou similar para variáveis de ambiente)

2.2. Configuração do Banco de Dados 💾

Para persistir nossas tarefas, utilizaremos um banco de dados relacional. MySQL ou MariaDB são excelentes escolhas.

2.2.1. Criação da Tabela tasks

Primeiro, vamos definir a estrutura da nossa tabela tasks. Crie um arquivo database/schema.sql com o seguinte conteúdo:

-- database/schema.sql
 
CREATE DATABASE IF NOT EXISTS task_manager_db;
 
USE task_manager_db;
 
CREATE TABLE IF NOT EXISTS tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    description VARCHAR(255) NOT NULL,
    completed BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
 
-- Inserir algumas tarefas de exemplo (opcional)
INSERT INTO tasks (description, completed) VALUES
('Estudar PHP para o projeto final', FALSE),
('Comprar pão', TRUE),
('Fazer exercícios físicos', FALSE);

Você pode executar este script usando um cliente MySQL/MariaDB (como phpMyAdmin, MySQL Workbench ou via terminal):

mysql -u seu_usuario -p < database/schema.sql

2.2.2. Conexão com o Banco de Dados (PDO)

O PHP Data Objects (PDO) é a extensão oficial e recomendada para acessar bancos de dados em PHP. Ele oferece uma interface consistente para diferentes tipos de bancos de dados e recursos de segurança importantes, como prepared statements.

Crie o arquivo config/database.php:

<?php
// config/database.php
 
// Variáveis de ambiente para conexão com o banco de dados
// Em um ambiente de produção, estas deveriam vir de variáveis de ambiente
// ou um arquivo .env, e NUNCA hardcoded no código.
$host = 'localhost';
$db   = 'task_manager_db';
$user = 'root'; // Altere para seu usuário do banco de dados
$pass = '';     // Altere para sua senha do banco de dados
$charset = 'utf8mb4';
 
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Lança exceções em caso de erros
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // Retorna resultados como arrays associativos
    PDO::ATTR_EMULATE_PREPARES   => false,                  // Desabilita emulação de prepared statements para segurança
];
 
try {
    $pdo = new PDO($dsn, $user, $pass, $options);
    // echo "Conexão com o banco de dados estabelecida com sucesso!"; // Apenas para teste
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int)$e->getCode());
}

Documentação Oficial: Para mais detalhes sobre PDO, consulte a documentação oficial do PHP.

2.3. Model e Repository para Tarefas 🧩

Vamos criar classes para organizar a lógica de negócio e a interação com o banco de dados.

2.3.1. src/Model/Task.php (Opcional, mas recomendado para projetos maiores)

Para este projeto inicial, podemos até pular a classe Model para simplificar, mas é uma boa prática tê-la. Ela representaria uma única tarefa.

<?php
// src/Model/Task.php
 
namespace App\Model;
 
class Task
{
    public ?int $id;
    public string $description;
    public bool $completed;
    public string $createdAt;
 
    public function __construct(
        ?int $id,
        string $description,
        bool $completed = false,
        ?string $createdAt = null
    ) {
        $this->id = $id;
        $this->description = $description;
        $this->completed = $completed;
        $this->createdAt = $createdAt ?? date('Y-m-d H:i:s');
    }
 
    // Métodos getters e setters (opcional, mas boa prática)
    public function getId(): ?int { return $this->id; }
    public function getDescription(): string { return $this->description; }
    public function isCompleted(): bool { return $this->completed; }
    public function getCreatedAt(): string { return $this->createdAt; }
 
    public function setDescription(string $description): void { $this->description = $description; }
    public function setCompleted(bool $completed): void { $this->completed = $completed; }
}

2.3.2. src/Repository/TaskRepository.php

Esta classe será responsável por todas as operações de banco de dados relacionadas às tarefas.

<?php
// src/Repository/TaskRepository.php
 
namespace App\Repository;
 
use PDO;
use App\Model\Task; // Se você criou a classe Task
 
class TaskRepository
{
    private PDO $pdo;
 
    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }
 
    /**
     * Retorna todas as tarefas do banco de dados.
     * @return array<Task> Um array de objetos Task.
     */
    public function findAll(): array
    {
        $stmt = $this->pdo->query('SELECT id, description, completed, created_at FROM tasks ORDER BY created_at DESC');
        $tasksData = $stmt->fetchAll(PDO::FETCH_ASSOC);
 
        $tasks = [];
        foreach ($tasksData as $data) {
            $tasks[] = new Task(
                $data['id'],
                $data['description'],
                (bool)$data['completed'],
                $data['created_at']
            );
        }
        return $tasks;
    }
 
    // Outros métodos como findById, save, update, delete serão adicionados depois
}

2.4. Ponto de Entrada da Aplicação e Listagem (index.php) 🌐

O arquivo public/index.php será o "controlador" principal, que orquestra a lógica e a exibição.

<?php
// public/index.php
 
// Autoload de classes (se estiver usando Composer)
// require __DIR__ . '/../vendor/autoload.php';
 
// Incluir manualmente as classes por enquanto (sem Composer)
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../src/Model/Task.php';
require_once __DIR__ . '/../src/Repository/TaskRepository.php';
 
use App\Repository\TaskRepository;
 
// 1. Instanciar o repositório de tarefas, passando a conexão PDO
$taskRepository = new TaskRepository($pdo);
 
// 2. Obter todas as tarefas do banco de dados
$tasks = $taskRepository->findAll();
 
// 3. Incluir a view para exibir as tarefas
include __DIR__ . '/../views/tasks/list.php';

2.5. View para Exibição das Tarefas (list.php) 🖼️

A view é responsável apenas por exibir os dados. Ela deve conter o mínimo de lógica PHP possível.

Crie o arquivo views/tasks/list.php:

<!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="/css/style.css">
</head>
<body>
    <div class="container">
        <h1>Minhas Tarefas 📝</h1>
 
        <div class="task-list">
            <?php if (empty($tasks)): ?>
                <p>Nenhuma tarefa encontrada. Que tal adicionar uma?</p>
            <?php else: ?>
                <ul>
                    <?php foreach ($tasks as $task): ?>
                        <li class="<?= $task->isCompleted() ? 'completed' : '' ?>">
                            <span><?= htmlspecialchars($task->getDescription()) ?></span>
                            <div class="actions">
                                <a href="?action=toggle&id=<?= $task->getId() ?>" class="btn-action toggle">
                                    <?= $task->isCompleted() ? 'Marcar como Pendente' : 'Marcar como Concluída' ?>
                                </a>
                                <a href="?action=edit&id=<?= $task->getId() ?>" class="btn-action edit">Editar</a>
                                <a href="?action=delete&id=<?= $task->getId() ?>" class="btn-action delete">Excluir</a>
                            </div>
                        </li>
                    <?php endforeach; ?>
                </ul>
            <?php endif; ?>
        </div>
 
        <div class="add-task">
            <!-- Formulário para adicionar tarefas virá na próxima aula -->
            <a href="?action=add" class="btn-add">Adicionar Nova Tarefa</a>
        </div>
    </div>
</body>
</html>

Adicione um estilo básico em public/css/style.css:

/* public/css/style.css */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 20px;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    min-height: 100vh;
}
 
.container {
    background-color: #fff;
    padding: 30px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    width: 100%;
    max-width: 600px;
}
 
h1 {
    text-align: center;
    color: #333;
    margin-bottom: 30px;
}
 
.task-list ul {
    list-style: none;
    padding: 0;
}
 
.task-list li {
    background-color: #f9f9f9;
    border: 1px solid #ddd;
    border-radius: 5px;
    padding: 15px;
    margin-bottom: 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
 
.task-list li.completed {
    background-color: #e6ffe6;
    text-decoration: line-through;
    color: #888;
}
 
.task-list li span {
    flex-grow: 1;
    margin-right: 10px;
}
 
.actions a {
    text-decoration: none;
    padding: 5px 10px;
    border-radius: 4px;
    font-size: 0.9em;
    margin-left: 5px;
    white-space: nowrap; /* Evita quebra de linha em botões */
}
 
.actions .toggle { background-color: #007bff; color: white; }
.actions .edit { background-color: #ffc107; color: #333; }
.actions .delete { background-color: #dc3545; color: white; }
 
.btn-add {
    display: block;
    width: fit-content;
    margin: 20px auto 0;
    padding: 10px 20px;
    background-color: #28a745;
    color: white;
    text-decoration: none;
    border-radius: 5px;
    text-align: center;
}
 
.btn-add:hover, .actions a:hover {
    opacity: 0.9;
}

3. Exercícios/Desafios 🚀

É hora de colocar a mão na massa e construir o esqueleto do seu Gerenciador de Tarefas!

Checklist de Tarefas:

  • Crie a estrutura de diretórios conforme o exemplo (public, src, config, views, database).
  • Crie o banco de dados task_manager_db e a tabela tasks executando o script database/schema.sql.
  • Configure a conexão PDO no arquivo config/database.php, ajustando user e pass se necessário. Teste a conexão (pode descomentar o echo para verificar).
  • Crie a classe Task em src/Model/Task.php.
  • Crie a classe TaskRepository em src/Repository/TaskRepository.php com o método findAll().
  • Crie o arquivo public/index.php para ser o ponto de entrada da aplicação, usando TaskRepository para buscar as tarefas.
  • Crie o arquivo views/tasks/list.php para exibir as tarefas em uma lista HTML.
  • Crie o arquivo public/css/style.css com o estilo básico fornecido.
  • Acesse http://localhost/seu_projeto/public/index.php (ou a URL configurada para seu servidor web) no navegador e verifique se as tarefas de exemplo são listadas corretamente.

Dica: Se estiver usando o servidor embutido do PHP, você pode iniciá-lo na pasta public: php -S localhost:8000 -t public E então acessar http://localhost:8000/index.php


4. Resumo e Próximos Passos 🚦

Nesta aula, você deu os primeiros e cruciais passos no desenvolvimento do seu Gerenciador de Tarefas. Você aprendeu a:

  • Organizar um projeto PHP com uma estrutura de diretórios clara.
  • Conectar-se a um banco de dados MySQL/MariaDB usando PDO, a prática recomendada.
  • Criar uma tabela no banco de dados para armazenar suas tarefas.
  • Implementar um Repository para abstrair a lógica de acesso a dados.
  • Exibir dados do banco de dados em uma página web, separando a lógica da apresentação.

Na próxima aula, vamos expandir nosso Gerenciador de Tarefas, adicionando a funcionalidade de criar novas tarefas e persistí-las no banco de dados! Fique ligado! ✨

© 2025 Escola All Dev. Todos os direitos reservados.