Herramientas Informaticas

Categoría: CODEIGNITER 4.1

CI 4.0 MedicalSoft CRUD Para Medicamentos

Ya creamos el CRUD para pacientes, ahora será necesario crear un CRUD para los medicamentos.

Primero creamos la tabla medicamentos, les dejo la exportación desde phpmyadmin

-- phpMyAdmin SQL Dump
-- version 5.0.4
-- https://www.phpmyadmin.net/
--
-- Servidor: 127.0.0.1
-- Tiempo de generación: 06-01-2023 a las 20:37:36
-- 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: `medicalsoft`
--

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

--
-- Estructura de tabla para la tabla `medicamentos`
--

CREATE TABLE `medicamentos` (
  `id` int(11) NOT NULL,
  `descripcion` varchar(256) COLLATE utf8_spanish2_ci NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `deleted_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish2_ci;

--
-- Índices para tablas volcadas
--

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

--
-- AUTO_INCREMENT de las tablas volcadas
--

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

Creamos el archivo MedicamentosModel.php en app/models/

<?php

namespace App\Models;

use CodeIgniter\Model;

class MedicamentosModel extends Model
{
    protected $table      = 'medicamentos';
    protected $primaryKey = 'id';

    protected $useAutoIncrement = true;

    protected $returnType     = 'array';
    protected $useSoftDeletes = true;

    protected $allowedFields = ['id','descripcion', 'created_at','updated_at'];

    protected $useTimestamps = true;
    protected $createdField  = 'created_at';
    protected $deletedField  = 'deleted_at';

    protected $validationRules    =  [
        'descripcion'     => 'required|alpha_numeric_space|min_length[3]'
        
    ];
    protected $validationMessages = [];
    protected $skipValidation     = false;
    
   
}

Creamos el archivo MedicamentosController.php en app/controller

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use App\Models\MedicamentosModel;
use \App\Models\BitacoraModel;
use CodeIgniter\API\ResponseTrait;

class MedicamentosController extends BaseController {

    use ResponseTrait;

    protected $bitacora;
    protected $medicamentos;

    public function __construct() {
        $this->medicamentos = new MedicamentosModel();
        $this->bitacora = new BitacoraModel();
        helper('menu');
    }

    public function index() {


        if ($this->request->isAJAX()) {

            /*
              $start = $this->request->getGet('start');
              $length = $this->request->getGet('length');
              $search = $this->request->getGet('search[value]');
              $order = BitacoraModel::ORDERABLE[$this->request->getGet('order[0][column]')];
              $dir = $this->request->getGet('order[0][dir]');
             */

            $datos = $this->medicamentos->select('id,descripcion,created_at,updated_at')->where('deleted_at', null);
            // $resultado = $this->bitacora->findAll();
            // $this->bitacora->getResource()->countAllResults(),
            // $this->bitacora->getResource($search)->countAllResults()
            //      var_dump($datos);


            return \Hermawan\DataTables\DataTable::of($datos)->add('action', function ($row) {
                                return " <div class=\"btn-group\">
                          
                  <button class=\"btn btn-warning btnEditarMedicamento\" data-toggle=\"modal\" idMedicamento=\"$row->id\" data-target=\"#modalAgregarMedicamentos\">  <i class=\" fa fa-edit \"></i></button>
                  <button class=\"btn btn-danger btnEliminarMedicamento\" idMedicamento=\"$row->id\"><i class=\"fa fa-times\"></i></button></div>";
                            }, 'last')
                            ->toJson();
        }

        $titulos["title"] = lang('medicamentos.title');
        $titulos["subtitle"] = lang('medicamentos.subtitle');

        return view('medicamentos', $titulos);
    }

    /*
     * Lee paciente
     */

    public function traeMedicamento() {


        $idMedicamento = $this->request->getPost("idMedicamento");
        $datosMedicamento = $this->medicamentos->find($idMedicamento);

        echo json_encode($datosMedicamento);
    }

    /*
     * Guarda o actualiza paciente
     */

    public function guardar() {


        helper('auth');
        $userName = user()->username;
        $idUser = user()->id;

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

        if ($datos["idMedicamento"] == 0) {


            try {


                if ($this->medicamentos->save($datos) === false) {

                    $errores = $this->medicamentos->errors();

                    foreach ($errores as $field => $error) {

                        echo $error . " ";
                    }

                    return;
                }

                $datosBitacora["descripcion"] = "Se guardo la medicamento con los siguientes datos: " . json_encode($datos);
                $datosBitacora["usuario"] = $userName;

                $this->bitacora->save($datosBitacora);

                echo "Guardado Correctamente";
            } catch (\PHPUnit\Framework\Exception $ex) {


                echo "Error al guardar " . $ex->getMessage();
            }
        } else {


            if ($this->medicamentos->update($datos["idMedicamento"], $datos) == false) {
                
                $errores = $this->medicamentos->errors();
                foreach ($errores as $field => $error) {

                    echo $error . " ";
                }
                
                return;
               
            } else {

                $datosBitacora["descripcion"] = "Se actualizo el medicamento con los siguientes datos: " . json_encode($datos);
                $datosBitacora["usuario"] = $userName;
                $this->bitacora->save($datosBitacora);
                echo "Actualizado Correctamente";

                return;
            }
        }

        return;


    }
    
    
    
     public function delete($id)
    {
        if (!$found = $this->medicamentos->delete($id)) {
            return $this->failNotFound(lang('medicamentos.msg.msg_get_fail'));
        }
        
        $infoMedicamento = $this->medicamentos->find($id);
        
        $datosBitacora["descripcion"] = "Se elimino la medicamento que contenia los siguientes datos ". json_encode($infoMedicamento);
        
        $this->bitacora->save($datosBitacora);
        return $this->respondDeleted($found, lang('medicamentos.msg.msg_delete'));
    }

}

Creamos el archivo de la vista medicamentos.php en app/views

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

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

<?= $this->include('medicamentosModulos\modalCaptura') ?>
<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="float-right">
            <div class="btn-group">

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

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

                </button>

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



                                <th>#</th>
                                <th><?= lang('medicamentos.description') ?></th>
                        
                                <th><?= lang('medicamentos.createdAt') ?></th>
                                <th><?= lang('medicamentos.updateAt') ?></th>
                                <th>Acciones </th>


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

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




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

    /**
     * Cargamos la tabla
     */


    function cargaTabla() {



         $('.tablaMedicamentos').DataTable({
         "ajax": "<?= route_to('admin/medicamentos') ?>",
         "deferRender": true,
         "serverSide": true,
         "retrieve": true,
         "processing": true
         
         });
        
    }


    cargaTabla();



    /**
     * Carga datos actualizar
     */


    /*=============================================
     EDITAR PACIENTE
     =============================================*/
    $(".tablaMedicamentos").on("click", ".btnEditarMedicamento", function () {

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


        console.log("idMedicamento ", idMedicamento);

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

        $.ajax({

            url: "<?= route_to('admin/medicamentos/traerMedicamento') ?>",
            method: "POST",
            data: datos,
            cache: false,
            contentType: false,
            processData: false,
            dataType: "json",
            success: function (respuesta) {
                console.log(respuesta);
                $("#idMedicamento").val(respuesta["id"]);
                $("#descripcion").val(respuesta["descripcion"]);
            
            }

        })

    })


    /*=============================================
     ELIMINAR PACIENTE
     =============================================*/
    $(".tablaMedicamentos").on("click", ".btnEliminarMedicamento", function () {

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


 

        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: `<?= route_to('admin/medicamentos') ?>/` + idMedicamento,
                            method: 'DELETE',
                        }).done((data, textStatus, jqXHR) => {
                            Toast.fire({
                                icon: 'success',
                                title: jqXHR.statusText,
                            });

                           $(".tablaMedicamentos").DataTable().destroy();
                            cargaTabla();
                            //tableUser.ajax.reload();
                        }).fail((error) => {
                            Toast.fire({
                                icon: 'error',
                                title: error.responseJSON.messages.error,
                            });
                        })
                    }
                })
    })




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

Creamos la carpeta en views medicamentosModulos y dentro de ella creamos el archivo modelCaptura.php con el siguiente código

<!-- Modal Medicamentos -->
<div class="modal fade" id="modalAgregarMedicamentos" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title"><?= lang('medicamentos.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-enfermedad" class="form-horizontal">
                    <input type="hidden" id="idMedicamento" name="idMedicamento" value="0">



                    <div class="form-group row">
                        <label for="inputName" class="col-sm-2 col-form-label"><?= lang('medicamentos.description') ?></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="descripcion" id="descripcion" class="form-control <?= session('error.descripcion ') ? 'is-invalid' : '' ?>" value="<?= old('descripcion') ?>" placeholder="<?= lang('medicamentos.description') ?>" 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="btnGuardarMedicamento"><?= lang('boilerplate.global.save') ?></button>
            </div>
        </div>
    </div>
</div>

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


<script>

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

        console.log("asdasd");
        $(".form-control").val("");

        $("#idMedicamento").val("0");
        
           $("#btnGuardarMedicamento").removeAttr("disabled");

    })

    /* 
     * AL hacer click al editar
     */



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


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

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

        $("#idMedicamento").val(idMedicamento);
        $("#btnGuardarMedicamento").removeAttr("disabled");

    })

    /**
     * Guardar paciente
     */

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

        var idMedicamento = $("#idMedicamento").val();
        var descripcion = $("#descripcion").val();
      


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


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


        $.ajax({

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


                if (respuesta.match(/Correctamente.*/)) {


                    Toast.fire({
                        icon: 'success',
                        title: "Guardado Correctamente"
                    });


                    $('.tablaMedicamentos').DataTable().destroy();
                    cargaTabla();
                    $("#btnGuardarMedicamento").removeAttr("disabled");

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

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

                    $("#btnGuardarMedicamento").removeAttr("disabled");
                  //  $('#modalAgregarMedicamento').modal('hide');

                }

            }

        }

        )




    });
</script>


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

en app/Languaje/en creamos el archivo medicamentos.php con el siguiente código

<?php

$medicamentos["descrption"] = "Description";

$medicamentos["createdAt"] = "Date Creation";
$medicamentos["updateAt"] = "Date Update";
$medicamentos["add"] = "Add medicine";
$medicamentos["actions"] = "Actions";
$medicamentos["createEdit"] = "Create  / Edit medicine";
$medicamentos["title"] = "Medicine";
$medicamentos["subtitle"] = "List of medicines";

$medicamentos["msg_delete"] = "medicine has deleted .";
$medicamentos["msg_get_fail"] = "The medicine not exist or has deleted.";





return $medicamentos;

en app/Languaje/escreamos el archivo medicamentos.php con el siguiente código

<?php

$medicamentos["description"] = "Descripcion";

$medicamentos["createdAt"] = "Fecha Creación";
$medicamentos["updateAt"] = "Fecha de Modificación";
$medicamentos["add"] = "Agregar Medicamentos";
$medicamentos["actions"] = "Acciones";
$medicamentos["createEdit"] = "Crear  / Editar Medicamentos";
$medicamentos["title"] = "Medicamentos";
$medicamentos["subtitle"] = "Lista de Medicamentos";

$medicamentos["msg_delete"] = "El medicamento ha sido eliminada .";
$medicamentos["msg_get_fail"] = "La medicamento no existe o fue eliminada.";





return $medicamentos;

en el archivo app/config/routes.php agregamos dentro del grupo admin la siguiente rutas

    $routes->resource('medicamentos', [
        'filter' => 'permission:medicamentos-permiso',
        'controller' => 'MedicamentosController',
        'except' => 'show'
    ]);

    $routes->post('medicamentos/guardar', 'MedicamentosController::guardar');

    $routes->post('medicamentos/traerMedicamento', 'MedicamentosController::traeMedicamento');
Y listo ya tenemos nuestro CRUD de medicamentos

CI 4.0 MedicalSoft CRUD Para Pacientes

Ahora veremos como crear el CRUD de pacientes en el framework CodeIgniter 4.0 con los siguientes datos, Nombres, Apellidos, DNI, Correo Electrónico, para ello creamos la siguiente tabla.

Leer Mas: CI 4.0 MedicalSoft CRUD Para Pacientes
-- phpMyAdmin SQL Dump
-- version 5.0.4
-- https://www.phpmyadmin.net/
--
-- Servidor: 127.0.0.1
-- Tiempo de generación: 04-01-2023 a las 18:20:08
-- 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: `medicalsoft`
--

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

--
-- Estructura de tabla para la tabla `pacientes`
--

CREATE TABLE `pacientes` (
  `id` int(11) NOT NULL,
  `nombres` varchar(256) COLLATE utf8_spanish2_ci DEFAULT NULL,
  `apellidos` varchar(256) COLLATE utf8_spanish2_ci DEFAULT NULL,
  `dni` varchar(32) COLLATE utf8_spanish2_ci DEFAULT NULL,
  `telefono` varchar(16) COLLATE utf8_spanish2_ci DEFAULT NULL,
  `correoElectronico` varchar(64) COLLATE utf8_spanish2_ci DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `deleted_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish2_ci;

--
-- Índices para tablas volcadas
--

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

--
-- AUTO_INCREMENT de las tablas volcadas
--

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

Creamos el archivo PacientesModel.php en la carpeta model para el acceso a la tabla de la base de datos

<?php

namespace App\Models;

use CodeIgniter\Model;

class PacientesModel extends Model
{
    protected $table      = 'pacientes';
    protected $primaryKey = 'id';

    protected $useAutoIncrement = true;

    protected $returnType     = 'array';
    protected $useSoftDeletes = true;

    protected $allowedFields = ['id','nombres', 'apellidos','dni','telefono','correoElectronico','created_at','updated_at'];

    protected $useTimestamps = true;
    protected $createdField  = 'created_at';
    protected $deletedField  = 'deleted_at';

    protected $validationRules    =  [
        'nombres'     => 'required|alpha_numeric_space|min_length[3]',
        'apellidos'     => 'required|alpha_numeric_space|min_length[5]',
        'correoElectronico'        => 'required|valid_email|is_unique[users.email]'
        
    ];
    protected $validationMessages = [];
    protected $skipValidation     = false;
    
   
}

Creamos el archivo PacientesController.php alli tendremos la funciones para guardar, leer y modificar, creo que no falta decir que va en la carpeta controller

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use \App\Models\PacientesModel;
use \App\Models\BitacoraModel;
use CodeIgniter\API\ResponseTrait;

class PacientesController extends BaseController {

    use ResponseTrait;

    protected $bitacora;
    protected $pacientes;

    public function __construct() {
        $this->pacientes = new PacientesModel();
        $this->bitacora = new BitacoraModel();
        helper('menu');
    }

    public function index() {


        if ($this->request->isAJAX()) {

            /*
              $start = $this->request->getGet('start');
              $length = $this->request->getGet('length');
              $search = $this->request->getGet('search[value]');
              $order = BitacoraModel::ORDERABLE[$this->request->getGet('order[0][column]')];
              $dir = $this->request->getGet('order[0][dir]');
             */

            $datos = $this->pacientes->select('id,nombres,apellidos,dni,telefono,correoElectronico,created_at,updated_at')->where('deleted_at', null);
// $resultado = $this->bitacora->findAll();
// $this->bitacora->getResource()->countAllResults(),
// $this->bitacora->getResource($search)->countAllResults()
//      var_dump($datos);


            return \Hermawan\DataTables\DataTable::of($datos)->add('action', function ($row) {
                                return " <div class=\"btn-group\">
                          
                  <button class=\"btn btn-warning btnEditarPaciente\" data-toggle=\"modal\" idPaciente=\"$row->id\" data-target=\"#modalAgregarPaciente\">  <i class=\" fa fa-edit \"></i></button>
                  <button class=\"btn btn-danger btnEliminarPaciente\" idPaciente=\"$row->id\"><i class=\"fa fa-times\"></i></button></div>";
                            }, 'last')
                            ->toJson();
        }

        $titulos["title"] = lang('patients.title');
        $titulos["subtitle"] = lang('patients.subtitle');
        
       
//$data["data"] = $datos;
        return view('pacientes', $titulos);
    }

    /*
     * Lee paciente
     */

    public function traePaciente() {


        $idPaciente = $this->request->getPost("idPaciente");
        $datosPaciente = $this->pacientes->find($idPaciente);

        echo json_encode($datosPaciente);
    }

    /*
     * Guarda o actualiza paciente
     */

    public function guardar() {


        helper('auth');
        $userName = user()->username;
        $idUser = user()->id;

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

        if ($datos["idPaciente"] == 0) {


            try {


                if ($this->pacientes->save($datos) === false) {

                    $errores = $this->pacientes->errors();

                    foreach ($errores as $field => $error) {

                        echo $error . " ";
                    }

                    return;
                }

                $datosBitacora["descripcion"] = "Se guardo el paciente con los siguientes datos: " . json_encode($datos);
                $datosBitacora["usuario"] = $userName;

                $this->bitacora->save($datosBitacora);

                echo "Guardado Correctamente";
            } catch (\PHPUnit\Framework\Exception $ex) {


                echo "Error al guardar " . $ex->getMessage();
            }
        } else {


            if ($this->pacientes->update($datos["idPaciente"], $datos) == false) {

                $errores = $this->pacientes->errors();
                foreach ($errores as $field => $error) {

                    echo $error . " ";
                }

                return;
            } else {

                $datosBitacora["descripcion"] = "Se actualizo el paciente con los siguientes datos: " . json_encode($datos);
                $datosBitacora["usuario"] = $userName;
                $this->bitacora->save($datosBitacora);
                echo "Actualizado Correctamente";

                return;
            }
        }

        return;
    }

    public function delete($id) {
        if (!$found = $this->pacientes->delete($id)) {
            return $this->failNotFound(lang('patients.msg.msg_get_fail'));
        }

        $infoPaciente = $this->pacientes->find($id);

        $datosBitacora["descripcion"] = "Se elimino el paciente que contenia los siguientes datos " . json_encode($infoPaciente);

        $this->bitacora->save($datosBitacora);
        return $this->respondDeleted($found, lang('patients.msg.msg_delete'));
    }

    /**
     * Trae en formato JSON los pacientes para el select2
     * @return type
     */
    public function traerPacientesAjax() {
        
        $request = service('request');
        $postData = $request->getPost();

        $response = array();

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

        if (!isset($postData['searchTerm'])) {
            // Fetch record
            $pacientes = new PacientesModel();
            $listaPacientes = $pacientes->select('id,nombres,apellidos')
                    ->orderBy('nombres')
                    ->findAll(10);
        } else {
            $searchTerm = $postData['searchTerm'];

            // Fetch record
            $pacientes = new PacientesModel();
            $listaPacientes = $pacientes->select('id,nombres,apellidos')
                    ->where("deleted_at",null)
                    ->like('nombres', $searchTerm)
                    ->orLike('apellidos', $searchTerm)
                    ->orderBy('nombres')
                    ->findAll(10);
        }

        $data = array();
        foreach ($listaPacientes as $paciente) {
            $data[] = array(
                "id" => $paciente['id'],
                "text" => $paciente['nombres'].' '.$paciente['apellidos'],
            );
        }

        $response['data'] = $data;

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

}

En Views creamos el archivo de la vista

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

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

<?= $this->include('pacientesModulos\modalCaptura') ?>
<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="float-right">
            <div class="btn-group">

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

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

                </button>

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



                                <th>#</th>
                                <th><?= lang('patients.names') ?></th>
                                <th><?= lang('patients.lastName') ?></th>
                                <th><?= lang('patients.dni') ?></th>
                                <th><?= lang('patients.phone') ?></th>
                                <th><?= lang('patients.email') ?></th>
                                <th><?= lang('patients.createdAt') ?></th>
                                <th><?= lang('patients.updateAt') ?></th>
                                <th>Acciones </th>


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

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




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

    /**
     * Cargamos la tabla
     */


    function cargaTabla() {



         $('.tablaPacientes').DataTable({
         "ajax": "<?= route_to('admin/pacientes') ?>",
         "deferRender": true,
         "serverSide": true,
         "retrieve": true,
         "processing": true
         
         });
        
    }


    cargaTabla();



    /**
     * Carga datos actualizar
     */


    /*=============================================
     EDITAR PACIENTE
     =============================================*/
    $(".tablaPacientes").on("click", ".btnEditarPaciente", function () {

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


        console.log("paciente ", idPaciente);

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

        $.ajax({

            url: "<?= route_to('admin/pacientes/traerPaciente') ?>",
            method: "POST",
            data: datos,
            cache: false,
            contentType: false,
            processData: false,
            dataType: "json",
            success: function (respuesta) {
                console.log(respuesta);
                $("#idPaciente").val(respuesta["id"]);
                $("#nombres").val(respuesta["nombres"]);
                $("#apellidos").val(respuesta["apellidos"]);
                $("#correoElectronico").val(respuesta["correoElectronico"]);
                $("#telefono").val(respuesta["telefono"]);
                $("#dni").val(respuesta["dni"]);

            }

        })

    })


    /*=============================================
     ELIMINAR PACIENTE
     =============================================*/
    $(".tablaPacientes").on("click", ".btnEliminarPaciente", function () {

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


        console.log("eliminar");

        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: `<?= route_to('admin/pacientes') ?>/` + idPaciente,
                            method: 'DELETE',
                        }).done((data, textStatus, jqXHR) => {
                            Toast.fire({
                                icon: 'success',
                                title: jqXHR.statusText,
                            });

                           $(".tablaPacientes").DataTable().destroy();
                            cargaTabla();
                            //tableUser.ajax.reload();
                        }).fail((error) => {
                            Toast.fire({
                                icon: 'error',
                                title: error.responseJSON.messages.error,
                            });
                        })
                    }
                })
    })




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

