Skip to content

Commit e0459e8

Browse files
authored
Merge pull request #8 from longaodai/develop
Develop
2 parents 2fa0a69 + 6744c98 commit e0459e8

File tree

5 files changed

+277
-24
lines changed

5 files changed

+277
-24
lines changed

README.md

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ Service Interface .............. App\Services\User\UserServiceInterface
5656
Service Implementation ......... App\Services\User\UserService
5757
```
5858

59-
### Register Service Providers
59+
## Important Note: Service Provider Registration
60+
61+
The service provider registration depends on your Laravel version and configuration:
62+
63+
### For Provider Binding Mode (Default - Works well on all Laravel versions)
64+
65+
If your `config/repository.php` has `'binding_mode' => 'provider'` (default), you **must** register the service providers.
6066

6167
Add the generated service providers to your `bootstrap/providers.php` (only once after running the first make repository command):
6268

@@ -72,6 +78,19 @@ return [
7278
];
7379
```
7480

81+
### For Attribute Binding Mode (Laravel >= 12)
82+
83+
If your `config/repository.php` has `'binding_mode' => 'attribute'` and you're using **Laravel 12+**, you can skip the service provider registration entirely. The package will automatically register bindings using PHP attributes.
84+
85+
**Configuration Example:**
86+
```php
87+
// config/repository.php
88+
return [
89+
'binding_mode' => 'attribute', // Change to 'attribute' for Laravel 12+
90+
// ... other config
91+
];
92+
```
93+
7594
## Usage
7695
### Controller Integration
7796

@@ -290,16 +309,16 @@ class UserService implements UserServiceInterface
290309

291310
The base repository provides these methods out of the box:
292311

293-
| Method | Description | Example |
294-
|--------|--------------------------------|-----------------------------------------------------|
295-
| `all()` | Get all records | `$service->all()` |
296-
| `getList($params)` | Get paginated list with filters | `$service->getList(['per_page' => 10])` |
297-
| `find($conditions)` | Find by id | `$service->find(['id' => 1])` |
298-
| `first($conditions)` | Get first record by conditions | `$service->first(['status' => 'active'])` |
299-
| `create($data)` | Create new record | `$service->create(['name' => 'John'])` |
300-
| `update($data, $conditions)` | Update records | `$service->update(['name' => 'Jane'], ['id' => 1])` |
301-
| `updateOrCreate($conditions, $data)` | Update or create record | `$service->updateOrCreate(['name' => 'Test'], ['email' => 'test@example.com'])` |
302-
| `destroy($conditions)` | Delete records | `$service->destroy(['id' => 1])` |
312+
| Method | Description | Example |
313+
|------------------------------|--------------------------------|---------------------------------------------------------------------------------|
314+
| `all()` | Get all records | `$service->all()` |
315+
| `getList()` | Get paginated list with filters | `$service->getList(['status' => 'active'], ['per_page' => 10])` |
316+
| `find()` | Find by id | `$service->find(['id' => 1])` |
317+
| `first()` | Get first record by conditions | `$service->first(['status' => 'active'])` |
318+
| `create()` | Create new record | `$service->create(['name' => 'John'])` |
319+
| `update()` | Update records | `$service->update(['name' => 'Jane'], ['id' => 1])` |
320+
| `updateOrCreate()` | Update or create record | `$service->updateOrCreate(['name' => 'Test'], ['email' => 'test@example.com'])` |
321+
| `destroy()` | Delete records | `$service->destroy(['id' => 1])` |
303322

304323
## Method Examples
305324

@@ -311,10 +330,8 @@ $users = $userService->all();
311330

312331
// Get paginated list with search
313332
$users = $userService->getList([
314-
'per_page' => 20,
315-
'search' => 'john',
316333
'status' => 'active'
317-
]);
334+
], ['per_page' => 20,]);
318335

319336
// Find specific user
320337
$user = $userService->find(['id' => 1]);

config/repository.php

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,45 @@
44

