Create Controller
Learn how to create the Controller layer - the business logic orchestrator. Master mapping request data to models and coordinating between API and Model layers.
What You'll Learn
Understanding Controller
What is the Controller layer and its responsibilities
Mapping Request to Model
Use mapPostToObject() to convert requests
Creating Controller
Create your first Controller class
Video Coming Soon...
What is Controller Layer?
The Controller Layer is the business logic orchestrator in GEMVC. It's the second layer in the 4-layer architecture and sits between the API Service and Model layers.
- Business Logic Orchestration - Coordinates the flow of data and operations
- Request Mapping - Maps HTTP request data to Model objects using
mapPostToObject() - Coordination - Can coordinate between multiple models if needed
- Delegation - Passes mapped data to Model layer for business validations
Key Principle: The Controller layer orchestrates business logic flow but doesn't contain data validations or database operations. It maps requests to models and delegates to the Model layer.
Understanding the Structure
Basic Controller Structure
Every Controller must extend Controller. Here's the basic structure:
<?php
namespace App\Controller;
use App\Model\ProductModel;
use Gemvc\Core\Controller;
use Gemvc\Http\Request;
use Gemvc\Http\JsonResponse;
class ProductController extends Controller
{
public function __construct(Request $request)
{
parent::__construct($request);
}
public function create(): JsonResponse
{
// Map POST data to Model
$model = $this->request->mapPostToObject(
new ProductModel(),
[
'name' => 'name',
'price' => 'price',
'description' => 'description'
]
);
if(!$model instanceof ProductModel) {
return $this->request->returnResponse();
}
// Delegate to Model layer
return $model->createModel();
}
}
Key Points:
- ✓ Extends
Controllerbase class - ✓ Constructor receives
Requestobject - ✓ Methods return
JsonResponse - ✓ Uses
mapPostToObject()to convert request data to Model - ✓ Delegates to Model layer methods (e.g.,
createModel())
Mapping Request to Model
Using mapPostToObject()
The mapPostToObject() method converts POST request data into a Model object. It takes two parameters:
- Model instance - A new instance of your Model class (e.g.,
new ProductModel()) - Mapping array - An array that maps POST field names to Model property names or method calls
<?php
public function create(): JsonResponse
{
// Map POST data to Model
$model = $this->request->mapPostToObject(
new ProductModel(),
[
'name' => 'name', // POST['name'] → $model->name
'price' => 'price', // POST['price'] → $model->price
'description' => 'description' // POST['description'] → $model->description
]
);
// Check if mapping was successful
if(!$model instanceof ProductModel) {
// Mapping failed - return error response
return $this->request->returnResponse();
}
// Mapping successful - delegate to Model
return $model->createModel();
}
Mapping Array Format:
'field' => 'property'- Maps POST field to Model property'field' => 'methodName()'- Calls a method on the Model (e.g.,'password' => 'setPassword()')
Method Calls in Mapping:
You can specify method calls in the mapping array. The method will be called with the POST value as the argument:
<?php
$model = $this->request->mapPostToObject(
new ProductModel(),
[
'name' => 'name',
'price' => 'price',
'discount' => 'applyDiscount()' // Calls $model->applyDiscount($post['discount'])
]
);
Note: Method calls are useful for data transformations (e.g., password hashing, discount calculations).
Complete Example
Full CRUD Controller
Here's a complete example of a Controller with all CRUD operations:
<?php
namespace App\Controller;
use App\Model\ProductModel;
use Gemvc\Core\Controller;
use Gemvc\Http\Request;
use Gemvc\Http\JsonResponse;
class ProductController extends Controller
{
public function __construct(Request $request)
{
parent::__construct($request);
}
// Create - Map POST data to Model
public function create(): JsonResponse
{
$model = $this->request->mapPostToObject(
new ProductModel(),
[
'name' => 'name',
'price' => 'price',
'?description' => 'description'
]
);
if(!$model instanceof ProductModel) {
return $this->request->returnResponse();
}
return $model->createModel();
}
// Read - Get product by ID
public function read(): JsonResponse
{
$id = $this->request->intValueGet('id');
if (!$id) {
return $this->request->returnResponse();
}
$model = new ProductModel();
return $model->readModel($id);
}
// Update - Map POST data to existing Model
public function update(): JsonResponse
{
$id = $this->request->intValueGet('id');
if (!$id) {
return $this->request->returnResponse();
}
$model = new ProductModel();
$existing = $model->selectById($id);
if (!$existing) {
return $this->request->returnResponse();
}
$model = $this->request->mapPostToObject(
$existing,
[
'name' => 'name',
'?price' => 'price',
'?description' => 'description'
]
);
if(!$model instanceof ProductModel) {
return $this->request->returnResponse();
}
return $model->updateModel();
}
// Delete - Delete product by ID
public function delete(): JsonResponse
{
$id = $this->request->intValueGet('id');
if (!$id) {
return $this->request->returnResponse();
}
$model = new ProductModel();
return $model->deleteModel($id);
}
}
⚠️ ProductModel Not Created Yet
The use App\Model\ProductModel; import and all ProductModel references will cause errors until we create the Model class. This is normal! We'll create ProductModel in the next step: Create Model.
Key Methods Used:
mapPostToObject()- Maps POST data to ModelintValueGet('id')- Gets integer value from GET parametersstringValueGet('name')- Gets string value from GET parametersreturnResponse()- Returns error response if validation fails
Important Notes
- No Data Validations: Controller layer should not contain business validations (e.g., duplicate email check). That's the Model layer's responsibility.
- No Database Operations: Controller never directly accesses the database. Always delegate to Model layer.
-
Always Check Mapping Result: Always verify that
mapPostToObject()returns the correct Model instance before proceeding. -
Naming Convention: Use PascalCase + "Controller" suffix (e.g.,
ProductController.php,UserController.php).
Create Your Controller
Manual Creation
To create a Controller, simply create a new PHP class file in the app/controller/ directory. For example, to create a Product Controller:
File Location:
Create app/controller/ProductController.php
The class name should match the filename (e.g., ProductController.php → class ProductController)
Example: Create a Product Controller
<?php
namespace App\Controller;
use App\Model\ProductModel;
use Gemvc\Core\Controller;
use Gemvc\Http\Request;
use Gemvc\Http\JsonResponse;
class ProductController extends Controller
{
public function __construct(Request $request)
{
parent::__construct($request);
}
public function create(): JsonResponse
{
$model = $this->request->mapPostToObject(
new ProductModel(),
[
'name' => 'name',
'price' => 'price',
'description' => 'description'
]
);
if(!$model instanceof ProductModel) {
return $this->request->returnResponse();
}
return $model->createModel();
}
}
⚠️ ProductModel Not Created Yet
The use App\Model\ProductModel; import will cause an error because the Model class doesn't exist yet. This is expected! We'll create the ProductModel class in the next step: Create Model.
✨ Controller Flow:
The Controller receives validated data from the API Service layer, maps it to a Model object, and delegates to the Model layer for business logic and database operations.
Request Flow:
Alternative: Use CLI Command
You can also use the GEMVC CLI command to generate the Controller file automatically:
gemvc create:controller Product
Tip: Use gemvc create:controller Product -mt to also create Model and Table layers!
🎉 Controller Created!
Great job! You've learned how to create Controller layer. Now let's move to the Model layer to handle business validations and data transformations.