Mostrando entradas con la etiqueta web. Mostrar todas las entradas
Mostrando entradas con la etiqueta web. Mostrar todas las entradas

martes, 25 de junio de 2019

Sombra Circular Para Imagen

Seguramente maquetando más de alguno se habrá vuelto loco a la hora de hacer una sombra circular a un icono, normalmente flotante. Para resolverlo la práctica más sencilla es tomando una sombra de tipo bitmap y posicionarla debajo de la imagen. Ésto podría servirnos si se plantea compatibilidad con navegadores viejos o que no soportan CSS3.


CSS3


En CSS3 disponemos de una serie de nuevas funcionalidades en las que se encuentra box-shadow , que sirve para crear sombras. Las sombras son para las etiquetas, que son cuadradas, pero ésto no es problema si lo combinamos con la propiedad border-radius, en la cual podemos indicar cuanto de redondo queremos que sean las esquinas de la etiqueta. La sombra generada se adaptará a la silueta de la etiqueta.

Algunas veces puede que la imagen escogida no encaje bien, para solucionar eso habría que prescindir de la etiqueta img y trabajar con el background-image, para asignar una imagen, el background-size, para configurar el tamaño de la imagen (no de la etiqueta) y por último hacer un background-position : center.

viernes, 14 de junio de 2019

Framework Minimalista MVC En Php

 Bueno, antes de comenzar hablar sobre el tema de la entrada o publicación quisiera hablar de otra cosa, más que nada para desahogarme un poco, porque es un tema que me ha repateado desde que he comenzado recientemente en el mundo corporativista de las empresas. Yo anteriormente vengo de realizar desarrollos freelance/autónomo, en teoría un portafolio debería ser prueba inequívoca de que sabes moverte en el mundo de la programación y si a eso le sumas que tienes estudios oficiales relacionados con el desarrollo de aplicaciones pues yo creo que no cabe duda que es así. El proyecto que presento es prueba de que ésto no es así, las empresas exigen a los candidatos a un puesto de trabajo pruebas y entrevistas que para mi rayan un poco el absurdo, si a eso le sumas que después de exigir una prueba ya no es que te rechacen por hacerla mal desde el punto personal de la persona que se encarga de seleccionar sino peor aun, no te comunique en que punto del proceso te encuentras, no conteste o se haga el loco. Yo desde las dos pruebas realizadas, bastante complicadas por cierto, nunca volveré a realizar ninguna más. Para entender lo absurdo de la cuestión, usted cuando contrata un electricista o un fontanero ¿le hace alguna prueba? le dice, mire monte un grifo antes de contratarlo y si ya, pues ya veremos si lo contratamos(hay como diez fontaneros haciendo la prueba, montando grifos para demostrar su pericia). Pues eso pasa o me ha pasado.

 Éste proyecto como antes comenté fue para demostrar que estaba al tanto del funcionamiento de un modelo MVC en este caso con Php, no bastaba que supiera Laravel o Symfony, quería demostrar que además de saber trabajar con los frameworks más conocidos también sabía como funcionaban interiormente, que no sólo me dedico a picar código (que de vez en cuando lo hago), sino que también puedo hacer uno. Claro que hacer un framework bien hecho con todas sus tonterías toma mucho trabajo y como siempre ¿por qué reinventar la rueda? pues eso, aquí como lo que se mostró el otro día en la versión front es puramente de propósito educativo. Y bueno, si alguien les pide una prueba para algún trabajo como a mi pues por qué no copiarlo.

Framework MVC y enrutador


 Un marco MVC, modelo, vista y controlador, es un marco actualmente muy extendido en los grandes desarrollos, como contamos en la entrada anterior es un patrón de diseño que mejora la organización y mantenimiento del programa obteniendo mejores resultados en tecnologías que soportan la programación orientada a objetos como es el caso de java

 Normalmente los frames de desarrollo web que soportan MVC disponen de un sistema para enrutar, ésto significa que permiten definir rutas que son direccionadas desde la página principal a sus convenientes vistas. Ésto se realiza mapeando asociativamente las rutas con las vitas o controladores de vistas. Para éste caso, como se muestra abajo, se ha usado vistas con código embebido, pero perfectamente podría haber sido un controlador compuesto por una clase con varios métodos y que retornara una página tal como hacen por ejemplo Spring o Symfony 4.
