├── .github ├── dependabot.yml └── workflows │ ├── dependabot-auto-merge.yml │ ├── fix-php-code-style-issues.yml │ ├── phpstan.yml │ └── run-tests.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock ├── config └── repository-generator.php ├── img └── banner.png ├── phpstan-baseline.neon ├── phpstan.neon.dist ├── phpunit.xml.dist ├── phpunit.xml.dist.bak ├── src ├── Console │ ├── MakeRepository.php │ └── MakeRepositoryInterface.php ├── Repository │ ├── BaseRepository.php │ └── EloquentRepositoryInterface.php └── RepositoryGeneratorServiceProvider.php ├── stubs ├── repository-interface.stub └── repository.stub └── tests ├── Pest.php ├── RepositoryGeneratorTest.php └── TestCase.php /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | labels: 12 | - "dependencies" 13 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: dependabot-auto-merge 2 | on: pull_request_target 3 | 4 | permissions: 5 | pull-requests: write 6 | contents: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | steps: 13 | 14 | - name: Dependabot metadata 15 | id: metadata 16 | uses: dependabot/fetch-metadata@v1.6.0 17 | with: 18 | github-token: "${{ secrets.GITHUB_TOKEN }}" 19 | 20 | - name: Auto-merge Dependabot PRs for semver-minor updates 21 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}} 22 | run: gh pr merge --auto --merge "$PR_URL" 23 | env: 24 | PR_URL: ${{github.event.pull_request.html_url}} 25 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 26 | 27 | - name: Auto-merge Dependabot PRs for semver-patch updates 28 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}} 29 | run: gh pr merge --auto --merge "$PR_URL" 30 | env: 31 | PR_URL: ${{github.event.pull_request.html_url}} 32 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 33 | -------------------------------------------------------------------------------- /.github/workflows/fix-php-code-style-issues.yml: -------------------------------------------------------------------------------- 1 | name: Fix PHP code style issues 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**.php' 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | php-code-styling: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | with: 19 | ref: ${{ github.head_ref }} 20 | 21 | - name: Fix PHP code style issues 22 | uses: aglipanci/laravel-pint-action@2.4 23 | 24 | - name: Commit changes 25 | uses: stefanzweifel/git-auto-commit-action@v5 26 | with: 27 | commit_message: Fix styling 28 | -------------------------------------------------------------------------------- /.github/workflows/phpstan.yml: -------------------------------------------------------------------------------- 1 | name: PHPStan 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**.php' 7 | - 'phpstan.neon.dist' 8 | 9 | jobs: 10 | phpstan: 11 | name: phpstan 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Setup PHP 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: '8.1' 20 | coverage: none 21 | 22 | - name: Install composer dependencies 23 | uses: ramsey/composer-install@v2 24 | 25 | - name: Run PHPStan 26 | run: ./vendor/bin/phpstan --error-format=github 27 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: run-tests 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | fail-fast: true 14 | matrix: 15 | os: [ubuntu-latest, windows-latest] 16 | php: [8.2, 8.1] 17 | laravel: [10.*] 18 | stability: [prefer-lowest, prefer-stable] 19 | include: 20 | - laravel: 10.* 21 | testbench: 8.* 22 | carbon: ^2.63 23 | 24 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} 25 | 26 | steps: 27 | - name: Checkout code 28 | uses: actions/checkout@v4 29 | 30 | - name: Setup PHP 31 | uses: shivammathur/setup-php@v2 32 | with: 33 | php-version: ${{ matrix.php }} 34 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo 35 | coverage: none 36 | 37 | - name: Setup problem matchers 38 | run: | 39 | echo "::add-matcher::${{ runner.tool_cache }}/php.json" 40 | echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" 41 | 42 | - name: Install dependencies 43 | run: | 44 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "nesbot/carbon:${{ matrix.carbon }}" --no-interaction --no-update 45 | composer update --${{ matrix.stability }} --prefer-dist --no-interaction 46 | 47 | - name: List Installed Dependencies 48 | run: composer show -D 49 | 50 | - name: Execute tests 51 | run: vendor/bin/pest 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .phpunit.cache 3 | build 4 | composer.lock 5 | coverage 6 | docs 7 | phpunit.xml 8 | phpstan.neon 9 | testbench.yaml 10 | vendor 11 | node_modules 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Tim Wassenburg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Logo 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/timwassenburg/laravel-repository-generator.svg?style=flat-square)](https://packagist.org/packages/timwassenburg/laravel-repository-generator) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/timwassenburg/laravel-repository-generator/run-tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/timwassenburg/laravel-repository-generator/actions?query=workflow%3Arun-tests+branch%3Amaster) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/timwassenburg/laravel-repository-generator.svg?style=flat-square)](https://packagist.org/packages/timwassenburg/laravel-repository-generator) 6 | [![License](https://img.shields.io/packagist/l/timwassenburg/laravel-repository-generator)](https://packagist.org/packages/timwassenburg/laravel-repository-generator) 7 | 8 |
9 | 10 | ## Table of Contents 11 |
    12 |
  1. Features
  2. 13 |
  3. 14 | Getting started 15 | 19 |
  4. 20 |
  5. 21 | Usage 22 | 26 |
  6. 27 |
  7. Manual binding
  8. 28 |
  9. Testing
  10. 29 |
  11. More generator packages
  12. 30 |
  13. Contributing
  14. 31 |
  15. License
  16. 32 |
