ZF2 - Как изменить страницу ответа об ошибке/404? Не только шаблон, но и установка новой ViewModel

По умолчанию страница устанавливается в массиве Application module.config следующим образом:

'template_map' => array(
    'error/404' => __DIR__ . '/../view/error/404.phtml'

Я хочу изменить страницу. Я хочу новый ViewModel для него полный переменных. Это означает, что просто изменить шаблон недостаточно:

'error/404' => __DIR__ . '/../view/error/my_new_404_template.phtml'

Но я не могу понять, как это сделать. Я не вижу, как запрос приходит к 'error/404'.

  • Как создать для него новый ViewModel?

  • Как прикрепить к нему переменные?

  • Как маршрут подходит к 'error/404', чтобы поймать его, чтобы изменить?

Например, у меня есть такой метод для страницы 'error/404':

public function pageNotFoundAction() {

    $view = new ViewModel();

    $view->setTemplate('error/404');     // set my template

    $sm = $this->getServiceLocator()->get('SessionManager');
    $cont = new Container('SomeNamespace', $sm);

    $view->var1 = $cont->offsetGet('someValue1');   // the "error/404" template
    $view->var2 = $cont->offsetGet('someValue2');   //       is full of variables
    $view->var3 = $cont->offsetGet('someValue3');
    $view->var4 = "One more view variable";

    // And now I return it somewhere and want it to be called
    //    in case of "the page is not found"
    return $view;
}

Как сделать такое изменение? Я не могу заставить систему, которую они создали, справиться с такими вещами, как 'error/404'. Пожалуйста помоги.

ОБНОВЛЕНИЕ 1

Еще более сложная задача. Как иметь несколько 'error/404' страниц? Хотел бы спросить у ребят, создававших фреймворк, знают ли они, что 'not_found_template' не может иметь массив из 'error/404' страниц. Как это может быть? Если я установлю этот параметр следующим образом:

'template_map' => array(
    'error/404' => __DIR__ . '/../view/error/404.phtml',
    'my-page/one_more_error404' => __DIR__ . '/../view/my-page/my-page/one_more_error404.phtml',
    'other_page/second_404' => __DIR__ . '/../view/other-page/one_more_error404.phtml',

'not_found_template' => array(
    'error/404',
    'my-page/one_more_error404',
    'other-page/second_404',
);

выдает ошибку. 'not_found_template' заставить вас иметь только один 'error/404' шаблон?


person Green    schedule 10.12.2012    source источник
comment
Возможно, стоит заглянуть в Zend\Mvc\View\RouteNotFoundStrategy для подсказок. В нашем приложении эта стратегия запускалась установкой статуса 404 в нашем ответе.   -  person DrBeza    schedule 11.12.2012
comment
Комментарий @DrBeza, я думаю, что это путь Zend\Mvc\View\Http\RouteNotFoundStrategy для всех, кто ищет.   -  person four43    schedule 01.05.2013
comment
@ cr125rider Спасибо, что указали правильное местоположение (в то время я использовал более старую бета-версию ZF2).   -  person DrBeza    schedule 02.05.2013
comment
@DrBeza Нет проблем. Эти версии многое изменили, и в SO и остальной части Интернета есть много запутанных данных о том, для какой версии ZF2 предназначены примеры. Мой был для ZF2.1!   -  person four43    schedule 02.05.2013


Ответы (7)


Есть еще один способ. Чтобы поймать EVENT_DISPATCH_ERROR и полностью перестроить viewModel. Cavern — это макет — это корневой viewModel, а контент, добавленный в макет по умолчанию, — это еще один viewModel (дочерний). Эти моменты не так четко описаны в официальных документах.

Вот как это может выглядеть в вашем Module.php:

public function onBootstrap(MvcEvent $event)
{
    $app = $event->getParam( 'application' );
    $eventManager = $app->getEventManager();


    /** attach Front layout for 404 errors */
    $eventManager->attach( MvcEvent::EVENT_DISPATCH_ERROR, function( MvcEvent $event ){

        /** here you can retrieve anything from your serviceManager */
        $serviceManager = $event->getApplication()->getServiceManager();
        $someVar = $serviceManager->get( 'Some\Factory' )->getSomeValue();

        /** here you redefine layout used to publish an error */
        $layout = $serviceManager->get( 'viewManager' )->getViewModel();
        $layout->setTemplate( 'layout/start' );

        /** here you redefine template used to the error exactly and pass custom variable into ViewModel */
        $viewModel = $event->getViewModel();
        $viewModel->setVariables( array( 'someVar' => $someVar ) )
                  ->setTemplate( 'error/404' );
    });
}
person zelibobla    schedule 06.11.2013
comment
У меня сначала этот код не работал, причина была в строчке: $viewModel = $event-›getResult(); Я изменил его на: $viewModel = $event->getViewModel(); и теперь это работает как шарм - person Yaronius; 29.01.2015
comment
@Yaronius, вероятно, это может произойти, если не определена карта шаблона для отображения ошибок в module.config.php по ключу view_manager[ 'not_found_template' ]. Я считаю, что в этом случае не будет создана модель представления, и вы получите NULL при вызове $event->getResult(). В любом случае ваше предложение более универсально, поэтому я исправил свой ответ. Спасибо! - person zelibobla; 30.01.2015

Я использовал это для управления ошибкой 404 (я переместил свой сайт с spip на cms на основе ZF2):

В модуле onBootstrap функция:

$eventManager->getSharedManager()->attach('*', MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onDispatchError'), -100);

затем

public function onDispatchError(MvcEvent $event)
{
    $response = $event->getResponse();
    if ($response->getStatusCode() == 404) {
        $url = $event->getRouter()->assemble(array(), array('name' => 'index'));
        $requestUri = $event->getRequest()->getRequestUri();
        $response->getHeaders()->addHeaderLine('Location', "$url?url=$requestUri");
        $response->setStatusCode(200);
        $response->sendHeaders();
        $event->stopPropagation(true);
    } elseif($response->getStatusCode() == 500){
        //DO SOMETHING else?
        return;
     }
}

В этом коде мы никогда не возвращаем ошибку 404, мы просто вызываем маршрут (в моем примере index) с запрошенным URL-адресом в качестве параметра.

Надеюсь, это поможет вам.

person Abdel    schedule 15.08.2013
comment
Ну, я искал ответ слишком долго. Вы, сэр, получили от меня голос - person MKroeders; 06.10.2013
comment
$event-›stopPropagation(true); не останавливает приложение для меня :( Это правильный ответ, но я не могу остановить приложение, если не использую выход или смерть, что неправильно - person bksi; 20.01.2014

Я не уверен, что следую тому, чего вы пытаетесь достичь, можете ли вы привести четкий пример того, что вы пытаетесь сделать?

Если вы просто пытаетесь добавить переменные в переданную модель представления, вы можете сделать это даже в своем контроллере, проверьте AbstractActionController.

/**
 * Action called if matched action does not exist
 *
 * @return array
 */
public function notFoundAction()
{
    $response   = $this->response;
    $event      = $this->getEvent();
    $routeMatch = $event->getRouteMatch();
    $routeMatch->setParam('action', 'not-found');

    if ($response instanceof HttpResponse) {
        return $this->createHttpNotFoundModel($response);
    }
    return $this->createConsoleNotFoundModel($response);
}

/**
 * Create an HTTP view model representing a "not found" page
 *
 * @param  HttpResponse $response
 * @return ViewModel
 */
protected function createHttpNotFoundModel(HttpResponse $response)
{
    $response->setStatusCode(404);

    // Add in extra stuff from your ServiceLocator here...

    // $viewModel->setTemplate(..); 

    return new ViewModel(array(
        'content' => 'Page not found',
    ));
}
person Andrew    schedule 16.01.2013

Первое, что нужно сделать, это создать представления:

модули/Yourrapplication/view/yourapplication/error/index.phtml

модули/Yourrapplication/view/yourapplication/error/404.phtml

Второе — прописать представления в конфиге модуля:

В module.config.php вашего приложения

'view_manager' => array(
        //[...]
        'not_found_template'       => 'error/404',
        'exception_template'       => 'error/index',
        'template_map' => array(
        //[...]
        'error/404'   => __DIR__ . '/../view/yourapplication/error/404.phtml',
        'error/index' => __DIR__ . '/../view/yourapplication/error/index.phtml',
        ),
   // [...]
    ),
person Etienne    schedule 09.07.2013

в module.php вы также можете изменить шаблон и макет.

function onBootstrap(EventInterface $e) {
  $app = $e->getApplication();
  $evt = $app->getEventManager();
  $evt->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this,'onDispatchError'), 100);    
}

function onDispatchError(MvcEvent $e) {
  $vm = $e->getViewModel();
  $vm->setTemplate('layout/blank');
}
person Saurabh Chandra Patel    schedule 25.04.2015

Или проще (где хотите):

/* @var \Zend\Mvc\View\Http\RouteNotFoundStrategy $strategy */
$strategy = $this->getServiceLocator()->get('HttpRouteNotFoundStrategy');
$strategy->setNotFoundTemplate('application/other/404');

$view = new ViewModel();
//$view->setTemplate('application/other/404');
return $view;
person B.Asselin    schedule 24.06.2016

Сначала вы должны отключить notfoundstrategy по умолчанию и в своем Module.php, а в случае ошибки 404 вы должны вернуть новую модель представления из контроллера. См. этот пост: http://www.cagataygurturk.com/zf2-controller-specific-not-found-page/

person Çağatay Gürtürk    schedule 17.04.2015