Atualização de perfil do usuário

Neste tópico, vamos entender como as camadas DAO, Controller e View se comunicam no contexto real de implementação de uma feature, exemplificado pelos arquivos "profile-update.php", "update-user.php" e "user-dao.php".

Planejamento Arquitetural do sistema

  • View: Exibirá um formulário para edição dos dados do usuário, com os dados dele já setados como value dos inputs
  • Controller: armazenará os resultados nos inputs no HTML em variáreis e passará para a camada de DAO por referência nos seus metodos
  • DAO: executará queries SQL para persistir esses dados no banco.

Na prática

Arquivo: t06-crud-php/view/profile-update.php

<?php
require_once __DIR__ . "/../dir-config.php";
require_once __DIR__ . "/../src/controllers/users/update-user.php";
//echo $id;
?>
<!DOCTYPE html>
<html lang="pt-BR">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Atualizar Perfil</title>
    <link rel="stylesheet" href="<?= BASE_URL ?>public/css/profile-update.css">
</head>

<body>
    <?php include __DIR__ . '/components/side-bar.php'; ?>  

    <div class="form-container">
        <h1>Atualize seu perfil</h1>
        <form method="POST" action="<?= BASE_URL ?>src/controllers/users/update-user.php?id=<?= $id ?>" class="form-group" enctype="multipart/form-data">
            <div class="form-wrapper">
                <div class="form-control">
                    <label for="username">Nome: </label>
                    <input type="text" name="username" value="<?= htmlspecialchars($user['username']) ?>" id="username"/>
                </div>
                <div class="form-control">
                    <label for="phone">Telefone: </label>
                    <input type="tel" name="phone" value="<?= htmlspecialchars($user['phone']) ?>" id="phone"/>
                </div>
                <div class="form-control">
                    <label for="email">Email: </label>
                    <input type="email" name="email" value="<?= htmlspecialchars($user['email']) ?>" id="email"/>
                </div>
                <div class="form-control">
                    <label for="bio">Bio: </label>
                    <input type="text" name="bio" value="<?= htmlspecialchars($user['bio'] || "") ?>" id="bio" />
                </div>
            </div>
            <div class="form-control">
                <label for="profile_pic">Foto de Perfil: </label>
                <input type="file" name="profile_pic_url" id="profile_pic_url" accept="image/*" />
            </div>
            <div class="btn-wrapper">
                <button class="btn" name="edit">Confirmar</button>
            </div>
            <div class="btn-wrapper">
                <button class="btn btn-danger" name="delete" onclick="return confirm('Tem certeza que deseja excluir sua conta? Esta ação não pode ser desfeita.');">
                    Deletar Usuário
                </button>
                <button class="btn btn-danger" name="logout" onclick="return confirm('Tem certeza que deseja sair?');">
                    Sair
                </button>
            </div>
        </form> 
    </div>
</body>

</html>
  • Exibe um formulário HTML contendo os inputs preenchidos com os dados atuais do usuário (como nome, e-mail, telefone, bio e foto de perfil).
  • Inclui o atributo enctype="multipart/form-data" para possibilitar o upload de arquivos (foto de perfil).
  • Define a ação do formulário para o controller de atualização, enviando os dados via método POST.
  • Renderiza a barra lateral e demais componentes de layout para manter a consistência visual da aplicação.

Ao enviar o formulário, os dados e o arquivo (imagem) são enviados para o update-user.php.


Arquivo: t06-crud-php/src/controllers/users/update-user.php

<?php
session_start();

require_once __DIR__ . "/../../../dir-config.php";
require_once __DIR__ . "/../../dao/user-dao.php";
require_once __DIR__ . "/../../../database.php";
require_once __DIR__ . "/../../utils/upload-handler.php";

$userDao = new UserDao();

if (!isset($_GET["id"])) {
    die("Parâmetro user_id não informado.");
}

$id = $_GET["id"];

$user = $userDao->getUserProfileById($id);

