Fundamentos do PHP
Projeto Final: Gerenciador de Tarefas - Estrutura e Listagem
Aprenda sobre projeto final: gerenciador de tarefas - estrutura e listagem
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 é:
- Definir uma estrutura de projeto organizada.
- Configurar a conexão com o banco de dados (MySQL/MariaDB).
- Criar a tabela de tarefas no banco de dados.
- 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.sql2.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_dbe a tabelatasksexecutando o scriptdatabase/schema.sql. - Configure a conexão PDO no arquivo
config/database.php, ajustandouserepassse necessário. Teste a conexão (pode descomentar oechopara verificar). - Crie a classe
Taskemsrc/Model/Task.php. - Crie a classe
TaskRepositoryemsrc/Repository/TaskRepository.phpcom o métodofindAll(). - Crie o arquivo
public/index.phppara ser o ponto de entrada da aplicação, usandoTaskRepositorypara buscar as tarefas. - Crie o arquivo
views/tasks/list.phppara exibir as tarefas em uma lista HTML. - Crie o arquivo
public/css/style.csscom 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
Repositorypara 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! ✨