Agregar comando Artisan de Laravel para backups de la base de datos

El objetivo del siguiente contenido es explicar como extender la funcionalidad de artisan agregando un nuevo comando que permita generar periódicamente un respaldo de la base de datos, para esto ultimo haremos uso de las tareas programadas con crontab.

linux+laravel+crontab

linux+laravel+crontab

Consideraciones

Vamos a considerar un par de cosas:

  1. Nuestro sistema se encuentra en un servidor Linux
  2. La base de datos es MySQL
  3. Usaremos Laravel 5 o superior

Artisan

Artisan es la herramienta de lineas de comandos de Laravel la cual nos permite hacer distintas tareas por ejemplo mapear la base de datos, crear modelos, vistas, migrates, limpiar cache, etc..

Para saber mas podemos listar las opciones disponibles, esto lo podemos hacer con la siguiente instrucción:

php artisan list

Agregando Nuevo comando

Lo siguiente seria agregar el nuevo comando db:dump para esto vamos a escribir la siguiente instrucción:

php artisan make:command DbDump

Esto nos va a generar la plantilla de un comando, en el archivo app/Console/Commands/DbDump.php al cual solo le faltaría agregar nuestro código, vamos a empezar re-definir las propiedades:

protected $signature = 'db:dump';

Esta propiedad($signature) define la forma como se debe invocar el comando para ser ejecutado, en este caso estamos diciendo que se mande a llamar como php artisan db:dump.

La siguiente propiedad a modificar es la descripción($description), la cual la definiremos como:

protected $description = 'Respalda la base de datos, comprimiendo los datos en un archivo .gz';

Finalmente vamos a poner un mensaje en la función handle la cual se ejecuta cuando se llama el comando para la cual quedaría como:

public function handle() {
   $this->line('<fg=red;bg=yellow>Soy el nuevo comando db:dump</>');
}

Declarar el comando

Lo siguiente seria declarar el comando nuevo para que este disponible y la próxima vez listemos los comandos de Artisan aparezca, para esto abrimos el archivo app/Console/Kernel.php y modificamos el valor del atributo $commands quedando de la siguiente manera:

protected $commands = [
   \App\Console\Commands\DbDump::class
 ];

Ahora podemos probar que el comando este disponible ejecutando: php artisan list y donde nos debería de aparecer el nuevo comando, el cual para ejecutarlo tendríamos que escribir:

php artisan db:dump

Codificando la función handle

Finalmente vamos a codificar la función handle, la cual dejó aquí:

public function handle() {
	$ds = DIRECTORY_SEPARATOR;
	$host = env('DB_HOST');
	$username = env('DB_USERNAME');
	$password = env('DB_PASSWORD');
	$database = env('DB_DATABASE');
	$path = database_path('backups' . $ds);
	$file = 'bd' . date('_Y-m-d') . '.sql';
	if (!is_dir($path)) {
			mkdir($path, 0755, true);
	}
	$this->line('<fg=cyan>Backup: </><fg=yellow;bg=black>'. $path . $file . '</>');
	# Generamos el comando con mysqldump para exportar los datos
	$command = sprintf(
		'mysqldump --skip-comments --skip-compact --no-create-info'
		. ' --skip-triggers --complete-insert --skip-add-locks'
		. ' --disable-keys --lock-tables --host="%s" --user="%s" '
		, $host, $username
		);
	if (!empty($password)) {
		$command .= sprintf('--password="%s" ', $password);
	}
	$command .= sprintf('%s > "%s"', $database, $path . $file);
	$this->line('<fg=green>CMD: </><fg=yellow;bg=black>'. $command . '</>');
	exec($command, $output, $return);
	if ($return) {
		$this->line('<fg=red;bg=yellow>Error al intentar generar el Backup</>');
		if (file_exists($path . $ds . $file)) {
			unlink($path . $ds . $file);
		}
		return; // error
	}
	// Comprimiendo el archivo:
	// mayor info: https://www.php.net/manual/es/function.gzopen.php
	// Open the gz file (w9 is the highest compression)
	$fileCompress = gzopen ($path . $ds . $file . '.gz', 'w9');
	// Compress the file
	gzwrite ($fileCompress, file_get_contents($path . $ds . $file));
	// Close the gz file and we are done
	gzclose($fileCompress);
	// Generando el esquema
	$path = database_path('backups' . $ds . 'schemas'. $ds);
	$file = 'schema.sql';
	if (!is_dir($path)) {
		mkdir($path, 0755, true);
	}
	# Generamos el comando con mysqldump para exportar la estructura
	$command = sprintf(
		'mysqldump --skip-comments --skip-compact '
		. ' --no-data --host="%s" --user="%s" '
		, $host, $username
		);
	if (!empty($password)) {
		$command .= sprintf('--password="%s" ', $password);
	}
	$command .= sprintf(
		'%s | sed "s/ AUTO_INCREMENT=[0-9]*//g"  > "%s"',
		$database, $path . $file
	);
	$this->line('<fg=magenta>Generando Schema</>');
	exec($command, $output, $return);
	if ($return) {
		$this->line('<fg=red;bg=yellow>Error al intentar generar el Schema</>');
		if (file_exists($path . $ds . $file)) {
			unlink($path . $ds . $file);
		}
		return; // error
	}
}

