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    protected $schemes = array(
24        'tcp' => 'Predis\Connection\StreamConnection',
25        'unix' => 'Predis\Connection\StreamConnection',
26        'redis' => 'Predis\Connection\StreamConnection',
27        'http' => 'Predis\Connection\WebdisConnection',
28    );
29
30    /**
31     * Checks if the provided argument represents a valid connection class
32     * implementing Predis\Connection\NodeConnectionInterface. Optionally,
33     * callable objects are used for lazy initialization of connection objects.
34     *
35     * @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
36     *
37     * @throws \InvalidArgumentException
38     *
39     * @return mixed
40     */
41    protected function checkInitializer($initializer)
42    {
43        if (is_callable($initializer)) {
44            return $initializer;
45        }
46
47        $class = new \ReflectionClass($initializer);
48
49        if (!$class->isSubclassOf('Predis\Connection\NodeConnectionInterface')) {
50            throw new \InvalidArgumentException(
51                'A connection initializer must be a valid connection class or a callable object.'
52            );
53        }
54
55        return $initializer;
56    }
57
58    /**
59     * {@inheritdoc}
60     */
61    public function define($scheme, $initializer)
62    {
63        $this->schemes[$scheme] = $this->checkInitializer($initializer);
64    }
65
66    /**
67     * {@inheritdoc}
68     */
69    public function undefine($scheme)
70    {
71        unset($this->schemes[$scheme]);
72    }
73
74    /**
75     * {@inheritdoc}
76     */
77    public function create($parameters)
78    {
79        if (!$parameters instanceof ParametersInterface) {
80            $parameters = $this->createParameters($parameters);
81        }
82
83        $scheme = $parameters->scheme;
84
85        if (!isset($this->schemes[$scheme])) {
86            throw new \InvalidArgumentException("Unknown connection scheme: '$scheme'.");
87        }
88
89        $initializer = $this->schemes[$scheme];
90
91        if (is_callable($initializer)) {
92            $connection = call_user_func($initializer, $parameters, $this);
93        } else {
94            $connection = new $initializer($parameters);
95            $this->prepareConnection($connection);
96        }
97
98        if (!$connection instanceof NodeConnectionInterface) {
99            throw new \UnexpectedValueException(
100                'Objects returned by connection initializers must implement '.
101                "'Predis\Connection\NodeConnectionInterface'."
102            );
103        }
104
105        return $connection;
106    }
107
108    /**
109     * {@inheritdoc}
110     */
111    public function aggregate(AggregateConnectionInterface $connection, array $parameters)
112    {
113        foreach ($parameters as $node) {
114            $connection->add($node instanceof NodeConnectionInterface ? $node : $this->create($node));
115        }
116    }
117
118    /**
119     * Creates a connection parameters instance from the supplied argument.
120     *
121     * @param mixed $parameters Original connection parameters.
122     *
123     * @return ParametersInterface
124     */
125    protected function createParameters($parameters)
126    {
127        return Parameters::create($parameters);
128    }
129
130    /**
131     * Prepares a connection instance after its initialization.
132     *
133     * @param NodeConnectionInterface $connection Connection instance.
134     */
135    protected function prepareConnection(NodeConnectionInterface $connection)
136    {
137        $parameters = $connection->getParameters();
138
139        if (isset($parameters->password)) {
140            $connection->addConnectCommand(
141                new RawCommand(array('AUTH', $parameters->password))
142            );
143        }
144
145        if (isset($parameters->database)) {
146            $connection->addConnectCommand(
147                new RawCommand(array('SELECT', $parameters->database))
148            );
149        }
150    }
151}
152