En views creamos la carpeta pacientesModulos y dentro de esa capeta creamos el archivo modalCaptura.php con la siguiente código

<!-- Modal Pacientes -->
<div class="modal fade" id="modalAgregarPaciente" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title"><?= lang('patients.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-paciente" class="form-horizontal">
                    <input type="hidden" id="idPaciente" name="idPaciente" value="0">



                    <div class="form-group row">
                        <label for="inputName" class="col-sm-2 col-form-label"><?= lang('patients.names') ?></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="nombres" id="nombres" class="form-control <?= session('error.nombres') ? 'is-invalid' : '' ?>" value="<?= old('nombres') ?>" placeholder="<?= lang('patients.names') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>

                    <div class="form-group row">
                        <label for="inputName" class="col-sm-2 col-form-label"><?= lang('patients.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="apellidos"  id="apellidos"class="form-control <?= session('error.apellidos') ? 'is-invalid' : '' ?>" value="<?= old('apellidos') ?>" placeholder="<?= lang('patients.lastName') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>

                    <div class="form-group row">
                        <label for="dni" class="col-sm-2 col-form-label"><?= lang('patients.dni') ?></label>
                        <div class="col-sm-10">
                            <div class="input-group">
                                <div class="input-group-prepend">
                                    <span class="input-group-text"><i class="fas fa-credit-card"></i></span>
                                </div>
                                <input type="text" name="dni"  id="dni" class="form-control <?= session('error.dni') ? 'is-invalid' : '' ?>" value="<?= old('dni') ?>" placeholder="<?= lang('patients.dni') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>

                    <div class="form-group row">
                        <label for="phone" class="col-sm-2 col-form-label"><?= lang('patients.phone') ?></label>
                        <div class="col-sm-10">
                            <div class="input-group">
                                <div class="input-group-prepend">
                                    <span class="input-group-text"><i class="fas fa-mobile"></i></span>
                                </div>
                                <input type="text" name="telefono" id="telefono" class="form-control <?= session('error.phone') ? 'is-invalid' : '' ?>" value="<?= old('telefono') ?>" placeholder="<?= lang('patients.phone') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>

                    <div class="form-group row">
                        <label for="correoElectronico" class="col-sm-2 col-form-label"><?= lang('patients.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-envelope"></i></span>
                                </div>
                                <input type="text" name="correoElectronico" id="correoElectronico" class="form-control <?= session('error.correoElectronico') ? 'is-invalid' : '' ?>" value="<?= old('correoElectronico') ?>" placeholder="<?= lang('patients.email') ?>" 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="btnGuardarPaciente"><?= lang('boilerplate.global.save') ?></button>
            </div>
        </div>
    </div>
</div>

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


<script>

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

        console.log("asdasd");
        $(".form-control").val("");

        $("#idPaciente").val("0");
        
           $("#btnGuardarPaciente").removeAttr("disabled");

    })

    /* 
     * AL hacer click al editar
     */



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


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

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

        $("#idPaciente").val(idPaciente);
        $("#btnGuardarPaciente").removeAttr("disabled");

    })

    /**
     * Guardar paciente
     */

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

        var idPaciente = $("#idPaciente").val();
        var nombres = $("#nombres").val();
        var apellidos = $("#apellidos").val();
        var telefono = $("#telefono").val();
        var dni = $("#dni").val();
        var correoElectronico = $("#correoElectronico").val();

        var ajaxPaciente = "ajaxPaciente";


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


        var datos = new FormData();
        datos.append("idPaciente", idPaciente);
        datos.append("nombres", nombres);
        datos.append("apellidos", apellidos);
        datos.append("telefono", telefono);
        datos.append("dni", dni);
        datos.append("correoElectronico", correoElectronico);

        $.ajax({

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


                if (respuesta.match(/Correctamente.*/)) {


                    Toast.fire({
                        icon: 'success',
                        title: "Guardado Correctamente"
                    });


                    $('.tablaPacientes').DataTable().destroy();
                    cargaTabla();
                    $("#btnGuardarPaciente").removeAttr("disabled");

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

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

                    $("#btnGuardarPaciente").removeAttr("disabled");
                  //  $('#modalAgregarPaciente').modal('hide');

                }

            }

        }

        )




    });
