Mostrando las entradas con la etiqueta Programación. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Programación. Mostrar todas las entradas

martes, 21 de abril de 2026

¿Qué son los breadcrumbs?

Son una serie de enlaces, normalmente en la parte superior de una página, como:

Inicio > Productos > Electrónica > Celulares

Cada parte es clickeable y permite regresar a niveles anteriores.

<?php 
$breadcrumbs = [
    "Inicio" => "index.php",
    "Productos" => "productos.php",
    "Celulares" => "celulares.php",
    "Samsung" => ""
];
?>

 <nav>
     <?php foreach ($breadcrumbs as $nombre => $link): ?>
         <?php if ($link): ?>
             <a href=" <?= $link ?>"> <?= $nombre ?> </a> >
         <?php else: ?>
             <span> <?= $nombre ?> </span>
         <?php endif; ?>
     <?php endforeach; ?>
 </nav>

viernes, 6 de junio de 2025

Ejemplos de Estilos Bootstrap

Ejemplos de Estilos Bootstrap

Ejemplos de Estilos de Bootstrap

1. Tipografía


h1 - h6

Bootstrap redefine los estilos de los encabezados <h1> a <h6>.

Encabezado h1

Encabezado h2

Encabezado h3

Encabezado h4

Encabezado h5
Encabezado h6

display-1 a display-6

Clases para encabezados más grandes y destacados.

Display 1

Display 4

text-muted

Color de texto más suave.

Este es un texto con la clase `text-muted`.

fw-bold, fst-italic, text-decoration-underline

Clases para modificar el estilo del texto.

Texto en negrita (`fw-bold`)

Texto en cursiva (`fst-italic`)

Texto subrayado (`text-decoration-underline`)

2. Botones


btn btn-[color]

Estilos de botones con diferentes colores predefinidos.

btn-outline-[color]

Botones con contorno.

btn-lg, btn-sm

Tamaños de botones.

3. Sistema de Rejilla (Grid System)


.container, .row, .col-[tamaño]-[columnas]

Bootstrap utiliza un sistema de rejilla de 12 columnas. El `container` es el ancho máximo, el `row` contiene las columnas y las `col` definen el ancho de cada columna.

Columna 1 (sm-4)
Columna 2 (sm-4)
Columna 3 (sm-4)
Columna 1 (md-6)
Columna 2 (md-6)

4. Alertas


.alert .alert-[color]

Mensajes de alerta con diferentes significados.

5. Tarjetas (Cards)


.card

Contenedores flexibles para mostrar contenido de forma organizada.

Título de la Tarjeta
Subtítulo

Algun ejemplo de texto rápido para construir el contenido de la tarjeta y que se ajuste al tamaño.

Enlace de Tarjeta Otro enlace
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ejemplos de Estilos Bootstrap</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <style>
        .example-section {
            background-color: #f8f9fa;
            border: 1px solid #dee2e6;
            padding: 20px;
            margin-bottom: 20px;
            border-radius: 5px;
        }
    </style>