Declarar la tarea en el crontab

Crontab es un servicio que nos permite agregar tareas que serán ejecutadas periódicamente, lo siguiente que nos faltaría seria declarar una tarea, para acceder al modo edición de reglas tenemos que ejecutar crontab -e la sintaxis de como declarar una regla se describe a continuación:

.--------------- minuto (0-59) 
|  .------------ hora (0-23)
|  |  .--------- día del mes (1-31)
|  |  |  .------ mes (1-12) o jan,feb,mar,apr,may,jun,jul... (meses en inglés)
|  |  |  |  .--- día de la semana (0-6) (domingo=0 ó 7) o
|  |  |  |  |     sun,mon,tue,wed,thu,fri,sat (días en inglés) 
|  |  |  |  |
*  *  *  *  *  comando a ejecutar

En este caso lo pondré a que se ejecute todos los días a las 2am, esto seria con la siguiente declaración de regla:

#.-------------- minuto cero (0-60)
#| .------------ hora dos (0-23)
#| |  .--------- todos los días (1-31)
#| |  |  .------ todos los meses (1-12)
#| |  |  |  .--- Cualquier dia de la semana (0-6)
#| |  |  |  |
#| |  |  |  |
0  2  *  *  *  php ruta_completa_larvel/artisan db:dump

Ejemplo completo

Dejo aquí el código completo del archivo, el cual lo puse en mi github:

https://gist.github.com/fitorec/d7f8003ff1b5501177068f00087cb51a

Enlaces recomendados

Por último les dejó un par de enlaces en donde puedan abundar un poquito mas al respecto:

Cargando distintos archivos .Env para cada subdominio con Laravel

En este post quisiera explicar acerca de una implementación que permita cargar distintas configuraciones para cada subdominio, el objetivo es tener una aplicación desarrollada con Laravel(5.8) que a partir de cada subdominio cargue una configuración distinta, de esta forma por ejemplo para cliente1.miapp.com se conectara a su propia base de datos diferente a clientex.miapp.com, la siguiente imagen trata de ilustrar este comportamiento.

Cargando configuración por subdominio con Laravel

Cargando configuración por subdominio con Laravel

Ciclo de Vida de Laravel

Quisiera detenerme un momento para explicar a grandes rasgos como funciona el ciclo de vida de Laravel, cuando accedemos a una aplicación de Laravel lo primero que cargamos es el archivo /public/index.php este a su vez manda a cargar dos archivos /vendor/autoload.php y /bootstrap/app.php el primero es generado por composer y se encarga de cargar todas las dependencias de terceros, este archivo no lo debería modificar por que en cada actualización se perdería, el segundo este es el indicado.

Si deseas profundizar en el tema te recomiendo la siguiente lectura: https://laravel.com/docs/5.8/lifecycle#lifecycle-overview, si te gusta explorar el código fuente de Laravel puedes ver el archivo en el archivo /public/index.php en github, en al siguiente imagen trataré de ejemplificar lo que ocurre cuando se ingresa en una aplicación de Laravel realizando un request desde nuestro navegador.

Ciclo de vida de Laravel

Ciclo de vida de Laravel

Codificando la solución

Como se comento los cambios los realizaremos en el archivo /bootstrap/app.php este archivo genera una instancia de Illuminate\Foundation\Application como podemos ver en la linea 14 del código original, ahora lo que vamos hacer es que a partir de la linea 17 vamos agregar el código encargado de detectar el subdominio (o ver si estamos en modo CLI):

