Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Populate migration file with actual model fields #935

Merged
merged 46 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
6bdd938
populate migration file with actual model fields as best as we can
mjauvin Jul 4, 2023
f59f6f1
add missing space after catch keyword
mjauvin Jul 4, 2023
d50680d
do not hardcode the primary key
mjauvin Jul 4, 2023
191b425
do not process fields if not in create mode
mjauvin Jul 4, 2023
8b9dd19
return vars
mjauvin Jul 4, 2023
934f00f
add missing quotes around the primaryKey
mjauvin Jul 4, 2023
5978677
use mediumText type for jsonable fields
mjauvin Jul 5, 2023
a940128
only generate fields in create stub if --model option is supplied
mjauvin Jul 5, 2023
ff06eab
autocreate model fields in --update mode as well if --model option su…
mjauvin Jul 5, 2023
fcdd327
jsonable use mediumText in stub files now
mjauvin Jul 5, 2023
3337df5
use boolean for checkbox/switch field types; use datetime for datepic…
mjauvin Jul 5, 2023
b95cac7
be smarted about number/range types
mjauvin Jul 5, 2023
68be02b
make sure step and min configs are set
mjauvin Jul 5, 2023
9ccbb0d
move fields mapping into a helper class
mjauvin Jul 5, 2023
3afef8f
add comments and type hinting
mjauvin Jul 5, 2023
d8e2e88
add more comments and type hinting
mjauvin Jul 5, 2023
65fd61d
add comment
mjauvin Jul 5, 2023
eb9bf9f
add unit tests for Migration helper
mjauvin Jul 5, 2023
3cf9b31
remove extra space
mjauvin Jul 5, 2023
36101b8
repeater can be ignored here, defined with the jsonable model property
mjauvin Jul 15, 2023
5fa0975
check if field is required in model's rules property
mjauvin Jul 16, 2023
c632529
Merge branch 'develop' into create-migration
mjauvin Jul 17, 2023
112e60b
use text column type for textarea
mjauvin Jul 19, 2023
24f1401
fix trsts
mjauvin Jul 19, 2023
449efbd
fix variable name
mjauvin Aug 20, 2023
adde4be
Merge branch 'develop' into create-migration
mjauvin Oct 14, 2023
b7139b8
fix coding style
mjauvin Oct 14, 2023
a66eef9
add missing space before closing twig tag
mjauvin Oct 14, 2023
5830179
move back to protected method
mjauvin Oct 15, 2023
add9450
remove Migration helper class tests
mjauvin Oct 15, 2023
b33cdc6
leave regular exception flow
mjauvin Oct 19, 2023
a7f66cc
add initial migration test and model
mjauvin Oct 21, 2023
fabd105
fix test filename
mjauvin Oct 21, 2023
27997fb
fix test plugins_path and add $rules to TestModel
mjauvin Oct 21, 2023
4b588db
use plugins_path() instead
mjauvin Oct 21, 2023
e05cea9
call artisan within the test, not setUp()
mjauvin Oct 21, 2023
c15776e
fix test method name
mjauvin Oct 21, 2023
3651826
cleanup after ourselves
mjauvin Oct 21, 2023
bdff39e
complete migration tests
mjauvin Oct 21, 2023
cc25878
simplify code logic
mjauvin Oct 21, 2023
0f436b1
check if the index have been created
mjauvin Oct 21, 2023
fd8be03
add Sortable trait and test sort_order column get added
mjauvin Oct 22, 2023
3869e49
test required field property
mjauvin Oct 22, 2023
af65980
cleanup
mjauvin Oct 22, 2023
6eb7b07
fix fields.yaml indentation
mjauvin Oct 26, 2023
614354e
require create or update option when table or model option is provided
mjauvin Oct 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 120 additions & 2 deletions modules/system/console/CreateMigration.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php namespace System\Console;

use File;
use InvalidArgumentException;
use Str;
use System\Console\BaseScaffoldCommand;
Expand Down Expand Up @@ -157,11 +158,13 @@ protected function prepareVars(): array
}

if ($this->option('create') && $this->option('update')) {
$this->error('The create & update options cannot both be set at the same time');
return false;
throw new InvalidArgumentException('The create & update options cannot both be set at the same time');
}