</head>
<body>

    <div class="container mt-5">
        <h1 class="mb-4 text-center">Ejemplos de Estilos de Bootstrap</h1>

        <div class="example-section">
            <h2>1. Tipografía</h2>
            <hr>
            <h3><span class="badge bg-primary">h1 - h6</span></h3>
            <p>Bootstrap redefine los estilos de los encabezados <code><h1></code> a <code><h6></code>.</p>
            <h1>Encabezado h1</h1>
            <h2>Encabezado h2</h2>
            <h3>Encabezado h3</h3>
            <h4>Encabezado h4</h4>
            <h5>Encabezado h5</h5>
            <h6>Encabezado h6</h6>

            <h3 class="mt-4"><span class="badge bg-primary">display-1 a display-6</span></h3>
            <p>Clases para encabezados más grandes y destacados.</p>
            <p class="display-1">Display 1</p>
            <p class="display-4">Display 4</p>

            <h3 class="mt-4"><span class="badge bg-primary">text-muted</span></h3>
            <p>Color de texto más suave.</p>
            <p class="text-muted">Este es un texto con la clase `text-muted`.</p>

            <h3 class="mt-4"><span class="badge bg-primary">fw-bold, fst-italic, text-decoration-underline</span></h3>
            <p>Clases para modificar el estilo del texto.</p>
            <p class="fw-bold">Texto en negrita (`fw-bold`)</p>
            <p class="fst-italic">Texto en cursiva (`fst-italic`)</p>
            <p class="text-decoration-underline">Texto subrayado (`text-decoration-underline`)</p>
        </div>

        <div class="example-section">
            <h2>2. Botones</h2>
            <hr>
            <h3><span class="badge bg-primary">btn btn-[color]</span></h3>
            <p>Estilos de botones con diferentes colores predefinidos.</p>
            <button type="button" class="btn btn-primary me-2">Botón Primario</button>
            <button type="button" class="btn btn-secondary me-2">Botón Secundario</button>
            <button type="button" class="btn btn-success me-2">Botón Éxito</button>
            <button type="button" class="btn btn-danger me-2">Botón Peligro</button>
            <button type="button" class="btn btn-warning me-2">Botón Advertencia</button>
            <button type="button" class="btn btn-info me-2">Botón Información</button>
            <button type="button" class="btn btn-light me-2">Botón Claro</button>
            <button type="button" class="btn btn-dark me-2">Botón Oscuro</button>
            <button type="button" class="btn btn-link">Botón Enlace</button>

            <h3 class="mt-4"><span class="badge bg-primary">btn-outline-[color]</span></h3>
            <p>Botones con contorno.</p>
            <button type="button" class="btn btn-outline-primary me-2">Primario</button>
            <button type="button" class="btn btn-outline-success me-2">Éxito</button>

            <h3 class="mt-4"><span class="badge bg-primary">btn-lg, btn-sm</span></h3>
            <p>Tamaños de botones.</p>
            <button type="button" class="btn btn-primary btn-lg me-2">Botón Grande</button>
            <button type="button" class="btn btn-secondary btn-sm">Botón Pequeño</button>
        </div>

        <div class="example-section">
            <h2>3. Sistema de Rejilla (Grid System)</h2>
            <hr>
            <h3><span class="badge bg-primary">.container, .row, .col-[tamaño]-[columnas]</span></h3>
            <p>Bootstrap utiliza un sistema de rejilla de 12 columnas. El `container` es el ancho máximo, el `row` contiene las columnas y las `col` definen el ancho de cada columna.</p>
            <div class="container text-center">
                <div class="row">
                    <div class="col-sm-4 bg-info text-white p-3 border">
                        Columna 1 (sm-4)
                    </div>
                    <div class="col-sm-4 bg-primary text-white p-3 border">
                        Columna 2 (sm-4)
                    </div>
                    <div class="col-sm-4 bg-success text-white p-3 border">
                        Columna 3 (sm-4)
                    </div>
                </div>
                <div class="row mt-3">
                    <div class="col-md-6 bg-warning text-dark p-3 border">
                        Columna 1 (md-6)
                    </div>
                    <div class="col-md-6 bg-danger text-white p-3 border">
                        Columna 2 (md-6)
                    </div>
                </div>
            </div>
        </div>

        <div class="example-section">
            <h2>4. Alertas</h2>
            <hr>
            <h3><span class="badge bg-primary">.alert .alert-[color]</span></h3>
            <p>Mensajes de alerta con diferentes significados.</p>
            <div class="alert alert-primary" role="alert">
                ¡Esta es una alerta primaria!
            </div>
            <div class="alert alert-success" role="alert">
                ¡Éxito! Tu operación se realizó correctamente.
            </div>
            <div class="alert alert-danger" role="alert">
                ¡Error! Algo salió mal.
            </div>
        </div>

        <div class="example-section">
            <h2>5. Tarjetas (Cards)</h2>
            <hr>
            <h3><span class="badge bg-primary">.card</span></h3>
            <p>Contenedores flexibles para mostrar contenido de forma organizada.</p>
            <div class="card" style="width: 18rem;">
                <div class="card-body">
                    <h5 class="card-title">Título de la Tarjeta</h5>
                    <h6 class="card-subtitle mb-2 text-muted">Subtítulo</h6>
                    <p class="card-text">
                        Algun ejemplo de texto rápido para construir el contenido de la tarjeta y que se ajuste al tamaño.
                    </p>
                    <a href="#" class="card-link">Enlace de Tarjeta</a>
                    <a href="#" class="card-link">Otro enlace</a>
                </div>
            </div>
        </div>

    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>>

martes, 27 de mayo de 2025

Validar desde el servidor la introducción de datos al editar y actualizar un registro

app\Models\ContactoModel.php (Queda igual)

<?php

namespace App\Models;

use CodeIgniter\Model;

class ContactoModel extends Model
{
    protected $table = 'contactos';
    protected $primaryKey = 'id';
    protected $allowedFields = ['nombre', 'apellidos', 'celular'];

     protected $validationRules = [
        'nombre'    => 'required|min_length[3]',
        'apellidos' => 'required|min_length[3]',
        'celular'   => 'required|numeric|min_length[7]'
    ];

    protected $validationMessages = [
        'nombre'    => ['required' => 'El nombre es obligatorio.', 'min_length' => 'Debe tener al menos 3 caracteres.'],
        'apellidos' => ['required' => 'Los apellidos son obligatorios.', 'min_length' => 'Los apellidos debe tener al menos 3 caracteres.'],
        'celular'   => ['required' => 'El celular es obligatorio.', 'numeric' => 'El celular debe contener solo números.', 'min_length' => 'El celular debe tener al menos 7 dígitos.']
    ];
}