$request = filter_input(INPUT_SERVER,'REQUEST_URI'); 
$rutas = ["/"         => "indice"  , // MAPA
          "/login"    => "login"   ,
          "/registro" => "registro",
          "/salir"    => "salir"   ,
          "/admin"    => "admin"   ,
          "/home"     => "home"    ];

if (array_key_exists($request, $rutas)!=false){
   require "Vistas/$rutas[$request].php"; // Redireccionamos

Estructura de ficheros


 Para una buena organización es recomendable o mejor dicho deseable sobre todo para este propósito disponer de una estructura intuitiva de directorios. Lejos de lo que algunos puedan imaginar, al final los controladores, vistas y modelos son simplemente ficheros que internamente tendrán quizás que disponer de un código adicional según el caso pero que suelen ser clases o código que deberá estar anclado en el espacio de trabajo(namespace, package, etc...) de la aplicación para poder estar localizado cuando sea requerido.

 En mi caso opté por crear una estructura similar a las empleadas por muchos frames Php conocidos, en la raíz el index.php (el enrutador) y luego tres directorios principales, modelos, vistas y controladores. 


Sobre el proyecto


 Para este ejemplo sólo se usaba un modelo, un usuario, y varios controladores que permiten llevar el registro de la cuenta de un usuario y acceso, con posibilidad de trabajar con roles. El sistema incluye control de sesiones artesanal, en plan cutre, y un sistema de verificación vía correo electrónico que provee la librería PHPMailer.

 El proyecto como siempre disponible en mi Github, cualquier duda hacérmela saber e intentaré en la medida de lo posible aclararla. No olviden que si quieren probarla deben configurar la información de la base de datos y correo electrónico.

 Bueno ésto es todo, ahora posiblemente me desapareceré un par de meses buenos trabajando con otras cosas que si tengo posibilidad ya contaré en siguientes entradas. Mañana puede que publique la chica del mes 😁que ya llevo tiempo sin presentar a ninguna y en este blog también se habla de mujeres y a quien no le guste que se aguante 😤

miércoles, 12 de junio de 2019

FrameWork Sencillo En VanillaScript O Algo Parecido


 Buenas, pues aquí estamos, a piñón con el desarrollo Web, aunque no es de mis pasiones a pesar de haberlo estudiado, más que nada porque no había otra cosa que estudiar, pues es importante para mi de cara al trabajo que desempeñaré. Espero que con experiencia algún día pueda saltar a otras ramas del desarrollo.

 Vale, pues lo que les traigo hoy aquí, es un sencillo framework con propósito meramente educativo, no se trata de reinventar la rueda, pero es importante tener un conocimiento de como funcionan esas cosas tipo Vue JS, React, Angulares y demás, que intentan facilitar el desarrollo en el frontend por medio de un marco de trabajo modular, que permita implementar la aplicación de forma organizada y modificar los módulos de éste sin mucho costo.

Etiquetado personalizado y componentes


 Este tipo de frames, los citados anteriormente, destacan por el uso de los llamados componentes, digamos que la filosofía es llevar la programación orientada objetos a límites insospechables en el front integrando objetos que tengan parte lógica, funcional, propiedades o atributos y una vista o plantilla que les confiera en resumen una independencia del resto de componentes pero que permita integrarse conjuntamente con todo.

 En el ejemplo que mostraré abajo de nuestro componente se trata simplemente de una estructura, que bien podría ser una clase, que muestra las características descritas. 


{ "etiqueta": {
                body: {
                    campo1: 'soy el campo1',
                    campo2: 'soy el campo2'
                },
                template: "<h1> {{ campo1 }} / {{ campo2 }} </h1>" }

 Como se puede apreciar arriba, hemos definido una propiedad template para nuestro componente que define como será visualmente, la plantilla, así como un nombre de etiqueta que representará al componente tanto en nuestro html como cuando nos queramos referir a éste en el programa.

 Dentro de la propiedad body estarán los atributos de la plantilla, que estarán vinculados al render, de esta forma se diseñará para que cuando trabajemos con el componente nos olvidemos de la parte que actualiza el html. Prácticamente ésto nos permitirá ocuparnos solamente de la funcionalidad del componente.

 En muchos de los frames se facilitan instrucciones embebidas en las etiquetas, tipo como for o if, ésto no está contemplado en la publicación porque simplemente no he querido generar mucha complejidad. Para los que estén interesados en saber como se haría les diré que simplemente se trata de definir propiedades a las etiquetas y en los valores se toma el resto de instrucciones y los valores o argumentos. Claro que después hay que incluirlo, pero no es difícil. Ejemplo:

<etiqueta for="let i=0 to 10"></etiqueta>


Estructura principal e integración de los componentes

 Como vamos a tener todo organizado vamos a definir nuestro marco de trabajo, framework, con el nombre de app aunque podría ser cualquier nombre. Nuestro marco de trabajo incluirá una parte donde se indicarán los componentes, llamada igual, que existirán en el programa, instanciados en la página. Digamos que la parte del código es lo que representa o define el componente mientras que su instancia la llevará a cabo el motor del frame al examinar la página del programa.

 Por último la parte del main, es el ámbito donde trabajaremos con las estancias que estarán generadas como se dijo por el frame, invisible para nosotros. En dicha parte es donde definiremos el programa y el comportamiento de los componentes, por ejemplo definir un evento para que haga algo, como un click, o cualquier cosa.

 Ejemplo de la página:

<head>
    <meta>
    <style>
        etiqueta {
            background: red;
            display: block;
        }
    </style>
</head>

<body>
    <h1>Hola mundo</h1>
    <etiqueta></etiqueta>
    <etiqueta></etiqueta>
</body>

 El código en nuestro script:


app = {
    componentes: [{
        "etiqueta": {
            body: {
                campo1: 'soy el campo1',
                campo2: 'soy el campo2'
            },
            template: "<h1> {{ campo1 }} / {{ campo2 }} </h1>"
        }
    }],
    main() {
        this.etiqueta[0].campo1 = "Soy un frame sencillo sin mucha ambición";
        this.etiqueta[1].click = function() {
            alert("Hola holita");
        };
    }
}


Para no complicar la cosa, el motor genera las instancias en un array con el nombre de la etiqueta. Por ejemplo si agregáramos otro componente llamado listado y sólo hubiera una instancia en la página simplemente accederíamos a ella en el programa como listado[0]. En el caso que exponemos en el ejemplo observamos que tenemos un componente etiqueta definido en componentes y en la página tenemos dos instancias de este por eso accedemos con etiqueta[0] para el primero, orden descendente (luego veremos por qué), y al segundo componente accedemos por etiqueta[1].


Motor del framework


 El engine o motor es la parte que no se ve, es la que normalmente se llama por medio del enlace pertinente. Lo ideal sería crearse un código ofuscado del motor y vincularlo, así la página estaría más clara y sólo trabajaríamos con la estructura del frame.

 Para desarrollar este muy sencillo framework sólo vamos a requerir de una función recursiva que nos permitirá navegar por los nodos de forma amistosa. A la función le vamos a pasar el nombre de la etiqueta que queramos localizar y asignarle una acción.

// Herramienta
function buscaTag(nodo, tag, action, retorno) {
    tag = tag.toUpperCase();
    nodo.childNodes.forEach((item) => {
        if (tag == item.nodeName) {
            if (retorno) return action(item);
            action(item);
        }
        buscaTag(item, tag, action);
    });
}



 Luego habrá que inicializar el framework. En esta parte se comprueban los componentes disponibles y se instancian los componentes para que estén accesibles en el programa. En el código he usado la función eval(), para instanciar, pero puede hacerse de otra forma, eso es a gusto del consumidor.


// inicializadomos!!
buscaTag(document.getRootNode(), "html", function(item) {
    app.html = item;
}, true);
// Examinamos los componentes disponibles y creamos las instancias de estos
app.componentes.forEach(componente => {
    var i = 0;
    var nombreComponente = Object.keys(componente)[0];
    app[nombreComponente] = [];

    // Instanciamos componentes
    buscaTag(document.getRootNode(), nombreComponente, function(item) {
        item.id = nombreComponente + i;
        eval("app." + nombreComponente + "[" + i + "]=" + JSON.stringify(componente[nombreComponente].body));
        i++;
    }, false);
});
// Ejecutamos el programa
app.main();

 Y por último tenemos la parte que actualiza periódicamente. Como podrán observar las propiedades renderizables de las plantillas se buscan por medio de una sencilla expresión regular y luego se sustituye con el valor acorde que tenga el componente en ese momento. Aunque parezca todo muy estático podemos comprobar por ejemplo mediante la consola del navegador como es posible acceder a la aplicación por medio del objeto app y modificar la función click() de cualquiera de los dos componentes existentes en el ejemplo o cambiar el contenido de los campos que en un segundo estará todo actualizado.


// Actualizamos!! (cada segundo)
window.setInterval(() => {
    /////////////////////////////////////////////////////
    app.componentes.forEach(componente => {
        var nombreComponente = Object.keys(componente)[0],
            appComponente = componente[nombreComponente],
            i = 0;

        buscaTag(app.html, nombreComponente, function(item) {
            componente = app[nombreComponente][i];
            componente["render"] = appComponente.template;

            // sustituimos los atributos por sus valores
            Object.keys(appComponente.body).forEach(atributo => {
                componente.render = componente.render.replace(
                    new RegExp("({{)+[\\s](" + atributo + ")+[\\s]+(}})", "g"), componente[atributo]);
            });

            // introducimos el render
            let etiqueta = document.getElementById(nombreComponente + i);
            if (etiqueta.innerHTML !== componente.render) {
                etiqueta.innerHTML = componente.render;
            }

            // Añadimos propiedades especiales como eventos ...
            var elementoDom = document.getElementById(item.id);
            elementoDom.parentNode.replaceChild(item.cloneNode(true), item); // Eliminamos eventos
            if (app[nombreComponente][i].click !== undefined) {
                document.getElementById(item.id).addEventListener("click", app[nombreComponente][i].click);
            }

            i++;
        }, false);
    });
}, 1000);

 Como ven todo ésto de los frameworks no es magia y sólo se trata de una especie de patrón de diseño para organizar mejor el desarrollo y mantenimiento de la aplicación. Quizás en otra ocasión con tiempo pueda mostraros lo mismo pero en la parte del backend, en Php of course.

  Si quieren cacharrear subo el fichero a mi espacio Github para que piquen y hagan experimentos, que lo disfruten y me dicen si quieren que la próxima entrada sea el framework de Php o comenten alguna sugerencia. Bye.

martes, 16 de enero de 2018

Cambiar colores de los mensajes en consola, Laravel 5.1

 Bueno, al final averigüe como cambiarlo sin hacer tanto trasteo con js, que aparte de conseguirlo hice petar todo el Cloud9 en el intento y menos mal que usando ?reset=user pude dejarlo todo por default.
Lo primero, es que no es una solución que haya encontrado por ahí ni nada de eso, todo es investigación propia.
Lo segundo, que tanto para cambiar el esquema de colores del artisan como del tinker hay que toquetear en distintos sitios. Porque el artisan en verdad lo que hace cuando invocas al tinker es ejecutar una aplicación php denominada PsySh. Ambas, PsySh y Artisan usan algunos componentes de Symphony, por ejemplo el Console (Seguro que con el nombre os da una pista).

Cambiar esquemas de color del artisan

 Simplemente hay que irse al fichero en la raíz de nuestro proyecto Web, por ejemplo Laravel. Y editar el fichero artisan (un fichero de texto plano sin extensión), y colocar en la cabecera :

use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Output\ConsoleOutput;
...
 Luego en el mismo fichero localizamos la línea :
$status=$kernel->handle(
    $input=new Symfony\Component\Console\Input\ArgvInput,
    new Symfony\Component\Console\Output\ConsoleOutput
);
 Y antes de esta línea definimos nuestra propia salida personalizada que denominaremos como no $output , de esta forma :
$outputFormatter=new OutputFormatter(false,[
    // En este array vamos agregando los estilos para cada caso (solo me se algunos)
    'error'=>new OutputFormatterStyle('yellow','blue'),// fondo azul y letras amarillas, por ejemplo
]);

$output=new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL,null,$outputFormatter);
 Una vez tenemos nuestra salida personalizada lista simplemente reemplazamos el new Symfony\Component\Console\Output\ConsoleOutput de la función handle que mostré anteriormente por nuestro objeto ConsoleOutput denominado $output. Y listo.

Cambiar esquemas de color del tinker (PsySh)

Para éste es un poco más sencillo, simplemente nos vamos a la carpeta vendor, donde el composer aloja todas las librerías php, y buscamos la carpeta psy. Y dentro de ella buscamos el fichero /psysh/src/psy/output/ShellOutPut.php y lo editamos. Dentro del fichero nos vamos abajo del todo en la función initFormatters() y veremos como define los estilos. Simplemente lo que haremos es reasignar los colores con la combinación que nos guste y en caso por ejemplo de cambiar el estilo de los mensajes de error, al no existir dentro de las definiciones la crearemos de la misma forma que el resto de estilos definidos pero con el nombre de error:
...
...
     * Initialize output formatter styles.
     */
    private function initFormatters()
    {
        $formatter=$this->getFormatter();

        // usamos la palabra 'error'
        $formatter->setStyle('error',new OutputFormatterStyle('black','yellow'));// ejemplo (un copy/paste del de abajo)
        
        $formatter->setStyle('warning',new OutputFormatterStyle('black','yellow'));
...
...
 Y listo calisto.

Laravel 5.1 usando policies

 Buenas, en esta publicación indicaré como implementar sencillamente las policies en Laravel 5.1


¿Qué son las policies en Laravel?


 Las policies como indica su nombre son las políticas relacionadas con los permisos y/o autorizaciones. Van encaminadas a ofrecer una alternativa al midleware de Laravel, pues se puede hacer casi lo mismo con estas, pero con la diferencia de la actuación, pues mientras que con el midleware uno puede tratar la excepción dentro de la clase casi de forma opaca para el que la usa, en el Policy se maneja en el lugar, o función, donde queremos que actúe. Realmente al final se resume en devolver verdadero o falso según las condiciones de la operación.

 Bueno, conformes o no con mi definición de las policies siempre podrán consultarla directamente desde la documentación oficial de Laravel e interpretarla al gusto o literal.

https://laravel.com/docs/5.1/authorization#policies

Implementación y explicación



 Como habrán visto en la documentación el procedimiento es simple. Se crea una clase por medio de artisan, luego se añade (registro) a la clase AuthServiceProvider y luego la usamos en el lugar o función que queremos que actúe.



 Uno de los principales problemas que se nos puede presentar es la ausencia de esta clase, AuthServiceProvider, al recién instalar Laravel 5.1. Para ello podemos solucionar esto de forma sencilla. Nos vamos a la carpeta donde Composer aloja las librerías Php, la vendor de nuestro directorio de trabajo. Luego desde la ruta laravel/framework/src/Illuminate/Auth/ copiamos la clase citada a la ruta app/providers, cambiamos su espacio de trabajo por el de App\Providers y por último registramos esta clase en la configuración del laravel, config\app.php , en la clave 'providers' añadimos al array App\Providers\AuthServiceProvider::class . Podemos luego limpiar la clase y solamente dejarla así de momento para este propósito :



namespace App\Providers;
        
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register any application authentication / authorization services.
     *
     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
     * @return void
     */
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);
    }
}

 Una vez hecho esto ya simplemente es ejecutar el comando artisan, php artisan make:policy y el nombre de la política que queremos aplicar. 


 Como esto era para clase he usado un proyecto que ya tenía hecho que trata de un portal de anuncios. En el proyecto originalmente el problema de impedir que editaran anuncios de los que los usuarios no fueran propietarios lo resolvía con un midleware. Pero como el profe nos pidió implementarlo para experimentar con este pues aplicaré el Policy para resolver el problema antes indicado.



 Creo entonces el Policy denominado PoliticaDePublicacion, el cual una vez ejecutado el comando artisan me aloja la clase en la ruta app\policies.



 Dentro de esta clase ya creada, como la idea es que en el momento después de la edición y al actualizar el anuncio se evalúe si el usuario puede o no modificar, pues creo un método denominado actualizar y le indico los dos parámetros que participan en esta evaluación o comprobación que no son otros que el usuario registrado y el anuncio a editar. Y al final queda una cosa así :