if ($this->option('create')) {
if (empty($model)) {
throw new InvalidArgumentException('The create options requires the --model option');
}
mjauvin marked this conversation as resolved.
Show resolved Hide resolved
$scaffold = 'create';
} elseif ($this->option('update')) {
$scaffold = 'update';
Expand Down Expand Up @@ -189,6 +192,7 @@ protected function prepareVars(): array
'name' => $name,
'author' => $author,
'plugin' => $plugin,
'model' => $model,
'version' => $version,
];

Expand All @@ -199,6 +203,120 @@ protected function prepareVars(): array
return $vars;
}

protected function processVars($vars): array
{
$vars = parent::processVars($vars);

if (!$this->option('create')) {
return $vars;
}

$vars['fields'] = [];

try {
$fields_path = '$/' . $vars['plugin_url'] . '/models/' . $vars['lower_model'] . '/fields.yaml';
$fields = Yaml::parseFile(File::symbolizePath($fields_path));
} catch (\Exception $e) {
die($e->getMessage());
LukeTowers marked this conversation as resolved.
Show resolved Hide resolved
}

$modelName = $vars['plugin_namespace'] . '\\Models\\' . $vars['model'];

$vars['model'] = $model = new $modelName();

foreach (['fields', 'tabs', 'secondaryTabs'] as $type) {
if (!isset($fields[$type])) {
continue;
}
if ($type === 'fields') {
$fieldList = $fields[$type];
} else {
$fieldList = $fields[$type]['fields'];
}

foreach ($fieldList as $field => $config) {
if (str_contains($field, '@')) {
list($field, $context) = explode('@', $field);
}

$type = $config['type'] ?? 'text';

if (str_starts_with($field, '_')
or $field === $model->getKeyName()
or str_contains($field, '[')
or in_array($type, ['fileupload','relation','relationmanager','section','hint'])
or in_array($field, $model->purgeable ?? [])
or $model->getRelationType($field)
mjauvin marked this conversation as resolved.
Show resolved Hide resolved
) {
continue;
}

$vars['fields'][$field] = $this->mapFieldType($field, $config);
}
}

foreach ($model->getRelationDefinitions() as $relationType => $definitions) {
if (in_array($relationType, ['belongsTo', 'hasOne'])) {
foreach (array_keys($definitions) as $relation) {
$vars['fields'][$relation . '_id'] = [
'type' => 'foreignId',
'index' => true,
'required' => true,
];
}
}
}

if ($model->methodExists('getSortOrderColumn')) {
$field = $model->getSortOrderColumn();
$vars['fields'][$field] = [
'type' => 'unsignedinteger',
'required' => false,
'index' => true,
];
}

$vars['primaryKey'] = $model->getKeyName();
$vars['jsonable'] = $model->getJsonable();
$vars['timestamps'] = $model->timestamps;

if ($morphable = $model->morphTo) {
$vars['morphable'] = array_keys($morphable);
}

return $vars;
}

protected function mapFieldType($name, $fieldConfig)
{
switch ($fieldConfig['type'] ?? 'text') {
case 'checkbox':
case 'switch':
$dbType = 'unsignedinteger';
break;
case 'number':
case 'range':
$dbType = 'integer';
break;
case 'datepicker':
$dbType = 'timestamp';
break;
case 'markdown':
case 'textarea':
$dbType = 'text';
break;
default:
$dbType = 'string';
}
$required = $fieldConfig['required'] ?? false;

return [
'type' => $dbType,
'required' => $required,
'index' => in_array($name, ["slug"]) or str_ends_with($name, "_id"),
];
mjauvin marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Get the next version number based on the current number.
*/
Expand Down
13 changes: 12 additions & 1 deletion modules/system/console/scaffold/migration/migration.create.stub
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,19 @@ return new class extends Migration
public function up()
{
Schema::create('{{ table }}', function (Blueprint $table) {
$table->id();
$table->increments({{ primaryKey }});
{% for field,config in fields %}
$table->{{ config.type }}('{{ field }}'){{ config.required == false ? '->nullable()'}}{{ config.index ? '->index()' }};
mjauvin marked this conversation as resolved.
Show resolved Hide resolved
{% endfor %}
{% for field in jsonable %}
$table->text('{{ field }}')->nullable();
mjauvin marked this conversation as resolved.
Show resolved Hide resolved
{% endfor %}
{% for field in morphable %}
$table->nullableMorphs('{{ field }}', 'morphable_index');
{% endfor %}
{% if timestamps %}
$table->timestamps();
{% endif %}
});
}

Expand Down