Controllers
Controllers are the central hub of your application's request handling logic. In AvelPress, controllers help organize the logic for handling HTTP requests in a clean, organized manner.
Introduction
Controllers group related request handling logic into a single class. For example, a UserController
class might handle all incoming requests related to users, including displaying, creating, updating, and deleting users.
Controllers are stored in the app/Controllers
directory (or src/app/Controllers
depending on your structure) and extend the base AvelPress\Routing\Controller
class.
Basic Controllers
Creating Controllers
You can create controllers manually or use the AvelPress CLI:
# Create a basic controller
avel make:controller UserController
# Create a resource controller (with CRUD methods)
avel make:controller PostController --resource
Basic Controller Structure
<?php
namespace App\Controllers;
use AvelPress\Routing\Controller;
class UserController extends Controller
{
public function index()
{
// Return all users
return ['users' => []];
}
public function show($request)
{
$id = $request->get_param('id');
// Return specific user
return ['user' => ['id' => $id]];
}
}
Resource Controllers
Resource controllers make it easy to build RESTful controllers around a resource. A resource controller includes methods for the typical "CRUD" operations:
Generating Resource Controllers
avel make:controller PhotoController --resource
This creates a controller with the following methods:
Verb | URI | Action | Route Name |
---|---|---|---|
GET | /photos | index | photos.index |
POST | /photos | store | photos.store |
GET | /photos/{id} | show | photos.show |
PUT | /photos/{id} | update | photos.update |
DELETE | /photos/{id} | destroy | photos.destroy |
Resource Controller Example
<?php
namespace App\Controllers;
use App\Models\Photo;
use AvelPress\Routing\Controller;
use AvelPress\Http\Json\JsonResource;
class PhotoController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
$photos = Photo::all();
return JsonResource::collection($photos);
}
/**
* Store a newly created resource in storage.
*/
public function store($request)
{
$photo = Photo::create([
'title' => $request->get_param('title'),
'description' => $request->get_param('description'),
'url' => $request->get_param('url'),
]);
return new JsonResource($photo);
}
/**
* Display the specified resource.
*/
public function show($request)
{
$id = $request->get_param('id');
$photo = Photo::findOrFail($id);
return new JsonResource($photo);
}
/**
* Update the specified resource in storage.
*/
public function update($request)
{
$id = $request->get_param('id');
$photo = Photo::findOrFail($id);
$photo->update([
'title' => $request->get_param('title'),
'description' => $request->get_param('description'),
'url' => $request->get_param('url'),
]);
return new JsonResource($photo);
}
/**
* Remove the specified resource from storage.
*/
public function destroy($request)
{
$id = $request->get_param('id');
$photo = Photo::findOrFail($id);
$photo->delete();
return ['message' => 'Photo deleted successfully'];
}
}
Request Handling
Accessing Request Data
Controllers receive the WordPress WP_REST_Request
object, which provides access to all request data:
public function store($request)
{
// Get individual parameters
$title = $request->get_param('title');
$content = $request->get_param('content');
// Get all parameters
$params = $request->get_params();
// Get JSON body
$body = $request->get_json_params();
// Get file uploads
$files = $request->get_file_params();
// Get headers
$authHeader = $request->get_header('authorization');
}
Route Parameters
Access route parameters (like {id}
in the URL) using the request object:
public function show($request)
{
$id = $request->get_param('id');
$user = User::find($id);
if (!$user) {
return new \WP_Error('user_not_found', 'User not found', ['status' => 404]);
}
return new JsonResource($user);
}
Dependency Injection
Controllers support automatic dependency injection. You can type-hint dependencies in your controller methods and they will be automatically resolved:
Service Injection
use App\Services\UserService;
class UserController extends Controller
{
public function index(UserService $userService)
{
$users = $userService->getAllUsers();
return JsonResource::collection($users);
}
}
Model Injection
You can also inject models directly:
use App\Models\User;
class UserController extends Controller
{
public function show(User $user)
{
// The $user will be automatically resolved based on route parameter
return new JsonResource($user);
}
}
Form Request Injection
Inject form requests for automatic validation:
use App\Http\Requests\StoreUserRequest;
class UserController extends Controller
{
public function store(StoreUserRequest $request)
{
// Request is automatically validated
$user = User::create($request->validated());
return new JsonResource($user);
}
}
Response Handling
JSON Responses
Return arrays, and they'll be automatically converted to JSON:
public function index()
{
return [
'users' => User::all()->toArray(),
'total' => User::count(),
];
}
Resource Responses
Use JSON resources for consistent API responses:
public function show($request)
{
$user = User::find($request->get_param('id'));
return new JsonResource($user);
}
public function index()
{
$users = User::all();
return JsonResource::collection($users);
}
Custom Status Codes
Return custom HTTP status codes using WP_REST_Response
:
public function store($request)
{
$user = User::create($request->get_params());
return new \WP_REST_Response([
'message' => 'User created successfully',
'user' => $user->toArray()
], 201);
}
Error Responses
Return errors using WP_Error
:
public function show($request)
{
$user = User::find($request->get_param('id'));
if (!$user) {
return new \WP_Error(
'user_not_found',
'The requested user was not found',
['status' => 404]
);
}
return new JsonResource($user);
}
Controller Organization
Nested Controllers
For complex applications, you can organize controllers in subdirectories:
app/Controllers/
├── UserController.php
├── PostController.php
├── Admin/
│ ├── DashboardController.php
│ └── SettingsController.php
└── Api/
├── V1/
│ ├── UserController.php
│ └── PostController.php
└── V2/
└── UserController.php
Controller Namespacing
<?php
namespace App\Controllers\Admin;
use AvelPress\Routing\Controller;
class DashboardController extends Controller
{
public function index()
{
// Admin dashboard logic
}
}
WordPress Integration
Accessing WordPress Functions
Controllers have full access to WordPress functions and globals:
public function currentUser()
{
$current_user = wp_get_current_user();
if ($current_user->ID === 0) {
return new \WP_Error('not_logged_in', 'User not logged in', ['status' => 401]);
}
return [
'id' => $current_user->ID,
'name' => $current_user->display_name,
'email' => $current_user->user_email,
'roles' => $current_user->roles,
];
}
Permission Checks
public function adminOnly()
{
if (!current_user_can('manage_options')) {
return new \WP_Error(
'insufficient_permissions',
'You do not have permission to access this resource',
['status' => 403]
);
}
// Admin-only logic here
return ['message' => 'Welcome, admin!'];
}
Working with WordPress Data
public function posts()
{
$posts = get_posts([
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 10,
]);
return [
'posts' => array_map(function($post) {
return [
'id' => $post->ID,
'title' => $post->post_title,
'content' => $post->post_content,
'date' => $post->post_date,
];
}, $posts)
];
}
Advanced Features
Controller Middleware
You can apply guards (middleware) to specific controller methods:
class UserController extends Controller
{
public function __construct()
{
// Apply authentication to all methods except index and show
$this->middleware('auth')->except(['index', 'show']);
// Apply admin guard only to destroy method
$this->middleware('admin')->only(['destroy']);
}
}
Shared Controller Logic
Create base controllers for shared functionality:
<?php
namespace App\Controllers;
use AvelPress\Routing\Controller;
class BaseController extends Controller
{
protected function getCurrentUser()
{
return wp_get_current_user();
}
protected function checkPermission($capability)
{
if (!current_user_can($capability)) {
return new \WP_Error(
'insufficient_permissions',
'Access denied',
['status' => 403]
);
}
return true;
}
}
Then extend it in your controllers:
class UserController extends BaseController
{
public function profile()
{
$user = $this->getCurrentUser();
return new JsonResource($user);
}
}
Real-World Example
Here's a complete example from the Infixs Mega ERP plugin:
<?php
namespace Infixs\MegaErp\App\Modules\Quote\Http\Controllers;
use AvelPress\Routing\Controller;
use Infixs\MegaErp\App\Modules\Quote\Http\Requests\StoreQuoteRequest;
use Infixs\MegaErp\App\Modules\Quote\Http\Requests\UpdateQuoteRequest;
use Infixs\MegaErp\App\Modules\Quote\Http\Resources\QuoteCollection;
use Infixs\MegaErp\App\Modules\Quote\Http\Resources\QuoteResource;
use Infixs\MegaErp\App\Modules\Quote\Models\Quote;
use Infixs\MegaErp\App\Modules\Quote\Services\QuoteService;
class QuoteController extends Controller
{
private $quoteService;
public function __construct(QuoteService $quoteService)
{
$this->quoteService = $quoteService;
}
public function index()
{
$quotes = Quote::with(['items', 'paymentMethods'])->get();
return new QuoteCollection($quotes);
}
public function store(StoreQuoteRequest $request)
{
$quote = $this->quoteService->create($request->validated());
return new QuoteResource($quote);
}
public function show($request)
{
$quote = Quote::with(['items', 'paymentMethods'])
->findOrFail($request->get_param('id'));
return new QuoteResource($quote);
}
public function update(UpdateQuoteRequest $request)
{
$quote = Quote::findOrFail($request->get_param('id'));
$quote = $this->quoteService->update($quote, $request->validated());
return new QuoteResource($quote);
}
public function destroy($request)
{
$quote = Quote::findOrFail($request->get_param('id'));
$quote->delete();
return ['message' => 'Quote deleted successfully'];
}
}
This example demonstrates:
- Dependency injection (QuoteService)
- Form request validation
- Resource responses
- Model relationships
- Service layer pattern
- RESTful controller structure
Controllers in AvelPress provide a clean, organized way to handle your application's HTTP requests while maintaining full compatibility with WordPress functionality.