$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
/*
|--------------------------------------------------------------------------
| Cargando configuración a partir de el subdominio (SUBDOMAIN)
|--------------------------------------------------------------------------
*/
if (!defined('SUBDOMAIN')) {
	$subdomain_tmp = 'localhost';
	if (isset($_SERVER['SERVER_NAME'])) {
		$domainParts = explode('.', $_SERVER['SERVER_NAME']);
		$subdomain_tmp =  array_shift($domainParts);
	} else {
		if (php_sapi_name() === 'cli') {
			//Modo CLI útil a futuro
		}
	}
	define('SUBDOMAIN', $subdomain_tmp);
}
$app->loadEnvironmentFrom('subdomains_config' . DIRECTORY_SEPARATOR . '.' . SUBDOMAIN);

 

Ahora solo faltaría agregar en la carpeta subdomains_config archivos de configuración con el nombre de cada subominio precedido con un punto(.) por ejemplo para el clientex.app.com. el subdominio es clientex. y el archivo de configuración seria subdomains_config/.clientex.

Cambiando el sistema de cache

Como queremos que cada subdominio tengan su propio cache vamos a cambiar la ruta en donde guardan el cache de tal forma que genere una carpeta de cache para cada subdominio, para esto modificamos el archivo /config/cache.php la linea 52 la cambiamos por:

'path' => storage_path('framework/cache/data_' . SUBDOMAIN),

¿Que sigue?

Con esto ya quedaría una aplicación que cargue determinada configuración a partir de un subdominio, faltaría agregar comandos de artisan que permitan realizar tareas administrativas en todos los subdominios como por ejemplo respaldar las bases de datos, tareas que se puedan programar en nuestro servidor utilizando crontab, en el siguiente posts espero escribir al respecto.

¿Dudas? o comentarios

Espero el contenido haya quedado bien explicado si existieran dudas, comentario o aportaciones son bienvenidos :¬D sin mas me despido y felices códigos.

PS

Recomiendo leer los siguientes posts:

 

Introducción a JavaFX

logoFX

Las tecnologías web llegaron para revolucionar a la Ingeniería de Software, ya hace un tiempo las webapps al ser cada vez mas complejas tendieron a dividir la complejidad en 3 partes:

  1. lógica de la aplicación(JavaScript y lenguajes del lado del servidor p.e. php,python, ruby, perl, asp, etc…)
  2. El contenido de la aplicación (El marcado HTML)
  3. El diseño (CSS).

JavaFX es una implementación de esto, diviendo los elementos en:

  1. lógica de la aplicación(Java)
  2. El contenido de la aplicación (El marcado FXML)
  3. El diseño (CSS).

En otras palabras javaFX es un conjunto de librerías que utiliza Java para el manejo de la lógica de la aplicación, FXML para el marcado de contenido(botones, etiquetas, textos de entrada, etc..) y CSS para darle estilo o diseño a estos elementos de contenidos, la siguiente imagen ilustra como se comporta las tecnologías JavaFX en un patrón MVC.

Vista:

La parte de la vista son escenas las cuales el contenido están descritas por archivos con extensión .FXML estos son modificados desde la aplicación JavaFX Scene Builder por otra parte el diseño de la ventana(escena) se realiza mediante archivos de descripción de estilo .CSS

Controlador:

La vista previamente tiene la capacidad de definir un controlador el cual hace referencia a una clase en Java que se va a encargar de controlar la lógica de la ventana.

Modelo:

El modelo es el responsable de la recuperación de datos convirtiéndolos en conceptos significativos para la aplicación, así como su procesamiento, validación, asociación y cualquier otra tarea relativa a la manipulación de dichos datos.

En los siguiente contenido de esta categoría javaFX se va a vamos a explicar mas el funcionamiento de las vistas.

Le recomiendo descargar y revisar el código de la calculadora con JavaFX para que se vaya contextualizando con esta forma de crear aplicaciones.

Calculadora con JavaFX

Vamos a crear la siguiente calculadora:

calculadora_estructura

Ejemplo del funcionamiento

calculadora

Estructura:

Vamos a crear una calculadora, la cual tiene la siguiente estructura:

  • Calculadora.java
  • Controller.java
  • Evaluar.java
  • Vista.fxml
  • Style.css

Vista

La vista de la aplicación es el archivo Vista.fxml el cual describe una ventana divida en dos partes la parte superior contiene el texto de entrada y la parte inferior es una rejilla(GridPane) de 4×4 que contiene los botones (4 renglones de 4 columnas), como se puede ver a continuación.

calculadora_estructura_detalle

Controlador:

