Контроллер форума в PHP: основы MVC и варианты реализации

Раздел: PHP -> Архитектура MVC

Архитектура контроллера форума в PHP MVC

Как реализовать базовый контроллер для форума с методами просмотра разделов и тем?

В классической MVC контроллер принимает запрос, взаимодействует с моделью и передает данные представлению. Для форума контроллер может содержать методы: index (список разделов), viewSection (темы раздела), viewTopic (сообщения темы), createTopic (создание новой темы) и другие.

class ForumController {
    private $db;
    public function __construct($db) {
        $this->db = $db;
    }
    public function index() {
        $sections = $this->db->query("SELECT * FROM sections");
        require 'views/forum/index.php';
    }
    public function viewSection($id) {
        $section = $this->db->query("SELECT * FROM sections WHERE id = " . intval($id));
        $topics = $this->db->query("SELECT * FROM topics WHERE section_id = " . intval($id));
        require 'views/forum/section.php';
    }
    public function viewTopic($id) {
        $topic = $this->db->query("SELECT * FROM topics WHERE id = " . intval($id));
        $posts = $this->db->query("SELECT * FROM posts WHERE topic_id = " . intval($id));
        require 'views/forum/topic.php';
    }
}

Index php app forums controller (контроллер форума в php)

Типичные проблемы: прямое использование $this->db без защиты от инъекций (в примере применяется intval, но не всегда). Отсутствие обработки случаев, когда раздел или тема не найдены. Нет проверки прав доступа. Жесткая привязка к представлению.

Как организовать гибкую маршрутизацию для URL форума?

Использование маршрутизатора (роутера) позволяет отвязать URL от файловой структуры. Пример роутера:

class Router {
    private $routes = [];
    public function add($pattern, $handler) {
        $this->routes[$pattern] = $handler;
    }
    public function dispatch($uri) {
        foreach ($this->routes as $pattern => $handler) {
            if (preg_match($pattern, $uri, $matches)) {
                return call_user_func_array($handler, array_slice($matches, 1));
            }
        }
        throw new Exception('Route not found');
    }
}
// Использование:
$router = new Router();
$router->add('#^/forum/section/(\d+)$#', function($id) use ($controller) {
    $controller->viewSection($id);
});
$router->add('#^/forum/topic/(\d+)$#', function($id) use ($controller) {
    $controller->viewTopic($id);
});

Model index php (модель в php (mvc))

Возможные ошибки: порядок маршрутов важен (первое совпадение). Некорректные регулярные выражения приводят к сбоям. Отсутствие валидации параметров.

Как вынести бизнес-логику из контроллера форума?

Применение сервисного слоя (Service Layer). Контроллер делегирует операции сервисам, а сервисы работают с моделями.

class ForumService {
    private $db;
    public function __construct($db) { $this->db = $db; }
    public function getSections() { /* логика */ }
    public function createTopic($userId, $sectionId, $title, $content) { /* логика */ }
}
// В контроллере:
$forumService = new ForumService($db);
$this->forumService = $forumService;
public function createTopic($request) {
    $result = $this->forumService->createTopic($request->userId, $request->sectionId, ...);
    // редирект или ответ
}

Php controllers index (индексный контроллер php)

Проблема: увеличение числа классов, усложнение тестирования, если не использовать внедрение зависимостей.

Как добавить аутентификацию и права доступа к действиям форума?

Middleware фильтры выполняются до контроллера. Например, проверка, залогинен ли пользователь.

class AuthMiddleware {
    public function handle($request, $next) {
        if (!isset($_SESSION['user'])) {
            header('Location: /login');
            exit;
        }
        return $next($request);
    }
}
// Применение в роутере:
$router->add('#^/forum/create-topic$#', [new AuthMiddleware(), 'handle'], function() use ($controller) {
    $controller->createTopic();
});

Ошибки: неправильная передача управления между middleware, проблемы с сессиями на REST API. Рекомендуется использовать готовые библиотеки.

Расширенные примеры реализации контроллера форума

Как построить полный каркас приложения форума с использованием фронт-контроллера, роутера, контроллера и модели?

