# Laravel ( Illuminate ) Components - Schedule

Este no es un componente pero si la joya de la corona del **Console** de Laravel por lo que merece un tratamiento especial.

En este capitulo veremos como usar el  [Schedule ](https://laravel.com/docs/5.8/scheduling) de Laravel fuera del framework para que podamos usarlo como mejor nos parezca.

Lo primero que vamos hacer es crear un archivo de ejecución con nombre de `artisan` (ya que se no hace familiar), este sera el que ejecutara nuestro cron tal como esta en la documentación.

```
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
``` 

Antes de comenzar os dejo el  [repo de github](https://github.com/millancore/illuminate-schedule) , por que a veces es mas sencillo ver todo desde alli! :D

Veamos nuestro artisan
```php
#!/usr/bin/env php
<?php

use Schedule\Kernel;
use Schedule\Application;
use Illuminate\Events\Dispatcher;

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

$app = new Application;

$app['config'] = [
    'cache.default' => 'file',
    'cache.stores.file' => [
        'driver' => 'file',
        'path' => __DIR__ . '/cache'
    ]
];

$app['files'] = new Filesystem;

$kernel = new Kernel($app, new Dispatcher($app));

$kernel->handle(
    new Symfony\Component\Console\Input\ArgvInput,
    new Symfony\Component\Console\Output\ConsoleOutput
);
```

Ahora veamos de que va esto, tenemos un Application y un Kernel que se encargara de manejar los diferentes comandos que le pasamos a nuestro artisan.

El **Application** de Laravel solo es un Container vitaminizado, así que nosotros crearemos nuestro Application solo con las cosas que necesita nuestro Schedule.

veamos las dependencias para nuestro proyecto antes de continuar

```
{
    "require": {
        "illuminate/console": "^5.8",
        "illuminate/events": "^5.8",
        "illuminate/cache": "^5.8",
        "illuminate/filesystem": "^5.8",
        "dragonmantank/cron-expression": "^2.3"
    },
    "autoload": {
        "psr-4": {
            "Schedule\\": "src/"
        },
        "files": [
            "helpers.php"
        ]
    }
}
```

Ahora si el **Application**

```php
<?php

namespace Schedule;

use Illuminate\Cache\CacheManager;
use Illuminate\Console\Scheduling\CacheEventMutex;
use Illuminate\Console\Scheduling\EventMutex;
use Illuminate\Container\Container;
use Illuminate\Contracts\Cache\Factory;

class Application extends Container
{
    public function __construct()
    {
        $this->registerBaseBindings();
        $this->registerScheduleBindings();
    }

    protected function registerBaseBindings()
    {
        static::setInstance($this);
    }

    protected function registerScheduleBindings()
    {
        $this->bind(
            Factory::class,
            function ($app) {
                return new CacheManager($app);
            }
        );

        $this->bind(EventMutex::class, CacheEventMutex::class);
        $this->bind(SchedulingMutex::class, CacheSchedulingMutex::class);
    }

    public function environment()
    {
        return 'prod';
    }

    public function isDownForMaintenance()
    {
        return false;
    }
}
```

Es un Application bastante sencillo como podemos ver, tenemos un `registerBaseBindings` que se encarga de setear nuestra instancia para que librerías que usan el container puedan acceder a este de manera global, luego tenemos un `registerScheduleBindings` en donde registramos un CacheManager y los **Mutex** estos ultimos se encarga de asignar un ID unico a los los eventos y al schedule para que no se solapen y se guardan en cache para que hacer el proceso mas eficiente.

Luego tenemos un `environment` y `isDownForMaintenance` , el primero donde retornamos nuestro entorno, muy util si tenemos tareas en nuestro Schedule con diferentes entornos y el segundo es para apagar el Schedule ambas que pueden llevar a un archivo de configuración.  (os dejo los cambio menores).

Ahora desmosle una mirada al nuestro Kernel

```php
<?php

namespace Schedule;

use Illuminate\Console\Application as Artisan;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Console\Scheduling\ScheduleRunCommand;
use Illuminate\Events\Dispatcher;

class Kernel
{
    protected $app;
    protected $artisan;
    protected $events;

    protected $commands = [
        #Register command here!!
    ];

    public function __construct(Application $app, Dispatcher $events)
    {
        $this->app = $app;
        $this->events = $events;
    }

    public function handle($input, $output = null)
    {
        $this->bootstrap();
        return $this->getArtisan()->run($input, $output);
    }
    
    protected function schedule(Schedule $schedule)
    {
         #Schedule comands here!!
    }

    protected function bootstrap()
    {
        $schedule = new Schedule();

        $this->getArtisan()->add(
            new ScheduleRunCommand($schedule)
        );

        $this->schedule($schedule);
    }

    protected function getArtisan()
    {
        if (is_null($this->artisan)) {
            return $this->artisan = (new Artisan($this->app, $this->events, '5.8'))
                ->resolveCommands($this->commands);
        }
        return $this->artisan;
    }
}
```
Tenemos como de costumbre un Array donde registrar nuestros commands y un método schedule donde agregaremos nuestras tareas. Toda la lógica de ejecución reside en el método **handle** que se encargara de resolver los comandos que le pasamos a artisan.

Y por ultimo tenemos un helper que usa Schedule para saber donde esta parado :D 

```php
<?php

if (! function_exists('base_path')) {
    /**
     * Get the path to the base of the install.
     *
     * @param  string  $path
     * @return string
     */
    function base_path($path = '')
    {
        return __DIR__;
    }
}
```

Nunca fue tan fácil usar Schedule! 

Espero os sea de ayuda! Alguna duda o sugerencia la podéis dejar como comentario o hacerme una mencion en twitter @millancore

