Completed
Pull Request — master (#3324)
by bobo
02:23
created

ResourceGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Console;
4
5
use Illuminate\Database\Eloquent\Model;
6
7
class ResourceGenerator
8
{
9
    /**
10
     * @var Model
11
     */
12
    protected $model;
13
14
    /**
15
     * @var array
16
     */
17
    protected $formats = [
18
        'form_field'  => "\$form->%s('%s', '%s')",
19
        'show_field'  => "\$show->%s('%s')",
20
        'grid_column' => "\$grid->%s('%s')",
21
    ];
22
23
    /**
24
     * @var array
25
     */
26
    private $doctrineTypeMapping = [
27
        'string' => [
28
            'enum', 'geometry', 'geometrycollection', 'linestring',
29
            'polygon', 'multilinestring', 'multipoint', 'multipolygon',
30
            'point',
31
        ],
32
    ];
33
34
    /**
35
     * @var array
36
     */
37
    protected $fieldTypeMapping = [
38
        'ip'       => 'ip',
39
        'email'    => 'email|mail',
40
        'password' => 'password|pwd',
41
        'url'      => 'url|link|src|href',
42
        'mobile'   => 'mobile|phone',
43
        'color'    => 'color|rgb',
44
        'image'    => 'image|img|avatar|pic|picture|cover',
45
        'file'     => 'file|attachment',
46
    ];
47
48
    /**
49
     * ResourceGenerator constructor.
50
     *
51
     * @param mixed $model
52
     */
53
    public function __construct($model)
54
    {
55
        $this->model = $this->getModel($model);
56
    }
57
58
    /**
59
     * @param mixed $model
60
     *
61
     * @return mixed
62
     */
63
    protected function getModel($model)
64
    {
65
        if ($model instanceof Model) {
66
            return $model;
67
        }
68
69
        if (!class_exists($model) || !is_string($model) || !is_subclass_of($model, Model::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Illuminate\Database\Eloquent\Model::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
70
            throw new \InvalidArgumentException("Invalid model [$model] !");
71
        }
72
73
        return new $model();
74
    }
75
76
    /**
77
     * @return string
78
     */
79
    public function generateForm()
80
    {
81
        $reservedColumns = $this->getReservedColumns();
82
83
        $output = '';
84
85
        foreach ($this->getTableColumns() as $column) {
86
            $name = $column->getName();
87
            if (in_array($name, $reservedColumns)) {
88
                continue;
89
            }
90
            $type = $column->getType()->getName();
91
            $default = $column->getDefault();
92
93
            $defaultValue = '';
94
95
            // set column fieldType and defaultValue
96
            switch ($type) {
97
                case 'boolean':
98
                case 'bool':
99
                    $fieldType = 'switch';
100
                    break;
101
                case 'json':
102
                case 'array':
103
                case 'object':
104
                    $fieldType = 'text';
105
                    break;
106
                case 'string':
107
                    $fieldType = 'text';
108
                    foreach ($this->fieldTypeMapping as $type => $regex) {
109
                        if (preg_match("/^($regex)$/i", $name) !== 0) {
110
                            $fieldType = $type;
111
                            break;
112
                        }
113
                    }
114
                    $defaultValue = "'{$default}'";
115
                    break;
116
                case 'integer':
117
                case 'bigint':
118
                case 'smallint':
119
                case 'timestamp':
120
                    $fieldType = 'number';
121
                    break;
122
                case 'decimal':
123
                case 'float':
124
                case 'real':
125
                    $fieldType = 'decimal';
126
                    break;
127
                case 'datetime':
128
                    $fieldType = 'datetime';
129
                    $defaultValue = "date('Y-m-d H:i:s')";
130
                    break;
131
                case 'date':
132
                    $fieldType = 'date';
133
                    $defaultValue = "date('Y-m-d')";
134
                    break;
135
                case 'time':
136
                    $fieldType = 'time';
137
                    $defaultValue = "date('H:i:s')";
138
                    break;
139
                case 'text':
140
                case 'blob':
141
                    $fieldType = 'textarea';
142
                    break;
143
                default:
144
                    $fieldType = 'text';
145
                    $defaultValue = "'{$default}'";
146
            }
147
148
            $defaultValue = $defaultValue ?: $default;
149
150
            $comment = $column->getComment();
151
            $comment = explode(' ', $comment)[0];
152
            if (!$comment) {
153
                $comment = $name;
154
            }
155
            $label = $this->formatLabel($comment);
156
157
            $output .= sprintf($this->formats['form_field'], $fieldType, $name, $label);
158
159
            if (trim($defaultValue, "'\"")) {
160
                $output .= "->default({$defaultValue})";
161
            }
162
163
            $output .= ";\r\n";
164
        }
165
166
        return $output;
167
    }
168
169 View Code Duplication
    public function generateShow()
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...
170
    {
171
        $output = '';
172
173
        foreach ($this->getTableColumns() as $column) {
174
            $name = $column->getName();
175
176
            // set column label
177
            $comment = $column->getComment();
178
            $comment = explode(' ', $comment)[0];
179
            if (!$comment) {
180
                $comment = $name;
181
            }
182
            $label = $this->formatLabel($comment);
183
184
            $output .= sprintf($this->formats['show_field'], $name, $label);
185
186
            $output .= ";\r\n";
187
        }
188
189
        return $output;
190
    }
191
192 View Code Duplication
    public function generateGrid()
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...
193
    {
194
        $output = '';
195
196
        foreach ($this->getTableColumns() as $column) {
197
            $name = $column->getName();
198
            $comment = $column->getComment();
199
            $comment = explode(' ', $comment)[0];
200
            if (!$comment) {
201
                $comment = $name;
202
            }
203
            $label = $this->formatLabel($comment);
204
205
            $output .= sprintf($this->formats['grid_column'], $name, $label);
206
            $output .= ";\r\n";
207
        }
208
209
        return $output;
210
    }
211
212
    protected function getReservedColumns()
213
    {
214
        return [
215
            $this->model->getKeyName(),
216
            $this->model->getCreatedAtColumn(),
217
            $this->model->getUpdatedAtColumn(),
218
            'deleted_at',
219
        ];
220
    }
221
222
    /**
223
     * Get columns of a giving model.
224
     *
225
     * @throws \Exception
226
     *
227
     * @return \Doctrine\DBAL\Schema\Column[]
228
     */
229
    protected function getTableColumns()
230
    {
231
        if (!$this->model->getConnection()->isDoctrineAvailable()) {
232
            throw new \Exception(
233
                'You need to require doctrine/dbal: ~2.3 in your own composer.json to get database columns. '
234
            );
235
        }
236
237
        $table = $this->model->getConnection()->getTablePrefix().$this->model->getTable();
238
        /** @var \Doctrine\DBAL\Schema\MySqlSchemaManager $schema */
239
        $schema = $this->model->getConnection()->getDoctrineSchemaManager($table);
0 ignored issues
show
Unused Code introduced by
The call to Connection::getDoctrineSchemaManager() has too many arguments starting with $table.

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...
240
241
        // custom mapping the types that doctrine/dbal does not support
242
        $databasePlatform = $schema->getDatabasePlatform();
243
244
        foreach ($this->doctrineTypeMapping as $doctrineType => $dbTypes) {
245
            foreach ($dbTypes as $dbType) {
246
                $databasePlatform->registerDoctrineTypeMapping($dbType, $doctrineType);
247
            }
248
        }
249
250
        $database = null;
251
        if (strpos($table, '.')) {
252
            list($database, $table) = explode('.', $table);
253
        }
254
255
        return $schema->listTableColumns($table, $database);
256
    }
257
258
    /**
259
     * Format label.
260
     *
261
     * @param string $value
262
     *
263
     * @return string
264
     */
265
    protected function formatLabel($value)
266
    {
267
        return ucfirst(str_replace(['-', '_'], ' ', $value));
268
    }
269
}
270