Core::perform()   F
last analyzed

Complexity

Conditions 23
Paths 454

Size

Total Lines 122
Code Lines 72

Duplication

Lines 6
Ratio 4.92 %

Importance

Changes 2
Bugs 2 Features 1
Metric Value
c 2
b 2
f 1
dl 6
loc 122
rs 3.2914
cc 23
eloc 72
nc 454
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Core
4
 *
5
 * Risolutoの中核部分に関するメソッドが含まれているクラス
6
 *
7
 * @package           risoluto
8
 * @author            Risoluto Developers
9
 * @license           http://opensource.org/licenses/bsd-license.php new BSD license
10
 * @copyright     (C) 2008-2015 Risoluto Developers / All Rights Reserved.
11
 */
12
13
//------------------------------------------------------//
14
// 名前空間の定義
15
//------------------------------------------------------//
16
namespace Risoluto;
17
18
class Core
19
{
20
    //------------------------------------------------------//
21
    // クラスメソッド定義
22
    //------------------------------------------------------//
23
    use RisolutoErrorLogTrait;
24
25
    /**
26
     * perform()
27
     *
28
     * 指定されたアプリケーションを呼び出す
29
     *
30
     * @access    public
31
     *
32
     * @param     void
33
     *
34
     * @return    void
35
     */
36
    public function perform()
37
    {
38
        //------------------------------------------------------//
39
        // アプリケーションクラスをロードし実行する
40
        //------------------------------------------------------//
41
        // クラスインスタンスを生成し、実行する
42
        try {
43
            // 呼び出すクラスを決定する
44
            $call = $this->findCallClass();
45
46
            // インスタンスの生成
47
            $targetInstance = new $call[ 'load' ];
48
49
            // イニシャライズメソッドをコール
50 View Code Duplication
            if (method_exists( $targetInstance, 'init' )) {
0 ignored issues
show
Duplication introduced by Yuta Hayakawa
This code seems to be duplicated across 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...
51
                $targetInstance->init( $call[ 'param' ] );
52
            } else {
53
                // メソッドが存在しなければ例外をThrow
54
                throw new \Exception( $this->coreError( 'error', 'notfound', 'Init()' ) );
55
            }
56
57
            // HTTPのメソッドに応じて適切なコントローラをコール
58
            switch ($_SERVER[ 'REQUEST_METHOD' ]) {
59
                // GETの場合
60
                case 'GET':
61
                    if (method_exists( $targetInstance, 'playGet' )) {
62
                        $targetInstance->playGet();
63
                    } else {
64
                        $this->playFuncCall( $targetInstance );
65
                    }
66
                    break;
67
68
                // POSTの場合
69
                case 'POST':
70
                    if (method_exists( $targetInstance, 'playPost' )) {
71
                        $targetInstance->playPost();
72
                    } else {
73
                        $this->playFuncCall( $targetInstance );
74
                    }
75
                    break;
76
77
                // PUTの場合
78
                case 'PUT':
79
                    if (method_exists( $targetInstance, 'playPut' )) {
80
                        $targetInstance->playPut();
81
                    } else {
82
                        $this->playFuncCall( $targetInstance );
83
                    }
84
                    break;
85
86
                // DELETEの場合
87
                case 'DELETE':
88
                    if (method_exists( $targetInstance, 'playDelete' )) {
89
                        $targetInstance->playDelete();
90
                    } else {
91
                        $this->playFuncCall( $targetInstance );
92
                    }
93
                    break;
94
95
                // OPTIONの場合
96
                case 'OPTION':
97
                    if (method_exists( $targetInstance, 'playOption' )) {
98
                        $targetInstance->playOption();
99
                    } else {
100
                        $this->playFuncCall( $targetInstance );
101
                    }
102
                    break;
103
104
                // HEADの場合
105
                case 'HEAD':
106
                    if (method_exists( $targetInstance, 'playHead' )) {
107
                        $targetInstance->playHead();
108
                    } else {
109
                        $this->playFuncCall( $targetInstance );
110
                    }
111
                    break;
112
113
                // TRACEの場合
114
                case 'TRACE':
115
                    if (method_exists( $targetInstance, 'playTrace' )) {
116
                        $targetInstance->playTrace();
117
                    } else {
118
                        $this->playFuncCall( $targetInstance );
119
                    }
120
                    break;
121
122
                // CONNECTの場合
123
                case 'CONNECT':
124
                    if (method_exists( $targetInstance, 'playConnect' )) {
125
                        $targetInstance->playConnect();
126
                    } else {
127
                        $this->playFuncCall( $targetInstance );
128
                    }
129
                    break;
130
131
                // デフォルトの場合
132
                default:
133
                    $this->playFuncCall( $targetInstance );
134
                    break;
135
            }
136
        } catch ( \Exception $e ) {
137
            // エラーハンドリングメソッドをコール
138
            if (!empty( $targetInstance )) {
139
                if (method_exists( $targetInstance, 'error' )) {
140
                    $targetInstance->error( $e );
141
                } else {
142
                    // メソッドが存在しなければ強制終了
143
                    die( $this->coreError( 'error', 'notfound', 'Error()' ) );
144
                }
145
            }
146
        } finally {
147
            // クリーニングメソッドをコール
148
            if (!empty( $targetInstance )) {
149
                if (method_exists( $targetInstance, 'clean' )) {
150
                    $targetInstance->clean();
151
                } else {
152
                    // メソッドが存在しなければ強制終了
153
                    die( $this->coreError( 'error', 'notfound', 'Clean()' ) );
154
                }
155
            }
156
        }
157
    }
158
159
    /**
160
     * playFuncCall($targetInstance)
161
     *
162
     * play()メソッドをコールする(存在しない場合は例外をThrow)
163
     *
164
     * @access private
165
     *
166
     * @param object $targetInstance クラスインスタンス
167
     *
168
     * @return void
169
     *
170
     * @throws \Exception
171
     */
172
    private function playFuncCall( $targetInstance )
173
    {
174 View Code Duplication
        if (method_exists( $targetInstance, 'play' )) {
0 ignored issues
show
Duplication introduced by Yuta Hayakawa
This code seems to be duplicated across 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...
175
            $targetInstance->play();
176
        } else {
177
            // メソッドが存在しなければ例外をThrow
178
            throw new \Exception( $this->coreError( 'error', 'notfound', 'play*()' ) );
179
        }
180
    }
181
182
    /**
183
     * fixSeqParam($value = '')
184
     *
185
     * $_GET['seq']の値から不適切な文字を排除する
186
     *
187
     * @access    private
188
     *
189
     * @param     String $value $_GET['seq']の値
190
     *
191
     * @return    String 適切な状態に加工した$_GET['seq']
192
     */
193
    private function fixSeqParam( $value = '' )
194
    {
195
        // 検出対象のリスト
196
        $searches = [ '/\.+/', '/_+/', '/\//', '/\¥/', '/\\\\/', '/[[:blank:]]/', '/[[:cntrl:]]/' ];
197
198
        // 対応する置換文字のリスト
199
        $replacement = [ '.', '_', '', '', '', '', '' ];
200
201
        // 不正な値を除去
202
        $retval = preg_replace( $searches, $replacement, $value );
203
204
        return $retval;
205
    }
206
207
    /**
208
     * isDisabled($dirpath, $target)
209
     *
210
     * 無効指定されているかを判定する
211
     *
212
     * @access    private
213
     *
214
     * @param     String $dirpath 無効指定ファイルの存在チェックを行うパス
215
     * @param     String $target 無効指定チェック対象となるクラス(RisolutoApps\からのフル指定)
216
     *
217
     * @return    Boolean true:無効指定されている/false:無効指定されていない
218
     */
219
    private function isDisabled( $dirpath, $target )
220
    {
221
        // 変数の初期化
222
        $retval = false;
223
        $ignorefile = $dirpath . '/RisolutoIgnore';
224
225
        // 無効指定ファイルが存在するかをチェック
226
        clearstatcache( true );
227
        if (file_exists( $ignorefile ) and is_file( $ignorefile ) and is_readable( $ignorefile )) {
228
            // ファイルの内容を読み込む
229
            $ignorelist = file( $ignorefile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
230
231
            // 無効指定されているかを判定(空の場合は全指定されているとみなす)
232
            if (empty( $ignorelist ) or in_array( $target, $ignorelist )) {
233
                $retval = true;
234
            }
235
        }
236
237
        return $retval;
238
    }
239
240
    /**
241
     * findCallClass()
242
     *
243
     * 呼び出すクラスを決定する
244
     *
245
     * @access    private
246
     *
247
     * @param     void
248
     *
249
     * @return    array   呼び出すクラスの情報等
250
     */
251
    private function findCallClass()
252
    {
253
        // コンフィグファイルの読み込み
254
        $conf = new Conf;
255
        $conf->parse( RISOLUTO_CONF . 'risoluto.ini' );
256
257
        // デフォルトの情報をセット
258
        $load = $conf->getIni( 'SEQ', 'default' );
259
        $param = [ ];
260
261
        // $_GET['seq']の値をチェックする
262
        $seq = $this->fixSeqParam( ( isset( $_GET[ 'seq' ] ) ) ? $_GET[ 'seq' ] : '' );
263
264
        // GETパラメタ中の情報(「seq」)が指定されていればそれを採用
265
        if (isset( $seq ) and !empty( $seq )) {
266
            // 「.」が付いていたらそこで分割
267
            if (strpos( '.', $seq ) === false) {
268
                $sep = explode( '.', $seq );
269
270
                // 分割後、1つめの要素は画面指定とみなし、2つめ以降の要素はパラメタと見なす
271
                $load = 'RisolutoApps\\' . $sep[ 0 ];
272
273
                unset( $sep[ 0 ] );
274
                foreach ($sep as $dat) {
275
                    $param[ ] = $dat;
276
                }
277
                // 「.」が付いていなければそのまま採用する
278
            } else {
279
                $load = 'RisolutoApps\\' . $seq;
280
                $param = [ ];
281
            }
282
283
            // $load中の「_」を「\」に置換
284
            $load = str_replace( '_', '\\', $load );
285
286
            // 指定されたアプリケーションが存在していないか無効指定されていたらエラーとする
287
            $target = RISOLUTO_APPS . str_replace( '\\', DIRECTORY_SEPARATOR, $load ) . '.php';
288
            clearstatcache( true );
289
            if (!file_exists( $target ) or !is_file( $target ) or !is_readable( $target ) or $this->isDisabled( dirname( $target ),
290
                    $load )
291
            ) {
292
                // ログにも記録しておく
293
                $this->coreError( 'warn', 'classnotfound', $load . ' (Path: ' . $target . ' ) / Go to Error page.' );
294
295
                $load = $conf->getIni( 'SEQ', 'error' );
296
                $param = [ ];
297
            }
298
        }
299
300
        // サービスストップファイルが存在するかロードアベレージが一定値以上ならサービスストップ
301
        $loadavg = sys_getloadavg();
302
        $max_loadavg = $conf->getIni( 'LIMITS', 'max_loadavg' );
303
        clearstatcache( true );
304
        if (file_exists( RISOLUTO_SYSROOT . 'ServiceStop' ) or ( !empty( $max_loadavg ) and $loadavg[ 0 ] > $max_loadavg )) {
305
            // ログにも記録しておく
306
            $this->coreError( 'warn', 'servicestop',
307
                'Current Loadavg: ' . $loadavg[ 0 ] . ' / Setting: ' . $max_loadavg );
308
309
            $load = $conf->getIni( 'SEQ', 'servicestop' );
310
            $param = [ ];
311
        }
312
313
        // 決定した情報を返却する
314
        $retval = [
315
            'load' => $load,
316
            'param' => $param
317
        ];
318
319
        return $retval;
320
    }
321
322
    /**
323
     * coreError($error_level = 'error', $key = '', $optional_text = 'unknown')
324
     *
325
     * クラス内で発生したエラーに対するエラーメッセージを生成する
326
     *
327
     * @access    private
328
     *
329
     * @param     string $error_level エラーレベル
330
     * @param     string $key エラーを示すキー文字列
331
     * @param     string $optional_text オプションの文字列
332
     *
333
     * @return    string    エラーメッセージ
334
     */
335
    private function coreError( $error_level = 'error', $key = '', $optional_text = 'unknown' )
336
    {
337
        // 引数の値に応じてエラーメッセージをセットする
338
        switch ($key) {
339
            // 未定義エラーの場合
340
            case 'notfound':
341
                $msg = 'Required method is not exists - ' . $optional_text;
342
                break;
343
344
            // URLで指定されたアプリケーションが存在しないか無効指定されている場合
345
            case 'classnotfound':
346
                $msg = 'Class not found or disabled - ' . $optional_text;
347
                break;
348
349
            // サービスストップが発生した場合
350
            case 'servicestop':
351
                $msg = 'Auto Service Stop - ' . $optional_text;
352
                break;
353
354
355
            // 未定義のエラーの場合
356
            default:
357
                $msg = 'Unknown Error occurred';
358
                break;
359
        }
360
361
        // ログ出力しエラーメッセージを返却
362
        $this->risolutoErrorLog( $error_level, '[' . __CLASS__ . '/]' . $msg );
363
364
        return $msg;
365
    }
366
}
367