</script>


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

Ahora configuramos las rutas en app/config/routes.php

    $routes->resource('pacientes', [
        'filter' => 'permission:pacientes-permiso',
        'controller' => 'PacientesController',
        'except' => 'show'
    ]);

    $routes->post('pacientes/guardar', 'PacientesController::guardar');

    $routes->post('pacientes/traerPaciente', 'PacientesController::traePaciente');

    $routes->post('pacientes/traerPacientesAjax', 'PacientesController::traerPacientesAjax');

En languaje en la carpeta es creamos el archivo patients con el siguiente codigo

<?php

$patients["names"] = "Firs Name";
$patients["lastName"] = "Last Name";
$patients["dni"] = "CARD ID";
$patients["phone"] = "Phone";
$patients["email"] = "E-Mail";
$patients["createdAt"] = "Date Creation";
$patients["updateAt"] = "Date Update";
$patients["add"] = "Add Patient";
$patients["actions"] = "Actions";
$patients["createEdit"] = "Create  / Edit Patient";
$patients["title"] = "Patient";
$patients["subtitle"] = "List of Patients";

$patients["msg_delete"] = "Patient has deleted .";
$patients["msg_get_fail"] = "The patient not exist or has deleted.";





return $patients;

Y en la carpeta es de español creamos el archivo patients con el siguiente código

