CakePHP 与 beforeFilter 的奇怪行为:我无法将变量设置到视图

发布于 2024-09-25 16:57:27 字数 1977 浏览 3 评论 0原文

好的,这需要一些设置:

我正在研究一种在我的 cakePHP 支持的博客的 URL 中使用漂亮的帖子标题“slugs”的方法。

例如:/blog/post-title-here 而不是 /blog/view_post/123

由于我显然不会为每篇文章都编写一个新方法,因此我尝试巧妙地使用 CakePHP 回调来模拟 PHP 5 的 __call() 魔术方法的行为。对于那些不知道的人,CakePHP 的调度程序会检查方法是否存在,并在控制器中调用 __call() 之前抛出 cakePHP 错误。

到目前为止我所做的:

为了充分披露(因为我不知道为什么会遇到问题),我有两条路线:

Router::connect('/blog/:action/*', array('controller' => 'blog_posts'));
Router::connect('/blog/*', array('controller' => 'blog_posts'));

这些为 BlogPostsController 设置了一个别名,这样我的网址就不会'看起来像 /blog_posts/action

然后在 BlogPostsController 中:

public function beforeFilter() {
    parent::beforeFilter();
    if (!in_array($this->params['action'], $this->methods)) {
        $this->setAction('single_post', $this->params['action']);
    }
}
public function single_post($slug = NULL) {
    $post = $this->BlogPost->get_post_by_slug($slug);
    $this->set('post', $post);
    //$this->render('single_post');
}

beforeFilter 捕获不存在的操作并将它们传递给我的 single_post 方法。 single_post 从模型中获取数据,并为视图设置变量 $post

还有一个 index 方法可以显示最近 10 篇帖子。

这是令人困惑的部分:

您会注意到上面有一个被注释掉的 $this->render 方法。

  1. 当我调用 $this->render('single_post') 时,视图会渲染一次,但 $post 变量不会放。
  2. 当我 do 调用 $this->render('single_post') 时,视图将使用 $post 变量集进行渲染,然后渲染再次未设置。因此,实际上我在同一个文档中得到了两个完整的布局,一个接一个。一种有内容,一种没有内容。

我尝试使用名为 single_post 的方法和名为 __single_post 的方法,但两者都有相同的问题。我希望最终结果是一个名为 __single_post 的方法,这样就无法通过 URL /blog/single_post 直接访问它。

另外,

我还没有对帖子不存在时的错误处理进行编码(这样当人们在 url 中输入随机内容时,他们就不会获得 single_post 视图)。我打算在解决这个问题后这样做。

Okay, this will require some setup:

I'm working on a method of using nice post title "slugs" in the URL's of my cakePHP powered blog.

For example: /blog/post-title-here instead of /blog/view_post/123.

Since I'm obviously not going to write a new method for every post, I'm trying to be slick and use CakePHP callbacks to emulate the behavior of PHP 5's __call() magic method. For those who do not know, CakePHP's dispatcher checks to see if a method exists and throws a cakePHP error before __call() can be invoked in the controller.

What I've done so far:

In the interest of full disclosure ('cause I have no Idea why I'm having a problem) I've got two routes:

Router::connect('/blog/:action/*', array('controller' => 'blog_posts'));
Router::connect('/blog/*', array('controller' => 'blog_posts'));

These set up an alias for the BlogPostsController so that my url doesn't look like /blog_posts/action

Then in the BlogPostsController:

public function beforeFilter() {
    parent::beforeFilter();
    if (!in_array($this->params['action'], $this->methods)) {
        $this->setAction('single_post', $this->params['action']);
    }
}
public function single_post($slug = NULL) {
    $post = $this->BlogPost->get_post_by_slug($slug);
    $this->set('post', $post);
    //$this->render('single_post');
}

The beforeFilter catches actions that do not exist and passes them to my single_post method. single_post grabs the data from the model, and sets a variable $post for the view.

There's also an index method that displays the 10 most recent posts.

