Passed
Pull Request — master (#81)
by Dante
01:06
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
class File
19
{
20
    /**
21
     * Parse a directory
22
     *
23
     * @param string $dir The directory
24
     * @param string $defaultDomain The default domain
25
     * @param array $translations The translations array
26
     * @return bool
27
     */
28
    public static function parseDir(string $dir, string $defaultDomain, array &$translations): bool
29
    {
30
        $result = true;
31
        if (!file_exists($dir)) {
32
            return false;
33
        }
34
        $scan = scandir($dir);
35
        if ($scan === false) {
36
            return false;
37
        }
38
        $scan = array_diff($scan, ['.', '..']);
39
        foreach ($scan as $subdir) {
40
            if (is_dir($dir . DS . $subdir)) {
41
                $result = $result && self::parseDir($dir . DS . $subdir, $defaultDomain, $translations);
42
            }
43
        }
44
        $files = preg_grep('~\.(php|ctp|thtml|inc|tpl|twig)$~', $scan);
45
        foreach ($files as $file) {
46
            $result = $result && self::parseFile($dir . DS . $file, $defaultDomain, $translations);
47
        }
48
49
        return $result;
50
    }
51
52
    /**
53
     * Parse file and rips gettext strings
54
     *
55
     * @param string $file The file name
56
     * @param string $defaultDomain The default domain
57
     * @param array $translations The translations array
58
     * @return bool
59
     */
60
    public static function parseFile(string $file, string $defaultDomain, array &$translations): bool
61
    {
62
        if (!file_exists($file)) {
63
            return false;
64
        }
65
        $content = file_get_contents($file);
66
        if (empty($content)) {
67
            return false;
68
        }
69
70
        $functions = [
71
            '__' => 0, // __( string $singular , ... $args )
72
            '__n' => 0, // __n( string $singular , string $plural , integer $count , ... $args )
73
            '__d' => 1, // __d( string $domain , string $msg , ... $args )
74
            '__dn' => 1, // __dn( string $domain , string $singular , string $plural , integer $count , ... $args )
75
            '__x' => 1, // __x( string $context , string $singular , ... $args )
76
            '__xn' => 1, // __xn( string $context , string $singular , string $plural , integer $count , ... $args )
77
            '__dx' => 2, // __dx( string $domain , string $context , string $msg , ... $args )
78
            '__dxn' => 2, // __dxn( string $domain , string $context , string $singular , string $plural , integer $count , ... $args )
79
        ];
80
81
        // temporarily replace "\'" with "|||||", fixString will replace "|||||" with "\'"
82
        // this fixes wrongly matched data in the following regexp
83
        $content = str_replace("\'", '|||||', $content);
84
85
        $options = [
86
            'open_parenthesis' => preg_quote('('),
87
            'quote' => preg_quote("'"),
88
            'double_quote' => preg_quote('"'),
89
        ];
90
91
        foreach ($functions as $fname => $singularPosition) {
92
            $capturePath = "'[^']*'";
93
            $doubleQuoteCapture = str_replace("'", $options['double_quote'], $capturePath);
94
            $quoteCapture = str_replace("'", $options['quote'], $capturePath);
95
96
            // phpcs:disable
97
            $rgxp = '/' . $fname . '\s*' . $options['open_parenthesis'] . str_repeat('((?:' . $doubleQuoteCapture . ')|(?:' . $quoteCapture . '))\s*[,)]\s*', $singularPosition + 1) . '/';
98
            // phpcs:enable
99
100
            $matches = [];
101
            preg_match_all($rgxp, $content, $matches);
102
103
            $limit = count($matches[0]);
104
            for ($i = 0; $i < $limit; $i++) {
105
                $domain = $defaultDomain;
106
                $ctx = '';
107
                $str = self::unquoteString($matches[1][$i]);
108
109
                if (strpos($fname, '__d') === 0) {
110
                    $domain = self::unquoteString($matches[1][$i]);
111
112
                    if (strpos($fname, '__dx') === 0) {
113
                        $ctx = self::unquoteString($matches[2][$i]);
114
                        $str = self::unquoteString($matches[3][$i]);
115
                    } else {
116
                        $str = self::unquoteString($matches[2][$i]);
117
                    }
118
                } elseif (strpos($fname, '__x') === 0) {
119
                    $ctx = self::unquoteString($matches[1][$i]);
120
                    $str = self::unquoteString($matches[2][$i]);
121
                }
122
123
                $str = self::fixString($str);
124
                if (empty($str)) {
125
                    continue;
126
                }
127
128
                if (!array_key_exists($domain, $translations)) {
129
                    $translations[$domain] = [];
130
                }
131
132
                if (!array_key_exists($str, $translations[$domain])) {
133
                    $translations[$domain][$str] = [''];
134
                }
135
136
                if (!in_array($ctx, $translations[$domain][$str])) {
137
                    $translations[$domain][$str][] = $ctx;
138
                }
139
            }
140
        }
141
142
        return true;
143
    }
144
145
    /**
146
     * Remove leading and trailing quotes from string
147
     *
148
     * @param string $str The string
149
     * @return string The new string
150
     */
151
    public static function unquoteString($str): string
152
    {
153
        return substr($str, 1, -1);
154
    }
155
156
    /**
157
     * "fix" string - strip slashes, escape and convert new lines to \n
158
     *
159
     * @param string $str The string
160
     * @return string The new string
161
     */
162
    public static function fixString($str): string
163
    {
164
        $str = stripslashes($str);
165
        $str = str_replace('"', '\"', $str);
166
        $str = str_replace("\n", '\n', $str);
167
        $str = str_replace('|||||', "'", $str); // special sequence used in parseContent to temporarily replace "\'"
168
169
        return $str;
170
    }
171
}
172