Herramientas Informaticas

Categoría: CURSOS PHP Página 1 de 2

Actualización de CodeIgniter 4.4.4 a 4.5.1 Correcciones en Fuentes

Son varias las novedades y cambios que se vinieron en los cambios del Framework de PHP CodeIgniter 4 en su versión 4.5.1.

Las novedades ya lo pueden ver directamente en su web https://codeigniter4.github.io/userguide/installation/upgrade_450.html

Entre los cambios mas básicos que se tienen que hacer es copiar el archivo spark e index.php desde la carpeta de vendor al proyecto principal mas o menos asi

cp vendor/codeigniter4/framework/public/index.php public/index.php
cp vendor/codeigniter4/framework/spark spark

Esa parte es la mas básica pero en nuestro caso vimos que fallo en una biblioteca de manejo de usuarios Myth/Auth el cual no guardaba usuarios y nos arrojaba el siguiente error:

Could not check compatibility between Myth\Auth\Authentication\Passwords\CompositionValidator::check(string $password, ?CodeIgniter\Entity\Entity $user = null): bool and Myth\Auth\Authentication\Passwords\ValidatorInterface::check(string $password, ?CodeIgniter\Entity $user = null): bool, because class CodeIgniter\Entity is not available in D:\proyectoCodeIgniter\vendor\julio101290\auth\src\Authentication\Passwords\CompositionValidator.php

Error que se corrige solo con cambiar la linea de use CodeIgniter\Entity; a use CodeIgniter\Entity\Entity; en el archivo proyectoCodeIgniter\vendor\julio101290\auth\src\Authentication\Passwords\ValidatorInterface.php

Igual ya se actualizo el repositorio https://github.com/julio101290/myth-auth/releases/tag/v1.2.8

Si utilizan este fork de la librería solo hagan un composer update

Otro detalle al parecer la ruta el resources ya no tomo en automático el update, o quizás se definieron por seguridad otro tipo de reglas por lo cual se corrigió la biblioteca de boilerplate

En el archivo de vendor\julio101290\boilerplate\src\Config\Routes.php se agregaron el siguiente código para que pueda actualizar, igual si existe otra manejara dejarlo en la caja de comentarios

        /**
     * Users Update
     */
    $routes->post('user/manage/(:any)/update', 'UserController::update/$1', [
        'filter' => 'permission:back-office',
        'namespace' => 'julio101290\boilerplate\Controllers\Users',
        'except' => 'show',
        'as' => 'update',
    ]);

    $routes->post('role/(:any)/update', 'RoleController::update/$1', [
        'filter' => 'permission:role-permission',
        'namespace' => 'julio101290\boilerplate\Controllers\Users',
        'except' => 'show',
        'as' => 'updateRole',
    ]);
    

De igual manera se actualizo la biblioteca en https://github.com/julio101290/boilerplate/releases/tag/v1.3.8

Otro de las correcciones que se tienen que hacer es que si se hacen peticiones Ajax el método tiene que ir en minúscula por ejemplo:

Así estaba uno antes

  ajax: {
            url: '<?= base_url('admin/sells') ?>',
            method: 'GET',
            dataType: "json"
        },..........................

Ahora tendría que quedar así, muy simple, entenderle a primera no fue fácil

  ajax: {
            url: '<?= base_url('admin/sells') ?>',
            method: 'get',
            dataType: "json"
        },

Otros de los errores fue en el nivel de modelo, nos arrojo el siguiente error

CodeIgniter\\Database\\BaseBuilder::getOperatorFromWhereKey(): Argument #1 ($whereKey) must be of type string, int given

El detalle era en el where que antes funcionaba de la siguiente manera

->where('\'0\'', $empresa,true)

Ahora funciona de la siguiente manera

->where('\'0\'', $empresa,true)

Extensiones Requeridas para CodeIgniter 4 en PHP 8.2

Las extensiones para trabajar en los proyectos actuales de MedicalSoft, Punto de venta ETC, son las siguientes

extension=curl
extension=ffi
extension=ftp
extension=fileinfo
extension=gd
extension=gettext
extension=gmp
extension=intl
extension=imap
extension=mbstring
;extension=exif      ; Must be after mbstring as it depends on it
extension=mysqli
;extension=oci8_12c  ; Use with Oracle Database 12c Instant Client
;extension=oci8_19  ; Use with Oracle Database 19 Instant Client
extension=odbc
extension=openssl
;extension=pdo_firebird
extension=pdo_mysql
;extension=pdo_oci
extension=pdo_odbc
extension=pdo_pgsql
extension=pdo_sqlite
extension=pgsql
extension=shmop
extension=php_pdo_sqlsrv_82_nts_x64.dll

; The MIBS data available in the PHP distribution must be installed.
; See https://www.php.net/manual/en/snmp.installation.php
;extension=snmp

extension=soap
;extension=sockets
;extension=sodium
extension=sqlite3
;extension=tidy
extension=xsl
extension=zip

Como Instalar PDO SQL SERVER en PHP 8.2 en Windows 10

Una de la extensiones requeridas en nuestro caso y como puede ser en el caso de ustedes es poder conectar SQL server Con PHP 8.2 asi que les mostraremos como instalarlo correctamente, suponiendo que tenemos instalado PHP 8.2 en Windows 10

Primero descargamos los controladores de SQL SERVER en la pagina oficial de Microsoft https://learn.microsoft.com/en-us/sql/connect/php/download-drivers-php-sql-server?view=sql-server-ver16
Enlace directo del archivo https://go.microsoft.com/fwlink/?linkid=2246325

Como instalar PHP 8.2 en Windows 10 2024

Recién se ha formateado de nuevo el equipo con Windows 10 así que lo que toca hacer es reinstalar PHP

Se instalar la versión 8.2 por que aunque ya existe la versión 8.3 hay mas librerías actualmente para la 8.2 como por ejemplo el PDO para SQL Server

Primero descargarnos el archivo desde la pagina oficial https://windows.php.net/download#php-8.2-nts-vs16-x64

Creando el CRUD de Tipos de Vehículos #14

Posteriormente vamos a necesitar el catalogo de tipo de vehículos y vehículos en esta publicación dejaremos la forma para crear el CRUD de tipos de vehículos con los siguientes datos.

  • Empresa
  • Codigo
  • Descripción

Creando CRUD de Tipos de movimiento #13

Para registrar los movimientos requerimos especificar que tipo de movimiento es como puede ser entradas por compra, salidas por venta, entrada por devolución de cliente, saluda por devolución a proveedor

Para ello crearemos el siguiente catalogo de Tipos de movimiento con los siguientes campos

  • Empresa
  • Descripción
  • tipo
  • Es traspaso

Primero creamos el archivo de migración App/Database/2023-08-17222335_Tipos_movimientos_inventario.php con el siguiente código

Creando CRUD de Almacenes #12

Es necesario para llevar el control correcto del inventario tener almacenes,

A continuación mostramos como crear el CRUD de almacenes

El CRUD tendrá los siguientes datos

  • Empresa
  • Clave
  • Nombre
  • Inicio de inventario

Creando CRUD de Proveedores #11

Antes de empezar con el inventario necesitaremos los catálogos principales, uno de ellos es el catalogo de proveedores.

El catalogo es similar al de clientes

Para ello necesitamos en los siguientes campos:

Datos Generales

  • Empresa
  • Nombre
  • Apellido
  • Correo Electrónico
  • Dirección
  • Código Postal
  • Fecha de nacimiento

Datos Extra Facturación

  • Razón social
  • RFC
  • Forma de pago
  • Método de pago
  • Uso CFDI
  • Regimen Fiscal
Leer Mas: Creando CRUD de Proveedores #11

Creamos el archivo de migración App/Database/Migrations/2023-04-21063336_Proveedores con el siguiente codigo

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class Proveedores extends Migration {

    public function up() {
        // Custumers
        $this->forge->addField([
            'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
            'idEmpresa' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'firstname' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'lastname' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'razonSocial' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
            'taxID' => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
            'email' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'direction' => ['type' => 'varchar', 'constraint' => 1024, 'null' => true],
            'birthdate' => ['type' => 'datetime', 'null' => true],
            'formaPago' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
            'metodoPago' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
            'usoCFDI' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
            'codigoPostal' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true],
            'regimenFiscal' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'created_at' => ['type' => 'datetime', 'null' => true],
            'updated_at' => ['type' => 'datetime', 'null' => true],
            'deleted_at' => ['type' => 'datetime', 'null' => true],
        ]);
        $this->forge->addKey('id', true);
        $this->forge->createTable('proveedores', true);
    }

    public function down() {
        $this->forge->dropTable('proveedores', true);
    }

}

Creamos el archivo modelo en App/Models/ProveedoresModel.php con el siguiente código

<?php

namespace App\Models;

use CodeIgniter\Model;

class ProveedoresModel extends Model {

    protected $table = 'proveedores';
    protected $primaryKey = 'id';
    protected $useAutoIncrement = true;
    protected $returnType = 'array';
    protected $useSoftDeletes = true;
    protected $allowedFields = ['id'
        , 'idEmpresa'
        , 'firstname'
        , 'lastname'
        , 'taxID'
        , 'email'
        , 'direction'
        , 'birthdate'
        , 'created_at'
        , 'updated_at'
        , 'deleted_at'
        , 'metodoPago'
        , 'formaPago'
        , 'codigoPostal'
        , 'regimenFiscal'
        , 'razonSocial'
        , 'usoCFDI'];
    protected $useTimestamps = true;
    protected $createdField = 'created_at';
    protected $deletedField = 'deleted_at';
    protected $validationRules = [
    ];
    protected $validationMessages = [];
    protected $skipValidation = false;

