Completed
Push — master ( af7267...09bff1 )
by Matthias
02:44
created

DataSourceManager::getDriver()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 7.551
c 0
b 0
f 0
cc 7
eloc 13
nc 5
nop 1
1
<?php
2
/*
3
 * The MIT License (MIT)
4
 *
5
 * Copyright (c) 2015 zepi
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 *
25
 */
26
27
/**
28
 * The DataSourceManager manages and delivers the available
29
 * data sources.
30
 * 
31
 * @package Zepi\Turbo\Manager
32
 * @author Matthias Zobrist <[email protected]>
33
 * @copyright Copyright (c) 2015 zepi
34
 */
35
36
namespace Zepi\Turbo\Manager;
37
38
use \Zepi\Turbo\Framework;
39
use \Zepi\Turbo\Exception;
40
use \Zepi\Turbo\Backend\ObjectBackendAbstract;
41
42
/**
43
 * The DataSourceManager manages and delivers the available
44
 * data sources.
45
 * 
46
 * @author Matthias Zobrist <[email protected]>
47
 * @copyright Copyright (c) 2015 zepi
48
 */
49
class DataSourceManager
50
{
51
    /**
52
     * @access protected
53
     * @var Framework
54
     */
55
    protected $framework;
56
    
57
    /**
58
     * @access protected
59
     * @var \Zepi\Turbo\Backend\ObjectBackendAbstract
60
     */
61
    protected $dataSourceObjectBackend;
62
    
63
    /**
64
     * @access protected
65
     * @var array
66
     */
67
    protected $dataSources = array();
68
    
69
    /**
70
     * @access protected
71
     * @var array
72
     */
73
    protected $definitions = array();
74
    
75
    /**
76
     * Constructs the object
77
     * 
78
     * @access public
79
     * @param \Zepi\Turbo\Framework $framework
80
     * @param \Zepi\Turbo\Backend\ObjectBackendAbstract $dataSourceObjectBackend
81
     */
82
    public function __construct(
83
        Framework $framework, 
84
        ObjectBackendAbstract $dataSourceObjectBackend
85
    ) {
86
        $this->framework = $framework;
87
        $this->dataSourceObjectBackend = $dataSourceObjectBackend;
88
    }
89
    
90
    /**
91
     * Initializes the data source manager. The function loads all saved
92
     * events from the object backend.
93
     *
94
     * @access public
95
     */
96
    public function initializeDataSourceManager()
97
    {
98
        $dataSources = $this->dataSourceObjectBackend->loadObject();
99
        if (!is_array($dataSources)) {
100
            $dataSources = array();
101
        }
102
    
103
        $this->dataSources = $dataSources;
104
    }
105
    
106
    /**
107
     * Adds a data source to the repository
108
     * 
109
     * @access public 
110
     * @param string $driver
111
     * @param string $className
112
     */
113
    public function addDataSource($driver, $className)
114
    {
115
        $typeClass = $this->getTypeClass($className);
116
117
        if (!isset($this->dataSources[$typeClass]) || !is_array($this->dataSources[$typeClass])) {
118
            $this->dataSources[$typeClass] = array();
119
        }
120
        
121
        $this->dataSources[$typeClass][$driver] = $className;
122
        $this->saveDataSources();
123
        
124
        return true;
125
    }
126
    
127
    /**
128
     * Removes a data source from the repository
129
     * 
130
     * @access public
131
     * @param string $driver
132
     * @param string $className
133
     * @return boolean
134
     */
135
    public function removeDataSource($driver, $className)
136
    {
137
        $typeClass = $this->getTypeClass($className);
138
        
139
        if (!isset($this->dataSources[$typeClass][$driver])) {
140
            return false;
141
        }
142
        
143
        unset($this->dataSources[$typeClass][$driver]);
144
        $this->saveDataSources();
145
        
146
        return true;
147
    }
148
    
149
    /**
150
     * Returns the DataSource type class for the given class
151
     * 
152
     * @access public
153
     * @param string $className
154
     * @return string
155
     * 
156
     * @throws \Zepi\Turbo\Exception Data Source "{className}" does not implement the DataSourceInterface.
157
     */
158
    protected function getTypeClass($className)
159
    {
160
        $implementedClasses = class_implements($className);
161
        $frameworkDataSourceInterface = 'Zepi\\Turbo\\FrameworkInterface\\DataSourceInterface';
162
163
        // If the class does not implement the DataSourceInterface we cannot use 
164
        // this class as DataSource
165
        if (!isset($implementedClasses[$frameworkDataSourceInterface])) {
166
            throw new Exception('Data Source "' . $className . '" does not implement the DataSourceInterface.');
167
        }
168
        
169
        // Remove the framework interface
170
        unset($implementedClasses[$frameworkDataSourceInterface]);
171
        
172
        return Framework::prepareClassName(current($implementedClasses));
173
    }
174
    
175
    /**
176
     * Saves the registred data sources in the object backend.
177
     *
178
     * @access protected
179
     */
180
    protected function saveDataSources()
181
    {
182
        $this->dataSourceObjectBackend->saveObject($this->dataSources);
183
    }
184
    
185
    /**
186
     * Adds a definition
187
     * 
188
     * @access public
189
     * @param string $selector
190
     * @param string $driver
191
     */
192
    public function addDefinition($selector, $driver)
193
    {
194
        $this->definitions[$selector] = $driver;
195
    }
196
    
197
    /**
198
     * Removes a definition
199
     * 
200
     * @access public
201
     * @param string $selector
202
     * @return boolean
203
     */
204
    public function removeDefinition($selector)
205
    {
206
        if (!isset($this->definitions[$selector])) {
207
            return false;
208
        }
209
        
210
        unset($this->definitions[$selector]);
211
        return true;
212
    }
213
    
214
    /**
215
     * Returns the data source for the given type class.
216
     * 
217
     * @access public
218
     * @param string $typeClass
219
     * @return mixed
220
     * 
221
     * @throws \Zepi\Turbo\Exception Cannot find a driver for the given type class.
222
     * @throws \Zepi\Turbo\Exception Cannot find a data source for the given type class.
223
     */
224
    public function getDataSource($typeClass)
225
    {
226
        $driver = $this->getDriver($typeClass);
227
        
228
        // If there is no driver for the given type class throw an exception
229
        if ($driver === false) {
230
            throw new Exception('Cannot find a driver for the given type class "' . $typeClass . '".');
231
        }
232
        
233
        $dataSourceClass = $this->searchDataSourceClass($typeClass, $driver);
234
235
        // If there is no data source class for the given type class throw an exception
236
        if ($dataSourceClass === false) {
237
            throw new Exception('Cannot find a data source for the given type class "' . $typeClass . '" (selected driver: "' . $driver . '").');
238
        }
239
        
240
        return $this->framework->getInstance($dataSourceClass);
241
    }
242
    
243
    /**
244
     * Returns an array with all DataSource type classes
245
     * 
246
     * @access public
247
     * @return array
248
     */
249
    public function getDataSourceTypeClasses()
250
    {
251
        return array_keys($this->dataSources);
252
    }
253
    
254
    /**
255
     * Returns the driver for the given type class or false if no 
256
     * driver is available.
257
     * 
258
     * @access protected
259
     * @param string $typeClass
260
     * @return false|string
261
     */
262
    protected function getDriver($typeClass)
263
    {
264
        $bestDriver = false;
265
        $numberOfParts = 0;
266
        
267
        foreach ($this->definitions as $selector => $driver) {
268
            if ($selector === '*' || $selector === $typeClass) {
269
                $bestDriver = $driver;
270
                $numberOfParts = $this->countNumberOfParts($selector);
271
            } else if (substr($selector, -1) === '*') {
272
                $selectorWithoutWildcard = substr($selector, 0, -1);
273
                
274
                if (strpos($selector, $selectorWithoutWildcard) === 0 || $numberOfParts < $this->countNumberOfParts($selector)) {
275
                    $bestDriver = $driver;
276
                    $numberOfParts = $this->countNumberOfParts($selector);
277
                }
278
            }
279
        }
280
        
281
        return $bestDriver;
282
    }
283
    
284
    /**
285
     * Returns the number of parts
286
     * 
287
     * @access protected
288
     * @param string $selector
289
     * @return integer
290
     */
291
    protected function countNumberOfParts($selector)
292
    {
293
        $selector = trim($selector, '*\\');
294
        
295
        if ($selector === '') {
296
            return 0;
297
        }
298
        
299
        return substr_count($selector, '\\');
300
    }
301
    
302
    /**
303
     * Returns the DataSource class for the given type class and driver
304
     * @param string $typeClass
305
     * @param string $driver
306
     * @return false|string
307
     */
308
    protected function searchDataSourceClass($typeClass, $driver)
309
    {
310
        if (isset($this->dataSources[$typeClass][$driver])) {
311
            return $this->dataSources[$typeClass][$driver];
312
        }
313
        
314
        return false;
315
    }
316
}
317