Completed
Push — master ( a2dd34...253c8c )
by Song
03:46
created

ResourceGenerator::generateShow()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17

Duplication

Lines 17
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 17
loc 17
rs 9.7
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
     * @return mixed
61
     */
62
    protected function getModel($model)
63
    {
64
        if ($model instanceof Model) {
65
            return $model;
66
        }
67
68
        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...
69
            throw new \InvalidArgumentException("Invalid model [$model] !");
70
        }
71
72
        return new $model;
73
    }
74
75
    /**
76
     * @return string
77
     */
78
    public function generateForm()
79
    {
80
        $reservedColumns = $this->getReservedColumns();
81
82
        $output = '';
83
84
        foreach ($this->getTableColumns() as $column) {
85
            $name = $column->getName();
86
            if (in_array($name, $reservedColumns)) {
87
                continue;
88
            }
89
            $type    = $column->getType()->getName();
90
            $default = $column->getDefault();
91
92
            $defaultValue = '';
93
94
            // set column fieldType and defaultValue
95
            switch ($type) {
96
                case 'boolean':
97
                case 'bool':
98
                    $fieldType = 'switch';
99
                    break;
100
                case 'json':
101
                case 'array':
102
                case 'object':
103
                    $fieldType = 'text';
104
                    break;
105
                case 'string':
106
                    $fieldType = 'text';
107
                    foreach ($this->fieldTypeMapping as $type => $regex) {
108
                        if (preg_match("/^($regex)$/i", $name) !== 0) {
109
                            $fieldType = $type;
110
                            break;
111
                        }
112
                    }
113
                    $defaultValue = "'{$default}'";
114
                    break;
115
                case 'integer':
116
                case 'bigint':
117
                case 'smallint':
118
                case 'timestamp':
119
                    $fieldType = 'number';
120
                    break;
121
                case 'decimal':
122
                case 'float':
123
                case 'real':
124
                    $fieldType = 'decimal';
125
                    break;
126
                case 'datetime':
127
                    $fieldType    = 'datetime';
128
                    $defaultValue = "date('Y-m-d H:i:s')";
129
                    break;
130
                case 'date':
131
                    $fieldType    = 'date';
132
                    $defaultValue = "date('Y-m-d')";
133
                    break;
134
                case 'time':
135
                    $fieldType    = 'time';
136
                    $defaultValue = "date('H:i:s')";
137
                    break;
138
                case 'text':
139
                case 'blob':
140
                    $fieldType = 'textarea';
141
                    break;
142
                default:
143
                    $fieldType    = 'text';
144
                    $defaultValue = "'{$default}'";
145
            }
146
147
            $defaultValue = $defaultValue ?: $default;
148
149
            $label = $this->formatLabel($name);
150
151
            $output .= sprintf($this->formats['form_field'], $fieldType, $name, $label);
152
153
            if (trim($defaultValue, "'\"")) {
154
                $output .= "->default({$defaultValue})";
155
            }
156
157
            $output .= ";\r\n";
158
        }
159
160
        return $output;
161
    }
162
163 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...
164
    {
165
        $output = '';
166
167
        foreach ($this->getTableColumns() as $column) {
168
            $name    = $column->getName();
169
170
            // set column label
171
            $label = $this->formatLabel($name);
172
173
            $output .= sprintf($this->formats['show_field'], $name, $label);
174
175
            $output .= ";\r\n";
176
        }
177
178
        return $output;
179
    }
180
181 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...
182
    {
183
        $output = '';
184
185
        foreach ($this->getTableColumns() as $column) {
186
            $name    = $column->getName();
187
            $label = $this->formatLabel($name);
188
189
            $output .= sprintf($this->formats['grid_column'], $name, $label);
190
            $output .= ";\r\n";
191
        }
192
193
        return $output;
194
    }
195
196
    protected function getReservedColumns()
197
    {
198
        return [
199
            $this->model->getKeyName(),
200
            $this->model->getCreatedAtColumn(),
201
            $this->model->getUpdatedAtColumn(),
202
            'deleted_at',
203
        ];
204
    }
205
206
    /**
207
     * Get columns of a giving model.
208
     *
209
     * @return \Doctrine\DBAL\Schema\Column[]
210
     * @throws \Exception
211
     */
212
    protected function getTableColumns()
213
    {
214
        if (!$this->model->getConnection()->isDoctrineAvailable()) {
215
            throw new \Exception(
216
                'You need to require doctrine/dbal: ~2.3 in your own composer.json to get database columns. '
217
            );
218
        }
219
220
        $table = $this->model->getConnection()->getTablePrefix() . $this->model->getTable();
221
        /** @var \Doctrine\DBAL\Schema\MySqlSchemaManager $schema */
222
        $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...
223
224
        // custom mapping the types that doctrine/dbal does not support
225
        $databasePlatform = $schema->getDatabasePlatform();
226
227
        foreach ($this->doctrineTypeMapping as $doctrineType => $dbTypes) {
228
            foreach ($dbTypes as $dbType) {
229
                $databasePlatform->registerDoctrineTypeMapping($dbType, $doctrineType);
230
            }
231
        }
232
233
        $database = null;
234
        if (strpos($table, '.')) {
235
            list($database, $table) = explode('.', $table);
236
        }
237
238
        return $schema->listTableColumns($table, $database);
239
    }
240
241
    /**
242
     * Format label.
243
     *
244
     * @param string $value
245
     * @return string
246
     */
247
    protected function formatLabel($value)
248
    {
249
        return ucfirst(str_replace(['-', '_'], ' ', $value));
250
    }
251
}