    /**
     * Obtener Clientes
     */
    public function mdlGetProveedores($empresas) {


        $resultado = $this->db->table('proveedores a, empresas b')
                ->select('a.id
                    ,a.idEmpresa
                    ,b.nombre as nombreEmpresa
                    ,a.firstname
                    ,a.lastname
                    ,a.taxID
                    ,a.email
                    ,a.direction
                    ,a.birthdate
                    ,a.metodoPago
                    ,a.formaPago
                    ,a.usoCFDI
                    ,a.created_at
                    ,a.updated_at
                    ,a.codigoPostal
                    ,a.regimenFiscal
                    ,a.razonSocial
                    ,a.deleted_at')
                ->where('a.idEmpresa', 'b.id', FALSE)
                ->whereIn('a.idEmpresa', $empresas);

        return $resultado;
    }

}

Creamos el archivo controlador en App/Controllers/ProveedoresController.php con el siguiente código.

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use \App\Models\{
    ProveedoresModel
};
use App\Models\LogModel;
use CodeIgniter\API\ResponseTrait;
use App\Models\EmpresasModel;

class ProveedoresController extends BaseController {

    use ResponseTrait;

    protected $log;
    protected $proveedores;
    protected $empresa;

    public function __construct() {
        $this->proveedores = new ProveedoresModel();
        $this->log = new LogModel();
        $this->empresa = new EmpresasModel();
        helper('menu');
        helper('utilerias');
    }

    public function index() {


        helper('auth');

        $idUser = user()->id;
        $titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);

        if (count($titulos["empresas"]) == "0") {

            $empresasID[0] = "0";
        } else {

            $empresasID = array_column($titulos["empresas"], "id");
        }

        if ($this->request->isAJAX()) {
            $datos = $this->proveedores->mdlGetProveedores($empresasID);
            return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
        }

        $fechaActual = fechaMySQLADateTimeHTML5(fechaHoraActual());

        $titulos["title"] = lang('proveedores.title');
        $titulos["subtitle"] = lang('proveedores.subtitle');
        $titulos["fecha"] = $fechaActual;

        $titulos["formaPago"] = $this->catalogosSAT->formasDePago40()->searchByField("texto", "%%", 99999);
        $titulos["usoCFDI"] = $this->catalogosSAT->usosCfdi40()->searchByField("texto", "%%", 99999);
        $titulos["metodoPago"] = $this->catalogosSAT->metodosDePago40()->searchByField("texto", "%%", 99999);
        $titulos["regimenFiscal"] = $this->catalogosSAT->regimenesFiscales40()->searchByField("texto", "%%", 99999);
        return view('proveedores', $titulos);
    }

    /**
     * Read Custumers
     */
    public function getProveedores() {
        $idProveedor = $this->request->getPost("idProveedor");

        $datosProveedor = $this->proveedores->find($idProveedor);
        echo json_encode($datosProveedor);
    }

    /**
     * Get Custumers via AJax
     */
    public function getProveedoresAjax() {

        $request = service('request');
        $postData = $request->getPost();

        $response = array();

        // Read new token and assign in $response['token']
        $response['token'] = csrf_hash();
        $proveedores = new ProveedoresModel();
        $idEmpresa = $postData['idEmpresa'];

        if (!isset($postData['searchTerm'])) {
            // Fetch record

            $listProveedores = $proveedores->select('id,firstname,lastname')->where("deleted_at", null)
                    ->where('idEmpresa', $idEmpresa)
                    ->orderBy('id')
                    ->orderBy('firstname')
                    ->orderBy('lastname')
                    ->findAll(10);
        } else {
            $searchTerm = $postData['searchTerm'];

            // Fetch record

            $listProveedores = $proveedores->select('id,firstname,lastname')->where("deleted_at", null)
                    ->where('idEmpresa', $idEmpresa)
                    ->groupStart()
                    ->like('firstname', $searchTerm)
                    ->orLike('id', $searchTerm)
                    ->orLike('lastname', $searchTerm)
                    ->groupEnd()
                    ->findAll(10);
        }

        $data = array();
        foreach ($listProveedores as $proveedores) {
            $data[] = array(
                "id" => $proveedores['id'],
                "text" => $proveedores['id'] . ' ' . $proveedores['firstname'] . ' ' . $proveedores['lastname'],
            );
        }

        $response['data'] = $data;

        return $this->response->setJSON($response);
    }

    /**
     * Save or update Custumers
     */
    public function save() {
        helper('auth');
        $userName = user()->username;
        $idUser = user()->id;
        $datos = $this->request->getPost();
        if ($datos["idProveedor"] == 0) {
            try {
                if ($this->proveedores->save($datos) === false) {
                    $errores = $this->proveedores->errors();
                    foreach ($errores as $field => $error) {
                        echo $error . " ";
                    }
                    return;
                }
                $dateLog["description"] = lang("vehicles.logDescription") . json_encode($datos);
                $dateLog["user"] = $userName;
                $this->log->save($dateLog);
                echo "Guardado Correctamente";
            } catch (\PHPUnit\Framework\Exception $ex) {
                echo "Error al guardar " . $ex->getMessage();
            }
        } else {
            if ($this->proveedores->update($datos["idProveedor"], $datos) == false) {
                $errores = $this->proveedores->errors();
                foreach ($errores as $field => $error) {
                    echo $error . " ";
                }
                return;
            } else {
                $dateLog["description"] = lang("proveedores.logUpdated") . json_encode($datos);
                $dateLog["user"] = $userName;
                $this->log->save($dateLog);
                echo "Actualizado Correctamente";
                return;
            }
        }
        return;
    }

    /**
     * Delete Custumers
     * @param type $id
     * @return type
     */
    public function delete($id) {
        $infoCustumers = $this->proveedores->find($id);
        helper('auth');
        $userName = user()->username;
        if (!$found = $this->proveedores->delete($id)) {
            return $this->failNotFound(lang('custumers.msg.msg_get_fail'));
        }
        $this->proveedores->purgeDeleted();
        $logData["description"] = lang("proveedores.logDeleted") . json_encode($infoCustumers);
        $logData["user"] = $userName;
        $this->log->save($logData);
        return $this->respondDeleted($found, lang('custumers.msg_delete'));
    }

}

Creamos el archivo principal de la vista en App/Views/proveedores.php con el siguiente código.

<?= $this->include('julio101290\boilerplate\Views\load\select2') ?>
<?= $this->include('julio101290\boilerplate\Views\load\datatables') ?>
<?= $this->include('julio101290\boilerplate\Views\load\nestable') ?>
<!-- Extend from layout index -->
<?= $this->extend('julio101290\boilerplate\Views\layout\index') ?>

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

<?= $this->include('modulesProveedores/modalCaptureProveedores') ?>

<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="float-right">
            <div class="btn-group">

                <button class="btn btn-primary btnAddProveedores" data-toggle="modal" data-target="#modalAddProveedores"><i
                        class="fa fa-plus"></i>

                    <?= lang('proveedores.add') ?>

                </button>

            </div>
        </div>
    </div>
    <div class="card-body">
        <div class="row">
            <div class="col-md-12">
                <div class="table-responsive">
                    <table id="tableProveedores" class="table table-striped table-hover va-middle tableProveedores">
                        <thead>
                            <tr>

                                <th>#</th>

                                <th>Empresa</th>
                                <th>
                                    <?= lang('proveedores.fields.firstname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.lastname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.taxID') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.email') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.direction') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.birthdate') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.created_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.updated_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.deleted_at') ?>
                                </th>

                                <th>
                                    <?= lang('proveedores.fields.actions') ?>
                                </th>

                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- /.card -->

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