app\Controllers\Contacto.php (Extracto)

 public function actualizar($id)
    {
        $modelo = new ContactoModel();
        $data = [
            'id' => $id, 
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];


        if (!$modelo->update($id,$data)) {
        // Vuelve a mostrar el formulario con los errores y datos ingresados
        return view('contacto/editar', [
            'errors' => $modelo->errors(),
            'contacto' => $data
            ]);
        }
        return redirect()->to(MI_BASE_URL.'listar')->with('mensaje', 'Contacto actualizado exitosamente.');
    }

app\Views\contacto\editar.php

<h1>Editar Contacto</h1>

    <!-- Mostrar errores si existen -->
    <?php if (isset($errors) && !empty($errors)): ?>
        <div class="error">
            <ul>
                <?php foreach ($errors as $error): ?>
                    <li><?= esc($error) ?></li>
                <?php endforeach; ?>
            </ul>
        </div>
    <?php endif; ?>

<form action="<?= MI_BASE_URL.'actualizar/'.$contacto['id'] ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre" value="<?= $contacto['nombre'] ?>"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos" value="<?= $contacto['apellidos'] ?>"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular" value="<?= $contacto['celular'] ?>"><br><br>
    <input type="submit" value="Actualizar">
</form>

app\Views\contacto\listar.php

<h1>Listado de Contactos</h1>

 <?php if (session()->getFlashdata('mensaje')): ?>
        <p style="color:green"><?= session()->getFlashdata('mensaje') ?></p>
    <?php endif; ?>

<table>
    <tr>
        <th>Nombre</th>
        <th>Apellido</th>
        <th>Celular</th>
        <th>Acciones</th>
    </tr>
    <?php foreach ($contactos as $contacto) : ?>
    <tr>
        <td><?= $contacto['nombre'] ?></td>
        <td><?= $contacto['apellidos'] ?></td>
        <td><?= $contacto['celular'] ?></td>
        <td>
            <a href="<?= MI_BASE_URL.'editar/'.$contacto['id'] ?>">Editar</a>
            <a href="<?= MI_BASE_URL.'eliminar/'.$contacto['id'] ?>">Eliminar</a>
        </td>
    </tr>
    <?php endforeach ?>
</table>

domingo, 25 de mayo de 2025

Validar desde el servidor la introducción de datos al crear un nuevo registro

app\Models\ContactoModel.php

<?php

namespace App\Models;

use CodeIgniter\Model;

class ContactoModel extends Model
{
    protected $table = 'contactos';
    protected $primaryKey = 'id';
    protected $allowedFields = ['nombre', 'apellidos', 'celular'];

     protected $validationRules = [
        'nombre'    => 'required|min_length[3]',
        'apellidos' => 'required|min_length[3]',
        'celular'   => 'required|numeric|min_length[7]'
    ];

    protected $validationMessages = [
        'nombre'    => ['required' => 'El nombre es obligatorio.', 'min_length' => 'Debe tener al menos 3 caracteres.'],
        'apellidos' => ['required' => 'Los apellidos son obligatorios.', 'min_length' => 'Los apellidos debe tener al menos 3 caracteres.'],
        'celular'   => ['required' => 'El celular es obligatorio.', 'numeric' => 'El celular debe contener solo números.', 'min_length' => 'El celular debe tener al menos 7 dígitos.']
    ];
}

app\Controllers\Contacto.php (Extracto)

   public function guardar()
    {
        $modelo = new ContactoModel();
        $data = [
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];

        if (!$modelo->insert($data)) {
                return view('contacto/crear', [
                    'errors' => $modelo->errors(),
                    'old' => $data
                ]);
            }

        return redirect()->to(MI_BASE_URL.'crear')->with('mensaje', 'Contacto agregado correctamente.');
    }

app\Views\contacto\crear.php

<h1>Crear Contacto</h1>


    <?php if (session()->getFlashdata('mensaje')): ?>
        <p style="color:green"><?= session()->getFlashdata('mensaje') ?></p>
    <?php endif; ?>

    <?php if (isset($errors)): ?>
        <ul style="color:red">
            <?php foreach ($errors as $error): ?>
                <li><?= esc($error) ?></li>
            <?php endforeach; ?>
        </ul>
    <?php endif; ?>

    
<form action="<?= MI_BASE_URL.'guardar' ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular"><br><br>
    <input type="submit" value="Crear">
</form>

sábado, 24 de mayo de 2025

CRUD en CodeIgniter 4

app\Models\ContactoModel.php

<?php

namespace App\Models;

use CodeIgniter\Model;

class ContactoModel extends Model
{
    protected $table = 'contactos';
    protected $primaryKey = 'id';
    protected $allowedFields = ['nombre', 'apellidos', 'celular'];
}

app\Controllers\Contacto.php

<?php
namespace App\Controllers;

use App\Models\ContactoModel;

class Contacto extends BaseController
{
    public function index()
    {
        return view('menu');
    }

