<?php
/**
* Exibe uma view com os dados informados
* @param string $view Caminho relativo da view desejada a partir de ./view/ e sem a extensao ".php"
* @param array $dados
* @return void
*/
function view(string $view, array $dados): void
{
static $viewTree = [];
$viewTree[] = $view;
$mainView = reset($viewTree);
$_file = __DIR__ . '/view/' . $view . '.php';
if (!is_file($_file)) {
throw new LogicException(sprintf('Invalid view file: %s', $_file));
}
unset($dados['_file'], $dados['viewTree'], $dados['mainView']);
extract($dados);
require($_file);
}
/**
* Redireciona o usuario para uma nova pagina
* @param string $path
*/
function redirecionar(string $path): void
{
$url = formatarLink($path);
header(sprintf('Location: %s', $url), true, 302);
}
/**
* Prepara um texto de um jogo para ser inserido no BD
* @param string $texto
* @return string
*/
function formatarTextoJogo(string $texto): string
{
return preg_replace('#<br\s*/?>#iu', "\n", $texto);
}
/**
* Formata uma mensagem de sucesso/erro
* @param string $tipo 'erro' ou 'sucesso' ou 'alerta'
* @param string $mensagem
* @return string
*/
function formatarMensagem(string $tipo, string $mensagem): string
{
$dados = [
'erro' => ['class' => 'danger', 'icon' => 'exclamation-triangle'],
'sucesso' => ['class' => 'success', 'icon' => 'check-circle'],
'alerta' => ['class' => 'warning', 'icon' => 'info-circle'],
][$tipo];
return sprintf('<div class="alert alert-%s" role="alert"><i class="fas fa-%s fa-sm"></i> %s</div>', $dados['class'], $dados['icon'], $mensagem);
}
/**
* Formata um link
* @param string $path
* @return string
*/
function formatarLink(string $path): string
{
$partes = parse_url($path);
if ($partes['path'] === '/index.php') {
$partes['path'] = '/';
} elseif (APP_REWRITE) {
$partes['path'] = preg_replace('#\.php$#u', '', $partes['path']);
}
return montarUrl($partes);
}
function ofuscarEmail(string $email): string
{
list($nome, $dominio) = explode('@', $email, 2);
return sprintf('%s@**********', $nome);
}
/**
* Monta uma url
* @param array $partes Partes vindas de parse_url
* @param array $query Array com valores para sobrescrever as query strings da url
* @return string
*/
function montarUrl(array $partes, array $query = []): string
{
if ($query) {
parse_str($partes['query'] ?? '', $queryOriginal);
$novaQuery = array_merge($queryOriginal, $query);
$partes['query'] = http_build_query($novaQuery);
}
$scheme = parse_url($_SERVER['SCRIPT_URI'], PHP_URL_SCHEME);
$port = intval($_SERVER['SERVER_PORT']);
return sprintf(
'%s://%s%s%s%s%s',
$scheme,
$_SERVER['HTTP_HOST'],
($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443) ? ':' . $port : '',
$partes['path'],
isset($partes['query']) ? sprintf('?%s', $partes['query']) : '',
isset($partes['fragment']) ? sprintf('#%s', $partes['fragment']) : '',
);
return $url;
}
/**
* Retorna um array com dados de paginacao
* @param string $path Path da URL
* @param int $total Total de itens
* @param int $quantidadePorPagina Quantidade de itens exibidos por pagina
* @param int $pagina Pagina atual
* @return array Array associativo com:
* * int 'total' - Total de itens
* * int 'atual' - Pagina atual
* * string 'primeira' - Link para primeira pagina (opcional)
* * string 'ultima' - Link para ultima pagina (opcional)
* * string 'proxima' - Link para proxima (opcional)
* * string 'anterior' - Link para anterior (opcional)
*/
function montarPaginacao(string $path, int $total, int $quantidadePorPagina, int $pagina = 1): array
{
$paginacao = [];
$partes = parse_url($path);
$paginacao['atual'] = $pagina;
$paginacao['total'] = $total;
if ($total) {
if ($pagina !== 1) {
$paginacao['primeira'] = montarUrl($partes, ['pagina' => 1]);
}
$ultima = (int) ceil($total / $quantidadePorPagina);
if ($pagina !== $ultima) {
$paginacao['ultima'] = montarUrl($partes, ['pagina' => $ultima]);
}
if ($pagina > 1) {
$paginacao['anterior'] = montarUrl($partes, ['pagina' => $pagina - 1]);
}
if ($pagina * $quantidadePorPagina < $total) {
$paginacao['proxima'] = montarUrl($partes, ['pagina' => $pagina + 1]);
}
}
return $paginacao;
}
/**
* Retorna uma instancia de PDO pre-configurada
* @return PDO
*/
function conectarBd(): PDO
{
static $pdo = null;
if (!is_null($pdo)) {
return $pdo;
}
$dsn = sprintf('mysql:host=%s;dbname=%s;charset=UTF8', MYSQL_HOST, MYSQL_DB);
$pdo = new PDO($dsn, MYSQL_USER, MYSQL_PASSWORD);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
}
/**
* Obtem os dados de um jogo
* @param int $id
* @return array Array associativo com:
* * string 'id_jogo'
* * string 'jogo'
* * string 'email'
* * array 'textos'
* * string 'id_texto'
* * string 'id_jogo'
* * string 'titulo'
* * string 'texto'
* * array 'parametros'
* * string 'id_parametro'
* * string 'id_jogo'
* * string 'parametroa'
* * string 'parametrob'
*/
function consultarJogo(int $id): array
{
$pdo = conectarBd();
// Obter jogo
$stmt = $pdo->prepare('SELECT * FROM jogo WHERE id_jogo = :id_jogo LIMIT 1');
$stmt->execute([':id_jogo' => $id]);
if (!$stmt->rowCount()) {
throw new RangeException('Jogo não encontrado');
}
$jogo = $stmt->fetch(PDO::FETCH_ASSOC);
// Obter textos
$stmt = $pdo->prepare('SELECT * FROM texto WHERE id_jogo = :id_jogo');
$stmt->execute([':id_jogo' => $id]);
$jogo['textos'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Obter parametros
$stmt = $pdo->prepare('SELECT * FROM parametro WHERE id_jogo = :id_jogo');
$stmt->execute([':id_jogo' => $id]);
$jogo['parametros'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $jogo;
}
/**
* Consulta a media des votos dos textos de determinado jogo
* @param int $idJogo
* @return array Array associativo indexado pelo ID do texto e apontando para um array associativo
* contendo a media dos votos do texto ('media_votos') e a quantidade total de votos ('total_votos')
*/
function consultarVotos(int $idJogo): array
{
$pdo = conectarBd();
$stmt = $pdo->prepare('SELECT v.id_texto, COUNT(v.id_voto) total_votos, AVG(v.voto) media_votos FROM voto v WHERE v.id_jogo = :id_jogo GROUP BY v.id_texto');
$stmt->execute([':id_jogo' => $idJogo]);
$result = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$result[$row['id_texto']] = [
'total_votos' => $row['total_votos'],
'media_votos' => $row['media_votos'],
];
}
return $result;
}
/**
* Retorna se determinado jogo possui pelo menos um voto
* @param int $idJogo
* @return bool
*/
function possuiVotos(int $idJogo): bool
{
$pdo = conectarBd();
$stmt = $pdo->prepare('SELECT 1 FROM voto WHERE id_jogo = :id_jogo LIMIT 1');
$stmt->execute([':id_jogo' => $idJogo]);
return $stmt->rowCount() > 0;
}