namespace App\Policies;

use Illuminate\Auth\Access\HandlesAuthorization;

use App\User;
use App\Anuncio;

class PoliticaDePublicacion
{
    
    public function actualiza(User $usuario,Anuncio $anuncio){
        return $usuario->id == $anuncio->id_usuario;
    }
}


 En el método o función se observa que simplemente se compara el id del usuario con el id del anunciante. Que en caso de corresponder devolverá verdadero y en caso contrario falso.



 Hecho esto ahora agregamos nuestra Policy al AuthServiceProvider. Para ello usaremos la propiedad protegida policies que toma una array asociativo. Donde en la parte de la clave usamos la ruta y el nombre de "una" clase entre comillas (o comilla simple), vinculante a nuestra Policy que será el valor que también se asignará por medio de la ruta completa con el nombre de la clase. Yo como clave escogí el controlador pero puedes usar también un modelo como se aprecia en la documentación pues eso depende de su uso.




namespace App\Providers;

use App\Anuncio;
use App\Policies\PoliticaDePublicacion;
        
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        'App\Http\Controllers\AnuncioController' => 'App\Policies\PoliticaDePublicacion',
    ];

    /**
     * Register any application authentication / authorization services.
     *
     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
     * @return void
     */
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);
    }
}

 Ya hecho esto simplemente queda usarla dentro de la función donde vaya actualizar por medio del helper o función policy(), a la cual indicamos nuestra clase, en este caso el controlador, y ésta nos devolverá nuestra Policy vinculada pudiendo así usar los métodos definidos, en este caso actualiza().



