2013-10-27 4 views
0

Обычно это не тот вопрос, который я задал бы, так как я ожидаю, что это что-то глупое, чего мне не хватает, но в отладке я нашел какое-то действительно странное поведение, которое действительно меня насторожило.Zend framework 2: redirect toRoute shortcircuit не запускается

Чтобы описать установку, в которой происходит (предположительно) ошибка: У меня есть основной CRUD-контроллер (или предпочтительный NERD в моем случае), где у меня есть четыре действия:

  • новый
  • редактировать
  • чтения
  • удалить

Считанные, редактировать и удалять действия требуют объект, скажем BlogPost, и URL вызывается такой маршрут, как /post/read/[:id], должен быть предоставлен идентификатор. Первое, что я делаю в каждом из этих действий, - проверить, что (a) установлен параметр id, и что (b) идентификатор соответствует действительному объекту, хранящемуся в базе данных (я использую Doctrine 2 в качестве mapper). Если какой-либо (а) или (б) не удается, я немедленно вернуться и перенаправить к действию индекса:

return $this->redirect()->toRoute('post/index'); 

Я делаю проверку в отдельной публичной функции в том же контроллере для предотвращения дублирования кода.

Кодекс:

<?php 

namespace Blog\Controller; 

use Zend\Mvc\Controller\AbstractActionController; 
use Zend\Mvc\Controller\Plugin\FlashMessenger as FlashMessenger; 

class PostController extends AbstractActionController 
{ 

    public function editAction() 
    { 
     $post_id = $this->params()->fromRoute('id'); 
     $post = $this->validatePostId($post_id); 

     // Create/Validate forms and persist/flush 

     return array(
      'post' => $post, 
      'form' => $form 
     ); 
    } 

    public function deleteAction() 
    { 
     $post_id = $this->params()->fromRoute('id'); 
     $post = $this->validatePostId($post_id); 

     // Remove post from database 
     $this->getBlogService()->deletePost($post); 
     $this->flashMessenger()->addSuccessMessage('Post successfully deleted'); 
     return $this->redirect()->toRoute('post'); 
    } 

    public function readAction() 
    { 
     $post_id = $this->params()->fromRoute('id'); 
     $post = $this->validatePostId($post_id); 

     return array(
      'post' => $post 
     ); 
    } 

    /** 
    * Checks if $id from url is set and tries to find the corresponding post 
    */ 
    public function validatePostId($post_id) 
    {   
     if (!$post_id) { 
      $this->flashMessenger()->addErrorMessage('Invalid post id'); 
      return $this->redirect()->toRoute('post'); 
     } 

     $post = $this->getBlogService()->getPostById($post_id); 

     if ($post == NULL) { 
      $this->flashMessenger()->addErrorMessage('Invalid post id'); 
      return $this->redirect()->toRoute('post'); 
     } 

     return $post; 
    } 
} 

Проблема

Этот код работает отлично для readAction() за исключением тех случаев, даже если два условными в validatePostId() огня, return $this->redirect() как-то не срабатывает, и приложение Отрисовывает просмотр и последующие ошибки с недействительным доступом не-объекта $post.

Я проверил тысячу раз, и условия, которые проверяют действительные $post, действительно введены и поэтому я уверен, что вызывается перенаправление. Подсказка, которую я нашел, но не могу объяснить, заключается в следующем. Если бы я изменить действие для чтения к следующему, просто добавив одну строку:

public function readAction() 
{ 
    $post_id = $this->params()->fromRoute('id'); 
    $post = $this->validatePostId($post_id); 

    $form = $this->getPostForm()->bind(); 

    return array(
     'post' => $post 
    ); 
} 

проблема исчезает, и приложение аккуратно перенаправляет. Однако это не имеет смысла. Строка просто вызывает публичную функцию в контроллере, которая создает форму, и, насколько я вижу, это не должно иметь никакого эффекта. Хуже, если я удалю вызов ->bind() с этой строки, старая проблема снова вернется. Таким образом, все, что мне удалось выяснить, заключается в том, что разница в действиях, по-видимому, заключается в отсутствии какого-либо дополнительного кода между вызовом validatePostId() и возвратом вида, что не имеет особого значения ...

Редактировать :

обновление, если я непосредственно использовать код функции validatePostId() в readAction() проблема исчезает:

public function readAction() 
{ 
    $post_id = $this->params()->fromRoute('id'); 
    $post = $this->validatePostId($post_id); 

    if (!$post_id) { 
     $this->flashMessenger()->addErrorMessage('Invalid post id'); 
     return $this->redirect()->toRoute('post'); 
    } 

    $post = $this->getBlogService()->getPostById($post_id); 

    if ($post == NULL) { 
     $this->flashMessenger()->addErrorMessage('Invalid post id'); 
     return $this->redirect()->toRoute('post'); 
    } 

    return array(
     'post' => $post 
    ); 
} 
+0

Интересно, что для проверки empty() вместо == NULL. – Ryan

+0

'empty()' не имеет значения – Pankrates

+0

последнее исправление говорит о том, что что-то идет не так в $ post = $ this-> getBlogService() -> getPostById ($ post_id); В исходном коде, если вы var_dump ($ post_id) и var_dump ($ post) перед возвратом, и оба они все равно null, я в тупике. Возможно, что-то пойдет не так после redirect -i.e. везде, где идет маршрут («сообщение»). +1 для вашего аватара, btw – Ryan

ответ

1

акт вызова $this->redirect() в контроллере не автоматически перенаправлять на новое место, он просто возвращает объект Response w поэтому вам необходимо вернуться из действия вашего контроллера, чтобы коротко закоротить запрос.

Поскольку вы возвращение результата redirect() вызова из другой функции, вам нужно сначала тест, если результат этого вызова является Response объектом и обрабатывать его в действии контроллера ...

<?php 

namespace Blog\Controller; 

use Zend\Mvc\Controller\AbstractActionController; 
use Zend\Mvc\Controller\Plugin\FlashMessenger as FlashMessenger; 

use Zend\Stdlib\ResponseInterface as Response; 

class PostController extends AbstractActionController 
{ 

    public function readAction() 
    { 
     $post_id = $this->params()->fromRoute('id'); 
     $post = $this->validatePostId($post_id); 

     // check to see if post validation returned a Response 
     if ($post instanceof Response) { 
      // redirect... 
      return $post; 
     } 

     return array(
      'post' => $post 
     ); 
    } 

    /** 
    * Checks if $id from url is set and tries to find the corresponding post 
    */ 
    public function validatePostId($post_id) 
    {   
     if (!$post_id) { 
      $this->flashMessenger()->addErrorMessage('Invalid post id'); 
      return $this->redirect()->toRoute('post'); 
     } 

     $post = $this->getBlogService()->getPostById($post_id); 

     if ($post == NULL) { 
      $this->flashMessenger()->addErrorMessage('Invalid post id'); 
      return $this->redirect()->toRoute('post'); 
     } 

     return $post; 
    } 
} 
+0

Полезное объяснение, спасибо. Я изменил чек в предложенном вами действии, является ли '$ post' экземпляром Response для проверки, является ли он объектом, хотя он работает – Pankrates

Смежные вопросы