13: Laravel Foundations - The PHP Framework
Laravel Foundations: The PHP Framework
Section titled “Laravel Foundations: The PHP Framework”Overview
Section titled “Overview”Laravel is to PHP what Nest.js is to TypeScript—a full-featured framework with elegant syntax, powerful features, and exceptional developer experience. If you’ve worked with Nest.js, Express, or Rails, Laravel will feel familiar yet distinctively refined.
Learning Objectives
Section titled “Learning Objectives”By the end of this chapter, you’ll be able to:
- ✅ Set up a Laravel project
- ✅ Understand Laravel’s MVC architecture
- ✅ Create routes and controllers
- ✅ Use dependency injection (Laravel’s IoC container)
- ✅ Work with Eloquent ORM
- ✅ Handle requests and responses
- ✅ Use middleware and service providers
- ✅ Apply Laravel best practices
Code Examples
Section titled “Code Examples”📁 View Code Examples on GitHub
This chapter includes Laravel foundation examples:
01-setup-guide.md- Complete Laravel setup instructions02-routes.php- Comprehensive routing patterns03-controllers.php- Controller examples and comparisons04-dependency-injection.php- Service container and DI05-middleware.php- Middleware patterns06-form-requests.php- Form validation examples
Get started:
cd code/php-typescript-developers/chapter-13# Review the setup guide for creating a Laravel projectcat 01-setup-guide.mdFramework Comparison
Section titled “Framework Comparison”| Laravel | Nest.js | Express | Purpose |
|---|---|---|---|
| Full-stack | ✅ | ❌ | Complete framework vs library |
| ORM | Eloquent | TypeORM | Database abstraction |
| DI Container | ✅ | ✅ | ❌ |
| CLI | Artisan | Nest CLI | N/A |
| Template Engine | Blade | EJS/Pug | EJS/Pug |
| Auth System | Built-in | Passport | Passport |
Laravel ≈ Nest.js (both are opinionated, full-featured frameworks)
Installation
Section titled “Installation”Nest.js Setup
Section titled “Nest.js Setup”npm install -g @nestjs/clinest new my-appcd my-appnpm run start:devLaravel Setup
Section titled “Laravel Setup”# Install Laravel via Composercomposer create-project laravel/laravel my-appcd my-app
# Start development serverphp artisan serve# Visit: http://localhost:8000Directory Structure:
my-app/├── app/ # Application code│ ├── Http/│ │ └── Controllers/│ └── Models/├── routes/ # Route definitions│ ├── web.php # Web routes│ └── api.php # API routes├── resources/ # Views, assets│ └── views/├── database/ # Migrations, seeders├── public/ # Web root└── artisan # CLI toolRouting
Section titled “Routing”Nest.js Routes
Section titled “Nest.js Routes”import { Controller, Get, Post, Body, Param } from '@nestjs/common';
@Controller('users')export class UsersController { @Get() findAll() { return ['Alice', 'Bob']; }
@Get(':id') findOne(@Param('id') id: string) { return { id, name: 'Alice' }; }
@Post() create(@Body() createUserDto: CreateUserDto) { return { id: 1, ...createUserDto }; }}Laravel Routes
Section titled “Laravel Routes”<?phpuse App\Http\Controllers\UserController;
// GET /api/usersRoute::get('/users', [UserController::class, 'index']);
// GET /api/users/{id}Route::get('/users/{id}', [UserController::class, 'show']);
// POST /api/usersRoute::post('/users', [UserController::class, 'store']);
// Or use resource routes (RESTful)Route::apiResource('users', UserController::class);<?phpnamespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller { public function index() { return response()->json(['Alice', 'Bob']); }
public function show(string $id) { return response()->json(['id' => $id, 'name' => 'Alice']); }
public function store(Request $request) { return response()->json([ 'id' => 1, ...$request->all() ], 201); }}Dependency Injection
Section titled “Dependency Injection”Nest.js DI
Section titled “Nest.js DI”@Injectable()export class UsersService { findAll() { return ['Alice', 'Bob']; }}
// users.controller.ts@Controller('users')export class UsersController { constructor(private usersService: UsersService) {}
@Get() findAll() { return this.usersService.findAll(); }}Laravel DI
Section titled “Laravel DI”<?phpnamespace App\Services;
class UserService { public function getAll(): array { return ['Alice', 'Bob']; }}
// app/Http/Controllers/UserController.phpclass UserController extends Controller { public function __construct( private UserService $userService ) {}
public function index() { return response()->json($this->userService->getAll()); }}Laravel automatically resolves dependencies via type hints!
Request Validation
Section titled “Request Validation”Nest.js with class-validator
Section titled “Nest.js with class-validator”import { IsString, IsEmail, MinLength } from 'class-validator';
export class CreateUserDto { @IsString() @MinLength(3) name: string;
@IsEmail() email: string;}
@Post()create(@Body() createUserDto: CreateUserDto) { // Validated automatically return this.usersService.create(createUserDto);}Laravel Form Requests
Section titled “Laravel Form Requests”<?phpnamespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreUserRequest extends FormRequest { public function rules(): array { return [ 'name' => ['required', 'string', 'min:3'], 'email' => ['required', 'email', 'unique:users'], ]; }}
// Controllerclass UserController extends Controller { public function store(StoreUserRequest $request) { // $request is automatically validated! $validated = $request->validated(); // Create user... }}Middleware
Section titled “Middleware”Nest.js Middleware
Section titled “Nest.js Middleware”@Injectable()export class LoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { console.log(`${req.method} ${req.url}`); next(); }}Laravel Middleware
Section titled “Laravel Middleware”<?phpnamespace App\Http\Middleware;
use Closure;
class LogRequests { public function handle($request, Closure $next) { \Log::info($request->method() . ' ' . $request->path()); return $next($request); }}
// Apply to routeRoute::get('/users', [UserController::class, 'index']) ->middleware(LogRequests::class);
// Or globally in app/Http/Kernel.phpEloquent ORM
Section titled “Eloquent ORM”Laravel’s Eloquent ORM is more elegant than TypeORM:
TypeORM
Section titled “TypeORM”@Entity()export class User { @PrimaryGeneratedColumn() id: number;
@Column() name: string;
@Column() email: string;
@OneToMany(() => Post, post => post.user) posts: Post[];}
// Usageconst user = await userRepository.findOne({ where: { id: 1 } });const users = await userRepository.find();Laravel Eloquent
Section titled “Laravel Eloquent”<?phpnamespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model { protected $fillable = ['name', 'email'];
public function posts() { return $this->hasMany(Post::class); }}
// Usage (so much cleaner!)$user = User::find(1);$users = User::all();$user->posts; // Automatic eager loadingMore details in Chapter 14!
Artisan CLI
Section titled “Artisan CLI”Laravel’s Artisan is like Nest CLI:
Nest CLI
Section titled “Nest CLI”nest generate controller usersnest generate service usersnest generate module usersArtisan
Section titled “Artisan”php artisan make:controller UserControllerphp artisan make:model Userphp artisan make:migration create_users_tablephp artisan make:request StoreUserRequestphp artisan make:middleware LogRequestsList all commands:
php artisan listEnvironment Configuration
Section titled “Environment Configuration”Nest.js (.env)
Section titled “Nest.js (.env)”DATABASE_URL=postgresql://localhost/mydbJWT_SECRET=secretConfigModule.forRoot({ envFilePath: '.env',});
// Usageconstructor(private configService: ConfigService) {}
const dbUrl = this.configService.get('DATABASE_URL');Laravel (.env)
Section titled “Laravel (.env)”DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_DATABASE=mydbJWT_SECRET=secret<?php// Usage (anywhere)$dbHost = env('DB_HOST');$secret = config('app.jwt_secret');Complete CRUD Example
Section titled “Complete CRUD Example”Create Controller
Section titled “Create Controller”php artisan make:controller Api/UserController --api<?phpnamespace App\Http\Controllers\Api;
use App\Models\User;use Illuminate\Http\Request;use App\Http\Controllers\Controller;
class UserController extends Controller { // GET /api/users public function index() { return User::all(); }
// GET /api/users/{id} public function show(User $user) { return $user; // Route model binding! }
// POST /api/users public function store(Request $request) { $validated = $request->validate([ 'name' => 'required|string', 'email' => 'required|email|unique:users', ]);
$user = User::create($validated); return response()->json($user, 201); }
// PUT /api/users/{id} public function update(Request $request, User $user) { $validated = $request->validate([ 'name' => 'sometimes|string', 'email' => 'sometimes|email|unique:users,email,' . $user->id, ]);
$user->update($validated); return $user; }
// DELETE /api/users/{id} public function destroy(User $user) { $user->delete(); return response()->noContent(); }}Routes
Section titled “Routes”<?phpRoute::apiResource('users', UserController::class);
// Equivalent to:// GET /api/users -> index()// POST /api/users -> store()// GET /api/users/{id} -> show()// PUT /api/users/{id} -> update()// DELETE /api/users/{id} -> destroy()Service Providers
Section titled “Service Providers”Laravel’s service providers are like Nest.js modules:
<?phpnamespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider { public function register(): void { // Bind interfaces to implementations $this->app->bind( \App\Contracts\UserRepositoryInterface::class, \App\Repositories\UserRepository::class ); }
public function boot(): void { // Run code on application boot }}Testing
Section titled “Testing”Laravel includes PHPUnit with helpful assertions:
<?phpnamespace Tests\Feature;
use Tests\TestCase;use App\Models\User;
class UserApiTest extends TestCase { public function test_can_list_users(): void { User::factory()->count(3)->create();
$response = $this->getJson('/api/users');
$response->assertStatus(200) ->assertJsonCount(3); }
public function test_can_create_user(): void { $data = [ 'name' => 'Alice', 'email' => 'alice@example.com', ];
$response = $this->postJson('/api/users', $data);
$response->assertStatus(201) ->assertJsonPath('name', 'Alice');
$this->assertDatabaseHas('users', $data); }}Run tests:
php artisan testKey Takeaways
Section titled “Key Takeaways”- Laravel ≈ Nest.js - Both are full-featured, opinionated frameworks with rich ecosystems
- Routing is clean and expressive with multiple definition styles
- Dependency injection works automatically via type hints (no manual binding needed)
- Eloquent ORM is incredibly elegant - Active Record pattern beats TypeORM’s Data Mapper
- Artisan CLI generates boilerplate (controllers, models, migrations, tests, etc.)
- Middleware pipeline like Express/Nest for request/response modification
- Testing is built-in and powerful with PHPUnit integration
- Service container resolves dependencies automatically - just type-hint in constructors
- Form request validation provides clean, reusable validation logic
- Route model binding automatically injects models - no manual
findOrFail() - API resources provide consistent JSON transformation layer
- Laravel ecosystem rivals Node.js: Forge (deployment), Vapor (serverless), Nova (admin panel)
Laravel vs Nest.js
Section titled “Laravel vs Nest.js”| Feature | Laravel | Nest.js |
|---|---|---|
| Language | PHP | TypeScript |
| Philosophy | Convention over configuration | TypeScript + Angular patterns |
| Learning Curve | Gentle | Moderate |
| ORM | Eloquent (Active Record) | TypeORM (Data Mapper) |
| Templating | Blade | Various (EJS, Handlebars) |
| Real-time | Laravel Echo + Pusher | Socket.io |
| Queue System | Built-in | Bull (separate) |
| Admin Panel | Nova (commercial) | Various |
Next Steps
Section titled “Next Steps”Now that you know Laravel basics, let’s dive deeper into Eloquent ORM and databases.
Next Chapter: 14: Database & ORMs: TypeORM meets Eloquent
Resources
Section titled “Resources”- Laravel Documentation
- Laracasts - Video tutorials
- Laravel News
- Laravel Daily
Questions or feedback? Open an issue on GitHub