Completed
Push — master ( c0d55c...07d418 )
by Alfred
01:53
created

ConfigManager   F

Complexity

Total Complexity 78

Size/Duplication

Total Lines 315
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 188
dl 0
loc 315
rs 2.16
c 0
b 0
f 0
wmc 78

8 Methods

Rating   Name   Duplication   Size   Complexity  
B normalize() 0 23 10
C set() 0 53 17
C get() 0 26 14
B del() 0 44 11
B Save() 0 36 8
B parseConfiguration() 0 29 7
B configureOptions() 0 24 8
A __construct() 0 14 3

How to fix   Complexity   

Complex Class

Complex classes like ConfigManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ConfigManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Iriven;
3
use Exception;
4
/**
5
 * Created by PhpStorm.
6
 * User: IRIVEN FRANCE
7
 * Date: 21/11/2015
8
 * Time: 10:44
9
 */
10
class ConfigManager
11
{
12
    /**
13
    * Chemin complet du fichier de configuration
14
    */
15
    private $targetFile;
16
    private $Options = [];
17
    /**
18
    * tableau multidimensionnel contenant les donnée de configuration, initialement
19
    * chargées depuis le fichier
20
    */
21
    private $Config = [];
22
    /**
23
    * processeurs de fichier pris en charge par l'application
24
    */
25
    private $availableDrivers = array('JSON', 'PHP','INI','YML');
26
27
    private $defaultSection = 'runtime';
28
29
    /**
30
     * @param $filename
31
     * @param null $location
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $location is correct as it would always require null to be passed?
Loading history...
32
     * @throws \Exception
33
     */
34
    public function __construct( $filename, $location=null )
35
    {
36
        $numargs = func_num_args();
37
        try
38
        {
39
            if($numargs > 2)
40
                throw new Exception('SETUP ERROR: configuration manager can accept only up to 2 parameters,'.$numargs.' given!');
41
            $this->configureOptions($filename,$location);
42
            $this->parseConfiguration($this->Options);
43
            return $this;
44
        }
45
        catch(Exception $a)
46
        {
47
            die($a->getMessage());
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
48
        }
49
    }
50
 /**
51
     * @param null $section
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $section is correct as it would always require null to be passed?
Loading history...
52
     * @param null $item
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $item is correct as it would always require null to be passed?
Loading history...
53
     * @return array|bool|mixed
54
     */
55
    public function get($section=null, $item=null)
56
    {
57
        if($item) $item = trim(strtolower($item));
58
        if($section) $section = trim(strtolower($section));
59
        if(!count($this->Config)) return false;
60
        if(!$section or !strlen($section)) return $this->Config;
61
        if($section AND $item)
62
        {
63
            if(!isset($this->Config[$section]))
64
            {
65
                $key = $item;
66
                $item = $section;
67
                $section = $this->defaultSection;
68
                if(!isset($this->Config[$section][$item][$key]))
69
                    return false;
70
                return $this->Config[$section][$item][$key];
71
            }
72
        }
73
        elseif(!$item or !strlen($item))
74
        {
75
            $item = $section;
76
            if(isset($this->Config[$item])) return $this->Config[$item];
77
            $section = $this->defaultSection;
78
        }
79
        if(!isset($this->Config[$section][$item])) return false;
80
        return $this->Config[$section][$item];
81
    }
82
83
 /**
84
     * @param null $section
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $section is correct as it would always require null to be passed?
Loading history...
85
     * @param $item
86
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
87
     * @return bool
88
     */
89
    public function set($section,$item=null,$value=null)
90
    { 
91
        ob_start();
92
        $numarg = func_num_args();
93
        $arguments=func_get_args();
94
        switch($numarg)
95
        {
96
            case 1:
97
                if(!is_array($arguments[0])) return false;
98
                $item=array_change_key_case($arguments[0], CASE_LOWER); $section=null; $value=null;	
99
		break;
100
            case 2:
101
                if(is_array($arguments[0])) return false;
102
                $_arg = strtolower(trim($arguments[0]));
103
                if(is_array($arguments[1])){ $section=$_arg; $item =array_change_key_case($arguments[1], CASE_LOWER);$value=null;}
104
                else {$item = $_arg;$value=$arguments[1];$section=null;}
105
                break;
106
            default:
107
                break;
108
        }
109
        $section = $section? trim(strtolower($section)) : $this->defaultSection;
110
        if(!is_array($item))
111
        {
112
            if(!$value) return false;
113
            $item=trim(strtolower($item));
114
            if(!isset($this->Config[$section][$item]) or !is_array($this->Config[$section][$item])):
115
                $this->Config[$section][$item]=$value;
116
            else:
117
                if(!is_array($value)) $value = array($value);
118
                $this->Config[$section][$item] = array_merge($this->Config[$section][$item],$value);
119
            endif;
120
        }
121
        else
122
        {
123
            if($value) return false;
124
            $item = array_change_key_case($item, CASE_LOWER);
125
            $sectionsize = count($this->Config[$section]);
126
            $itemsize = count($item);
127
            if($sectionsize)
128
            {
129
                if($itemsize=='1')
130
                {
131
                    if(isset($this->Config[$section][key($item)]))
132
                        $this->Config[$section][key($item)] = array_merge($this->Config[$section][key($item)],$item[key($item)]);
133
                    else if(!is_numeric(key($item))) $this->Config[$section][key($item)]=$item[key($item)];
134
                }
135
                else $this->Config[$section] = array_merge($this->Config[$section],$item);
136
            }
137
            else $this->Config[$section] = $item;
138
        }
139
        $re = $this->Save();
140
        ob_end_clean();
141
        return $re;
142
    }
143
/**
144
     * @param $section
145
     * @param null $item
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $item is correct as it would always require null to be passed?
Loading history...
146
     * @return bool
147
     */
148
    public function del($section, $item=null)
149
    {
150
        $section = trim(strtolower($section));
151
        if($item and strlen($item))
152
        {
153
            $item = trim(strtolower($item));
154
            if(!isset($this->Config[$section]))
155
            {
156
                $key = $item;
157
                $item = $section;
158
                $section = $this->defaultSection;
159
                if(isset($this->Config[$section][$item][$key]))
160
                {
161
                    $itemSize=count($this->Config[$section][$item]);
162
                    if($itemSize>1) unset($this->Config[$section][$item][$key]);
163
                    else unset($this->Config[$section]);
164
                }
165
            }
166
            else
167
            {
168
                $sectionSize=count($this->Config[$section]);
169
                if(isset($this->Config[$section][$item]))
170
                {
171
                    if($sectionSize>1) unset($this->Config[$section][$item]);
172
                    else unset($this->Config[$section]);
173
                }
174
            } 
175
        }
176
        else
177
        {
178
            $item = $section;
179
            if(!isset($this->Config[$item]))
180
            {
181
                $section = $this->defaultSection;
182
                $defaultSectionSize = count($this->Config[$section]);
183
                if(isset($this->Config[$section][$item]))
184
                {
185
                    if($defaultSectionSize>1) unset($this->Config[$section][$item]);
186
                    else unset($this->Config[$section]);
187
                }
188
            }
189
            else unset($this->Config[$item]);
190
        }
191
        return $this->Save();
192
    }
193
    /**
194
     * @param $file
195
     * @param null $location
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $location is correct as it would always require null to be passed?
Loading history...
196
     * @return array|bool
197
     */
198
    private function configureOptions($file,$location=null){
199
        if(!is_string($file) or ($location and !is_string($location)))
200
            throw new Exception('SETUP ERROR: configuration manager can accept string only parameters');
201
        $default=[
202
            'driver' => 'PHP',
203
            'filename' => null,
204
            'directory' => __DIR__,
205
        ];
206
        $Options = [];
207
        if($location)
208
            $Options['directory']=rtrim($this->normalize($location),DIRECTORY_SEPARATOR);
209
        else{
210
            if(basename($file)!==$file)
211
                $Options['directory']= rtrim($this->normalize(pathinfo($file,PATHINFO_DIRNAME)),DIRECTORY_SEPARATOR);
212
        }
213
        $Options['filename'] = basename($file);
214
        if(strpos($Options['filename'],'.')!==false)
215
            $Options['driver'] = strtoupper(pathinfo($Options['filename'], PATHINFO_EXTENSION));
216
        else
217
            $Options['filename']= $Options['filename'].'.'.strtolower($default['driver']);
218
	     if(!in_array($Options['driver'],$this->$availableDrivers))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $availableDrivers seems to be never defined.
Loading history...
219
            throw new Exception('ERROR: driver "'.$Options['driver'].'" not supported');
220
	    $this->Options = array_merge($default,$Options);
221
        return $this->Options;
222
    }
223
    /**
224
     * @param $path
225
     * @param null $relativeTo
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $relativeTo is correct as it would always require null to be passed?
Loading history...
226
     * @return string
227
     */
228
    private function normalize($path, $relativeTo = null) {
229
        $path = rtrim(preg_replace('#[/\\\\]+#', DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR);
230
        $isAbsolute = stripos(PHP_OS, 'win')===0 ? preg_match('/^[A-Za-z]+:/', $path): !strncmp($path, DIRECTORY_SEPARATOR, 1);
231
        if (!$isAbsolute)
232
        {
233
            if (!$relativeTo) $relativeTo = getcwd();
234
            $path = $relativeTo.DIRECTORY_SEPARATOR.$path;
235
        }
236
        if (is_link($path) and ($parentPath = realpath(dirname($path))))
237
            return $parentPath.DIRECTORY_SEPARATOR.$path;
238
        if ($realpath = realpath($path))  return $realpath;
239
        $parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR));
240
        while (end($parts) !== false)
241
        {
242
            array_pop($parts);
243
            $attempt = stripos(PHP_OS, 'win')===0 ? implode(DIRECTORY_SEPARATOR, $parts): DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts);
244
            if ($realpaths = realpath($attempt))
245
            {
246
                $path = $realpaths.substr($path, strlen($attempt));
247
                break;
248
            }
249
        }