<?php

$patients["names"] = "Nombres";
$patients["lastName"] = "Apellidos";
$patients["dni"] = "INE";
$patients["phone"] = "Telefono";
$patients["email"] = "Correo Electronico";
$patients["add"] = "Agregar Paciente";
$patients["updateAt"] = "Fecha Modificacion";
$patients["actions"] = "Acciones";
$patients["createEdit"] = "Crear / Editar Paciente";
$patients["title"] = "Pacientes";
$patients["subtitle"] = "Lista de Pacientes";

$patients["msg_delete"] = "El paciente ha sido eliminado correctamente.";
$patients["msg_get_fail"] = "El paciente no existe o fue eliminado.";




return $patients;
Y listo ya tenemos nuestro CRUD de pacientes

CI 4.0 MedicalSoft Datatable para tabla de Bitacora

Ya vimos como guardar los datos de la bitácora, ahora veremos como usar el datatable con server side para mostrar los datos de guardados en la bitácora

Primero creamos el archivo BitacoraModel.php de la siguiente forma en la carpeta app/model/ aunque a estas altura ya debemos tenerlo

Leer Mas: CI 4.0 MedicalSoft Datatable para tabla de Bitacora
<?php

namespace App\Models;

use CodeIgniter\Model;

class BitacoraModel extends Model
{
    protected $table      = 'bitacora';
    protected $primaryKey = 'id';

    protected $useAutoIncrement = true;

    protected $returnType     = 'array';
    protected $useSoftDeletes = true;

    protected $allowedFields = ['id','descripcion', 'usuario'];

    protected $useTimestamps = true;
    protected $createdField  = 'created_at';
    protected $deletedField  = 'deleted_at';

