[{"data":1,"prerenderedAt":561},["ShallowReactive",2],{"page-\u002Fv1\u002Fcore\u002Fuse-cases-and-dtos":3},{"id":4,"title":5,"body":6,"description":554,"extension":555,"meta":556,"navigation":395,"path":557,"seo":558,"stem":559,"__hash__":560},"content\u002Fv1\u002Fcore\u002Fuse-cases-and-dtos.md","Use cases and DTOs",{"type":7,"value":8,"toc":543},"minimark",[9,13,18,116,120,137,193,199,225,238,248,252,276,283,288,345,427,431,491,499,504,524,528,531,539],[10,11,5],"h1",{"id":12},"use-cases-and-dtos",[14,15,17],"h2",{"id":16},"naming-conventions","Naming conventions",[19,20,21,37],"table",{},[22,23,24],"thead",{},[25,26,27,31,34],"tr",{},[28,29,30],"th",{},"Component",[28,32,33],{},"Convention",[28,35,36],{},"Example",[38,39,40,57,72,86,101],"tbody",{},[25,41,42,46,52],{},[43,44,45],"td",{},"Use Case",[43,47,48],{},[49,50,51],"code",{},"[Name]UseCase",[43,53,54],{},[49,55,56],{},"PlaceOrderUseCase",[25,58,59,62,67],{},[43,60,61],{},"Application DTO",[43,63,64],{},[49,65,66],{},"[Name]DTO",[43,68,69],{},[49,70,71],{},"PlaceOrderDTO",[25,73,74,77,81],{},[43,75,76],{},"Domain DTO",[43,78,79],{},[49,80,66],{},[43,82,83],{},[49,84,85],{},"OrderLineDTO",[25,87,88,91,96],{},[43,89,90],{},"Port",[43,92,93],{},[49,94,95],{},"[Name]…Interface",[43,97,98],{},[49,99,100],{},"OrderRepositoryInterface",[25,102,103,106,111],{},[43,104,105],{},"Entity",[43,107,108],{},[49,109,110],{},"[Name]Entity",[43,112,113],{},[49,114,115],{},"OrderEntity",[14,117,119],{"id":118},"use-case-suffix-and-folder-depth","Use Case suffix and folder depth",[121,122,123,124,127,128,132,133,136],"p",{},"The ",[49,125,126],{},"UseCase"," suffix is governed by ",[129,130,131],"strong",{},"folder depth"," under ",[49,134,135],{},"Application\u002FUseCases\u002F",".",[19,138,139,151],{},[22,140,141],{},[25,142,143,146,149],{},[28,144,145],{},"Location",[28,147,148],{},"Suffix required?",[28,150,36],{},[38,152,153,175],{},[25,154,155,161,170],{},[43,156,157,158],{},"Directly inside ",[49,159,160],{},"UseCases\u002F{Capability}\u002F",[43,162,163,166,167],{},[129,164,165],{},"Yes"," — ",[49,168,169],{},"*UseCase",[43,171,172],{},[49,173,174],{},"PlaceOrderUseCase.php",[25,176,177,183,188],{},[43,178,179,180],{},"Inside any nested subfolder under ",[49,181,182],{},"{Capability}\u002F",[43,184,185],{},[129,186,187],{},"No",[43,189,190],{},[49,191,192],{},"OrderProcessor.php",[121,194,195,196,198],{},"Mirror the same ",[49,197,182],{}," folders for:",[200,201,202,208,213,219],"ul",{},[203,204,205],"li",{},[49,206,207],{},"Domain\u002FPorts\u002F{Capability}\u002F",[203,209,210],{},[49,211,212],{},"Application\u002FDTO\u002F{Capability}\u002F",[203,214,215,216],{},"Outbound ACL ports → ",[49,217,218],{},"Domain\u002FPorts\u002FAcl\u002F",[203,220,221,222],{},"Module façades → ",[49,223,224],{},"Domain\u002FPorts\u002FModule\u002F",[226,227,228],"blockquote",{},[121,229,230,233,234,237],{},[49,231,232],{},"{Capability}"," is a documentation placeholder — never a literal ",[49,235,236],{},"Feature\u002F"," directory.",[239,240,246],"pre",{"className":241,"code":243,"language":244,"meta":245},[242],"language-text","Application\u002FUseCases\u002F\n└── Order\u002F\n    ├── PlaceOrderUseCase.php              ✅ UseCase suffix\n    ├── CancelOrderUseCase.php             ✅ UseCase suffix\n    └── Processing\u002F                        nested — no suffix required\n        ├── OrderProcessor.php\n        └── Payment\u002F\n            └── CreditCardPaymentHandler.php\n","text","",[49,247,243],{"__ignoreMap":245},[14,249,251],{"id":250},"entry-point-boundary-strict","Entry-point boundary (strict)",[200,253,254,267,270],{},[203,255,256,257,260,261,263,264,136],{},"Only ",[129,258,259],{},"first-level"," ",[49,262,169],{}," classes may be invoked from UI, CLI, jobs, or admin actions in ",[129,265,266],{},"the same module",[203,268,269],{},"Nested helpers are internal. UI must never call them.",[203,271,272,275],{},[129,273,274],{},"Other modules must never call this module’s Use Cases."," Cross-module work uses ACL or Events only.",[14,277,279,280],{"id":278},"entry-method-__invoke","Entry method: ",[49,281,282],{},"__invoke",[121,284,285,286,136],{},"Every first-level Use Case exposes exactly one public entry: ",[49,287,282],{},[19,289,290,300],{},[22,291,292],{},[25,293,294,297],{},[28,295,296],{},"Rule",[28,298,299],{},"Detail",[38,301,302,320,334],{},[25,303,304,307],{},[43,305,306],{},"Method name",[43,308,309,310,312,313,316,317],{},"Always ",[49,311,282],{}," — not ",[49,314,315],{},"execute()"," \u002F ",[49,318,319],{},"handle()",[25,321,322,325],{},[43,323,324],{},"Invocation",[43,326,327,330,331],{},[49,328,329],{},"($useCase)($dto)"," or ",[49,332,333],{},"$useCase->__invoke($dto)",[25,335,336,339],{},[43,337,338],{},"Nested helpers",[43,340,341,342,344],{},"Not Use Cases; no ",[49,343,282],{}," requirement",[239,346,350],{"className":347,"code":348,"language":349,"meta":245,"style":245},"language-php shiki shiki-themes github-light github-dark","class PlaceOrderUseCase\n{\n    public function __construct(\n        private OrderRepositoryInterface $orders,\n        private WarehouseAvailabilityPortInterface $warehouse,\n    ) {}\n\n    public function __invoke(PlaceOrderDTO $dto): OrderEntity\n    {\n        \u002F\u002F orchestrate Domain + ports\n    }\n}\n","php",[49,351,352,360,366,372,378,384,390,397,403,409,415,421],{"__ignoreMap":245},[353,354,357],"span",{"class":355,"line":356},"line",1,[353,358,359],{},"class PlaceOrderUseCase\n",[353,361,363],{"class":355,"line":362},2,[353,364,365],{},"{\n",[353,367,369],{"class":355,"line":368},3,[353,370,371],{},"    public function __construct(\n",[353,373,375],{"class":355,"line":374},4,[353,376,377],{},"        private OrderRepositoryInterface $orders,\n",[353,379,381],{"class":355,"line":380},5,[353,382,383],{},"        private WarehouseAvailabilityPortInterface $warehouse,\n",[353,385,387],{"class":355,"line":386},6,[353,388,389],{},"    ) {}\n",[353,391,393],{"class":355,"line":392},7,[353,394,396],{"emptyLinePlaceholder":395},true,"\n",[353,398,400],{"class":355,"line":399},8,[353,401,402],{},"    public function __invoke(PlaceOrderDTO $dto): OrderEntity\n",[353,404,406],{"class":355,"line":405},9,[353,407,408],{},"    {\n",[353,410,412],{"class":355,"line":411},10,[353,413,414],{},"        \u002F\u002F orchestrate Domain + ports\n",[353,416,418],{"class":355,"line":417},11,[353,419,420],{},"    }\n",[353,422,424],{"class":355,"line":423},12,[353,425,426],{},"}\n",[14,428,430],{"id":429},"application-dto-vs-domain-dto","Application DTO vs Domain DTO",[19,432,433,449],{},[22,434,435],{},[25,436,437,440,443,446],{},[28,438,439],{},"Layer",[28,441,442],{},"Path",[28,444,445],{},"Purpose",[28,447,448],{},"Typical flow",[38,450,451,469],{},[25,452,453,458,463,466],{},[43,454,455],{},[129,456,457],{},"Application",[43,459,460],{},[49,461,462],{},"Application\u002FDTO\u002F",[43,464,465],{},"Carry validated UI input into a Use Case",[43,467,468],{},"Controller → Use Case",[25,470,471,476,481,488],{},[43,472,473],{},[129,474,475],{},"Domain",[43,477,478],{},[49,479,480],{},"Domain\u002FDTO\u002F",[43,482,483,484,487],{},"Structured data ",[129,485,486],{},"inside"," the module",[43,489,490],{},"Use Case ↔ Entity \u002F Port",[200,492,493,496],{},[203,494,495],{},"Application DTOs receive external input. Controllers map validated request data into them.",[203,497,498],{},"Domain DTOs never cross the HTTP\u002FUI boundary as the primary API contract.",[500,501,503],"h3",{"id":502},"illustrative-ordering-examples","Illustrative Ordering examples",[200,505,506,512,518],{},[203,507,508,511],{},[49,509,510],{},"Application\u002FDTO\u002FOrder\u002FPlaceOrderDTO.php"," — API input when placing an order.",[203,513,514,517],{},[49,515,516],{},"Domain\u002FDTO\u002FOrderLineDTO.php"," — line data while building the order.",[203,519,520,523],{},[49,521,522],{},"Domain\u002FDTO\u002FTotalsBreakdownDTO.php"," — totals consumed by another Use Case in the same module.",[14,525,527],{"id":526},"composition-inside-application","Composition inside Application",[121,529,530],{},"A first-level Use Case may delegate to nested helpers in the same feature tree. Helpers receive already-injected ports (or are resolved with the same port interfaces). They must not import ORM types or become a second UI entry point.",[121,532,533,534,136],{},"Next: ",[535,536,538],"a",{"href":537},"\u002Fv1\u002Fcore\u002Fports-and-persistence","ports & persistence",[540,541,542],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":245,"searchDepth":362,"depth":362,"links":544},[545,546,547,548,550,553],{"id":16,"depth":362,"text":17},{"id":118,"depth":362,"text":119},{"id":250,"depth":362,"text":251},{"id":278,"depth":362,"text":549},"Entry method: __invoke",{"id":429,"depth":362,"text":430,"children":551},[552],{"id":502,"depth":368,"text":503},{"id":526,"depth":362,"text":527},"First-level UseCase entry points, nested helpers, and Application vs Domain DTO rules.","md",{},"\u002Fv1\u002Fcore\u002Fuse-cases-and-dtos",{"title":5,"description":554},"v1\u002Fcore\u002Fuse-cases-and-dtos","arS-lo64-0tr7i-XnaqTKhcbZxcFtV-sekyCkE_Nq9g",1786241411691]