<?= $this->section('js') ?>
<script>

    /**
     * Cargamos la tabla
     */

    var tableProveedores = $('#tableProveedores').DataTable({
        processing: true,
        serverSide: true,
        responsive: true,
        autoWidth: false,
        order: [[1, 'asc']],

        ajax: {
            url: '<?= base_url('admin/proveedores') ?>',
            method: 'GET',
            dataType: "json"
        },
        columnDefs: [{
                orderable: false,
                targets: [11],
                searchable: false,
                targets: [11]

            }],
        columns: [{
                'data': 'id'
            },

            {
                'data': 'nombreEmpresa'
            },

            {
                'data': 'firstname'
            },

            {
                'data': 'lastname'
            },

            {
                'data': 'taxID'
            },

            {
                'data': 'email'
            },

            {
                'data': 'direction'
            },

            {
                'data': 'birthdate'
            },

            {
                'data': 'created_at'
            },

            {
                'data': 'updated_at'
            },

            {
                'data': 'deleted_at'
            },

            {
                "data": function (data) {
                    return `<td class="text-right py-0 align-middle">
                         <div class="btn-group btn-group-sm">
                             <button class="btn btn-warning btnEditProveedores" data-toggle="modal" idProveedor="${data.id}" data-target="#modalAddProveedores">  <i class=" fa fa-edit"></i></button>
                             <button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
                         </div>
                         </td>`
                }
            }
        ]
    });







    /**
     * Carga datos actualizar
     */


    /*=============================================
     EDITAR Proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btnEditProveedores", function () {

        var idProveedor = $(this).attr("idProveedor");

        var datos = new FormData();
        datos.append("idProveedor", idProveedor);

        $.ajax({

            url: "<?= base_url('admin/proveedores/getProveedores') ?>",
            method: "POST",
            data: datos,
            cache: false,
            contentType: false,
            processData: false,
            dataType: "json",
            success: function (respuesta) {

                $("#idProveedor").val(respuesta["id"]);
                $("#idEmpresaProveedor").val(respuesta["idEmpresa"]);
                $("#idEmpresaProveedor").trigger("change");
                $("#firstname").val(respuesta["firstname"]);
                $("#razonSocial").val(respuesta["razonSocial"]);
                $("#lastname").val(respuesta["lastname"]);
                $("#taxID").val(respuesta["taxID"]);
                $("#email").val(respuesta["email"]);
                $("#direction").val(respuesta["direction"]);
                $("#birthdate").val(respuesta["birthdate"]);

                $("#formaPago").val(respuesta["formaPago"]);
                $("#formaPago").trigger("change");
                $("#metodoPago").val(respuesta["metodoPago"]);
                $("#metodoPago").trigger("change");
                $("#usoCFDI").val(respuesta["usoCFDI"]);
                $("#usoCFDI").trigger("change");

                $("#codigoPostal").val(respuesta["codigoPostal"]);
                $("#regimenFiscal").val(respuesta["regimenFiscal"]);
                $("#regimenFiscal").trigger("change");

            }

        })

    })

    $("#idEmpresaProveedor ").select2();
    /*=============================================
     ELIMINAR proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btn-delete", function () {

        var idProveedores = $(this).attr("data-id");

        Swal.fire({
            title: '<?= lang('boilerplate.global.sweet.title') ?>',
            text: "<?= lang('boilerplate.global.sweet.text') ?>",
            icon: 'warning',
            showCancelButton: true,
            confirmButtonColor: '#3085d6',
            cancelButtonColor: '#d33',
            confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
        })
                .then((result) => {
                    if (result.value) {
                        $.ajax({
                            url: `<?= base_url('admin/proveedores') ?>/` + idProveedores,
                            method: 'DELETE',
                        }).done((data, textStatus, jqXHR) => {
                            Toast.fire({
                                icon: 'success',
                                title: jqXHR.statusText,
                            });


                            tableProveedores.ajax.reload();
                        }).fail((error) => {
                            Toast.fire({
                                icon: 'error',
                                title: error.responseJSON.messages.error,
                            });
                        })
                    }
                })
    })

    $(function () {
        $("#modalAddProveedores").draggable();

    });


</script>
<?= $this->endSection() ?>

Creamos el archivo secundario que contiene el modal en App/Views/modulesProveedores/modalCaptureProveedores.php con el siguiente codigo.

<?= $this->include('julio101290\boilerplate\Views\load\select2') ?>
<?= $this->include('julio101290\boilerplate\Views\load\datatables') ?>
<?= $this->include('julio101290\boilerplate\Views\load\nestable') ?>
<!-- Extend from layout index -->
<?= $this->extend('julio101290\boilerplate\Views\layout\index') ?>

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

<?= $this->include('modulesProveedores/modalCaptureProveedores') ?>

<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="float-right">
            <div class="btn-group">

                <button class="btn btn-primary btnAddProveedores" data-toggle="modal" data-target="#modalAddProveedores"><i
                        class="fa fa-plus"></i>

                    <?= lang('proveedores.add') ?>

                </button>

            </div>
        </div>
    </div>
    <div class="card-body">
        <div class="row">
            <div class="col-md-12">
                <div class="table-responsive">
                    <table id="tableProveedores" class="table table-striped table-hover va-middle tableProveedores">
                        <thead>
                            <tr>

                                <th>#</th>

                                <th>Empresa</th>
                                <th>
                                    <?= lang('proveedores.fields.firstname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.lastname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.taxID') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.email') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.direction') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.birthdate') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.created_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.updated_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.deleted_at') ?>
                                </th>

                                <th>
                                    <?= lang('proveedores.fields.actions') ?>
                                </th>

                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- /.card -->

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


<?= $this->section('js') ?>
<script>

    /**
     * Cargamos la tabla
     */

    var tableProveedores = $('#tableProveedores').DataTable({
        processing: true,
        serverSide: true,
        responsive: true,
        autoWidth: false,
        order: [[1, 'asc']],

        ajax: {
            url: '<?= base_url('admin/proveedores') ?>',
            method: 'GET',
            dataType: "json"
        },
        columnDefs: [{
                orderable: false,
                targets: [11],
                searchable: false,
                targets: [11]

            }],
        columns: [{
                'data': 'id'
            },

            {
                'data': 'nombreEmpresa'
            },

            {
                'data': 'firstname'
            },

            {
                'data': 'lastname'
            },

            {
                'data': 'taxID'
            },

            {
                'data': 'email'
            },

            {
                'data': 'direction'
            },

            {
                'data': 'birthdate'
            },

            {
                'data': 'created_at'
            },

            {
                'data': 'updated_at'
            },

            {
                'data': 'deleted_at'
            },

            {
                "data": function (data) {
                    return `<td class="text-right py-0 align-middle">
                         <div class="btn-group btn-group-sm">
                             <button class="btn btn-warning btnEditProveedores" data-toggle="modal" idProveedor="${data.id}" data-target="#modalAddProveedores">  <i class=" fa fa-edit"></i></button>
                             <button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
                         </div>
                         </td>`
                }
            }
        ]
    });







    /**
     * Carga datos actualizar
     */


    /*=============================================
     EDITAR Proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btnEditProveedores", function () {

        var idProveedor = $(this).attr("idProveedor");

        var datos = new FormData();
        datos.append("idProveedor", idProveedor);

        $.ajax({

            url: "<?= base_url('admin/proveedores/getProveedores') ?>",
            method: "POST",
            data: datos,
            cache: false,
            contentType: false,
            processData: false,
            dataType: "json",
            success: function (respuesta) {

                $("#idProveedor").val(respuesta["id"]);
                $("#idEmpresaProveedor").val(respuesta["idEmpresa"]);
                $("#idEmpresaProveedor").trigger("change");
                $("#firstname").val(respuesta["firstname"]);
                $("#razonSocial").val(respuesta["razonSocial"]);
                $("#lastname").val(respuesta["lastname"]);
                $("#taxID").val(respuesta["taxID"]);
                $("#email").val(respuesta["email"]);
                $("#direction").val(respuesta["direction"]);
                $("#birthdate").val(respuesta["birthdate"]);

                $("#formaPago").val(respuesta["formaPago"]);
                $("#formaPago").trigger("change");
                $("#metodoPago").val(respuesta["metodoPago"]);
                $("#metodoPago").trigger("change");
                $("#usoCFDI").val(respuesta["usoCFDI"]);
                $("#usoCFDI").trigger("change");

                $("#codigoPostal").val(respuesta["codigoPostal"]);
                $("#regimenFiscal").val(respuesta["regimenFiscal"]);
                $("#regimenFiscal").trigger("change");

            }

        })

    })

    $("#idEmpresaProveedor ").select2();
    /*=============================================
     ELIMINAR proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btn-delete", function () {

        var idProveedores = $(this).attr("data-id");

        Swal.fire({
            title: '<?= lang('boilerplate.global.sweet.title') ?>',
            text: "<?= lang('boilerplate.global.sweet.text') ?>",
            icon: 'warning',
            showCancelButton: true,
            confirmButtonColor: '#3085d6',
            cancelButtonColor: '#d33',
            confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
        })
                .then((result) => {
                    if (result.value) {
                        $.ajax({
                            url: `<?= base_url('admin/proveedores') ?>/` + idProveedores,
                            method: 'DELETE',
                        }).done((data, textStatus, jqXHR) => {
                            Toast.fire({
                                icon: 'success',
                                title: jqXHR.statusText,
                            });


                            tableProveedores.ajax.reload();
                        }).fail((error) => {
                            Toast.fire({
                                icon: 'error',
                                title: error.responseJSON.messages.error,
                            });
                        })
                    }
                })
    })

    $(function () {
        $("#modalAddProveedores").draggable();

    });


</script>
<?= $this->endSection() ?>

Creamos el archivo de lenguaje en español en App/Languaje/es/proveedores.php con el siguiente código.

 <?php
    $proveedores["logDescription"] = "El registro en proveedores fue guardado con los siguientes datos:";
    $proveedores["logUpdate"] = "El registro en proveedores fue actualizado con los siguientes datos:";
    $proveedores["logDeleted"] = "El registro en proveedores fue eliminado con los siguientes datos:";
    $proveedores["msg_delete"] = "El Registro en clieproveedoresntes fue eliminado correctamente:";
    $proveedores["add"] = "Agregar Proveedor";
    $proveedores["edit"] = "Editar Proveedor";
    $proveedores["createEdit"] = "Crear / Editar";
    $proveedores["title"] = "Admon. Proveedores";
    $proveedores["subtitle"] = "Lista de Proveedores";
    $proveedores["fields"]["firstname"] = "Nombre";
    $proveedores["fields"]["lastname"] = "Apellido";
    $proveedores["fields"]["taxID"] = "RFC";
    $proveedores["fields"]["email"] = "Correo Electronico";
    $proveedores["fields"]["direction"] = "Direccion";
    $proveedores["fields"]["birthdate"] = "Fecha de nacimiento";
    $cusproveedorestumers["fields"]["created_at"] = "Fecha de creacion";
    $proveedores["fields"]["updated_at"] = "Ultima modificacion";
    $proveedores["fields"]["deleted_at"] = "Fecha de eliminacion";

    $proveedores["fields"]["actions"] = "Acciones";
    $proveedores["msg"]["msg_insert"] = "Registro agregado correctamente.";
    $proveedores["msg"]["msg_update"] = "Registro modificado correctamente.";
    $proveedores["msg"]["msg_delete"] = "Registro eliminado correctamente.";
    $proveedores["msg"]["msg_get"] = "Registro obtenido correctamente.";
    $proveedores["msg"]["msg_get_fail"] = "Registro no encontrado o eliminado.";
    return $proveedores;

Creamos el archivo de lenguaje en ingles en App/Languaje/en/proveedores.php con el siguiente código.

 <?php

$proveedores["logDescription"] = "The custumers was saved with the following data:";
$proveedores["logUpdate"] = "The custumers was updated  with the following data:";
$proveedores["logDeleted"] = "The custumers was deleted  with the following data:";
$proveedores["msg_delete"] = "The custumers was deleted  correctly:";

$proveedores["add"] = "Add Vendor";
$proveedores["edit"] = "Edit Vendor";
$proveedores["createEdit"] = "Create / Edit";
$proveedores["title"] = "Vendors management";
$proveedores["subtitle"] = "Vendors list";
$proveedores["fields"]["firstname"] = "Firstname";
$proveedores["fields"]["lastname"] = "Lastname";
$proveedores["fields"]["taxID"] = "TaxID";
$proveedores["fields"]["email"] = "Email";
$proveedores["fields"]["direction"] = "Direction";
$proveedores["fields"]["birthdate"] = "Birthdate";
$proveedores["fields"]["created_at"] = "Created_at";
$proveedores["fields"]["updated_at"] = "Updated_at";
$proveedores["fields"]["deleted_at"] = "Deleted_at";

$proveedores["fields"]["actions"] = "Actions";
$proveedores["msg"]["msg_insert"] = "The Vendor has been correctly added.";
$proveedores["msg"]["msg_update"] = "The Vendor has been correctly modified.";
$proveedores["msg"]["msg_delete"] = "The Vendor has been correctly deleted.";
$proveedores["msg"]["msg_get"] = "The Vendor has been successfully get.";
$proveedores["msg"]["msg_get_fail"] = "The Vendor not found or already deleted.";

return $proveedores;
        

En App/Config/Routes.php en el grupo admin agregamos las siguientes rutas

    $routes->resource('proveedores', [
        'filter' => 'permission:proveedores-permission',
        'controller' => 'ProveedoresController',
        'except' => 'show'
    ]);
    $routes->post('proveedores/save', 'ProveedoresController::save');
    $routes->post('proveedores/getProveedores', 'ProveedoresController::getProveedores');
    $routes->post('proveedores/getProveedoresAjax', 'ProveedoresController::getProveedoresAjax');

Creamos el menú de proveedores tal cual se ve en la imagen

Creamos el permiso y lo asignamos al rol correspondiente

Y listo ya tenemos nuestro catalogo de proveedores

Video demostrativo

Creando CRUD de clientes #06

Ya vimos como usar AutoCrud para crear los catálogos, en esta ocasión tambien usamos autocrud, aun así dejaremos el código fuente completo de este modulo

Creamos el archivo modelo al app/models/CustumersModel.php con el siguiente contenido

Leer Mas: Creando CRUD de clientes #06
<?php
namespace App\Models;
use CodeIgniter\Model;
class CustumersModel extends Model{
    protected $table      = 'custumers';
    protected $primaryKey = 'id';
    protected $useAutoIncrement = true;
    protected $returnType     = 'array';
    protected $useSoftDeletes = true;
    protected $allowedFields = ['id','firstname','lastname','taxID','email','direction','birthdate','created_at','updated_at','deleted_at'];
    protected $useTimestamps = true;
    protected $createdField  = 'created_at';
    protected $deletedField  = 'deleted_at';
    protected $validationRules    =  [
    ];
    protected $validationMessages = [];
    protected $skipValidation     = false;
}
        

Creamos nuestro archivo controlador app/controllers/CustumersControllers.php

<?php
 namespace App\Controllers;
 use App\Controllers\BaseController;
 use \App\Models\{CustumersModel};
 use App\Models\LogModel;
 use CodeIgniter\API\ResponseTrait;
 class CustumersController extends BaseController {
     use ResponseTrait;
     protected $log;
     protected $custumers;
     public function __construct() {
         $this->custumers = new CustumersModel();
         $this->log = new LogModel();
         helper('menu');
         helper('utilerias');
     }
     public function index() {
         if ($this->request->isAJAX()) {
             $datos = $this->custumers->select('id,firstname,lastname,taxID,email,direction,birthdate,created_at,updated_at,deleted_at')->where('deleted_at', null);
             return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
         }


         $fechaActual =  fechaMySQLADateTimeHTML5(fechaHoraActual());

         $titulos["title"] = lang('custumers.title');
         $titulos["subtitle"] = lang('custumers.subtitle');
         $titulos["fecha"] = $fechaActual;
         return view('custumers', $titulos);
     }
     /**
      * Read Custumers
      */
     public function getCustumers() {
         $idCustumers = $this->request->getPost("idCustumers");
         $datosCustumers = $this->custumers->find($idCustumers);
         echo json_encode($datosCustumers);
     }
     /**
      * Save or update Custumers
      */
     public function save() {
         helper('auth');
         $userName = user()->username;
         $idUser = user()->id;
         $datos = $this->request->getPost();
         if ($datos["idCustumers"] == 0) {
             try {
                 if ($this->custumers->save($datos) === false) {
                     $errores = $this->custumers->errors();
                     foreach ($errores as $field => $error) {
                         echo $error . " ";
                     }
                     return;
                 }
                 $dateLog["description"] = lang("vehicles.logDescription") . json_encode($datos);
                 $dateLog["user"] = $userName;
                 $this->log->save($dateLog);
                 echo "Guardado Correctamente";
             } catch (\PHPUnit\Framework\Exception $ex) {
                 echo "Error al guardar " . $ex->getMessage();
             }
         } else {
             if ($this->custumers->update($datos["idCustumers"], $datos) == false) {
                 $errores = $this->custumers->errors();
                 foreach ($errores as $field => $error) {
                     echo $error . " ";
                 }
                 return;
             } else {
                 $dateLog["description"] = lang("custumers.logUpdated") . json_encode($datos);
                 $dateLog["user"] = $userName;
                 $this->log->save($dateLog);
                 echo "Actualizado Correctamente";
                 return;
             }
         }
         return;
     }
     /**
      * Delete Custumers
      * @param type $id
      * @return type
      */
     public function delete($id) {
         $infoCustumers = $this->custumers->find($id);
         helper('auth');
         $userName = user()->username;
         if (!$found = $this->custumers->delete($id)) {
             return $this->failNotFound(lang('custumers.msg.msg_get_fail'));
         }
         $this->custumers->purgeDeleted();
         $logData["description"] = lang("custumers.logDeleted") . json_encode($infoCustumers);
         $logData["user"] = $userName;
         $this->log->save($logData);
         return $this->respondDeleted($found, lang('custumers.msg_delete'));
     }
 }
        