    public function listar()
    {
        $modelo = new ContactoModel();
        $data['contactos'] = $modelo->findAll();
        return view('contacto/listar', $data);
    }

    public function crear()
    {
        return view('contacto/crear');
    }

    public function guardar()
    {
        $modelo = new ContactoModel();
        $data = [
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];
        $modelo->insert($data);
        return redirect()->to(MI_BASE_URL.'listar');
    }

    public function editar($id)
    {
        $modelo = new ContactoModel();
        $data['contacto'] = $modelo->find($id);
        return view('contacto/editar', $data);
    }

    public function actualizar($id)
    {
        $modelo = new ContactoModel();
        $data = [
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];
        $modelo->update($id, $data);
        return redirect()->to(MI_BASE_URL.'listar');
    }

    public function eliminar($id)
    {
        $modelo = new ContactoModel();
        $modelo->delete($id);
        return redirect()->to(MI_BASE_URL.'listar');
    }

}

app\Views\menu.php

<h1>Menú de Contactos</h1>

<ul>
    <li><a href="<?= MI_BASE_URL.'listar' ?> ">Listar Contactos</a></li>
    <li><a href="<?= MI_BASE_URL.'crear' ?> ">Crear Contacto</a></li>
</ul>

app\Views\contacto\crear.php

<h1>Crear Contacto</h1>

<form action="<?= MI_BASE_URL.'guardar' ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular"><br><br>
    <input type="submit" value="Crear">
</form>

app\Views\contacto\editar.php

<h1>Editar Contacto</h1>

<form action="<?= MI_BASE_URL.'actualizar/'.$contacto['id'] ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre" value="<?= $contacto['nombre'] ?>"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos" value="<?= $contacto['apellidos'] ?>"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular" value="<?= $contacto['celular'] ?>"><br><br>
    <input type="submit" value="Actualizar">
</form>

app\Views\contacto\listar.php

<h1>Listado de Contactos</h1>

<table>
    <tr>
        <th>Nombre</th>
        <th>Apellido</th>
        <th>Celular</th>
        <th>Acciones</th>
    </tr>
    <?php foreach ($contactos as $contacto) : ?>
    <tr>
        <td><?= $contacto['nombre'] ?></td>
        <td><?= $contacto['apellidos'] ?></td>
        <td><?= $contacto['celular'] ?></td>
        <td>
            <a href="<?= MI_BASE_URL.'editar/'.$contacto['id'] ?>">Editar</a>
            <a href="<?= MI_BASE_URL.'eliminar/'.$contacto['id'] ?>">Eliminar</a>
        </td>
    </tr>
    <?php endforeach ?>
</table>

app\Config\Routes.php

<?php

use CodeIgniter\Router\RouteCollection;

/**
 * @var RouteCollection $routes
 */
$routes->get('/', 'Contacto::index');
$routes->get('/listar', 'Contacto::listar');
$routes->get('/crear', 'Contacto::crear');
$routes->post('/guardar', 'Contacto::guardar');
$routes->get('/editar/(:num)', 'Contacto::editar/$1');
$routes->post('/actualizar/(:num)', 'Contacto::actualizar/$1');
$routes->get('/eliminar/(:num)', 'Contacto::eliminar/$1');

Un tropiezo en el camino: base_url() y site_url()

Me encontraba creando la segunda aplicación web en CodeIgniter cuando me tropezé con base_url() en el contexto de usarla para llamar una pagina php o html, definido previamente con una ruta. Primero me producía error al cargar las páginas. Luego de verificar que no estaba mal la configuración de las rutas y de escribir manualmente el recurso solicitado en la barra de direcciones, llegué a la conclusión de que no estaba funcionando adecuadamente. Al intentar modificar el contenido de la función para que apuntara a la url correcta en el archivo de configuración correspondiente, observé como toda la aplicación estallaba catastroficamente. Entonces, decidí no tocarla para nada, ni a base_url() y tampoco a site_url() e implementar mi propia constante para tener la ruta correcta y que no reviente toda la aplicación. Así que lo que hice fue agregar las siguientes lineas al archivo app\Config\Constants.php en el que se define una cosntante llamada MI_BASE_URL:

 $miBaseURL = "http://".$_SERVER['HTTP_HOST'];
 $miBaseURL .= str_replace(basename($_SERVER['SCRIPT_NAME']),'', $_SERVER['SCRIPT_NAME']);
 defined('MI_BASE_URL')      || define('MI_BASE_URL',$miBaseURL);

Luego, se puede usar esta constante en donde se necesite llamar a cualquier recurso:

<a href="<?= MI_BASE_URL.'listar' ?> ">Listar Contactos</a>

viernes, 23 de mayo de 2025

Mi primera Aplicación Web con CodeIgniter 4: Mostrando registros de la tabla

app/Models/AgendaModel.php

<?php 
namespace App\Models;

use CodeIgniter\Model;

