1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\Cache;
11
12use Traversable;
13use Zend\EventManager\EventsCapableInterface;
14use Zend\Stdlib\ArrayUtils;
15
16abstract class StorageFactory
17{
18    /**
19     * Plugin manager for loading adapters
20     *
21     * @var null|Storage\AdapterPluginManager
22     */
23    protected static $adapters = null;
24
25    /**
26     * Plugin manager for loading plugins
27     *
28     * @var null|Storage\PluginManager
29     */
30    protected static $plugins = null;
31
32    /**
33     * The storage factory
34     * This can instantiate storage adapters and plugins.
35     *
36     * @param array|Traversable $cfg
37     * @return Storage\StorageInterface
38     * @throws Exception\InvalidArgumentException
39     */
40    public static function factory($cfg)
41    {
42        if ($cfg instanceof Traversable) {
43            $cfg = ArrayUtils::iteratorToArray($cfg);
44        }
45
46        if (!is_array($cfg)) {
47            throw new Exception\InvalidArgumentException(
48                'The factory needs an associative array '
49                . 'or a Traversable object as an argument'
50            );
51        }
52
53        // instantiate the adapter
54        if (!isset($cfg['adapter'])) {
55            throw new Exception\InvalidArgumentException('Missing "adapter"');
56        }
57        $adapterName    = $cfg['adapter'];
58        $adapterOptions = array();
59        if (is_array($cfg['adapter'])) {
60            if (!isset($cfg['adapter']['name'])) {
61                throw new Exception\InvalidArgumentException('Missing "adapter.name"');
62            }
63
64            $adapterName    = $cfg['adapter']['name'];
65            $adapterOptions = isset($cfg['adapter']['options']) ? $cfg['adapter']['options'] : array();
66        }
67        if (isset($cfg['options'])) {
68            $adapterOptions = array_merge($adapterOptions, $cfg['options']);
69        }
70
71        $adapter = static::adapterFactory((string) $adapterName, $adapterOptions);
72
73        // add plugins
74        if (isset($cfg['plugins'])) {
75            if (!$adapter instanceof EventsCapableInterface) {
76                throw new Exception\RuntimeException(sprintf(
77                    "The adapter '%s' doesn't implement '%s' and therefore can't handle plugins",
78                    get_class($adapter),
79                    'Zend\EventManager\EventsCapableInterface'
80                ));
81            }
82
83            if (!is_array($cfg['plugins'])) {
84                throw new Exception\InvalidArgumentException(
85                    'Plugins needs to be an array'
86                );
87            }
88
89            foreach ($cfg['plugins'] as $k => $v) {
90                $pluginPrio = 1; // default priority
91
92                if (is_string($k)) {
93                    if (!is_array($v)) {
94                        throw new Exception\InvalidArgumentException(
95                            "'plugins.{$k}' needs to be an array"
96                        );
97                    }
98                    $pluginName    = $k;
99                    $pluginOptions = $v;
100                } elseif (is_array($v)) {
101                    if (!isset($v['name'])) {
102                        throw new Exception\InvalidArgumentException("Invalid plugins[{$k}] or missing plugins[{$k}].name");
103                    }
104                    $pluginName = (string) $v['name'];
105
106                    if (isset($v['options'])) {
107                        $pluginOptions = $v['options'];
108                    } else {
109                        $pluginOptions = array();
110                    }
111
112                    if (isset($v['priority'])) {
113                        $pluginPrio = $v['priority'];
114                    }
115                } else {
116                    $pluginName    = $v;
117                    $pluginOptions = array();
118                }
119
120                $plugin = static::pluginFactory($pluginName, $pluginOptions);
121                $adapter->addPlugin($plugin, $pluginPrio);
122            }
123        }
124
125        return $adapter;
126    }
127
128    /**
129     * Instantiate a storage adapter
130     *
131     * @param  string|Storage\StorageInterface                  $adapterName
132     * @param  array|Traversable|Storage\Adapter\AdapterOptions $options
133     * @return Storage\StorageInterface
134     * @throws Exception\RuntimeException
135     */
136    public static function adapterFactory($adapterName, $options = array())
137    {
138        if ($adapterName instanceof Storage\StorageInterface) {
139            // $adapterName is already an adapter object
140            $adapter = $adapterName;
141        } else {
142            $adapter = static::getAdapterPluginManager()->get($adapterName);
143        }
144
145        if ($options) {
146            $adapter->setOptions($options);
147        }
148
149        return $adapter;
150    }
151
152    /**
153     * Get the adapter plugin manager
154     *
155     * @return Storage\AdapterPluginManager
156     */
157    public static function getAdapterPluginManager()
158    {
159        if (static::$adapters === null) {
160            static::$adapters = new Storage\AdapterPluginManager();
161        }
162        return static::$adapters;
163    }
164
165    /**
166     * Change the adapter plugin manager
167     *
168     * @param  Storage\AdapterPluginManager $adapters
169     * @return void
170     */
171    public static function setAdapterPluginManager(Storage\AdapterPluginManager $adapters)
172    {
173        static::$adapters = $adapters;
174    }
175
176    /**
177     * Resets the internal adapter plugin manager
178     *
179     * @return void
180     */
181    public static function resetAdapterPluginManager()
182    {
183        static::$adapters = null;
184    }
185
186    /**
187     * Instantiate a storage plugin
188     *
189     * @param string|Storage\Plugin\PluginInterface     $pluginName
190     * @param array|Traversable|Storage\Plugin\PluginOptions $options
191     * @return Storage\Plugin\PluginInterface
192     * @throws Exception\RuntimeException
193     */
194    public static function pluginFactory($pluginName, $options = array())
195    {
196        if ($pluginName instanceof Storage\Plugin\PluginInterface) {
197            // $pluginName is already a plugin object
198            $plugin = $pluginName;
199        } else {
200            $plugin = static::getPluginManager()->get($pluginName);
201        }
202
203        if (!$options instanceof Storage\Plugin\PluginOptions) {
204            $options = new Storage\Plugin\PluginOptions($options);
205        }
206
207        if ($options) {
208            $plugin->setOptions($options);
209        }
210
211        return $plugin;
212    }
213
214    /**
215     * Get the plugin manager
216     *
217     * @return Storage\PluginManager
218     */
219    public static function getPluginManager()
220    {
221        if (static::$plugins === null) {
222            static::$plugins = new Storage\PluginManager();
223        }
224        return static::$plugins;
225    }
226
227    /**
228     * Change the plugin manager
229     *
230     * @param  Storage\PluginManager $plugins
231     * @return void
232     */
233    public static function setPluginManager(Storage\PluginManager $plugins)
234    {
235        static::$plugins = $plugins;
236    }
237
238    /**
239     * Resets the internal plugin manager
240     *
241     * @return void
242     */
243    public static function resetPluginManager()
244    {
245        static::$plugins = null;
246    }
247}
248