Factory

Il pattern OOP factory viene utilizzato per creare tipi di istanze differenti di una classe in base a diversi parametri che possiamo passare. Basandoci sulla classe singleton creata precedentemente, possiamo generare una classe factory che crea un tipo di connessione a seconda del driver utilizzato da PDO. Per esempio collegandoci col driver MySQL, SQLite, Oracle…

Creiamo un file DbFactory.php che conterrà la classe DbFactory

namespace App\DB;
use App\DB\DBPDO;

class DbFactory
{
}

inseriamo un metodo pubblico statico che riceverà un array di opzioni simile a quello singleton

public static function create(array $options)

nel metodo create() andremo a fare uno switch sulla chiave driver contenuta nel file di configurazione db. Per prima cosa verifica se è settato un driver col metodo array_key_exists() di php

if (!array_key_exists('driver', $options)) {
 throw new \InvalidArgumentException('Nessun driver predefinito');
}

se la chiave driver non esiste sollevo un’eccezione throw e usando la classe InvalidArgumentException() do un messaggio di errore. Ora passiamo ai casi a seconda del driver

$dsn = '';

switch ($options['driver']) {
    case 'mysql':
    case 'oracle':
    case 'mssql':
        $dsn = $options['driver'].':host='. $options['host'];
        $dsn .= ';dbname=' .$options['database'].';charset='.$options['charset'];
        break;
    case 'sqlite':
        $dsn = 'sqlite' . $options['database'];
        break;
    default :
        throw  new \InvalidArgumentException(' driver non impostato o sconosciuto');
}

Abbiamo impostato di default un’eccezione col messaggio. La parte più rilevante è la costruzione dei parametri di connessione memorizzati in $dsn che dovrà essere per esempio per MySQL:

$dsn = 'mysql:host=localhost;dbname=nomedatabase;charset=utf8';

visto che abbiamo costruito il dsn di connessione alla fine quello da noi costruito dobbiamo assegnarlo alla chiave di $options

$options['dsn'] = $dsn;

se il don è già costruito, tutto questo codice non serve, quindi possiamo fare un controllo a monte

if(!array_key_exists('dsn',$options)) { codice per costruire il dsn fatto in precedenza }

ora possiamo ritornare, alla fine del nostro file, il metodo statico getInstance() della classe singleton:

return DBPDO::getInstance($options);

dicendo preventivamente di usarla col comando use che si utilizza per richiamare una classe in presenza dei namespace :

use App\DB\DBPDO;

Ora includendo il file DbFactory.php  possiamo richiamare la factory che crea la connessione in base al database utilizzato col metodo create()

require_once __DIR__.'/../app/db/DbFactory.php';
$pdoConn = \App\DB\DbFactory::create($data);

Per verificare se è impostato il charset del db e impostarlo aggiungiamo il codice:

if(!array_key_exists('charset', $options)) {
    $options['charset'] = 'utf8';
}

ecco il codice della nostra classe factory completo:

namespace App\DB;
use App\DB\DBPDO;

class DbFactory
{
    public static function create(array $options)
    {
        if(!array_key_exists('charset', $options)) {
            $options['charset'] = 'utf8';
        }
        if(!array_key_exists('dsn',$options)) {
            if (!array_key_exists('driver', $options)) {
                throw  new \InvalidArgumentException('Nessun driver predefinito');
            }

            $dsn = '';

            switch ($options['driver']) {
                case 'mysql':
                case 'oracle':
                case 'mssql':
                    $dsn = $options['driver'].':host='. $options['host'];
                    $dsn .= ';dbname=' .$options['database'].';charset='.$options['charset'];
                    break;
                case 'sqlite':
                    $dsn = 'sqlite' . $options['database'];
                    break;
                default :
                    throw  new \InvalidArgumentException(' driver non impostato o sconosciuto');
            }
            $options['dsn'] = $dsn;
        }

        return DBPDO::getInstance($options);
    }
}