    protected $validationRules    = [];
    protected $validationMessages = [];
    protected $skipValidation     = false;
    
    
    
    const ORDERABLE = [
        1 => 'id',
        2 => 'descripcion',
        3 => 'usuario',
        4 => 'created_at',
        
    ];

    /**
     * Get resource data.
     *
     * @param string $search
     *
     * @return \CodeIgniter\Database\BaseBuilder
     */
   public function getResource(string $search = '')
    {
        $builder = $this->builder()
            ->select('id, descripcion, usuario, created_at');

        $condition = empty($search)
            ? $builder
            : $builder->groupStart()
                ->like('descripcion', $search)
                ->orLike('Usuario', $search)
                ->orLike('created_at', $search)
            ->groupEnd();

        return $condition->where('deleted_at', null);
    }
}

Para convertir fácilmente el resultado de la consulta SQL del QUERYBUILDER a formato json que usa datatable instalamos en la terminal el siguiente componente de hermawan usando composer

composer require hermawan/codeigniter4-datatables

Creamos el archivo BitacoraController.php con los siguientes, si observamos en la función index vemos que solo con una linea se crea el json

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use \App\Models\BitacoraModel;
use CodeIgniter\API\ResponseTrait;

class BitacoraController extends BaseController {

    use ResponseTrait;

    protected $bitacora;

    public function __construct() {
        $this->bitacora = new BitacoraModel();
        helper('menu');
    }

    public function index() {


        if ($this->request->isAJAX()) {

            /*
            $start = $this->request->getGet('start');
            $length = $this->request->getGet('length');
            $search = $this->request->getGet('search[value]');
            $order = BitacoraModel::ORDERABLE[$this->request->getGet('order[0][column]')];
            $dir = $this->request->getGet('order[0][dir]');
*/

           $datos = $this->bitacora->select('id,descripcion,usuario,created_at');
           // $resultado = $this->bitacora->findAll();
                                   // $this->bitacora->getResource()->countAllResults(),
                                   // $this->bitacora->getResource($search)->countAllResults()
           return \Hermawan\DataTables\DataTable::of($datos)->toJson();
        }
        
        $titulos["title"] = lang('log.title');
        $titulos["subtitle"] = lang('log.subtitle');
        //$data["data"] = $datos;
        return view('bitacora',$titulos);
    }

    public function tabla() {


        if ($this->request->isAJAX()) {
            $start = $this->request->getGet('start');
            $length = $this->request->getGet('length');
            $search = $this->request->getGet('search[value]');
            $order = BitacoraModel::ORDERABLE[$this->request->getGet('order[0][column]')];
            $dir = $this->request->getGet('order[0][dir]');

            return $this->respond(Collection::datatable(
                                    $this->bitacora->getResource($search)->orderBy($order, $dir)->limit($length, $start)->get()->getResultObject(),
                                    $this->bitacora->getResource()->countAllResults(),
                                    $this->bitacora->getResource($search)->countAllResults()
            ));
        }
    }

}

Creamos la vista en app/views/bitacora.php

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

<!-- Section content -->
<?= $this->section('content') ?>
<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="card-tools">
            <div class="btn-group">


            </div>
        </div>
    </div>
    <div class="card-body">
        <div class="row">
            <div class="col-md-12">
                <div class="table-responsive">
                    <table id="tablaBitacora" class="table table-striped table-hover va-middle tablaBitacora">
                        <thead>
                            <tr>
                                <th>#</th>
                                <th><?= lang('log.description') ?></th>
                                <th><?= lang('log.user') ?></th>
                                <th><?= lang('log.date') ?></th>


                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- /.card -->
<?= $this->endSection() ?>

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

/**
 * Cargamos la tabla
 */
$('.tablaBitacora').DataTable( {
    "ajax": "<?= route_to('admin/bitacora/manage') ?>",
    "deferRender": true,
     "serverSide" : true,
  "retrieve": true,
  "processing": true

} )

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

En las rutas app/config/routes.php agregamos la siguiente linea

    /*
     * RUTA BITACORA
     */

    $routes->resource('bitacora', [
        'filter' => 'permission:bitacora-permiso',
        'controller' => 'BitacoraController',
        'except' => 'show'
    ]);
Al final este es el resultado

CI 4.0 MedicalSoft Creando Funciones para guardar Bitacora “LOG” #10

En cualquier sistema es importante tener un log o una bitácora en donde vallamos almacenando lo cambios que vamos realizando en la base de datos, por ejemplo, ir guardando la información que va insertando el usuario a la tabla de clientes, también cuando se elimino y actualizo grabando un timestamp que guarde hasta el segundo exacto de modificación y ya con eso vamos llevando un control

Haremos todo esto en CodeIgniter 4

Empezamos primero creamos la tabla

--

-- Estructura de tabla para la tabla bitacora

