2012-07-24 68 views
0

我在PHP中创建了一个基本的MVC结构化CMS,作为学习MVC如何工作的手段(因此我没有使用真正的预构建引擎)。我有一个基本版本,其结构与本教程here非常相似。不过,我想要自动加载视图,而不需要模板类。如果强烈建议,我会坚持使用模板概念(如果有人可以解释为什么它是如此必要,我将不胜感激)。无论如何,下面是我的路由器类,我修改了自动加载视图文件沿控制器。PHP MVC - 模板/加载变量问题

public function loader() { 
     /*** check the route ***/ 
     $this->getPath(); 

     /*** if the file is not there diaf ***/ 
     if (is_readable($this->controller_path) == false) { 
      $this->controller_path = $this->path.'/controller/error404.php'; 
      $this->action_path = $this->path.'/view/error404.php'; 
     } 

     /*** include the path files ***/ 
     include $this->controller_path; 
     include $this->action_path; 

     /*** a new controller class instance ***/ 
     $class = $this->controller . 'Controller'; 
     $controller = new $class($this->registry); 

     /*** check if the action is callable ***/ 
     if (is_callable(array($controller, $this->action)) == false) { 
      $action = 'index'; 
     } else { 
      $action = $this->action; 
     } 
     $controller->$action(); 
    } 

    /** 
    * 
    * @get the controller 
    * 
    * @access private 
    * 
    * @return void 
    * 
    */ 
    private function getPath() { 

     /*** get the route from the url ***/ 
     $route = (empty($_GET['rt'])) ? '' : $_GET['rt']; 

     if (empty($route)) { 
      $route = 'index'; 
     } else { 
      /*** get the parts of the route ***/ 
      // mywebsite.com/controller/action 
      // mywebsite.com/blog/hello 
      $parts = explode('/', $route); 
      $this->controller = $parts[0]; 
      if(isset($parts[1])) { 
       $this->action = $parts[1]; 
      } 
     } 
     if(! $this->controller) { $this->controller = 'index'; } 
     if(! $this->action) { $this->action = 'index'; } 

     /*** set the file path ***/ 
     $this->controller_path = $this->path .'/controller/'. $this->controller . '.php'; 
     $this->action_path = $this->path .'/view/'. $this->controller . '/'. $this->action . '.php'; 
    } 

这是防止由控制器给出装载的变量(教程网站有这更好的证明)我的观点的文件,但设置$this->registry->template->blog_heading = 'This is the blog Index';时,因为template.class绕过视图不会加载它。基本上我问的是如何将template.class转换为加载函数?

+1

像你这样选择路由类中的视图模板是一个坏主意。不仅你假设每个动作都会呈现一个视图,而且视图只能有一个模板。一个单独的视图对象与从动作级别分配的模板和变量是更好的解决方案。 – lafor 2012-07-24 08:55:41

回答

0

