Object Relational Mapping
Creating Records
Reading Records
Updating Records
Deleting Records
Column Statistics
Dynamic Finders
Getting Paginated Data
Associations
Nested Properties
Object Validation
Object Callbacks
Calculated Properties
Transactions
Dirty Records
Soft Delete
Automatic Time Stamps
Using Multiple Data Sources
wheels generate controller
Generate a controller with actions and optional views.
Synopsis
wheels generate controller name=<controllerName> [options]
#Can also be used as:
wheels g controller name=<controllerName> [options]
Parameter Syntax
CommandBox supports multiple parameter formats:
- Named parameters:
name=value
(e.g.,name=Products
,actions=index,show
) - Flag parameters:
--flag
equalsflag=true
(e.g.,--rest
equalsrest=true
) - Flag with value:
--flag=value
equalsflag=value
(e.g.,--actions=index,show
)
Note: Flag syntax (--flag
) avoids positional/named parameter conflicts and is recommended for boolean options.
Description
The wheels generate controller
command creates a new controller CFC file with specified actions and optionally generates corresponding view files. It supports both traditional and RESTful controller patterns.
Arguments
| Argument | Description | Default |
|----------|-------------|---------|
| name
| Name of the controller to create (usually plural) | Required |
Options
| Option | Description | Default |
|--------|-------------|---------|
| actions
| Actions to generate (comma-delimited) | index
|
| rest
| Generate RESTful controller with CRUD actions | false
|
| api
| Generate API controller (no view-related actions) | false
|
| description
| Controller description comment | ""
|
| force
| Overwrite existing files | false
|
Examples
Basic controller
wheels generate controller name=Products
Creates:
app/controllers/Products.cfc
withindex
action
Controller with description
wheels generate controller name=Users --description="Handles user management operations"
Creates controller with description comment at the top.
Controller with multiple actions
wheels generate controller name=Products --actions=index,show,new,create
Creates controller with specified actions.
RESTful controller
wheels generate controller name=Products --rest
Automatically generates all RESTful actions and views:
index
,show
,new
,create
,edit
,update
,delete
API controller
wheels generate controller name=Orders --api --description="API endpoint for order processing"
Creates:
app/controllers/Orders.cfc
with JSON responses- No view files generated
Custom actions with description
wheels generate controller name=Reports --actions=dashboard,monthly,export --description="Reporting controller"
Generated Code
Basic Controller
component extends="Controller" {
/**
* Controller config settings
**/
function config() {
}
/**
* index action
*/
function index() {
// TODO: Implement index action
}
}
Controller with Description
/**
* Handles user management operations
*/
component extends="Controller" {
/**
* Controller config settings
**/
function config() {
}
/**
* index action
*/
function index() {
// TODO: Implement index action
}
}
RESTful Controller
component extends="Controller" {
function config() {
verifies(except="index,new,create", params="key", paramsTypes="integer", handler="objectNotFound");
}
/**
* View all Products
**/
function index() {
products=model("product").findAll();
}
/**
* View Product
**/
function show() {
product=model("product").findByKey(params.key);
}
/**
* Add New Product
**/
function new() {
product=model("product").new();
}
/**
* Create Product
**/
function create() {
product=model("product").create(params.product);
if(product.hasErrors()){
renderView(action="new");
} else {
redirectTo(action="index", success="Product successfully created");
}
}
/**
* Edit Product
**/
function edit() {
product=model("product").findByKey(params.key);
}
/**
* Update Product
**/
function update() {
product=model("product").findByKey(params.key);
if(product.update(params.product)){
redirectTo(action="index", success="Product successfully updated");
} else {
renderView(action="edit");
}
}
/**
* Delete Product
**/
function delete() {
product=model("product").deleteByKey(params.key);
redirectTo(action="index", success="Product successfully deleted");
}
/**
* Redirect away if verifies fails, or if an object can't be found
**/
function objectNotFound() {
redirectTo(action="index", error="That Product wasn't found");
}
}
API Controller
/**
* API endpoint for order processing
*/
component extends="wheels.Controller" {
function init() {
provides("json");
filters(through="setJsonResponse");
}
/**
* GET /orders
* Returns a list of all orders
*/
function index() {
local.orders = model("order").findAll();
renderWith(data={ orders=local.orders });
}
/**
* GET /orders/:key
* Returns a specific order by ID
*/
function show() {
local.order = model("order").findByKey(params.key);
if (IsObject(local.order)) {
renderWith(data={ order=local.order });
} else {
renderWith(data={ error="Record not found" }, status=404);
}
}
/**
* POST /orders
* Creates a new order
*/
function create() {
local.order = model("order").new(params.order);
if (local.order.save()) {
renderWith(data={ order=local.order }, status=201);
} else {
renderWith(data={ error="Validation failed", errors=local.order.allErrors() }, status=422);
}
}
/**
* PUT /orders/:key
* Updates an existing order
*/
function update() {
local.order = model("order").findByKey(params.key);
if (IsObject(local.order)) {
local.order.update(params.order);
if (local.order.hasErrors()) {
renderWith(data={ error="Validation failed", errors=local.order.allErrors() }, status=422);
} else {
renderWith(data={ order=local.order });
}
} else {
renderWith(data={ error="Record not found" }, status=404);
}
}
/**
* DELETE /orders/:key
* Deletes a order
*/
function delete() {
local.order = model("order").findByKey(params.key);
if (IsObject(local.order)) {
local.order.delete();
renderWith(data={}, status=204);
} else {
renderWith(data={ error="Record not found" }, status=404);
}
}
/**
* Set Response to JSON
*/
private function setJsonResponse() {
params.format = "json";
}
}
View Generation
Views are automatically generated for non-API controllers:
index.cfm
<h1>Products</h1>
<p>#linkTo(text="New Product", action="new")#</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<cfloop query="products">
<tr>
<td>#products.name#</td>
<td>
#linkTo(text="Show", action="show", key=products.id)#
#linkTo(text="Edit", action="edit", key=products.id)#
#linkTo(text="Delete", action="delete", key=products.id, method="delete", confirm="Are you sure?")#
</td>
</tr>
</cfloop>
</tbody>
</table>
Naming Conventions
- Controller names: PascalCase, typically plural (Products, Users)
- Action names: camelCase (index, show, createProduct)
- File locations:
- Controllers:
/controllers/
- Nested:
/controllers/admin/Products.cfc
- Views:
/views/{controller}/
- Controllers:
Routes Configuration
Add routes in /config/routes.cfm
:
Traditional Routes
<cfscript>
mapper()
.get(name="products", to="products##index")
.get(name="product", to="products##show")
.post(name="products", to="products##create")
.wildcard()
.end();
</cfscript>
RESTful Resources
<cfscript>
mapper()
.resources("products")
.wildcard()
.end();
</cfscript>
Testing
Generate tests alongside controllers:
wheels generate controller name=products --rest
wheels generate test controller name=products
Best Practices
- Use plural names for resource controllers
- Keep controllers focused on single resources
- Use
--rest
for standard CRUD operations - Implement proper error handling
- Add authentication in
config()
method - Use filters for common functionality
Common Patterns
Authentication Filter
function config() {
filters(through="authenticate", except="index,show");
}
private function authenticate() {
if (!session.isLoggedIn) {
redirectTo(controller="sessions", action="new");
}
}
Pagination
function index() {
products = model("Product").findAll(
page=params.page ?: 1,
perPage=25,
order="createdAt DESC"
);
}
Search
function index() {
if (StructKeyExists(params, "q")) {
products = model("Product").findAll(
where="name LIKE :search OR description LIKE :search",
params={search: "%#params.q#%"}
);
} else {
products = model("Product").findAll();
}
}
See Also
- wheels generate model - Generate models
- wheels generate view - Generate views
- wheels scaffold - Generate complete CRUD
- wheels generate test - Generate controller tests
- Synopsis
- Parameter Syntax
- Arguments
- Options
- Examples
- Basic controller
- Controller with multiple actions
- RESTful controller
- API controller
- Generated Code
- Basic Controller
- RESTful Controller
- API Controller
- View Generation
- index.cfm
- Naming Conventions
- Routes Configuration
- Traditional Routes
- RESTful Resources
- Testing
- Best Practices
- Common Patterns
- Authentication Filter
- Pagination
- Search
- See Also