Skip to content

Commit b1a8876

Browse files
committed
feat: add attribute binding support for Laravel 12+
1 parent 3f4de65 commit b1a8876

File tree

4 files changed

+231
-3
lines changed

4 files changed

+231
-3
lines changed

config/repository.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,25 @@
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', 'attribute'),
25+
726
/*
827
|--------------------------------------------------------------------------
928
| Composer Autoload Settings

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)