55
return [
66

7+
/*
8+
|--------------------------------------------------------------------------
9+
| Repository Binding Mode
10+
|--------------------------------------------------------------------------
11+
|
12+
| Choose how repositories are bound into Laravel's IoC container:
13+
|
14+
| Mode Description Laravel Version
15+
| ------------ ------------------------------------------ ----------------
16+
| "provider" Generates RepositoryServiceProvider with Laravel any
17+
| register() and provides() methods. (works everywhere)
18+
|
19+
| "attribute" Uses PHP Attributes #[Singleton], #[Bind] Laravel 12+
20+
| for auto-binding repositories. (not backward compatible)
21+
|
22+
*/
23+
24+
'binding_mode' => env('REPOSITORY_BINDING_MODE', 'provider'),
25+
726
/*
827
|--------------------------------------------------------------------------
928
| Composer Autoload Settings
1029
|--------------------------------------------------------------------------
1130
|
12-
| Control whether "composer dump-autoload" should run automatically
13-
| after generating repositories or services.
31+
| These options control whether "composer dump-autoload" should run
32+
| automatically after generating repositories or services.
33+
|
34+
| Purpose:
35+
| Running "composer dump-autoload" will refresh the Composer autoloader
36+
| so that Laravel can immediately recognize new bindings between
37+
| interfaces and their service/repository implementations.
1438
|
1539
| Logic:
16-
| - 'dump_auto_load' = true → always run automatically.
17-
| - 'dump_auto_load' = false + 'ask_dump_auto_load' = true → prompt user.
18-
| - 'dump_auto_load' = false + 'ask_dump_auto_load' = false → skip.
40+
| - 'dump_auto_load' = true
41+
| → Always run automatically after generation.
42+
| - 'dump_auto_load' = false + 'ask_dump_auto_load' = true
43+
| → Ask for confirmation before running.
44+
| - 'dump_auto_load' = false + 'ask_dump_auto_load' = false
45+
| → Never run (manual dump-autoload required).
1946
|
2047
*/
2148

@@ -30,8 +57,8 @@
3057
| Pagination Limit
3158
|--------------------------------------------------------------------------
3259
|
33-
| Base limit for paginated lists when using the repository methods.
34-
| Default: 20 records per page.
60+
| Default number of records per page for repository pagination methods.
61+
| Default: 20 (can be overridden here).
3562
|
3663
*/
3764
'limit_paginate' => 20,

src/Console/CreatePatternCommand.php

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ class CreatePatternCommand extends Command
5252
private const TYPE_CLASS = 'class';
5353
private const TYPE_INTERFACE = 'interface';
5454

55+
/**
56+
* Repository binding mode using PHP attributes
57+
* (#[Bind], #[Singleton], etc.).
58+
* Recommended for Laravel 12+.
59+
*/
60+
private const BINDING_MODE_ATTRIBUTE = 'attribute';
61+
62+
/**
63+
* Repository binding mode using a traditional Service Provider
64+
* with register() and provides() methods.
65+
* Recommended for Laravel 11 or below
66+
*/
67+
private const BINDING_MODE_PROVIDER = 'provider';
68+
5569
/**
5670
* Stub file paths mapping.
5771
*
@@ -108,6 +122,11 @@ protected function initializeStubs(): void
108122
'provider_repository' => $stubPath . 'provider.repository.stub',
109123
'provider_service' => $stubPath . 'provider.service.stub',
110124
];
125+
126+
if (config('repository.binding_mode') == self::BINDING_MODE_ATTRIBUTE) {
127+
$this->stubs['repository_interface'] = $stubPath . 'interface.repository.attribute.stub';
128+
$this->stubs['service_interface'] = $stubPath . 'interface.service.attribute.stub';
129+
}
111130
}
112131

113132
/**
@@ -126,7 +145,10 @@ public function handle(): int
126145
return Command::FAILURE;
127146
}
128147

129-
$this->updateServiceProviders();
148+
if (config('repository.binding_mode') == self::BINDING_MODE_PROVIDER) {
149+
$this->generateServiceProviders();
150+
}
151+
130152
$this->runComposerDumpAutoload();
131153
$this->displaySuccessMessages();
132154

@@ -223,11 +245,11 @@ private function setDirectoryPaths(): void
223245
}
224246

225247
/**
226-
* Update repository and service provider files with new bindings.
248+
* Generate repository and service provider files with new bindings.
227249
*
228250
* @return void
229251
*/
230-
protected function updateServiceProviders(): void
252+
protected function generateServiceProviders(): void
231253
{
232254
$providers = [
233255
'RepositoryServiceProvider' => self::PATH_REPOSITORY,
@@ -396,6 +418,7 @@ private function getStubReplacements(string $path): array
396418
'#InterfaceName' => $interfaceName,
397419
'#ClassName' => $className,
398420

421+
'#Bind' => "\\$namespace\\$className::class",
399422
'#InterfaceProvides' => "{$interfaceName}::class,\n\t\t\t#InterfaceProvides",
400423
'#Singleton' => "\$this->app->singleton({$interfaceName}::class, {$className}::class);\n\t\t#Singleton",
401424

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
namespace #Namespace;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use LongAoDai\Repository\RepositoryResponse;
7+
use Illuminate\Container\Attributes\Bind;
8+
use Illuminate\Container\Attributes\Singleton;
9+
10+
/**
11+
* Interface #InterfaceName
12+
*
13+
* Defines the contract for repository classes using the Repository pattern.
14+
* Each repository should extend BaseRepository and implement these methods.
15+
*
16+
* @package #Namespace
17+
*/
18+
#[Bind(#Bind)]
19+
#[Singleton]
20+
interface #InterfaceName
21+
{
22+
/**
23+
* Retrieve all records with optional filters.
24+
*
25+
* @param RepositoryResponse $params
26+
* @return mixed
27+
*/
28+
public function all(RepositoryResponse $params): mixed;
29+
30+
/**
31+
* Retrieve paginated list of records.
32+
*
33+
* @param RepositoryResponse $params
34+
* @return mixed
35+
*/
36+
public function getList(RepositoryResponse $params): mixed;
37+
38+
/**
39+
* Find a record by ID.
40+
*
41+
* @param RepositoryResponse $params
42+
* @return Model|null
43+
*/
44+
public function find(RepositoryResponse $params): ?Model;
45+
46+
/**
47+
* Get the first record that matches filters.
48+
*
49+
* @param RepositoryResponse $params
50+
* @return Model|null
51+
*/
52+
public function first(RepositoryResponse $params): ?Model;
53+
54+
/**
55+
* Create a new record.
56+
*
57+
* @param RepositoryResponse $params
58+
* @return Model
59+
*/
60+
public function create(RepositoryResponse $params): Model;
61+
62+
/**
63+
* Update existing records.
64+
*
65+
* @param RepositoryResponse $params
66+
* @return int Number of affected rows
67+
*/
68+
public function update(RepositoryResponse $params): int;
69+
70+
/**
71+
* Update or create a record.
72+
*
73+
* @param RepositoryResponse $params
74+
* @return Model
75+
*/
76+
public function updateOrCreate(RepositoryResponse $params): Model;
77+
78+
/**
79+
* Delete records.
80+
*
81+
* @param RepositoryResponse $params
82+
* @return int Number of deleted rows
83+
*/
84+
public function destroy(RepositoryResponse $params): int;
85+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace #Namespace;
6+
7+
use Illuminate\Support\Collection;
8+
use Illuminate\Container\Attributes\Bind;
9+
use Illuminate\Container\Attributes\Singleton;
10+
use LongAoDai\Repository\Exceptions\RepositoryFailureHandlingException;
11+
12+
/**
13+
* Interface #InterfaceName
14+
*
15+
* Defines the contract for service classes interacting with repositories.
16+
* Each method corresponds to a BaseService implementation.
17+
*/
18+
#[Bind(#Bind)]
19+
#[Singleton]
20+
interface #InterfaceName
21+
{
22+
/**
23+
* Retrieve all records.
24+
*
25+
* @param Collection|array $data
26+
* @param Collection|array $options
27+
* @return mixed
28+
*/
29+
public function all(Collection|array $data = [], Collection|array $options = []): mixed;
30+
31+
/**
32+
* Retrieve paginated list of records.
33+
*
34+
* @param Collection|array $data
35+
* @param Collection|array $options
36+
* @return mixed
37+
*/
38+
public function getList(Collection|array $data = [], Collection|array $options = []): mixed;
39+
40+
/**
41+
* Show a single record by ID.
42+
*
43+
* @param Collection|array $data
44+
* @param Collection|array $options
45+
* @return mixed
46+
*
47+
* @throws RepositoryFailureHandlingException
48+
*/
49+
public function show(Collection|array $data = [], Collection|array $options = []): mixed;
50+
51+
/**
52+
* Get the first record by conditions.
53+
*
54+
* @param Collection|array $data
55+
* @param Collection|array $options
56+
* @return mixed
57+
*/
58+
public function getFirstBy(Collection|array $data = [], Collection|array $options = []): mixed;
59+
60+
/**
61+
* Create a new record.
62+
*
63+
* @param Collection|array $data
64+
* @param Collection|array $options
65+
* @return mixed
66+
*
67+
* @throws RepositoryFailureHandlingException
68+
*/
69+
public function store(Collection|array $data = [], Collection|array $options = []): mixed;
70+
71+
/**
72+
* Update existing record(s).
73+
*
74+
* @param Collection|array $data
75+
* @param Collection|array $options
76+
* @return mixed
77+
*
78+
* @throws RepositoryFailureHandlingException
79+
*/
80+
public function update(Collection|array $data = [], Collection|array $options = []): mixed;
81+
82+
/**
83+
* Update an existing record or create a new one.
84+
*
85+
* @param Collection|array $data
86+
* @param Collection|array $options
87+
* @return mixed
88+
*/
89+
public function updateOrCreate(Collection|array $data = [], Collection|array $options = []): mixed;
90+
91+
/**
92+
* Delete record(s).
93+
*
94+
* @param Collection|array $data
95+
* @param Collection|array $options
96+
* @return mixed
97+
*
98+
* @throws RepositoryFailureHandlingException
99+
*/
100+
public function destroy(Collection|array $data = [], Collection|array $options = []): mixed;
101+
}

0 commit comments

Comments
 (0)