Как реализовать действие контроллера в среде PHP MVC? - PullRequest
2 голосов
/ 23 февраля 2012

Я пытаюсь создать свою собственную среду MVC на PHP, чтобы узнать о них, но в настоящее время у меня возникают проблемы с реализацией действия контроллера.

Проблема в том, что некоторые контроллеры имеют один или несколько аргументовтакой как actionView ($ id), в то время как другие не имеют аргументов, таких как actionCreate ().Как мне обращаться с этим по-разному?

Например:

$action; //contains my action
$params; //array containing my arguments

В моем контроллере я бы позвонил ...

$this->$action(); //for no parameters
$this->$action($params[0]); //for one parameter
$this->$action($params[0], $params[1]); //for two parameters
... and so on

Это было бы невозможносправиться с любой возможной ситуацией, как это.Возможно, я неправильно выполняю действия.Может ли кто-нибудь направить меня в правильном направлении?

РЕДАКТИРОВАТЬ: Как рамки MVC позволяют обрабатывать несколько аргументов?

Ответы [ 4 ]

2 голосов
/ 23 февраля 2012

Я бы просто передал массив аргументов в качестве единственного аргумента каждому действию. Пусть будет известно, что соглашение вашей платформы включает передачу аргументов действиям таким способом. Это позволяет коду реализации выбирать, как они хотят иметь с ним дело; используйте func_get_args() возможно или укажите параметр в сигнатуре метода:

public function action(array $args = array()) { ...

Однако следует опасаться, что, хотя в вашем действии может потребоваться параметр, пользователь может его не предоставить. Если ваша сигнатура метода настроена так, чтобы требовать передачи значения, и у вас недостаточно значений для подключения, вы можете получить всевозможные ошибки. Это одна из причин, по которой я бы предпочел просто передать массив параметров и всегда передавать массив, даже если он пуст.


В качестве альтернативы, частично влияя на ответ BrNathanH, вы можете каким-то образом привязать объект к заданному действию и затем внедрить этот массив в конструктор объекта. Этот объект может быть ответственным за предоставление данных, необходимых для действия, и предоставление подходящих значений по умолчанию / проверку на наличие значений. Затем вы можете просто добавить сигнатуру объекта к вашим действиям, если вы хотите быть вдвойне уверены, что они получают соответствующие данные. Я не уверен точно, как бы вы реализовали это в своем собственном коде, основной проблемой является сопоставление controller :: action с соответствующим «ParamObject». Но обертывание массива в объекты может быть хорошей идеей и решит проблему незнания, сколько параметров нужно передать. Это всегда один «ParamObject», связанный с этим действием.

1 голос
/ 23 февраля 2012

Лучший способ объяснить это с помощью примеров, так что вот пример моей собственной реализации приложения PHP-MVC. Обязательно обратите особое внимание на функцию Hook::run, которая обрабатывает аргументы для загрузки элемента управления.

index.php:

<?php
class Hook {
    const default_controller = 'home';
    const default_method = 'main';
    const system_dir = 'system/';

    static function control ($name, $method, $parameter) {
        self::req(Hook::system_dir.$name.'.php'); // Include the control file
        if (method_exists('Control', $method)) { // For my implementation, I can all control classes "Control" since we should only have one at a time
            if (method_exists('Control', 'autoload')) call_user_func(array('Control', 'autoload')); // This is extremely useful for having a function to execute everytime a particular control is loaded
            return call_user_func(array('Control', $method), $parameter); // Our page is actually a method
        }
        throw new NotFound($_GET['arg']); // Appear page.com/control/method does not exist, so give a 404
    }

    static function param ($str, $limit = NULL) { // Just a wrapper for a common explode function
        return (
            $limit
                ? explode('/', rtrim($str, '/'), $limit)
                : explode('/', rtrim($str, '/'))
            );
    }

    static function req ($path) { // Helper class to require/include a file
        if (is_readable($path)) return require_once($path); // Make sure it exists
        throw new NotFound($path); // Throw our 404 exeception if it doesn't
    }

    static function run() {
        list($name, $method, $parameter) = ( // This implementaion expects up to three arguements
            isset($_GET['arg'])
                ? self::param($_GET['arg'], 3) + array(self::default_controller, self::default_method, NULL) // + array allows to set for default params
                : array(self::default_controller, self::default_method, NULL) // simply use default params
        );
        return self::control($name, $method, $parameter); // Out control loader
    }

}

class AuthFail extends Exception {}
class UnexpectedError extends Exception {}
class NotFound extends Exception {}

try {
    Hook::run();
}
catch (AuthFail $exception) { // Makes it posssible to throw an exception when the user needs to login
    // Put login page here
    die('Auth failed');
}
catch (UnexpectedError $exception) { // Easy way out for error handling
    // Put error page here
    die('Error page');
}
catch (NotFound $exception) { // Throw when you can't load a control or give an appearance of 404
    die('404 not found');
}

система / home.php:

<?php

class Control {
    private function __construct () {}
    static function autoload () { // Executed every time home is loaded
        echo "<pre>Home autoload\n";
    }
    static function main ($param='') { // This is our page
        // Extra parameters may be delimited with slashes
        echo "Home main, params: ".$param;
    }
    static function other ($param='') { // Another page
        echo "Home other, params:\n";
        $param = Hook::param($param);
        print_r($param);
    }
}

.htaccess:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l

RewriteRule ^(.+)$ index.php?arg=$1 [QSA,L]

С помощью этого файла htaccess мы можем загрузить элемент home.php, используя localhost/home/main. Без этого наши URL выглядели бы как localhost/index?args=home/main.

Демонстрационный скриншот 1 (localhost / simple_mvc / home / main / args1 / args2 / args3): Demonstration screenshot 1

Вы не всегда знаете, сколько аргументов ожидает конкретный метод управления, поэтому я считаю, что лучше всего передать один аргумент, ограниченный косой чертой. Если метод управления ожидает более одного аргумента, вы можете использовать предоставленную функцию Hook::param для дальнейшей оценки.

Демонстрационный скриншот 2 (localhost / simple_mvc / home / other / args1 / args2 / args3): Demonstration screenshot 2

Чтобы ответить на ваш вопрос:
Ключевым файлом, который действительно помогает ответить на ваш вопрос, является файл .htaccess, который превращает localhost/these/types/of/urls в нечто вроде localhost/index.php?args=these/types/of/urls. Это тогда позволяет вам разделить аргументы, используя explode($_GET['args'], '/');.

БОЛЬШОЙ видеоурок на эту тему здесь . Это действительно помогает многое объяснить.

Я внес некоторые изменения в home.php и index.php с последним редактированием

0 голосов
/ 23 февраля 2012

Для аргументов вы всегда можете установить некоторые аргументы как необязательные. Как это:

function($argument='', $argument2='')
{
    // ...
}

Это означает, что $argument и $argument2 являются необязательными. Если эти аргументы установлены при вызове функции ... эти аргументы будут иметь значения.

Хотя передача некоторых символов array() (а затем использование isset() для проверки установленных ключей или элементов массива) будет проще для некоторых функций.

0 голосов
/ 23 февраля 2012

Вы можете просто передать весь массив.Проблема в том, что каждый контроллер должен выполнять проверку ошибок, чтобы увидеть, есть ли правильные значения.Другим решением будет создание объекта данных, который содержит параметры.У вас есть доступ к контроллеру (который выполняет всю проверку ошибок за вас).

...