Creamos nuestro archivo de la visa en app/views/custumers.php con el siguiente contenido

<?= $this->include('julio101290\boilerplate\Views\load\select2') ?>
<?= $this->include('julio101290\boilerplate\Views\load\datatables') ?>
<?= $this->include('julio101290\boilerplate\Views\load\nestable') ?>
<!-- Extend from layout index -->
<?= $this->extend('julio101290\boilerplate\Views\layout\index') ?>

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

<?= $this->include('modulesCustumers/modalCaptureCustumers') ?>

<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
 <div class="card-header">
     <div class="float-right">
         <div class="btn-group">

             <button class="btn btn-primary btnAddCustumers" data-toggle="modal" data-target="#modalAddCustumers"><i class="fa fa-plus"></i>

                 <?= lang('custumers.add') ?>

             </button>

         </div>
     </div>
 </div>
 <div class="card-body">
     <div class="row">
         <div class="col-md-12">
             <div class="table-responsive">
                 <table id="tableCustumers" class="table table-striped table-hover va-middle tableCustumers">
                     <thead>
                         <tr>

                             <th>#</th>
                             <th><?= lang('custumers.fields.firstname') ?></th>
<th><?= lang('custumers.fields.lastname') ?></th>
<th><?= lang('custumers.fields.taxID') ?></th>
<th><?= lang('custumers.fields.email') ?></th>
<th><?= lang('custumers.fields.direction') ?></th>
<th><?= lang('custumers.fields.birthdate') ?></th>
<th><?= lang('custumers.fields.created_at') ?></th>
<th><?= lang('custumers.fields.updated_at') ?></th>
<th><?= lang('custumers.fields.deleted_at') ?></th>

                             <th><?= lang('custumers.fields.actions') ?> </th>

                         </tr>
                     </thead>
                     <tbody>
                     </tbody>
                 </table>
             </div>
         </div>
     </div>
 </div>
</div>
<!-- /.card -->

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


<?= $this->section('js') ?>
<script>

 /**
  * Cargamos la tabla
  */

 var tableCustumers = $('#tableCustumers').DataTable({
     processing: true,
     serverSide: true,
     responsive: true,
     autoWidth: false,
     order: [[1, 'asc']],

     ajax: {
         url: '<?= base_url(route_to('admin/custumers')) ?>',
         method: 'GET',
         dataType: "json"
     },
     columnDefs: [{
             orderable: false,
             targets: [10],
             searchable: false,
             targets: [10]

         }],
     columns: [{
             'data': 'id'
         },
        
          
{
    'data': 'firstname'
},
 
{
    'data': 'lastname'
},
 
{
    'data': 'taxID'
},
 
{
    'data': 'email'
},
 
{
    'data': 'direction'
},
 
{
    'data': 'birthdate'
},
 
{
    'data': 'created_at'
},
 
{
    'data': 'updated_at'
},
 
{
    'data': 'deleted_at'
},

         {
             "data": function (data) {
                 return `<td class="text-right py-0 align-middle">
                         <div class="btn-group btn-group-sm">
                             <button class="btn btn-warning btnEditCustumers" data-toggle="modal" idCustumers="${data.id}" data-target="#modalAddCustumers">  <i class=" fa fa-edit"></i></button>
                             <button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
                         </div>
                         </td>`
             }
         }
     ]
 });



 $(document).on('click', '#btnSaveCustumers', function (e) {

     
var idCustumers = $("#idCustumers").val();
var firstname = $("#firstname").val();
var lastname = $("#lastname").val();
var taxID = $("#taxID").val();
var email = $("#email").val();
var direction = $("#direction").val();
var birthdate = $("#birthdate").val();

     $("#btnSaveCustumers").attr("disabled", true);

     var datos = new FormData();
    datos.append("idCustumers", idCustumers);
    datos.append("firstname", firstname);
    datos.append("lastname", lastname);
    datos.append("taxID", taxID);
    datos.append("email", email);
    datos.append("direction", direction);
    datos.append("birthdate", birthdate);


     $.ajax({

         url: "<?= route_to('admin/custumers/save') ?>",
         method: "POST",
         data: datos,
         cache: false,
         contentType: false,
         processData: false,
         success: function (respuesta) {
             if (respuesta.match(/Correctamente.*/)) {
        
                 Toast.fire({
                     icon: 'success',
                     title: "Guardado Correctamente"
                 });

                 tableCustumers.ajax.reload();
                 $("#btnSaveCustumers").removeAttr("disabled");


                 $('#modalAddCustumers').modal('hide');
             } else {

                 Toast.fire({
                     icon: 'error',
                     title: respuesta
                 });

                 $("#btnSaveCustumers").removeAttr("disabled");
                

             }

         }

     }

     )

 });



 /**
  * Carga datos actualizar
  */


 /*=============================================
  EDITAR Custumers
  =============================================*/
 $(".tableCustumers").on("click", ".btnEditCustumers", function () {

     var idCustumers = $(this).attr("idCustumers");
        
     var datos = new FormData();
     datos.append("idCustumers", idCustumers);

     $.ajax({

         url: "<?= base_url(route_to('admin/custumers/getCustumers')) ?>",
         method: "POST",
         data: datos,
         cache: false,
         contentType: false,
         processData: false,
         dataType: "json",
         success: function (respuesta) {
             $("#idCustumers").val(respuesta["id"]);
             
             $("#firstname").val(respuesta["firstname"]);
$("#lastname").val(respuesta["lastname"]);
$("#taxID").val(respuesta["taxID"]);
$("#email").val(respuesta["email"]);
$("#direction").val(respuesta["direction"]);
$("#birthdate").val(respuesta["birthdate"]);


         }

     })

 })


 /*=============================================
  ELIMINAR custumers
  =============================================*/
 $(".tableCustumers").on("click", ".btn-delete", function () {

     var idCustumers = $(this).attr("data-id");

     Swal.fire({
         title: '<?= lang('boilerplate.global.sweet.title') ?>',
         text: "<?= lang('boilerplate.global.sweet.text') ?>",
         icon: 'warning',
         showCancelButton: true,
         confirmButtonColor: '#3085d6',
         cancelButtonColor: '#d33',
         confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
     })
             .then((result) => {
                 if (result.value) {
                     $.ajax({
                         url: `<?= base_url(route_to('admin/custumers')) ?>/` + idCustumers,
                         method: 'DELETE',
                     }).done((data, textStatus, jqXHR) => {
                         Toast.fire({
                             icon: 'success',
                             title: jqXHR.statusText,
                         });


                         tableCustumers.ajax.reload();
                     }).fail((error) => {
                         Toast.fire({
                             icon: 'error',
                             title: error.responseJSON.messages.error,
                         });
                     })
                 }
             })
 })

 $(function () {
    $("#modalAddCustumers").draggable();
    
});


