martes, 16 de enero de 2018

Las consolas se mueren

 Pues si. Lamento ser tan dramático con el titular pero hace meses que le doy vueltas a este asunto tan preocupante porque esas cajas de diversión que comenzaron hace tantísimos años tienen el tiempo contado.

¿Pero cómo cojones hemos llegado a ésto?

 Son varios factores en mi opinión y aquí los enumero, aunque es posible que falten algunos porque ya digo esta es mi opinión que nace de la experiencia, muchos años de vicio:
  • Desarrollos cada vez más caros. Si, el caso es que GNU está presente en el PC pero en las multiples plataformas de videojuegos no. Eso y que cada vez las consolas son más complejas hacen que invertir tiempo para crear tú propia librería por medio de la ingeniería inversa sea casi una pérdida de tiempo y que cueste más que comprar una licencia para publicar juegos para determinada consola usando cualquiera de los montones de motores disponibles, tipo Unity o Unreal por mencionar los más populares.
  • Público más exigente, que se puede traducir en que cada vez un listón más alto, porque no es lo mismo sacar el tetris para PS4 que aparte haría desmerecer la potencia del cacharro. Lo que está claro es que queremos juegos cada vez con más filigranas y a la vez muy adictivo, y eso se traduce en un equipo de desarrollo relativamente grande y de ahí se podría pasar al primer punto, un mayor gasto. Tiempo atrás quedó cuando un programador podía hacer la música, los gráficos y el juego mismo!!
  • La estafa de los DLC, ampliaciones, expansión, extensiones o como coño quieran llamarlo. Si, ahora lo que da dinero no es crear un juego sino crear el juego en cachitos, y por supuesto, vendiendo cada cachito de tal forma que la suma de todos los cachos valgan el doble de lo que originalmente se vendería el juego completo solo.
  • Un mercado cada vez más errático debido a los factores citados, que dicho de forma llana, sino hay juegos o pocos en una plataforma los jugadores tarde o temprano la abandonan.
  • Actualizaciones infinitas y juego online por cojones, y de esto experimentando hace unos días y que fue la gota que culminó el vaso que me ha llevado a escribir esta entrada. Os lo cuento para queden flipando. Adquirí hace tiempo un juego de Ubi soft, el For honor, tuve un problema con la cuenta de Ubi soft (el primer día) y nunca más volví a poder jugarlo pues me quedé a la espera de que ese soporte tan gentil (malditos hijoputas prepotentes) me solucionaran el problema. Es un juego por cojones ya no es suficiente que estés conectado con tú cuenta de PS4 sino va más lejos aun y solo funciona conectado y con cuenta de usuario Ubi Soft, a joderse se ha dicho porque yo lo valgo, más o menos así habrán dicho el máximo representante de Ubi Soft con esta absurda política. EEeeeh y que no he mencionado que aunque juegues online hay que hacer por cojones la instalación de tropecientos gigas en la memoria de la consola ¿Qué no tienes espacio? Pues no juegas o eliminas lo que tengas, o en el mejor de los casos para las tiendas te compras otro y no pasa nada (total unos pocos euros €€€). Pues esto dije, nunca más compro un juego de Ubi Soft, pues el For Honor a la semana lo descambié, y terminé comprando otra perla, el Destinity 2 de Bungie Studios. Emocionado llegué a casa y metí el juego, entonces la PS4 me indica que tiene que actualizarse, 3 gigas, bueno no pasa nada me dije. Una vez acabó de actualizar el juego pidió actualizarse porque sino no se ejecutaba, bueno no pasa nada me dije. YA cuando acabo, al cabo de unas horas, me dije por fin... y el juego nuevamente me indicó que tenía que volver a actualizarse, y todo esto para luego jugar a un juego con problemas en el servidor, pues hay que jugarlo conectado por cojones y con algunos bugs... en fin, alado sea el equipo Steam y el PC, saben a lo que me refiero?  

Alternativas al hambre de los jugadores


 La alternativa pasa bien o pasarte a la plataforma rival o competencia, la cual no es nada barata, pues las consolas han llegado a una política de precios casi absurda. O volver al PC, esa máquina que en lo que se refería a jugabilidad siempre había sido pobre pero que ahora con el abaratamientos de componentes y un mercado glorioso de portabilidades, únicos y de bajo presupuesto (indies), hacen que la máquina con más juegos y más entretenida sea el Personal Computer, elegido por la mayoría de jugadores o gamers. Porque ¿dónde verás emuladores de PS, Nintendo, Super Nintendo, Sega Megadrive y sin fin de máquinas de entretenimiento? pues en el PC sino.

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.

La sexy de enero


pequeña pero matona


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.