Controllers
Organize your application logic with powerful, feature-rich controllers
Overview
Controllers are the heart of your Yabasi application, handling HTTP requests and coordinating your application's response. They provide a clean, organized way to group related request handling logic.
Automatic DI
Dependency injection out of the box for clean, testable code.
Built-in Security
Secure request handling with middleware and validation.
Clean Code
Modern PHP practices with expressive syntax.
Basic Controller Structure
Let's start with a basic controller example that demonstrates the core concepts and best practices in Yabasi:
namespace Yabasi\Controllers;
use Yabasi\Controller\Controller;
use Yabasi\Http\Request;
use Yabasi\Http\Response;
use Yabasi\Models\User;
class UserController extends Controller
{
public function index(Request $request): Response
{
$users = User::all();
return $this->view('users.index', ['users' => $users]);
}
public function show(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json(['error' => 'User not found'], 404);
}
return $this->view('users.show', ['user' => $user]);
}
public function store(Request $request): Response
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|min:8'
]);
$user = User::create($validated);
return $this->json([
'message' => 'User created successfully',
'user' => $user
], 201);
}
}
Key Features
- Type-hinted method parameters
- Built-in response methods
- Request validation
- Model integration
Best Practices
- Keep controllers slim and focused
- Use type declarations
- Validate input data
- Return appropriate status codes
Controller Methods
Yabasi controllers follow RESTful conventions with standardized method names that map to specific HTTP operations. Here's a complete overview of common controller methods and their purposes:
GET Request Methods
index()
Lists all resources
public function index(Request $request): Response
{
$users = User::all();
return $this->view('users.index', [
'users' => $users
]);
}
show($id)
Displays a specific resource
public function show(Request $request, int $id): Response
{
$user = User::find($id);
return $this->view('users.show', [
'user' => $user
]);
}
POST Modification Methods
store()
Creates a new resource
public function store(Request $request): Response
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|min:8'
]);
$user = User::create($validated);
return $this->json([
'message' => 'User created successfully',
'user' => $user
], 201);
}
update($id)
Updates an existing resource
public function update(Request $request, int $id): Response
{
$user = User::find($id);
$user->update($request->validated());
return $this->json($user);
}
Method Quick Reference
index()
List all resources
show($id)
Show single resource
store()
Create new resource
update($id)
Update resource
destroy($id)
Delete resource
create()
Show create form
Controller Middleware
Protecting Your Controllers
Middleware provides a convenient way to filter and transform HTTP requests entering your application. Yabasi makes it easy to attach middleware to your controller actions.
Basic Usage
class UserController extends Controller
{
public function __construct()
{
// Apply middleware to specific methods
$this->middleware('auth')->only(['store', 'update', 'destroy']);
// Apply middleware to all methods except specified ones
$this->middleware('log')->except(['index', 'show']);
// Apply middleware to all methods
$this->middleware('throttle:60,1');
}
}
only() Method
$this->middleware('auth')->only([
'store',
'update',
'destroy'
]);
Applies middleware only to specified methods, leaving others unprotected.
except() Method
$this->middleware('auth')->except([
'index',
'show'
]);
Applies middleware to all methods except those specified.
Available Middleware
auth
Ensures the user is authenticated.
$this->middleware('auth')
csrf
Protects against CSRF attacks.
$this->middleware('csrf')
throttle
Rate limiting for API routes.
$this->middleware('throttle:60,1')
Best Practices
Keep It Simple
Apply middleware only where necessary. Too many middleware layers can impact performance.
Order Matters
Middleware executes in the order they are defined. Plan your middleware chain carefully.
Resource Controllers
RESTful Resource Controllers
Resource controllers provide a quick way to generate all the typical CRUD routes and methods for a resource. This follows REST conventions and keeps your application consistent.
Generating a Resource Controller
php
yabasi
make:controller
UserController
--resource
This command generates a controller with all the necessary resource methods pre-configured.
Generated Methods
namespace Yabasi\Controllers;
use Yabasi\Controller\Controller;
use Yabasi\Http\Request;
use Yabasi\Http\Response;
class UserController extends Controller
{
/**
* Display a listing of users
*/
public function index(): Response
{
$users = User::paginate(20);
return $this->view('users.index', ['users' => $users]);
}
/**
* Show the form for creating a new user
*/
public function create(): Response
{
return $this->view('users.create');
}
/**
* Store a newly created user
*/
public function store(Request $request): Response
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users'
]);
$user = User::create($validated);
return $this->redirect('users.show', ['id' => $user->id])
->with('success', 'User created successfully');
}
/**
* Display the specified user
*/
public function show(int $id): Response
{
$user = User::findOrFail($id);
return $this->view('users.show', ['user' => $user]);
}
/**
* Show the form for editing the user
*/
public function edit(int $id): Response
{
$user = User::findOrFail($id);
return $this->view('users.edit', ['user' => $user]);
}
/**
* Update the specified user
*/
public function update(Request $request, int $id): Response
{
$user = User::findOrFail($id);
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,'.$id
]);
$user->update($validated);
return $this->redirect('users.show', ['id' => $id])
->with('success', 'User updated successfully');
}
/**
* Remove the specified user
*/
public function destroy(int $id): Response
{
$user = User::findOrFail($id);
$user->delete();
return $this->redirect('users.index')
->with('success', 'User deleted successfully');
}
}
Resource Routes
HTTP Method | URI | Action | Purpose |
---|---|---|---|
GET | /users |
index | Display all users |
GET | /users/create |
create | Show create form |
POST | /users |
store | Store new user |
GET | /users/{id} |
show | Display single user |
GET | /users/{id}/edit |
edit | Show edit form |
PUT/PATCH | /users/{id} |
update | Update user |
DELETE | /users/{id} |
destroy | Delete user |
Best Practices
Keep Controllers Focused
Each resource controller should handle a single type of resource. Don't mix different resources in the same controller.
Use Form Requests
For complex validation, create dedicated Form Request classes instead of validating directly in the controller.
Controller Responses
Response Types
Yabasi provides a variety of response types to handle different scenarios elegantly. From simple views to complex JSON responses, you have full control over your application's HTTP responses.
View Response
public function show(int $id): Response
{
$user = User::find($id);
return $this->view('users.show', [
'user' => $user,
'title' => 'User Profile'
]);
}
Returns a view with the specified template and data.
JSON Response
public function apiShow(int $id): Response
{
$user = User::find($id);
return $this->json([
'data' => $user,
'status' => 'success'
], 200);
}
Returns data as JSON with appropriate content type headers.
Redirect Response
public function store(Request $request): Response
{
// ... save the resource
return $this->redirect('/dashboard')
->with('success', 'Created successfully!');
}
Redirects to another URL with optional flash messages.
Download Response
public function download(string $filename): Response
{
return $this->download(
'path/to/file.pdf',
'custom-name.pdf'
);
}
Forces file download with optional custom filename.
Response Helpers
Headers
->withHeaders([
'X-Header' => 'Value'
])
Status Codes
->setStatusCode(201)
Cookies
->withCookie('name', 'value')
Common Response Scenarios
API Success Response
return $this->json([
'status' => 'success',
'data' => $result,
'message' => 'Operation completed successfully'
], 200);
Error Response
return $this->json([
'status' => 'error',
'message' => 'Resource not found',
'errors' => ['id' => 'Invalid ID provided']
], 404);
Redirect with Flash Data
return $this->redirect()
->route('users.index')
->with('success', 'User updated successfully')
->with('data', $userData);
Response Best Practices
Consistent Response Format
Maintain a consistent structure for your API responses across your application.
Appropriate Status Codes
Use proper HTTP status codes to indicate the outcome of requests.
Testing Controllers
Controller Testing Made Easy
Yabasi provides a robust testing framework that makes it simple to write tests for your controllers. Test HTTP requests, responses, and middleware behavior with confidence.
Basic Controller Test
namespace Tests\Controllers;
use Tests\TestCase;
use Yabasi\Models\User;
class UserControllerTest extends TestCase
{
public function test_index_displays_users_list()
{
// Arrange
$users = User::factory()->count(3)->create();
// Act
$response = $this->get('/users');
// Assert
$response->assertStatus(200)
->assertViewHas('users')
->assertSee($users[0]->name);
}
public function test_store_creates_new_user()
{
// Arrange
$userData = [
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => 'password123'
];
// Act
$response = $this->post('/users', $userData);
// Assert
$response->assertStatus(302); // Redirect after creation
$this->assertDatabaseHas('users', [
'email' => 'john@example.com'
]);
}
public function test_update_modifies_existing_user()
{
// Arrange
$user = User::factory()->create();
$updatedData = ['name' => 'Updated Name'];
// Act
$response = $this->put("/users/{$user->id}", $updatedData);
// Assert
$response->assertRedirect();
$this->assertDatabaseHas('users', [
'id' => $user->id,
'name' => 'Updated Name'
]);
}
}
Testing JSON Responses
public function test_api_returns_user_data()
{
$user = User::factory()->create();
$response = $this->getJson("/api/users/{$user->id}");
$response
->assertStatus(200)
->assertJson([
'data' => [
'id' => $user->id,
'name' => $user->name
]
]);
}
Testing Validation
public function test_store_validates_required_fields()
{
$response = $this->post('/users', []);
$response
->assertStatus(422)
->assertJsonValidationErrors([
'name',
'email',
'password'
]);
}
Testing Middleware
public function test_authenticated_user_can_access_protected_route()
{
// Create and authenticate a user
$user = User::factory()->create();
$this->actingAs($user);
$response = $this->get('/dashboard');
$response->assertStatus(200);
}
public function test_unauthenticated_user_cannot_access_protected_route()
{
$response = $this->get('/dashboard');
$response->assertRedirect('/login');
}
Available Assertions
Assertion | Description | Example |
---|---|---|
assertStatus() |
Assert HTTP status code | ->assertStatus(200) |
assertJson() |
Assert JSON response structure | ->assertJson(['status' => 'success']) |
assertViewIs() |
Assert specific view was returned | ->assertViewIs('users.index') |
assertRedirect() |
Assert response is a redirect | ->assertRedirect('/users') |
Testing Best Practices
Test Each Route
Write tests for both successful and failed scenarios for each route.
Use Factories
Create test data using model factories for consistent test data.
Clean Tests
Follow AAA pattern: Arrange, Act, Assert for clear test structure.
Next Steps
Models
Learn how to integrate your controllers with Yabasi's powerful model system for seamless data handling.
Form Validation
Discover advanced form validation techniques and request handling in your controllers.
Middleware
Dive deeper into middleware functionality to secure and enhance your controller actions.
Additional Resources
API Development
Learn how to build robust APIs using Yabasi controllers. Read more →
Advanced Patterns
Explore advanced controller patterns and best practices. Read more →