LaravelDb2DocCommand::render_json_content()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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