class AgendaModel extends Model
{
	protected $table = 'contactos';
	protected $primaryKey = 'id';
	protected $allowedFields = ['id','nombre','apellidos','celular'];

	public function getAll()
	{
		return $this->findAll();
	}
}

app/Controllers/AgendaController.php

<?php 
namespace App\Controllers;

use App\Models\AgendaModel;

class AgendaController extends BaseController
{
	public function index()
	{
		$AgendaModel = new AgendaModel();
		$data['agenda'] = $AgendaModel->getAll();
		return view('agenda',$data);
	}
}

app/Views/agenda.php

<h1>Agenda</h1>
<table>
	<thead>
		<tr>
			<th>Id</th>
			<th>Nombre</th>
			<th>Apellidos</th>
			<th>Celular</th>
		</tr>
	</thead>
	<tbody>
		<?php foreach($agenda as $item): ?>
			<tr>
				<td> <?= $item['id'] ?> </td>
				<td> <?= $item['nombre'] ?> </td>
				<td> <?= $item['apellidos'] ?> </td>
				<td> <?= $item['celular'] ?> </td>
			</tr>
		<?php endforeach ?>
	</tbody>
</table>

app/Config/Routes.php

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

Creando y configurando la base de datos.

  • Desde phpMyAdmin crear una base de datos llamada agenda, dentro de esta una tabla llamada contactos y dentro de esta cuatro campos llamados id, nombre, apellidos y celular. establecer Id con el atributo de AUTO_INCREMENT y como clave principal.
  • Configurar los parametros de la base de datos. Dentro de la carpeta del proyecto de CodeIgniter, entrar a app/Config/database.php y establecer valores como el nombre de la base de datos, el usuario y la contraseña entre otros.

Creando manualmente un proyecto en CodeIgniter 4.6.1

  • Descargar el archivo zip.
  • Descomprimir y guardar en la carpeta htdocs de XAMP.
  • Establecer un nombre adecuado para la carpeta. En mi caso le voy a llamar agenda
  • Dentro de la carpeta renombrar el archivo env a .env. Dentro del archivo .env establecer el entorno de trabajo a desarrollo en vez de producción. Para ello se descomenta la linea # CI_ENVIRONMENT = production y se modifica para que quede así: CI_ENVIRONMENT = development
  • En este punto se puede probar que se ha iniciado el proyecto adecuadamente. Se inicia Apache y en la barra de direcciones del navegador se escribe localhost/agenda. Se ingresa a public y allí deberá aparecer el mensaje de bienvenida y en la parte de abajo un mensaje indicando que está en modo de desarrollo.

Instalando XAMP y dejando todo listo para empezar

  • Descargar XAMP for Windows.
  • Ejecutar el instalador como administrador.
  • Tal vez haya que modificar el UAC (User Account Control) pero en mi caso no tuve que hacer nada.
  • Desde el panel de control de XAMP abrir el archivo de configuración php.ini y activar la extensión intl.
  • Ejecutar el Servidor Apache y MySQL.
  • En la primera ejecución se pedirá permiso para que el firewall de windows no los bloquee.
  • Escribir en la barra de direcciones del navegador localhost para verificar que todo esté funcionando bien.

martes, 13 de mayo de 2025

Una nueva forma de crear aplicaciones webs ... para mi.

Me gusta mucho el lenguaje PHP, pero hasta ahora solo lo he usado en su versión estructurada y sin un framework. Es hora de iniciar un proceso para crear una app web usando herramientas más profesionales. Estas son:

  • XAMP for Windows 8.0.30
  • Codeigniter 4.6.1
  • Visual Studio Code

Agrupada bajo una misma etiqueta, la intención es ir registrando todo lo necesario para crear una aplicación web de manera más profesional y aplicando los mejores practicas de programación.

martes, 29 de agosto de 2023

PHP: Una arquitectura de aplicación personalizada

Intentando resolver el problema planteado en esta entrada, me había puesto a crear (con mucha ayuda) un sistema MVC personalizado para aplicaciones PHP tal como se muestra en esta otra entrada. Tambien consideré aprender a fondo Codeigniter e incluso Laravel. Después de darle vueltas al asunto me he propuesto crear una arquitectura parecida a la MVC pero un poco más sencilla, que permita implementar buenas practicas de programación. Las principales características de esta opción son las siguientes:

  • No usa POO. Me parece que con la programación estructurada se mantiene más sencillo el código y a efectos prácticos, para los proyectos que pienso manejar, funciona bien.
  • Se divide el proyecto en dos bloques: Del lado dl cliente y del lado del servidor.
  • Se elimina el controlador principal que se usa en la arquitectura MVC.
  • Básicamente solo quedan las vistas y los modelos, las cuales se encuentran en carpetas distintas pero tienen los mismos nombres. Los controladores individuales se ha fusionado con el modelo pero su presencia es casi inperceptible.
  • Siempre se invoca primero el modelo y luego la vista: siempre en ese orden.