</script>
<?= $this->endSection() ?>
        

Para el modal creamos el siguiente archivo app/views/modulesCustumers/modalCaptureCustumers.php con el siguiente contenido

<!-- Modal Custumers -->
  <div class="modal fade" id="modalAddCustumers" tabindex="-1" role="dialog" aria-labelledby="modalAddCustumers" aria-hidden="true">
      <div class="modal-dialog modal-lg" role="document">
          <div class="modal-content">
              <div class="modal-header">
                  <h5 class="modal-title"><?= lang('custumers.createEdit') ?></h5>
                  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                      <span aria-hidden="true">&times;</span>
                  </button>
              </div>
              <div class="modal-body">
                  <form id="form-custumers" class="form-horizontal">
                      <input type="hidden" id="idCustumers" name="idCustumers" value="0">

                      <div class="form-group row">
    <label for="firstname" class="col-sm-2 col-form-label"><?= lang('custumers.fields.firstname') ?></label>
    <div class="col-sm-10">
        <div class="input-group">
            <div class="input-group-prepend">
                <span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
            </div>
            <input type="text" name="firstname" id="firstname" class="form-control <?= session('error.firstname') ? 'is-invalid' : '' ?>" value="<?= old('firstname') ?>" placeholder="<?= lang('custumers.fields.firstname') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="lastname" class="col-sm-2 col-form-label"><?= lang('custumers.fields.lastname') ?></label>
    <div class="col-sm-10">
        <div class="input-group">
            <div class="input-group-prepend">
                <span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
            </div>
            <input type="text" name="lastname" id="lastname" class="form-control <?= session('error.lastname') ? 'is-invalid' : '' ?>" value="<?= old('lastname') ?>" placeholder="<?= lang('custumers.fields.lastname') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="taxID" class="col-sm-2 col-form-label"><?= lang('custumers.fields.taxID') ?></label>
    <div class="col-sm-10">
        <div class="input-group">
            <div class="input-group-prepend">
                <span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
            </div>
            <input type="text" name="taxID" id="taxID" class="form-control <?= session('error.taxID') ? 'is-invalid' : '' ?>" value="<?= old('taxID') ?>" placeholder="<?= lang('custumers.fields.taxID') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="email" class="col-sm-2 col-form-label"><?= lang('custumers.fields.email') ?></label>
    <div class="col-sm-10">
        <div class="input-group">
            <div class="input-group-prepend">
                <span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
            </div>
            <input type="text" name="email" id="email" class="form-control <?= session('error.email') ? 'is-invalid' : '' ?>" value="<?= old('email') ?>" placeholder="<?= lang('custumers.fields.email') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="direction" class="col-sm-2 col-form-label"><?= lang('custumers.fields.direction') ?></label>
    <div class="col-sm-10">
        <div class="input-group">
            <div class="input-group-prepend">
                <span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
            </div>
            <input type="text" name="direction" id="direction" class="form-control <?= session('error.direction') ? 'is-invalid' : '' ?>" value="<?= old('direction') ?>" placeholder="<?= lang('custumers.fields.direction') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="birthdate" class="col-sm-2 col-form-label"><?= lang('custumers.fields.birthdate') ?></label>
    <div class="col-sm-10">
        <div class="input-group">
            <div class="input-group-prepend">
                <span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
            </div>
            
            <input type="datetime-local" name="birthdate" id="birthdate" class="form-control <?= session('error.birthdate') ? 'is-invalid' : '' ?>" value="<?= $fecha ?>" placeholder="<?= lang('custumers.fields.birthdate') ?>" autocomplete="off">
        </div>
    </div>
</div>

        
                  </form>
              </div>
              <div class="modal-footer">
                  <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal"><?= lang('boilerplate.global.close') ?></button>
                  <button type="button" class="btn btn-primary btn-sm" id="btnSaveCustumers"><?= lang('boilerplate.global.save') ?></button>
              </div>
          </div>
      </div>
  </div>

  <?= $this->section('js') ?>


  <script>

      $(document).on('click', '.btnAddCustumers', function (e) {


          $(".form-control").val("");

          $("#idCustumers").val("0");

          $("#birthdate").val("<?= $fecha ?>");

          $("#btnSaveCustumers").removeAttr("disabled");

      });

      /* 
       * AL hacer click al editar
       */



      $(document).on('click', '.btnEditCustumers', function (e) {


          var idCustumers = $(this).attr("idCustumers");

          //LIMPIAMOS CONTROLES
        $(".form-control").val("");

          $("#idCustumers").val(idCustumers);
          $("#btnGuardarCustumers").removeAttr("disabled");

      });




  </script>


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

Para la traducción en ingles creamos el archivo app/languaje/es/custumers.php con el siguiente contenido

 <?php

$custumers["logDescription"] = "The custumers was saved with the following data:";
$custumers["logUpdate"] = "The custumers was updated  with the following data:";
$custumers["logDeleted"] = "The custumers was deleted  with the following data:";
$custumers["msg_delete"] = "The custumers was deleted  correctly:";

$custumers["add"] = "Add Custumers";
$custumers["edit"] = "Edit custumers";
$custumers["createEdit"] = "Create / Edit";
$custumers["title"] = "custumers management";
$custumers["subtitle"] = "custumers list";
$custumers["fields"]["firstname"] = "Firstname";
$custumers["fields"]["lastname"] = "Lastname";
$custumers["fields"]["taxID"] = "TaxID";
$custumers["fields"]["email"] = "Email";
$custumers["fields"]["direction"] = "Direction";
$custumers["fields"]["birthdate"] = "Birthdate";
$custumers["fields"]["created_at"] = "Created_at";
$custumers["fields"]["updated_at"] = "Updated_at";
$custumers["fields"]["deleted_at"] = "Deleted_at";

$custumers["fields"]["actions"] = "Actions";
$custumers["msg"]["msg_insert"] = "The custumers has been correctly added.";
$custumers["msg"]["msg_update"] = "The custumers has been correctly modified.";
$custumers["msg"]["msg_delete"] = "The custumers has been correctly deleted.";
$custumers["msg"]["msg_get"] = "The Custumers has been successfully get.";
$custumers["msg"]["msg_get_fail"] = "The custumers not found or already deleted.";

return $custumers;
        

Para nuestra traduccion en español creamos el archivo app/languaje/es/custumers.php

 <?php
$custumers["logDescription"] = "El registro en clientes fue guardado con los siguientes datos:";
$custumers["logUpdate"] = "El registro en clientes fue actualizado con los siguientes datos:";
$custumers["logDeleted"] = "El registro en clientes fue eliminado con los siguientes datos:";
$custumers["msg_delete"] = "El Registro en clientes fue eliminado correctamente:";
$custumers["add"] = "Agregar Cliente";
$custumers["edit"] = "Editar Cliente";
$custumers["createEdit"] = "Crear / Editar";
$custumers["title"] = "Admon. Clientes";
$custumers["subtitle"] = "Lista de Clientes";
$custumers["fields"]["firstname"] = "Nombre";
$custumers["fields"]["lastname"] = "Apellido";
$custumers["fields"]["taxID"] = "RFC";
$custumers["fields"]["email"] = "Correo Electronico";
$custumers["fields"]["direction"] = "Direccion";
$custumers["fields"]["birthdate"] = "Fecha de nacimiento";
$custumers["fields"]["created_at"] = "Fecha de creacion";
$custumers["fields"]["updated_at"] = "Ultima modificacion";
$custumers["fields"]["deleted_at"] = "Fecha de eliminacion";

 $custumers["fields"]["actions"] = "Acciones";       
$custumers["msg"]["msg_insert"] = "Registro agregado correctamente.";
$custumers["msg"]["msg_update"] = "Registro modificado correctamente.";
$custumers["msg"]["msg_delete"] = "Registro eliminado correctamente.";
$custumers["msg"]["msg_get"] = "Registro obtenido correctamente.";
$custumers["msg"]["msg_get_fail"] = "Registro no encontrado o eliminado.";
return $custumers;
        

Creamos nuestro archivo de migración en app/databases/migrations/2023-04-21063335_Custumers.php con el siguiente contenido

