我在Kohana 3.1.3.1中的HMVC子请求后保留变量的值时遇到了问题,我想知道如何最好地处理/修复它。我认为Kohana中的其他请求是相互隔离的,但事实似乎并非如此。。。
首先,我创建了一个控制器来扩展controller_Template:
abstract class Controller_Website extends Controller_Template {
public $page_info;
public $allow_caching;
public function before()
{
// ... more unrelated code here ...
// Only do this if auto_render is TRUE (default)
if ($this->auto_render === TRUE AND $this->request->is_initial())
{
// Set our Page_Info to the values we just loaded from the database
$this->page_info = clone $this->navs[$slug];
}
// ... more unrelated code here ...
}
public function after()
{
// ... more unrelated code here ...
// For internal requests, let's just get everything except for the template
if (! $this->request->is_initial())
{
$this->response->body($this->template->main_view->render());
}
// Only if auto_render is still TRUE (Default)
if ($this->auto_render === TRUE AND $this->request->is_initial())
{
// ... more unrelated code here ...
// ... get stuff from the database to populate the template ...
// now render the response body
$this->response->body($this->template->render());
}
// ... more unrelated code here...
// including setting headers to disable/enable caching
}
}
下面是一个例子,其中一个控制器是什么样子的:
class Controller_Events extends Controller_Website {
public function action_filtered()
{
// ... do some stuff ...
// and set some values
$this->page_info->page_title = 'Set in Events controller';
// and some more stuff including generating some output
}
}
现在,我希望我的另一个控制器能够在没有模板的情况下从事件控制器中提取输出。Controller_Website(如上)负责将模板从输出中排除,但请考虑:
class Controller_Search extends Controller_Website {
public function action_index()
{
// ... do some stuff ...
// now let's include the result from our events controller
$this->template->main_view->events = Request::factory()
->controller('events')
->action('filtered')
->execute();
// and set some values
$this->page_info->page_title = 'Set in Search controller';
// and some more stuff including generating some output
}
}
因此,当我的模板调用echo $this->page_info->page_title;
时(记住,我的模板只包含在搜索控制器的输出中,而不是事件控制器的输出),我希望它返回"Set in search controller",但它却返回Set in Events controller"
问题是这个action_filtered()
方法很长,而且我已经设置了几个路由,使用这个方法来输出几个事件页面(比如按年份、月份、地点、城市等过滤事件),所以在我的搜索控制器中复制这个方法是没有意义的。因此需要HMVC请求。当过滤后的操作被调用为主/初始请求时,在$page_info
中设置值是有意义的,但当它被调用为子请求时,我需要保留在搜索控制器中设置的值,或者不管初始控制器是什么
当然,我可以在事件控制器中创建一个if语句,只在它是主请求的情况下更新这些值,但这显然不太理想。必须有一种方法使此子请求与初始请求隔离运行?
我做错了什么,或者解决这个问题的最佳方法是什么?
提前感谢!
DM
Request::factory()
->controller('events')
->action('filtered')
->execute();
这是不正确的。Request::factory()
调用返回一个初始Request
实例(因此它使用当前URI值)。您需要为HMVC调用生成一个URI:
Request::factory(Request::current()->uri(array(
'controller' => 'events',
'action' => 'filtered'
)))->execute();
PS。对不起,这是我的错误。您的代码在3.1中似乎有效。无论如何,请尝试使用Request->uri()来更改它
我找到了问题/解决方案!
问题是,在我的Controller_网站上,我的action_before()
:中有这个
// Create a new DM_Nav object to hold our page info
// Make this page info available to all views as well
$this->page_info = new DM_Nav;
View::bind_global('page_info', $this->page_info);
问题是bind_global
——它实际上按照预期工作,让你在事后更改这个变量的值(确实是一个非常巧妙的功能。)
变通方法/解决方案是通过检测模板是否为初始/主请求来强制模板仅使用原始page_info
。所以在Controller_Website
的action_before()
方法的最后,它说:
// Only if auto_render is still TRUE (Default)
if ($this->auto_render === TRUE AND $this->request->is_initial())
{
我在if
语句的末尾添加了这一行:
$this->template->page_info = $this->page_info;
}
这一行在初始/主请求上是多余的,但这意味着任何附加的子请求仍然可以访问它们自己的page_info
值,而不会影响模板中使用的值。因此,如果将属性指定给视图,然后尝试用新值bind_global()
同一属性,则它不会覆盖该属性,而是使用原始值(这就是这个解决方案有效的原因。)有趣。