1
- <br />
2
- <br />
3
1
<div align =" center " >
4
2
<a href =" https://github.com/YorCreative " >
5
3
<img src="content/Laravel-Argonaut-DTO.png" alt="Logo" width="245" height="200">
17
15
<a href =" https://github.com/YorCreative/Laravel-Argonaut-DTO/actions/workflows/phpunit-tests.yml " ><img alt =" PHPUnit " src =" https://github.com/YorCreative/Laravel-Argonaut-DTO/actions/workflows/phpunit-tests.yml/badge.svg " ></a >
18
16
</div >
19
17
20
- Laravel Argonaut DTO is a lightweight, highly composable package for transforming arrays, objects, or collections into structured DTOs (Data Transfer Objects), with built-in support for:
18
+ Laravel Argonaut DTO is a lightweight, highly composable package for transforming arrays, objects, or collections into
19
+ structured DTOs (Data Transfer Objects), with built-in support for:
21
20
22
21
- 🧱 Deep nested transformation and casting
23
22
- 🔁 Type-safe data conversion
@@ -74,6 +73,7 @@ This defines a strongly typed DTO with both validation rules and simple type cas
74
73
Assemblers are responsible for mapping raw inputs (arrays or objects) into your DTOs.
75
74
76
75
``` php
76
+ // static usage example
77
77
class UserDTOAssembler extends ArgonautAssembler
78
78
{
79
79
public static function toUserDTO(object $input): UserDTO
@@ -84,9 +84,26 @@ class UserDTOAssembler extends ArgonautAssembler
84
84
]);
85
85
}
86
86
}
87
+
88
+ // instance usage example
89
+ class UserDTOAssembler extends ArgonautAssembler
90
+ {
91
+ public function __construct(protected UserFormattingService $formattingService)
92
+ {
93
+ //
94
+ }
95
+
96
+ public static function toUserDTO(object $input): UserDTO
97
+ {
98
+ return new UserDTO([
99
+ 'username' => $formatingService->userName($input->display_name),
100
+ 'email' => $formatingService->email($input->email),
101
+ ]);
102
+ }
103
+ }
87
104
```
88
105
89
- > Assembler method names must follow the format ` to<ClassName> ` , and are resolved automatically using ` class_basename ` .
106
+ > Assembler method names must follow the format ` to<ClassName> ` or ` from<ClassName> ` , and are resolved automatically using ` class_basename ` .
90
107
91
108
---
92
109
@@ -95,22 +112,38 @@ class UserDTOAssembler extends ArgonautAssembler
95
112
Use the assembler to transform raw data into structured, casted DTO instances.
96
113
97
114
``` php
115
+ // static usage example
98
116
$dto = UserDTOAssembler::assemble([
99
117
'display_name' => 'jdoe',
100
118
'email' => 'jdoe@example.com',
101
119
], UserDTO::class);
120
+
121
+ // instance usage example
122
+ $dto = $userDTOAssemblerInstance->assembleInstance([
123
+ 'display_name' => 'jdoe',
124
+ 'email' => 'jdoe@example.com',
125
+ ], UserDTO::class);
102
126
```
103
127
104
128
You can also batch transform arrays or collections:
105
129
106
130
``` php
131
+ // static usage
107
132
UserDTOAssembler::fromArray($userArray, UserDTO::class);
108
133
UserDTOAssembler::fromCollection($userCollection, UserDTO::class);
134
+
135
+ // instance usage
136
+ UserDTOAssembler::fromArray($userArray, UserDTO::class, $userDTOAssemblerInstance);
137
+ UserDTOAssembler::fromCollection($userCollection, UserDTO::class, $userDTOAssemblerInstance);
138
+
139
+ // or using the assembler instance's static methods
140
+ $userDTOAssemblerInstance::fromArray($userArray, UserDTO::class, $userDTOAssemblerInstance);
141
+ $userDTOAssemblerInstance::fromCollection($userCollection, UserDTO::class, $userDTOAssemblerInstance);
109
142
```
110
143
111
144
---
112
145
113
- ## 🧪 Real-World Example: Product + Features + Reviews
146
+ ## 🧪 Real-World Static Usage Example: Product + Features + Reviews
114
147
115
148
This example demonstrates nested relationships and complex type casting in action.
116
149
@@ -173,11 +206,155 @@ class ProductDTOAssembler extends ArgonautAssembler
173
206
}
174
207
```
175
208
209
+ ## 🎯 Advanced: Dependency Injection in Assemblers
210
+
211
+ ArgonautAssembler offers enhanced flexibility for your Assembler logic by supporting dependency injection. This allows
212
+ you to leverage services or custom logic, whether defined in static or non-static methods, during the DTO assembly
213
+ process. This is particularly powerful when integrating with Laravel's service container.
214
+
215
+ This feature enables you to:
216
+
217
+ - ** Integrate Application Services:** Easily inject your existing application services (e.g., a custom formatting
218
+ utility, a validation service) directly into your assembler methods.
219
+ - ** Decouple Complex Logic:** Keep your assembler methods focused on the core task of data mapping by delegating more
220
+ complex operations or external data fetching/processing to injected dependencies.
221
+ - ** Improve Testability:** By injecting dependencies, you can more easily mock them in your unit tests, leading to more
222
+ robust and isolated tests for your assemblers.
223
+
224
+ ### How Dependency Injection Works
225
+
226
+ ` ArgonautAssembler ` supports dependency injection in non-static transformation methods (e.g., ` toUserDTO ` or
227
+ ` fromUserDTO ` ) by leveraging Laravel’s service container. When you call ` ArgonautAssembler::assemble() ` ,
228
+ ` fromCollection() ` , ` fromArray() ` , or ` assembleInstance() ` with an instance of the assembler, the transformation method
229
+ is invoked on that instance. Laravel’s container automatically resolves and injects any dependencies declared in the
230
+ method’s signature.
231
+
232
+ - ** Static Methods:** Static transformation methods (e.g., ` public static function toUserDTO($input) ` ) do not support
233
+ dependency injection, as they are called statically without an instance.
234
+ - ** Instance Methods:** Non-static transformation methods (e.g., ` public function toUserDTO($input) ` ) are called on an
235
+ assembler instance, allowing Laravel to inject dependencies into the method.
236
+
237
+ ### Example: Using Dependency Injection
238
+
239
+ Below is an example of an assembler with a non-static transformation method that uses dependency injection to format a
240
+ user’s name via an injected service.
241
+
242
+ ``` php
243
+ <?php
244
+
245
+ namespace App\Assemblers;
246
+
247
+ use App\DTOs\UserDTO;
248
+ use App\Services\UserFormattingService;
249
+ use YorCreative\LaravelArgonautDTO\ArgonautAssembler;
250
+
251
+ class UserAssembler extends ArgonautAssembler
252
+ {
253
+ public function __construct(protected UserFormattingService $formattingService)
254
+ {
255
+ //
256
+ }
257
+
258
+ /**
259
+ * Transform input data into a UserDTO with dependency injection.
260
+ *
261
+ * @param object $input Input data (e.g., from a model or array cast to object).
262
+ * @param UserFormattingService $formatter Injected service for formatting user data.
263
+ * @return UserDTO
264
+ */
265
+ public function toUserDTO(object $input): UserDTO
266
+ {
267
+ return new UserDTO([
268
+ 'full_name' => $formattingService->formatName($input->first_name, $input->last_name),
269
+ 'email' => $input->email,
270
+ 'created_at' => $input->created_at,
271
+ ]);
272
+ }
273
+ }
274
+ ```
275
+
276
+ ### Registering the Assembler
277
+
278
+ ``` php
279
+ // ServiceProvider
280
+ <?php
281
+
282
+ namespace App\Providers;
283
+
284
+ use Illuminate\Support\ServiceProvider;
285
+
286
+ class YourServiceProvider extends ServiceProvider
287
+ {
288
+ public function register()
289
+ {
290
+ $this->app->bind(FormattingServiceInterface::class, function($app) {
291
+ return new FormattingService();
292
+ })
293
+ $this->app->bind(YourArgonautAssembler::clas, function ($app) {
294
+ return new YourArgonautAssembler($app->get(FormattingServiceInterface::class));
295
+ });
296
+ }
297
+
298
+ public function provides()
299
+ {
300
+ return [
301
+ YourArgonautAssembler::class,
302
+ FormattingServiceInterface::class
303
+ ]
304
+ }
305
+ }
306
+ ```
307
+
308
+ #### Using the Assembler
309
+
310
+ To use the assembler with dependency injection, you need to provide an instance of the assembler to the ` assemble `
311
+ method or related methods (` fromCollection ` , ` fromArray ` , or ` assembleInstance ` ). Laravel’s container will resolve the
312
+ dependencies when the method is invoked.
313
+
314
+ ``` php
315
+ <?php
316
+
317
+ use App\Assemblers\UserAssembler;
318
+ use App\DTOs\UserDTO;
319
+
320
+ // Example input (e.g., a model or object)
321
+ $input = (object) [
322
+ 'first_name' => 'John',
323
+ 'last_name' => 'Doe',
324
+ 'email' => 'john.doe@example.com',
325
+ 'created_at' => now(),
326
+ ];
327
+
328
+ // Creating an assembler instance
329
+ $formattingService = new UserFormattingService();
330
+ $assembler = new UserAssembler($formattingService);
331
+ // or using the container instance
332
+ $assembler = resolve(YourArgonautAssembler::class);
333
+
334
+ // Pass the $assembler instance
335
+ $userDTO = UserAssembler::assemble($input, UserDTO::class, $assembler);
336
+ // Or use the instance method
337
+ $userDTO = $assembler->assembleInstance($input, UserDTO::class);
338
+
339
+ // Transform a collection passing the $assembler instance
340
+ $array = [$input, $input];
341
+ $collection = collect($array);
342
+ $userDTOs = UserAssembler::fromCollection($collection, UserDTO::class, $assembler);
343
+ $userDTOs = $assembler::fromArray($array, UserDTO::class, $assembler)
344
+ ```
345
+
346
+ In this example:
347
+
348
+ - The ` toUserDTO ` method requires a ` UserFormattingService ` dependency.
349
+ - The assembler instance (` $assembler ` ) is passed to ` assemble ` , ` fromArray ` or ` fromCollection ` , ensuring the
350
+ non-static ` toUserDTO ` method is invoked on the instance.
351
+
176
352
---
177
353
178
- ## 🎯 DTOs with Prioritized Attributes and Custom Setters
354
+ ## Advanced: 🎯 DTOs with Prioritized Attributes and Custom Setters
179
355
180
- ArgonautDTO allows you to prioritize the assignment of specific fields using ` $prioritizedAttributes ` , which is critical for cases where one field influences others.
356
+ ArgonautDTO allows you to prioritize the assignment of specific fields using ` $prioritizedAttributes ` , which is critical
357
+ for cases where one field influences others.
181
358
182
359
``` php
183
360
class UserDTO extends ArgonautDTO
@@ -237,13 +414,13 @@ protected array $casts = [
237
414
];
238
415
```
239
416
240
- | Cast Type | Example | Description |
241
- | ------------------------ | --------------------------------------------------- | ---- ----------------------------------|
242
- | Scalar | ` 'string' ` , ` 'int' ` , etc. | Native PHP type cast |
243
- | Single DTO | ` ProfileDTO::class ` | Cast an array to a DTO instance |
244
- | Array of DTOs | ` [RoleDTO::class] ` | Cast to array of DTOs |
245
- | Collection of DTOs | ` Collection::class . ':' . CommentDTO::class ` | Cast to a Laravel Collection |
246
- | Date casting | ` Carbon::class ` | Cast to Carbon/DateTime instance |
417
+ | Cast Type | Example | Description |
418
+ | --------------------| -----------------------------------------------| ----------------------------------|
419
+ | Scalar | ` 'string' ` , ` 'int' ` , etc. | Native PHP type cast |
420
+ | Single DTO | ` ProfileDTO::class ` | Cast an array to a DTO instance |
421
+ | Array of DTOs | ` [RoleDTO::class] ` | Cast to array of DTOs |
422
+ | Collection of DTOs | ` Collection::class . ':' . CommentDTO::class ` | Cast to a Laravel Collection |
423
+ | Date casting | ` Carbon::class ` | Cast to Carbon/DateTime instance |
247
424
248
425
---
249
426
@@ -301,4 +478,4 @@ composer test
301
478
302
479
## 📃 License
303
480
304
- This package is open-sourced software licensed under the [ MIT license] ( LICENSE ) .
481
+ This package is open-sourced software licensed under the [ MIT license] ( LICENSE ) .
0 commit comments