Completed
Push — master ( 54b8d1...ceafd9 )
by Avtandil
02:36
created

ImportCommand   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 176
Duplicated Lines 9.66 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 17
loc 176
rs 10
c 1
b 0
f 0
wmc 18
lcom 1
cbo 5

3 Methods

Rating   Name   Duplication   Size   Complexity  
C handle() 8 32 7
C import() 0 67 9
A getDatabase() 9 9 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/*
3
 * This file is part of the Laravel MultiLang package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\LaravelMultiLang\Console;
12
13
use App;
14
use Illuminate\Console\Command;
15
use Carbon\Carbon;
16
use InvalidArgumentException;
17
use Illuminate\Database\DatabaseManager as Database;
18
use Symfony\Component\Yaml\Yaml;
19
20
class ImportCommand extends Command
21
{
22
    /**
23
     * The name and signature of the console command.
24
     *
25
     * @var string
26
     */
27
    protected $signature = 'multilang:import        
28
        {--path=storage/multilang : The path to multilang folder}
29
        {--lang= : Comma separated langs to import, default all}
30
        {--scope= : Comma separated scopes, default all}
31
        {--force : Force update existing texts in database}';
32
33
    /**
34
     * The console command description.
35
     *
36
     * @var string
37
     */
38
    protected $description = 'Import texts in database from yml files.';
39
40
    /**
41
     * The name of texts table.
42
     *
43
     * @var string
44
     */
45
    protected $table;
46
47
    /**
48
     * The database connection instance.
49
     *
50
     * @var \Illuminate\Database\Connection
51
     */
52
    protected $db;
53
54
    /**
55
     * The path to texts files.
56
     *
57
     * @var string
58
     */
59
    protected $path;
60
61
    /**
62
     * The langs.
63
     *
64
     * @var array
65
     */
66
    protected $langs;
67
68
    /**
69
     * The available scopes.
70
     *
71
     * @var array
72
     */
73
    protected $scopes = ['global', 'site', 'admin'];
74
75
    /**
76
     * Execute the console command.
77
     *
78
     * @return mixed
79
     */
80
    public function handle()
81
    {
82
        $this->table = config('multilang.db.texts_table', 'texts');
83
        $this->db    = $this->getDatabase();
84
85
        $lang = $this->option('lang');
86
        if (! empty($lang)) {
87
            $this->langs = explode(',', $lang);
88
        }
89
90
        $scopes = $this->scopes;
91
        $scope  = $this->option('scope');
92 View Code Duplication
        if (! empty($scope)) {
0 ignored issues
show
Duplication introduced by
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...
93
            $scopes = explode(',', $scope);
94
            foreach ($scopes as $scope) {
95
                if (! in_array($scope, $this->scopes)) {
96
                    throw new InvalidArgumentException('Scope "' . $scope . '" is not found! Available scopes is ' . implode(', ', $this->scopes));
97
                }
98
            }
99
        }
100
101
        $path       = $this->option('path', 'storage/multilang');
0 ignored issues
show
Unused Code introduced by
The call to ImportCommand::option() has too many arguments starting with 'storage/multilang'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
102
        $this->path = base_path($path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $this->option('path', 'storage/multilang') on line 101 can also be of type array; however, base_path() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
103
        if (! is_dir($this->path)) {
104
            throw new InvalidArgumentException('Folder "' . $this->path . '" is not accessible!');
105
        }
106
107
        $force = $this->option('force');
108
        foreach ($scopes as $scope) {
109
            $this->import($scope, $force);
0 ignored issues
show
Documentation introduced by
$force is of type string|array, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
110
        }
111
    }
112
113
    protected function import($scope = 'global', $force = false)
114
    {
115
        $path = $this->path . '/' . $scope . '.yml';
116
        if (! is_readable($path)) {
117
            $this->warn('File "' . $path . '" is not readable!');
118
            return false;
119
        }
120
        $data = Yaml::parse(file_get_contents($path));
121
        if (empty($data)) {
122
            $this->warn('File "' . $path . '" is empty!');
123
            return false;
124
        }
125
126
        $created_at = Carbon::now()->toDateTimeString();
127
        $updated_at = $created_at;
128
        $inserted   = 0;
129
        $updated    = 0;
130
        foreach ($data as $text) {
0 ignored issues
show
Bug introduced by
The expression $data of type array|string|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
131
            $key = $text['key'];
132
133
            foreach ($text['texts'] as $lang => $value) {
134
                if (! empty($this->langs) && ! in_array($lang, $this->langs)) {
135
                    continue;
136
                }
137
138
                $row = $this->db
139
                    ->table($this->table)
140
                    ->where('scope', $scope)
141
                    ->where('key', $key)
142
                    ->first();
143
144
                if (empty($row)) {
145
                    // insert row
146
                    $ins               = [];
147
                    $ins['key']        = $key;
148
                    $ins['lang']       = $lang;
149
                    $ins['scope']      = $scope;
150
                    $ins['value']      = $value;
151
                    $ins['created_at'] = $created_at;
152
                    $ins['updated_at'] = $updated_at;
153
                    $this->db
154
                        ->table($this->table)
155
                        ->insert($ins);
156
                    $inserted++;
157
                } else {
158
                    if ($force) {
159
                        // force update row
160
                        $upd               = [];
161
                        $upd['key']        = $key;
162
                        $upd['lang']       = $lang;
163
                        $upd['scope']      = $scope;
164
                        $upd['value']      = $value;
165
                        $upd['updated_at'] = $updated_at;
166
                        $this->db
167
                            ->table($this->table)
168
                            ->where('key', $key)
169
                            ->where('lang', $lang)
170
                            ->where('scope', $scope)
171
                            ->update($upd);
172
                        $updated++;
173
                    }
174
                }
175
            }
176
        }
177
178
        $this->info('Import texts of "' . $scope . '" is finished. Inserted: ' . $inserted . ', Updated: ' . $updated);
179
    }
180
181
    /**
182
     * Get a database connection instance.
183
     *
184
     * @return \Illuminate\Database\Connection
185
     */
186 View Code Duplication
    protected function getDatabase()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
187
    {
188
        $connection = config('multilang.db.connection', 'default');
189
        $db         = App::make(Database::class);
190
        if ($connection == 'default') {
191
            return $db->connection();
192
        }
193
        return $db->connection($connection);
194
    }
195
}
196