Understanding the Wheels CLI service layer architecture.
Overview
The Wheels CLI uses a service-oriented architecture that separates concerns and provides reusable functionality across commands. This architecture makes the CLI more maintainable, testable, and extensible.
Architecture Diagram
┌─────────────────┐
│ Commands │ ← User interacts with
├─────────────────┤
│ Services │ ← Business logic
├─────────────────┤
│ Models │ ← Data and utilities
├─────────────────┤
│ Templates │ ← Code generation
└─────────────────┘
Core Components
1. Commands (/commands/wheels/)
Commands are the user-facing interface:
// commands/wheels/generate/model.cfc
component extends="wheels.cli.models.BaseCommand" {
property name="codeGenerationService" inject="CodeGenerationService@wheels-cli";
property name="migrationService" inject="MigrationService@wheels-cli";
function run(
required string name,
boolean migration = true,
string properties = "",
boolean force = false
) {
// Delegate to services
var result = codeGenerationService.generateModel(argumentCollection=arguments);
if (arguments.migration) {
migrationService.createTableMigration(arguments.name, arguments.properties);
}
print.greenLine("✓ Model generated successfully");
}
}
component extends="wheels.cli.models.BaseCommand" {
property name="myNewService" inject="MyNewService@wheels-cli";
function run(required string input) {
var result = myNewService.doSomething(arguments.input);
print.line(result);
}
}
Service Patterns
1. Singleton Pattern
Most services are singletons:
component singleton {
// Shared instance across commands
}
2. Factory Pattern
For creating multiple instances:
component {
function createGenerator(required string type) {
switch(arguments.type) {
case "model":
return new ModelGenerator();
case "controller":
return new ControllerGenerator();
}
}
}
3. Strategy Pattern
For different implementations:
component {
function setStrategy(required component strategy) {
variables.strategy = arguments.strategy;
}
function execute() {
return variables.strategy.execute();
}
}
Testing Services
Unit Testing Services
component extends="testbox.system.BaseSpec" {
function beforeAll() {
// Create service instance
variables.templateService = createMock("wheels.cli.models.TemplateService");
}
function run() {
describe("TemplateService", function() {
it("loads templates correctly", function() {
var template = templateService.getTemplate("model");
expect(template).toBeString();
expect(template).toInclude("component extends=""Model""");
});
it("substitutes variables", function() {
var result = templateService.populateTemplate(
"Hello {{name}}",
{name: "World"}
);
expect(result).toBe("Hello World");
});
});
}
}