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'. Моля помогнете.

UPD 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' ]. Вярвам, че в този случай няма да бъде създаден viewModel и ще получите NULL при $event->getResult() повикване. Както и да е, вашето предложение е по-универсално, затова поправих отговора си. Благодаря! - person zelibobla; 30.01.2015

Използвах това, за да управлявам грешка 404 (преместих уебсайта си от spip към базиран на ZF2 cms):

В модула 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, просто извикваме маршрута (в моя примерен индекс) с искания url като параметър

Надявам се това да ви помогне.

person Abdel    schedule 15.08.2013
comment
Е, търсих отговора твърде дълго. Вие, сър, получихте подкрепа от мен - person MKroeders; 06.10.2013
comment
$event-›stopPropagation(true); не спира приложението за мен :( Това е правилният отговор, но не мога да спра приложението, освен ако не използвам exit или die, което не е правилният начин - 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

Първото нещо е да създадете изгледи:

modules/Yourapplication/view/yourapplication/error/index.phtml

modules/Yourapplication/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