Рассмотрим полный пример, когда запросы обрабатываются единой точкой входа index.php, маршруты настраиваются в роутере, контроллер использует модель для работы с БД, а представления подключаются для вывода HTML.

Пример
// index.php
spl_autoload_register(function ($class) {
    include 'classes/' . $class . '.php';
});
$router = new Router();
$model = new ForumModel($pdo);
$controller = new ForumController($model);
$router->add('#^/forum$#', [$controller, 'index']);
$router->add('#^/forum/section/(\d+)$#', [$controller, 'viewSection']);
$router->add('#^/forum/topic/(\d+)$#', [$controller, 'viewTopic']);
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
try {
    $router->dispatch($uri);
} catch (Exception $e) {
    http_response_code(404);
    echo 'Страница не найдена';
}
Пример
// ForumController.php
class ForumController {
    private $model;
    public function __construct($model) {
        $this->model = $model;
    }
    public function index() {
        $sections = $this->model->getAllSections();
        include 'views/forum/index.php';
    }
    public function viewSection($id) {
        $section = $this->model->getSectionById($id);
        if (!$section) {
            http_response_code(404);
            echo 'Раздел не найден';
            return;
        }
        $topics = $this->model->getTopicsBySection($id);
        include 'views/forum/section.php';
    }
    public function viewTopic($id) {
        $topic = $this->model->getTopicById($id);
        if (!$topic) {
            http_response_code(404);
            echo 'Тема не найдена';
            return;
        }
        $posts = $this->model->getPostsByTopic($id);
        include 'views/forum/topic.php';
    }
}
Пример
// ForumModel.php
class ForumModel {
    private $pdo;
    public function __construct($pdo) {
        $this->pdo = $pdo;
    }
    public function getAllSections() {
        $stmt = $this->pdo->query('SELECT * FROM sections');
        return $stmt->fetchAll();
    }
    public function getSectionById($id) {
        $stmt = $this->pdo->prepare('SELECT * FROM sections WHERE id = ?');
        $stmt->execute([$id]);
        return $stmt->fetch();
    }
    public function getTopicsBySection($sectionId) {
        $stmt = $this->pdo->prepare('SELECT * FROM topics WHERE section_id = ?');
        $stmt->execute([$sectionId]);
        return $stmt->fetchAll();
    }
    public function getTopicById($id) {
        $stmt = $this->pdo->prepare('SELECT * FROM topics WHERE id = ?');
        $stmt->execute([$id]);
        return $stmt->fetch();
    }
    public function getPostsByTopic($topicId) {
        $stmt = $this->pdo->prepare('SELECT * FROM posts WHERE topic_id = ?');
        $stmt->execute([$topicId]);
        return $stmt->fetchAll();
    }
}
Пример

Разделы форума

Результат работы: при переходе по адресу /forum отображается список разделов, каждый раздел является ссылкой на /forum/section/ID, где выводятся темы раздела. Модель использует подготовленные запросы PDO, что защищает от SQL-инъекций.

Список разделов форума:
 - Общий раздел
 - Техническая поддержка
 - Предложения

Как реализовать REST API для форума с выводом данных в JSON?

Для API контроллер возвращает JSON вместо HTML, часто используется отдельный namespace или префикс URL.

Пример
class ApiForumController {
    private $model;
    public function __construct($model) { $this->model = $model; }
    public function getSections() {
        header('Content-Type: application/json');
        $sections = $this->model->getAllSections();
        echo json_encode($sections);
    }
    public function getTopicsBySection($id) {
        header('Content-Type: application/json');
        $topics = $this->model->getTopicsBySection($id);
        echo json_encode($topics);
    }
}
// В роутере добавляем:
$apiController = new ApiForumController($model);
$router->add('#^/api/forum/sections$#', [$apiController, 'getSections']);
$router->add('#^/api/forum/section/(\d+)/topics$#', [$apiController, 'getTopicsBySection']);
{"getSections": [{"id":1,"title":"Общий раздел"},{"id":2,"title":"Техническая поддержка"}]}

При обращении к /api/forum/sections возвращается JSON со списком разделов. Это позволяет строить SPA или мобильные приложения. Для защиты API можно добавить аутентификацию через токены.

Контроллер форума в PHP - comments

En
Index php app forums controller (php)