Completed
Push — master ( aa9f88...7ffb35 )
by Nasrul Hazim
02:12
created

LaravelDb2DocCommand::determineUnsigned()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace CleaniqueCoders\LaravelDB2DOC\Console\Commands;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Facades\DB;
7
8
class LaravelDb2DocCommand extends Command
9
{
10
    public $database_connection;
11
    public $format;
12
    public $connection;
13
    public $schema;
14
    public $tables;
15
    public $collections = [];
16
17
    /**
18
     * Output Path.
19
     *
20
     * @var string
21
     */
22
    public $output_path;
23
    /**
24
     * The name and signature of the console command.
25
     *
26
     * @var string
27
     */
28
    protected $signature = 'db:2doc {--database=} {--format=md} {--path=} {--emoji}';
29
30
    /**
31
     * The console command description.
32
     *
33
     * @var string
34
     */
35
    protected $description = 'Generate database schema to markdown (by default)';
36
37
    /**
38
     * Create a new command instance.
39
     */
40
    public function __construct()
41
    {
42
        parent::__construct();
43
    }
44
45
    /**
46
     * Execute the console command.
47
     *
48
     * @return mixed
49
     */
50
    public function handle()
51
    {
52
        /*
53
         * Initialize
54
         */
55
        $this->init();
56
57
        /*
58
         * Generate Table & Column Data Structure
59
         */
60
        $this->generateDataStructure();
61
62
        /*
63
         * Generate Document
64
         */
65
        $this->generateDocument();
66
    }
67
68
    private function init()
69
    {
70
        $this->output_path = $this->option('path') ?? storage_path('app/db2doc');
71
72
        if (! file_exists($this->output_path)) {
73
            mkdir($this->output_path);
74
        }
75
76
        $this->database_connection = $this->option('database') ?? config('database.default');
77
        $this->format              = $this->option('format');
78
        $this->connection          = DB::connection($this->database_connection)->getDoctrineConnection();
79
        $this->schema              = $this->connection->getSchemaManager();
80
        $this->tables              = $this->schema->listTableNames();
81
    }
82
83
    private function generateDataStructure()
84
    {
85
        $tables = $this->tables;
86
        $schema = $this->schema;
87
88
        $this->collections = [];
89
        foreach ($tables as $table) {
90
            $columns     = $schema->listTableColumns($table);
91
            $foreignKeys = collect($schema->listTableForeignKeys($table))->keyBy(function($foreignColumn) {
92
                return $foreignColumn->getLocalColumns()[0];
93
            });
94
            $this->info('Table: ' . $table);
95
            foreach ($columns as $column) {
96
                $columnName = $column->getName();
97
                $columnType = $column->getType()->getName();
98
                if (isset($foreignKeys[$columnName])) {
99
                    $foreignColumn = $foreignKeys[$columnName];
100
                    $foreignTable  = $foreignColumn->getForeignTableName();
101
                    $columnType    = 'FK -> ' . $foreignTable;
102
                }
103
104
                $details['column']           = $columnName;
105
                $details['type']             = $columnType . $this->determineUnsigned($column);
106
                $details['length']           = $column->getLength() && 255 !== $column->getLength() ? $column->getLength() : null;
107
                $details['default']          = $this->getDefaultValue($column);
108
                $details['nullable']         = $this->getExpression(true === ! $column->getNotNull());
109
                $details['comment']          = $column->getComment();
110
                $this->collections[$table][] = $details;
111
            }
112
        }
113
    }
114
115
    private function generateDocument()
116
    {
117
        switch ($this->format) {
118
            case 'json':
119
                $rendered = $this->render_json_content();
120
                break;
121
122
            default:
123
                $rendered = $this->render_markdown_content();
124
                break;
125
        }
126
        $filename = $rendered['filename'];
127
        $output   = $rendered['output'];
128
        $path     = $this->output_path . DIRECTORY_SEPARATOR . $filename;
129
        if (file_exists($path)) {
130
            unlink($path);
131
        }
132
        file_put_contents($path, $output);
133
    }
134
135
    private function getStub()
136
    {
137
        return file_get_contents(__DIR__ . '/stubs/header.stub');
138
    }
139
140
    private function determineUnsigned($column)
141
    {
142
        return (true === $column->getUnsigned()) ? '(unsigned)' : '';
143
    }
144
145
    private function getDefaultValue($column)
146
    {
147
        if ('boolean' == $column->getType()->getName()) {
148
            return $column->getDefault() ? 'true' : 'false';
149
        }
150
151
        return $column->getDefault();
152
    }
153
154
    private function getExpression($status)
155
    {
156
        if ($this->option('emoji')) {
157
            return $status ? "\u{2705}" : "\u{274C}";
158
        }
159
160
        return $status ? 'Yes' : 'No';
161
    }
162
163
    private function render_json_content()
164
    {
165
        $collections = $this->collections;
166
167
        return [
168
            'output'   => json_encode($collections),
169
            'filename' => config('app.name') . ' Database Schema.json',
170
        ];
171
    }
172
173
    private function render_markdown_content()
174
    {
175
        $collections = $this->collections;
176
        $output      = [];
177
        foreach ($collections as $table => $properties) {
178
            $table    = preg_replace('/[^A-Za-z0-9]/', ' ', $table);
179
            $output[] = '### ' . title_case($table) . PHP_EOL . PHP_EOL;
180
            $output[] = '| Column | Type | Length | Default | Nullable | Comment |' . PHP_EOL;
181
            $output[] = '|--------|------|--------|---------|----------|---------|' . PHP_EOL;
182
            foreach ($properties as $key => $value) {
183
                $fields = [];
184
                foreach ($value as $k => $v) {
185
                    $fields[] = "{$v}";
186
                }
187
                $output[] = '| ' . join(' | ', $fields) . ' |' . PHP_EOL;
188
            }
189
            $output[] = PHP_EOL;
190
        }
191
192
        $schema          = join('', $output);
193
        $stub            = $this->getStub();
194
        $database_config = config('database.' . $this->database_connection);
195
        $output          = str_replace([
196
                'APP_NAME',
197
                'DB_CONNECTION', 'DB_HOST', 'DB_PORT', 'DB_DATABASE',
198
                'SCHEMA_CONTENT',
199
            ], [
200
                config('app.name'),
201
                $this->database_connection, $database_config['host'], $database_config['port'], $database_config['database'],
202
                $schema,
203
            ], $stub);
204
205
        $filename = config('app.name') . ' Database Schema.md';
206
207
        return [
208
            'output'   => $output,
209
            'filename' => $filename,
210
        ];
211
    }
212
}
213