CREATE TABLE bitacora (
id bigint(20) NOT NULL,
descripcion text COLLATE utf8_spanish2_ci DEFAULT NULL,
usuario varchar(16) COLLATE utf8_spanish2_ci DEFAULT NULL,
created_at datetime DEFAULT NULL,
deleted_at datetime DEFAULT NULL,
updated_at datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish2_ci;

--

-- Índices para tablas volcadas

--

-- Indices de la tabla bitacora

ALTER TABLE bitacora
ADD PRIMARY KEY (id);

ALTER TABLE bitacora
MODIFY id bigint(20) NOT NULL AUTO_INCREMENT;
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 */;


Creamos el archivo modelo BitacoraModel.php

<?php

namespace App\Models;

use CodeIgniter\Model;

class BitacoraModel extends Model
{
protected $table = 'bitacora';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;

protected $returnType     = 'array';
protected $useSoftDeletes = true;

protected $allowedFields = ['id','descripcion', 'usuario'];

protected $useTimestamps = true;
protected $createdField  = 'created_at';
protected $deletedField  = 'deleted_at';

protected $validationRules    = [];
protected $validationMessages = [];
protected $skipValidation     = false;



const ORDERABLE = [
    1 => 'id',
    2 => 'descripcion',
    3 => 'usuario',
    4 => 'created_at',

];

/**
 * Get resource data.
 *
 * @param string $search
 *
 * @return \CodeIgniter\Database\BaseBuilder
 */
public function getResource(string $search = '')
{
$builder = $this->builder()
->select('id, descripcion, usuario, created_at');    
$condition = empty($search)
        ? $builder
        : $builder->groupStart()
            ->like('descripcion', $search)
            ->orLike('Usuario', $search)
            ->orLike('created_at', $search)
        ->groupEnd();

    return $condition->where('deleted_at', null);
}


Ahora usaremos el modelo para guardar cada vez que se haga un cambio al guardar la configuración del hospital

<?php
namespace agungsugiarto\boilerplate\Controllers\Users;
namespace App\Controllers;




use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller;
use App\Models\ConfiguracionesModel;
use App\Models\BitacoraModel;
use agungsugiarto\boilerplate\Controllers\BaseController;
use agungsugiarto\boilerplate\Entities\Collection;
use agungsugiarto\boilerplate\Models\GroupModel;




use CodeIgniter\Config\Services;


class HospitalController extends Controller
{

    use ResponseTrait;

    /** @var \agungsugiarto\boilerplate\Models\GroupModel */
    protected $group;
    protected $configuraciones;
    protected $bitacora;

    public function __construct()
    {

        $this->group = new GroupModel();
        $this->configuraciones = new ConfiguracionesModel();
        $this->bitacora = new BitacoraModel();
        $autorize = $this->authorize = Services::authorization();
        helper('menu');

    }

    public function index()
    {


        $datos = $this->configuraciones->where("id",1)->first();

        $data["title"] = lang('settings.settings.title');
        $data["subtitle"] = lang('settings.settings.title');
        $data["data"] = $datos;

        return view('configuracionEmpresa/index',$data);


    }


    public function guardar()
    {


        helper('auth');
        $userName = user()->username ;
        $idUser  = user()->id ;






        $bitacoraDatos["descripcion"] = "Se Modifico las configuracion con los siguientes datos:". json_encode($_POST);
        $bitacoraDatos["usuario"] = $userName;


        //GUARDA CONFIGURACIONES
        $this->configuraciones->update(1,$_POST);

        //GUARDAR EN BITACORA
       $this->bitacora->save($bitacoraDatos);
        //  return redirect()->to("/admin/hospital");
       return redirect()->back()->with('sweet-success', 'Actualizado Correctamente');
         // return redirect()->back()->with('sweet-success','Guardado Correctamente');

          }

}

Ya con eso cada vez que se haga un cambio a a configuración nos guardara un registro sobre quien hizo el cambio y también nos servirá para los próximos módulos que se vallan programando.

En la próxima publicación veremos como mostrar los datos en un datatable.

CI 4.0 MedicalSoft Creando Login y menú AdminLTE 3 #7

Veremos como crear el proyecto desde cero, meteremos el login con adminLTE3 y crearemos los menús que vamos a utilizar

Como convertir Web hecha en PHP8 con FrameWork CodeIgniter 4 en una APP de Escritorio

code

git clone https://github.com/electron/electron-quick-start.git

en el archivo package.json lo dejamos de la siguiente manera

	{

	"build": {
	"appId": "com.electron.example",
	"compression": "maximum"
	},
	"name": "XML2PDF CFDI",

	"version": "2.0.0",

	"description": "Una pequeña aplicación para convertir el CFDI XML a PDF",

	"main": "main.js",

	"compression": "maximum",

	"scripts": {

	"***": null,
	"pro:windows": "electron-builder --win"

	},
	"repository": "https://github.com/electron/electron-quick-start",  

	"keywords": [
	"CFDI",
	"XML",
	"PDF",
	"tutorial"
	],
	"author": "Julio Cesar Leyva Rodriguez",
	"license": "CC0-1.0",
	"devDependencies": {
	"electron": "^21.2.3",
	"electron-builder": "^22.14.13",
	"electron-packager": "^17.1.1"
	},
	"dependencies": {
	"modclean": "^3.0.0-beta.1"
	}
	}

en main.js lo dejamos haci lo que hara es cargar la url y levantar el servicio de php

	// Modules to control application life and create native browser window

	const {app, BrowserWindow} = require('electron')

	const path = require('path')

	const exec = require('child_process').exec;

	  
	  

	function execute(command, callback) {

	exec(command, (error, stdout, stderr) => {

	callback(stdout);

	});

	};

	  
	  

	// call the function

	execute('Ejecutar.bat', (output) => {

	console.log(output);

	});

	  

	function createWindow () {

	// Create the browser window.

	const mainWindow = new BrowserWindow({

	width: 800,

	height: 600,

	webPreferences: {

	preload: path.join(__dirname, 'preload.js')

	}

	})

	  

	// and load the index.html of the app.

	mainWindow.setMenu(null)

	mainWindow.loadURL('http://localhost:8097')

	  

	// Open the DevTools.

	// mainWindow.webContents.openDevTools()

	}

	  

	// This method will be called when Electron has finished

	// initialization and is ready to create browser windows.

	// Some APIs can only be used after this event occurs.

	app.whenReady().then(() => {

	createWindow()

	  

	app.on('activate', function () {

	// On macOS it's common to re-create a window in the app when the

	// dock icon is clicked and there are no other windows open.

	if (BrowserWindow.getAllWindows().length === 0) createWindow()

	})

	})

	  

	// Quit when all windows are closed, except on macOS. There, it's common

	// for applications and their menu bar to stay active until the user quits

	// explicitly with Cmd + Q.

	app.on('window-all-closed', function () {

	if (process.platform !== 'darwin') app.quit()

	})

	  

	// In this file you can include the rest of your app's specific main process

	// code. You can also put them in separate files and require them here.

ahora posicionados en la carpeta \electron-quick-start> corremos el siguiente comando

npm install

Después creamos el paquete-ejecutable con el siguiente comando

electron-packager . -platform=win32 -arch=x64 ConversorXMLPDF

y nos genera los archivos necesarios
image

Creamos una carpeta en C: llamada aplicación o como ustedes quieran llamarle y copiamos el contenido, la carpeta del proyecto del codeigniter y los archivos ejecutable de PHP con los que trabajan, pueden copiar los del xampp y con el que debugean a través de netbeans
quedaría de la siguiente forma

image

ConvertidorXMLPDF seria el proyecto en codeigniter, php8 son los binarios necesarios para ejecutar código php, este lo pueden extraer de xampp y lo demas son los archivos de electronJS

Ahora en el archivo de configuración de código igniter en config/app.php en la base URL la dejamos asi

public $baseURL = '[http://localhost:8097/](http://localhost:8097/)';

El archivo Ejecutar.bat es el que va iniciar todo el codeigniter y dentro de el va el siguiente codigo

@echo off

php8\php.exe convertidorXMLPDF/spark serve --port 8097

El archivo Ejecutar.bat se ejecuta automáticamente al abrir el ejecutable

Y listo ahora solo queda hacer el instalador pero lo dejamos para otro manual.

Crear un Conversor de Facturas XML Mexicanas a PDF en CodeIgniter4

En este pequeño tutorial vamos a mostrar como crear rápidamente un conversor XML a PDF de las facturas electrónicas Mexicanas
Requisitos

  1. Tener instalado la versión mas reciente de Composer
  2. Conocimiento básico de PHP y Programación
  3. Ganas de aprender

Paso uno creamos el proyecto en CodeIgniter 4

composer create-project codeigniter4/appstarter convertidorXMLPDF

Actualizamos

composer update

Instalamos de composer el paquete que convierte el xml PDF

composer require phpcfdi/cfditopdf

creamos el archivo FileUpload.php en controladores

<?php 
namespace App\Controllers;
// use App\Models\FormModel;
use CodeIgniter\Controller;
class FileUpload extends Controller
{
    public function index() 
    {
        return view('home');
    }
    function upload() { 
        helper(['form', 'url','filesystem']);



 
            $xml = $this->request->getFile('file');
           /* $img->move(WRITEPATH . 'uploads');
    
            $data = [
               'name' =>  $img->getName(),
               'type'  => $img->getClientMimeType()
            ];
    
            $save = $db->insert($data);
            print_r('File has successfully uploaded');     */


         //  echo $_FILES['file']['tmp_name'];
            $string = file_get_contents($_FILES['file']['tmp_name']);

         
            // clean cfdi
            $xml = \PhpCfdi\CfdiCleaner\Cleaner::staticClean($string);

            
         
            // create the main node structure
            $comprobante = \CfdiUtils\Nodes\XmlNodeUtils::nodeFromXmlString($xml);

            // create the CfdiData object, it contains all the required information
            $cfdiData = (new \PhpCfdi\CfdiToPdf\CfdiDataBuilder())
                ->build($comprobante);

            // create the converter
            $converter = new \PhpCfdi\CfdiToPdf\Converter(
                new \PhpCfdi\CfdiToPdf\Builders\Html2PdfBuilder()
            );

            // create the invoice as output.pdf
            $converter->createPdfAs($cfdiData,  'output.pdf');
            
                $filename = WRITEPATH . 'uploads\output.pdf';
                
                echo '
                <script type="text/javascript">
                    window.open("/output.pdf" , "_blank");
                  </script>';
                
             
               return view('welcome_message');
                  
                
        }
     
    
}

*Agregamos el formulario en las vistas en este caso al archivo welcome_message.php

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Conversor CFDI!</title>
        <meta name="description" content="Pequeño y poderoso conversor de CFDI XML a PDF hecho en CodeIgnter">
        <meta name="keywords" content="CFDI, CFDI 4.0, CFDI 3.3, Representación Impresa, CodeIgniter, Factura Electrónica"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="shortcut icon" type="image/png" href="/favicon.ico"/>

        <!-- STYLES -->

        <style {csp-style-nonce}>
            * {
                transition: background-color 300ms ease, color 300ms ease;
            }
            *:focus {
                background-color: rgba(221, 72, 20, .2);
                outline: none;
            }
            html, body {
                color: rgba(33, 37, 41, 1);
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
                font-size: 16px;
                margin: 0;
                padding: 0;
                -webkit-font-smoothing: antialiased;
                -moz-osx-font-smoothing: grayscale;
                text-rendering: optimizeLegibility;
            }
            header {
                background-color: rgba(247, 248, 249, 1);
                padding: .4rem 0 0;
            }
            .menu {
                padding: .4rem 2rem;
            }
            header ul {
                border-bottom: 1px solid rgba(242, 242, 242, 1);
                list-style-type: none;
                margin: 0;
                overflow: hidden;
                padding: 0;
                text-align: right;
            }
            header li {
                display: inline-block;
            }
            header li a {
                border-radius: 5px;
                color: rgba(0, 0, 0, .5);
                display: block;
                height: 44px;
                text-decoration: none;
            }
            header li.menu-item a {
                border-radius: 5px;
                margin: 5px 0;
                height: 38px;
                line-height: 36px;
                padding: .4rem .65rem;
                text-align: center;
            }
            header li.menu-item a:hover,
            header li.menu-item a:focus {
                background-color: rgba(221, 72, 20, .2);
                color: rgba(221, 72, 20, 1);
            }
            header .logo {
                float: left;
                height: 44px;
                padding: .4rem .5rem;
            }
            header .menu-toggle {
                display: none;
                float: right;
                font-size: 2rem;
                font-weight: bold;
            }
            header .menu-toggle button {
                background-color: rgba(221, 72, 20, .6);
                border: none;
                border-radius: 3px;
                color: rgba(255, 255, 255, 1);
                cursor: pointer;
                font: inherit;
                font-size: 1.3rem;
                height: 36px;
                padding: 0;
                margin: 11px 0;
                overflow: visible;
                width: 40px;
            }
            header .menu-toggle button:hover,
            header .menu-toggle button:focus {
                background-color: rgba(221, 72, 20, .8);
                color: rgba(255, 255, 255, .8);
            }
            header .heroe {
                margin: 0 auto;
                max-width: 1100px;
                padding: 1rem 1.75rem 1.75rem 1.75rem;
            }
            header .heroe h1 {
                font-size: 2.5rem;
                font-weight: 500;
            }
            header .heroe h2 {
                font-size: 1.5rem;
                font-weight: 300;
            }
            section {
                margin: 0 auto;
                max-width: 1100px;
                padding: 2.5rem 1.75rem 3.5rem 1.75rem;
            }
            section h1 {
                margin-bottom: 2.5rem;
            }
            section h2 {
                font-size: 120%;
                line-height: 2.5rem;
                padding-top: 1.5rem;
            }
            section pre {
                background-color: rgba(247, 248, 249, 1);
                border: 1px solid rgba(242, 242, 242, 1);
                display: block;
                font-size: .9rem;
                margin: 2rem 0;
                padding: 1rem 1.5rem;
                white-space: pre-wrap;
                word-break: break-all;
            }
            section code {
                display: block;
            }
            section a {
                color: rgba(221, 72, 20, 1);
            }
            section svg {
                margin-bottom: -5px;
                margin-right: 5px;
                width: 25px;
            }
            .further {
                background-color: rgba(247, 248, 249, 1);
                border-bottom: 1px solid rgba(242, 242, 242, 1);
                border-top: 1px solid rgba(242, 242, 242, 1);
            }
            .further h2:first-of-type {
                padding-top: 0;
            }
            footer {
                background-color: rgba(221, 72, 20, .8);
                text-align: center;
            }
            footer .environment {
                color: rgba(255, 255, 255, 1);
                padding: 2rem 1.75rem;
            }
            footer .copyrights {
                background-color: rgba(62, 62, 62, 1);
                color: rgba(200, 200, 200, 1);
                padding: .25rem 1.75rem;
            }
            @media (max-width: 629px) {
                header ul {
                    padding: 0;
                }
                header .menu-toggle {
                    padding: 0 1rem;
                }
                header .menu-item {
                    background-color: rgba(244, 245, 246, 1);
                    border-top: 1px solid rgba(242, 242, 242, 1);
                    margin: 0 15px;
                    width: calc(100% - 30px);
                }
                header .menu-toggle {
                    display: block;
                }
                header .hidden {
                    display: none;
                }
                header li.menu-item a {
                    background-color: rgba(221, 72, 20, .1);
                }
                header li.menu-item a:hover,
                header li.menu-item a:focus {
                    background-color: rgba(221, 72, 20, .7);
                    color: rgba(255, 255, 255, .8);
                }
            }
        </style>
    </head>
    <body>

        <!-- HEADER: MENU + HEROE SECTION -->
        <header>

            <div class="menu">
                <ul>
                    <li class="logo">
                        <a href="https://cesarsystems.com.mx/" target="_blank">
                            <img src="<?php echo base_url();?>/logo.png"
                                 aria-label="Visita mi pagina oficial para mas programas y utilidades!"/></img>
                        </a>
                    </li>
                    <li class="menu-toggle">
                        <button onclick="toggleMenu();">&#9776;</button>
                    </li>
                    <li class="menu-item hidden"><a href="#">Inicio</a></li>
                    <li class="menu-item hidden"><a href="https://cesarsystems.com.mx/" target="_blank">Descargas</a>
                    </li>
                    <li class="menu-item hidden"><a href="https://www.youtube.com/c/rasec555" target="_blank">Comunidad</a></li>
                    <li class="menu-item hidden"><a
                            href="https://patreon.com/user?u=74078772&utm_medium=clipboard_copy&utm_source=copyLink&utm_campaign=creatorshare_creator" target="_blank">Patrocinar</a>
                    </li>
                </ul>
            </div>

            <div class="heroe">

                <h1>Bienvenido a Conversor XML A PDF V2</h1>

                <h2>Un simple software para convertir los CFDI XML a PDF</h2>

            </div>

        </header>

        <!-- CONTENT -->

        <section>

            <h1>Acerca de este programa</h1>

            <p>Este programa toma los archivos XML de la factura 3.3 o 4.0 para convertirlos a una representación generica impresa de un Comprobante Fiscal Digital</p>

            <p>Para convertir el XML a PDF puede arrastrar el archivo XML en el Boton llamado "Seleccionar archivo" </p>

            <p>En caso de que no salga el PDF asegurate de no tener bloqueado el popup o desbloquealo para esta pagina ya que el pdf saldra en el popup" </p>



            <form method="post" action="<?php echo base_url('FileUpload/upload'); ?>" enctype="multipart/form-data">
                <div class="form-group">
                    <label>Seleccione el archivo XML </label>
                    <input type="file" name="file" id="file"  accept=".xml" class="form-control">
                </div>
                <div class="form-group">
                    <button type="submit" class="btn btn-danger">Generar PDF</button>
                </div>
            </form>

        </section>

        <div class="further">

            <section>

                <h1>¡Ir por más!</h1>

                <h2>
                    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><rect x='32' y='96' width='64' height='368' rx='16' ry='16' style='fill:none;stroke:#000;stroke-linejoin:round;stroke-width:32px'/><line x1='112' y1='224' x2='240' y2='224' style='fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px'/><line x1='112' y1='400' x2='240' y2='400' style='fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px'/><rect x='112' y='160' width='128' height='304' rx='16' ry='16' style='fill:none;stroke:#000;stroke-linejoin:round;stroke-width:32px'/><rect x='256' y='48' width='96' height='416' rx='16' ry='16' style='fill:none;stroke:#000;stroke-linejoin:round;stroke-width:32px'/><path d='M422.46,96.11l-40.4,4.25c-11.12,1.17-19.18,11.57-17.93,23.1l34.92,321.59c1.26,11.53,11.37,20,22.49,18.84l40.4-4.25c11.12-1.17,19.18-11.57,17.93-23.1L445,115C443.69,103.42,433.58,94.94,422.46,96.11Z' style='fill:none;stroke:#000;stroke-linejoin:round;stroke-width:32px'/></svg>
                    Descargas y tutoriales
                </h2>

                <p>Puedes encontrar mas aplicativos, manuales y tutoriales en la siguiente pagina <a href="https://cesarsystems.com.mx/"
                                                target="_blank">Pagina Principal</a> !</p>

                <h2>
                    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><path d='M431,320.6c-1-3.6,1.2-8.6,3.3-12.2a33.68,33.68,0,0,1,2.1-3.1A162,162,0,0,0,464,215c.3-92.2-77.5-167-173.7-167C206.4,48,136.4,105.1,120,180.9a160.7,160.7,0,0,0-3.7,34.2c0,92.3,74.8,169.1,171,169.1,15.3,0,35.9-4.6,47.2-7.7s22.5-7.2,25.4-8.3a26.44,26.44,0,0,1,9.3-1.7,26,26,0,0,1,10.1,2L436,388.6a13.52,13.52,0,0,0,3.9,1,8,8,0,0,0,8-8,12.85,12.85,0,0,0-.5-2.7Z' style='fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><path d='M66.46,232a146.23,146.23,0,0,0,6.39,152.67c2.31,3.49,3.61,6.19,3.21,8s-11.93,61.87-11.93,61.87a8,8,0,0,0,2.71,7.68A8.17,8.17,0,0,0,72,464a7.26,7.26,0,0,0,2.91-.6l56.21-22a15.7,15.7,0,0,1,12,.2c18.94,7.38,39.88,12,60.83,12A159.21,159.21,0,0,0,284,432.11' style='fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/></svg>
                    Grupos
                </h2>

                <p>Puede seguirnos en los siguientes grupos y redes sociales como <a href="https://www.youtube.com/c/rasec555"
                                      target="_blank">Canal de youtube </a>, 
                                      
                                      <a href="https://t.me/CesarSystems"
                                      target="_blank">Canal de Telegram</a> ,
                                      
                                      <a href="https://twitter.com/JulioLeyvaR"
                                      target="_blank">Twitter</a> ,
                                      
                                       <a href="https://odysee.com/@JulioCesarLeyvaRodriguez:9"
                                      target="_blank">Odysee</a> y
                                      
                                      <a href="https://www.facebook.com/rasec555/"
                                      target="_blank">Facebook</a> 
                
                
                </p>

                <h2>
                    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><line x1='176' y1='48' x2='336' y2='48' style='fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='118' y1='304' x2='394' y2='304' style='fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><path d='M208,48v93.48a64.09,64.09,0,0,1-9.88,34.18L73.21,373.49C48.4,412.78,76.63,464,123.08,464H388.92c46.45,0,74.68-51.22,49.87-90.51L313.87,175.66A64.09,64.09,0,0,1,304,141.48V48' style='fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/></svg>
                    Patrocinar
                </h2>

                <p>Puedes apoyar nuestros proyectos en Patreon y obtendras acceso exclusivo a los fuentes mas recientes
                    <a href="https://patreon.com/user?u=74078772&utm_medium=clipboard_copy&utm_source=copyLink&utm_campaign=creatorshare_creator" target="_blank">
                        Unete</a> </p>

            </section>

        </div>

        <!-- FOOTER: DEBUG INFO + COPYRIGHTS -->

        <footer>
            <div class="environment">

                <p>Tiempo de Renderizado {elapsed_time} seconds</p>

            

            </div>

            <div class="copyrights">

                <p>&copy; <?= date('Y') ?> Conversor XML a PDF es un proyecto de código abierto lanzado con la licencia MIT
                    open source licence.</p>

            </div>

        </footer>

        <!-- SCRIPTS -->

        <script>
            function toggleMenu() {
                var menuItems = document.getElementsByClassName('menu-item');
                for (var i = 0; i < menuItems.length; i++) {
                    var menuItem = menuItems[i];
                    menuItem.classList.toggle("hidden");
                }
            }
        </script>

        <!-- -->

    </body>
</html>

Y por último agregamos esto en las rutas

$routes->get('/', 'FileUpload::index');
$routes->match(['get', 'post'], 'FileUpload/upload', 'FileUpload::upload');

y listo pueden ver un ejemplo de como quedo en el siguiente enlace https://xml2pdf.cesarsystems.com.mx/

CREANDO SISTEMA DE CONSULTORIO MEDICO – INSTALANDO CODEIGNITER 4.1.1 EN PHP8 CAPITULO #1

En esta serie de vídeos veremos como hacer un sistema basico de consultorio medico En este capitulo veremos las caracteristicas de codeigniter hasta su instalación básica cualquier distribución de GNU/Linux basade de Ubuntu 18.04 en este caso es Zorin Linux Core 15.3
0:00 Intro
1:00 Descargar Code Igniter
1:32 Caracteristicas
4:15 Requisitos del Servidor
6:13 Configurando CodeIgniter con Netbeans 12.0
10:30 Instalando Extensiones PHP Necesarias

VK
https://vk.com/id543521033

FACEBOOK
https://www.facebook.com/rasec555

TWITTER
https://twitter.com/Cesar101290

CHANNEL TELEGRAM
https://telegram.me/CesarSystems


PAGINA WEB https://cesarsystems.com.mx/

MOVIL / WHATSAPP

6688612348

Página 2 de 2

Creado con WordPress & Tema de Anders Norén