Estructura de la carpeta

El siguiente código es mi versión personalizada de una aplicación hecha con la arquitectura personalizada que he planteado.

index.php

<a href="mo/estudiante_listar.php"> Listar </a>

mo/a_conectar.php

<?php 

if (!($link=mysqli_connect("localhost","root","9810402254"))) 
   
	{ 
      
	echo "Error conectando a la base de datos.";
  
      exit(); 
   
	} 

if (!mysqli_select_db($link,"colegio")) 
   
	{ 
      
	echo "Error seleccionando la base de datos.";
  
      exit(); 
  
	}
  
?>

mo/estudiante_listar.php

<?php 
$dato = array();

require("a_conectar.php");
$rs = mysqli_query($link," select * from estudiantes ");

while($f = mysqli_fetch_array($rs))
        {  
	$dato[] = $f;
	}

mysqli_free_result($rs);
mysqli_close($link); 

require("../vi/estudiante_listar.php");
?>

vi/estudiante_listar.php

<table>
<tr>
<td>ID</td>
<td>NOMBRES</td>
<td>APELLIDOS</td>
</tr>
 
<?php foreach ($dato as $d): ?>
   <tr>
   <td><?php echo $d['id'] ?></td>
   <td><?php echo $d['nombres'] ?></td>
   <td><?php echo $d['apellidos'] ?></td>
   </tr>
<?php endforeach; ?>

</table>

sábado, 26 de agosto de 2023

PHP: Creando una aplicación MVC personalizada con POO

El siguiente código es una versión personalizada de una aplicación hecha en PHP que permite realizar la misma acción que la de esta entrada. Precisamente la única diferencia es que se implementa en una arquitectura MVC y la mayoría ha sido adaptado de otros códigos encontrados en Internet.

Estructura de carpetas

index.php

<?php 

require_once 'conf/config.php';

if(!isset($_GET["c"])) $_GET["c"] = constant("DEFAULT_CONTROLLER");
if(!isset($_GET["a"])) $_GET["a"] = constant("DEFAULT_ACTION");

// Establece la ruta donde se encuentra el controlador
$controller_path = 'controladores/'.$_GET["c"].'.php';

// Pregunta si el archivo con el controlador existe.
if(!file_exists($controller_path)) $controller_path = 'controladores/'.constant("DEFAULT_CONTROLLER").'.php';

/* Load controller */
require_once $controller_path;
$controllerName = $_GET["c"].'Controlador';
$controller = new $controllerName();

// crea $dato como un arreglo vacío
$dato = array();
// Si el método existe lo ejecuta y recibe el resultado en el arreglo $dato
if(method_exists($controller,$_GET["a"])) $dato = $controller->{$_GET["a"]}(); 


// Carga las vistas
require_once 'vistas/plantillas/cabeza.php';
require_once 'vistas/'.$controller->vista.'.php';
require_once 'vistas/plantillas/pie.php';

?>

conf/config.php

<?php

/* Valores de conexión a la base de datos*/
define("DB_HOST", "localhost");
define("DB", "colegio");
define("DB_USER", "root");
define("DB_PASS", "9810402254");

/* Controlador y acción (método) por defecto. */
define("DEFAULT_CONTROLLER", "estudiante");
define("DEFAULT_ACTION", "listar");

?>

controladores/estudiante.php

<?php 

// Este controlador usa un modelo 
require_once 'modelos/estudianteModelo.php';


class estudianteControlador 
	{
	//la variable vista contiene el archivo que mostrará la vista al usuario 
	public $vista ;

	public function __construct() 
		{
		
		}

		public function listar()
		{
		// Se asigna el nombre de la vista que se mostrará al usuario como resultado de esta acción 
		$this->vista = "estudianteListar";
		//Creación del modelo que accederá a la base de datos. 
		$m = new estudianteModelo();
		// Se ejecuta el método para listar y se obtiene el resultado en la variable rs
		$rs = $m->obtenerEstudiantes();
		// Se devuelve el arreglo obtenido. 
		return $rs;
		}

	}


?>

modelos/bd.php

<?php 

// Establece una conexión con la base de datos usando PDO y de acuerdo a los valores que se encuentran en el archivo de configuración.

require_once 'conf/config.php';

class bd {

	private $host;
	private $db;
	private $user;
	private $pass;
	public $conection;

	public function __construct() {		

		$this->host = constant('DB_HOST');
		$this->db = constant('DB');
		$this->user = constant('DB_USER');
		$this->pass = constant('DB_PASS');

		try {
           $this->conection = new PDO('mysql:host='.$this->host.'; dbname='.$this->db, $this->user, $this->pass);
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit();
        }

	}

}

?>

modelos/estudianteModelo.php

<?php 

require_once 'modelos/bd.php';

class estudianteModelo {

	// la variable con guardará la conexión.
	private $con;

