Передний контроллер лучше всего связывает параметры с логикой приложения?

Я создаю приложение с использованием шаблона проектирования Front Controller, и есть только одна страница index.php, через которую все пользовательские запросы передаются как параметры (по сравнению с разными страницами/контроллерами в обычном дизайне).

Как подключить эти параметры к логике приложения?

например. У меня есть два разных действия:

index.php?action=userLogin&username=admin&password=qwerty //process user login

index.php?action=displayUsersTable //show registered users

В настоящее время у меня есть array со всеми действиями, которые система принимает (вместе с ожидаемыми аргументами), и я сравниваю параметр action от URL-адреса к key этого массива, а затем проверяю необходимые аргументы для этого действия.

//1 = optional, 2=required
$systemActions = [
      "userLogin" => [
            "login" => 2,
            "password" => 2
                     ],
      "displayUsersTable" => []
                 ];

Очевидно, что это станет монстром, когда система растет.

Есть ли лучший подход для привязки параметров, отправленных на передний контроллер к действиям системы?

Ответ 1

Поскольку код "фиксирован" (т.е. не управляется из базы данных), нет необходимости перекачивать в массив (и все служебные данные обработки/памяти, которые ему требуются). Да, это может быть улучшено.

Но есть много вариантов в зависимости от того, насколько будет расти проект.

Простейшие

Простейшими были бы простые инструкции "если" или переключатель. Я бы начал там, чтобы все было просто.

Более сложный

Вы говорите, что другие проекты имеют разные страницы/контроллеры, но есть причина. И поскольку вы просите улучшения, особенно если вы ожидаете, что проект вырастет до такой степени, что вы ищете оптимизацию, тогда вам действительно стоит рассмотреть эти причины (и разделить на файлы).

На другом конце шкалы вы можете разделить все вызовы на файлы/классы и автоматически загрузить файлы/классы.

Таким образом, вы выполняете только код, который вам нужен (меньшие размеры файлов), очень модульный и удобный для совместной работы. И если вы добавляете новое действие, вам не нужно изменять индекс или массив - вы только изменяете файл действия, над которым работаете.

Пример (значительно упрощен из проекта, над которым я сейчас работаю):

1) Создайте базовый класс baseAction, из которого будут действовать все действия. Вы можете добавить общие функции, такие как параметры очистки/предварительной обработки, протоколирование, проверка заголовков и т.д.

abstract class baseAction {
    protected $aExpectedParams = [];
    protected $aParams = [];
    protected $validParams = true;

    function __construct() {
        foreach (self::$aExpectedParams as $name=>$aParam) {
            if (isset($_GET[$name]))
                if ($aParam['type'] == 'string') {
                    self::$aParams[$name] = $_GET[$name];
                } elseif ($aParam['type'] == 'int') {
                    self::$aParams[$name] = (int)$_GET[$name];
                }
            } elseif ($aParam['required']) {
                self::$validParams = false;                
            }
        }
    }

    // This is the called function
    abstract function execute();

}

2) Создайте классы "действия", расширив базовое действие. Сохраните их в отдельных файлах (чтобы другие могли взаимодействовать с проектом без вмешательства).

// put in 'actions/userLogin.php
class userLogin extends baseAction {
    protected $aExpectedParams = [
            'login' => ['type' => 'string', 'required' => true]
            'password' => ['type' => 'string', 'required' => true]  // NOTE: you should never actually pass password unencrypted through "get" as they'll get stuck in user logs!
                    ];

    public function execute() {
        // Do Whatever
    }
}

.

// put in 'actions/displayUsersTable.php
class displayUsersTable extends baseAction {
    public function execute() {
        // Do Whatever
    }
}

3) Создайте автозагрузчик, чтобы вытащить эти отдельные файлы.

function myAutoloader($className) {
    if (file_exists(__DIR__ . '/actions/' . $className . '.php')) {
        require_once(__DIR__ . '/actions/' . $className . '.php');
    }
}
spl_autoload_register ('myAutoloader');

4) Затем ваш index.php так же чист, как

$action = $_GET['action'] ?? '';
if (strlen($action) > 0 && class_exists($action) && method_exists($action, 'execute')) {
    $oAction = new $action();
    $oAction->execute();
} else {
    // Oopsie
}

(Примечания к этому последнему фрагменту: "class_exists" запускает автозагрузчик. "method_exists" проверяет, что кто-то не запросил общий класс php, такой как "объект"; если вы безопаснее, namespace это или добавить дополнительную проверку. Это просто пример!)