ResourceGenerator
Generates the CLOSED compound: everything a REST resource needs to exist, persist, serve, and be judged — one call, zero manual steps among the required consequences. This is the shape a measured cattle run paid 583k tokens and 60 turns to assemble by hand out of `make entity` + guidance prose; the rule extracted from that run is this generator's contract: a deterministic operation that knows a required postcondition materializes it, or the run is incomplete. Everything is COMPOSED, never reimplemented: - {@see CrudGenerator} (which itself composes {@see EntityGenerator}) contributes the entity from the `--fields` DSL (enums with declared cases materialized alongside), the 5-method REST controller, and the combined repository+controller+routes wiring plugin. - {@see ServiceGenerator} contributes a `<Name>Service` domain seam; its registration is spliced into the SAME wiring plugin (marker anchor or {@see PluginSurgeon} structural insert), because two generators planning two plugins at one path would be the composition bug {@see CrudGenerator} already refuses for {@see EntityGenerator}. - {@see TestGenerator} contributes the behavioral judge, red on purpose, so the thing that can say what the resource must DO exists from birth. One deliberate degradation, NAMED instead of hidden: `<field>:belongsTo:<Target>` cannot exist as a relation in a runtime entity (`milpa/data` has no relation concept — {@see EntityGenerator}'s runtime path refuses it with exactly this advice), so the resource stores the related id as the `<target>_id:int` scalar that advice prescribes, and the postcondition report carries one advisory check per degraded relation so the caller learns it from the verdict, not from a surprise. Only a RUNTIME convention exists — see {@see generate()} for why LEGACY throws.
ResourceGenerator::__construct()
public function __construct(Milpa\DevTools\Make\Generators\CrudGenerator $crudGenerator = new CrudGenerator(), Milpa\DevTools\Make\Generators\ServiceGenerator $serviceGenerator = new ServiceGenerator(), Milpa\DevTools\Make\Generators\TestGenerator $testGenerator = new TestGenerator(), Milpa\DevTools\Make\MarkerInserter $markers = new MarkerInserter(), Milpa\DevTools\Make\PluginSurgeon $surgeon = new PluginSurgeon(), Milpa\DevTools\Make\ConventionDetector $detector = new ConventionDetector()):Parameters
| Name | Type | Description |
|---|---|---|
| $crudGenerator | Milpa\DevTools\Make\Generators\CrudGenerator | |
| $serviceGenerator | Milpa\DevTools\Make\Generators\ServiceGenerator | |
| $testGenerator | Milpa\DevTools\Make\Generators\TestGenerator | |
| $markers | Milpa\DevTools\Make\MarkerInserter | |
| $surgeon | Milpa\DevTools\Make\PluginSurgeon | |
| $detector | Milpa\DevTools\Make\ConventionDetector |
ResourceGenerator::name()
public function name(): stringThe `<what>` token this generator answers to: `'resource'`.
ResourceGenerator::relationColumn()
public static function relationColumn(string $target): stringThe scalar column a `belongsTo:<Target>` field degrades to under the runtime convention — `Author` -> `author_id`, `UserGroup` -> `user_group_id`. Public and static because the {@see \Milpa\DevTools\Make\PostconditionVerifier} must name the SAME column in its relation advisory that the generator actually emitted; one authority, two readers.
Parameters
| Name | Type | Description |
|---|---|---|
| $target | string |
ResourceGenerator::generate()
public function generate(Milpa\DevTools\Make\GenerationContext $context): Milpa\DevTools\Make\GenerationResultRenders the composed resource per the detected/overridden {@see Flavor}.
Parameters
| Name | Type | Description |
|---|---|---|
| $context | Milpa\DevTools\Make\GenerationContext |
Throws
\RuntimeException When the detected/forced flavor is {@see Flavor::Legacy} — the
composed resource is a runtime-only concept, same reasoning as
{@see CrudGenerator::generate()}.