	public function __construct() 
			{

			}

	// Establece y guarda el valor de la conexión.
	public function establecerConeccion(){
		$dbObj = new bd();
		$this->con = $dbObj->conection;
	}


	public function obtenerEstudiantes(){
		
		// Establece la conexión.
		$this->establecerConeccion();
		// Realiza la consulta y guarda el resultado.
		$sql = "SELECT * FROM ESTUDIANTES";
		$s = $this->con->prepare($sql);
		$s->execute();
		// fetchAll — Devuelve un array que contiene todas las filas del conjunto de resultados.
		$rs = $s->fetchAll();
		// Retorna el valor del resutado.
		return $rs;
	}

// Considerar establecer un destructor para cerrar la conexión a la base de datos. Aunque el recolector de basura de PHP también se encargrá de esta operación.
	
}

?>

vistas/estudianteListar.php

<table>
    <tr>
        <th>Id</th>
        <th>Nombres</th>
        <th>Apellidos</th>

    </tr>
    <?php foreach ($dato as $r): ?>

        <tr>
            <td><?php echo $r["id"] ?></td>
            <td><?php echo $r["nombres"] ?></td>
            <td><?php echo $r["apellidos"] ?></td>

        </tr>

     <?php endforeach; ?>
</table>

vistas/plantillas/cabeza.php

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title></title>
</head>
<body>

vistas/plantillas/pie.php

</div>
</body>
</html>

miércoles, 19 de julio de 2023

Arte Pixel

  CORAZÓN 1 
Ancho: 11

  MUJER  
Ancho: 34

  PINGUINO 
Ancho: 10

  CORAZÓN 2 
Ancho: 13

En el siguiente script se puede probar las instrucciones para generar Arte Pixel:

Ancho:

Instrucciones:

Código fuente del generador de Arte Pixel en JavaScript:

<div>
<form  style="background-color: lightgrey;" > 
Ancho:<br> <input type = text id =ancho placeholder="Ancho"  /> <br>
Instrucciones:<br> <textarea rows="30" cols="20" id="texto" placeholder="Instrucciones">


</textarea>
<p> <button onclick="armar()" type="button">Armar</button> </p>   
<p> <button onclick="borrar()" type="button">Borrar</button> </p>   
</form>
</div>

<div id ="tabla">

</div>

<script>  

function armar() 
 {  
  var s,text,a,color,pasos,linea,i,ancho,anchoactual,j,canlineas,colorcelda;
  s = document.getElementById("texto").value;
  ancho = parseInt(document.getElementById("ancho").value);
  a = s.split(/\n/);
  text = "<table border = 1  cellpadding= 0 cellspacing = 0>";
   i=0;
   anchoactual = 0;
   canlineas = a.length;
   while (i < canlineas)
   {
    linea = a[i];
    color = linea[0];
    pasos = parseInt(linea.slice(1));
    for (j=1;j<=pasos;j++)
    {
      
      if (anchoactual==0)
      {
        text = text + "<tr>";        
      }

      colorcelda = " ";
      if (color == "N" || color == "n" )
        {
          colorcelda = " bgcolor = black ";
        }
        else if (color == "A" || color == "a" )
        {
          colorcelda = " bgcolor = blue ";
        }
        else  if (color == "J" || color == "j" )
        {
          colorcelda = " bgcolor = orange ";
        }
        else if (color == "M" || color == "m" )
        {
          colorcelda = " bgcolor = brown ";
        }
        else if (color == "V" || color == "v" )
        {
          colorcelda = " bgcolor = green ";
        }
        else if (color == "R" || color == "r" )
        {
          colorcelda = " bgcolor = red ";
        }
        else if (color == "G" || color == "g" )
        {
          colorcelda = " bgcolor = gray ";
        }
        else
        {
          colorcelda = "  ";
        }

      text = text + "<td "+colorcelda+">    </td>";
      anchoactual++;
      if (anchoactual>=ancho)
      {
        text = text + "</tr>";
        anchoactual=0;
      }
    }
    i++;  
   }
   text = text+"</table>";
   document.getElementById("tabla").innerHTML = text;  
 }  

function borrar() 
 {  
  var text;
  text = "";
   document.getElementById("tabla").innerHTML = text;  
 }  


</script>  

martes, 9 de mayo de 2023

Introducción a Appinventor 2 (Offline)

Para mí, App Inventor 2 es la manera más fácil y sencilla de crear aplicaciones para Android. Existe una forma de trabajar on-line que es la que normalmente uso y tambien la forma off-line la cual uso en entornos donde no es posible o es muy dificil el accesso a Internet.

lunes, 10 de abril de 2023

PHP: ¡No quiero volver a programar así!

Uno de mis lenguajes favoritos de programación es PHP (si acaso el que más me gusta). Cuando tuve el primer contacto con él, por allá en el 2004 me gustó mucho lo fácil que era crear aplicaciones web; y además con AppServ que instalaba y dejaba todo listo: PHP, MySQL,phpyAdmin y el servidor Apache.

