Parte 4 - Start

Continua l'analisi di Laravel nel dettaglio dei suoi file. Oggi ci occupiamo ancora dei file di Start, seguendo un po' tutte le procedure di bootstrapping.
francesco
Francesco Malatesta
09/10/2014 in

In questa serie, traduzione autorizzata di quella pubblicata da Christopher Pitt su Rebuilding Laravel, esploreremo in profondità il framework in tutti i suoi aspetti. Dall'autoloading alla configurazione, passando per le operazioni di pulizia ed il routing.

Seguendo la memorizzazione dei paths nell'istanza di Container/Application, possiamo arrivare a capire dove si trova il file di bootstrapping della nostra applicazione. Esatto, un altro file di Bootstrapping, dalla stessa cartella del file Application.php.

$framework = $app['path.base'].'/vendor/laravel/framework/src';

require $framework.'/Illuminate/Foundation/start.php';

Siamo nel file bootstrap/start.php.

Sembra un po' ridondante, considerando il metodo getBootstrapFile() definito nella classe Application:

public static function getBootstrapFile()
{
  return __DIR__.'/start.php';
}

Mcrypt

C'è anche un po' di codice procedurale da queste parti, che serve ad avviare l'applicazione. Diamoci un'occhiata:

if ( ! extension_loaded('mcrypt'))
{
  echo 'Mcrypt PHP extension required.'.PHP_EOL;

  exit(1);
}

Qui siamo in vendor/laravel/framework/src/Illuminate/Foundation/start.php.

Questo file di bootstrap serve ad assicurarsi il caricamento effettivo del modulo PHP Mcrypt. È molto importante.

Nota: il modulo Mcrypt trova applicazioni in molte "zone" di Laravel. Viene usato dal sistema di hashing, ma anche per la protezione di dati relativi a sessioni e cookies. Senza contare le altre applicazioni come le code e i token di autenticazione. Ne parleremo meglio più tardi, comunque.

Testing delle Facade

Poi c'è qualcosa di strano...

$app->instance('app', $app);

Siamo nel file vendor/laravel/framework/src/Illuminate/Foundation/start.php.

Nei commenti viene spiegato che il codice appena visto serve come test facade per l'applicazione. Non ho fatto caso a situazioni del genere nella test suite, ma ha un suo senso.

Assumiamo una classe Foo implementata così:

class Foo
{
  public function getBar()
  {
    return App::make("bar");
  }
}

... potresti effettivamente testare che la chiamata ad App::make() è stata effettuata ed un determinato valore è stato ritornato.

$app = Mockery::mock("stdClass");
$app->shouldReceive("make")->andReturn("mocked make");

App::swap($app);

$foo = new Foo();

$this->assertEquals("mocked make", $foo->getBar());

Sull'utilità di questo test ci sarebbe da dissertare un bel po'... comunque, questo esempio dimostra che può essere fatto, e non che dovrebbe essere fatto.

Andando avanti ecco il codice nel quale ci imbattiamo:

if (isset($unitTesting))
{
    $app['env'] = $env = $testEnvironment;
}

Siamo sempre in vendor/laravel/framework/src/Illuminate/Foundation/start.php.

Una cosa del genere è totalmente fuori contesto, finchè non diamo un'occhiata anche alla classe TestCase inclusa in Laravel.

public function createApplication()
{
    $unitTesting = true;

    $testEnvironment = 'testing';

    return require __DIR__.'/../../bootstrap/start.php';
}

Siamo in app/test/TestCase.php.

Il codice in vendor/.../start.php è interamente a beneficio della classe TestCase. È il luogo dove viene impostato l'ambiente dell'applicazione per il testing, in modo tale da includere l'uso dei file di configurazione in app/config/testing oltre a quelli "canonici" in app/config.

Facade

Andando ancora avanti troviamo del codice che riguarda le Facade.

Facade::clearResolvedInstances();

Facade::setFacadeApplication($app);

Facade, in Laravel, è un termine usato per riferirsi alle classi static-like che fanno da proxy per classi regolari. Le abbiamo viste poco fa: la classe App! La Facade App, infatti, invoca un'istanza della classe Illuminate\Foundation\Application. Decisamente più corto App, vero?

L'uso della parola Facade ha portato a svariate discussioni. Ad ogni modo, in questa sede, non desidero parlarne.

Ecco come appaiono i metodi: siamo nella classe vendor/laravel/framework/src/Illuminate/Support/Facade/Facade.php, adesso.

public static function clearResolvedInstance($name)
{
  unset(static::$resolvedInstance[$name]);
}

public static function setFacadeApplication($app)
{
  static::$app = $app;
}

La classe Facade è la classe base di tutte le Facade presenti in Laravel, come puoi ben immaginare. Ha un array statico, protected, di istanze che corrispondono ad una determinata key di Container.

Registrare una Facade è un processo che si divide in due passi fondamentali. Un service provider aggiunge un resolver tramite i metodi bind() o instance(). La classe Facade, quindi, avrà il compito di definire un metodo che riceverà l'istanza dal container. Vedremo meglio dopo tutta la procedura.

Quindi, il primo metodo si occupa di pulire l'array delle istanze... il secondo, invece, si occupa di inserire una reference della classe Application.