Completed
Push — master ( c622f7...33a06a )
by Richard
09:52 queued 02:32
created

Manager::locate()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 33
Code Lines 21

Duplication

Lines 6
Ratio 18.18 %

Code Coverage

Tests 18
CRAP Score 6.0052

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 4
nop 1
dl 6
loc 33
ccs 18
cts 19
cp 0.9474
crap 6.0052
rs 8.439
c 0
b 0
f 0
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
namespace Xoops\Core\Service;
13
14
use Xmf\Yaml;
15
16
/**
17
 * Xoops services manager, locate, register, choose and dispatch
18
 *
19
 * @category  Xoops\Core\Service\Manager
20
 * @package   Xoops\Core
21
 * @author    Richard Griffith <[email protected]>
22
 * @copyright 2013-2014 The XOOPS Project https://github.com/XOOPS/XoopsCore
23
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
24
 * @version   Release: 1.0
25
 * @link      http://xoops.org
26
 * @since     2.6.0
27
 */
28
class Manager
29
{
30
    /**
31
     * Service Mode constant - Exclusive mode where only one located service
32
     * will be used.
33
     */
34
    const MODE_EXCLUSIVE = 1;
35
36
    /**
37
     * Service Mode constant - Choice mode where one service from potentially
38
     * many located services will be used. The service dispatched will be selected
39
     * by system default.
40
     */
41
    const MODE_CHOICE = 2;
42
43
    /**
44
     * Service Mode constant - Choice mode where one service from potentially many
45
     * located services will be used. The service dispatched will be selected by user
46
     * preference, or system default if no user valid preference is available.
47
     */
48
    const MODE_PREFERENCE = 4;
49
50
    /**
51
     * Service Mode constant - Multiple mode where all located services will be
52
     * dispatched in priority order.
53
     */
54
    const MODE_MULTIPLE  = 8;
55
56
    /**
57
     * Provider priorities
58
     */
59
    const PRIORITY_SELECTED = 0;
60
    const PRIORITY_HIGH     = 1;
61
    const PRIORITY_MEDIUM   = 5;
62
    const PRIORITY_LOW      = 9;
63
64
    /**
65
     * Services registry - array keyed on service name, with provider object as value
66
     *
67
     * @var array
68
     */
69
    protected $services = array();
70
71
    /**
72
     * Provider Preferences - array keyed on service name, where each element is
73
     * an array of provider name => priority entries
74
     *
75
     * @var array|null
76
     */
77
    protected $providerPrefs = null;
78
79
    /**
80
     * @var string config file with provider prefs
81
     */
82
    private $providerPrefsFilename = 'var/configs/system_provider_prefs.yml';
83
84
    /**
85
     * @var string config cache key
86
     */
87
    private $providerPrefsCacheKey = 'system/provider/prefs';
88
89
    /**
90
     * __construct
91
     */
92 1
    protected function __construct()
93
    {
94 1
        $this->providerPrefs = $this->readProviderPrefs();
95 1
    }
96
97
    /**
98
     * Allow one instance only!
99
     *
100
     * @return Manager instance
101
     */
102 12
    public static function getInstance()
103
    {
104 12
        static $instance = false;
105
106 12
        if (!$instance) {
107 1
            $instance = new Manager();
108
        }
109
110 12
        return $instance;
111
    }
112
113
    /**
114
     * readYamlProviderPrefs - read configured provider preferences from file
115
     *
116
     * @return array of configured provider preferences
117
     */
118 1
    public function readYamlProviderPrefs()
119
    {
120 1
        $xoops = \Xoops::getInstance();
121
122 1
        $providerPrefs = array();
123
124
        try {
125 1
            $file = $xoops->path($this->providerPrefsFilename);
126 1
            if (file_exists($file)) {
127
                $providerPrefs = Yaml::read($xoops->path($file));
128
            }
129 1
            if (empty($providerPrefs)) {
130 1
                $providerPrefs = array();
131
            }
132
        } catch (\Exception $e) {
133
            $xoops->events()->triggerEvent('core.exception', $e);
134
            $providerPrefs = array();
135
        }
136 1
        return $providerPrefs;
137
    }
138
139
    /**
140
     * readProviderPrefs - read configured provider preferences from cache
141
     *
142
     * @return array of configured provider preferences
143
     */
144 1
    protected function readProviderPrefs()
145
    {
146 1
        $xoops = \Xoops::getInstance();
147 1
        $providerPrefs = $xoops->cache()->cacheRead(
148 1
            $this->providerPrefsCacheKey,
149 1
            array($this, 'readYamlProviderPrefs')
150
        );
151 1
        return $providerPrefs;
152
    }
153
154
    /**
155
     * saveProviderPrefs - record array of provider preferences in config file, and
156
     * update cache
157
     *
158
     * @param array $providerPrefs array of provider preferences to save
159
     *
160
     * @return void
161
     */
162 View Code Duplication
    protected function saveProviderPrefs($providerPrefs)
163
    {
164
        if (is_array($providerPrefs)) {
165
            $xoops = \Xoops::getInstance();
166
            try {
167
                Yaml::save($providerPrefs, $xoops->path($this->providerPrefsFilename));
168
                $xoops->cache()->write($this->providerPrefsCacheKey, $providerPrefs);
169
            } catch (\Exception $e) {
170
                $xoops->events()->triggerEvent('core.exception', $e);
171
            }
172
        }
173
    }
174
175
    /**
176
     * saveChoice - record priority choices for service providers
177
     *
178
     * This registers a permanent choice (i.e. setting system default) that will
179
     * persist after the lifetime of this service manager.
180
     *
181
     * @param string $service the service name being set
182
     * @param array  $choices array of priorities for each of the named service providers
183
     *
184
     * @return void
185
     */
186
    public function saveChoice($service, $choices)
187
    {
188
        // read current preferences
189
        $prefs = $this->readProviderPrefs();
190
        // replace prefs for selected service
191
        $prefs[$service] = $choices;
192
        // save the changes
193
        $this->saveProviderPrefs($prefs);
194
        // apply to current manager instance
195
        $this->registerChoice($service, $choices);
196
    }
197
198
    /**
199
     * registerChoice - record priority choices for service providers
200
     *
201
     * This registers a temporary choice (i.e. applying user preferences) for the
202
     * lifetime of this service manager only.
203
     *
204
     * @param string $service the service name being set
205
     * @param array  $choices array of priorities for each of the named service providers
206
     *
207
     * @return void
208
     */
209
    public function registerChoice($service, $choices)
210
    {
211
        $provider = $this->locate($service);
212
        $providers = $provider->getRegistered();
213 View Code Duplication
        foreach ($providers as $p) {
214
            $name = strtolower($p->getName());
215
            if (isset($choices[$name])) {
216
                $p->setPriority($choices[$name]);
217
            }
218
        }
219
        $provider->sortProviders();
220
    }
221
222
    /**
223
     * listChoices - list choices availabe for a named service
224
     *
225
     * For MODE_CHOICE services, this can supply an array containing the
226
     * available choices. This array can be used to construct a user form
227
     * to make a choice.
228
     *
229
     * @param string $service the service name being set
230
     *
231
     * @return array of available service provider objects for this service.
232
     */
233
    public function listChoices($service)
234
    {
235
        $providers = $this->locate($service)->getRegistered();
236
        return $providers;
237
    }
238
239
    /**
240
     * locate - create a provider object for a named service, locating all contract implementors
241
     *
242
     * @param string $service the service name being set
243
     *
244
     * @return Provider object for the requested service
245
     */
246 4
    public function locate($service)
247
    {
248 4
        $service = strtolower($service);
249 4
        if (isset($this->services[$service])) {
250
            // service already located
251 2
            $provider = $this->services[$service];
252
        } else {
253 2
            $xoops = \Xoops::getInstance();
254 2
            $provider = new Provider($this, $service);
255 2
            $event = 'core.service.locate.' . $service;
256
            // locate service provider(s)
257
            // In response to trigger message, the contract implementor should register()
258 2
            $xoops->events()->triggerEvent($event, $provider);
259
            // get reference to the list of providers and prioritize it.
260 2
            $registered=$provider->getRegistered();
261 2
            if (count($registered)) {
262 1
                $choices = isset($this->providerPrefs[$service]) ? $this->providerPrefs[$service] : array();
263 1 View Code Duplication
                foreach ($registered as $p) {
264 1
                    $name = strtolower($p->getName());
265 1
                    if (isset($choices[$name])) {
266
                        $p->setPriority($choices[$name]);
267
                    }
268
                }
269 1
                $provider->sortProviders();
270
            } else {
271
                // replace with a null provider since no contract implementers were
272 1
                $provider = new NullProvider($this, $service);
273
            }
274 2
            $this->services[$service] = $provider;
275
        }
276
277 4
        return $provider;
278
    }
279
}
280