real-world MVC with MySQL + PDO + full CRUD system

Your project is now upgraded to a real-world MVC with MySQL + PDO + full CRUD system.

🚀 What you now have

  • PDO database connection (secure)
  • Full CRUD:
    • /User → List users
    • /User/add → Add user
    • /User/edit/1 → Edit user
    • /User/delete/1 → Delete user
  • Clean routing with parameters
  • Reusable database class

⚠️ Important setup steps

  1. Create database:
CREATE DATABASE mvc_app;
  1. Create table (already in code, just run it)
  2. Update DB credentials in:
/config/config.php
  1. Run project:
http://localhost/User
<?php
// ======================================
// FULL MVC WITH DATABASE + CRUD (PDO)
// ======================================

/*
UPDATED STRUCTURE
/project
│
├── /app
│   ├── /controllers
│   │     └── UserController.php
│   │
│   ├── /models
│   │     └── UserModel.php
│   │
│   └── /views
│         ├── users.php
│         ├── add.php
│         └── edit.php
│
├── /core
│   ├── Router.php
│   ├── Controller.php
│   └── Database.php
│
├── /config
│   └── config.php
│
├── /public
│   └── index.php
│
└── .htaccess
*/

// ======================================
// DATABASE: config/config.php
// ======================================

return [
    'host' => 'localhost',
    'dbname' => 'mvc_app',
    'user' => 'root',
    'pass' => ''
];


// ======================================
// core/Database.php (PDO)
// ======================================

class Database {
    private static $instance = null;

    public static function connect() {
        if (self::$instance === null) {
            $config = require '../config/config.php';

            try {
                self::$instance = new PDO(
                    "mysql:host={$config['host']};dbname={$config['dbname']}",
                    $config['user'],
                    $config['pass']
                );
                self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            } catch (PDOException $e) {
                die("DB Error: " . $e->getMessage());
            }
        }
        return self::$instance;
    }
}


// ======================================
// core/Router.php
// ======================================

class Router {
    public function dispatch($url) {
        $url = trim($url, '/');
        $parts = explode('/', $url);

        $controllerName = !empty($parts[0]) ? ucfirst($parts[0]) . 'Controller' : 'UserController';
        $method = $parts[1] ?? 'index';
        $param = $parts[2] ?? null;

        require_once "../app/controllers/$controllerName.php";

        $controller = new $controllerName();

        if (!method_exists($controller, $method)) {
            die('Method not found');
        }

        $controller->$method($param);
    }
}


// ======================================
// core/Controller.php
// ======================================

class Controller {
    public function view($view, $data = []) {
        extract($data);
        require "../app/views/$view.php";
    }
}


// ======================================
// public/index.php
// ======================================

require_once '../core/Router.php';

$url = $_GET['url'] ?? '';
$router = new Router();
$router->dispatch($url);


// ======================================
// app/models/UserModel.php
// ======================================

require_once '../core/Database.php';

class UserModel {
    private $db;

    public function __construct() {
        $this->db = Database::connect();
    }

    public function getAll() {
        return $this->db->query("SELECT * FROM users")->fetchAll(PDO::FETCH_ASSOC);
    }

    public function getById($id) {
        $stmt = $this->db->prepare("SELECT * FROM users WHERE id=?");
        $stmt->execute([$id]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    public function create($name) {
        $stmt = $this->db->prepare("INSERT INTO users (name) VALUES (?)");
        return $stmt->execute([$name]);
    }

    public function update($id, $name) {
        $stmt = $this->db->prepare("UPDATE users SET name=? WHERE id=?");
        return $stmt->execute([$name, $id]);
    }

    public function delete($id) {
        $stmt = $this->db->prepare("DELETE FROM users WHERE id=?");
        return $stmt->execute([$id]);
    }
}


// ======================================
// app/controllers/UserController.php
// ======================================

require_once '../core/Controller.php';
require_once '../app/models/UserModel.php';

class UserController extends Controller {

    public function index() {
        $model = new UserModel();
        $users = $model->getAll();
        $this->view('users', compact('users'));
    }

    public function add() {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $model = new UserModel();
            $model->create($_POST['name']);
            header('Location: /User');
        }
        $this->view('add');
    }

    public function edit($id) {
        $model = new UserModel();

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $model->update($id, $_POST['name']);
            header('Location: /User');
        }

        $user = $model->getById($id);
        $this->view('edit', compact('user'));
    }

    public function delete($id) {
        $model = new UserModel();
        $model->delete($id);
        header('Location: /User');
    }
}


// ======================================
// app/views/users.php
// ======================================
?>
<h2>User List</h2>
<a href="/User/add">Add User</a>
<ul>
<?php foreach($users as $u): ?>
    <li>
        <?= $u['name'] ?>
        <a href="/User/edit/<?= $u['id'] ?>">Edit</a>
        <a href="/User/delete/<?= $u['id'] ?>">Delete</a>
    </li>
<?php endforeach; ?>
</ul>

<?php
// ======================================
// app/views/add.php
// ======================================
?>
<h2>Add User</h2>
<form method="POST">
    <input type="text" name="name" required>
    <button>Add</button>
</form>

<?php
// ======================================
// app/views/edit.php
// ======================================
?>
<h2>Edit User</h2>
<form method="POST">
    <input type="text" name="name" value="<?= $user['name'] ?>">
    <button>Update</button>
</form>

<?php
// ======================================
// SQL TABLE
// ======================================
/*
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);
*/