diff --git a/CHANGELOG.md b/CHANGELOG.md index f35e66b..86c27f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to `model-required-fields` will be documented in this file. +## 3.1.1 - 2025-09-20 + +### What's Changed + +* Add documentation for console commands + +**Full Changelog**: https://github.com/WatheqAlshowaiter/model-fields/compare/3.1.0...3.1.1 + +## 3.1.0 - 2025-09-20 + +### What's Changed + +* feat: add askToStarRepository command by @WatheqAlshowaiter in https://github.com/WatheqAlshowaiter/model-fields/pull/26 + +**Full Changelog**: https://github.com/WatheqAlshowaiter/model-fields/compare/3.0.2...3.1.0 + ## 3.0.2 - 2025-09-19 Fix banner when install diff --git a/README.md b/README.md index b3fa679..cd22b67 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,8 @@ Think that's simple? You probably haven’t faced the legacy projects I have. :) > [!Note] > This is the documentation for version 3, if you want the version 1 or version 2 documentations go -> V1 with [this link](./v1.documentation.md). -> V2 with [this link](./v2.documentation.md). +> V2 with [this link](./v2.documentation.md).\ +> V1 with [this link](./v1.documentation.md). ## Installation @@ -84,9 +84,9 @@ Schema::create('users', function (Blueprint $table) { > We have two ways: > - Either use the `ModelFields` facade. > - Or use the method statically on the model. (using the magic of laravel macros). +> - Or use the `model:fields` console command. -We will explain the **macro way** in two examples, and the other will be only using the **facade way** and all the -methods in both ways are the same. +Here is the sample: ```php // Facade way @@ -103,9 +103,15 @@ User::allFields(); // returns ['id', 'name', 'email', 'email_verified_at', 'pass User::requiredFields(); // returns ['name', 'email', 'password'] ``` +```sh +# console command +php artisan model:fields \\App\\Models\\User --all --format=json +php artisan model:fields "App\Models\User" --required --format=table +``` + That's it! -> [!NOTE] +> [!NOTE] > To disable the macro approach, set the `enable_macro` value to false in the published `model-fields.php` > configuration file. @@ -143,13 +149,19 @@ Fields::model(Post::class)->requiredFields(); // returns ['user_id', 'ulid', 'ti Post::requiredFields(); // returns ['user_id', 'ulid', 'title', 'description'] ``` +```sh +# console command +php artisan model:fields App\\Models\\Post --required # or -r +``` + ### And more We have the flexibility to get all fields, required fields, nullable fields, primary key, database default fields, application default fields, and default fields. You can use these methods with these results: +#### All fields + ```php -// All fields Fields::model(Post::class)->allFields(); // or @@ -161,8 +173,13 @@ Post::allFields(); // ] ``` +```sh +php artisan model:fields App\\Models\\Post --all # or just the model without option because it is the default +``` + +#### Nullable fields + ```php -// Nullable fields Fields::model(Post::class)->nullableFields(); //or @@ -175,8 +192,14 @@ Post::nullableFields(); // ] ``` +```sh +# console command +php artisan model:fields App\\Models\\Post --nullable # or -N +``` + +#### Primary field + ```php -// Primary field Fields::model(Post::class)->primaryField(); // or @@ -185,8 +208,14 @@ Post::primaryField(); // returns ['id'] ``` +```sh +# console command +php artisan model:fields User --primary # or -p +``` + +#### Database default fields + ```php -// Database default fields Fields::model(Post::class)->databaseDefaultFields(); //or @@ -195,8 +224,14 @@ Post::databaseDefaultFields(); // returns ['active'] ``` +```sh +# console command +php artisan model:fields User --db-default # or -D +``` + +#### Application default fields + ```php -// Application default fields Fields::model(Post::class)->applicationDefaultFields(); //or @@ -217,8 +252,14 @@ class Post extends Model // ] ``` +```sh +#console command +php artisan model:fields User --app-default # or -A +``` + +#### Default fields + ```php -// Default fields Fields::model(Post::class)->defaultFields(); //or @@ -239,13 +280,49 @@ class Post extends Model // ] ``` +```sh +#console command +php artisan model:fields User --default # or -d +``` + +### More on console commands + +- All fields is the default option if you didn't specify one. + +```sh +php artisan model:fields \\App\\Models\\Post # will result all fields +``` + +- The package will try to find models in common places if you don't provide full namespace. + +```sh +php artisan model:fields User # It will try to find the model in `App\Models\User` or `App\User` namespaces +``` + +- You can add namespaces in two ways: in two backslashes `\\` or inside double quotes `""`. This is a laravel thing and + not specific to the package. + +```sh +php artisan model:fields \\Modules\\Order\\src\\Models\\Order +# or +php artisan model:fields "Modules\Order\src\Models\Order" +``` + +- You have 3 output formats: list, json and table. the list is the default + +```sh +php artisan model:fields User --format=json +php artisan model:fields User --format=table +php artisan model:fields User --format=list # default +``` + ## Why? ### The problem I wanted to add tests to a legacy project that didn't have any. I wanted to add tests but couldn't find a factory, so I tried building them. However, it was hard to figure out the required fields for testing the basic functionality since -some tables have too many fields. +some tables have too many fields across many migration files. ### The Solution @@ -266,6 +343,8 @@ So Briefly, This package is useful if: ✅ Supports PHP versions: 8.4, 8.3, 8.2, 8.1, 8.0, and 7.4. +✅ Supports multiple ways of fetching fields: using console commands, or facades, or models macros. + ✅ Supports SQL databases: SQLite, MySQL/MariaDB, PostgreSQL, and SQL Server. ✅ Fully automated tested with PHPUnit. diff --git a/composer.json b/composer.json index ec683f8..3c71ff9 100644 --- a/composer.json +++ b/composer.json @@ -58,10 +58,7 @@ "@composer run build", "@php vendor/bin/testbench serve" ], - "test": "vendor/bin/phpunit", - "post-autoload-dump": [ - "@php -r \"class_exists('WatheqAlshowaiter\\\\ModelFields\\\\Console\\\\ThanksCommand') && WatheqAlshowaiter\\\\ModelFields\\\\Console\\\\ThanksCommand::show();\"" - ] + "test": "vendor/bin/phpunit" }, "config": { "sort-packages": true, diff --git a/src/Console/ModelFieldsCommand.php b/src/Console/ModelFieldsCommand.php new file mode 100644 index 0000000..b8da93d --- /dev/null +++ b/src/Console/ModelFieldsCommand.php @@ -0,0 +1,245 @@ +argument('model'); + $format = $this->option('format'); + + if (! in_array($format, ['list', 'json', 'table'])) { + $this->error("Invalid format '$format'. Use: list, json, or table."); + + return 1; + } + + $modelClass = $this->resolveModelClass($modelName); + + if (! $modelClass) { + $this->error("Model class '$modelName' not found."); + + return 1; + } + + $type = $this->determineType(); + + if ($type === -1) { // error of adding more than one field type + return 1; + } + + $fields = $this->getFieldsByType($modelClass, $type); + + $this->outputFields($fields, $format, $type, $modelClass); + + $this->askToStarRepository(); + + return 0; + } + + /** + * @return string|null + */ + protected function resolveModelClass(string $modelName) + { + // Try as-is first + if (class_exists($modelName) && $this->isEloquentModel($modelName)) { + return $modelName; + } + + // Try common paths with proper case + $modelName = ucfirst($modelName); + $possibleClasses = [ + "App\\Models\\$modelName", + "App\\$modelName", + ]; + + foreach ($possibleClasses as $class) { + if (class_exists($class) && $this->isEloquentModel($class)) { + return $class; + } + } + + return null; + } + + /** + * @return bool + */ + private function isEloquentModel(string $class) + { + return is_subclass_of($class, 'Illuminate\Database\Eloquent\Model'); + } + + /** + * @return int|string + */ + protected function determineType() + { + $validTypes = ['all', 'required', 'nullable', 'primary', 'default', 'app-default', 'db-default']; + $selectedTypes = []; + + foreach ($validTypes as $type) { + if ($this->option($type)) { + $selectedTypes[] = $type; + } + } + + if (count($selectedTypes) > 1) { + $this->error('Please specify only one field type option.'); + + return -1; + } + + if (count($selectedTypes) === 1) { + return $selectedTypes[0]; + } + + return 'all'; // default if no flags are set + } + + /** + * @param string $modelClass + * @param string $type + * @return array + */ + protected function getFieldsByType($modelClass, $type) + { + switch ($type) { + case 'required': + return Fields::model($modelClass)->requiredFields(); + case 'nullable': + return Fields::model($modelClass)->nullableFields(); + case 'primary': + return Fields::model($modelClass)->primaryField(); + case 'default': + return Fields::model($modelClass)->defaultFields(); + case 'app-default': + return Fields::model($modelClass)->applicationDefaultFields(); + case 'db-default': + return Fields::model($modelClass)->databaseDefaultFields(); + case 'all': + default: + return Fields::model($modelClass)->allFields(); + } + } + + /** + * @param array $fields + * @param string $format + * @param string $type + * @param string $modelClass + * @return void + */ + protected function outputFields($fields, $format, $type, $modelClass) + { + $modelName = class_basename($modelClass); + + switch ($format) { + case 'json': + if (empty($fields)) { + $this->info("No $type fields found for $modelName model."); + + return; + } + + /** @noinspection PhpComposerExtensionStubsInspection */ + $this->line(json_encode($fields, JSON_PRETTY_PRINT)); + break; + + case 'table': + if (empty($fields)) { + $this->info("No $type fields found for $modelName model."); + + return; + } + + $tableData = array_map(function ($field) { + return [$field]; + }, $fields); + $this->table(["$modelName $type fields"], $tableData); + break; + + case 'list': + default: + if (empty($fields)) { + $this->info("No $type fields found for $modelName model."); + + return; + } + + $this->info("$modelName $type fields:"); + foreach ($fields as $field) { + $this->line(" - $field"); + } + break; + } + } + + /** + * Ask user to star the GitHub repository for only the first time he uses the package in terminal + * + * @return void + */ + private function askToStarRepository() + { + if (! $this->input->isInteractive()) { + return; + } + + $cacheKey = 'model-fields.banner_shown'; + $repo = 'https://github.com/WatheqAlshowaiter/model-fields'; + + if (Cache::get($cacheKey)) { + return; + } + + $wantsToStar = $this->confirm( + '🌟 Help other developers find this package by starring it on GitHub?' + ); + + if ($wantsToStar) { + $this->openUrl($repo); + $this->info('Thank you!'); + } + + Cache::forever($cacheKey, true); + } + + /** + * @return void + */ + protected function openUrl(string $url) + { + if (PHP_OS_FAMILY === 'Darwin') { + $command = 'open'; + } elseif (PHP_OS_FAMILY === 'Windows') { + $command = 'start'; + } else { + $command = 'xdg-open'; + } + + exec(sprintf('%s %s', $command, escapeshellarg($url))); + } +} diff --git a/src/Console/ThanksCommand.php b/src/Console/ThanksCommand.php deleted file mode 100644 index 3d9a9af..0000000 --- a/src/Console/ThanksCommand.php +++ /dev/null @@ -1,65 +0,0 @@ -environment() === 'testing'; - } - - protected static function openUrl(string $url): void - { - switch (PHP_OS_FAMILY) { - case 'Darwin': - $command = 'open'; - break; - case 'Windows': - $command = 'start'; - break; - default: - $command = 'xdg-open'; - break; - } - - exec(sprintf('%s %s', $command, escapeshellarg($url))); - } -} diff --git a/src/ModelFieldsServiceProvider.php b/src/ModelFieldsServiceProvider.php index 8c3400b..de754a8 100644 --- a/src/ModelFieldsServiceProvider.php +++ b/src/ModelFieldsServiceProvider.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider; +use WatheqAlshowaiter\ModelFields\Console\ModelFieldsCommand; use WatheqAlshowaiter\ModelFields\Exceptions\UnsupportedDatabaseDriverException; use WatheqAlshowaiter\ModelFields\Support\Helpers; @@ -23,6 +24,10 @@ public function boot() __DIR__.'/config.php' => config_path('model-fields.php'), ], 'config'); + $this->commands([ + ModelFieldsCommand::class, + ]); + if ($this->app->environment() === 'testing') { // This migration works only in the package test $this->loadMigrationsFrom(__DIR__.'/../tests/database/migrations'); diff --git a/tests/FieldsTest.php b/tests/FieldsTest.php index bbe7c79..3227b61 100644 --- a/tests/FieldsTest.php +++ b/tests/FieldsTest.php @@ -2,10 +2,13 @@ namespace WatheqAlshowaiter\ModelFields\Tests; +use BadMethodCallException; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Schema; +use ReflectionClass; +use ReflectionException; use WatheqAlshowaiter\ModelFields\Exceptions\InvalidModelClassException; use WatheqAlshowaiter\ModelFields\Fields; use WatheqAlshowaiter\ModelFields\Tests\Models\Brother; @@ -20,7 +23,7 @@ class FieldsTest extends TestCase use RefreshDatabase; /** - * @throws \ReflectionException + * @throws ReflectionException */ public function test_get_required_fields_only_if_config_enabled_macro() { @@ -29,7 +32,7 @@ public function test_get_required_fields_only_if_config_enabled_macro() */ $this->removeMacro(Builder::class, 'requiredFields'); - $this->expectException(\BadMethodCallException::class); + $this->expectException(BadMethodCallException::class); Father::requiredFields(); } @@ -54,10 +57,14 @@ public static function requiredFields() }; $this->assertEquals(['some_field'], $testModelClass::requiredFields()); + + // but other methods works fine + $this->assertEquals(['created_at', 'updated_at'], $testModelClass::nullableFields()); + } /** - * @throws \ReflectionException + * @throws ReflectionException */ private function removeMacro(string $class, string $macro): void { @@ -65,7 +72,7 @@ private function removeMacro(string $class, string $macro): void return; } - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); $property = $reflection->getProperty('macros'); $property->setAccessible(true); diff --git a/tests/ModelFieldsCommandTest.php b/tests/ModelFieldsCommandTest.php new file mode 100644 index 0000000..aca36f4 --- /dev/null +++ b/tests/ModelFieldsCommandTest.php @@ -0,0 +1,260 @@ +expectException(RuntimeException::class); + $this->expectExceptionMessage('Not enough arguments (missing: "model").'); + + $this->artisan('model:fields'); + } + + public function test_fail_when_no_actual_model_provided() + { + $this->artisan('model:fields', ['model' => 'NonExistentModel']) + ->expectsOutput("Model class 'NonExistentModel' not found.") + ->assertExitCode(self::FAILURE_EXIT_CODE); + } + + public function test_failed_when_format_option_is_not_valid() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "format" argument does not exist.'); + + $this->artisan('model:fields', ['model' => Father::class, 'format' => 'graph']); + } + + public function test_failed_when_format_value_is_not_valid() + { + $invalidFormat = 'something'; + + $this->artisan('model:fields', [ + 'model' => Father::class, + '--required' => true, + '--format' => $invalidFormat, + ])->expectsOutput("Invalid format '$invalidFormat'. Use: list, json, or table.") + ->assertExitCode(self::FAILURE_EXIT_CODE); + } + + public function test_use_list_format_when_not_provided() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', ['model' => Father::class]) + ->assertExitCode(self::SUCCESS_EXIT_CODE); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_fail_when_provided_more_than_one_field_type() + { + $this->artisan('model:fields', [ + 'model' => Father::class, + '--required' => true, + '--nullable' => true, + ]) + ->expectsOutput('Please specify only one field type option.') + ->assertExitCode(self::FAILURE_EXIT_CODE); + } + + public function test_default_to_all_fields_when_no_type_specified() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + ]) + ->expectsOutput('Father all fields:') + ->expectsOutput(' - id') + ->expectsOutput(' - active') + ->expectsOutput(' - name') + ->expectsOutput(' - email') + ->expectsOutput(' - username') + ->expectsOutput(' - created_at') + ->expectsOutput(' - updated_at') + ->expectsOutput(' - deleted_at'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_uses_type_when_specified() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + '--required' => true, + ]) + ->expectsOutput('Father required fields:') + ->expectsOutput(' - name') + ->expectsOutput(' - email'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_uses_type_shortname_when_specified() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + '-r' => true, + ]) + ->expectsOutput('Father required fields:') + ->expectsOutput(' - name') + ->expectsOutput(' - email'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_json_format() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + '--nullable' => true, + '--format' => 'json', + ]) + ->expectsOutput('[ + "username", + "created_at", + "updated_at", + "deleted_at" +]'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_table_format() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + '--primary' => true, + '--format' => 'table', + ]) + ->expectsOutput('+-----------------------+') + ->expectsOutput('| Father primary fields |') + ->expectsOutput('+-----------------------+') + ->expectsOutput('| id |') + ->expectsOutput('+-----------------------+'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_json_format_with_empty_results() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + '-A' => true, + '--format' => 'json', + ])->expectsOutput('No app-default fields found for Father model.'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_table_format_with_empty_results() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + '-A' => true, + '--format' => 'table', + ])->expectsOutput('No app-default fields found for Father model.'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_list_format_with_empty_results() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + '-A' => true, + ])->expectsOutput('No app-default fields found for Father model.'); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_does_not_ask_if_already_cached() + { + Cache::forever('model-fields.banner_shown', true); + + $this->artisan('model:fields', [ + 'model' => Father::class, + ])->assertExitCode(0); + + $this->assertTrue(Cache::get('model-fields.banner_shown')); + + Cache::forget('model-fields.banner_shown'); + } + + public function test_asks_and_user_declines() + { + Cache::forget('model-fields.banner_shown'); + + $this->artisan('model:fields', [ + 'model' => Father::class, + ]) + ->expectsQuestion('🌟 Help other developers find this package by starring it on GitHub?', false) + ->assertExitCode(self::SUCCESS_EXIT_CODE); + + $this->assertTrue(Cache::get('model-fields.banner_shown')); + Cache::forget('model-fields.banner_shown'); + } + + public function test_asks_and_user_accepts() + { + Cache::forget('model-fields.banner_shown'); + + // Create a subclass that overrides openUrl() + $stubCommand = new class extends ModelFieldsCommand + { + public string $calledWith = ''; + + // Change to protected so test can inspect + protected function openUrl(string $url): void + { + // Do NOT actually exec() — just record that it was called + $this->calledWith = $url; + } + }; + + // Replace the command in Laravel's container so artisan uses our stub + $this->app->extend(ModelFieldsCommand::class, fn () => $stubCommand); + + $this->artisan('model:fields', [ + 'model' => Father::class, + ]) + ->expectsQuestion('🌟 Help other developers find this package by starring it on GitHub?', true) + ->expectsOutput('Thank you!') + ->assertExitCode(self::SUCCESS_EXIT_CODE); + + $this->assertStringContainsString('github.com/WatheqAlshowaiter/model-fields', $stubCommand->calledWith); + + Cache::forget('model-fields.banner_shown'); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 20e9973..e6b4793 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -87,7 +87,7 @@ public function getEnvironmentSetUp($app) // if not supported above then stop the test if (! in_array($dbConnection, ['mysql', 'mariadb', 'pgsql', 'sqlite', 'sqlsrv'])) { - echo "database {$dbConnection} is not supported"; + echo "database $dbConnection is not supported"; exit; } } diff --git a/tests/ThanksCommandTest.php b/tests/ThanksCommandTest.php deleted file mode 100644 index c4294cd..0000000 --- a/tests/ThanksCommandTest.php +++ /dev/null @@ -1,105 +0,0 @@ -assertTrue(class_exists(ThanksCommand::class)); - $this->assertTrue(method_exists(ThanksCommand::class, 'show')); - } - - public function test_cache_logic() - { - // Ensure cache key doesn't exist initially - Cache::forget('model-fields.banner_shown'); - $this->assertFalse(Cache::get('model-fields.banner_shown', false)); - - // Set cache manually to test the "already shown" logic - Cache::forever('model-fields.banner_shown', true); - $this->assertTrue(Cache::get('model-fields.banner_shown')); - - // Clean up for next test - Cache::forget('model-fields.banner_shown'); - $this->assertFalse(Cache::get('model-fields.banner_shown', false)); - } - - public function test_show_outputs_message_and_sets_cache() - { - // Clear cache and simulate non-CI environment - Cache::forget('model-fields.banner_shown'); - putenv('CI'); - - // Mock posix_isatty to return true (interactive terminal) - if (! function_exists('posix_isatty')) { - function posix_isatty($fd) - { - return true; - } - } - - // Create a mock stream for stdin - $input = fopen('php://memory', 'r+'); - fwrite($input, "n\n"); - rewind($input); - - // Use reflection to temporarily replace the input handling - ob_start(); - - // Since we can't easily mock stdin in the show method, we'll test the cache behavior - // and verify that the method runs without CI detection - $reflection = new \ReflectionMethod(ThanksCommand::class, 'runningInCi'); - $reflection->setAccessible(true); - - // Test that in testing environment, runningInCi returns true - $this->assertTrue($reflection->invoke(null)); - - // Therefore show() should return early and not output anything - ThanksCommand::show(); - $output = ob_get_clean(); - - $this->assertEmpty($output); - $this->assertFalse(Cache::get('model-fields.banner_shown', false)); - - fclose($input); - } - - public function test_show_skips_in_ci_environment() - { - Cache::forget('model-fields.banner_shown'); - putenv('CI=1'); // simulate CI environment - - ob_start(); - ThanksCommand::show(); // should skip showing - $output = ob_get_clean(); - - $this->assertEmpty($output, 'Expected no output in CI environment'); - - putenv('CI'); // clean up - } - - public function test_running_in_ci_detects_testing_environment() - { - // app()->environment() returns 'testing' in PHPUnit - $reflection = new \ReflectionMethod(ThanksCommand::class, 'runningInCi'); - $reflection->setAccessible(true); - $this->assertTrue($reflection->invoke(null)); - } - - public function test_cache_key_constant() - { - $reflection = new \ReflectionClass(ThanksCommand::class); - $constant = $reflection->getConstant('CACHE_KEY'); - $this->assertEquals('model-fields.banner_shown', $constant); - } -} diff --git a/tests/database/migrations/2024_07_13_090447_create_fathers_table.php b/tests/database/migrations/2024_07_13_090447_create_fathers_table.php index 845b517..a134095 100644 --- a/tests/database/migrations/2024_07_13_090447_create_fathers_table.php +++ b/tests/database/migrations/2024_07_13_090447_create_fathers_table.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Schema; use WatheqAlshowaiter\ModelFields\Tests\Constants; +/** @noinspection PhpIllegalPsrClassPathInspection */ class CreateFathersTable extends Migration { public function up(): void @@ -27,6 +28,6 @@ public function up(): void public function down(): void { - Schema::dropIfExists('parent_test_models'); + Schema::dropIfExists('fathers'); } } diff --git a/tests/database/migrations/2024_07_13_093048_create_mothers_table.php b/tests/database/migrations/2024_07_13_093048_create_mothers_table.php index cd35f70..d7432ff 100644 --- a/tests/database/migrations/2024_07_13_093048_create_mothers_table.php +++ b/tests/database/migrations/2024_07_13_093048_create_mothers_table.php @@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Schema; use WatheqAlshowaiter\ModelFields\Tests\Constants; +/** @noinspection PhpIllegalPsrClassPathInspection */ class CreateMothersTable extends Migration { public function up(): void @@ -41,6 +42,6 @@ public function up(): void public function down(): void { - Schema::dropIfExists('another_parent_test_models'); + Schema::dropIfExists('mothers'); } } diff --git a/tests/database/migrations/2024_07_13_100247_create_sons_table.php b/tests/database/migrations/2024_07_13_100247_create_sons_table.php index f68c21e..8fb2d84 100644 --- a/tests/database/migrations/2024_07_13_100247_create_sons_table.php +++ b/tests/database/migrations/2024_07_13_100247_create_sons_table.php @@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Schema; use WatheqAlshowaiter\ModelFields\Tests\Constants; +/** @noinspection PhpIllegalPsrClassPathInspection */ class CreateSonsTable extends Migration { public function up(): void diff --git a/tests/database/migrations/2025_02_14_100247_create_brothers_table.php b/tests/database/migrations/2025_02_14_100247_create_brothers_table.php index 406ecb0..86bd79d 100644 --- a/tests/database/migrations/2025_02_14_100247_create_brothers_table.php +++ b/tests/database/migrations/2025_02_14_100247_create_brothers_table.php @@ -4,6 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +/** @noinspection PhpIllegalPsrClassPathInspection */ class CreateBrothersTable extends Migration { public function up(): void diff --git a/todos.md b/todos.md index c01cffe..cff7cd7 100644 --- a/todos.md +++ b/todos.md @@ -40,14 +40,32 @@ - [x] Fields::model(User::class)->defaultFields() // both database and laravel fields - [x] Fields::model(User::class)->allFields() // all fields - [x] fix postgres database for databaseDefaultFields -- [x] fix SQLServer in github action +- [x] fix SQLServer in github action - [x] fix all todos - [x] return github actions -- [x] add all what is inside FieldsTest to Builder::macros +- [x] add all what is inside FieldsTest to Builder::macros - [x] change the readme docs in response to that -- [x] change the banner +- [x] change the banner - [x] in next version change the whole namespace, github about to model fields - [x] remove old code that is not in v3 - [x] star after install -- [ ] (next version) make commands like backup:tables -- [ ] (next version) exclude from required fields that are filled in "creating" observers/events and add test cases for that +- [ ] make model:fields command + - [x] signature + - [x] improve signature without types + - [x] if --type is is not correct through an exception + - [x] make appreciation for types like required/r, nullable, json|array etc and make naming consistent and + symmetric + - [x] improve $description + - [x] improve resolveModelClass + - [x] make sure cache is working correctly for github star + - [x] in format=table "Field Name" should be the actual field name + - [x] remove unuseful try catch + - [x] test each step + - [x] for testing ask to star I need + - [x] test cache key + - [x] test output + - [x] test opening the url (mocking with reflectionClass) + - [x] make sure $this->input->isInteractive() it enough + - [ ] add new changes in using the terminal to the docs +- [ ] (next version) exclude from required fields that are filled in "creating" observers/events and add test cases for + that