Slim 3 y Monolog - parte 1

 dentro de la carpeta de nuestro proyecto,

agregar la dependencia de slim

sudo composer require slim/slim:3.*

agregar la dependencia de monolog

sudo composer require monolog/monolog

----------------------------------------------------

nota: podemos levantar el servidor integrado de php, así:

php -S localhost:8000 -t public/

(siempre que los archivos esten en la carpeta public)

------------------------------------------

en el archivo public/index.php


<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Utils\NumberConversionUtils;
use Utils\TestUtils;

require '../vendor/autoload.php';

$configuration = [
'settings' => [
'displayErrorDetails' => true,
],
];
$container = new \Slim\Container($configuration);
$app = new \Slim\App($container);


$container['Logger'] = function($c) {

$logger = new Monolog\Logger('my_logger');
$filename = _DIR__ . '/../log/error.log';
$file_handler = new Monolog\Handler\StreamHandler($filename);
$logger->pushHandler($file_handler);
return $logger;
};


$app->get('/hello/{name}', function (Request $request, Response $response, array $args) {
$name = $args['name'];
$response->getBody()->write("Hello, $name");
$this->get('Logger')->addInfo('Something interesting happened');

return $response;
});

$app->run();



SOLID

 defectos que causan daño al sw:

-poner mas codigo/funcionalidad no relacionada en una unica clase

-hacer depender una clase de otra (estrechamente acopladas) el cambio en una afectará a la otra

-meter codigo duplicado

soluciones:

-elegir arquitectura correcta (mvc,etc)

-seguir principios de diseño ...solid

-elegir patrones de diseño

--------------------------------------------

SOLID

-acrónimo: cada letra representa un principio. 

-si se sigue hará de nuestro sw uno escalable en el tiempo.

-tiene una relación con los conceptos de:

alta cohesión y bajo acoplamiento

alta cohesión: la información que almacena una clase debe ser coherente y estar relacionada con la clase.

bajo acoplamiento: tener las clases lo menos ligadas entre si. de tal modo que si se modifica una de ellas, no afecte o afecte poco al resto de clases.


SOLID, principios:

S: responsabilidad única

0: abierto o cerrado

L: sustitución de Liskov

I: segregación de interfaces

D: inversión de dependencia


un buen diseño nos ayuda a hacer más sencillo el mantenimiento del sw, para que cada vez que nos pidan una nueva funcionalidad no tener que estar tocando media aplicación de código antiguo.

reducimos así el costo de mantenimiento de sw.


Principio de Responsabilidad Unica:

-cada modulo de sw debe tener una sola razón para cambiar (no como una navaja suiza)

ejemplo

class Usuario{

public function pagarMisDeudas(){

  if(tieneDineroEnELBanco(id_usuario){

...

}


}

public function tieneDineroEnELBanco(id_usuario){

...

}

}

-----------------------

la responsabilidad de la funcion tieneDineroEnELBanco(id_usuario)

