CRUD Bootstrap 5 Mysql e Codeigniter 4 Lista de tarefas parte 1

Neste tutorial vamos criar um pequeno #sistema #crud de gerenciamento de #tarefas mais conhecido como #todolist utilizando o Codeigniter 4 (CI4), Mysql e #Boostrap 5. Vamos, também, fazer algumas validações no client side e no server side utilizando a biblioteca validation do CI4.

Para acessar o código fonte: https://www.codesnippets.dev.br/post/crud-bootstrap-5-mysql-e-codeigniter-4-lista-de-tarefas-download

Se você deseja ir para a parte 2 - CRUD Codeigniter 4 - Parte 2

 

Não colocaremos nossos códigos no diretório /app, para isso vamos montrar uma estrutura de módulos.

Ex. modules/auth modules/todo, modules/main.

Nossos endereços terão este formato: http://localhost:8080/todo/tasks

A versão utilizado no Tutorial é 4.3.6 => https://www.codeigniter.com/user_guide/changelogs/v4.3.6.html

Depois que você instalou o CI4 no seu ambiente faça as seguintes alterações utilizando seu editor preferido.


Explicação;
1 - Crie um diretório modules na raiz do projeto, no mesmo nível que /app.

2 - Dentro de modules, crie Auth e Todo (aqui ficará nossa área protegida por filters)

3 - Dentro de Auth  coloque a estrutura (controller model e view) padrão do CI4. Vamos utilizar este módulo para a parte de login e logout.

4 - Dentro de Todo crie os seguintes diretórios, cada um com a estrutura padrão sugerida. Nesta parte a diferença é que dentro de Config teremos o arquivo Routes.php, onde configuraremos as rotas. Repita a estrutura acima (Controllers, Models e Views) para cada uma (Não para a Config).

Dashboard, Main e Tasks terão a mesma estrutura que Auth.

Agora nós vamos fazer alguns ajustes para fazer os testes iniciais.

Acesse app/Config/App.php e faça os ajustes conforme se ambiente e endereço do seu sistema

app/Config/App.php
public string $baseURL = 'http://localhost/curso-ci4/curso-todo/public/';

// retire index.php
public string $indexPage = '';

Se você estiver utilizando o arquivo .env faça os ajustes necessários colocando o ambiente para o modo desenvolvimento.

CI_ENVIRONMENT = development

E aproveite para ajustar outras configurações como baseURL e dados de conexão com o banco de dados. Vamos utilizar o #Mysql

app.baseURL = ''

// descomente as linhas abaixo e insira as informações pedidas conforme a sua conexão

database.default.hostname = localhost
database.default.database = ci4_todo_list
database.default.username = root
database.default.password = root
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306

 

Filtros e rotas.

Vamos fazer uma simples configuração de filters e rotas para nos ajudar na navegação do sistema.

Acesse app/Filters/ e crie um arquivo #php chamado MyFilter.php.

Essa PRIVATE_KEY é opcional, mas pode ser criada em app/Config/Constants.php

/*
  |
  |Key única para checagem no login
 */

 define('PRIVATE_KEY', '321daDsd3w505eDwFq5eswq5eqx065H');

Conteúdo do before em app/Filters/MyFilter.php

<?php

namespace App\Filters;

use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class MyFilter implements FilterInterface
{

    public $ip;
    private $auth;

    public function before(RequestInterface $request, $arguments = null)
    {
        
        $this->auth = service('session')->get();
        $this->ip = $request->getIPAddress();

        if (!$this->isLoggedIn() or ($this->auth['key'] != PRIVATE_KEY) or ($this->ip != $this->auth['ip_login'])) {
            
            service('session')->destroy();
            return redirect()->to(base_url('auth/logout'));
        }
    }



    // --------------------------------------------------------------------
    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Do something here
    }


    /**
     * Checks whether a user is logged in.
     *
     * @return bool if a user is logged in
     */
    private function isLoggedIn(): bool
    {
        if (!isset($this->auth['isLoggedIn']) or !isset($this->auth['ip_login'])) {
            return false;
        }
        return (null !== $this->auth['isLoggedIn'] && $this->auth['userData'] !== null && $this->ip === $this->auth['ip_login']);
    }
}

Acesse app/Config/Filters.php e configure como mostra este código.

Estamos chamando o nosso filtro use \App\Filters\MyFilter;

Criando um alias para ele 'auth' => MyFilter::class,

E utilizando antes todas as rotas todo 'auth' => ['before' => ['todo*']],

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Filters\CSRF;
use CodeIgniter\Filters\DebugToolbar;
use CodeIgniter\Filters\Honeypot;
use CodeIgniter\Filters\InvalidChars;
use CodeIgniter\Filters\SecureHeaders;
use \App\Filters\MyFilter;

