CakePHP странное поведение с beforeFilter: я не могу установить переменные для представления - PullRequest
0 голосов
/ 03 октября 2010

Хорошо, для этого потребуется некоторая настройка:

Я работаю над методом использования красивого заголовка сообщения "slugs" в URL-адресах моего блога с поддержкой cakePHP.

Например: /blog/post-title-here вместо /blog/view_post/123.

Поскольку я, очевидно, не собираюсь писать новый метод для каждого поста, я стараюсь быть хитрым и использовать обратные вызовы CakePHP, чтобы эмулировать поведение магического метода PHP 5 __call(). Для тех, кто не знает, диспетчер CakePHP проверяет, существует ли метод, и выдает ошибку cakePHP, прежде чем __call() может быть вызван в контроллере.

Что я сделал до сих пор:

В интересах полного раскрытия информации (потому что я понятия не имею, почему у меня возникла проблема) у меня есть два пути:

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

Они устанавливают псевдоним для BlogPostsController, чтобы мой URL не выглядел как /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. Когда я выполняю вызов $this->render('single_post'), представление отображается с установленной переменной $post, а затем снова отображается с ней не установлено . Таким образом, в действительности я получаю два полных макета, один за другим, в одном документе. Один с содержанием, а другой без.

Я пытался использовать метод с именем single_post и метод с именем __single_post, и у обоих была одна и та же проблема. Я бы предпочел, чтобы конечным результатом был метод с именем __single_post, чтобы к нему нельзя было напрямую получить доступ с помощью URL /blog/single_post.

Также

Я еще не закодировал обработку ошибок, когда сообщение не существует (поэтому, когда люди вводят случайные вещи в URL, они не получают представление single_post). Я планирую сделать это после того, как выясню эту проблему.

1 Ответ

1 голос
/ 03 октября 2010

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

// 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 перехватывает все URL, которые начинаются с /blog/, он поймает /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
}

Обработка ошибок: сделано.

...