 no le pertenece directamenreal Usuario...

pues esa misma logica la vamos a querer usar en otra parte de la aplicacion y terminemos copiando y pegando ese codigo, haciendo luego inmantenible.

entonces, una solución sencilla sería:

class Usuario{

Banco $banco;

public Usuario(Banco banco){

     $this->banco = banco;

}

public function pagarMisDeudas(){

  if($this->banco->tieneDineroEnELBanco(id_usuario){

...

}


}

Principio Abierto Cerrado

un modulo o clase de sw está abierto para extensión cerrado para modificación.


entonces si por ejemplo tenemos

class AreaService{

  public sumarAreas(Rectangulo[] rectangulos){
    //recorremos el arreglo de rectangulos ,
    /por cada rectangulo, segun su base y altura y calculamos el area y lo acumulamos en una variable
   //devolvemos el valor de la variable de acumulacion
  }
}

si ahora tambien ademas de rectangulos tenemos circulos, 
una solución podria ser
hacer una clase Figura de la cual extender Rectangulo y Circulo
entonces
modificamos el metodo
  public sumarAreas(Figura[] figura){
    //recorremos el arreglo de figuras ,
    /por cada figura, segun la instancia de què objeto sea calculamos su area y lo acumulamos en una variable
   //devolvemos el valor de la variable de acumulacion
  }
pero que pasa si se agregan mas tipos de Figura?

entonces tendriamos que modificar el metodo de sumarAreas para poder calcular el area
segun cada uno de los nuevos tipos de figuras.

se viola lo de "cerrado para modificación" del método..
entonces lo que se puede hacer es que el método que calcula el área debe estar implementado en cada una de las clases y ser llamadas  dentro del mètodo de sumarAreas

PRINCIPIO DE LISKOV

asegurarse de que la clase derivada no modifique el comportamiento de la clase padre.


class FileManager{
   writeFiles(File[] file){
      file->write();
   }
}

donde File tiene 2 metodos: read y write

si luego, nos indican que hay Files que no pueden escribirse.

se podria crear FileReadeable para que extiendan de File y reescriba el metodo write
donde el metodo write de FileReadeable lance una exception.

esto viola el principio, ya que el hijo ya no hace lo del padre.


entonces lo que vamos a hacer es crear 2 interfaces

IFileReadeable con el unico metodo read
IFileWritable con el unico metodo write


donde File implementaria ambas interfaces

entonces, FileManager quedaria asi:

class FileManager{
   writeFiles(IFileWriteable[] file){
      file->write();
   }
}


principio de Segregación de Interfaces

es preferible muchas interfaces con pocos metodos
que pocas con muchos.
asi no obligamos a un cliente a implementar metodos que no usa.

por ejemplo
tenemos que una emplresa hay un TeamLead que puede crear una tarea, asignar una tarea y trabajarenunatarea.
entonces podemos crear la interface ILead
con los metodos 
createTask()
assignTask()
WorkOnTask()

y luego creamos la clase TeamLead que implementa ILead

luego nos dicen que hay un Manager con similares capacidades que el TeamLead pero que no puede trabajar en ninguna tarea,
entonces podemos crear una clase Manager que implemente ILead
y en el metodo workOnTask() que lance una excepcion indicando un error.

esta soluciòn viola el principio, pues se està obligando a Manager a implementar un método que no usa.
ahora imaginemos que tambien tenemos un programador que solo puede trabajar en una tarea,

lo que tendriamos que hacer es crear 3 interfaces

IProgrammer con el metodo workOnTask()
IManager con el metodo createTask() y assignTask()

entonces :
La clase TeamLead implementa IProgrammer y IManager
La clase Programmer implementa IProgrammer
La clase Manager implementa IManager

Principio de inversión de dependencias


Los modulos/clases de alto nivel no deberian depender de las de bajo nivel.

supongamos que tenemos
class Logger{
   logMessage(string message){
  }
}
class DBLogger{
  logMessage(string message){
 }
}

y tenemos una 
class ExceptionLoggerManager{
logearEnFile(Exception e){
  log =new FileLoger()
  log->logMessage(e->getMessage())
}
logearEnDB(Exception e){
}
  log = new DBLoger();
  log->logMessage(e->getMessage())

}

class exportarData(){
 try{
}catch(IOException e){
new ExceptionLogerManager->logearEnDb(e);
}catch(Exception e){
new ExceptionLogerManager->logearEnFile(e)
}

}

el problema aca es que cada vez que nos pidan logear en otro lado, la clase ExceptionLogerManager
va a tener que modificarse. Eso pasa porque depende mucho de clase de bajo nivel.

la solucion:
creamos una interface ILoger metodo log(string)
y cada log distinto que la implemente
entonces

la nueva interfaz se pasa como parametro en el constructor de la clase ExcpetionLogerManager

class ExceptionLogerManager{

ILoger _iloger;

ExceptionLogerManager(Iloger iloger)
{
_iloger = iloger;
}

}
 entonces ahora la clase de exportar quedaria asi:

class exportarData(){
 try{
}catch(IOException e){
new ExceptionLogerManager(new DBLOger())->log(e);
}catch(Exception e){
new ExceptionLogerManager(new FIleLOger())->loge(e)
}

}





 

composer de una version especifica

 el comando require instalarà la version que se adapte a tu proyecto

composer require monolog/monolog


pero tambien se le puede indicar una versión especifica:

composer require monolog/monolog:~1.17.0


# Signature:

composer require <vendor>/<name>:<version>

donde, version se puede expresar de distintas manera:

 ^ (caret)  ^1.2.3 es equivalente a >=1.2.3 <2.0.0)

 ~ (tilde)  ~1.2 es equivalente a >=1.2 <2.0.0 

              o  ~1.2.3 es equivalente a >=1.2.3 <1.3.0)

* (wildcard) 1.0.* es equivalente a >=1.0 <1.1.


listar servicios en linux

 ejecutar el comando:

sudo systemctl list-unit-files --type service --all


para listar sólo los servicios habilitados (enabled), osea los que se estan ejecutando actualmente:

sudo systemctl | grep running




composer install y composer update

composer install

Las dependencias de nuestra aplicación con Composer se configuran en el fichero composer.json

La primera vez que ejecutamos composer install en un proyecto, Composer lee ese fichero, 

resuelve las dependencias que hay en él e instala los paquetes en el directorio vendor

segun la version configurada para cada paquete y la configuración de estabilidad especificadas 

en el fichero composer.json.

Luego, Composer crea en el directorio donde se ha ejecutado el comando install el fichero 

composer.lock en el cual anota todos los paquetes instalados y la versión instalada de cada uno de ellos. 

Comando update

El comando composer update lee siempre el fichero composer.json e instala las dependencias de ese fichero. 

Después de instalar los paquetes, crea en el directorio donde se ha ejecutado este comando 

el fichero composer.lock o lo actualiza si ya existe.


NOTA:


Cuando añades un nuevo paquete a tu aplicación, si usas el comando composer require 

(por ejemplo, composer require doctrine/dbal:~2.3), 

Composer añadirá ese paquete al fichero composer.json y lo instalará. 

Por lo que seguirás manteniendo para el resto de paquetes las mismas versiones que tenían instaladas.

como encontrar archivos que contengan un cierto texto en linux

 desde la carpeta donde vas a buscar los archivos ejecutar el sgt comando


grep -iRl "your-text-to-find" ./


donde 

-i - ignore text case

-R - recursively search files in subdirectories.

-l - show file names instead of file contents portions.

abrir un archivo pdf desde la terminal de linux

 use la siguiente sentencia:


evince my_file.pdf


para hacer que luego de abrir el archivo el cursor vuelva al prompt


evince my_file.pdf &

linux ubuntu mint actualizar chrome

 desde una terminal: $ sudo apt update $ sudo apt install google-chrome-stable