1- <br />
2- <br />
31<div align =" center " >
42 <a href =" https://github.com/YorCreative " >
53 <img src="content/Laravel-Argonaut-DTO.png" alt="Logo" width="245" height="200">
1715<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 >
1816</div >
1917
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:
2120
2221- 🧱 Deep nested transformation and casting
2322- 🔁 Type-safe data conversion
@@ -74,6 +73,7 @@ This defines a strongly typed DTO with both validation rules and simple type cas
7473Assemblers are responsible for mapping raw inputs (arrays or objects) into your DTOs.
7574
7675``` php
76+ // static usage example
7777class UserDTOAssembler extends ArgonautAssembler
7878{
7979 public static function toUserDTO(object $input): UserDTO
@@ -84,9 +84,26 @@ class UserDTOAssembler extends ArgonautAssembler
8484 ]);
8585 }
8686}
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+ }
87104```
88105
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 ` .
90107
91108---
92109
@@ -95,22 +112,38 @@ class UserDTOAssembler extends ArgonautAssembler
95112Use the assembler to transform raw data into structured, casted DTO instances.
96113
97114``` php
115+ // static usage example
98116$dto = UserDTOAssembler::assemble([
99117 'display_name' => 'jdoe',
100118101119], UserDTO::class);
120+
121+ // instance usage example
122+ $dto = $userDTOAssemblerInstance->assembleInstance([
123+ 'display_name' => 'jdoe',
124+ 125+ ], UserDTO::class);
102126```
103127
104128You can also batch transform arrays or collections:
105129
106130``` php
131+ // static usage
107132UserDTOAssembler::fromArray($userArray, UserDTO::class);
108133UserDTOAssembler::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);
109142```
110143
111144---
112145
113- ## 🧪 Real-World Example: Product + Features + Reviews
146+ ## 🧪 Real-World Static Usage Example: Product + Features + Reviews
114147
115148This example demonstrates nested relationships and complex type casting in action.
116149
@@ -173,11 +206,155 @@ class ProductDTOAssembler extends ArgonautAssembler
173206}
174207```
175208
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+ 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+
176352---
177353
178- ## 🎯 DTOs with Prioritized Attributes and Custom Setters
354+ ## Advanced: 🎯 DTOs with Prioritized Attributes and Custom Setters
179355
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.
181358
182359``` php
183360class UserDTO extends ArgonautDTO
@@ -237,13 +414,13 @@ protected array $casts = [
237414];
238415```
239416
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 |
247424
248425---
249426
@@ -301,4 +478,4 @@ composer test
301478
302479## 📃 License
303480
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