if (!$user) {
    die("Usuário não encontrado.");
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (isset($_POST['edit'])) {
        $name = trim($_POST['username']);
        $email = trim($_POST['email']);
        $phone = trim($_POST['phone']);
        $bio = trim($_POST['bio']);

        if (isset($_FILES['profile_pic_url']) && $_FILES['profile_pic_url']['error'] === UPLOAD_ERR_OK) {
            $uploadDir = __DIR__ . "/../../../uploads/avatars/";
            $allowedTypes = ['jpg', 'jpeg', 'png', 'gif'];

            $dbUpdateCallback = function ($photoUrl) use ($id, $userDao) {
                return $userDao->updateProfilePic($photoUrl, $id);
            };

            $uploadResult = UploadHandler::handleUpload($_FILES['profile_pic_url'], $uploadDir, $allowedTypes, $dbUpdateCallback);

            if (!$uploadResult['success']) {
                die($uploadResult['error']);
            }
        }

        try {
            $userDao->updateUser($name, $email, $bio, $phone, $id);
            $_SESSION['user_name'] = $name;
            header("Location: " . BASE_URL . "view/profile.php?id=$id");
            exit;
        } catch (Exception $e) {
            echo 'Erro: ' . $e->getMessage();
        }
    } else if(isset($_POST['delete'])) {
        try {
            $userDao->deleteUser($id);
            session_destroy();
            header("Location: " . BASE_URL . "view/login.php");
            exit;
        } catch (Exception $e) {
            echo 'Erro: ' . $e->getMessage();
        }
    } else if (isset($_POST['logout'])) {
        session_destroy();
        header("Location: " . BASE_URL . "view/login.php");
        exit;
    }
}

O arquivo update-user.php é responsável por:

  • Iniciar a sessão com session_start() para garantir que os dados do usuário estejam disponíveis.
  • Incluir dependências importantes, como as classes do DAO, o arquivo de configuração (dir-config.php), e o upload-handler para processar o arquivo enviado.

Fluxo do Controller:

  1. Verificação de parâmetros:

    • O controller certifica-se de que o parâmetro id (identificador do usuário a ser atualizado) está definido.
    • Recupera os dados atuais do usuário usando o método getUserProfileById do UserDao.
  2. Processamento da requisição:

    • Caso o método HTTP seja POST, o controller identifica qual ação será executada:
      • Editar o perfil (edit):

        • Extrai os dados enviados pelo formulário (nome, e-mail, telefone, bio).
        • Verifica se há um arquivo para upload (campo profile_pic_url), e em caso afirmativo, chama o upload-handler que:
          • Processa o arquivo (valida extensão, move para o diretório correto).
          • Utiliza um callback para atualizar a foto de perfil no banco de dados (por meio do método updateProfilePic do DAO).
        • Após o upload (se houver) e a validação dos dados, o controller chama o método updateUser, que executa a query SQL para atualizar o registro.
        • Atualiza variáveis de sessão (por exemplo, o nome do usuário) e redireciona para a página de perfil com um status de sucesso.
      • Deletar o usuário (delete):

        • Caso o usuário opte por excluir a conta, o controller chama o método deleteUser, destrói a sessão e redireciona para a tela de login.
      • Logout (logout):

        • Se o usuário optar por sair da aplicação, o controller encerra a sessão e redireciona para a página de login.
  3. Tratamento de erros:

    • Caso ocorra alguma exceção (por exemplo, erro de upload ou na execução de uma query SQL), o controller imprime a mensagem de erro para auxiliar na depuração.

Arquivo: t06-crud-php/src/dao/user-dao.php

    public function getUserProfileById($id)
    {
        $query = "SELECT id, username, email, phone, bio, profile_pic_url, count_followers, count_following FROM users WHERE id = :id";
        $stmt = $this->db->prepare($query);
        $stmt->execute([':id' => $id]);

        return $stmt->fetch();
    }
  • getUserProfileById($id) Recupera os dados id, username, email, phone, bio, profile_pic_url, count_followers, count_following referente ao perfil do usuário apartir do seu id.
    public function updateProfilePic($profilePicUrl, $id): bool {
        $query = "UPDATE users SET profile_pic_url = :profile_pic_url WHERE id = :id";
        $stmt = $this->db->prepare($query);
        return $stmt->execute([":profile_pic_url" => $profilePicUrl, ":id" => $id]);
    }
  • updateProfilePic($profilePicUrl, $id):
    Método específico para atualização da foto de perfil, este método recebe a url da imagem processada e executa uma query para persistir o valor no campo profile_pic_url da tabela users.
    public function updateUser($username, $email, $bio, $phone, $id): bool
    {
        $query = "UPDATE users SET username = :username, email = :email, bio = :bio, phone = :phone WHERE id = :id";
        $stmt = $this->db->prepare($query);
        $stmt->execute([":username"  => $username,":email" => $email,":bio"=> $bio,":phone" => $phone,":id"=> $id ]);
        return true;
    }
  • updateUser($username, $email, $bio, $phone, $id):
    Atualiza os dados básicos do usuário (nome, e-mail, bio, telefone) através de uma query SQL.
    public function deleteUser($id): bool
    {
        $query = "DELETE FROM users WHERE id = :id";
        $stmt = $this->db->prepare($query);
        $stmt->execute([':id' => $id]);

        return true;
    }
  • deleteUser($id):
    Remove o registro do usuário do banco, sendo ativado quando o usuário opta por excluir sua conta.