Skip to content

datfooldive/php-mvc-framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHP MVC Framework

A simple PHP MVC framework.

Features

  • Attribute-Based Routing - Use PHP attributes for clean route definitions
  • Dependency Injection - Automatic DI container with singleton support
  • Middleware System - Flexible middleware with attribute support
  • Database Abstraction - PDO wrapper with ActiveRecord-style ORM
  • Twig Templates - Powerful and secure template engine support

Quick Start

  1. Clone the repository

    git clone <repository-url>
    cd php-mvc-framework
  2. Install dependencies

    composer install
  3. Setup environment

    cp .env.example .env
  4. Create database (for SQLite)

    touch storage/database.sqlite
  5. Start development server

    composer serve
  6. Visit your application Open http://localhost:8000 in your browser

Project Structure

mvc-framework/
├── app/                    # Application code
│   ├── Controllers/        # HTTP controllers
│   ├── Models/            # Data models
│   ├── Services/          # Business logic
│   └── Middleware/        # HTTP middleware
├── config/                # Configuration files
├── core/                  # Framework core
│   ├── Attributes/        # PHP attributes
│   └── Http/             # HTTP components
├── public/               # Web server document root
├── views/                # Template files
└── storage/              # App storage (logs, cache, etc.)

Creating Controllers

<?php

namespace App\Controllers;

use Core\Attributes\Route;
use Core\Attributes\Controller;
use Core\Http\Request;

#[Controller(prefix: '/api')]
class ApiController extends BaseController
{
    #[Route('/users', 'GET', name: 'users.index')]
    public function index(): array
    {
        return ['users' => []];
    }

    #[Route('/users/{id}', 'GET')]
    public function show(int $id): array
    {
        return ['user' => ['id' => $id]];
    }
}

Templates (Twig)

The framework uses Twig as its template engine. Templates are located in the views/ directory.

Rendering a Template

In your controller:

public function index()
{
    return $this->view()->render('home', [
        'name' => 'John Doe'
    ]);
}

Template Example (views/home.twig)

<!DOCTYPE html>
<html>
<head>
    <title>{{ app_name }}</title>
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
    <p>Welcome to our simple MVC framework.</p>
</body>
</html>

Database & ORM

The framework includes a powerful ActiveRecord-style ORM with support for relationships and eager loading.

Defining Models

Models should extend Core\Model. The table name is automatically derived from the class name (snake_case + plural), or can be explicitly defined.

<?php

namespace App\Models;

use Core\Model;
use Core\Relations\HasMany;

class User extends Model
{
    // Optional: Override table name
    protected string $table = 'users';

    // Define relationships
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}

Basic CRUD

// Create
$user = User::create([
    'name' => 'John Doe',
    'email' => '[email protected]'
]);

// Read
$users = User::all();
$user = User::find(1);
$activeUsers = User::where('status', 'active');

// Update
$user->name = 'Jane Doe';
$user->save();

// Delete
$user->delete();

Relationships & Eager Loading

Support for hasMany and belongsTo relationships with efficient eager loading to solve the N+1 problem.

// Define the inverse relationship in Post model
public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}

// Eager load posts with users
$users = User::with('posts')->get();

foreach ($users as $user) {
    // Relationships are accessible as properties
    foreach ($user->posts as $post) {
        echo $post->title;
    }
}

Database Migrations

The framework includes a simple migration system to manage your database schema.

Creating a Migration

Create a new file in the migrations/ directory.

<?php

use Core\Database\Migration;

class CreatePostsTable extends Migration
{
    public function up()
    {
        $table = $this->table('posts');
        $table->addColumn('id', 'id') // Helper for auto-incrementing primary key
              ->addColumn('user_id', 'integer')
              ->addColumn('title', 'string')
              ->addColumn('body', 'text')
              ->addColumn('created_at', 'datetime')
              ->foreign('user_id', 'id', 'users') // Foreign key
              ->create();
    }

    public function down()
    {
        $this->table('posts')->drop();
    }
}

Running Migrations

Use the console script to run migrations.

# Run all pending migrations
php bin/console migrate

# Rollback the last migration batch
php bin/console migrate:rollback

# Rollback all migrations and run them again
php bin/console migrate:refresh

# Drop all tables and re-run all migrations
php bin/console migrate:fresh

Services with DI

<?php

namespace App\Services;

use Core\Attributes\Service;

#[Service(singleton: true)]
class UserService
{
    public function __construct(
        private User $user
    ) {}

    public function getAllUsers(): array
    {
        return $this->user->all();
    }
}

Middleware

<?php

namespace App\Middleware;

use Core\Http\Request;
use Core\Http\Response;

class AuthMiddleware implements MiddlewareInterface
{
    public function handle(Request $request): ?Response
    {
        if (!$request->header('Authorization')) {
            return (new Response())->status(401)->json(['error' => 'Unauthorized']);
        }

        return null; // Continue
    }
}

Configuration

Database Configuration

Edit config/database.php to configure your database connection:

return [
    'default' => 'mysql',
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'host' => 'localhost',
            'database' => 'your_database',
            'username' => 'your_username',
            'password' => 'your_password',
        ],
    ],
];

Application Configuration

Edit config/app.php for application settings:

return [
    'name' => 'Your App Name',
    'debug' => true,
    'controllers' => [
        \App\Controllers\HomeController::class,
        \App\Controllers\UserController::class,
    ],
];

API Examples

GET /api/users

curl -X GET http://localhost:8000/api/users

POST /api/users

curl -X POST http://localhost:8000/api/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-token" \
  -d '{"name":"John Doe","email":"[email protected]"}'

Requirements

  • PHP 8.0 or higher
  • PDO extension
  • Composer

License

MIT License

Contributing

Pull requests are welcome. For major changes, please open an issue first.

About

a simple php mvc framework

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published