diff --git a/README.md b/README.md index fd268c7..ff56f73 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,17 @@ -# WIP - DON'T INSTALL, yet! - # TALL-forms Blueprint Addon -#### This package is based on [Blueprint Nova Addon](https://github.com/Naoray/blueprint-nova-addon) by [Krishan König](https://github.com/naoray). +Auto generate [TALL-forms](https://github.com/tanthammar/tall-forms/wiki) for all models with the `php artisan blueprint:build` command. + +#### This plugin is based on [Blueprint Nova Addon](https://github.com/Naoray/blueprint-nova-addon) by [Krishan König](https://github.com/naoray). + -Installing this addon will allow you to generate Tall-forms for all models with the `php artisan blueprint:build` command. +# What you get +* Consider the code you get as a mockup/draft. **It won't work as is**. You'll have to review and finalize the field declarations. +* You will get a single form component for each model. + It's up to you to split it in two components if you need separate forms for create/update forms. + +# Early version! +* Relationship fields are outputted as `Repeaters`, `Selects` or `MultiSelect`. This will change when I create required fields in TALL-forms +* Review generated code, it's not perfect :) ## Requirements * tall-forms >= v7.8.4 @@ -47,21 +55,27 @@ controllers: create: render: post.create store: + validate: title, content, author_id + save: post + dispatch: SyncMedia with:post notify: post.author ReviewPost with:post send: ReviewPost to:post.author with:post - validate: title, content - save: post - redirect: post.index + flash: post.title fire: NewPost with:post + redirect: post.index update: + update: post dispatch: SyncMedia with:post destroy: flash: post.title - send: PostDeleted to:post.author with:post + send: SupportPostDeleted to:support with:post + delete: post + redirect: post.index Comment: resource + ``` ## Configuration diff --git a/config/tall_forms_blueprint.php b/config/tall_forms_blueprint.php index b46a2f1..00cda22 100644 --- a/config/tall_forms_blueprint.php +++ b/config/tall_forms_blueprint.php @@ -25,7 +25,9 @@ //set to true if you want redirects on CREATE and UPDATE form methods. //only applicable if you use the blueprint controllers RESOURCE SHORTHAND //tall-forms has a save-and-stay, and a save-and-go-back button, setting this option to true REPLACES that behaviour - 'resource-redirect' => true, - //if don't have any redirects on create and update, perhaps it makes no sense to flash to session either? - 'resource-session' => true, + 'resource-redirect' => false, + + //tall-forms has a notify() method that displays a success message on create/update, maybe you don't need to flash to session? + //only applicable if you use the blueprint controllers RESOURCE SHORTHAND + 'resource-session' => false, ]; diff --git a/src/TallMethodsBlueprintGenerator.php b/src/TallMethodsBlueprintGenerator.php index 4378731..161a576 100644 --- a/src/TallMethodsBlueprintGenerator.php +++ b/src/TallMethodsBlueprintGenerator.php @@ -72,10 +72,10 @@ protected function populateStub(string $stub, \Blueprint\Models\Controller $cont } } - $stub = $this->sharedStrReplace($stub, $controller->name(), $controller->fullyQualifiedClassName()); $stub = str_replace('// create...', data_get($data, 'create'), $stub); $stub = str_replace('// update...', data_get($data, 'update'), $stub); $stub = str_replace('// delete...', data_get($data, 'delete'), $stub); + $stub = $this->sharedStrReplace($stub, $controller->name(), $controller->fullyQualifiedClassName()); $imports = array_unique(data_get($data, 'imports', [])); $stub = str_replace('use Controllers;', implode(PHP_EOL, $imports), $stub); diff --git a/src/Tasks/AddIdentifierField.php b/src/Tasks/AddIdentifierField.php index 8913fcf..39a4e33 100644 --- a/src/Tasks/AddIdentifierField.php +++ b/src/Tasks/AddIdentifierField.php @@ -18,7 +18,7 @@ public function handle($data, Closure $next): array { $column = $this->identifierColumn($data['model']); - $identifierName = $column->name() === 'id' ? 'ID, id' : "'".$column->name()."'"; + $identifierName = $column->name() === 'id' ? '"ID", "id"' : "'".$column->name()."'"; $data['fields'] .= 'Number::make('.$identifierName.'),'.PHP_EOL.PHP_EOL; $data['imports'][] = 'Number'; diff --git a/src/Tasks/AddRegularFields.php b/src/Tasks/AddRegularFields.php index f65816c..39cc8af 100644 --- a/src/Tasks/AddRegularFields.php +++ b/src/Tasks/AddRegularFields.php @@ -98,7 +98,7 @@ private function addRules(Column $column, string $tableName): string return ''; } - return PHP_EOL . self::INDENT_PLUS . '->rules(' . trim(implode(',', $rules)) . ')'; + return PHP_EOL . self::INDENT_PLUS . '->rules([' . trim(implode(',', $rules)) . '])'; } private function fieldType(string $dataType) diff --git a/src/Tasks/AddRelationshipFields.php b/src/Tasks/AddRelationshipFields.php index c916888..7aa5877 100644 --- a/src/Tasks/AddRelationshipFields.php +++ b/src/Tasks/AddRelationshipFields.php @@ -41,23 +41,37 @@ public function handle(array $data, Closure $next): array $fieldType = $this->fieldType($type); $imports[] = $fieldType; - if ($fieldType === 'MorphTo') { + if ($type === 'morphto') { $label .= 'able'; } $fields .= self::INDENT.$fieldType."::make('".$label."'"; - if ($fieldType !== 'MorphTo' && $this->classNameNotGuessable($label, $class)) { - $fields .= ", '".$methodName."', ".$class.'::class'; + + if ($type !== 'morphto' && $this->classNameNotGuessable($label, $class)) { +// $fields .= ", '".$methodName."', ".$class.'::class'; //sets third option in make() command. Example make('Author', 'user_id', User::class) + $fields .= ", '".$methodName."'"; } $fields .= ')'; - if ($this->isNullable($reference, $model)) { - $fields .= '->nullable()'; + + + switch ($fieldType) { + case 'Select': + case 'MultiSelect': + $fields .= $this->classNameNotGuessable($label, $class) ? "->options(".$class."::take(10)->pluck('id', 'name'))" : "->options()"; + break; + case 'KeyVal': + case 'Repeater': + $fields .= '->fields([])'; + break; } + $fields .= '->relation()'; - //$fields .= '->relation()'; + if ($this->isNullable($reference, $model)) { + $fields .= "->rules('nullable')"; + } $fields .= ','.PHP_EOL; } @@ -106,13 +120,13 @@ private function isNullable($relation, Model $model): bool private function fieldType(string $dataType): string { static $fieldTypes = [ - 'belongsto' => 'BelongsTo', - 'belongstomany' => 'BelongsToMany', - 'hasone' => 'HasOne', - 'hasmany' => 'HasMany', - 'morphto' => 'MorphTo', - 'morphone' => 'MorphOne', - 'morphmany' => 'MorphMany', + 'belongsto' => 'Select', //BelongsTo + 'belongstomany' => 'MultiSelect', //BelongsToMany type multiple + 'hasone' => 'KeyVal', //HasOne + 'hasmany' => 'Repeater', //HasMany + 'morphto' => 'Select', //MorphTo, get the Parent morpheable model + 'morphone' => 'KeyVal', //MorphOne, example has one image() + 'morphmany' => 'Repeater', //MorphMany ]; return $fieldTypes[strtolower($dataType)]; diff --git a/src/Tasks/MethodsTrait.php b/src/Tasks/MethodsTrait.php index a6a15b9..d92d909 100644 --- a/src/Tasks/MethodsTrait.php +++ b/src/Tasks/MethodsTrait.php @@ -16,8 +16,13 @@ trait MethodsTrait protected $imports = []; protected $data = []; protected $statements; - public $name = ''; - public $action = ''; + protected $name = ''; + protected $action = ''; + protected $eloquentActions = [ + 'create' => '$this->model = DummyModel::create($validated_data);' . PHP_EOL . self::INDENT . '$dummymodel = $this->model;' . PHP_EOL . self::INDENT . '$this->showDelete = true;', + 'update' => '$this->model->update($validated_data);' . PHP_EOL . self::INDENT . '$dummymodel = $this->model;', + 'delete' => '$this->model->delete();' + ]; public function __construct($statements, array $data) { @@ -48,6 +53,13 @@ protected function addImport($class) $this->imports[$this->name][] = 'use ' . $class . ';'; } + protected function makeEloquentStatement(string $statement): string + { + $string = \Str::contains($statement, $this->action . '(') ? $this->eloquentActions[$this->action] : $statement; + if (\Str::contains($string, '->save(')) $string = $this->eloquentActions['create']; + return $string; + } + private function buildMethods($statements): string { $body = ''; @@ -71,19 +83,20 @@ private function buildMethods($statements): string } } elseif ($statement instanceof RedirectStatement) { $this->redirect(self::INDENT . $statement->output() . PHP_EOL); + $body .= $this->redirect; } elseif ($statement instanceof SessionStatement) { $this->session(self::INDENT . str_replace('$request->', null, $statement->output()) . PHP_EOL); + $body .= $this->session; } elseif ($statement instanceof EloquentStatement) { - $body .= self::INDENT . '//Otiose EloquentStatement from Blueprint' . PHP_EOL; - $body .= self::INDENT . '//' . $statement->output($this->name, $this->action, false) . PHP_EOL; + $body .= self::INDENT . $this->makeEloquentStatement($statement->output($this->name, $this->action, false)) . PHP_EOL; } elseif ($statement instanceof QueryStatement) { $body .= self::INDENT . '//Otiose QueryStatement from Blueprint' . PHP_EOL; $body .= self::INDENT . '//' . $statement->output($this->name) . PHP_EOL; } } - $body .= $this->session; - $body .= $this->redirect; +// $body .= $this->session; +// $body .= $this->redirect; return trim($body); } diff --git a/src/Tasks/OnDelete.php b/src/Tasks/OnDelete.php index e7c920e..91c1b32 100644 --- a/src/Tasks/OnDelete.php +++ b/src/Tasks/OnDelete.php @@ -10,8 +10,9 @@ class OnDelete const INDENT = ' '; - protected $session = self::INDENT.'session()->flash("success", "The {$className} was deleted");'. PHP_EOL; - protected $redirect = self::INDENT.'return redirect(urldecode($this->previous));'. PHP_EOL; + protected $session = self::INDENT . 'session()->flash("success", "The "' . ' . class_basename($this->model). ' . '" was deleted");' . PHP_EOL; + + protected $redirect = self::INDENT . 'return redirect(urldecode($this->previous));' . PHP_EOL; protected function redirect($string): void { diff --git a/src/Tasks/RemapImports.php b/src/Tasks/RemapImports.php index e190e7e..9e2c5bd 100644 --- a/src/Tasks/RemapImports.php +++ b/src/Tasks/RemapImports.php @@ -33,6 +33,10 @@ public function freeFields(): array return [ 'Checkbox', 'Input', + 'Trix', + 'Select', + 'KeyVal', + 'Repeater' ]; } } diff --git a/stubs/class.stub.php b/stubs/class.stub.php index 146ba66..0d2c6f2 100644 --- a/stubs/class.stub.php +++ b/stubs/class.stub.php @@ -23,32 +23,22 @@ public function mount(?DummyModel $dummymodel) } + // REQUIRED, if you are creating a model with this form public function onCreateModel($validated_data) { - // Set the $model property in order to conditionally display fields if the model exists - $this->model = DummyModel::create($validated_data); - //remove if you do not want to show the delete button or if you are redirecting. - $this->showDelete = true; - //because Blueprint auto-generates $modelName - $dummymodel = $this->model; // create... } + // OPTIONAL, method exists in tall-form component public function onUpdateModel($validated_data) { - $this->model->update($validated_data); - //because Blueprint auto-generates $modelName - $dummymodel = $this->model; // update... } + // OPTIONAL, method exists in tall-form component public function onDeleteModel() { - //for session flash message - $className = class_basename($this->model); - //if you want to pass the model data somewhere with the data after model is deleted - $modelArray = $this->model->toArray(); - $this->model->delete(); + $dummymodel = $this->model; // delete... }