namespace App\Http\Controllers;

...
use App\Http\Requests\ValidaAnuncio;

class AnuncioController extends Controller
{
...
    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(ValidaAnuncio $request, $id)
    {
        $anuncio = Anuncio::find($id);
        if (policy('App\Http\Controllers\AnuncioController')->actualiza($request->user(),$anuncio)){ 
            $anuncio->update(["titulo"=>$request->titulo, "cuerpo"=>$request->mensaje, "categoria"=>$request->categoria]);
            return "";
        }
        
        return redirect('/'); // en caso de no poderse modficar saltamos al inicio de la pa�gina   
    }
...
 
 También como alternativa podremos usar el $this en el argumento de la función policy() para indicar la clase en vez de escribir el nombre completo de esta(tal como muestro arriba en el código), pues estamos además dentro del controlador para cual se definió la política.


 Y ya por último, también indicar que podríamos usar otra forma que indica la documentación y que engaña mucho con el ejemplo que nos muestra, aunque en una notita lo deja bien claro. Se trata del método authorize(). Dicho método funciona de la siguiente forma; cuando devuelve true el flujo del programa continúa con normalidad y en caso contrario genera una excepción que responde con un código 403 (No autorizado), que en Laravel podremos definir con una vista personalizada. Para usar el authorize() hay que incluir la clase AuthorizesRequests dentro de nuestro controlador o clase pues sino el servidor nos lanza el mensaje de método no encontrado.


By default, the base App\Http\Controllers\Controller class included with Laravel uses the AuthorizesRequests trait. This trait provides the authorize method, which may be used to quickly authorize a given action and throw a HttpException if the action is not authorized.

 Además también habrá que definir los métodos a usar en el método boot() de la clase AuthServiceProvider. Usando a su vez el método define() del objeto GateContract de la citada función. Todo para que el authorize() pueda encontrar los métodos pues de lo contrario siempre generará la excepción 403.


Conclusión


En mi humilde opinión esto puede ser prescindible en el desarrollo de una aplicación con un framework en el que abundan todo tipo de funcionalidades.