├── .all-contributorsrc ├── .github └── workflows │ ├── composer-normalize.yml │ └── run-tests.yml ├── .gitignore ├── .styleci.yml ├── README.md ├── changelog.md ├── code_of_conduct.md ├── composer.json ├── config └── laravel-resources.php ├── contributing.md ├── docs └── demo.gif ├── license.md ├── phpunit.xml ├── src ├── Commands │ └── ResourceCommand.php ├── Exceptions │ └── File.php ├── Generators │ ├── AbstractGenerator.php │ ├── CollectionGenerator.php │ ├── ControllerGenerator.php │ ├── FactoryGenerator.php │ ├── Generator.php │ ├── MigrationGenerator.php │ ├── ModelGenerator.php │ ├── PolicyGenerator.php │ ├── RequestGenerator.php │ ├── ResourceGenerator.php │ ├── RouteGenerator.php │ └── SeederGenerator.php ├── Helpers │ └── helpers.php ├── LaravelResourcesServiceProvider.php └── stubs │ ├── controllers │ ├── controller.method.destroy.stub │ ├── controller.method.index.stub │ ├── controller.method.show.stub │ ├── controller.method.store.stub │ ├── controller.method.update.stub │ └── controller.stub │ ├── factories │ └── factory.stub │ ├── migrations │ └── migration.stub │ ├── models │ └── model.stub │ ├── policies │ └── api.policies.stub │ ├── requests │ └── api.request.stub │ ├── resources │ ├── api.collection.stub │ └── api.resource.stub │ ├── routes │ └── api.routes.stub │ └── seeds │ └── seed.stub └── tests ├── CollectionGeneratorTest.php ├── ControllerGeneratorTest.php ├── FactoryGeneratorTest.php ├── MigrationGeneratorTest.php ├── ModelGeneratorTest.php ├── PolicyGeneratorTest.php ├── RequestGeneratorTest.php ├── ResourceCommandTest.php ├── ResourceGeneratorTest.php ├── SeederGeneratorTest.php └── TestCase.php /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "RafaelFerreiraTVD", 10 | "name": "Rafael Ferreira", 11 | "avatar_url": "https://avatars1.githubusercontent.com/u/15105462?v=4", 12 | "profile": "http://www.xgeeks.io", 13 | "contributions": [ 14 | "doc" 15 | ] 16 | }, 17 | { 18 | "login": "tiagomichaelsousa", 19 | "name": "tiagomichaelsousa", 20 | "avatar_url": "https://avatars1.githubusercontent.com/u/28356381?v=4", 21 | "profile": "https://github.com/tiagomichaelsousa", 22 | "contributions": [ 23 | "code", 24 | "doc", 25 | "content", 26 | "review" 27 | ] 28 | }, 29 | { 30 | "login": "white-hyena", 31 | "name": "White Hyena", 32 | "avatar_url": "https://avatars3.githubusercontent.com/u/62600397?v=4", 33 | "profile": "https://github.com/white-hyena", 34 | "contributions": [ 35 | "code", 36 | "content" 37 | ] 38 | }, 39 | { 40 | "login": "pkboom", 41 | "name": "Keunbae Park", 42 | "avatar_url": "https://avatars2.githubusercontent.com/u/13960169?v=4", 43 | "profile": "https://github.com/pkboom", 44 | "contributions": [ 45 | "code", 46 | "content" 47 | ] 48 | } 49 | ], 50 | "contributorsPerLine": 7, 51 | "projectName": "LaravelResources", 52 | "projectOwner": "tiagomichaelsousa", 53 | "repoType": "github", 54 | "repoHost": "https://github.com", 55 | "skipCi": true 56 | } 57 | -------------------------------------------------------------------------------- /.github/workflows/composer-normalize.yml: -------------------------------------------------------------------------------- 1 | name: Composer Normalize 2 | 3 | on: 4 | push: 5 | paths: 6 | - "composer.json" 7 | 8 | jobs: 9 | normalize: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Git checkout 13 | uses: actions/checkout@v3 14 | 15 | - name: normalize composer.json 16 | run: | 17 | composer global require ergebnis/composer-normalize 18 | composer normalize 19 | - uses: stefanzweifel/git-auto-commit-action@v4 20 | with: 21 | commit_message: Normalize composer.json 22 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: ['push', 'pull_request'] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | php: 13 | - '8.0' 14 | - '8.1' 15 | - '8.2' 16 | laravel: 17 | - 8.* 18 | - 9.* 19 | - 10.* 20 | prefer: 21 | - 'prefer-stable' 22 | include: 23 | - laravel: 8.* 24 | testbench: 6.* 25 | - laravel: 9.* 26 | testbench: 7.* 27 | - laravel: 10.* 28 | testbench: 8.* 29 | exclude: 30 | - laravel: 10.* 31 | php: 8.0 32 | 33 | name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} --${{ matrix.prefer }} 34 | 35 | steps: 36 | - uses: actions/checkout@v2.4.0 37 | 38 | - name: Setup PHP 39 | uses: shivammathur/setup-php@v2 40 | with: 41 | php-version: ${{ matrix.php }} 42 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, yaml 43 | coverage: pcov 44 | 45 | - uses: actions/cache@v2.1.7 46 | name: Cache dependencies 47 | with: 48 | path: ~/.composer/cache/files 49 | key: composer-php-${{ matrix.php }}-${{ matrix.laravel }}-${{ matrix.prefer }}-${{ hashFiles('composer.json') }} 50 | 51 | - name: Install dependencies 52 | run: | 53 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 54 | composer update --${{ matrix.prefer }} --prefer-dist --no-interaction --no-suggest 55 | 56 | - name: Run tests 57 | run: | 58 | vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.result.cache 2 | /build/ 3 | /vendor/ 4 | /tests/temp 5 | composer.lock 6 | composer.phar 7 | .idea 8 | /report 9 | .DS_Store 10 | coverage.clover 11 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel 2 | 3 | finder: 4 | name: 5 | - "*.php" 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Resources 2 | 3 |

4 | Laravel Resources Demo 5 |

6 | 7 |

8 | Packagist Version 9 | Packagist Downloads 10 | Build Status 11 | Style Status 12 | Licence 13 | All Contributors 14 | Code Quality 15 | Code Coverage 16 | 17 |

18 | 19 | --- 20 | 21 | Laravel Resources is a speed-up development package that allows you to create a boilerplate for Laravel apps with a default API structure. 22 | 23 | ## Versions 24 | 25 | | Laravel | Laravel Resources | 26 | |----------| ----------------- | 27 | | 7.x | v1.7 | 28 | | 8.x | v2.x | 29 | | 9.x | v2.x | 30 | | 10.x | v3.x | 31 | 32 | ## Installation 33 | 34 | Via Composer 35 | 36 | ```bash 37 | $ composer require tiagomichaelsousa/laravelresources --dev 38 | ``` 39 | 40 | ## Usage 41 | 42 | Create the resources 43 | 44 | ```bash 45 | $ php artisan resources:create 46 | ``` 47 | 48 | This command will create the Controller, the Request, the Policy, the API Resource and Collection and will also add the default routes for the API. 49 | 50 | Publish configuration file 51 | 52 | ```bash 53 | $ php artisan vendor:publish --provider="tiagomichaelsousa\LaravelResources\LaravelResourcesServiceProvider" --tag="config" 54 | ``` 55 | 56 | **Notes:** 57 | 58 | - This package is fully configurable. You can change all the namespaces for the resources that will be created in the config file. 59 | - Don't forget to edit the request file in order to add your default validation for the model. 60 | - Don't forget to edit the policy file in order to fulfill your app business logic. 61 | 62 | ## Change log 63 | 64 | Please see the [changelog](changelog.md) for more information on what has changed recently. 65 | 66 | ## Testing 67 | 68 | ```bash 69 | $ composer test 70 | ``` 71 | 72 | ### With test coverage 73 | 74 | ```bash 75 | $ composer test-report 76 | ``` 77 | 78 | ## Contributing 79 | 80 | Please see [contributing.md](contributing.md) for details and a todolist. 81 | 82 | ## Security 83 | 84 | If you discover any security related issues, please email the [author](mailto:tiagomichaelsousa@gmail.com) instead of using the issue tracker. 85 | 86 | ## Credits 87 | 88 | - [@tiagomichaelsousa][link-author] 89 | - [All Contributors][link-contributors] 90 | 91 | ## License 92 | 93 | License MIT. Please see the [license file](license.md) for more information. 94 | 95 | ## Code Of Conduct 96 | 97 | Please see the [code of conduct](code_of_conduct.md) for more information. 98 | 99 | [ico-version]: https://img.shields.io/packagist/v/tiagomichaelsousa/laravelresources.svg?style=flat-square 100 | [ico-downloads]: https://img.shields.io/packagist/dt/tiagomichaelsousa/laravelresources.svg?style=flat-square 101 | [ico-travis]: https://img.shields.io/travis/tiagomichaelsousa/laravelresources/master.svg?style=flat-square 102 | [ico-styleci]: https://github.styleci.io/repos/236964942/shield 103 | [link-packagist]: https://packagist.org/packages/tiagomichaelsousa/laravelresources 104 | [link-downloads]: https://packagist.org/packages/tiagomichaelsousa/laravelresources 105 | [link-travis]: https://travis-ci.org/tiagomichaelsousa/laravelresources 106 | [link-styleci]: https://styleci.io/repos/236964942 107 | [link-author]: https://github.com/tiagomichaelsousa 108 | [link-contributors]: ../../contributors 109 | 110 | ## Contributors ✨ 111 | 112 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 |