Si se tiene una base de datos llamada colegio y una tabla estudiantes con tres campos: id, nombres y apellidos, crear un script para listar la tabla usando PHP es tan fácil como escribir esto:

<?php 
if (!($link=mysqli_connect("localhost","root","9810402254"))) 
   { 
      echo "Error conectando a la base de datos."; 
      exit(); 
   } 

if (!mysqli_select_db($link,"colegio")) 
   { 
      echo "Error seleccionando la base de datos."; 
      exit(); 
  }

$rs = mysqli_query($link," select * from estudiantes ");

echo "<table>";
echo "<tr>";
echo "<td>ID</td>";
echo "<td>NOMBRES</td>";
echo "<td>APELLIDOS</td>";
echo "</tr>";

while($f = mysqli_fetch_array($rs))
         {  
            echo "<tr>";
            echo "<td>". $f["id"]."</td>";
            echo "<td>". $f["nombres"]."</td>";
            echo "<td>". $f["apellidos"]."</td>";
            echo "</tr>";
         }

echo "<table>";

mysqli_free_result($rs);
mysqli_close($link); 

?>

El gran problema es que esta forma de programar en PHP, que se usó extensivamente en los noventas y parte de la década de los dosmil, conllevaba muy malas prácticas de programación. El asunto llegó a un punto en el que algunos renegaron del lenguaje.

Lo estoy viviendo en la actualidad. hace años creé una aplicación web con PHP que ha ido creciendo hasta el punto de volverse muy dificil de mantener, precisamente por la forma como fue escrita. Es una aplicación en la que ha trabajado una sola persona, pero si se tratase de un trabajo colaborativo sería un caos por no decir casi imposible de mantener. 

La solución: El programador puede usar una arquitectura como la MVC (modelo, vista, programador) o puede usar frameworks, los cuales ya trabajan con una arquitectura especifíca y "obligaban" a los programadores a tener buenas prácticas.

Por ello me digo: ¡Ya quiero programar más así en PHP! De ahora en adelante o implemento yo mismo la arquitectura MVC o aprendo a usar uno de los framework existentes.

domingo, 20 de noviembre de 2022

COBOL: suma de dos números

COBOL no estaba muerto, solo andaba de parranda. En algún momento tuve la oportunidad de aprender un poco sobre COBOL, luego me olvidé de este lenguaje. Llegué a pensar que había quedado en desuso. Si bien no es un lenguaje muy conocido hoy en día, los grandes sistemas informáticos bancarios del planeta lo usan. El siguiente código fue probado en OpenCobolIDE.

IDENTIFICATION DIVISION.
PROGRAM-ID. SUMA.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
01 NUM1 PIC 9(4).
01 NUM2 PIC 9(4).
01 RESULTADO PIC 9(5).
PROCEDURE DIVISION.
MAIN-PROCEDURE.
	DISPLAY "Introduce el primer número: ".
	ACCEPT NUM1.
	DISPLAY "Introduce el segundo número: ".
	ACCEPT NUM2.
	ADD NUM1 TO NUM2 GIVING RESULTADO.
	DISPLAY "El resultado es " RESULTADO.
	STOP RUN.
END PROGRAM SUMA.

jueves, 3 de noviembre de 2022

PHP: suma de dos números

PHP es un lenguaje de programación del lado del servidor. El siguiente ejemplo suma dos números que se han introducido en un formulario HTML. El código HTML se ha escrito junto al código PHP en el mismo archivo, lo cual viene a ser una mala práctica de programación. Sin embargo, en esta ocasión la pasamos por alto puesto que se trata de un ejemplo básico.

<html>
<head>
<title>Suma de números en PHP</title>
</head>
<body>
<form method="POST">
Primer número:   <input type="text" name="numero1"> <br>
Segundo número: <input type="text" name="numero2"> <br>
<input type="submit" value="sumar"> <br>
</form>
</body>
</html>

<?php
	if($_POST)
	{	
		$num1 = $_POST['numero1'];
		$num2 = $_POST['numero2'];
		$suma = $num1 + $num2;
		echo "<p>La suma de ".$num1." y ".$num2." es ".$suma."</p>"; 
	}
?>

miércoles, 2 de noviembre de 2022

C++: suma de dos números

Mientras que el lenguaje C maneja el paradigma de programación estructurada, C++ incorpora programación orientada a objetos. El siguiente código muestra la suma de dos números enteros en C++ usando programación estructurada. Por supuesto, se podría implementar una versión con POO.

#include <iostream>

using namespace std;

int main()
{
   int num1, num2, suma;
   cout << "Primer número: " ;
   cin >> num1;
   cout << "Segundo número: " ;
   cin >> num2;
   suma = num1 + num2;
   cout <<" la suma es : " <<suma;
}