拥有URL的PHP​​ MVC?

时间:2014-11-25 02:47:42

标签: php oop model-view-controller architecture model

我正在使用MVC技术实现PHP应用程序。加载http://site/photos/25?options的简要介绍,重写为http://site/index.php?page=photos&id=25&options

  • index.php - >实例化并调用PhotoController object
  • PhotoController实例化PhotoView并将正确的Photo(模型)加载到其中
  • PhotoController调用PhotoView->render()和页眉/页脚视图
  • PhotoView可以访问Photo模型及其所需的其他模型数据

PhotoView将输出HTML并希望超链接到不同的页面。当该视图生成超链接时,我对哪个层应该拥有URL感到困惑。我看到的选项概述如下。请帮我选择正确的方法。


模型图层拥有网址

  

模型有getURL()方法

优点:

  • 基础View类可以包含Open Graph属性
  • PhotoView可以执行此操作:$folderHref = $photo->getFolder()->url

缺点:

  • 有些控制器没有单一的对应型号,例如LoginControllerAdminController,我如何获取这些的网址?

控制器拥有网址

  

控制器具有urltitle属性。要创建链接,呈现控制器将创建目标控制器并传递给视图。该视图从传递的对象访问urltitle

优点:

  • 每个网址都直接映射到控制器(在index.php中),因此反之亦然

缺点:

  • 需要其他视图的网址的视图需要以下丑陋的黑客之一:

    • 查询不相关的控制器$folderHref = Controllers\FolderController::urlForFolder($photo->getFolder())

    • 了解他们的控制器$folderHref = $photo->getFolder()->getControllerAndSetURL()->getURL()

    • 的观点太多了
    • 视图与其控制器$folderHref = $this->delegate->getURLForFolder($photo->getFolder())$adminHref = $this->delegate->getURLForAdminHref()之间的过度通信,delegate有多种方法


每个人都拥有网址

  

基类OpenGraphObjectControllers AND Models的父类,其方法为getURL()

ControllersModels只有在没有参数的情况下才能运行它。 (例如PhotoController返回NULL,因为URL取决于Photo将显示的内容。

优点:

  • 以上所有优势

缺点

  • 混乱
  • 撤销我的编程许可

1 个答案:

答案 0 :(得分:0)

为了解决问题,我会将其分解为:

/**
 * Responsible for processing and rendering user output
 */
interface View {

    public function render();
}

/**
 * Used just to further formalize the messages between Photo and View
 */
interface PhotoView extends View {

    public function setPhotoData($id, $title, $link);
}

/**
 * Among other things knows how to generate URLs to routes
 */
interface Router {

    /**
     * Returns the URL to route based on route name
     * @param string $routeName
     * @param array $params
     */
    public function urlTo($routeName, $params = null);
}

我不打算实现每个类,你可以使用大量的现成解决方案,例如模板引擎和路由器。

基于id显示图像的示例控制器可以是:

class PhotoController {

    public function displayAction($photoId) {
        $photo = Photo::findById($photoId);

        $templateFile = $this->pathTo('photo-template.php');

        //can be a singleton for example, it holds all the routes for the application
        //and knows how to render them based on the name and parameters
        $router = AppRouter::instance();

        return $photo->render(new ConcretePhotoView($templateFile, $router));
    }

}

在此示例中,Photo需要能够从数据库中获取自身,然后将自身呈现给PhotoView:

class Photo {

    private $id;
    private $title;
    private $sourceLink;

    //other methods...

    public function render(PhotoView $view) {
        $view->setPhotoData($this->id, $this->title, $this->sourceLink);

        return $view->render();
    }

}

假设HTML模板photo-template.php如下所示:

<a href="<?= $userLogin['href'] ?>"><?= $userLogin['label'] ?></a>
<a href="<?= $userRegister['href'] ?>"><?= $userRegister['label'] ?></a>
<div>
    <img src="<?= $photo['src'] ?>" title="<?= $photo['title'] ?>" />
    <a href="<?= $photoLink['href'] ?>"><?= $photoLink['label'] ?></a>
</div>

应该清楚这个模板需要什么变量。没有逻辑,只是纯粹的显示,虽然一些基本的控制是可以的。

剩下的就是编写ConcretePhotoView代码,它将使用提供的模板文件和路由器来调整域对象Photo和具体的html模板之间的数据:

class ConcretePhotoView implements PhotoView {

    private $templateEngine;
    private $router;

    public function __construct($templateFile, Router $router) {
        $this->templateEngine = new SomeTemplateEngine($templateFile);
        $this->router = $router;
    }

    public function render() {
        //router has a route userLogin with no params
        $this->templateEngine->assign('userLogin', array(
            'href' => $this->router->urlTo('userLogin'),
            'label' => 'Login'
        ));

        $this->templateEngine->assign('userRegister', array(
            //router has a route named userRegister that requires no params
            'href' => $this->router->urlTo('userRegister'),
            'label' => 'Register'
        ));

        return $this->templateEngine->render();
    }

    public function setPhotoData($id, $title, $link) {
        $this->templateEngine->assign('photo', array(
            'src' => $link,
            'title' => $title
        ));

        $this->templateEngine->assign('photoLink', array(
            //router has a route named photo that requires an id
            'href' => $this->router->urlTo('photo', array('id' => $id)),
            'label' => $title
        ));
    }

}

最后回答“谁拥有网址?”的问题。 - 路由器。该知识封装在那里,并且特定于应用程序配置。其他对象使用它来生成链接。