Umsetzung – Struktur, Routing und Datenbank‑Abbildung

Erste Schritte: Umsetzung – Struktur, Routing und Datenbank‑Abbildung

In diesem Tutorial setzen wir die zuvor geplante TaskBoard‑Mini‑App praktisch um.
Fokus: Verzeichnisstruktur, Front‑Controller + Routing und die Abbildung des Datenmodells
(Task‑Tabelle) auf eine einfache Model‑Klasse.

1. Verzeichnisstruktur anlegen

/taskboard
├── composer.json
├── public/               # öffentlich erreichbar (Document‑Root)
│   ├── index.php         # Front‑Controller
│   └── assets/           # CSS, JS, Bilder
├── src/                  # Application Code (PSR‑4)
│   ├── Controller/
│   │   └── TaskController.php
│   ├── Model/
│   │   └── Task.php
│   └── Core/
│       ├── Router.php
│       └── Database.php
└── views/
    ├── tasks/
    │   ├── list.php
    │   └── form.php
    └── layout.php

composer.json (Ausschnitt)

{
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  },
  "require": {
    "vlucas/valitron": "^1.4"  # Beispiel‑Validator
  }
}

Nach dem Anlegen:

composer install

und

composer dump-autoload

.

2. Core\Database – PDO‑Wrapper

 PDO::ERRMODE_EXCEPTION
            ]);
        }
        return self::$pdo;
    }
}
?>

3. Model\Task – Datenbank‑Abbildung (Active‑Record‑Light)

query("SELECT * FROM tasks ORDER BY id DESC");
        return $stmt->fetchAll(PDO::FETCH_CLASS, self::class);
    }

    public static function find(int $id): ?self {
        $stmt = Database::conn()->prepare("SELECT * FROM tasks WHERE id = :id");
        $stmt->execute([':id' => $id]);
        return $stmt->fetchObject(self::class) ?: null;
    }

    public function save(): void {
        $pdo = Database::conn();
        if (isset($this->id)) {
            $sql = "UPDATE tasks SET title=:t, description=:d, status=:s WHERE id=:id";
            $pdo->prepare($sql)->execute([
                ':t'=>$this->title, ':d'=>$this->description,
                ':s'=>$this->status, ':id'=>$this->id
            ]);
        } else {
            $sql = "INSERT INTO tasks (title,description,status) VALUES (:t,:d,:s)";
            $pdo->prepare($sql)->execute([
                ':t'=>$this->title, ':d'=>$this->description, ':s'=>$this->status
            ]);
            $this->id = (int)$pdo->lastInsertId();
        }
    }

    public static function delete(int $id): void {
        Database::conn()->prepare("DELETE FROM tasks WHERE id=:id")->execute([':id'=>$id]);
    }
}
?>

4. Core\Router – simples Mapping

routes[] = [$method, "#^$pattern$#", $handler];
    }

    public function dispatch(string $method, string $uri): void {
        foreach ($this->routes as [$m,$regex,$h]) {
            if ($m === $method && preg_match($regex, $uri, $matches)) {
                array_shift($matches);
                return is_array($h)
                    ? (new $h[0])->{$h[1]}(...$matches)
                    : $h(...$matches);
            }
        }
        http_response_code(404); echo "404 – Not Found";
    }
}
?>

5. public/index.php – Front‑Controller

add('GET',  '/',              [TaskController::class, 'index']);
$router->add('GET',  '/task/new',      [TaskController::class, 'create']);
$router->add('POST', '/task/store',    [TaskController::class, 'store']);
$router->add('GET',  '/task/(\d+)/edit',  [TaskController::class, 'edit']);
$router->add('POST', '/task/(\d+)/update',[TaskController::class, 'update']);
$router->add('POST', '/task/(\d+)/del',   [TaskController::class, 'destroy']);

$router->dispatch($_SERVER['REQUEST_METHOD'], parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
?>

6. Controller\TaskController – Geschäfts­logik

save(); }
    public function update(int $id) { $this->save($id); }

    private function save(?int $id=null): void {
        $task = $id ? Task::find($id) : new Task();
        $task->title       = trim($_POST['title'] ?? '');
        $task->description = trim($_POST['desc']  ?? '');
        $task->status      = $_POST['status'] ?? 'open';
        $task->save();
        header('Location: /'); exit;
    }

    public function destroy(int $id) {
        Task::delete($id);
        header('Location: /');
    }
}
?>

7. View – Aufgaben­liste (views/tasks/list.php)



Meine Aufgaben

+ Neue Aufgabe

layout.php liefert simple Wrapper‑Funktionen

start()

 / 

end()

zum Einfügen in den HTML‑Rahmen – Details ausgelassen.

8. Migration ausführen

mysql -u user -p taskboard < create_tasks.sql   # siehe vorheriges Tutorial

Fazit

Mit dieser Grundstruktur – Core‑Router, Active‑Record‑ähnlichem Model und Views –
steht das Fundament deiner TaskBoard‑App.
Von hier aus kannst du Features wie CSRF‑Token, Login, AJAX‑Drag‑and‑Drop oder Tests
schrittweise ergänzen, ohne das Gerüst zu verändern.