Files
predis/src/Connection/Factory.php
T
Daniele Alessandri dd5d665156 Dramatically improve aggregate connections initialization.
This is a complete overhaul of how aggregate connections are created and
initialized, now everything is self-contained in our usual 3 supported
client options: "aggregate", "cluster" and "replication".

The usage of callables acting as connection initializerss is now more
consistent through the various options. When the callable is invoked it
receives 3 arguments (the original set of connection parameters passed
by reference, the options container, the current option) and must return
an instance of Predis\Connection\AggregateConnectionInterface otherwise
an InvalidArgumentException is thrown.

When using "cluster" and "replication" the returned aggregate connection
is automatically populated by adding the list of nodes in $parameters,
on the other hand "aggregate" skips this automatism so it is up to the
user. In any case the user-supplied callable receives $parameters as a
reference, setting $parameters to NULL inside the body of the callable
makes the client skip automatic aggregation regardless of the option in
use.

In addition to this the actual procedure of adding nodes to an aggregate
connection has been moved directly into the respective options instead
of being spread between the client (which instead should just pass a set
of parameters and get back a fully-configured aggregate connection) and
the connection factory (and the scope of a connection factory is only to
create new connetion instances to single Redis servers).
2020-09-03 12:43:15 +02:00

183 lines
5.1 KiB
PHP

<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Connection;
use Predis\Command\RawCommand;
/**
* Standard connection factory for creating connections to Redis nodes.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class Factory implements FactoryInterface
{
private $defaults = array();
protected $schemes = array(
'tcp' => 'Predis\Connection\StreamConnection',
'unix' => 'Predis\Connection\StreamConnection',
'tls' => 'Predis\Connection\StreamConnection',
'redis' => 'Predis\Connection\StreamConnection',
'rediss' => 'Predis\Connection\StreamConnection',
'http' => 'Predis\Connection\WebdisConnection',
);
/**
* Checks if the provided argument represents a valid connection class
* implementing Predis\Connection\NodeConnectionInterface. Optionally,
* callable objects are used for lazy initialization of connection objects.
*
* @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
*
* @throws \InvalidArgumentException
*
* @return mixed
*/
protected function checkInitializer($initializer)
{
if (is_callable($initializer)) {
return $initializer;
}
$class = new \ReflectionClass($initializer);
if (!$class->isSubclassOf('Predis\Connection\NodeConnectionInterface')) {
throw new \InvalidArgumentException(
'A connection initializer must be a valid connection class or a callable object.'
);
}
return $initializer;
}
/**
* {@inheritdoc}
*/
public function define($scheme, $initializer)
{
$this->schemes[$scheme] = $this->checkInitializer($initializer);
}
/**
* {@inheritdoc}
*/
public function undefine($scheme)
{
unset($this->schemes[$scheme]);
}
/**
* {@inheritdoc}
*/
public function create($parameters)
{
if (!$parameters instanceof ParametersInterface) {
$parameters = $this->createParameters($parameters);
}
$scheme = $parameters->scheme;
if (!isset($this->schemes[$scheme])) {
throw new \InvalidArgumentException("Unknown connection scheme: '$scheme'.");
}
$initializer = $this->schemes[$scheme];
if (is_callable($initializer)) {
$connection = call_user_func($initializer, $parameters, $this);
} else {
$connection = new $initializer($parameters);
$this->prepareConnection($connection);
}
if (!$connection instanceof NodeConnectionInterface) {
throw new \UnexpectedValueException(
'Objects returned by connection initializers must implement '.
"'Predis\Connection\NodeConnectionInterface'."
);
}
return $connection;
}
/**
* Assigns a default set of parameters applied to new connections.
*
* The set of parameters passed to create a new connection have precedence
* over the default values set for the connection factory.
*
* @param array $parameters Set of connection parameters.
*/
public function setDefaultParameters(array $parameters)
{
$this->defaults = $parameters;
}
/**
* Returns the default set of parameters applied to new connections.
*
* @return array
*/
public function getDefaultParameters()
{
return $this->defaults;
}
/**
* Creates a connection parameters instance from the supplied argument.
*
* @param mixed $parameters Original connection parameters.
*
* @return ParametersInterface
*/
protected function createParameters($parameters)
{
if (is_string($parameters)) {
$parameters = Parameters::parse($parameters);
} else {
$parameters = $parameters ?: array();
}
if ($this->defaults) {
$parameters += $this->defaults;
}
return new Parameters($parameters);
}
/**
* Prepares a connection instance after its initialization.
*
* @param NodeConnectionInterface $connection Connection instance.
*/
protected function prepareConnection(NodeConnectionInterface $connection)
{
$parameters = $connection->getParameters();
if (isset($parameters->password) && strlen($parameters->password)) {
$cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
? array($parameters->username, $parameters->password)
: array($parameters->password);
$connection->addConnectCommand(
new RawCommand('AUTH', $cmdAuthArgs)
);
}
if (isset($parameters->database) && strlen($parameters->database)) {
$connection->addConnectCommand(
new RawCommand('SELECT', array($parameters->database))
);
}
}
}