Completed
Push — feature/0.7.0 ( 38440f...02d6a4 )
by Ryuichi
07:28
created

LoggerConfigurationManager   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 230
Duplicated Lines 11.3 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 26
loc 230
rs 8.2608
c 0
b 0
f 0
wmc 40
lcom 1
cbo 4

11 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 26 4
A load() 0 9 1
A getConfig() 0 4 1
A loadLogLevel() 0 11 2
A loadLogFilePath() 0 14 3
A loadRotateCycle() 0 8 2
A loadRotateSize() 0 13 3
A loadApplicationName() 0 8 3
A loadFormat() 0 10 2
C cycle2value() 0 25 8
C toLogLevelValue() 26 26 11

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like LoggerConfigurationManager 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 LoggerConfigurationManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace WebStream\Log;
3
4
use WebStream\IO\File;
5
use WebStream\IO\Writer\SimpleFileWriter;
6
use WebStream\Container\Container;
7
use WebStream\Exception\Extend\LoggerException;
8
9
/**
10
 * LoggerConfigurationManager
11
 * @author Ryuichi Tanaka
12
 * @since 2016/01/29
13
 * @version 0.7
14
 */
15
class LoggerConfigurationManager
16
{
17
    /**
18
     * @var Container ログ設定コンテナ
19
     */
20
    private $logContainer;
21
22
    /**
23
     * @var Container IOコンテナ
24
     */
25
    private $ioContainer;
26
27
    /**
28
     * @var array<string> ログ設定情報
29
     */
30
    private $configMap;
31
32
    /**
33
     * Constructor
34
     * @param mixed $config ログ設定
35
     * @throws LoggerException
36
     */
37
    public function __construct($config)
38
    {
39
        if (is_array($config)) {
40
            $configMap = $config;
41
        } else {
42
            $configMap = parse_ini_file($config);
43
            if ($configMap === null) {
44
                throw new LoggerException("Log config file does not exist: " . $config);
45
            }
46
        }
47
48
        $this->logContainer = new Container(false);
49
        $this->ioContainer = new Container();
50
51
        $this->ioContainer->file = function () use ($configMap) {
0 ignored issues
show
Documentation introduced by
The property file does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
52
            if (!array_key_exists("path", $configMap)) {
53
                throw new LoggerException("Log path must be defined.");
54
            }
55
            return new File($configMap["path"]);
56
        };
57
        $this->ioContainer->fileWriter = function () use ($configMap) {
0 ignored issues
show
Documentation introduced by
The property fileWriter does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
58
            return new SimpleFileWriter($configMap["path"]);
59
        };
60
61
        $this->configMap = $configMap;
62
    }
63
64
    /**
65
     * 設定を読み込む
66
     * @throws LoggerException
67
     */
68
    public function load()
69
    {
70
        $this->loadLogLevel()
71
             ->loadLogFilePath()
72
             ->loadRotateCycle()
73
             ->loadRotateSize()
74
             ->loadApplicationName()
75
             ->loadFormat();
76
    }
77
78
    /**
79
     * ログ設定を返却する
80
     * @return Container ログ設定
81
     */
82
    public function getConfig()
83
    {
84
        return $this->logContainer;
85
    }
86
87
    /**
88
     * ログレベルを読み込む
89
     * @throws LoggerException
90
     */
91
    private function loadLogLevel()
92
    {
93
        if (!array_key_exists("level", $this->configMap)) {
94
            throw new LoggerException("Log level must be defined.");
95
        }
96
97
        $logLevel = $this->toLogLevelValue($this->configMap["level"]);
98
        $this->logContainer->logLevel = $logLevel;
0 ignored issues
show
Documentation introduced by
The property logLevel does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
99
100
        return $this;
101
    }
102
103
    /**
104
     * ログ保存先パスを読み込む
105
     * @throws LoggerException
106
     */
107
    private function loadLogFilePath()
108
    {
109
        $file = $this->ioContainer->file;
0 ignored issues
show
Documentation introduced by
The property file does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
110
        if (!($file->exists() && $file->isFile())) {
111
            $this->ioContainer->fileWriter->write("");
0 ignored issues
show
Documentation introduced by
The property fileWriter does not exist on object<WebStream\Container\Container>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
112
        }
113
114
        $this->logContainer->logPath = $file->getFilePath();
0 ignored issues
show
Documentation introduced by
The property logPath does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
115
        $this->logContainer->statusPath = preg_replace_callback('/(.*)\..+/', function ($matches) {
0 ignored issues
show
Documentation introduced by
The property statusPath does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
116
            return "$matches[1].status";
117
        }, $this->logContainer->logPath);
0 ignored issues
show
Documentation introduced by
The property logPath does not exist on object<WebStream\Container\Container>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
118
119
        return $this;
120
    }
121
122
    /**
123
     * ログローテートサイクルを読み込む
124
     * @throws LoggerException
125
     */
126
    private function loadRotateCycle()
127
    {
128
        if (array_key_exists("rotate_cycle", $this->configMap)) {
129
            $this->logContainer->rotateCycle = $this->cycle2value($this->configMap["rotate_cycle"]);
0 ignored issues
show
Documentation introduced by
The property rotateCycle does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
130
        }
131
132
        return $this;
133
    }
134
135
    /**
136
     * ログローテートサイズを読み込む
137
     * @throws LoggerException
138
     */
139
    private function loadRotateSize()
140
    {
141
        if (array_key_exists("rotate_size", $this->configMap)) {
142
            $rotateSize = intval($this->configMap["rotate_size"]);
143
            // ローテートサイズが不正の場合(正の整数以外の値が設定された場合)
144
            if ($rotateSize <= 0) {
145
                throw new LoggerException("Invalid log rotate size: " . $this->configMap["rotate_size"]);
146
            }
147
            $this->logContainer->rotateSize = $rotateSize;
0 ignored issues
show
Documentation introduced by
The property rotateSize does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
148
        }
149
150
        return $this;
151
    }
152
153
    /**
154
     * アプリケーション名を読み込む
155
     */
156
    private function loadApplicationName()
157
    {
158
        if (array_key_exists("application_name", $this->configMap) && !empty($this->configMap["application_name"])) {
159
            $this->logContainer->applicationName = $this->configMap["application_name"];
0 ignored issues
show
Documentation introduced by
The property applicationName does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
160
        }
161
162
        return $this;
163
    }
164
165
    /**
166
     * ロガーフォーマットを読み込む
167
     */
168
    private function loadFormat()
169
    {
170
        if (array_key_exists("format", $this->configMap)) {
171
            $this->logContainer->format = $this->configMap["format"];
0 ignored issues
show
Documentation introduced by
The property format does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
172
        } else {
173
            $this->logContainer->format = $this->defaultLoggerFormatter();
0 ignored issues
show
Documentation introduced by
The property format does not exist on object<WebStream\Container\Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
The method defaultLoggerFormatter() does not seem to exist on object<WebStream\Log\LoggerConfigurationManager>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
174
        }
175
176
        return $this;
177
    }
178
179
    /**
180
     * ログローテートサイクルを時間に変換
181
     * @param string ローテートサイクル
182
     * @return int ローテート時間
183
     * @throws LoggerException
184
     */
185
    private function cycle2value($cycle)
186
    {
187
        $day_to_h = 24;
188
        $week_to_h = $day_to_h * 7;
189
        $month_to_h = $day_to_h * intval(date("t", time()));
190
        $year_to_h = $day_to_h * 365;
191
192
        $year = date("Y");
193
        if (($year % 4 === 0 && $year % 100 !== 0) || $year % 400 === 0) {
194
            $year_to_h = $day_to_h * 366;
195
        }
196
197
        switch (strtolower($cycle)) {
198
            case 'day':
199
                return $day_to_h;
200
            case 'week':
201
                return $week_to_h;
202
            case 'month':
203
                return $month_to_h;
204
            case 'year':
205
                return $year_to_h;
206
            default:
207
                throw new LoggerException("Invalid log rotate cycle: " . $cycle);
208
        }
209
    }
210
211
    /**
212
     * ログレベルを数値に変換
213
     * ログレベルはWebStream独自、PSR-3両方対応
214
     * @param string ログレベル文字列
215
     * @throws LoggerException
216
     * @return int ログレベル数値
217
     */
218 View Code Duplication
    private function toLogLevelValue(string $level)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
219
    {
220
        switch (strtolower($level)) {
221
            case 'debug':
222
                return 1;
223
            case 'info':
224
                return 2;
225
            case 'notice':    // PSR-3
226
                return 3;
227
            case 'warn':
228
            case 'warning':   // PSR-3
229
                return 4;
230
            case 'error':
231
                return 5;
232
            case 'critical':  // PSR-3
233
                return 6;
234
            case 'alert':     // PSR-3
235
                return 7;
236
            case 'emergency': // PSR-3
237
                return 8;
238
            case 'fatal':
239
                return 9;
240
            default:
241
                throw new LoggerException("Undefined log level: $level");
242
        }
243
    }
244
}
245