Material organizado para estudo progressivo, com leitura confortável, recursos complementares e navegação para a próxima etapa da disciplina.
Resumo
Aula 8: A última aula finalizou o projeto com a loja pública, onde os games cadastrados no painel aparecem para visitantes sem necessidade de login. Foram criadas as rotas loja e game/detalhe, os métodos públicos no GameController.php, consultas como listarParaLoja() no Game.php, views como games/loja.php e games/detalhe.php, além de um checklist final de testes para validar o funcionamento completo do GameStock 2026 V2.
Linguagens de Programação16/04/2026Aula interativa importada
Leitura pensada para estudo, consulta e revisão. Use a navegação lateral para alternar entre etapas da aula.
Estudo
Conteúdo interativo — HTML importado
Aula 8 - Loja Online e Finalização do Projeto
Abra o material em tela cheia para estudar com conforto, sem sair da disciplina.
Aula 8 - Loja Online e Finalização do Projeto
100%
Carregando conteúdo interativo...
Aula 8 — Loja Publica e Finalizacao ◀▶ 1 / 0Tela cheia A8 GameStock 2026 V2 · Aula 8 Loja pública e finalização Agora os games cadastrados no painel aparecem em uma vitrine aberta para visitantes, com busca, filtros simples, detalhe do jogo e links para login administrativo. VitrineLoja publicaBuscaDetalheFinal /loja Games em destaque CAPA Pixel Quest R$ 59,90 CAPA Cyber Kart R$ 89,90 URL Dungeon R$ 74,90 01 01·Objetivo Do painel para a loja Publicar Mostrar na loja os games cadastrados no CRUD administrativo. Buscar Permitir pesquisa por título e filtro por categoria. Detalhar Abrir uma página com descrição, preço, estoque e imagem. Finalizar Organizar links, testes e checklist do projeto. A8 FechamentoEsta aula liga tudo: banco, PDO, MVC, CRUDs, login, upload de imagem e a vitrine pública do GameStock. 02 02·Onde Fica Mapa da loja pública /GameStock2026V2 |-- app/ | |-- controllers/ | | `-- GameController.php loja(), detalhePublico() e CRUD admin | |-- models/ | | `-- Game.php listarParaLoja(), buscarPublicoPorId() | `-- views/ | `-- games/ | |-- loja.php vitrine publica | |-- detalhe.php pagina publica do game | |-- index.php lista administrativa | |-- criar.php cadastro admin | `-- editar.php edicao admin `-- public/ |-- assets/css/style.css visual da loja e painel |-- assets/js/app.js busca/filtros simples |-- assets/img/sem-capa.png imagem reserva da interface |-- uploads/games/ capas enviadas no CRUD `-- index.php rotas publicas e admin VIS VisitanteEntra em ?url=loja sem precisar estar logado. ADM AdministradorContinua acessando ?url=games após login. IMG ImagemA loja usa URL externa ou arquivo em public/uploads/games. 03 03·Ajuste Atenção ao GameController app/controllers/GameController.php - ajuste depois da Aula 7 PHPCopiar class GameController { // Publico: visitante pode acessar sem login. public function loja() { // sem exigirLogin() } public function detalhePublico() { // sem exigirLogin() } // Administrativo: precisa estar logado. public function listar() { exigirLogin(); // lista administrativa } public function criar() { exigirLogin(); } public function salvar() { exigirLogin(); } public function editar() { exigirLogin(); } public function atualizar() { exigirLogin(); } public function excluir() { exigirLogin(); } } POR QUE Mudanca necessariaNa Aula 7, proteger o controller inteiro funcionava porque tudo era painel. Agora o mesmo controller também tem telas públicas. ONDE Onde ficaEsse ajuste fica em app/controllers/GameController.php. ! CuidadoNão proteja loja() nem detalhePublico(); se proteger, visitantes cairão no login. 04 04·Rotas Rotas finais no public/index.php Rota Metodo Controller Protecao ?url=loja GET GameController::loja() publica ?url=game/detalhe&id=1 GET GameController::detalhePublico() publica ?url=auth/login GET AuthController::login() publica ?url=games GET GameController::listar() login ?url=users GET UserController::listar() admin public/index.php - novas rotas publicas PHPCopiar $url = $_GET['url'] ?? 'loja'; switch ($url) { case 'loja': (new GameController())->loja(); break; case 'game/detalhe': (new GameController())->detalhePublico(); break; case 'games': (new GameController())->listar(); break; } 05 05·Model Consultas da loja app/models/Game.php - listarParaLoja() PHPCopiar public static function listarParaLoja($busca = '', $categoria = ''): array { $sql = 'SELECT * FROM games WHERE estoque > 0'; $params = []; if ($busca !== '') { $sql .= ' AND titulo LIKE :busca'; $params[':busca'] = '%' . $busca . '%'; } if ($categoria !== '') { $sql .= ' AND categoria = :categoria'; $params[':categoria'] = $categoria; } $sql .= ' ORDER BY titulo ASC'; $stmt = self::db()->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(); } ONDE Onde ficaEste método entra em app/models/Game.php. LOJA RegraA loja mostra apenas games com estoque > 0. GET Filtros$busca e $categoria vêm da URL por formulário GET. 06 06·Detalhe Buscando um game público app/models/Game.php - buscarPublicoPorId() PHPCopiar public static function buscarPublicoPorId($id): ?array { $sql = 'SELECT * FROM games WHERE id = :id AND estoque > 0 LIMIT 1'; $stmt = self::db()->prepare($sql); $stmt->execute([ ':id' => $id ]); $game = $stmt->fetch(); return $game ?: null; } ID Onde usaEste método alimenta a rota ?url=game/detalhe&id=1. 404 Sem estoqueSe o jogo não existe ou está sem estoque, a página pública não deve exibir o produto. 07 07·Controller Métodos públicos do GameController app/controllers/GameController.php - loja() PHPCopiar public function loja() { $busca = trim($_GET['busca'] ?? ''); $categoria = trim($_GET['categoria'] ?? ''); $games = Game::listarParaLoja($busca, $categoria); view('games/loja', [ 'titulo' => 'Loja GameStock', 'games' => $games, 'busca' => $busca, 'categoria' => $categoria ]); } app/controllers/GameController.php - detalhePublico() PHPCopiar public function detalhePublico() { $id = $_GET['id'] ?? null; $game = Game::buscarPublicoPorId($id); if (!$game) { http_response_code(404); echo 'Game nao encontrado.'; return; } view('games/detalhe', [ 'titulo' => $game['titulo'], 'game' => $game ]); } 08 08·View Vitrine em games/loja.php app/views/games/loja.php - lista publica PHP/HTMLCopiar <header class="store-header"> <a href="<?= BASE_URL ?>/index.php?url=loja">GameStock</a> <a href="<?= BASE_URL ?>/index.php?url=auth/login">Entrar</a> </header> <form class="store-filter" method="get"> <input type="hidden" name="url" value="loja"> <input type="text" name="busca" value="<?= htmlspecialchars($busca ?? '') ?>" placeholder="Buscar game"> <input type="text" name="categoria" value="<?= htmlspecialchars($categoria ?? '') ?>" placeholder="Categoria"> <button>Filtrar</button> </form> <section class="game-grid"> <?php foreach ($games as $game): ?> <article class="game-card"> <img src="<?= imagemGame($game['imagem']) ?>" alt="<?= htmlspecialchars($game['titulo']) ?>"> <h2><?= htmlspecialchars($game['titulo']) ?></h2> <p><?= htmlspecialchars($game['categoria']) ?></p> <strong>R$ <?= number_format($game['preco'], 2, ',', '.') ?></strong> <a href="<?= BASE_URL ?>/index.php?url=game/detalhe&id=<?= $game['id'] ?>">Ver detalhes</a> </article> <?php endforeach; ?> </section> ONDE Onde ficaCrie este arquivo em app/views/games/loja.php. GET FiltroO formulário envia filtros pela URL, sem gravar nada no banco. ESC EscapeUse htmlspecialchars() para todo texto vindo do banco. 09 09·Detalhe Página do game em games/detalhe.php app/views/games/detalhe.php PHP/HTMLCopiar <main class="game-detail"> <img src="<?= imagemGame($game['imagem']) ?>" alt="<?= htmlspecialchars($game['titulo']) ?>"> <section> <a href="<?= BASE_URL ?>/index.php?url=loja">Voltar para loja</a> <h1><?= htmlspecialchars($game['titulo']) ?></h1> <p class="categoria"> <?= htmlspecialchars($game['categoria']) ?> </p> <p><?= nl2br(htmlspecialchars($game['descricao'])) ?></p> <strong class="preco"> R$ <?= number_format($game['preco'], 2, ',', '.') ?> </strong> <p>Estoque: <?= (int) $game['estoque'] ?> unidades</p> </section> </main> ONDE Onde ficaCrie este arquivo em app/views/games/detalhe.php. INFO O que mostrarImagem, título, categoria, descrição, preço e estoque já bastam para a vitrine simples. 10 10·Imagem Mostrando imagem externa ou upload app/config/config.php - helper imagemGame() PHPCopiar function imagemGame(?string $imagem): string { if (empty($imagem)) { return BASE_URL . '/assets/img/sem-capa.png'; } if (str_starts_with($imagem, 'http://') || str_starts_with($imagem, 'https://')) { return $imagem; } return BASE_URL . '/uploads/games/' . $imagem; } ONDE Onde ficaColoque em app/config/config.php, junto com os helpers da sessão. URL Imagem externaSe começar com http:// ou https://, usamos a URL direto. UP UploadSe for apenas nome de arquivo, buscamos em public/uploads/games. 11 11·CSS Visual da loja em style.css public/assets/css/style.css - loja publica CSSCopiar .store-header { display: flex; justify-content: space-between; align-items: center; padding: 22px 6%; border-bottom: 1px solid #dde3ec; } .store-filter { display: grid; grid-template-columns: 1fr 220px auto; gap: 12px; padding: 28px 6%; } .game-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px; padding: 0 6% 48px; } .game-card { background: #fff; border: 1px solid #dde3ec; border-radius: 8px; overflow: hidden; } .game-card img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; } ONDE Onde ficaEsse CSS entra em public/assets/css/style.css. GRID Responsivoauto-fit faz a vitrine adaptar a quantidade de cards por linha. IMG Capaaspect-ratio evita cards pulando de tamanho por causa das imagens. 12 12·JavaScript Pequeno ajuste em app.js public/assets/js/app.js - limpar busca JSCopiar const botaoLimparBusca = document.querySelector('[data-limpar-busca]'); if (botaoLimparBusca) { botaoLimparBusca.addEventListener('click', function () { window.location.href = this.dataset.urlLoja; }); } ONDE Onde ficaEsse trecho entra em public/assets/js/app.js. OPC OpcionalA loja funciona sem JavaScript, porque a busca principal usa GET. Este botão só melhora a experiência. 13 13·Links Conectando loja e painel app/views/games/loja.php - topo com painel PHP/HTMLCopiar <header class="store-header"> <a href="<?= BASE_URL ?>/index.php?url=loja">GameStock</a> <?php if (estaLogado()): ?> <a href="<?= BASE_URL ?>/index.php?url=games">Painel</a> <?php else: ?> <a href="<?= BASE_URL ?>/index.php?url=auth/login">Entrar</a> <?php endif; ?> </header> LOGADO Com sessaoSe o usuario estiver logado, o topo mostra link para o painel. VIS VisitanteSe não estiver logado, aparece o link para entrar. UX Fluxo finalO administrador consegue ir da loja para o painel e voltar para a loja. 14 14·Previa Como a loja pode ficar? /GameStock2026V2/public/index.php?url=loja GameStock LojaEntrar Vitrine publica Games disponiveis Buscar game... Categoria Filtrar CAPA Pixel Quest Aventura R$ 59,90Detalhes CAPA Cyber Kart Corrida R$ 89,90Detalhes URL Dungeon Stack RPG R$ 74,90Detalhes UI Navegador fakeEssa tela é uma referência visual para a loja. A implementação real pode usar cards parecidos. OK Elementos esperadosTopo, busca, filtro, cards, preço, imagem e botão de detalhes. RESP ResponsivoNo celular, os cards ficam empilhados por causa do grid responsivo. 15 15·Testes Checklist final do GameStock Teste Resultado esperado Abrir ?url=loja Mostra a vitrine sem login. Buscar por titulo Lista apenas games compatíveis. Clicar em detalhes Abre ?url=game/detalhe&id=... Abrir ?url=games sem login Redireciona para login. Login admin Libera CRUD de games e usuarios. Login editor Libera games, bloqueia usuarios. FINAL Projeto prontoQuando esses testes passam, o fluxo principal do curso está completo. ERRO Problema comumSe a loja pedir login, confira se exigirLogin() não ficou no __construct() inteiro do GameController. 16 16·Exercicios Prática da Aula 8 01 Crie as rotas loja e game/detalhe no public/index.php.FACIL Use GameController::loja() e GameController::detalhePublico().Ver dica 02 Implemente Game::listarParaLoja() filtrando por busca, categoria e estoque maior que zero.MEDIO Monte o SQL aos poucos e guarde os placeholders no array $params.Ver dica 03 Crie app/views/games/loja.php com cards de games e link para detalhes.MEDIO Use foreach ($games as $game) e htmlspecialchars().Ver dica 04 Finalize o CSS responsivo da vitrine e teste no celular.DESAFIO Use grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)).Ver dica FIM FIM·Resumo Resumo da Aula 8 01Criamos a vitrine pública em app/views/games/loja.php. 02Adicionamos busca, categoria e detalhe público do game. 03Ajustamos o GameController para separar loja pública e CRUD protegido. 04Reaproveitamos imagens de URL ou upload com imagemGame(). 05Fechamos o fluxo completo: visitante compra visualmente, admin cadastra, editor alimenta o estoque. Curso concluído GameStock 2026 V2