Passed
Push — 2.x ( e8dd26...ba8025 )
by Quentin
07:25
created

SyncLang   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Test Coverage

Coverage 5.56%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 66
c 1
b 0
f 0
dl 0
loc 156
ccs 4
cts 72
cp 0.0556
rs 10
wmc 20

10 Methods

Rating   Name   Duplication   Size   Complexity  
A generateLangFileContent() 0 17 3
A convertArrayToString() 0 8 1
A getArrayFromCsv() 0 3 1
A cleanup() 0 4 1
A __construct() 0 4 1
A generateLangFiles() 0 9 2
A handle() 0 12 3
A getLangCodesFromCsv() 0 8 1
A getIndexByCode() 0 3 1
A toCsv() 0 28 6
1
<?php
2
3
namespace A17\Twill\Commands;
4
5
use Illuminate\Console\Command;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, A17\Twill\Commands\Command. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Illuminate\Filesystem\Filesystem;
7
use Illuminate\Support\Arr;
8
9
class SyncLang extends Command
10
{
11
    /**
12
     * The name and signature of the console command.
13
     *
14
     * @var string
15
     */
16
    protected $signature = 'twill:lang {--toCsv}';
17
18
    /**
19
     * The console command description.
20
     *
21
     * @var string
22
     */
23
    protected $description = "Sync the translations";
24
25
    /**
26
     * @var Filesystem
27
     */
28
    protected $files;
29
30
    protected $langDirPath = __DIR__ . '/../../lang';
31
32
    protected $csvPath = __DIR__ . '/../../lang/lang.csv';
33
34
    protected $langStubPath = __DIR__ . '/stubs/lang.stub';
35
36
    /**
37
     * @param ValidatorFactory $validatorFactory
0 ignored issues
show
Bug introduced by
The type A17\Twill\Commands\ValidatorFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
38
     * @param Config $config
0 ignored issues
show
Bug introduced by
The type A17\Twill\Commands\Config was not found. Did you mean Config? If so, make sure to prefix the type with \.
Loading history...
39
     */
40 69
    public function __construct(Filesystem $files)
41
    {
42 69
        parent::__construct();
43 69
        $this->files = $files;
44 69
    }
45
46
    /**
47
     * Create super admin account.
48
     *
49
     * @return void
50
     */
51
    public function handle()
52
    {
53
        if ($this->option('toCsv')) {
54
            return $this->toCsv();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->toCsv() targeting A17\Twill\Commands\SyncLang::toCsv() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
55
        }
56
57
        $this->info('Converting csv to lang files...');
58
        if ($this->confirm('This operation will overwrite all your changes made on lang file, are you sure?')) {
59
            $this->cleanup();
60
            $this->info('Generating the new lang directories...');
61
            $this->generateLangFiles();
62
            $this->info('Done!');
63
        }
64
    }
65
66
    // BETA METHOD, NOT STABLE
67
    private function toCsv()
68
    {
69
        if ($this->confirm('This operation will overwrite the lang.csv file, are you sure?')) {
70
            $csvArray = $this->getArrayFromCsv();
71
            foreach ($this->files->directories($this->langDirPath) as $directory) {
72
                $code = $this->files->basename($directory);
73
                $columnIndex = $this->getIndexByCode($code);
74
                $translations = $this->files->getRequire($directory . '/lang.php');
75
                foreach (Arr::dot($translations) as $key => $translation) {
76
                    $rowIndex = array_search($key, Arr::pluck(array_slice($csvArray, 2), 0));
77
                    if ($rowIndex === FALSE) {
78
                        $newRow = array_fill(0, count($csvArray[0]), "");
79
                        $newRow[0] = $key;
80
                        $newRow[$columnIndex] = $translation;
81
                        array_push($csvArray, $newRow);
82
                    } else {
83
                        $csvArray[$rowIndex + 2][$columnIndex] = $translation;
84
                    }
85
                }
86
            }
87
88
            $fp = fopen($this->csvPath, 'w');
89
90
            foreach ($csvArray as $row) {
91
                fputcsv($fp, $row);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fputcsv() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
                fputcsv(/** @scrutinizer ignore-type */ $fp, $row);
Loading history...
92
            }
93
94
            fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

94
            fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
95
        }
96
    }
97
98
    private function getArrayFromCsv()
99
    {
100
        return array_map('str_getcsv', file($this->csvPath));
0 ignored issues
show
Bug introduced by
It seems like file($this->csvPath) can also be of type false; however, parameter $arr1 of array_map() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

100
        return array_map('str_getcsv', /** @scrutinizer ignore-type */ file($this->csvPath));
Loading history...
101
    }
102
103
    private function getLangCodesFromCsv()
104
    {
105
        $codes = $this->getArrayFromCsv()[1];
106
107
        // Remove the first element: row name
108
        array_shift($codes);
109
110
        return $codes;
111
    }
112
113
    private function generateLangFiles()
114
    {
115
        foreach ($this->getLangCodesFromCsv() as $code) {
116
            $langDirPath = $this->langDirPath . '/' . $code;
117
            $this->files->makeDirectory($langDirPath);
118
            $this->files->put(
119
                $this->langDirPath . '/' . $code . '/lang.php',
120
                // increment the index by one to match its actual index in csv
121
                $this->generateLangFileContent($code)
122
            );
123
        }
124
    }
125
126
    private function generateLangFileContent($code)
127
    {
128
        $content = [];
129
        $index = $this->getIndexByCode($code);
130
131
        foreach (array_slice($this->getArrayFromCsv(), 2) as $row) {
132
            $key = $row[0];
133
            $translation = $row[$index];
134
            if (!empty($translation)) {
135
                Arr::set($content, $key, $translation);
136
            }
137
        }
138
139
        return str_replace(
140
            ['{{content}}'],
141
            [$this->convertArrayToString($content)],
142
            $this->files->get($this->langStubPath)
143
        );
144
    }
145
146
    private function getIndexByCode($code)
147
    {
148
        return array_search($code, $this->getArrayFromCsv()[1]);
149
    }
150
151
    private function convertArrayToString($array)
152
    {
153
        $export = var_export($array, true);
154
        $export = preg_replace("/^([ ]*)(.*)/m", '$1$1$2', $export);
155
        $array = preg_split("/\r\n|\n|\r/", $export);
156
        $array = preg_replace(["/\s*array\s\($/", "/\)(,)?$/", "/\s=>\s$/"], [null, ']$1', ' => ['], $array);
157
        $export = join(PHP_EOL, array_filter(["["] + $array));
158
        return $export;
159
    }
160
161
    private function cleanup()
162
    {
163
        $this->info('Cleaning up the lang directories...');
164
        $this->files->deleteDirectories($this->langDirPath);
165
    }
166
}
167