Passed
Pull Request — master (#81)
by Dante
12:23
created

File::parseFile()   C

Complexity

Conditions 12
Paths 40

Size

Total Lines 83
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 51
c 1
b 0
f 0
nc 40
nop 3
dl 0
loc 83
rs 6.9666

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
declare(strict_types=1);
3
4
/**
5
 * BEdita, API-first content management framework
6
 * Copyright 2023 Atlas Srl, Chialab Srl
7
 *
8
 * This file is part of BEdita: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published
10
 * by the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
14
 */
15
16
namespace BEdita\I18n\Filesystem;
17
18
use function PHPUnit\Framework\directoryExists;
19
20
class File
21
{
22
    /**
23
     * Parse a directory
24
     *
25
     * @param string $dir The directory
26
     * @param string $defaultDomain The default domain
27
     * @param array $translations The translations array
28
     * @return bool
29
     */
30
    public static function parseDir(string $dir, string $defaultDomain, array &$translations): bool
31
    {
32
        $result = true;
33
        if (!file_exists($dir)) {
34
            return false;
35
        }
36
        $scan = scandir($dir);
37
        if ($scan === false) {
38
            return false;
39
        }
40
        $scan = array_diff($scan, ['.', '..']);
41
        foreach ($scan as $subdir) {
42
            if (is_dir($dir . DS . $subdir)) {
43
                $result = $result && self::parseDir($dir . DS . $subdir, $defaultDomain, $translations);
44
            }
45
        }
46
        $files = preg_grep('~\.(php|ctp|thtml|inc|tpl|twig)$~', $scan);
47
        foreach ($files as $file) {
48
            $result = $result && self::parseFile($dir . DS . $file, $defaultDomain, $translations);
49
        }
50
51
        return $result;
52
    }
53
54
    /**
55
     * Parse file and rips gettext strings
56
     *
57
     * @param string $file The file name
58
     * @param string $defaultDomain The default domain
59
     * @param array $translations The translations array
60
     * @return bool
61
     */
62
    public static function parseFile(string $file, string $defaultDomain, array &$translations): bool
63
    {
64
        if (!file_exists($file)) {
65
            return false;
66
        }
67
        $content = file_get_contents($file);
68
        if (empty($content)) {
69
            return false;
70
        }
71
72
        $functions = [
73
            '__' => 0, // __( string $singular , ... $args )
74
            '__n' => 0, // __n( string $singular , string $plural , integer $count , ... $args )
75
            '__d' => 1, // __d( string $domain , string $msg , ... $args )
76
            '__dn' => 1, // __dn( string $domain , string $singular , string $plural , integer $count , ... $args )
77
            '__x' => 1, // __x( string $context , string $singular , ... $args )
78
            '__xn' => 1, // __xn( string $context , string $singular , string $plural , integer $count , ... $args )
79
            '__dx' => 2, // __dx( string $domain , string $context , string $msg , ... $args )
80
            '__dxn' => 2, // __dxn( string $domain , string $context , string $singular , string $plural , integer $count , ... $args )
81
        ];
82
83
        // temporarily replace "\'" with "|||||", fixString will replace "|||||" with "\'"
84
        // this fixes wrongly matched data in the following regexp
85
        $content = str_replace("\'", '|||||', $content);
86
87
        $options = [
88
            'open_parenthesis' => preg_quote('('),
89
            'quote' => preg_quote("'"),
90
            'double_quote' => preg_quote('"'),
91
        ];
92
93
        foreach ($functions as $fname => $singularPosition) {
94
            $capturePath = "'[^']*'";
95
            $doubleQuoteCapture = str_replace("'", $options['double_quote'], $capturePath);
96
            $quoteCapture = str_replace("'", $options['quote'], $capturePath);
97
98
            // phpcs:disable
99
            $rgxp = '/' . $fname . '\s*' . $options['open_parenthesis'] . str_repeat('((?:' . $doubleQuoteCapture . ')|(?:' . $quoteCapture . '))\s*[,)]\s*', $singularPosition + 1) . '/';
100
            // phpcs:enable
101
102
            $matches = [];
103
            preg_match_all($rgxp, $content, $matches);
104
105
            $limit = count($matches[0]);
106
            for ($i = 0; $i < $limit; $i++) {
107
                $domain = $defaultDomain;
108
                $ctx = '';
109
                $str = self::unquoteString($matches[1][$i]);
110
111
                if (strpos($fname, '__d') === 0) {
112
                    $domain = self::unquoteString($matches[1][$i]);
113
114
                    if (strpos($fname, '__dx') === 0) {
115
                        $ctx = self::unquoteString($matches[2][$i]);
116
                        $str = self::unquoteString($matches[3][$i]);
117
                    } else {
118
                        $str = self::unquoteString($matches[2][$i]);
119
                    }
120
                } elseif (strpos($fname, '__x') === 0) {
121
                    $ctx = self::unquoteString($matches[1][$i]);
122
                    $str = self::unquoteString($matches[2][$i]);
123
                }
124
125
                $str = self::fixString($str);
126
                if (empty($str)) {
127
                    continue;
128
                }
129
130
                if (!array_key_exists($domain, $translations)) {
131
                    $translations[$domain] = [];
132
                }
133
134
                if (!array_key_exists($str, $translations[$domain])) {
135
                    $translations[$domain][$str] = [''];
136
                }
137
138
                if (!in_array($ctx, $translations[$domain][$str])) {
139
                    $translations[$domain][$str][] = $ctx;
140
                }
141
            }
142
        }
143
144
        return true;
145
    }
146
147
    /**
148
     * Remove leading and trailing quotes from string
149
     *
150
     * @param string $str The string
151
     * @return string The new string
152
     */
153
    public static function unquoteString($str): string
154
    {
155
        return substr($str, 1, -1);
156
    }
157
158
    /**
159
     * "fix" string - strip slashes, escape and convert new lines to \n
160
     *
161
     * @param string $str The string
162
     * @return string The new string
163
     */
164
    public static function fixString($str): string
165
    {
166
        $str = stripslashes($str);
167
        $str = str_replace('"', '\"', $str);
168
        $str = str_replace("\n", '\n', $str);
169
        $str = str_replace('|||||', "'", $str); // special sequence used in parseContent to temporarily replace "\'"
170
171
        return $str;
172
    }
173
}
174