Here's the confounding part:

You'll notice that there is a $this->render method that is commented-out above.

  1. When I do not call $this->render('single_post'), the view renders once, but the $post variable is not set.
  2. When I do call $this->render('single_post'), The view renders with the $post variable set, and then renders again with it not set. So in effect I get two full layouts, one after the other, in the same document. One with the content, and one without.

I've tried using a method named single_post and a method named __single_post and both have the same problem. I would prefer the end result to be a method named __single_post so that it cannot be accessed directly with the url /blog/single_post.

Also

I've not yet coded error handling for when the post does not exist (so that when people type random things in the url they don't get the single_post view). I plan on doing that after I figure out this problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

°如果伤别离去 2024-10-02 16:57:27

这并没有明确回答您的问题,但我只是通过仅使用路线解决问题来放弃整个复杂性:

// Whitelist other public actions in BlogPostsController first,
// so they're not caught by the catch-all slug rule.
// This whitelists BlogPostsController::other() and ::actions(), so
// the URLs /blog/other/foo and /blog/actions/bar still work.
Router::connect('/blog/:action/*',
                array('controller' => 'blog_posts'),
                array('action' => 'other|actions'));

// Connect all URLs not matching the above, like /blog/my-frist-post,
// to BlogPostsController::single_post($slug). Optionally use RegEx to
// filter slug format.
Router::connect('/blog/:slug',
                array('controller' => 'blog_posts', 'action' => 'single_post'),
                array('pass' => array('slug') /*, 'slug' => 'regex for slug' */));

请注意,上述路线仅依赖于最近的错误修复,截至撰写本文时,合并到 Cake 中(请参阅 http: //cakephp.lighthouseapp.com/projects/42648/tickets/1197-routing-error-when-using-regex-on-action)。请参阅这篇文章的编辑历史以获得更兼容的解决方案。

至于可直接访问的 single_post 方法:我不会。由于 /blog/:slug 路由捕获所有/blog/ 开头的 URL,因此它会捕获 /blog/single_post 并调用 BlogPostsController::single_post('single_post')。然后,您将尝试查找带有“single_post”名称的帖子,该帖子可能不存在。在这种情况下,您可以抛出 404 错误:

function single_post($slug) {
    $post = $this->BlogPost->get_post_by_slug($slug);
    if (!$post) {
        $this->cakeError('error404');
    }

    // business as usual here
}

错误处理:完成。

This doesn't explicitly answer your question, but I'd just forego the whole complexity by solving the problem using only routes:

// Whitelist other public actions in BlogPostsController first,
// so they're not caught by the catch-all slug rule.
// This whitelists BlogPostsController::other() and ::actions(), so
// the URLs /blog/other/foo and /blog/actions/bar still work.
Router::connect('/blog/:action/*',
                array('controller' => 'blog_posts'),
                array('action' => 'other|actions'));

// Connect all URLs not matching the above, like /blog/my-frist-post,
// to BlogPostsController::single_post($slug). Optionally use RegEx to
// filter slug format.
Router::connect('/blog/:slug',
                array('controller' => 'blog_posts', 'action' => 'single_post'),
                array('pass' => array('slug') /*, 'slug' => 'regex for slug' */));

Note that the above routes depend on a bug fix only recently, as of the time of this writing, incorporated into Cake (see http://cakephp.lighthouseapp.com/projects/42648/tickets/1197-routing-error-when-using-regex-on-action). See the edit history of this post for a more compatible solution.

As for the single_post method being accessible directly: I won't. Since the /blog/:slug route catches all URLs that start with /blog/, it'll catch /blog/single_post and invoke BlogPostsController::single_post('single_post'). You will then try to find a post with the slug "single_post", which probably won't exist. In that case, you can throw a 404 error:

function single_post($slug) {
    $post = $this->BlogPost->get_post_by_slug($slug);
    if (!$post) {
        $this->cakeError('error404');
    }

    // business as usual here
}

Error handling: done.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文