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

Я создаю приложение, используя шаблон проектирования 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 ответ

Решение

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

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

самыйпростой

Самым простым будет простой оператор if или переключатель. Я бы начал там, чтобы все было просто.

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

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

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

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

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

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) Создайте классы "action", расширив базовый Action. Сохраните их в отдельных файлах (чтобы другие могли сотрудничать в проекте без вмешательства).

// 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, такой как "object"; если вы в большей безопасности, вам следует указать пространство имен этого или добавить дополнительную проверку. Это всего лишь пример!)

Другие вопросы по тегам