Rafael Ferreira

📖

tiagomichaelsousa

💻 📖 🖋 👀

White Hyena

💻 🖋

Keunbae Park

💻 🖋
125 | 126 | 127 | 128 | 129 | 130 | 131 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 132 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `LaravelResources` will be documented in this file. 4 | 5 | ## Version 1.0 6 | 7 | ### Added 8 | - Everything 9 | -------------------------------------------------------------------------------- /code_of_conduct.md: -------------------------------------------------------------------------------- 1 | # Code Of Conductd 2 | 3 | This code of conduct is derived from the Ruby code of conduct. Any violations of the code of conduct may be reported to [author](tiagomichaelsousa@gmail.com). 4 | 5 | - Participants will be tolerant of opposing views. 6 | - Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. 7 | - When interpreting the words and actions of others, participants should always assume good intentions. 8 | - Behavior which can be reasonably considered harassment will not be tolerated. 9 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiagomichaelsousa/laravelresources", 3 | "description": "Laravel Resources is a speed-up development package that allows you to create a boilerplate for Laravel apps with a default API structure.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "tiagomichaelsousa", 8 | "email": "tiagomichaelsousa@gmail.com", 9 | "homepage": "https://github.com/tiagomichaelsousa", 10 | "role": "Developer" 11 | } 12 | ], 13 | "homepage": "https://github.com/tiagomichaelsousa/laravelresources", 14 | "keywords": [ 15 | "Laravel", 16 | "LaravelResources", 17 | "laravelresources", 18 | "laravel-resources" 19 | ], 20 | "require": { 21 | "illuminate/support": "^7.0|^8.0|^9.0|^10.0" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "^8.5|^9.0|^10.0", 25 | "mockery/mockery": "^1.3.1", 26 | "sempro/phpunit-pretty-print": "^1.4", 27 | "orchestra/testbench": "^8.5" 28 | }, 29 | "autoload": { 30 | "files": [ 31 | "src/Helpers/helpers.php" 32 | ], 33 | "psr-4": { 34 | "tiagomichaelsousa\\LaravelResources\\": "src/" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "psr-4": { 39 | "tiagomichaelsousa\\LaravelResources\\Tests\\": "tests" 40 | } 41 | }, 42 | "scripts": { 43 | "test": "vendor/bin/phpunit", 44 | "test-report": "vendor/bin/phpunit --coverage-html report" 45 | }, 46 | "extra": { 47 | "laravel": { 48 | "providers": [ 49 | "tiagomichaelsousa\\LaravelResources\\LaravelResourcesServiceProvider" 50 | ], 51 | "aliases": { 52 | "LaravelResources": "tiagomichaelsousa\\LaravelResources\\Facades\\LaravelResources" 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /config/laravel-resources.php: -------------------------------------------------------------------------------- 1 | [ 16 | 'namespace' => 'App\Http\Controllers', 17 | 'suffix' => 'API', 18 | 'prefix' => null, 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Resources configs 24 | |-------------------------------------------------------------------------- 25 | | 26 | | This values are used when a new resource is created. 27 | | If you change the namespace, it will automatically create the resource in the folder base path. 28 | | The suffix and prefix are variables that can be edited to change the class name for the controller. 29 | | When you create a resource you can also create a collection that will inherit the data from the resource. 30 | | The collection class will also have the possibility to define the suffix and prefix for the class name. 31 | | 32 | */ 33 | 'resources' => [ 34 | 'namespace' => 'App\Http\Resources', 35 | 'suffix' => null, 36 | 'prefix' => null, 37 | ], 38 | 39 | 'collections' => [ 40 | 'namespace' => 'App\Http\Resources\Collections', 41 | 'suffix' => null, 42 | 'prefix' => null, 43 | ], 44 | 45 | /* 46 | |-------------------------------------------------------------------------- 47 | | Resources configs 48 | |-------------------------------------------------------------------------- 49 | | 50 | | This values are used when a new resource is created. 51 | | If you change the namespace, it will automatically create the resource in the folder base path. 52 | | The suffix and prefix are variables that can be edited to change the class name for the controller. 53 | | When you create a resource you can also create a collection that will inherit the data from the resource. 54 | | The collection class will also have the possibility to define the suffix and prefix for the class name. 55 | | 56 | */ 57 | 'requests' => [ 58 | 'namespace' => 'App\Http\Requests', 59 | 'suffix' => null, 60 | 'prefix' => null, 61 | ], 62 | 63 | /* 64 | |-------------------------------------------------------------------------- 65 | | Policies configs 66 | |-------------------------------------------------------------------------- 67 | | 68 | | This values are used when a new policy is created. 69 | | If you change the namespace, it will automatically create the resource in the folder base path. 70 | | The suffix and prefix are variables that can be edited to change the class name for the policy. 71 | | 72 | */ 73 | 'policies' => [ 74 | 'namespace' => 'App\Policies', 75 | 'suffix' => null, 76 | 'prefix' => null, 77 | ], 78 | 79 | /* 80 | |-------------------------------------------------------------------------- 81 | | Model configs 82 | |-------------------------------------------------------------------------- 83 | | 84 | | This config is used to fetch the models from the namespace. 85 | | Many projects change the path for the models to /app/models and thats the mainly reason 86 | | for the usage of this config value. 87 | | 88 | */ 89 | 'models' => [ 90 | 'namespace' => 'App\Models', 91 | ], 92 | 93 | /* 94 | |-------------------------------------------------------------------------- 95 | | Routes configs 96 | |-------------------------------------------------------------------------- 97 | | 98 | | This config is used set the path and the filename where the stubs for the routes 99 | | will be added. 100 | | 101 | */ 102 | 'routes' => [ 103 | 'path' => 'routes', 104 | 'filename' => 'api.php', 105 | ], 106 | 107 | /* 108 | |-------------------------------------------------------------------------- 109 | | Database configs 110 | |-------------------------------------------------------------------------- 111 | | 112 | | This config is used to set the path for the migrations, factories and seeds 113 | | This configs should not be edited if you dont change the laravel mapping folders 114 | | 115 | */ 116 | 'database' => [ 117 | 'migrations' => 'database/migrations', 118 | 'factories' => 'database/factories', 119 | 'seeds' => 'database/seeders', 120 | ], 121 | ]; 122 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome and will be fully credited. 4 | 5 | Contributions are accepted via Pull Requests on [Github](https://github.com/tiagomichaelsousa/laravelresources). 6 | 7 | # Things you could do 8 | 9 | If you want to contribute but do not know where to start, this list provides some starting points. 10 | 11 | - Set up TravisCI, StyleCI 12 | - Write a comprehensive ReadMe 13 | 14 | ## Pull Requests 15 | 16 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 17 | 18 | - **Document any change in behaviour** - Make sure the `readme.md` and any other relevant documentation are kept up-to-date. 19 | 20 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 21 | 22 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 23 | 24 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 25 | 26 | **Happy coding**! 27 | -------------------------------------------------------------------------------- /docs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiagomichaelsousa/LaravelResources/124fa0d81691a7e2dbb1922029bdd7700839c400/docs/demo.gif -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | # The license 2 | 3 | Copyright 2020 [@tiagomichaelsousa](https://github.com/tiagomichaelsousa) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src/ 6 | 7 | 8 | 9 | 10 | tests/ 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Commands/ResourceCommand.php: -------------------------------------------------------------------------------- 1 | MigrationGenerator::class, 41 | 'factory' => FactoryGenerator::class, 42 | 'seeder' => SeederGenerator::class, 43 | ]; 44 | 45 | /** 46 | * The model name for the resources. 47 | * 48 | * @var string 49 | */ 50 | private $model; 51 | 52 | /** 53 | * The name and signature of the console command. 54 | * 55 | * @var string 56 | */ 57 | protected $signature = 'resources:create 58 | {model : The model for the resource}'; 59 | 60 | /** 61 | * The console command description. 62 | * 63 | * @var string 64 | */ 65 | protected $description = 'This command will allow you to create all resources that you need for a clean api code structure'; 66 | 67 | /** 68 | * Verify if the model exists to create the resources. 69 | * 70 | * @return bool 71 | */ 72 | private function modelExists() 73 | { 74 | return File::exists(base_path(lcfirst(str_replace('\\', '/', config('laravel-resources.models.namespace'))))."/{$this->model}.php"); 75 | } 76 | 77 | /** 78 | * Create the model if does not exists. 79 | * 80 | * @return void 81 | */ 82 | private function createModelResources() 83 | { 84 | foreach ($this->modelResources as $resource => $generator) { 85 | if ($this->confirm("Should I create the {$resource} for {$this->model}?", true)) { 86 | array_push($this->resources, $generator); 87 | } 88 | } 89 | } 90 | 91 | /** 92 | * Create the resources for the model. 93 | * 94 | * @return void 95 | */ 96 | private function createResources() 97 | { 98 | $this->info('Creating '.count($this->resources).' resources ...'); 99 | $this->line(''); 100 | 101 | $bar = $this->getOutput()->createProgressBar(count($this->resources)); 102 | 103 | foreach ($this->resources as $resource) { 104 | (new $resource($this->model))->handle(); 105 | $bar->advance(); 106 | } 107 | 108 | $bar->finish(); 109 | $this->line(''); 110 | 111 | $this->line(''); 112 | 113 | $this->info('🚀 Resources created successfully 🚀'); 114 | $this->line(''); 115 | 116 | exec('composer dumpautoload'); 117 | } 118 | 119 | /** 120 | * Execute the console command. 121 | * 122 | * @return mixed 123 | */ 124 | public function handle() 125 | { 126 | $this->info('Checking if the model exists ...'); 127 | 128 | $this->model = $this->argument('model'); 129 | 130 | if (! $this->modelExists()) { 131 | $this->info("The model {$this->model} does not exists."); 132 | 133 | if (! $this->confirm('Should I create it?', true)) { 134 | return; 135 | } 136 | 137 | (new ModelGenerator($this->model))->handle(); 138 | 139 | $this->createModelResources(); 140 | } 141 | 142 | $this->createResources(); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/Exceptions/File.php: -------------------------------------------------------------------------------- 1 | model = $model; 25 | } 26 | 27 | /** 28 | * Verify if the directory and create one if it doesn't. 29 | * 30 | * @return bool 31 | */ 32 | public function directoryExists($path) 33 | { 34 | return (bool) File::isDirectory($path) ?: make_directory($path); 35 | } 36 | 37 | /** 38 | * Verify if the resource already exists. 39 | * 40 | * @return mixed|\tiagomichaelsousa\LaravelResources\Exceptions\File 41 | */ 42 | public function fileAlreadyExists($path) 43 | { 44 | if (File::exists($path)) { 45 | throw FileException::alreadyExistsInDirectory($path); 46 | } 47 | } 48 | 49 | /** 50 | * Generate the file name. 51 | * 52 | * @return string 53 | */ 54 | public function fileName() 55 | { 56 | return "{$this->className()}.php"; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Generators/CollectionGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.collections.namespace'), 28 | '{{CLASS_NAME}}' => "{$this->className()}", 29 | '{{RESOURCE_NAMESPACE}}' => config('laravel-resources.resources.namespace'), 30 | '{{RESOURCE_CLASS_NAME}}' => create_class_name($this->model, ResourceGenerator::class), 31 | ]); 32 | } 33 | 34 | /** 35 | * Generate the class name. 36 | * 37 | * @return string 38 | */ 39 | public function className() 40 | { 41 | return create_class_name($this->model, self::class); 42 | } 43 | 44 | /** 45 | * Handle the resource creation. 46 | * 47 | * @return void 48 | */ 49 | public function handle() 50 | { 51 | $namespace = config('laravel-resources.collections.namespace'); 52 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 53 | $path = "{$directory}/{$this->fileName()}"; 54 | 55 | $this->fileAlreadyExists($path); 56 | 57 | $replaces = $this->replacements($this->model); 58 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 59 | 60 | $this->directoryExists($directory); 61 | 62 | file_put_contents($path, $stub); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Generators/ControllerGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.controllers.namespace'), 30 | '{{CONTROLLER_NAMESPACE}}' => config('laravel-resources.controllers.namespace'), 31 | '{{CONTROLLER_NAME}}' => "{$this->className()}", 32 | '{{RESOURCE_NAMESPACE}}' => config('laravel-resources.resources.namespace').'\\'.create_class_name($this->model, ResourceGenerator::class), 33 | '{{RESOURCE_COLLECTION_NAMESPACE}}' => config('laravel-resources.collections.namespace').'\\'.create_class_name($this->model, CollectionGenerator::class), 34 | '{{MODEL_CLASS}}' => "{$this->model}", 35 | ], 36 | $this->modelReplacements(), 37 | $this->requestReplacements(), 38 | $this->methodsReplacements() 39 | ); 40 | } 41 | 42 | /** 43 | * Get the replacements for the stub methods. 44 | * 45 | * @return array 46 | */ 47 | private function methodsReplacements() 48 | { 49 | $methods = []; 50 | 51 | foreach (['index', 'store', 'show', 'update', 'destroy'] as $method) { 52 | $stub = File::get(__DIR__."/../stubs/controllers/controller.method.{$method}.stub"); 53 | 54 | $replaces = [ 55 | '{{CLASS_NAME}}' => $this->model, 56 | '{{RESOURCE_NAME}}' => $method === 'index' ? create_class_name($this->model, CollectionGenerator::class) : create_class_name($this->model, ResourceGenerator::class), 57 | '{{CLASS_VARIABLE}}' => lcfirst($this->model), 58 | ]; 59 | 60 | $methodStubName = strtoupper($method); 61 | 62 | array_push($methods, ["{{{$methodStubName}_METHOD}}" => str_replace(array_keys($replaces), array_values($replaces), $stub)]); 63 | } 64 | 65 | return Arr::collapse($methods); 66 | } 67 | 68 | /** 69 | * Get the replacements for the current model. 70 | * 71 | * @return array 72 | */ 73 | public function modelReplacements() 74 | { 75 | return [ 76 | '{{MODEL_CLASS}}' => $this->model, 77 | '{{MODEL_VARIABLE}}' => lcfirst($this->model), 78 | '{{MODEL_NAMESPACE}}' => config('laravel-resources.models.namespace')."\\{$this->model}", 79 | ]; 80 | } 81 | 82 | /** 83 | * Get the replacements for the current request of the current model. 84 | * 85 | * @return array 86 | */ 87 | public function requestReplacements() 88 | { 89 | $requestClass = create_class_name($this->model, RequestGenerator::class); 90 | 91 | return [ 92 | '{{REQUEST_CLASS}}' => $requestClass, 93 | '{{REQUEST_NAMESPACE}}' => config('laravel-resources.requests.namespace')."\\{$requestClass}", 94 | ]; 95 | } 96 | 97 | /** 98 | * Generate the class name. 99 | * 100 | * @return string 101 | */ 102 | public function className() 103 | { 104 | return create_class_name($this->model, self::class); 105 | } 106 | 107 | /** 108 | * Handle the resource creation. 109 | * 110 | * @return void 111 | */ 112 | public function handle() 113 | { 114 | $namespace = config('laravel-resources.controllers.namespace'); 115 | $directory = namespace_path($namespace); 116 | 117 | $path = "{$directory}/{$this->filename()}"; 118 | 119 | $this->fileAlreadyExists($path); 120 | 121 | $replaces = $this->replacements($this->model); 122 | 123 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 124 | 125 | $this->directoryExists($directory); 126 | 127 | file_put_contents($path, $stub); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/Generators/FactoryGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.models.namespace'), 28 | '{{MODEL_NAME}}' => $this->model, 29 | '{{CLASS_NAME}}' => $this->className(), 30 | ]); 31 | } 32 | 33 | /** 34 | * Generate the class name. 35 | * 36 | * @return string 37 | */ 38 | public function className() 39 | { 40 | return "{$this->model}Factory"; 41 | } 42 | 43 | /** 44 | * Handle the resource creation. 45 | * 46 | * @return void 47 | */ 48 | public function handle() 49 | { 50 | $namespace = config('laravel-resources.database.factories'); 51 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 52 | $path = "{$directory}/{$this->fileName()}"; 53 | 54 | $this->fileAlreadyExists($path); 55 | 56 | $replaces = $this->replacements($this->model); 57 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 58 | 59 | $this->directoryExists($directory); 60 | 61 | file_put_contents($path, $stub); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Generators/Generator.php: -------------------------------------------------------------------------------- 1 | $this->className(), 30 | '{{TABLE_NAME}}' => Str::lower(Str::snake(Str::plural($this->model))), 31 | ]); 32 | } 33 | 34 | /** 35 | * Generate the class name. 36 | * 37 | * @return string 38 | */ 39 | public function className() 40 | { 41 | $name = Str::plural($this->model); 42 | 43 | return "Create{$name}Table"; 44 | } 45 | 46 | /** 47 | * Generate the file name. 48 | * 49 | * @return string 50 | */ 51 | public function fileName() 52 | { 53 | $date = Carbon::now()->format('Y_m_d_Hms'); 54 | $name = Str::lower(Str::snake($this->className())); 55 | 56 | return "{$date}_{$name}.php"; 57 | } 58 | 59 | /** 60 | * Handle the resource creation. 61 | * 62 | * @return void 63 | */ 64 | public function handle() 65 | { 66 | $namespace = config('laravel-resources.database.migrations'); 67 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 68 | $path = "{$directory}/{$this->fileName()}"; 69 | 70 | $this->fileAlreadyExists($path); 71 | 72 | $replaces = $this->replacements($this->model); 73 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 74 | 75 | $this->directoryExists($directory); 76 | 77 | file_put_contents($path, $stub); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Generators/ModelGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.models.namespace'), 28 | '{{CLASS_NAME}}' => $this->model, 29 | ]); 30 | } 31 | 32 | /** 33 | * Generate the class name. 34 | * 35 | * @return string 36 | */ 37 | public function className() 38 | { 39 | return ucfirst($this->model); 40 | } 41 | 42 | /** 43 | * Handle the resource creation. 44 | * 45 | * @return void 46 | */ 47 | public function handle() 48 | { 49 | $namespace = config('laravel-resources.models.namespace'); 50 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 51 | $path = "{$directory}/{$this->fileName()}"; 52 | 53 | $this->fileAlreadyExists($path); 54 | 55 | $replaces = $this->replacements($this->model); 56 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 57 | 58 | $this->directoryExists($directory); 59 | 60 | file_put_contents($path, $stub); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Generators/PolicyGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.policies.namespace'), 28 | '{{CLASS_NAME}}' => "{$this->className()}", 29 | '{{MODEL_NAMESPACE}}' => config('laravel-resources.models.namespace'), 30 | '{{MODEL_NAME}}' => config('laravel-resources.models.namespace'), 31 | '{{MODEL_CLASS}}' => $this->model, 32 | '{{MODEL_VARIABLE}}' => lcfirst($this->model), 33 | ]); 34 | } 35 | 36 | /** 37 | * Generate the class name. 38 | * 39 | * @return string 40 | */ 41 | public function className() 42 | { 43 | return create_class_name($this->model, self::class); 44 | } 45 | 46 | /** 47 | * Handle the resource creation. 48 | * 49 | * @return void 50 | */ 51 | public function handle() 52 | { 53 | $namespace = config('laravel-resources.policies.namespace'); 54 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 55 | $path = "{$directory}/{$this->fileName()}"; 56 | 57 | $this->fileAlreadyExists($path); 58 | 59 | $replaces = $this->replacements($this->model); 60 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 61 | 62 | $this->directoryExists($directory); 63 | 64 | file_put_contents($path, $stub); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Generators/RequestGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.requests.namespace'), 28 | '{{CLASS_NAME}}' => $this->className(), 29 | ]); 30 | } 31 | 32 | /** 33 | * Generate the class name. 34 | * 35 | * @return string 36 | */ 37 | public function className() 38 | { 39 | return create_class_name($this->model, self::class); 40 | } 41 | 42 | /** 43 | * Handle the resource creation. 44 | * 45 | * @return void 46 | */ 47 | public function handle() 48 | { 49 | $namespace = config('laravel-resources.requests.namespace'); 50 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 51 | $path = "{$directory}/{$this->filename()}"; 52 | 53 | $this->fileAlreadyExists($path); 54 | 55 | $replaces = $this->replacements($this->model); 56 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 57 | 58 | $this->directoryExists($directory); 59 | 60 | file_put_contents($path, $stub); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Generators/ResourceGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.resources.namespace'), 28 | '{{CLASS_NAME}}' => "{$this->className()}", 29 | ]); 30 | } 31 | 32 | /** 33 | * Generate the class name. 34 | * 35 | * @return string 36 | */ 37 | public function className() 38 | { 39 | return create_class_name($this->model, self::class); 40 | } 41 | 42 | /** 43 | * Handle the resource creation. 44 | * 45 | * @return void 46 | */ 47 | public function handle() 48 | { 49 | $namespace = config('laravel-resources.resources.namespace'); 50 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 51 | $path = "{$directory}/{$this->filename()}"; 52 | 53 | $this->fileAlreadyExists($path); 54 | 55 | $replaces = $this->replacements($this->model); 56 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 57 | 58 | $this->directoryExists($directory); 59 | 60 | file_put_contents($path, $stub); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Generators/RouteGenerator.php: -------------------------------------------------------------------------------- 1 | $this->model, 30 | '{{MODEL_VARIABLE}}' => lcfirst($this->model), 31 | '{{CONTROLLER_NAME}}' => $this->generateControllerName(), 32 | '{{ROUTE_NAME}}' => Str::plural(Str::kebab($this->model)), 33 | ]); 34 | } 35 | 36 | /** 37 | * Verify if the resource already exists. 38 | * 39 | * @return mixed|\tiagomichaelsousa\LaravelResources\Exceptions\File 40 | */ 41 | public function fileAlreadyExists($path) 42 | { 43 | if (File::missing($path)) { 44 | throw FileException::doesNotExists($path); 45 | } 46 | } 47 | 48 | /** 49 | * Generate the class name. 50 | * 51 | * @return string 52 | */ 53 | public function className() 54 | { 55 | return 'Route'; 56 | } 57 | 58 | /** 59 | * Generate the file name. 60 | * 61 | * @return string 62 | */ 63 | public function fileName() 64 | { 65 | return config('laravel-resources.routes.filename'); 66 | } 67 | 68 | /** 69 | * Handle the resource creation. 70 | * 71 | * @return void 72 | */ 73 | public function handle() 74 | { 75 | $path = config('laravel-resources.routes.path'); 76 | $directory = base_path($path); 77 | $path = "{$directory}/{$this->fileName()}"; 78 | 79 | $this->fileAlreadyExists($path); 80 | 81 | $replaces = $this->replacements($this->model); 82 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 83 | 84 | $this->directoryExists($directory); 85 | 86 | $controllerNamespace = config('laravel-resources.controllers.namespace'); 87 | $controllerImport = "use {$controllerNamespace}\\{$this->generateControllerName()}"; 88 | $content = str_replace("model, 'ControllerGenerator'); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Generators/SeederGenerator.php: -------------------------------------------------------------------------------- 1 | config('laravel-resources.models.namespace'), 29 | '{{MODEL_NAME}}' => $this->model, 30 | '{{MODEL_PLURAL}}' => Str::plural($this->model), 31 | '{{CLASS_NAME}}' => $this->className(), 32 | ]); 33 | } 34 | 35 | /** 36 | * Generate the class name. 37 | * 38 | * @return string 39 | */ 40 | public function className() 41 | { 42 | $plural = Str::plural($this->model); 43 | 44 | return "{$plural}TableSeeder"; 45 | } 46 | 47 | /** 48 | * Handle the resource creation. 49 | * 50 | * @return void 51 | */ 52 | public function handle() 53 | { 54 | $namespace = config('laravel-resources.database.seeds'); 55 | $directory = base_path(lcfirst(str_replace('\\', '/', $namespace))); 56 | $path = "{$directory}/{$this->fileName()}"; 57 | 58 | $this->fileAlreadyExists($path); 59 | 60 | $replaces = $this->replacements($this->model); 61 | $stub = str_replace(array_keys($replaces), array_values($replaces), $this->getStub()); 62 | 63 | $this->directoryExists($directory); 64 | 65 | file_put_contents($path, $stub); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Helpers/helpers.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 27 | $this->bootForConsole(); 28 | } 29 | } 30 | 31 | /** 32 | * Register any package services. 33 | * 34 | * @return void 35 | */ 36 | public function register() 37 | { 38 | $this->mergeConfigFrom(__DIR__.'/../config/laravel-resources.php', 'laravel-resources'); 39 | } 40 | 41 | /** 42 | * Console-specific booting. 43 | * 44 | * @return void 45 | */ 46 | protected function bootForConsole() 47 | { 48 | // Publishing the configuration file. 49 | $this->publishes([ 50 | __DIR__.'/../config/laravel-resources.php' => app()->basePath().'/config/laravel-resources.php', 51 | ], 'config'); 52 | 53 | // Registering package commands. 54 | $this->commands($this->commands); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/stubs/controllers/controller.method.destroy.stub: -------------------------------------------------------------------------------- 1 | ${{CLASS_VARIABLE}}->delete(); 2 | 3 | return new {{RESOURCE_NAME}}(${{CLASS_VARIABLE}}); 4 | -------------------------------------------------------------------------------- /src/stubs/controllers/controller.method.index.stub: -------------------------------------------------------------------------------- 1 | ${{CLASS_VARIABLE}} = {{CLASS_NAME}}::all(); 2 | 3 | return new {{RESOURCE_NAME}}(${{CLASS_VARIABLE}}); 4 | -------------------------------------------------------------------------------- /src/stubs/controllers/controller.method.show.stub: -------------------------------------------------------------------------------- 1 | return new {{RESOURCE_NAME}}(${{CLASS_VARIABLE}}); 2 | -------------------------------------------------------------------------------- /src/stubs/controllers/controller.method.store.stub: -------------------------------------------------------------------------------- 1 | ${{CLASS_VARIABLE}} = {{CLASS_NAME}}::create($request->validated()); 2 | 3 | return new {{RESOURCE_NAME}}(${{CLASS_VARIABLE}}); 4 | -------------------------------------------------------------------------------- /src/stubs/controllers/controller.method.update.stub: -------------------------------------------------------------------------------- 1 | ${{CLASS_VARIABLE}}->update($request->validated()); 2 | 3 | return new {{RESOURCE_NAME}}(${{CLASS_VARIABLE}}); 4 | -------------------------------------------------------------------------------- /src/stubs/controllers/controller.stub: -------------------------------------------------------------------------------- 1 | authorize('viewAny', {{MODEL_CLASS}}::class); 19 | 20 | {{INDEX_METHOD}} 21 | } 22 | 23 | /** 24 | * Store a newly created resource in storage. 25 | */ 26 | public function store({{REQUEST_CLASS}} $request) 27 | { 28 | $this->authorize('create', {{MODEL_CLASS}}::class); 29 | 30 | {{STORE_METHOD}} 31 | } 32 | 33 | /** 34 | * Display the specified resource. 35 | */ 36 | public function show({{MODEL_CLASS}} ${{MODEL_VARIABLE}}) 37 | { 38 | $this->authorize('view', ${{MODEL_VARIABLE}}); 39 | 40 | {{SHOW_METHOD}} 41 | } 42 | 43 | /** 44 | * Update the specified resource in storage. 45 | */ 46 | public function update({{REQUEST_CLASS}} $request, {{MODEL_CLASS}} ${{MODEL_VARIABLE}}) 47 | { 48 | $this->authorize('update', ${{MODEL_VARIABLE}}); 49 | 50 | {{UPDATE_METHOD}} 51 | } 52 | 53 | /** 54 | * Remove the specified resource from storage. 55 | */ 56 | public function destroy({{MODEL_CLASS}} ${{MODEL_VARIABLE}}) 57 | { 58 | $this->authorize('delete', ${{MODEL_VARIABLE}}); 59 | 60 | {{DESTROY_METHOD}} 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/stubs/factories/factory.stub: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class {{CLASS_NAME}} extends Factory 12 | { 13 | /** 14 | * Define the model's default state. 15 | * 16 | * @return array 17 | */ 18 | public function definition(): array 19 | { 20 | return [ 21 | 'name' => $this->faker->name, 22 | ]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/stubs/migrations/migration.stub: -------------------------------------------------------------------------------- 1 | table, function (Blueprint $table) { 20 | $table->id(); 21 | $table->string('name'); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | */ 29 | public function down(): void 30 | { 31 | Schema::dropIfExists($this->table); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/stubs/models/model.stub: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'name' => ['required'], 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/stubs/resources/api.collection.stub: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function toArray(Request $request): array 23 | { 24 | return parent::toArray($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/stubs/resources/api.resource.stub: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function toArray(Request $request): array 16 | { 17 | return parent::toArray($request); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/stubs/routes/api.routes.stub: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | {{MODEL_NAME}} endpoints 4 | |-------------------------------------------------------------------------- 5 | */ 6 | Route::name('{{ROUTE_NAME}}.')->controller({{CONTROLLER_NAME}}::class)->prefix('{{ROUTE_NAME}}')->group(function () { 7 | Route::get('/', 'index')->name('index'); 8 | Route::post('/', 'store')->name('create'); 9 | Route::get('/{{{MODEL_VARIABLE}}}', 'show')->name('show'); 10 | Route::patch('/{{{MODEL_VARIABLE}}}', 'update')->name('update'); 11 | Route::delete('/{{{MODEL_VARIABLE}}}', 'destroy')->name('destroy'); 12 | }); 13 | -------------------------------------------------------------------------------- /src/stubs/seeds/seed.stub: -------------------------------------------------------------------------------- 1 | command->table(['{{MODEL_PLURAL}} table seeder notice'], [ 18 | ['Edit this file to change the number of {{MODEL_PLURAL}} created'], 19 | ]); 20 | 21 | $this->command->info('Creating ' . $this->numberOf{{MODEL_PLURAL}} . ' {{MODEL_PLURAL}} ...'); 22 | $bar = $this->command->getOutput()->createProgressBar($this->numberOf{{MODEL_PLURAL}}); 23 | 24 | for ($i = 0; $i < $this->numberOf{{MODEL_PLURAL}}; ++$i) { 25 | {{MODEL_NAME}}::factory()->create(); 26 | $bar->advance(); 27 | } 28 | 29 | $bar->finish(); 30 | $this->command->info(''); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/CollectionGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->fileName(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, "{$generator->className()}.php"); 17 | } 18 | 19 | /** @test */ 20 | public function it_generates_the_right_class_name() 21 | { 22 | $generator = new CollectionGenerator($this->model); 23 | $filename = $generator->className(); 24 | $generator->handle(); 25 | 26 | $this->assertEquals($filename, create_class_name($this->model, CollectionGenerator::class)); 27 | } 28 | 29 | /** @test */ 30 | public function it_creates_the_collection_file() 31 | { 32 | $generator = new CollectionGenerator($this->model); 33 | $config = namespace_path(config('laravel-resources.collections.namespace')."\\{$generator->fileName()}"); 34 | 35 | $generator->handle(); 36 | 37 | $this->assertFileExists($config); 38 | } 39 | 40 | /** @test */ 41 | public function it_creates_the_collection_in_the_config_namespace() 42 | { 43 | config()->set('laravel-resources.collections.namespace', 'App\Http\Resources'); 44 | $generator = new CollectionGenerator($this->model); 45 | 46 | $config = namespace_path(config('laravel-resources.collections.namespace')."\\{$generator->fileName()}"); 47 | 48 | $generator->handle(); 49 | 50 | $this->assertFileExists($config); 51 | } 52 | 53 | /** @test */ 54 | public function it_generates_the_name_with_the_suffix_defined_in_the_configuration_file_for_the_collection() 55 | { 56 | config()->set('laravel-resources.collections.suffix', $suffix = 'Suffix'); 57 | config()->set('laravel-resources.collections.prefix', null); 58 | 59 | $generator = new CollectionGenerator($this->model); 60 | $generator->handle(); 61 | 62 | $this->assertEquals("{$this->model}Collection{$suffix}", $generator->className()); 63 | } 64 | 65 | /** @test */ 66 | public function it_generates_the_name_with_the_prefix_defined_in_the_configuration_file_for_the_collection() 67 | { 68 | config()->set('laravel-resources.collections.suffix', null); 69 | config()->set('laravel-resources.collections.prefix', $prefix = 'PrefixAPI'); 70 | 71 | $generator = new CollectionGenerator($this->model); 72 | $generator->handle(); 73 | 74 | $this->assertEquals("{$prefix}{$this->model}Collection", $generator->className()); 75 | } 76 | 77 | /** @test */ 78 | public function it_generates_the_name_with_the_suffix_and_prefix_defined_in_the_configuration_file_for_the_collection() 79 | { 80 | config()->set('laravel-resources.collections.prefix', $prefix = 'Foo'); 81 | config()->set('laravel-resources.collections.suffix', $suffix = 'BarAPI'); 82 | 83 | $generator = new CollectionGenerator($this->model); 84 | $generator->handle(); 85 | 86 | $this->assertEquals("{$prefix}{$this->model}Collection{$suffix}", $generator->className()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/ControllerGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->fileName(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, "{$generator->className()}.php"); 17 | } 18 | 19 | /** @test */ 20 | public function it_generates_the_right_class_name() 21 | { 22 | $generator = new ControllerGenerator($this->model); 23 | $filename = $generator->className(); 24 | $generator->handle(); 25 | 26 | $this->assertEquals($filename, create_class_name($this->model, ControllerGenerator::class)); 27 | } 28 | 29 | /** @test */ 30 | public function it_creates_the_controller_file() 31 | { 32 | $generator = new ControllerGenerator($this->model); 33 | 34 | $config = namespace_path(config('laravel-resources.controllers.namespace')."\\{$generator->fileName()}"); 35 | 36 | $generator->handle(); 37 | 38 | $this->assertFileExists($config); 39 | } 40 | 41 | /** @test */ 42 | public function it_creates_the_controller_in_the_config_namespace() 43 | { 44 | config()->set('laravel-resources.controllers.namespace', 'App\Http\Controllers\API'); 45 | 46 | $generator = new ControllerGenerator($this->model); 47 | 48 | $config = namespace_path(config('laravel-resources.controllers.namespace')."\\{$generator->fileName()}"); 49 | 50 | $generator->handle(); 51 | 52 | $this->assertFileExists($config); 53 | } 54 | 55 | /** @test */ 56 | public function it_generates_the_name_with_the_suffix_defined_in_the_configuration_file_for_the_controller() 57 | { 58 | config()->set('laravel-resources.controllers.suffix', $suffix = 'Suffix'); 59 | config()->set('laravel-resources.controllers.prefix', null); 60 | 61 | $generator = new ControllerGenerator($this->model); 62 | $generator->handle(); 63 | 64 | $this->assertEquals("{$this->model}Controller{$suffix}", $generator->className()); 65 | } 66 | 67 | /** @test */ 68 | public function it_generates_the_name_with_the_prefix_defined_in_the_configuration_file_for_the_controller() 69 | { 70 | config()->set('laravel-resources.controllers.prefix', $prefix = 'Prefix'); 71 | config()->set('laravel-resources.controllers.suffix', null); 72 | 73 | $generator = new ControllerGenerator($this->model); 74 | $generator->handle(); 75 | 76 | $this->assertEquals("{$prefix}{$this->model}Controller", $generator->className()); 77 | } 78 | 79 | /** @test */ 80 | public function it_generates_the_name_with_the_suffix_and_prefix_defined_in_the_configuration_file_for_the_controller() 81 | { 82 | config()->set('laravel-resources.controllers.prefix', $prefix = 'Foo'); 83 | config()->set('laravel-resources.controllers.suffix', $suffix = 'BarAPI'); 84 | 85 | $generator = new ControllerGenerator($this->model); 86 | $generator->handle(); 87 | 88 | $this->assertEquals("{$prefix}{$this->model}Controller{$suffix}", $generator->className()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/FactoryGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->className(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, 'UserFactory'); 17 | } 18 | 19 | /** @test */ 20 | public function it_creates_the_migration_file() 21 | { 22 | $generator = new FactoryGenerator($this->model); 23 | 24 | $config = namespace_path(config('laravel-resources.database.factories')."\\{$generator->fileName()}"); 25 | 26 | $generator->handle(); 27 | 28 | $this->assertFileExists($config); 29 | } 30 | 31 | /** @test */ 32 | public function it_creates_the_migration_in_the_config_namespace() 33 | { 34 | config()->set('laravel-resources.database.factories', 'database/dummy'); 35 | 36 | $generator = new FactoryGenerator($this->model); 37 | 38 | $config = namespace_path(config('laravel-resources.database.factories')."\\{$generator->fileName()}"); 39 | 40 | $generator->handle(); 41 | 42 | $this->assertFileExists($config); 43 | } 44 | 45 | /** @test */ 46 | public function it_creates_the_migration_in_the_default_namespace() 47 | { 48 | $generator = new FactoryGenerator($this->model); 49 | 50 | $config = namespace_path(config('laravel-resources.database.factories')."\\{$generator->fileName()}"); 51 | 52 | $generator->handle(); 53 | 54 | $this->assertFileExists($config); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/MigrationGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->className(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, 'CreateUsersTable'); 17 | } 18 | 19 | /** @test */ 20 | public function it_creates_the_migration_file() 21 | { 22 | $generator = new MigrationGenerator($this->model); 23 | 24 | $config = namespace_path(config('laravel-resources.database.migrations')."\\{$generator->fileName()}"); 25 | 26 | $generator->handle(); 27 | 28 | $this->assertFileExists($config); 29 | } 30 | 31 | /** @test */ 32 | public function it_creates_the_migration_in_the_config_namespace() 33 | { 34 | config()->set('laravel-resources.database.migrations', 'database/dummy'); 35 | 36 | $generator = new MigrationGenerator($this->model); 37 | 38 | $config = namespace_path(config('laravel-resources.database.migrations')."\\{$generator->fileName()}"); 39 | 40 | $generator->handle(); 41 | 42 | $this->assertFileExists($config); 43 | } 44 | 45 | /** @test */ 46 | public function it_creates_the_migration_in_the_default_namespace() 47 | { 48 | $generator = new MigrationGenerator($this->model); 49 | 50 | $config = namespace_path(config('laravel-resources.database.migrations')."\\{$generator->fileName()}"); 51 | 52 | $generator->handle(); 53 | 54 | $this->assertFileExists($config); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/ModelGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 20 | 21 | $config = namespace_path(config('laravel-resources.models.namespace')."\\{$generator->fileName()}"); 22 | 23 | $generator->handle(); 24 | 25 | $this->assertFileExists($config); 26 | } 27 | 28 | /** @test */ 29 | public function it_creates_the_model_in_the_config_namespace() 30 | { 31 | config()->set('laravel-resources.models.namespace', 'App\Models'); 32 | 33 | $generator = new ModelGenerator($this->model); 34 | 35 | $config = namespace_path(config('laravel-resources.models.namespace')."\\{$generator->fileName()}"); 36 | 37 | $generator->handle(); 38 | 39 | $this->assertFileExists($config); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/PolicyGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->fileName(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, "{$generator->className()}.php"); 17 | } 18 | 19 | /** @test */ 20 | public function it_generates_the_right_class_name() 21 | { 22 | $generator = new PolicyGenerator($this->model); 23 | $filename = $generator->className(); 24 | $generator->handle(); 25 | 26 | $this->assertEquals($filename, create_class_name($this->model, PolicyGenerator::class)); 27 | } 28 | 29 | /** @test */ 30 | public function it_creates_the_policy_file() 31 | { 32 | $generator = new PolicyGenerator($this->model); 33 | 34 | $config = namespace_path(config('laravel-resources.policies.namespace')."\\{$generator->fileName()}"); 35 | 36 | $generator->handle(); 37 | 38 | $this->assertFileExists($config); 39 | } 40 | 41 | /** @test */ 42 | public function it_creates_the_policy_in_the_config_namespace() 43 | { 44 | config()->set('laravel-resources.policies.namespace', 'App\Http\Policies'); 45 | 46 | $generator = new PolicyGenerator($this->model); 47 | 48 | $config = namespace_path(config('laravel-resources.policies.namespace')."\\{$generator->fileName()}"); 49 | 50 | $generator->handle(); 51 | 52 | $this->assertFileExists($config); 53 | } 54 | 55 | /** @test */ 56 | public function it_generates_the_name_with_the_suffix_defined_in_the_configuration_file_for_the_policy() 57 | { 58 | config()->set('laravel-resources.policies.suffix', $suffix = 'Suffix'); 59 | config()->set('laravel-resources.policies.prefix', null); 60 | 61 | $generator = new PolicyGenerator($this->model); 62 | $generator->handle(); 63 | 64 | $this->assertEquals("{$this->model}Policy{$suffix}", $generator->className()); 65 | } 66 | 67 | /** @test */ 68 | public function it_generates_the_name_with_the_prefix_defined_in_the_configuration_file_for_the_policy() 69 | { 70 | config()->set('laravel-resources.policies.prefix', $prefix = 'Prefix'); 71 | config()->set('laravel-resources.policies.suffix', null); 72 | 73 | $generator = new PolicyGenerator($this->model); 74 | $generator->handle(); 75 | 76 | $this->assertEquals("{$prefix}{$this->model}Policy", $generator->className()); 77 | } 78 | 79 | /** @test */ 80 | public function it_generates_the_name_with_the_suffix_and_prefix_defined_in_the_configuration_file_for_the_policy() 81 | { 82 | config()->set('laravel-resources.policies.prefix', $prefix = 'Foo'); 83 | config()->set('laravel-resources.policies.suffix', $suffix = 'BarAPI'); 84 | 85 | $generator = new PolicyGenerator($this->model); 86 | $generator->handle(); 87 | 88 | $this->assertEquals("{$prefix}{$this->model}Policy{$suffix}", $generator->className()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/RequestGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->fileName(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, "{$generator->className()}.php"); 17 | } 18 | 19 | /** @test */ 20 | public function it_generates_the_right_class_name() 21 | { 22 | $generator = new RequestGenerator($this->model); 23 | $filename = $generator->className(); 24 | $generator->handle(); 25 | 26 | $this->assertEquals($filename, create_class_name($this->model, RequestGenerator::class)); 27 | } 28 | 29 | /** @test */ 30 | public function it_creates_the_request_file() 31 | { 32 | $generator = new RequestGenerator($this->model); 33 | 34 | $config = namespace_path(config('laravel-resources.requests.namespace')."\\{$generator->fileName()}"); 35 | 36 | $generator->handle(); 37 | 38 | $this->assertFileExists($config); 39 | } 40 | 41 | /** @test */ 42 | public function it_creates_the_request_in_the_config_namespace() 43 | { 44 | config()->set('laravel-resources.requests.namespace', 'App\Http'); 45 | 46 | $generator = new RequestGenerator($this->model); 47 | 48 | $config = namespace_path(config('laravel-resources.requests.namespace')."\\{$generator->fileName()}"); 49 | 50 | $generator->handle(); 51 | 52 | $this->assertFileExists($config); 53 | } 54 | 55 | /** @test */ 56 | public function it_generates_the_name_with_the_suffix_defined_in_the_configuration_file_for_the_request() 57 | { 58 | config()->set('laravel-resources.requests.suffix', $suffix = 'Suffix'); 59 | config()->set('laravel-resources.requests.prefix', null); 60 | 61 | $generator = new RequestGenerator($this->model); 62 | $generator->handle(); 63 | 64 | $this->assertEquals("{$this->model}Request{$suffix}", $generator->className()); 65 | } 66 | 67 | /** @test */ 68 | public function it_generates_the_name_with_the_prefix_defined_in_the_configuration_file_for_the_request() 69 | { 70 | config()->set('laravel-resources.requests.prefix', $prefix = 'PrefixAPI'); 71 | config()->set('laravel-resources.requests.suffix', null); 72 | 73 | $generator = new RequestGenerator($this->model); 74 | $generator->handle(); 75 | 76 | $this->assertEquals("{$prefix}{$this->model}Request", $generator->className()); 77 | } 78 | 79 | /** @test */ 80 | public function it_generates_the_name_with_the_suffix_and_prefix_defined_in_the_configuration_file_for_the_request() 81 | { 82 | config()->set('laravel-resources.requests.prefix', $prefix = 'Foo'); 83 | config()->set('laravel-resources.requests.suffix', $suffix = 'BarAPI'); 84 | 85 | $generator = new RequestGenerator($this->model); 86 | $generator->handle(); 87 | 88 | $this->assertEquals("{$prefix}{$this->model}Request{$suffix}", $generator->className()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/ResourceCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('resources:create', ['model' => 'Foo']) 13 | ->expectsOutput('The model Foo does not exists.') 14 | ->expectsQuestion('Should I create it?', false); 15 | 16 | $this->assertFalse(File::exists(app_path('/Foo.php'))); 17 | } 18 | 19 | /** @test */ 20 | public function it_creates_the_model_if_it_does_not_exists_and_the_user_accepts_the_question() 21 | { 22 | $this->defaultQuestions(); 23 | 24 | $path = namespace_path(config('laravel-resources.models.namespace').'\\Foo.php'); 25 | 26 | $this->assertTrue(File::exists($path)); 27 | } 28 | 29 | /** @test */ 30 | public function it_creates_the_migration_when_the_response_to_the_question_is_true() 31 | { 32 | $this->defaultQuestions(['migration']); 33 | 34 | $this->assertEquals(1, collect(File::files(database_path('/migrations')))->count()); 35 | } 36 | 37 | /** @test */ 38 | public function it_creates_the_factory_when_the_response_to_the_question_is_true() 39 | { 40 | $this->defaultQuestions(['factory']); 41 | 42 | $this->assertEquals(1, collect(File::files(database_path('/factories')))->count()); 43 | } 44 | 45 | /** @test */ 46 | public function it_creates_the_seeder_when_the_response_to_the_question_is_true() 47 | { 48 | $this->defaultQuestions(['migration', 'factory', 'seeder']); 49 | 50 | $this->assertEquals(1, collect(File::files(database_path('/migrations')))->count()); 51 | $this->assertEquals(1, collect(File::files(database_path('/seeders')))->count()); 52 | $this->assertEquals(1, collect(File::files(database_path('/factories')))->count()); 53 | } 54 | 55 | /** @test */ 56 | public function it_creates_the_all_files_when_the_response_to_the_question_is_always_true() 57 | { 58 | $this->defaultQuestions(['seeder']); 59 | 60 | $this->assertEquals(1, collect(File::files(database_path('/seeders')))->count()); 61 | } 62 | 63 | /** 64 | * Create the command boilerplate for the model creation. 65 | * 66 | * @return void 67 | */ 68 | protected function defaultQuestions($args = [], $shouldCreate = true) 69 | { 70 | $this->artisan('resources:create', ['model' => 'Foo']) 71 | ->expectsOutput('The model Foo does not exists.') 72 | ->expectsQuestion('Should I create it?', $shouldCreate) 73 | ->expectsQuestion('Should I create the migration for Foo?', in_array('migration', $args)) 74 | ->expectsQuestion('Should I create the factory for Foo?', in_array('factory', $args)) 75 | ->expectsQuestion('Should I create the seeder for Foo?', in_array('seeder', $args)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/ResourceGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->fileName(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, "{$generator->className()}.php"); 17 | } 18 | 19 | /** @test */ 20 | public function it_generates_the_right_class_name() 21 | { 22 | $generator = new ResourceGenerator($this->model); 23 | $filename = $generator->className(); 24 | $generator->handle(); 25 | 26 | $this->assertEquals($filename, create_class_name($this->model, ResourceGenerator::class)); 27 | } 28 | 29 | /** @test */ 30 | public function it_creates_the_resource_file() 31 | { 32 | $generator = new ResourceGenerator($this->model); 33 | 34 | $config = namespace_path(config('laravel-resources.resources.namespace')."\\{$generator->fileName()}"); 35 | 36 | $generator->handle(); 37 | 38 | $this->assertFileExists($config); 39 | } 40 | 41 | /** @test */ 42 | public function it_creates_the_request_in_the_config_namespace() 43 | { 44 | config()->set('laravel-resources.resources.namespace', 'App\Http'); 45 | 46 | $generator = new ResourceGenerator($this->model); 47 | 48 | $config = namespace_path(config('laravel-resources.resources.namespace')."\\{$generator->fileName()}"); 49 | 50 | $generator->handle(); 51 | 52 | $this->assertFileExists($config); 53 | } 54 | 55 | /** @test */ 56 | public function it_generates_the_name_with_the_suffix_defined_in_the_configuration_file_for_the_resource() 57 | { 58 | config()->set('laravel-resources.resources.suffix', $suffix = 'Suffix'); 59 | config()->set('laravel-resources.resources.prefix', null); 60 | 61 | $generator = new ResourceGenerator($this->model); 62 | $generator->handle(); 63 | 64 | $this->assertEquals("{$this->model}Resource{$suffix}", $generator->className()); 65 | } 66 | 67 | /** @test */ 68 | public function it_generates_the_name_with_the_prefix_defined_in_the_configuration_file_for_the_resource() 69 | { 70 | config()->set('laravel-resources.resources.prefix', $prefix = 'Prefix'); 71 | config()->set('laravel-resources.resources.suffix', null); 72 | 73 | $generator = new ResourceGenerator($this->model); 74 | $generator->handle(); 75 | 76 | $this->assertEquals("{$prefix}{$this->model}Resource", $generator->className()); 77 | } 78 | 79 | /** @test */ 80 | public function it_generates_the_name_with_the_suffix_and_prefix_defined_in_the_configuration_file_for_the_resource() 81 | { 82 | config()->set('laravel-resources.resources.prefix', $prefix = 'Foo'); 83 | config()->set('laravel-resources.resources.suffix', $suffix = 'BarAPI'); 84 | 85 | $generator = new ResourceGenerator($this->model); 86 | $generator->handle(); 87 | 88 | $this->assertEquals("{$prefix}{$this->model}Resource{$suffix}", $generator->className()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/SeederGeneratorTest.php: -------------------------------------------------------------------------------- 1 | model); 13 | $filename = $generator->className(); 14 | $generator->handle(); 15 | 16 | $this->assertEquals($filename, 'UsersTableSeeder'); 17 | } 18 | 19 | /** @test */ 20 | public function it_creates_the_seeder_file() 21 | { 22 | $generator = new SeederGenerator($this->model); 23 | 24 | $config = namespace_path(config('laravel-resources.database.seeds')."\\{$generator->fileName()}"); 25 | 26 | $generator->handle(); 27 | 28 | $this->assertFileExists($config); 29 | } 30 | 31 | /** @test */ 32 | public function it_creates_the_seeder_in_the_config_namespace() 33 | { 34 | config()->set('laravel-resources.database.seeds', 'database/dummy'); 35 | 36 | $generator = new SeederGenerator($this->model); 37 | 38 | $config = namespace_path(config('laravel-resources.database.seeds')."\\{$generator->fileName()}"); 39 | 40 | $generator->handle(); 41 | 42 | $this->assertFileExists($config); 43 | } 44 | 45 | /** @test */ 46 | public function it_creates_the_seeder_in_the_default_namespace() 47 | { 48 | $generator = new SeederGenerator($this->model); 49 | 50 | $config = namespace_path(config('laravel-resources.database.seeds')."\\{$generator->fileName()}"); 51 | 52 | $generator->handle(); 53 | 54 | $this->assertFileExists($config); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | clearDirectories(); 28 | 29 | $this->initialize(); 30 | } 31 | 32 | /** 33 | * Clean up the testing environment before the next test. 34 | * 35 | * @return void 36 | */ 37 | protected function tearDown(): void 38 | { 39 | parent::tearDown(); 40 | } 41 | 42 | /** 43 | * Clean up the testing environment directories before the next test. 44 | * 45 | * @return void 46 | */ 47 | private function clearDirectories() 48 | { 49 | File::cleanDirectory(base_path('app')); 50 | File::deleteDirectory(base_path('routes')); 51 | File::cleanDirectory(database_path('migrations')); 52 | File::cleanDirectory(database_path('factories')); 53 | File::cleanDirectory(database_path('seeders')); 54 | File::cleanDirectory(database_path('dummy')); 55 | } 56 | 57 | /** 58 | * Create the test suite default folder structure. 59 | * 60 | * @return void 61 | */ 62 | private function initialize() 63 | { 64 | if (! File::exists(namespace_path(config('laravel-resources.models.namespace')).'/User.php')) { 65 | $this->artisan('make:model User'); 66 | } 67 | 68 | if (! File::exists($route = namespace_path(config('laravel-resources.routes.path')).'/'.config('laravel-resources.routes.filename'))) { 69 | make_directory(namespace_path(config('laravel-resources.routes.path'))); 70 | file_put_contents($route, '