<?php
    namespace App\Database\Migrations;
    use CodeIgniter\Database\Migration;
    class Custumers extends Migration
    {
    public function up()
    {
     // Custumers
    $this->forge->addField([
        'id'                    => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
        'firstname'             => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
        'lastname'             => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
        'taxID'             => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
        'email'             => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
        'direction'             => ['type' => 'varchar', 'constraint' => 1024, 'null' => true],
        'birthdate'             => ['type' => 'datetime' , 'null' => true],
        'created_at'       => ['type' => 'datetime', 'null' => true],
        'updated_at'       => ['type' => 'datetime', 'null' => true],
        'deleted_at'       => ['type' => 'datetime', 'null' => true],
    ]);
    $this->forge->addKey('id', true);
    $this->forge->createTable('custumers', true);
    }
    public function down(){
        $this->forge->dropTable('custumers', true);
        }
    }

Corremos el comando php serve migrate para levantar la tabla custumers

Listo ya solo queda configurar los permisos y menú

Demostración en video

Creando CRUD de categorías usando AutoCrud #05

Ya vimos como crear módulos y catalogo ahora mostraremos como automatizar esa parte del proceso de desarrollo para ser un poco mas eficientes para ello escribimos un código que escribe el código repetitivo

Creamos el archivo app/controller/AutoCrudController.php con el siguiente código

Leer Mas: Creando CRUD de categorías usando AutoCrud #05
<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use App\Controllers\Time;
use CodeIgniter\API\ResponseTrait;
use Faker\Provider\zh_CN\DateTime;

class AutoCrudController extends BaseController {

    use ResponseTrait;

    protected $db;

    public function __construct() {
        $this->db = \Config\Database::connect();
        helper('utilerias');
    }

    public function index($table) {
     /*
       $this->generateModel($table);
       $this->generateController($table);
       $this->generateView($table);
       $this->generateViewModal($table);
       $this->generateLanguage($table);
        */
        $this->generateMigration($table);
       
     //$this->generateLanguageES($table);

        $tableUpCase = ucfirst($table);
        $route = <<<EOF
                 \$routes->resource('$table', [
                                'filter' => 'permission:$table-permission',
                                'controller' => '{$table}Controller',
                                'except' => 'show'
                            ]);
                \$routes->post('$table/save', '{$tableUpCase}Controller::save');
                \$routes->post('{$table}/get{$tableUpCase}', '{$tableUpCase}Controller::get$tableUpCase');
        EOF;

        echo $route;
    }

    /**
     * Generate Model
     */
    public function generateModel($table) {

        $tableUpCase = ucfirst($table);
        $query = $this->db->getFieldNames($table);

        $fields = "";

        foreach ($query as $field) {
            $fields .= "'" . $field . "'" . ",";
        }


        $fields = substr($fields, 0, strlen($fields) - 1);

        $nombreClase = ucfirst($table) . "Model";

        $model = <<<EOF
        <?php
        namespace App\Models;
        use CodeIgniter\Model;
        class $nombreClase extends Model{
            protected \$table      = '$table';
            protected \$primaryKey = 'id';
            protected \$useAutoIncrement = true;
            protected \$returnType     = 'array';
            protected \$useSoftDeletes = true;
            protected \$allowedFields = [$fields];
            protected \$useTimestamps = true;
            protected \$createdField  = 'created_at';
            protected \$deletedField  = 'deleted_at';
            protected \$validationRules    =  [
            ];
            protected \$validationMessages = [];
            protected \$skipValidation     = false;
        }
                
        EOF;

        file_put_contents(ROOTPATH . "app/Models/$nombreClase.php", $model);
    }

    /**
     * Generate Controller
     * 
     */

    /**
     * Generate Controller
     */
    public function generateController($table) {

        $query = $this->db->getFieldNames($table);

        $fields = "";

        foreach ($query as $field) {
            $fields .= $field . ",";
        }


        $fields = substr($fields, 0, strlen($fields) - 1);

        $nameClassModel = ucfirst($table) . "Model";

        $tableUpCase = ucfirst($table);

        $controller = <<<EOF
        <?php
         namespace App\Controllers;
         use App\Controllers\BaseController;
         use \App\Models\{$nameClassModel};
         use App\Models\LogModel;
         use CodeIgniter\API\ResponseTrait;
         class {$tableUpCase}Controller extends BaseController {
             use ResponseTrait;
             protected \$log;
             protected $$table;
             public function __construct() {
                 \$this->$table = new $nameClassModel();
                 \$this->log = new LogModel();
                 helper('menu');
             }
             public function index() {
                 if (\$this->request->isAJAX()) {
                     \$datos = \$this->{$table}->select('$fields')->where('deleted_at', null);
                     return \Hermawan\DataTables\DataTable::of(\$datos)->toJson(true);
                 }
                 \$titulos["title"] = lang('$table.title');
                 \$titulos["subtitle"] = lang('$table.subtitle');
                 return view('$table', \$titulos);
             }
             /**
              * Read $tableUpCase
              */
             public function get$tableUpCase() {
                 \$id$tableUpCase = \$this->request->getPost("id$tableUpCase");
                 \$datos$tableUpCase = \$this->{$table}->find(\$id$tableUpCase);
                 echo json_encode(\$datos$tableUpCase);
             }
             /**
              * Save or update $tableUpCase
              */
             public function save() {
                 helper('auth');
                 \$userName = user()->username;
                 \$idUser = user()->id;
                 \$datos = \$this->request->getPost();
                 if (\$datos["id$tableUpCase"] == 0) {
                     try {
                         if (\$this->{$table}->save(\$datos) === false) {
                             \$errores = \$this->{$table}->errors();
                             foreach (\$errores as \$field => \$error) {
                                 echo \$error . " ";
                             }
                             return;
                         }
                         \$dateLog["description"] = lang("vehicles.logDescription") . json_encode(\$datos);
                         \$dateLog["user"] = \$userName;
                         \$this->log->save(\$dateLog);
                         echo "Guardado Correctamente";
                     } catch (\PHPUnit\Framework\Exception \$ex) {
                         echo "Error al guardar " . \$ex->getMessage();
                     }
                 } else {
                     if (\$this->{$table}->update(\$datos["id$tableUpCase"], \$datos) == false) {
                         \$errores = \$this->{$table}->errors();
                         foreach (\$errores as \$field => \$error) {
                             echo \$error . " ";
                         }
                         return;
                     } else {
                         \$dateLog["description"] = lang("$table.logUpdated") . json_encode(\$datos);
                         \$dateLog["user"] = \$userName;
                         \$this->log->save(\$dateLog);
                         echo "Actualizado Correctamente";
                         return;
                     }
                 }
                 return;
             }
             /**
              * Delete $tableUpCase
              * @param type \$id
              * @return type
              */
             public function delete(\$id) {
                 \$info$tableUpCase = \$this->{$table}->find(\$id);
                 helper('auth');
                 \$userName = user()->username;
                 if (!\$found = \$this->{$table}->delete(\$id)) {
                     return \$this->failNotFound(lang('$table.msg.msg_get_fail'));
                 }
                 \$this->{$table}->purgeDeleted();
                 \$logData["description"] = lang("{$table}.logDeleted") . json_encode(\$info$tableUpCase);
                 \$logData["user"] = \$userName;
                 \$this->log->save(\$logData);
                 return \$this->respondDeleted(\$found, lang('$table.msg_delete'));
             }
         }
                
        EOF;

        file_put_contents(ROOTPATH . "app/Controllers/{$tableUpCase}Controller.php", $controller);
    }

