1<?php 2 3/* 4 * This file is part of the Predis package. 5 * 6 * (c) Daniele Alessandri <suppakilla@gmail.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Predis\Connection; 13 14use Predis\Command\RawCommand; 15 16/** 17 * Standard connection factory for creating connections to Redis nodes. 18 * 19 * @author Daniele Alessandri <suppakilla@gmail.com> 20 */ 21class Factory implements FactoryInterface 22{ 23 private $defaults = array(); 24 25 protected $schemes = array( 26 'tcp' => 'Predis\Connection\StreamConnection', 27 'unix' => 'Predis\Connection\StreamConnection', 28 'tls' => 'Predis\Connection\StreamConnection', 29 'redis' => 'Predis\Connection\StreamConnection', 30 'rediss' => 'Predis\Connection\StreamConnection', 31 'http' => 'Predis\Connection\WebdisConnection', 32 ); 33 34 /** 35 * Checks if the provided argument represents a valid connection class 36 * implementing Predis\Connection\NodeConnectionInterface. Optionally, 37 * callable objects are used for lazy initialization of connection objects. 38 * 39 * @param mixed $initializer FQN of a connection class or a callable for lazy initialization. 40 * 41 * @throws \InvalidArgumentException 42 * 43 * @return mixed 44 */ 45 protected function checkInitializer($initializer) 46 { 47 if (is_callable($initializer)) { 48 return $initializer; 49 } 50 51 $class = new \ReflectionClass($initializer); 52 53 if (!$class->isSubclassOf('Predis\Connection\NodeConnectionInterface')) { 54 throw new \InvalidArgumentException( 55 'A connection initializer must be a valid connection class or a callable object.' 56 ); 57 } 58 59 return $initializer; 60 } 61 62 /** 63 * {@inheritdoc} 64 */ 65 public function define($scheme, $initializer) 66 { 67 $this->schemes[$scheme] = $this->checkInitializer($initializer); 68 } 69 70 /** 71 * {@inheritdoc} 72 */ 73 public function undefine($scheme) 74 { 75 unset($this->schemes[$scheme]); 76 } 77 78 /** 79 * {@inheritdoc} 80 */ 81 public function create($parameters) 82 { 83 if (!$parameters instanceof ParametersInterface) { 84 $parameters = $this->createParameters($parameters); 85 } 86 87 $scheme = $parameters->scheme; 88 89 if (!isset($this->schemes[$scheme])) { 90 throw new \InvalidArgumentException("Unknown connection scheme: '$scheme'."); 91 } 92 93 $initializer = $this->schemes[$scheme]; 94 95 if (is_callable($initializer)) { 96 $connection = call_user_func($initializer, $parameters, $this); 97 } else { 98 $connection = new $initializer($parameters); 99 $this->prepareConnection($connection); 100 } 101 102 if (!$connection instanceof NodeConnectionInterface) { 103 throw new \UnexpectedValueException( 104 'Objects returned by connection initializers must implement '. 105 "'Predis\Connection\NodeConnectionInterface'." 106 ); 107 } 108 109 return $connection; 110 } 111 112 /** 113 * {@inheritdoc} 114 */ 115 public function aggregate(AggregateConnectionInterface $connection, array $parameters) 116 { 117 foreach ($parameters as $node) { 118 $connection->add($node instanceof NodeConnectionInterface ? $node : $this->create($node)); 119 } 120 } 121 122 /** 123 * Assigns a default set of parameters applied to new connections. 124 * 125 * The set of parameters passed to create a new connection have precedence 126 * over the default values set for the connection factory. 127 * 128 * @param array $parameters Set of connection parameters. 129 */ 130 public function setDefaultParameters(array $parameters) 131 { 132 $this->defaults = $parameters; 133 } 134 135 /** 136 * Returns the default set of parameters applied to new connections. 137 * 138 * @return array 139 */ 140 public function getDefaultParameters() 141 { 142 return $this->defaults; 143 } 144 145 /** 146 * Creates a connection parameters instance from the supplied argument. 147 * 148 * @param mixed $parameters Original connection parameters. 149 * 150 * @return ParametersInterface 151 */ 152 protected function createParameters($parameters) 153 { 154 if (is_string($parameters)) { 155 $parameters = Parameters::parse($parameters); 156 } else { 157 $parameters = $parameters ?: array(); 158 } 159 160 if ($this->defaults) { 161 $parameters += $this->defaults; 162 } 163 164 return new Parameters($parameters); 165 } 166 167 /** 168 * Prepares a connection instance after its initialization. 169 * 170 * @param NodeConnectionInterface $connection Connection instance. 171 */ 172 protected function prepareConnection(NodeConnectionInterface $connection) 173 { 174 $parameters = $connection->getParameters(); 175 176 if (isset($parameters->password) && strlen($parameters->password)) { 177 $cmdAuthArgs = isset($parameters->username) && strlen($parameters->username) 178 ? array('AUTH', $parameters->username, $parameters->password) 179 : array('AUTH', $parameters->password); 180 181 $connection->addConnectCommand( 182 new RawCommand($cmdAuthArgs) 183 ); 184 } 185 186 if (isset($parameters->database) && strlen($parameters->database)) { 187 $connection->addConnectCommand( 188 new RawCommand(array('SELECT', $parameters->database)) 189 ); 190 } 191 } 192} 193