33 | 34 | ## Features 35 | With this package you can generate repositories with the ```artisan make:repository``` command. 36 | The generator will generate the repository, repository interface and will bind them automatically (can be changed to 37 | manual binding) to the Service Container so you can inject the interface into your controllers. 38 | 39 | ## Installation 40 | Require the Laravel Repository Generator with composer. 41 | ```bash 42 | composer require timwassenburg/laravel-repository-generator --dev 43 | ``` 44 | 45 | ### Publish config (optional) 46 | ```bash 47 | php artisan vendor:publish --provider="TimWassenburg\RepositoryGenerator\RepositoryGeneratorServiceProvider" --tag="config" 48 | ``` 49 | 50 | ## Usage 51 | For usage take the following steps. Generate the repository and then inject it into a controller or service. 52 | 53 | ### Generating repositories 54 | Run the following command. 55 | ```bash 56 | php artisan make:repository UserRepository 57 | ``` 58 | This example will generate the following files: 59 | ```bash 60 | app\Repositories\Eloquent\UserRepository 61 | app\Repositories\UserRepositoryInterface 62 | ``` 63 | 64 | ### Dependency Injection 65 | Next we have to inject the interface into the constructor our controller or service. For this example we will use the UserController. 66 | ```php 67 | user = $userRepository; 80 | } 81 | 82 | // your controller functions 83 | } 84 | ``` 85 | 86 | By default you will be able to use Eloquent methods like ```all()``` and ```find()```. 87 | You can extend this in your repository. Now you will be able to use your repository 88 | in your methods like this. 89 | ```php 90 | public function index() 91 | { 92 | return $this->user->all(); 93 | } 94 | ``` 95 | ## Manual binding 96 | By default the package will automatically bind the repository interfaces for you with the repositories so you can 97 | inject the interface into your controllers. If you want to bind manually you can disable 98 | this behaviour by setting the ```auto_bind_interfaces``` option to ```false``` in ```config\repository-generator.php```. 99 | If the config is not there make sure to publish it first as described in the Installation chapter. 100 | 101 | You can add your bindings to your AppServiceProvider or 102 | you can a create a new provider with ```php artisan make:provider RepositoryServiceProvider``` 103 | (don't forget to add it in ```config\app.php```) and add the bindings in the ```register()``` method, see the example below. 104 | 105 | ```php 106 | app->bind(UserRepositoryInterface::class, UserRepository::class); 128 | } 129 | } 130 | ``` 131 | 132 | ## Testing 133 | 134 | Run the tests with: 135 | 136 | ```bash 137 | composer test 138 | ``` 139 | 140 | ## More generator packages 141 | 142 | Looking for more ways to speed up your workflow? Make sure to check out these packages. 143 | 144 | - [Laravel Action Generator](https://github.com/timwassenburg/laravel-action-generator) 145 | - [Laravel Pivot Table Generator](https://github.com/timwassenburg/laravel-pivot-table-generator) 146 | - [Laravel Repository Generator](https://github.com/timwassenburg/laravel-repository-generator) 147 | - [Laravel Service Generator](https://github.com/timwassenburg/laravel-service-generator) 148 | - [Laravel Trait Generator](https://github.com/timwassenburg/laravel-trait-generator) 149 | 150 | The packages mentioned above are part of [Laravel Artisan Extender](https://github.com/timwassenburg/laravel-artisan-extender). 151 | 152 | ## Contributing 153 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 154 | 155 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 156 | Don't forget to give the project a star! Thanks again! 157 | 158 | 1. Fork the Project 159 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 160 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 161 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 162 | 5. Open a Pull Request 163 | 164 | ## License 165 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 166 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "timwassenburg/laravel-repository-generator", 3 | "description": "Generate Laravel repositories", 4 | "keywords": ["generator", "php", "cli", "generator", "laravel", "artisan"], 5 | "homepage": "https://github.com/timwassenburg/laravel-repository-generator", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Tim Wassenburg" 10 | } 11 | ], 12 | "autoload": { 13 | "psr-4": { 14 | "TimWassenburg\\RepositoryGenerator\\": "src/" 15 | } 16 | }, 17 | "autoload-dev": { 18 | "psr-4": { 19 | "TimWassenburg\\RepositoryGenerator\\Tests\\": "tests/" 20 | } 21 | }, 22 | "scripts": { 23 | "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", 24 | "analyse": "vendor/bin/phpstan analyse", 25 | "test": "vendor/bin/pest", 26 | "test-coverage": "vendor/bin/pest --coverage", 27 | "format": "vendor/bin/pint" 28 | }, 29 | "extra": { 30 | "laravel": { 31 | "providers": [ 32 | "TimWassenburg\\RepositoryGenerator\\RepositoryGeneratorServiceProvider" 33 | ] 34 | } 35 | }, 36 | "require-dev": { 37 | "pestphp/pest": "^2.5", 38 | "orchestra/testbench": "^8.5", 39 | "laravel/pint": "^1.10", 40 | "nunomaduro/larastan": "^2.0" 41 | }, 42 | "config": { 43 | "allow-plugins": { 44 | "pestphp/pest-plugin": true 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/repository-generator.php: -------------------------------------------------------------------------------- 1 | true, 5 | ]; 6 | -------------------------------------------------------------------------------- /img/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timwassenburg/laravel-repository-generator/85b4a089141f7975216c8e8774299aa3cf8e481a/img/banner.png -------------------------------------------------------------------------------- /phpstan-baseline.neon: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timwassenburg/laravel-repository-generator/85b4a089141f7975216c8e8774299aa3cf8e481a/phpstan-baseline.neon -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | includes: 2 | - phpstan-baseline.neon 3 | 4 | parameters: 5 | level: 4 6 | paths: 7 | - src 8 | tmpDir: build/phpstan 9 | checkMissingIterableValueType: false 10 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /phpunit.xml.dist.bak: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | tests 21 | 22 | 23 | 24 | 25 | ./src 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Console/MakeRepository.php: -------------------------------------------------------------------------------- 1 | call('make:repository-interface', ['name' => $this->getNameInput().'Interface']); 45 | 46 | return parent::handle(); 47 | } 48 | 49 | /** 50 | * Get the default namespace for the class. 51 | * 52 | * @param string $rootNamespace 53 | * @return string 54 | */ 55 | protected function getDefaultNamespace($rootNamespace) 56 | { 57 | return $rootNamespace.'\Repositories\Eloquent'; 58 | } 59 | 60 | /** 61 | * Replace the namespace for the given stub. 62 | * 63 | * @param string $stub 64 | * @param string $name 65 | * @return $this 66 | */ 67 | protected function replaceNamespace(&$stub, $name) 68 | { 69 | $classname = Str::replace('Repository', '', $this->getNameInput()); 70 | $stub = Str::replace('{{ Model }}', $classname, $stub); 71 | $stub = Str::replace('{{ namespacedModel }}', 'App\Models\\'.$classname, $stub); 72 | 73 | return parent::replaceNamespace($stub, $name); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Console/MakeRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | model = $model; 18 | } 19 | 20 | public function all(): Collection 21 | { 22 | return $this->model->all(); 23 | } 24 | 25 | public function create(array $attributes): Model 26 | { 27 | return $this->model->create($attributes); 28 | } 29 | 30 | public function find(int $id, array $with = [], array $params = []): ?Model 31 | { 32 | return $this->model->with($with)->findOrFail($id); 33 | } 34 | 35 | public function findWithTrash(int $id): ?Model 36 | { 37 | return $this->model::query()->withTrashed()->find($id); 38 | } 39 | 40 | public function delete(int $id) 41 | { 42 | return $this->model::query()->find($id)->delete(); 43 | } 44 | 45 | public function update(int $id, array $attributes): bool 46 | { 47 | $model = $this->find($id); 48 | 49 | return $model->update($attributes); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Repository/EloquentRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | bindInterfaces(); 21 | } 22 | 23 | $this->mergeConfigFrom(__DIR__.'/../config/repository-generator.php', 'repository-generator'); 24 | } 25 | 26 | public function boot() 27 | { 28 | if ($this->app->runningInConsole()) { 29 | $this->commands([ 30 | MakeRepository::class, 31 | MakeRepositoryInterface::class, 32 | ]); 33 | 34 | $this->publishes([ 35 | __DIR__.'/../config/repository-generator.php' => config_path('repository-generator.php'), 36 | ], 'config'); 37 | } 38 | } 39 | 40 | protected function bindInterfaces() 41 | { 42 | $path = app_path('Repositories/Eloquent'); 43 | $files = (file_exists($path)) ? File::files($path) : []; 44 | 45 | foreach ($files as $file) { 46 | $repository = 'App\Repositories\Eloquent\\'.$file->getFilenameWithoutExtension(); 47 | $repositoryInterface = 'App\Repositories\\'.$file->getFilenameWithoutExtension().'Interface'; 48 | 49 | $this->app->bind($repositoryInterface, $repository); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /stubs/repository-interface.stub: -------------------------------------------------------------------------------- 1 | in(__DIR__); 6 | -------------------------------------------------------------------------------- /tests/RepositoryGeneratorTest.php: -------------------------------------------------------------------------------- 1 | artisan('make:repository Test') 5 | ->assertExitCode(0); 6 | }); 7 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | 'TimWassenburg\\RepositoryGenerator\\Database\\Factories\\'.class_basename($modelName).'Factory' 17 | ); 18 | } 19 | 20 | protected function getPackageProviders($app) 21 | { 22 | return [ 23 | RepositoryGeneratorServiceProvider::class, 24 | ]; 25 | } 26 | 27 | public function getEnvironmentSetUp($app) 28 | { 29 | config()->set('database.default', 'testing'); 30 | } 31 | } 32 | --------------------------------------------------------------------------------