250
        return $path;
251
    }
252
	  /**
253
     * @param array $options
254
     * @return mixed
255
     */
256
    private function parseConfiguration($options=[])
257
    {
258
259
        try
260
        {  $this->targetFile = $this->normalize($options['directory'].DIRECTORY_SEPARATOR.$options['filename']);
261
            if(!file_exists($this->targetFile))
262
                file_put_contents($this->targetFile,'',LOCK_EX);
263
            switch($this->Options['driver'])
264
            {
265
                case 'JSON':
266
                    $this->Config = unserialize(json_decode(file_get_contents($this->targetFile), true));
267
                    break;
268
                case 'INI':
269
                    $this->Config = parse_ini_file($this->targetFile, true);
270
                    break;
271
                case 'YML':
272
                    $ndocs=0;
273
                    $this->Config = yaml_parse_file($this->targetFile,0,$ndocs);
274
                    break;
275
                default:
276
                    if(!$this->Config = include $this->targetFile) $this->Config = [];
277
                    break;
278
            }
279
        }
280
        catch(Exception $b)
281
        {
282
            die( $b->getMessage());
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
283
        }
284
        return $this->Config;
285
    }
286
/**
287
     * @return bool
288
     */
289
     private function Save()
290
    {
291
        if( !is_writeable( $this->targetFile ) ) @chmod($this->targetFile,0775);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

291
        if( !is_writeable( $this->targetFile ) ) /** @scrutinizer ignore-unhandled */ @chmod($this->targetFile,0775);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
292
        $content = null;
293
        switch($this->Options['driver'])
294
        {
295
            case 'JSON':
296
                $content .= json_encode(serialize($this->Config));
297
                break;
298
            case 'INI':
299
                $content .= '; @file generator: Iriven France Php "'.get_class($this).'" Class'.PHP_EOL;
300
                $content .= '; @Last Update: '.date('Y-m-d H:i:s').PHP_EOL;
301
                $content .= PHP_EOL;
302
                foreach($this->Config as $section => $array)
303
                {
304
                    is_array($array) or $array = array($array);
305
                    $content .= '[' . $section . ']'.PHP_EOL;
306
                    foreach( $array as $key => $value )
307
                        $content .= PHP_TAB.$key.' = '.$value.PHP_EOL;
0 ignored issues
show
Bug introduced by
The constant Iriven\PHP_TAB was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
308
                    $content .= PHP_EOL;
309
                }
310
                break;
311
            case 'YML':
312
                $content .= yaml_emit ($this->Config, YAML_UTF8_ENCODING , YAML_LN_BREAK );
313
                break;
314
            default:
315
                $content .= '<?php'.PHP_EOL;
316
                $content .= 'return ';
317
                $content .= var_export($this->Config, true) . ';';
318
                $content = preg_replace('/array\s+\(/', '[', $content);
319
                $content = preg_replace('/,(\s+)\)/', '$1]', $content);
320
                break;
321
        }
322
        file_put_contents($this->targetFile, $content, LOCK_EX);
323
        @chmod($this->targetFile,0644);
324
        return true;
325
    }
326
    /**
327
     * fin de la classe
328
     */
329
330
}
331