    /**
     * Generate View
     */
    public function generateView($table) {

        $tableUpCase = ucfirst($table);
        $query = $this->db->getFieldNames($table);

        $fields = "";

        $columnaDatatable = "";
        $datosDatatable = "";
        $variablesGuardar1 = "";
        $variablesFormData = "";
        $inputsEdit = "";
        $contador = 0;
        foreach ($query as $field) {
            $fields .= $field . ",";

            if ($contador > 0) {

                $columnaDatatable .= "<th><?= lang('$table.fields.$field') ?></th>" . PHP_EOL;

                $datosDatatable .= <<<EOF
                         
                        {
                            'data': '$field'
                        },
                        EOF . PHP_EOL;
                if ($field <> "created_at" && $field <> "updated_at" && $field <> "deleted_at") {
                    $variablesGuardar1 .= "var $field = $(\"#$field\").val();" . PHP_EOL;
                    $variablesFormData .= "datos.append(\"$field\", $field);" . PHP_EOL;
                    $inputsEdit .= "$(\"#$field\").val(respuesta[\"$field\"]);" . PHP_EOL;
                    ;
                }
            } else {
                $variablesGuardar1 .= <<<EOF
                    
                    var id$tableUpCase = $("#id$tableUpCase").val();
                    EOF . PHP_EOL;

                $variablesFormData .= <<<EOF
                        var datos = new FormData();
                        datos.append("id$tableUpCase", id$tableUpCase);
                        EOF . PHP_EOL;
            }
            $contador++;
        }
        $fields = substr($fields, 0, strlen($fields) - 1);
        $nameClassModel = ucfirst($table) . "Model";
        $view = <<<EOF
        <?= \$this->include('julio101290\boilerplate\Views\load\select2') ?>
        <?= \$this->include('julio101290\boilerplate\Views\load\datatables') ?>
        <?= \$this->include('julio101290\boilerplate\Views\load\\nestable') ?>
        <!-- Extend from layout index -->
        <?= \$this->extend('julio101290\boilerplate\Views\layout\index') ?>

        <!-- Section content -->
        <?= \$this->section('content') ?>

        <?= \$this->include('modules$tableUpCase/modalCapture$tableUpCase') ?>

        <!-- SELECT2 EXAMPLE -->
        <div class="card card-default">
         <div class="card-header">
             <div class="float-right">
                 <div class="btn-group">

                     <button class="btn btn-primary btnAdd$tableUpCase" data-toggle="modal" data-target="#modalAdd$tableUpCase"><i class="fa fa-plus"></i>

                         <?= lang('$table.add') ?>

                     </button>

                 </div>
             </div>
         </div>
         <div class="card-body">
             <div class="row">
                 <div class="col-md-12">
                     <div class="table-responsive">
                         <table id="table$tableUpCase" class="table table-striped table-hover va-middle table$tableUpCase">
                             <thead>
                                 <tr>

                                     <th>#</th>
                                     $columnaDatatable
                                     <th><?= lang('$table.fields.actions') ?> </th>

                                 </tr>
                             </thead>
                             <tbody>
                             </tbody>
                         </table>
                     </div>
                 </div>
             </div>
         </div>
        </div>
        <!-- /.card -->

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


        <?= \$this->section('js') ?>
        <script>

         /**
          * Cargamos la tabla
          */

         var table{$tableUpCase} = $('#table{$tableUpCase}').DataTable({
             processing: true,
             serverSide: true,
             responsive: true,
             autoWidth: false,
             order: [[1, 'asc']],

             ajax: {
                 url: '<?= base_url(route_to('admin/$table')) ?>',
                 method: 'GET',
                 dataType: "json"
             },
             columnDefs: [{
                     orderable: false,
                     targets: [$contador],
                     searchable: false,
                     targets: [$contador]

                 }],
             columns: [{
                     'data': 'id'
                 },
                
                 $datosDatatable
                 {
                     "data": function (data) {
                         return `<td class="text-right py-0 align-middle">
                                 <div class="btn-group btn-group-sm">
                                     <button class="btn btn-warning btnEdit$tableUpCase" data-toggle="modal" id$tableUpCase="\${data.id}" data-target="#modalAdd$tableUpCase">  <i class=" fa fa-edit"></i></button>
                                     <button class="btn btn-danger btn-delete" data-id="\${data.id}"><i class="fas fa-trash"></i></button>
                                 </div>
                                 </td>`
                     }
                 }
             ]
         });



         $(document).on('click', '#btnSave$tableUpCase', function (e) {

             $variablesGuardar1
             $("#btnSave$tableUpCase").attr("disabled", true);

             $variablesFormData

             $.ajax({

                 url: "<?= route_to('admin/$table/save') ?>",
                 method: "POST",
                 data: datos,
                 cache: false,
                 contentType: false,
                 processData: false,
                 success: function (respuesta) {
                     if (respuesta.match(/Correctamente.*/)) {
                
                         Toast.fire({
                             icon: 'success',
                             title: "Guardado Correctamente"
                         });

                         table$tableUpCase.ajax.reload();
                         $("#btnSave$tableUpCase").removeAttr("disabled");


                         $('#modalAdd$tableUpCase').modal('hide');
                     } else {

                         Toast.fire({
                             icon: 'error',
                             title: respuesta
                         });

                         $("#btnSave$tableUpCase").removeAttr("disabled");
                        

                     }

                 }

             }

             )

         });



         /**
          * Carga datos actualizar
          */


         /*=============================================
          EDITAR $tableUpCase
          =============================================*/
         $(".table$tableUpCase").on("click", ".btnEdit$tableUpCase", function () {

             var id$tableUpCase = $(this).attr("id$tableUpCase");
                
             var datos = new FormData();
             datos.append("id$tableUpCase", id$tableUpCase);

             $.ajax({

                 url: "<?= base_url(route_to('admin/$table/get$tableUpCase')) ?>",
                 method: "POST",
                 data: datos,
                 cache: false,
                 contentType: false,
                 processData: false,
                 dataType: "json",
                 success: function (respuesta) {
                     $("#id$tableUpCase").val(respuesta["id"]);
                     
                     $inputsEdit

                 }

             })

         })


         /*=============================================
          ELIMINAR $table
          =============================================*/
         $(".table$tableUpCase").on("click", ".btn-delete", function () {

             var id$tableUpCase = $(this).attr("data-id");

             Swal.fire({
                 title: '<?= lang('boilerplate.global.sweet.title') ?>',
                 text: "<?= lang('boilerplate.global.sweet.text') ?>",
                 icon: 'warning',
                 showCancelButton: true,
                 confirmButtonColor: '#3085d6',
                 cancelButtonColor: '#d33',
                 confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
             })
                     .then((result) => {
                         if (result.value) {
                             $.ajax({
                                 url: `<?= base_url(route_to('admin/$table')) ?>/` + id$tableUpCase,
                                 method: 'DELETE',
                             }).done((data, textStatus, jqXHR) => {
                                 Toast.fire({
                                     icon: 'success',
                                     title: jqXHR.statusText,
                                 });


                                 table$tableUpCase.ajax.reload();
                             }).fail((error) => {
                                 Toast.fire({
                                     icon: 'error',
                                     title: error.responseJSON.messages.error,
                                 });
                             })
                         }
                     })
         })

         $(function () {
            $("#modalAdd$tableUpCase").draggable();
            
        });


        </script>
        <?= \$this->endSection() ?>
                
        EOF;

        file_put_contents(ROOTPATH . "app/Views/{$table}.php", $view);
    }

    /**
     * Generate ViewModal
     */
    public function generateViewModal($table) {

        $tableUpCase = ucfirst($table);
        $query = $this->db->getFieldNames($table);

        $fields = "";

        $campos = "";
        $contador = 0;
        foreach ($query as $field) {
            $fields .= $field . ",";

            if ($contador > 0) {




                if ($field <> "created_at" && $field <> "updated_at" && $field <> "deleted_at") {

                    $campos .= <<<EOF
                        <div class="form-group row">
                            <label for="$field" class="col-sm-2 col-form-label"><?= lang('$table.fields.$field') ?></label>
                            <div class="col-sm-10">
                                <div class="input-group">
                                    <div class="input-group-prepend">
                                        <span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
                                    </div>
                                    <input type="text" name="$field" id="$field" class="form-control <?= session('error.$field') ? 'is-invalid' : '' ?>" value="<?= old('$field') ?>" placeholder="<?= lang('$table.fields.$field') ?>" autocomplete="off">
                                </div>
                            </div>
                        </div>
                        EOF . PHP_EOL;
                }
            }




            $contador++;
        }


        $fields = substr($fields, 0, strlen($fields) - 1);

        $nameClassModel = ucfirst($table) . "Model";

        $viewModal = <<<EOF
        <!-- Modal $tableUpCase -->
          <div class="modal fade" id="modalAdd$tableUpCase" tabindex="-1" role="dialog" aria-labelledby="modalAdd$tableUpCase" aria-hidden="true">
              <div class="modal-dialog modal-lg" role="document">
                  <div class="modal-content">
                      <div class="modal-header">
                          <h5 class="modal-title"><?= lang('$table.createEdit') ?></h5>
                          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                              <span aria-hidden="true">&times;</span>
                          </button>
                      </div>
                      <div class="modal-body">
                          <form id="form-$table" class="form-horizontal">
                              <input type="hidden" id="id$tableUpCase" name="id$tableUpCase" value="0">

                              $campos
                
                          </form>
                      </div>
                      <div class="modal-footer">
                          <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal"><?= lang('boilerplate.global.close') ?></button>
                          <button type="button" class="btn btn-primary btn-sm" id="btnSave$tableUpCase"><?= lang('boilerplate.global.save') ?></button>
                      </div>
                  </div>
              </div>
          </div>

          <?= \$this->section('js') ?>


          <script>

              $(document).on('click', '.btnAdd$tableUpCase', function (e) {


                  $(".form-control").val("");

                  $("#id$tableUpCase").val("0");

                  $("#btnSave$tableUpCase").removeAttr("disabled");

              });

              /* 
               * AL hacer click al editar
               */



              $(document).on('click', '.btnEdit$tableUpCase', function (e) {


                  var id$tableUpCase = $(this).attr("id$tableUpCase");

                  //LIMPIAMOS CONTROLES
                  $(".form-control").val("");

                  $("#id$tableUpCase").val(id$tableUpCase);
                  $("#btnGuardar$tableUpCase").removeAttr("disabled");

              });




          </script>


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

        $path = ROOTPATH . "app/Views/modules$tableUpCase/";
        if (!is_dir($path))
            mkdir($path, 0777, TRUE);

        file_put_contents($path . "modalCapture{$tableUpCase}.php", $viewModal);
    }

    /**
     * Generate Languaje EN
     */
    public function generateLanguage($table) {

        $tableUpCase = ucfirst($table);
        $query = $this->db->getFieldNames($table);

        $fields = "";

        $campos = "";
        $contador = 0;
        foreach ($query as $field) {
            $fields .= $field . ",";

            if ($contador > 0) {






                $campos .= "\${$table}[\"fields\"][\"$field\"] = \"" . ucfirst($field) . "\";" . PHP_EOL;
            }




            $contador++;
        }


        $fields = substr($fields, 0, strlen($fields) - 1);

        $nameClassModel = ucfirst($table) . "Model";

        $languaje = <<<EOF
         <?php

        \${$table}["logDescription"] = "The $table was saved with the following data:";
        \${$table}["logUpdate"] = "The $table was updated  with the following data:";
        \${$table}["logDeleted"] = "The $table was deleted  with the following data:";
        \${$table}["msg_delete"] = "The $table was deleted  correctly:";

        \${$table}["add"] = "Add $tableUpCase";
        \${$table}["edit"] = "Edit $table";
        \${$table}["createEdit"] = "Create / Edit";
        \${$table}["title"] = "$table management";
        \${$table}["subtitle"] = "$table list";
        $campos
        \${$table}["fields"]["actions"] = "Actions";
        \${$table}["msg"]["msg_insert"] = "The $table has been correctly added.";
        \${$table}["msg"]["msg_update"] = "The $table has been correctly modified.";
        \${$table}["msg"]["msg_delete"] = "The $table has been correctly deleted.";
        \${$table}["msg"]["msg_get"] = "The $tableUpCase has been successfully get.";
        \${$table}["msg"]["msg_get_fail"] = "The $table not found or already deleted.";

        return $$table;
                
        EOF;

        $path = ROOTPATH . "app/Language/en/";
        if (!is_dir($path))
            mkdir($path, 0777, TRUE);

        file_put_contents($path . "$table.php", $languaje);
    }

