Ya vimos [en un post pasado lo que es Laminas y como instalarlo][1], ahora, en esta primera parte vamos a crear un CRUD. Esta es una serie de post donde vamos a crear un CRUD con Laminas MVC. CRUD es una cronimo para las acciones de Crear, Leer, Actualizar y Borrar, en inglés.
Estructura de directorios del Skeleton Application.
Una vez que hayamos creado nuestro proyecto, vamos a abrirlo con nuestro editor de código favorito, en este caso PHPStorm. Vamos a ver la estructura de carpetas que tiene la carpeta de Skeleton de nuestra aplicación llamada Application.
Los archivos de configuración del framework se encuentran en el directorio config/. Los archivos que se encuentran son archivos PHP regulares.
Laminas por default viene con un primer módulo llamado Application. Este módulo de ejemplo está diseñado principalmente para mostrar información estática del sitio con links a la documentación o a páginas de ayuda.
Los directorios bajo el módulo Application son:
Directorio config/, se encuentra el archivo module.config.php allí se guarda información de las rutas de tu aplicación, los controllers que usa la aplicación y la configuración de las vistas de la aplicación.
Directorio src/, dentro vamos a colocar todo el código fuente que vayamos a crear. Dentro de esta carpeta se encuentra otra llamada Controllers donde se van a colocar los controladores de la aplicación. También se encuentra el archivo Module.php donde vamos a colocar la configuración de nuestra aplicación.
Directorio test/, aquí vamos a colocar los archivos de testing para nuestra aplicación.
Directorio views/, dentro vamos a encontrar otros tres directorios: application la cual contiene las vistas de nuestra aplicación definida por cada action que tenga nuestros controllers, error contiene las vistas de error para la aplicación y el directorio layout, contiene el diseño general que se va a usar en nuestra aplicación.
Aplicación de lista de tareas (To do list)
Crear estructura de directorios para aplicación de To do list.
En el directorio modules, crear la siguiente estructura que almacenará nuestra nueva aplicación.
/module
/TodosApp
/config
/src
/Controller
/Form
/Model
/view
/error
/layout
/todos-app
/to-do
El nuevo módulo que hemos creado se llama TodosApp que hace referencia a una aplicación de lista de tareas. El módulo TodosApp tiene directorios separados para los diferentes tipos de archivos que tendremos. Los archivos PHP contienen clases dentro del namespace TodosApp viven en el directorio src/. El directorio de vistas contiene una subcarpeta para las vistas de nuestro módulo.
Para cargar y configurar nuestro nuevo módulo, Laminas proporciona un ModuleManager, el cual carga todos los módulos registrados en la configuración de la aplicación. Cada módulo debe tener su propio archivo Module.php. Vamos a crear el archivo Module.php dentro del directorio src/ con el siguiente contenido.
<?php
namespace TodosApp;
class Module
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
}
Si bien Laminas proporciona carga automática de componentes, se recomienda usar composer. Debemos informar a composer en donde se encuentran los archivos. Abre el archivo composer.json que se encuentra en la raíz del proyecto y localiza la sección autoload, se debe ver así:
"autoload": {
"psr-4": {
"Application\\": "module/Application/src/"
}
},
Vamos a agregar nuestro nuevo módulo a la lista y se debe ver así:
"autoload": {
"psr-4": {
"Application\\": "module/Application/src/",
"TodosApp\\": "module/TodosApp/src"
}
},
A continuación vamos a ejecutar lo siguiente en la terminal para actualizar las reglas de carga de composer:
$ composer dump-autoload
Configuración
Una vez que registramos nuestro nuevo módulo, vamos a crear el archivo module.config.php, a este archivo hace referencia al archivo anterior que creamos Module.php. Creamos un archivo llamado module.config.php bajo module/TodosApp/config, con el siguiente contenido:
<?php
namespace TodosApp;
use TodosApp\Controller\ToDoController;
use Laminas\ServiceManager\Factory\InvokableFactory;
return [
'controllers' => [
'factories' => [
ToDoController::class => InvokableFactory::class
]
],
'view_manager' => [
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'template_path_stack' => [
__DIR__ . '/../view',
]
]
];
Como configuración inicial tenemos dos secciones principales controllers y view_manager. La sección de controladores proporciona una lista de todos los controladores en el módulo. Podemos observar que tenemos un controller llamado ToDoController, este es referenciado por su nombre de clase y usa laminas-servicemanager InvokableFactory para crear instancias de él.
En la sección view_manager, agregamos nuestro directorio de vistas a la configuración de template_path_stack. Esto permitirá encontrar las vistas para nuestro módulo TodosApp, estas son almacenadas en el directorio views/. Aquí también se especifica la vista general de la aplicación, llamada layout, en la llave template_map, se tomará la vista del módulo Application sino se especifica.
Informar a la aplicación sobre el nuevo módulo
Ahora necesitamos informarle a la aplicación sobre nuestro nuevo módulo. En la raíz de nuestro proyecto dentro de config/, vamos abrir el archivo modules.config.php y agregar en el array el nombre de nuestro módulo: TodosApp, quedando algo así:
return [
'Laminas\Form',
'Laminas\Db',
'Laminas\Router',
'Laminas\Validator',
'Application',
'TodosApp' // ← Agregar esto
];
Controlador, rutas y vistas
Creando nuestro primer controlador
En la carpeta controllers dentro de src: src/Controller, vamos a crear un nuevo archivo llamado ToDoController.php, que va a contener nuestra primera acción:
<?php
namespace TodosApp\Controller;
use Laminas\View\Model\ViewModel;
class ToDoController extends \Laminas\Mvc\Controller\AbstractActionController
{
public function indexAction(): ViewModel
{
$message = 'Hola desde indexAction';
return new ViewModel(['message' => $message]);
}
}
La convención para nombrar a tus controladores es: {Controller name}Controller.php, nota que {Controller name} debe iniciar con la primera letra mayúscula. Cada action es un método público en el controlador y es nombrado así {action name}Action, dónde {action name} debe iniciar con una letra minúscula. En el código anterior estamos almacenando a la variable $message la cadena "Hola desde indexAction".
Con Laminas para setear variables en la vista devolvemos una instancia de ViewModel, donde el primer parámetro del constructor es un array con los datos que deseamos regresar, en este caso regresamos la variable $mensaje.
Creando nuestra primera vista
El objeto ViewModel permite especificar el nombre de la vista que deseamos usar pero por default este busca la vista de la siguiente manera {nombre del módulo}/{nombre del controlador}/{nombre de la acción}. De esta manera nuestra vista quedará así: view/todos-app/to-do/index.phtml. Así que vamos a crear esa vista en el directorio /views/todos-app/to-do y la vamos a nombrar index.html. Y vamos a agregar el siguiente contenido:
<h1>Hola desde el modulo To Do App!</h1>
<p>You said "<?php echo $this->escapeHtml($message) ?>".</p>
Como podemos ver tenemos un texto estético como título H1, a continuación el siguiente párrafo P, You said “aqui va el contenido de la variable message”, escapeHtml, es un helper para protegernos de vulnerabilidades Cross Site Scripting (XSS).
Definiendo las rutas de nuestra aplicación
Estamos construyendo una lista de tareas sencillas. El home lo dejaremos que apunte a la aplicación que trae por default Laminas. Nuestra aplicación de lista de tareas tendrá las siguientes páginas:
Cada página de la aplicación es conocida como un action, cada action son agrupadas dentro de controladores. Generalmente se agrupan actions similares dentro de un controlador.
Para nuestra aplicación tendremos las siguientes acciones dentro de un controlador que hemos nombrado ToDoController.
Para mapear una URL a una action en particular lo hacemos mediante las rutas, estas son definidas dentro del archivo module.config.php. Abrimos y actualizamos el archivo module.config.php quedando de la siguiente manera:
<?php
namespace TodosApp;
use Laminas\Router\Http\Segment;
use TodosApp\Controller\ToDoController;
return [
//La siguiente sección es nueva y debe ser agregada a tu archivo
'router' => [
'routes' => [
'todo-app' => [
'type' => Segment::class,
'options' => [
'route' => '/todo-app[/:action[/:id]]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[1-9]\d*',
],
'defaults' => [
'controller' => ToDoController::class,
'action' => 'index'
],
]
]
]
],
'controllers' => [
'factories' => [
ToDoController::class => InvokableFactory::class
]
],
'view_manager' => [
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'template_map' => [
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
],
'template_path_stack' => [
__DIR__ . '/../view',
]
]
];
El nombre de la ruta es todo-app y es de tipo Segment, este tipo de ruta nos permite especificar placeholders. Los placeholders son marcadores de posición que llevan un nombre, en este caso :action y :id, para hacer coincidir dinámicamente los segmentos de la URI de la solicitud HTTP. Las rutas /todo-app[/:action[/:id]] puede coincidir con cualquier URL que empiece con /todo-app. El siguiente segmento es el nombre de la acción y puede ser opcional y finalmente el último segmento puede ser mapeado a un id opcional. Los corchetes "[]" indican que los segmentos son opcionales. La sección de constraints nos asegura que los caracteres dentro de un segmento sean los esperados, por lo que tenemos acciones limitadas que comienzan con una letra y los siguientes caracteres son alfanuméricos, guiones bajos o guiones. También limitamos el placeholder :id para aceptar solo dígitos. La última sección llamada defaults indica el controlador y acción por default. Esta ruta nos permite tener las siguientes URLs:
En este punto solo hemos creado la primera action en nuestro controller que es index. Vamos abrir nuestro navegador y tecleamos http://localhost:8080/todo-app deberías ver algo así:
Wow salio muy largo este primer post sobre el CRUD en Laminas así que hasta aquí dejo la primera parte, en la segunda parte vamos cambiar el layout de nuestra aplicación para que luzca diferente, a demás vamos a configurar la base de datos y a listar las task desde base de datos.
Actualización.
Aquí dejo los links del tutorial: Creando un CRUD con Laminas.
-
Creando Un Crud Con Laminas 1a Parte.
-
Creando Un Crud Con Laminas Ultima Parte: Refactorizar Vistas
Y el repositorio del proyecto: Tutorial con laminas