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.