在我自己开发的MVC中,加载一个视图的方法和你所拥有的类似,但是以一种比你所链接的例子更简单的方式。 (当我第一次决定尝试学习MVC时,我看到了这个例子,并且我记得它让我感到困惑;

本质上,在确定文件存在后,您只需要(是的,我觉得没有找到文件是停止脚本在这种情况下执行的一个很好的理由)

所以..而不是整个模板类的东西(我希望我不是躲闪你的问题并获得太远基地,这里有一种具有控制器打开查看文件的一个简单的例子。

<?php 
class Pizza_Shop_Controller extends Base_Controller 
{ 
    public function index() 
    { 
     $data['users'] = array('bob','lisa','bertha'); 
     $data['some_string'] = "Whoa I'm a string!"; 

     $this->render_view('index',$data); 
    } 

    public function contact() 
    { 
     if($_POST) 
     { 
      Contact::process($_POST); 
      return $this->render_view('contact_success'); 
     } 
     else 
     { 
      return $this->render_view('contact_form'); 
     } 
    } 


} 

class Base_Controller 
{ 

    protected function render_view($view_name,$data = array()) 
    { 
     /* 
     * I also think render_view should take care of loading the layout, and then inject the content into the middle of the layout file, 
     * so that you aren't trapping yourself to a specific layout, and repeating the header and footer inside of every view file 
     */ 

     extract($data); //places all $data variables into the local scope.. very clean and ezy ;]. 
     require($this->root_directory.DS."$view_name.php"); 
    } 

    /**********************************/ 
    public function _no_action($view_name) //Called if there is no corresponding action 
    { 
     /* You can use method_exists to test if a method exists within the controller, if it does not exist, 
     * you can then call this function, and pass it the name of the view that is attempting to be opened 
     */ 
     if($this->view_exists($view_name)) 
     { 
      $this->render_view($view_name,$data); 
     } 
     else 
     { 
      $this->render404(); 
     } 
    } 

} 
+0

虽然这解决了变量的问题,但我认为OP需要它,因此视图会根据控制器操作自动加载。我在家里有这样的东西,当我回来时我会发布,但我想它会被回答,然后哈哈 – andy 2012-07-24 08:49:29

+0

哈哈,好的。我添加了一个名为_no_action的方法来表示如果没有对应于视图文件的显式操作,则调用它。 – Anther 2012-07-24 08:54:11

+0

这是有效的,但我只会说你需要把它放在调用控制器的部分。这样,如果你有50多个控制器哈哈,你不必再重复该代码。除此之外,它的作品! – andy 2012-07-24 08:55:59

1

我知道这是不是难以置信的帮助现在给你,但几个月前我有同样的问题。这是基于框架我建:

https://github.com/andyhmltn/Cherry-Framework-Blog-Example/

我不完全知道从哪里或者是怎样做的,因为我还没有真正在一段时间看着它,但各地采取一捅和加载控制器,设置变量然后加载视图的代码可能在库文件夹中。它可以让你做到这一点:

/** Controller **/ 
class ExampleController extends Controller { 
    public function index() { 
     $helloworld = 'Hello world'; 
     $this->set('hello_world', $helloworld); 
     #Renders view automatically 
    } 
} 

/** View **/ 
echo $hello_world; 
+0

我会看看,希望这是我正在寻找。 – 2012-07-24 08:59:46

+0

你需要的是在那里挑衅,它只是一个适应它的情况,以适应你自己的框架,因为我确信它的行为非常不同。 – andy 2012-07-24 09:01:26

+0

找到它设置变量,然后决定渲染的变量:https://github.com/andyhmltn/Cherry-Framework/blob/master/library/template.class.php – andy 2012-07-24 09:02:43

2

相当常见的误解“的观点仅仅是一个愚蠢的模板”主要是由的Ruby-on-Rails和跟随他们破碎的ORM - 模板适配器那些长期存在。我不能直接面对他们作为模型 - 视图 - 控制器实现的...

视图应该处理MVC和MVC设计模式模式中的表示逻辑。这使得它们成为对象,并具有处理多个模板的能力。根据你的Web应用使用哪种MVC启发模式(用PHP实现传统的MVC是不可能的),你的Views将从Controller类结构(MVP和MVVM模式)接收数据,或者能够直接从模型层请求信息(Model2 MVC和HMVC模式)。我个人更喜欢活跃的意见,从模型层获取数据。

P.S.这样的代码$this->registry->template->blog_heading使得Demeter流血。

P.P.S.关于如何实现纯php模板,请阅读this article

+0

我会检查出来,感谢指针! – 2012-07-24 11:39:05

+0

您发送的链接非常翔实,并且符合我的最终目标。对于php模板链接,教程叫做“$ view-> render('main.php');”我怎么能够设置我的系统自动渲染,而不是每次手动输入? – 2012-07-24 11:42:49

+0

你可以通过为对象实现['__toString()'](http://www.php.net/manual/en/language.oop5.magic.php#object.tostring)方法来模仿,那么你可以只需使用'echo $ view;'并触发该方法。但我会建议避免它。有详细的代码,然后添加隐藏的魔法好多了。此外,该链接的部分原因是向你展示,你被称为“视图”的实际上是**模板**。这将导致演示逻辑泄漏到控制器中。 – 2012-07-24 13:16:52