Parte 3 - Criação da tabela e testes de login

Para testarmos o login vamos criar uma pequena table como abaixo. Todas as senhas de teste são 123456

Não se esqueça de configurar o banco de dados. 

-- phpMyAdmin SQL Dump
-- version 4.9.5deb2
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Tempo de geração: 23-Jul-2023 às 00:09
-- Versão do servidor: 5.7.34
-- versão do PHP: 7.4.33

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Banco de dados: `todo`
--

-- --------------------------------------------------------

--
-- Estrutura da tabela `users`
--

CREATE TABLE `users` (
 `id` int(11) UNSIGNED NOT NULL,
 `name` varchar(128) NOT NULL,
 `email` varchar(240) NOT NULL,
 `password` varchar(240) NOT NULL,
 `status` tinyint(1) NOT NULL,
 `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
 `updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
 `deleted_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Extraindo dados da tabela `users`
--

INSERT INTO `users` (`id`, `name`, `email`, `password`, `status`, `created_at`, `updated_at`, `deleted_at`) VALUES
(1, 'gilberto 1', 'email1@teste.com', '$2y$10$9wQKrMuhGMZ85H6oCBQssORWOsf1w/Fy5DF.Igo7Zm/t6TFTd/Sq.', 1, '2023-07-23 02:30:02', NULL, NULL),
(2, 'pedro 2', 'email2@teste.com', '$2y$10$9wQKrMuhGMZ85H6oCBQssORWOsf1w/Fy5DF.Igo7Zm/t6TFTd/Sq.', 1, '2023-07-23 02:30:02', NULL, NULL),
(3, 'maria 3', 'email3@teste.com', '$2y$10$9wQKrMuhGMZ85H6oCBQssORWOsf1w/Fy5DF.Igo7Zm/t6TFTd/Sq.', 1, '2023-07-23 02:30:02', NULL, NULL),
(4, 'jose 4', 'email4@teste.com', '$2y$10$9wQKrMuhGMZ85H6oCBQssORWOsf1w/Fy5DF.Igo7Zm/t6TFTd/Sq.', 1, '2023-07-23 02:30:02', NULL, NULL),
(5, 'ana 5', 'email5@teste.com', '$2y$10$9wQKrMuhGMZ85H6oCBQssORWOsf1w/Fy5DF.Igo7Zm/t6TFTd/Sq.', 1, '2023-07-23 02:30:02', NULL, NULL),
(6, 'Bastião 6', 'email6@teste.com', '$2y$10$9wQKrMuhGMZ85H6oCBQssORWOsf1w/Fy5DF.Igo7Zm/t6TFTd/Sq.', 1, '2023-07-23 02:30:02', NULL, NULL);

--
-- Índices para tabelas despejadas
--

--
-- Índices para tabela `users`
--
ALTER TABLE `users`
 ADD PRIMARY KEY (`id`),
 ADD UNIQUE KEY `email` (`email`);

--
-- AUTO_INCREMENT de tabelas despejadas
--

--
-- AUTO_INCREMENT de tabela `users`
--
ALTER TABLE `users`
 MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Acesse modules/Auth/Controllers/Auth.php e cole este código

<?php

namespace Modules\Auth\Controllers;

use Modules\Todo\Main\Controllers\BaseController;

class Auth extends BaseController
{
 protected $helpers = ['form', 'html'];

 public function index()
 {
 return view('Modules\Auth\Views\login');
 }
 
 /*
 // teste para encriptar a senha...
 public function encriptar($str)
 {
 return password_hash($str, PASSWORD_DEFAULT);
 }
 */


 public function login()
 {
 if ($_POST) {

 $authModel = model('Modules\Auth\Models\AuthModel', false);

 $post = $this->request->getPost(); 

 $auth = $authModel->chkLogin([
 'email' => $post['email'],
 'password' => $post['password'],
 ]);

 if ($auth != false && $auth->id > 0) {
 // O login foi efetuado com sucesso.
 session()->set([
 'isLoggedIn' => true,
 'ip_login' => \Config\Services::request()->getIPAddress(),
 'key' => PRIVATE_KEY, // Constants
 'userData' => [
 'name' => (string) $auth->name,
 'id' => (int) $auth->id,
 'email' => $auth->email,
 'isAdmin' => false
 ]
 ]);

 return redirect()->to(base_url('todo/dashboard'));
 }
 }
 }

 public function logout()
 { 
 session()->destroy();
 return redirect()->to(site_url('auth'));
 }
}

Acesse modules/Auth/Views/login.php e atualize a view login.php

<?= $this->extend('Modules\Todo\Main\Views\external_template'); ?>

<?= $this->section('css'); ?>
<?= $this->endSection(); ?>

<?= $this->section('content'); ?>

<?= form_open(site_url('auth/login')); ?>
<div class="row">
 <div class="col-12 col-md-6 mx-auto">
 <h1 class="h3 mb-3 fw-normal">Login</h1>
 <div class="form-floating mb-1">
 <input type="email" class="form-control" name="email" id="email" placeholder="name@example.com">
 <label for="email">E-mail</label>
 </div>
 <div class="form-floating bm-1">
 <input type="password" class="form-control" name="password" id="password" placeholder="Password">
 <label for="password">Password</label>
 </div>
 <button class="w-100 btn btn-lg btn-primary mt-2" type="submit">Login</button>
 <p class="mt-5 mb-3 text-muted">© 2023</p>
 </div>
</div>
<?= form_close() ?>

<?= $this->endSection(); ?>

<?= $this->section('scripts'); ?>
<?= $this->endSection(); ?>

Acesse modules/Auth/Models/AuthModel.php e cole o código da model.

<?php

namespace Modules\Auth\Models;

use CodeIgniter\Model;

class AuthModel extends Model
{
 protected $table = 'users';
 protected $primaryKey = 'id';
 protected $returnType = 'object';

 public function chkLogin($data)
 {
 $password = $data['password'];

 $query = $this->query("SELECT id, name,email,password,status FROM users WHERE (email = " . $this->escape($data['email']) . ")");

 if (count($query->getResult()) === 1 && password_verify($password, $query->getRow()->password)) { // deve retornar apenas 1 resultado.
 unset($query->getRow()->senha);
 return $query->getRow();
 }
 return false;
 }
}

Acesse modules/Todo/Main/Controllers/BaseController.php  e atualize.

<?php

namespace Modules\Todo\Main\Controllers;

use CodeIgniter\Controller;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;

abstract class BaseController extends Controller
{
 /**
 * Instance of the main Request object.
 *
 * @var CLIRequest|IncomingRequest
 */
 protected $request;

 /**
 * An array of helpers to be loaded automatically upon
 * class instantiation. These helpers will be available
 * to all other controllers that extend BaseController.
 *
 * @var array
 */
 protected $helpers = [];
 protected $data = [];
 

 /**
 * Constructor.
 */
 public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
 {
 // Do Not Edit This Line
 parent::initController($request, $response, $logger);
 
 $this->data['userData'] = [ 
 'name'=> $this->getUser('name'),
 'email'=> $this->getUser('email')
 ];


 // Preload any models, libraries, etc, here.

 // E.g.: $this->session = \Config\Services::session();
 }

 /**
 * retorna dados do usuario
 * @return string/array
 */
 protected function getUser(?string $field = null)
 {
 $user = service('session')->get('userData');

 if (null === $user) {
 return null;
 }
 return null === $field ? $user : ($user[$field] ?? null);
 }
}

Acesse modules/Todo/Config/Routes.php e atualize as rotas

<?php

// Páginas fora do controle de login

$routes->group('/', ['namespace' => '\Modules\Auth\Controllers'], function ($routes) {

 $routes->get('', 'Auth::index');

 $routes->group('auth', function ($routes) {
 $routes->get('', 'Auth::index');

 // login e logout
 $routes->get('logout', 'Auth::logout');
 $routes->get('login', 'Auth::login');
 $routes->post('login', 'Auth::login');
 });
});

// rotas protegidas
$routes->group('todo', ['namespace' => '\Modules\Todo'], function ($routes) {

 // painel principal
 $routes->get('/', 'Dashboard\Controllers\Dashboard::index');
 $routes->get('dashboard', 'Dashboard\Controllers\Dashboard::index');

 // nossa lista de tarefas
 $routes->group('tasks', function ($routes) {
 $routes->get('', 'Auth::index');
 });
});

Acesse modules/Todo/Dashboard/Controllers/Dashboard.php e atualize o código do dashboard.

<?php

namespace Modules\Todo\Dashboard\Controllers;

use Modules\Todo\Main\Controllers\BaseController;

class Dashboard extends BaseController
{
 protected $helpers = ['form', 'html'];

 public function index()
 { 
 // $this->getUser('id')
 return view('Modules\Todo\Dashboard\Views\index',$this->data);
 }
}

Se você ainda não criou, Crie uma view para o Dashboard.

Acesse ou crie o arquivo em modules/Todo/Dashboard/Views/index.php

<?= $this->extend('Modules\Todo\Main\Views\internal_template'); ?>

<?= $this->section('css'); ?>
<?= $this->endSection(); ?>

<?= $this->section('content'); ?>
<h1>
 Dashboard
</h1>
últimas tarefas...
<?= $this->endSection(); ?>

<?= $this->section('scripts'); ?>
<?= $this->endSection(); ?>

Acesse o template interno em modules/Todo/Main/Views/internal_template.php e atualize.

<!DOCTYPE html>
<html lang="pt-br">

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Lista de Tarefas</title>
 <?= link_tag(base_url('assets/css/bootstrap.min.css')); ?>
 <?= $this->renderSection('css'); ?>
</head>

<body>
 <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
 <div class="container-fluid">
 <a class="navbar-brand" href="#">Tarefas</a>
 <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="true" aria-label="Toggle navigation">
 <span class="navbar-toggler-icon"></span>
 </button>
 <div class="navbar-collapse collapse " id="navbarCollapse" style="">
 <ul class="navbar-nav me-auto mb-2 mb-md-0">
 <li class="nav-item">
 <a class="nav-link active" aria-current="page" href="#">Home</a>
 </li>
 <li class="nav-item">
 <a class="nav-link" href="#">Nova tarefa</a>
 </li>
 <li class="nav-item">
 <a class="nav-link" href="#">Lista de tarefas</a>
 </li>

 </ul>
 <form class="d-flex" role="search">
 <input class="form-control me-2" type="search" placeholder="Buscar" aria-label="Search">
 <button class="btn btn-outline-success" type="submit">buscar</button>
 </form>
 </div>
 </div>
 </nav>

 <div class="container" style="margin-top:100px;">
 <div class="row">
 <div class="d-flex justify-content-between">
 <div>
 Olá: <strong><?= $userData['name']; ?></strong>
 </div>
 <div class="text-end">
 Codeigniter Versão <?= CodeIgniter\CodeIgniter::CI_VERSION ?> - <a href="<?= site_url('auth/logout'); ?>">Sair</a>
 </div>
 </div>
 <div class="col-12">
 <hr>
 </div>
 </div>
 <!-- cada view renderiza uma row -->
 <?= $this->renderSection('content'); ?>
 </div>
 <?= script_tag(site_url('assets/js/bootstrap.bundle.min.js')); ?>
 <?= $this->renderSection('scripts'); ?>
</body>

</html>

Resultado esperado ao acessar a rota auth

Após o login (email2@teste.com.br e senha 123456)

Agora podemos partir para o formuláro de cadastro das tarefas...

Ante, porém, vamos criar um helper para nos auxiliar na exibição das mensagens de info, success e error. Utilizaremos as #classes do Bootstrap.

Acesse app/Helpers/ e crie um arquivo alert_helper.php

Vamos criar um helper, chamar ele no controller. Criar a mensagem de erro de login no método login e chamar a função do helper na view de login

<?php
function renderAlerts($arr)
{ 
 if ($arr !== null) {
 return '<div class="alert alert-' . $arr['class'] . '">' . $arr['text'] . '</div>';
 }
}

Nosso controller rece mais um helper, o alert

E no else da falha de login colocamos a mensagem.

<?php

namespace Modules\Auth\Controllers;

use Modules\Todo\Main\Controllers\BaseController;

class Auth extends BaseController
{
 protected $helpers = ['form', 'html', 'alert'];

 public function index()
 {
 return view('Modules\Auth\Views\login');
 } 

 public function login()
 {
 if ($_POST) {

 $authModel = model('Modules\Auth\Models\AuthModel', false);

 $post = $this->request->getPost();

 $auth = $authModel->chkLogin([
 'email' => $post['email'],
 'password' => $post['password'],
 ]);

 if ($auth != false && $auth->id > 0) {
 // O login foi efetuado com sucesso.
 session()->set([
 'isLoggedIn' => true,
 'ip_login' => \Config\Services::request()->getIPAddress(),
 'key' => PRIVATE_KEY, // Constants
 'userData' => [
 'name' => (string) $auth->name,
 'id' => (int) $auth->id,
 'email' => $auth->email,
 'isAdmin' => false
 ]
 ]);

 return redirect()->to(base_url('todo/dashboard'));
 } else {
 // em caso de erro.
 session()->setFlashdata('message', ['class' => 'danger', 'text' => 'Ocorreu um erro, verifique seus dados!']);
 // return view('Modules\Auth\Views\login');
 return redirect()->to(base_url('auth'));
 }
 }
 }

 public function logout()
 {
 session()->destroy();
 return redirect()->to(site_url('auth'));
 }
}

Alguns ajustes na view de login.

<?= $this->extend('Modules\Todo\Main\Views\external_template'); ?>

<?= $this->section('css'); ?>
<?= $this->endSection(); ?>

<?= $this->section('content'); ?>

<?= form_open(site_url('auth/login')); ?>
<div class="row mt-5">
 <div class="col-12 col-md-6 mx-auto"> 
 <?php echo renderAlerts(session('message')); ?>
 <h1 class="h3 mb-3 fw-normal">Login</h1>
 <div class="form-floating mb-1">
 <input type="email" class="form-control" name="email" id="email" placeholder="name@example.com" required />
 <label for="email">E-mail</label>
 </div>
 <div class="form-floating bm-1">
 <input type="password" class="form-control" name="password" id="password" placeholder="Password" required />
 <label for="password">Password</label>
 </div>
 <button class="w-100 btn btn-lg btn-primary mt-2" type="submit">Login</button>
 <p class="mt-5 mb-3 text-muted">© 2023</p>
 </div>
</div>
<?= form_close() ?>

<?= $this->endSection(); ?>

<?= $this->section('scripts'); ?>
<?= $this->endSection(); ?>

E o resultado será este.

Próximo passo é a parte 4 - Criar o formulário de cadastro de tarefas, a tabela e validações