El archivo Controller se encarga de “controlar la lógica de la vista”, el cual contiene los métodos:

  • Evaluar: es ejecutada cuando se presiona el Enter en la “#entrada” o el botón con símbolo “=”
  • Borrar: Es ejecutada cuando se presiona el botón con símbolo “c”(clear)
  • OtroBoton: Es ejecutada cuando se presiona cualquier otro botón(0-9*/+-) y simplemente concatena el símbolo contenido en el botón a #entrada..

Evaluar.java se encarga de realizar las operaciones detectando errores de aritmética como la división entre cero.

Código:

Dejo el enlace del código fuente:

https://github.com/fitorec/calculadora_javaFX

Paginación de Twitter Bootstrap en WordPress

El twitter Bootstrap entre sus componente que tiene trae incorporado un sistema de paginación con links activos, normales y deshabilitados.

Paginación de twitterBootstrap en WordPress

Resultado Paginación de twitterBootstrap en WordPress

http://twitter.github.com/bootstrap/components.html#pagination

Por otra parte el sistema WordPress suele agregar la paginación de los posts en el archivo loop.php de la plantilla en cuestión, desgraciadamente la función paginate_links nos genera un código html algo diferente a lo que requerimos para adaptarlo al bootstrap.

Salida en HTML necesaria

Salida en HTML necesaria

http://codex.wordpress.org/Function_Reference/paginate_links

Navegando por Internet encontré algunas implementaciones, p.e:

http://panosgalatis.com/2012/08/14/wordrpess-and-twitter-bootstrap-pagination/#.UHvXCqyqyio

Sin embargo incluyen modificaciones al CSS, cuando este renderizado se puede hacer solo con PHP como se muestra continuación:

loop.php

loop.php

Hice un gists en github con el código fuente para que se pueda descargar:

Agregando Tooltips de Twitter Bootstrap al calendario de WordPress

Ejemplo Calendario con tooltip de twitterBoostrap

Ejemplo Calendario con tooltip de twitterBoostrap

El Twitter Boostrap trae integrado en su sección de javascript un plugin de JQuery (el ToolTip) el cual resulta muy útil e interesante a la hora de mostrar información extra sobre algún elemento o enlace de nuestro sitio.

Por otra parte WordPress nos proporciona un calendario que nos muestra los posts por fecha, el código html del calendario que nos interesa es básicamente este:

 
<table id="wp-calendar">
..
<td>
<a href="url" title="descripcion detallada">num día</a>
</td>
...
</table>

Conociendo el código HTML al que queremos acceder podemos acceder a estos elementos y agregarle el tooltip, como se muestra a continuación:

/** Le agregamos el toolTip a los elementos que nos interesan **/
$('#wp-calendar').find('td a').tooltip();

Queda a reflexión del lector por que use $('#wp-calendar').find('td a') en lugar de $('#wp-calendar td a').

Rockola en Flujos.org

La rockola

rockola.flujos.org

Flujos.org es un laboratorio de radio y streaming por Internet, entre las cosas desarrolladas es la versión de flujos vivos el cual es una distribución basada en debian booteable el cual tiene todo lo necesario para empezar a trasmitir.

Desde hace algunos meses se empezo con el subproyecto la rockola el cual es un concentrado de las trasmisiones y a la vez un auditeka, para esto estamos haciendo uso de octopress(A blogging framework for hackers), jQuery corriendo sobre HTML5, el proyecto lo administramos con git.

Proyecto:

https://github.com/kyv/rockola

Ejemplo Manejo de eventos con Javascript & Mootools – Teclado

Vegeta movimiento con el evento del teclado
Vegeta movimiento con el evento del teclado

Hace un par de meses que di mi taller Mootools en la academia de software libre, uno de  los ejemplos que di fue el de manejo de eventos con el teclado, aqui programe un monito que se mueve y que dejo pendiente el código para en un futuro hacer algún game.

Codigo & ejemplo en linea: <http://vivoenhuajuapan.com/eventos-teclado-ejemplo/>

 

Tema para phpmyadmin.

Hace un tiempo hice una plantilla para el phpmyadmin ya que no me gusta el que viene por defecto, hoy la comparto:

phpmyadmin theme dark orange

phpmyadmin theme dark orange

¿Como instalar?

Descargue el proyecto descomprima la carpeta y adentro ejecute como superusuario:

 ./install.sh 

Para mayores informes visitar el micrositio oficial del proyecto:

http://fitorec.github.com/phpmyadmin_theme_dark_orange/