class Filters extends BaseConfig
{
    /**
     * Configures aliases for Filter classes to
     * make reading things nicer and simpler.
     */
    public array $aliases = [
        'auth'          => MyFilter::class,
        'csrf'          => CSRF::class,
        'toolbar'       => DebugToolbar::class,
        'honeypot'      => Honeypot::class,
        'invalidchars'  => InvalidChars::class,
        'secureheaders' => SecureHeaders::class,
    ];

    /**
     * List of filter aliases that are always
     * applied before and after every request.
     */
    public array $globals = [
        'before' => [
            // 'honeypot',
            // 'csrf',
            // 'invalidchars',
        ],
        'after' => [
            'toolbar',
            // 'honeypot',
            // 'secureheaders',
        ],
    ];

    /**
     * List of filter aliases that works on a
     * particular HTTP method (GET, POST, etc.).
     *
     * Example:
     * 'post' => ['foo', 'bar']
     *
     * If you use this, you should disable auto-routing because auto-routing
     * permits any HTTP method to access a controller. Accessing the controller
     * with a method you don’t expect could bypass the filter.
     */
    public array $methods = [];

    /**
     * List of filter aliases that should run on any
     * before or after URI patterns.
     *
     * Example:
     * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
     */
    public array $filters = [
        'auth' => ['before' => ['todo*']],
    ];
}
Vamos criar as rotas
Acesse app/Config/Routes.php (crie uma cópia por segurança).
<?php

namespace Config;

// Create a new instance of our RouteCollection class.
$routes = Services::routes();

/*
 * --------------------------------------------------------------------
 * Router Setup
 * --------------------------------------------------------------------
 */
$routes->setDefaultNamespace('App\Controllers');
$routes->setDefaultController('Home');
$routes->setDefaultMethod('index');
$routes->setTranslateURIDashes(false);
$routes->set404Override();

$routes->setAutoRoute(false); // Vamos utilizar rotas definidas

if (is_file(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) {
    require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
}


/**
 * --------------------------------------------------------------------
 * Definições de rotas em \Modules\Todo\Config
 * --------------------------------------------------------------------
 */
if (file_exists(ROOTPATH . 'modules')) {

    $modulesPath = ROOTPATH . 'modules/';
    $modules = scandir($modulesPath);

    foreach ($modules as $module) {
        if ($module === '.' || $module === '..')
            continue;
        if (is_dir($modulesPath) . '/' . $module) {
            $routesPath = $modulesPath . $module . '/Config/Routes.php';

            if (file_exists($routesPath)) {

                require($routesPath);
            } else {
                continue;
            }
        }
    }
}
Configurando as rotas de teste

Acesse modules/Todo/Config/Routes.php e insira este código.

<?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');
    });
});

// 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');
    });
});

Alterando os controller para testes iniciais. Vamos verificar se está tudo certo com as rotas.

Acesse modules/Todo/Dashboard/Controllers/Dashboard.php e faça algumas alterações (apenas para testes iniciais)

<?php

namespace Modules\Todo\Dashboard\Controllers;

use Modules\Todo\Main\Controllers\BaseController;

class Dashboard extends BaseController
{

    public function __construct()
    {
        //...
    }

    public function index()
    {
        echo 'dashboard em rota protegida pelo filter';
    }
}

Agora, se acessarmos o endereço http://localhost:8080/todo/ (verifique o endereço de acordo com sua url base)

Veremos algo parecido com isso

Isso aconteceu porque a nossa rota está protegida e não permitiu acesso sem um login realizado.

Para testarmos se o filtro está realmente funcionando vamos fazer um pequeno debug.

Acesse app/Filters/MyFilter.php e adicione um dei('caiu no filtro')  logo após a abertura do método before

public function before(RequestInterface $request, $arguments = null)
    {
        die(' caiu no filtro');
        
        $this->auth = service('session')->get();
        $this->ip = $request->getIPAddress();

        if (!$this->isLoggedIn() or ($this->auth['key'] != PRIVATE_KEY) or ($this->ip != $this->auth['ip_login'])) {
            
            service('session')->destroy();
            return redirect()->to(base_url('auth/logout'));
        }
    }

E veremos o seguinte.

Com isso concluímos que o filtro está protegendo as rotas.

A partir deste ponto vamos iniciar a construção do sistema. Vamos configurar nossas dependencias CSS e #templates.

Ir para o próximo passo. CRUD Codeigniter 4 - Parte 2