Completed
Push — master ( f69f19...cf538a )
by Daniel
03:03
created

MySQLParser::parseFile()   D

Complexity

Conditions 13
Paths 17

Size

Total Lines 100
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 100
rs 4.9923
cc 13
eloc 48
nc 17
nop 3

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
 * This file is part of MySQLParser with Delimiter Support.
4
 *
5
 * File: MysqlParser.php
6
 *
7
 * User: dherrman
8
 * Date: 23.11.15
9
 * Time: 10:39
10
 */
11
12
namespace wazaari\MySQLParser;
13
14
class MySQLParser
15
{
16
17
    /**
18
     * @var string Delimiter command used by the SQL flavor to indicate delimiter change
19
     */
20
    private $delimiterString = "DELIMITER";
21
22
    /**
23
     * This function parses the given SQL file and returns an array including the commands and the delimiter.
24
     * For each command, both the command itself and the delimiter is returned.
25
     * Refer to the test cases for a detailled explanation
26
     *
27
     * @param $file
28
     * @param string $defaultDelimiter
29
     * @param boolean $appendDelimiterCommand Controls whether the Delimiter command itself should be returned
30
     * @return array
31
     * @throws \Exception
32
     */
33
    public function parseFile($file, $defaultDelimiter = ";", $appendDelimiterCommand = false)
34
    {
35
        $currentDelimiter = $defaultDelimiter;
36
37
        //Try to open File
38
        if (!file_exists($file)) {
39
            throw new \Exception('Unable to open file \'' . $file .'\': File not found');
40
        }
41
        try {
42
            $handle = fopen($file, "r");
43
        } catch (\Exception $e) {
44
            throw new \Exception('Unable to open file \'' . $file .'\': File was found but unknown error occured.');
45
        }
46
47
        //Initialize result array
48
        $_lineArray = array();
49
50
        //Initialize multi-line cache
51
        $multiLineCommand = null;
52
53
        //Read file by line and watch out for DELIMITER clauses
54
        while (($line = fgets($handle)) !== false) {
55
            //Remove unneccessary whitespaces
56
            $line = trim($line);
57
58
            //if line starts with "--", it is a comment. Ignore
59
            if ($this->startsWith($line, "--")) {
60
                continue;
61
            }
62
63
            //Check if line starts with DELIMITER and extract it
64
            if ($this->startsWith($line, $this->delimiterString)) {
65
                $currentDelimiter = trim(substr($line, strlen($this->delimiterString)));
66
                if ($appendDelimiterCommand === true) {
67
                    $_lineArray[] = array(
68
                        'command' => $this->delimiterString . ' ' . $currentDelimiter,
69
                        'delimiter' => null,
70
                    );
71
                }
72
                continue;
73
            }
74
75
            //Otherwise, this is a normal line
76
            //Extract commands and save them to array
77
            $instructions = array_map(
78
                'trim',
79
                array_filter(preg_split('~\\\\.(*SKIP)(*FAIL)|'.$currentDelimiter.'~s', $line))
80
            );
81
82
            //When there is no instruction (empty line) --> continue with next
83
            if (count($instructions) == 0) {
84
                continue;
85
            }
86
87
            /**
88
             * If the current multi-line cache is not null, all commands up to the next delimiter
89
             * belong to this command
90
             */
91
            if ($multiLineCommand !== null) {
92
                $firstCommand = array_shift($instructions);
93
                // If this is the only instruction here and there is no Delimiter
94
                // append to current file cache and continue. Else write to array and continue with next line
95
                // Otherwise write to array and proceed with this line
96
                if (count($instructions) == 0) {
97
                    if (substr($line, -strlen($currentDelimiter)) == $currentDelimiter) {
98
                        $_lineArray[] = array(
99
                            'command' => $multiLineCommand . ' ' . $firstCommand,
100
                            'delimiter' => $currentDelimiter
101
                        );
102
                        $multiLineCommand = null;
103
                        continue;
104
                    } else {
105
                        $multiLineCommand .= ' ' . $firstCommand;
106
                        continue;
107
                    }
108
                } else {
109
                    $multiLineCommand .= ' ' . $firstCommand;
110
                }
111
            }
112
113
            /**
114
             * If line does not end with delimiter, the last element of the array belongs
115
             * to a multi-line command
116
             */
117
            if (substr($line, -strlen($currentDelimiter)) != $currentDelimiter) {
118
                $multiLineCommand = array_pop($instructions);
119
            }
120
121
            //Proceed with all other instructions as usual
122
            foreach ($instructions as $i) {
123
                $_lineArray[] = array(
124
                    'command' => $i,
125
                    'delimiter' => $currentDelimiter
126
                );
127
            }
128
        }
129
130
        fclose($handle);
131
        return $_lineArray;
132
    }
133
134
    /**
135
     * Calculates whether the string $haystack starts with $needle
136
     *
137
     * @see http://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php
138
     * @param $haystack The string to search in
139
     * @param $needle The string to be searched
140
     * @return bool
141
     */
142
    private function startsWith($haystack, $needle)
143
    {
144
        return strncasecmp($haystack, $needle, strlen($needle)) === 0;
145
    }
146
}
147