├── .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 |
2 |
3 | [](https://packagist.org/packages/timwassenburg/laravel-repository-generator)
4 | [](https://github.com/timwassenburg/laravel-repository-generator/actions?query=workflow%3Arun-tests+branch%3Amaster)
5 | [](https://packagist.org/packages/timwassenburg/laravel-repository-generator)
6 | [](https://packagist.org/packages/timwassenburg/laravel-repository-generator)
7 |
8 |
9 |
10 | ## Table of Contents
11 |
12 | - Features
13 | -
14 | Getting started
15 |
19 |
20 | -
21 | Usage
22 |
26 |
27 | - Manual binding
28 | - Testing
29 | - More generator packages
30 | - Contributing
31 | - License
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 |
--------------------------------------------------------------------------------