Laravel Tips and Tricks for Better Productivity
Laravel adalah framework PHP yang powerful dan elegan. Setelah bertahun-tahun menggunakannya, berikut adalah tips dan tricks yang saya temukan untuk meningkatkan produktivitas dan kualitas kode.
1. Route Model Binding
Gunakan route model binding untuk clean controller methods:
// Instead of
public function show($id)
{
$user = User::findOrFail($id);
return view('users.show', compact('user'));
}
// Use
public function show(User $user)
{
return view('users.show', compact('user'));
}
Route:
Route::get('/users/{user}', [UserController::class, 'show']);
2. Eloquent Scopes
Scopes untuk reusable query constraints:
class Post extends Model
{
// Local scope
public function scopePublished($query)
{
return $query->where('status', 'published');
}
public function scopeRecent($query)
{
return $query->orderBy('created_at', 'desc');
}
}
// Usage
$posts = Post::published()->recent()->get();
3. Accessor & Mutator
Format data secara otomatis:
class User extends Model
{
// Accessor
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
);
}
// Mutator
protected function password(): Attribute
{
return Attribute::make(
set: fn (string $value) => bcrypt($value),
);
}
}
4. Form Request Validation
Pisahkan validation logic:
// app/Http/Requests/StoreUserRequest.php
class StoreUserRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|min:8|confirmed',
];
}
public function messages(): array
{
return [
'email.unique' => 'Email ini sudah terdaftar.',
];
}
}
Controller:
public function store(StoreUserRequest $request)
{
// Data sudah tervalidasi
User::create($request->validated());
return redirect()->route('users.index');
}
5. Service Container & Dependency Injection
Manfaatkan IoC container:
// Bind interface to implementation
app()->bind(PaymentGatewayInterface::class, StripePaymentGateway::class);
// Resolve via constructor injection
class OrderController extends Controller
{
public function __construct(
private PaymentGatewayInterface $paymentGateway
) {}
public function store(Request $request)
{
$this->paymentGateway->charge($request->amount);
}
}
6. Collections Power
Manfaatkan Collection methods:
$users = User::all();
// Group by
$grouped = $users->groupBy('role');
// Filter
$admins = $users->where('role', 'admin');
// Map
$names = $users->map(fn ($user) => $user->name);
// Reduce
$total = $orders->reduce(fn ($carry, $order) => $carry + $order->total, 0);
// Chaining
$stats = $users
->where('active', true)
->groupBy('department')
->map(fn ($dept) => $dept->count());
7. Database Optimization
Eager Loading
// N+1 problem
$users = User::all();
foreach ($users as $user) {
echo $user->posts->count(); // Query berulang
}
// With eager loading
$users = User::with('posts')->get();
foreach ($users as $user) {
echo $user->posts->count(); // Sudah diload
}
// Nested eager loading
$users = User::with(['posts.comments', 'profile'])->get();
Query Optimization
// Select specific columns
$users = User::select('id', 'name', 'email')->get();
// Chunk large datasets
User::chunk(100, function ($users) {
foreach ($users as $user) {
// Process user
}
});
// Cursor for memory efficiency
foreach (User::cursor() as $user) {
// Process user
}
8. Artisan Commands
Custom commands untuk automation:
// app/Console/Commands/SendWeeklyReport.php
class SendWeeklyReport extends Command
{
protected $signature = 'report:weekly {--email=}';
protected $description = 'Send weekly report to admin';
public function handle()
{
$email = $this->option('email') ?? config('app.admin_email');
$this->info('Sending report...');
// Send report logic
$this->info('Report sent successfully!');
}
}
Schedule:
// routes/console.php
Schedule::command('report:weekly')->weekly()->mondays()->at('09:00');
9. Queues for Background Jobs
Offload heavy tasks:
// Dispatch job
ProcessPodcast::dispatch($podcast);
// Delayed dispatch
ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(10));
// On specific queue
ProcessPodcast::dispatch($podcast)->onQueue('processing');
// Job class
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(public Podcast $podcast) {}
public function handle(): void
{
// Heavy processing
}
public function failed(Throwable $exception): void
{
// Handle failure
}
}
10. API Resources
Transform data untuk API:
// app/Http/Resources/UserResource.php
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'avatar' => $this->avatar_url,
'member_since' => $this->created_at->format('M Y'),
'posts_count' => $this->whenCounted('posts'),
'roles' => RoleResource::collection($this->whenLoaded('roles')),
];
}
}
// Usage
return new UserResource($user);
return UserResource::collection($users);
11. Caching Strategies
Cache untuk performance:
// Remember forever
$users = Cache::rememberForever('users', function () {
return User::all();
});
// With expiration
$value = Cache::remember('key', 3600, function () {
return expensiveOperation();
});
// Cache tags (Redis/Memcached)
Cache::tags(['users', 'admins'])->put('admin-list', $admins, 3600);
Cache::tags(['users', 'admins'])->flush();
// View caching
@cache(['key' => 'sidebar', 'seconds' => 3600])
@include('partials.sidebar')
@endcache
12. Testing dengan PHPUnit
Testing yang efektif:
class UserTest extends TestCase
{
use RefreshDatabase;
public function test_user_can_register()
{
$response = $this->postJson('/api/register', [
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => 'password123',
]);
$response->assertCreated()
->assertJsonPath('user.name', 'John Doe');
$this->assertDatabaseHas('users', [
'email' => 'john@example.com',
]);
}
public function test_user_can_login()
{
$user = User::factory()->create();
$response = $this->postJson('/api/login', [
'email' => $user->email,
'password' => 'password',
]);
$response->assertOk()
->assertJsonStructure(['token']);
}
}
Kesimpulan
Laravel menyediakan banyak fitur untuk meningkatkan produktivitas. Gunakan:
- Route Model Binding untuk clean code
- Eloquent Scopes untuk reusable queries
- Form Requests untuk organized validation
- Collections untuk data manipulation
- Queues untuk background processing
- Caching untuk performance
Keep learning dan eksplorasi fitur-fitur Laravel yang baru!