1.6.2. Connection Locator

Some applications may use multiple database servers; for example, one for writes, and one or more for reads. The ConnectionLocator allows you to define multiple Connection objects for lazy-loaded read and write connections. It will create the connections only when they are when called. The Connection creation logic should be wrapped in factory callable.

1.6.2.1. Instantiation

The easiest way to create a ConnectionLoctor is to use its static new() method, either with PDO connection arguments, or with an actual PDO instance:

use Atlas\Pdo\ConnectionLocator;

// pass PDO constructor arguments ...
$connectionLocator = ConnectionLocator::new(
    'mysql:host=localhost;dbname=testdb',
    'username',
    'password'
);

// ... or a PDO instance.
$connectionLocator = ConnectionLocator::new($pdo);

Doing so will define the default connection factory for the ConnectionLocator.

1.6.2.2. Runtime Configuration

Once you have a ConnectionLocator, you can add as many named read and write connection factories as you like:

// the write (master) server
$connectionLocator->setWriteFactory('master', Connection::factory(
    'mysql:host=master.db.localhost;dbname=database',
    'username',
    'password'
));

// read (slave) #1
$connectionLocator->setReadFactory('slave1', Connection::factory(
    return new Connection(
        'mysql:host=slave1.db.localhost;dbname=database',
        'username',
        'password'
    );
});

// read (slave) #2
$connectionLocator->setReadFactory('slave2', Connection::factory(
    'mysql:host=slave2.db.localhost;dbname=database',
    'username',
    'password'
));

// read (slave) #3
$connectionLocator->setReadFactory('slave3', Connection::factory(
    'mysql:host=slave3.db.localhost;dbname=database',
    'username',
    'password'
));

1.6.2.3. Getting Connections

Retrieve a Connection from the locator when you need it. This will create the Connection (if needed) and then return it.

  • getDefault() will return the default Connection.

  • getRead() will return a random read Connection; after the first call, getRead() will always return the same Connection. (If no read Connections are defined, it will return the default connection.)

  • getWrite() will return a random write Connection; after the first call, getWrite() will always return the same Connection. (If no read Connections are defined, it will return the default connection.)

$read = $connectionLocator->getRead();
$results = $read->fetchAll('SELECT * FROM table_name LIMIT 10');

$readAgain = $connectionLocator->getRead();
assert($read === $readAgain); // true

You can get any read or write connection directly by name using the get() method:

$foo = $connectionLocator->get(ConnectionLocator::READ, 'foo');
$bar = $connectionLocator->get(ConnectionLocator::WRITE, 'bar');

1.6.2.4. Locking To The Write Connection

If you call the lockToWrite() method, calls to getRead() will return the write connection instead of the read connection.

$read = $connectionLocator->getRead();
$write = $connectionLocator->getWrite();

$connectionLocator->lockToWrite();
$readAgain = $connectionLocator->getRead();
assert($readAgain === $write); // true

You can disable the lock-to-write behavior by calling lockToWrite(false).

1.6.2.5. Construction-Time Configuration

The ConnectionLocator can be configured with all its connections at construction time; this can be useful with dependency injection mechanisms. (Note that this requires using the constructor proper, not the static new() method.)

use Atlas\Pdo\Connection;
use Atlas\Pdo\ConnectionLocator;

// default connection
$default = Connection::factory(
    'mysql:host=default.db.localhost;dbname=database',
    'username',
    'password'
);

// read connections
$read = [
    'slave1' => Connection::factory(
        'mysql:host=slave1.db.localhost;dbname=database',
        'username',
        'password'
    ),
    'slave2' => Connection::factory(
        'mysql:host=slave2.db.localhost;dbname=database',
        'username',
        'password'
    ),
    'slave3' => Connection::factory(
        'mysql:host=slave3.db.localhost;dbname=database',
        'username',
        'password'
    ),
];

// write connection
$write = [
    'master' => Connection::factory(
        'mysql:host=master.db.localhost;dbname=database',
        'username',
        'password'
    ),
];

// configure locator at construction time
$connectionLocator = new ConnectionLocator($default, $read, $write);