EncryptModel::handle()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 27
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 20
c 2
b 0
f 0
nc 2
nop 0
dl 0
loc 27
rs 9.6
1
<?php
2
3
namespace Magros\Encryptable;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Database\Schema\Blueprint;
8
use Illuminate\Support\Facades\Schema;
9
use Illuminate\Support\Facades\DB;
10
use Illuminate\Support\Str;
11
12
class EncryptModel extends Command
13
{
14
    /**
15
     * The name and signature of the console command.
16
     *
17
     * @var string
18
     */
19
    protected $signature = 'encryptable:encryptModel {model}';
20
21
    /**
22
     * The console command description.
23
     *
24
     * @var string
25
     */
26
    protected $description = 'Encrypt models rows';
27
28
    private $attributes = [];
29
    private $model;
30
31
    /**
32
     * Execute the console command.
33
     *
34
     * @return mixed
35
     * @throws \Exception
36
     */
37
    public function handle()
38
    {
39
        $class = $this->argument('model');
40
        $this->model = $this->guardClass($class);
41
        $this->attributes = $this->model->getEncryptableAttributes();
42
        $table = $this->model->getTable();
43
        $total = $this->model->where('encrypted', 0)->count();
44
        $this->model::$enableEncryption = false;
45
46
        if($total > 0){
47
            $this->comment($total.' records will be encrypted');
0 ignored issues
show
Bug introduced by
Are you sure $total of type Illuminate\Database\Eloquent\Builder|integer|mixed can be used in concatenation? ( Ignorable by Annotation )

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

47
            $this->comment(/** @scrutinizer ignore-type */ $total.' records will be encrypted');
Loading history...
48
            $bar = $this->output->createProgressBar($total);
0 ignored issues
show
Bug introduced by
It seems like $total can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $max of Symfony\Component\Consol...le::createProgressBar() does only seem to accept integer, 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

48
            $bar = $this->output->createProgressBar(/** @scrutinizer ignore-type */ $total);
Loading history...
49
            $bar->setFormat('%current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%');
50
51
            $records =  $this->model->orderBy('id', 'asc')->where('encrypted', 0)->get();
52
            foreach ($records as $record) {
53
                $record->timestamps = false;
54
                $attributes = $this->getEncryptedAttributes($record);
55
                DB::table($table)->where('id', $record->id)->update($attributes);
56
                $bar->advance();
57
                $record = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $record is dead and can be removed.
Loading history...
58
                $attributes = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $attributes is dead and can be removed.
Loading history...
59
            }
60
            $bar->finish();
61
        }
62
63
        $this->comment('Finished encryption');
64
    }
65
66
    private function getEncryptedAttributes($record)
67
    {
68
        $encryptedFields = ['encrypted' => 1];
69
70
        foreach ($this->attributes as $attribute) {
71
            $raw = $record->{$attribute};
72
            if (!Str::contains($raw, $record->encrypter()->getPrefix())) {
73
                $encryptedFields[$attribute] = $this->model->encryptAttribute($raw);
74
            }
75
        }
76
        return $encryptedFields;
77
    }
78
79
    private function validateHasEncryptedColumn($model)
80
    {
81
        $table = $model->getTable();
82
        if (! Schema::hasColumn($table, 'encrypted')) {
83
            $this->comment('Creating encrypted column');
84
            Schema::table($table, function (Blueprint $table) {
85
                $table->tinyInteger('encrypted')->default(0);
86
            });
87
        }
88
    }
89
90
    /**
91
     * @param $class
92
     * @return Model
93
     * @throws \Exception
94
     */
95
    public function guardClass($class)
96
    {
97
        if (!class_exists($class))
98
            throw new \Exception("Class {$class} does not exists");
99
        $model = new $class();
100
        $this->validateHasEncryptedColumn($model);
101
        return $model;
102
    }
103
}
104