    /**
     * Lenguaje ES
     * @param type $table
     */
    public function generateLanguageES($table) {

        $tableUpCase = ucfirst($table);
        $query = $this->db->getFieldNames($table);

        $fields = "";

        $campos = "";
        $contador = 0;
        foreach ($query as $field) {
            $fields .= $field . ",";

            if ($contador > 0) {


                $campos .= "\${$table}[\"fields\"][\"$field\"] = \"" . ucfirst($field) . "\";" . PHP_EOL;
            }




            $contador++;
        }


        $fields = substr($fields, 0, strlen($fields) - 1);

        $nameClassModel = ucfirst($table) . "Model";

        $languaje = <<<EOF
         <?php
        \${$table}["logDescription"] = "El registro en $table fue guardado con los siguientes datos:";
        \${$table}["logUpdate"] = "El registro en $table fue actualizado con los siguientes datos:";
        \${$table}["logDeleted"] = "El registro en $table fue eliminado con los siguientes datos:";
        \${$table}["msg_delete"] = "El Registro en $table fue eliminado correctamente:";
        \${$table}["add"] = "Agregar $tableUpCase";
        \${$table}["edit"] = "Editar $table";
        \${$table}["createEdit"] = "Crear / Editar";
        \${$table}["title"] = "Admon. $table";
        \${$table}["subtitle"] = "Lista $table";
        $campos
         \${$table}["fields"]["actions"] = "Acciones";       
        \${$table}["msg"]["msg_insert"] = "Registro agregado correctamente.";
        \${$table}["msg"]["msg_update"] = "Registro modificado correctamente.";
        \${$table}["msg"]["msg_delete"] = "Registro eliminado correctamente.";
        \${$table}["msg"]["msg_get"] = "Registro obtenido correctamente.";
        \${$table}["msg"]["msg_get_fail"] = "Registro no encontrado o eliminado.";
        return $$table;
                
        EOF;

        $path = ROOTPATH . "app/Language/es/";
        if (!is_dir($path))
            mkdir($path, 0777, TRUE);

        file_put_contents($path . "$table.php", $languaje);
    }

    /**
     * Generate Migration
     * @param type $table
     */
    public function generateMigration($table) {

        $tableUpCase = ucfirst($table);
        $query = $this->db->getFieldData($table);

        $campos = "";
        $contador = 0;
        foreach ($query as $field) {


            
            if ($contador > 0) {

                
                if($field->nullable==1){
                    
                    $nullable="true";
                    
                }   else{
                    
                    $nullable="false";
                    
                } 
                if ($field->name <> "created_at" && $field->name <> "updated_at" && $field->name <> "deleted_at") {
                    $campos .= "'{$field->name}'             => ['type' => '{$field->type}', 'constraint' => {$field->max_length}, 'null' => $nullable]," . PHP_EOL;
                }
            } else {

                    $campos .= "'id'                    => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true]," . PHP_EOL;
            }



            $contador++;
        }




        $nameClassModel = ucfirst($table) . "Model";

        $migration = <<<EOF
            <?php
            namespace App\Database\Migrations;
            use CodeIgniter\Database\Migration;
            class $tableUpCase extends Migration
            {
            public function up()
            {
             // $tableUpCase
            \$this->forge->addField([
                $campos
                'created_at'       => ['type' => 'datetime', 'null' => true],
                'updated_at'       => ['type' => 'datetime', 'null' => true],
                'deleted_at'       => ['type' => 'datetime', 'null' => true],
            ]);
            \$this->forge->addKey('id', true);
            \$this->forge->createTable('$table', true);
            }
            public function down(){
                \$this->forge->dropTable('$table', true);
                }
            }
        EOF;

        $path = ROOTPATH . "app/Database/Migrations/";
        if (!is_dir($path))
            mkdir($path, 0777, TRUE);

        $fechaActual = fechaParaMigraciones(fechaHoraActual());

        file_put_contents($path . "{$fechaActual}_{$tableUpCase}.php", $migration);

        //file_put_contents($path . "2023-02-07-165411_$tableUpCase.php", $viewModal);
    }
    
    

}

Creamos el archivo app/helpers/utilerias_helper.php con el siguiente codigo

<?php

function strMenuActivo($strMenu1, $strMenu2) {
    if ($strMenu1 == $strMenu2) {
        $respuesta = 'class="active"';
    } else {
        $respuesta = "";
    }
    return $respuesta;
}

//SI LA VARIABLE ESTA VACIA O NO SETA DECLARADA MANDARA CERO SIEMPRE, ES COMO EL VAL DE VISUAL BASIC 6.0

function esCero($value) {

    if (empty($value)) {
        return "0";
    } else {
        return $value;
    }
}

//FECHA SQL PARA GUARDAR EN BASE DE DATOS

function fechaSQL($fecha) {

    return date("Ymd", strtotime($fecha));
}

// CONVIERTE FECHA MYSQLDATETIME A HTML5
function fechaMySQLADateTimeHTML5($fecha) {

    return date("Y-m-d", strtotime($fecha)) . "T" . date("H:i:s", strtotime($fecha));
}

function agregarMinutos($fecha, $minutos) {


    return date("Y/m/d h:i:s", strtotime($fecha . "+ $minutos minutes"));

    /*
      $fecha1= new DateTime($fecha);
      $fecha1->add(new DateInterval('PT10H30S'));
      return $date->format('Y-m-d H:i:s') . "\n";
     * 
     */
}

//CONVIERTE LA FECHA EN PERIODO
function fechaPeriodo($fecha) {

    return date("Ym", strtotime($fecha));
}

//OBTIENE FECHA ACTUAL
function fechaActual() {

    return date("Y/m/d");
}

//OBTIENE FECHA HORA ACTUAL

function fechaHoraActual() {

    return date("Y-m-d H:i:s ", time());
}

//DIFERENCIA ENTRE MINUTOS
function diferenciaMinutos($fecha_i, $fecha_f) {
    $minutos = (strtotime($fecha_i) - strtotime($fecha_f)) / 60;

    $minutos = abs($minutos);
    $minutos = floor($minutos);

    return $minutos;
}

function strSellar($llave, $password, $cadenaOriginal) {


    $archivoPem = "/tmp/llave.key.pem";
    $comando = "openssl pkcs8 -inform DER -in $llave -passin pass:$password -out $archivoPem";

    exec($comando);
    $sello = "ok";

    //Sellar
    $archivo = openssl_pkey_get_private(file_get_contents($archivoPem));
    $sig = "";
    openssl_sign($cadenaOriginal, $sig, $archivo, OPENSSL_ALGO_SHA256);

    $sello = base64_encode($sig);

    return $sello;
}

//SOLO DIA
function dia($fecha) {

    return date("d", strtotime($fecha));
}

//SOLO MES
function mes($fecha) {

    return date("m", strtotime($fecha));
}

//SOLO AÑO
function año($fecha) {

    return date("Y", strtotime($fecha));
}

//GENERA UUID
function generaUUID() {


    $uuid = service('uuid');
    $uuid4 = $uuid->uuid4();
    $string = $uuid4->toString();

    return $string;
}

function satinizar($var, $type) {
    switch ($type) {
        case 'html':
            $safe = htmlspecialchars($var);
            break;
        case 'sql':
            $safe = mysql_real_escape_string($var);
            break;
        case 'file':
            $safe = preg_replace('/(\/|-|_)/', '', $var);
            break;
        case 'shell':
            $safe = escapeshellcmd($var);
            break;
        default:
            $safe = htmlspecialchars($var);
    }
    return $safe;
}

function limpiaCadena($cadena) {

    $cadena = str_replace('"', "", $cadena);
    $cadena = str_replace('\n', "", $cadena);
    $cadena = str_replace('\t', "", $cadena);
    $cadena = trim($cadena);

    $cadena = preg_replace("[\n|\r|\n\r]", "", $cadena);

    $descripcion = preg_replace("[\n|\r|\n\r]", "", $descripcion);

    return $cadena;
}


// CONVIERTE FECHA MYSQLDATETIME A HTML5
function fechaParaMigraciones($fecha) {

    return date("Y-m-d", strtotime($fecha)) . date("His", strtotime($fecha));
    
}

En rutas ponemos el siguiente codigo

$routes->get('generateCRUD/(:any)', 'AutoCrudController::index/$1');

Creamos la tabla de categorías

-- phpMyAdmin SQL Dump
-- version 5.0.4
-- https://www.phpmyadmin.net/
--
-- Servidor: 127.0.0.1
-- Tiempo de generación: 21-04-2023 a las 20:19:25
-- Versión del servidor: 10.4.17-MariaDB
-- Versión de PHP: 7.4.15

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
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 */;

--
-- Base de datos: `ci4jcpos`
--

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

--
-- Estructura de tabla para la tabla `categorias`
--

CREATE TABLE `categorias` (
  `id` int(11) NOT NULL,
  `descripcion` varchar(128) COLLATE utf8mb4_spanish2_ci DEFAULT NULL,
  `deleted_at` datetime DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_spanish2_ci;

--
-- Índices para tablas volcadas
--

--
-- Indices de la tabla `categorias`
--
ALTER TABLE `categorias`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT de las tablas volcadas
--

--
-- AUTO_INCREMENT de la tabla `categorias`
--
ALTER TABLE `categorias`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
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 */;

Corremos la siguiente URL en el navegador para crear todo el catalogo

http://localhost:8080/admin/generateCRUD/categorias

Esto nos generara los archivos necesarios y ademas la ruta para agregarlo en routes.php


         $routes->resource('categorias', [
                        'filter' => 'permission:categorias-permission',
                        'controller' => 'categoriasController',
                        'except' => 'show'
                    ]);
        $routes->post('categorias/save', 'CategoriasController::save');
        $routes->post('categorias/getCategorias', 'CategoriasController::getCategorias');
Ya solo hacemos los cambios estéticos necesarios, agregamos los permisos necesarios corregimos la ruta en el menú y listo
Video Demostrativo

Página 1 de 2

Creado con WordPress & Tema de Anders Norén