Slyweb
На разработку сайта! Скидки 50%!

Модули и макеты. Как привязать модуль к определенному макету (layout) в Zend Framework 2!

jQuery и CSS

В Zend Framework 2 не так просто привязать к определённому макету определенный модуль. По умолчанию для всех модулей макет наследуется от предыдущих модулей, но как сделать, чтобы для каждого модуля был свой макет (шаблон). Говоря о макете, я подразумеваю шаблон HTML и ничего больше.

Предположим Вы имеете структуру из следующих модулей (глобальный конфигурационный файл "application.config.php"):

  • Код
  • Чистый код
  • Копировать в буфер
  1.<?php
  2.return array(
  3.    'modules' => array(
  4.        'Application',
  5.        'Suggest',
  6.        'Album',
  7.        'ZfcUser',
  8.        'ZfcBase',
  9.    ),
10.    'module_listener_options' => array(
11.        'config_glob_paths'    => array(
12.            'config/autoload/{,*.}{global,local}.php',
13.        ),
14.        'module_paths' => array(
15.            './module',
16.            './vendor',
17.        ),
18.
19.    )
20.
21.);
22.

        

В добавок к этому, для большей наглядности, структура моего модуля выглядит так:

  • Код
  • Чистый код
  • Копировать в буфер
  1.Suggest/
  2.    config/
  3.        module.config.php
  4.    language/
  5.    src/
  6.        Suggest/
  7.            Controller/
  8.            Form/
  9.            Model/
10.    view/
11.        layout/
12.            suggest.phtml
13.    Module.php

        

Если вы определите глобальный шаблон в модуле "Application", то все последующие модули будут его наследовать, это одна из концепций Zend Framework 2. Концепция наследования часто встречается в Zend Framework 2, например все конфигурационные файлы так же наследуются собираясь в один. Не отходя от нашей цели - как же модулю, к примеру "Suggest", использовать свой макет, а не наследовать его от предыдущего модуля? Возможно, вам интересно и Вы думаете: "зачем этому модулю свой макет (шаблон)"? Мне понадобился для того чтобы возвращать "голый" html для ajax запроса, так как насколько я понял из документации представление в Zend Framework 2 может отображаться тремя способами для шаблона php, как json и RSS. Это мне не подошло, нужен был просто пустой шаблон с html.

Я нашёл два способа:

  • с использованием Module.php(или внутри класса Module);
  • или использовать представление модуля (представление для действия контроллёра);

Рассмотрим первый способ. Файл Module.php - стандартный файл, используемый по умолчанию во всех модулях, без которого модуль не будет работать. Итак, давайте откроем этот файл, у меня он первоначально выглядел следующим образом:

  • Код
  • Чистый код
  • Копировать в буфер
  1.<?php
  2./**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link     http://github.com/zendframework/ZendSkeletonSuggest for the canonical source repository
  6. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9.
10.
11.namespace Suggest;
12.
13.use Suggest\Model\SuggestTable;
14.use Suggest\Model\SuggestAuth;
15.use Zend\Authentication\Adapter\AdapterInterface;
16.use Zend\Mvc\ModuleRouteListener;
17.
18.class Module
19.{
20.    public function onBootstrap($e)
21.    {
22.        $e->getApplication()->getServiceManager()->get('translator');
23.        $eventManager        = $e->getApplication()->getEventManager();
24.        $moduleRouteListener = new ModuleRouteListener();
25.        $moduleRouteListener->attach($eventManager);
26.
27.    }
28.
29.    public function getConfig()
30.    {
31.        return include __DIR__ . '/config/module.config.php';
32.    }
33.    
34.    public function getServiceConfig()
35.    {
36.        return array(
37.            'factories' => array(
38.                'Suggest\Model\SuggestTable' => function($sm) {
39.                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
40.                    $table = new SuggestTable($dbAdapter);
41.                    return $table;
42.                },
43.                'suggest_options' => function ($sm) {
44.                    $config = $sm->get('Config');
45.                    return new Options\ModuleOptions(isset($config['zfcuser']) ? $config['zfcuser'] : array());
46.                },
47.                'suggest_form' => function ($sm) {
48.        
49.                    $options = $sm->get('suggest_options');
50.                    $id = $options->getSuugestId();
51.
52.                    $userinfo = $sm->get('zfcuser_user_service');
53.                    $suggetions = $sm->get('zfcuser_suggesttion_data');
54.                    $zfcuser_auth_service = $sm->get('zfcuser_auth_service');
55.                    
56.                    $form = new Form\Suggest(null, $options,$userinfo,$suggetions, $zfcuser_auth_service,$id);
57.                 //$form->setCaptchaElement($sm->get('zfcuser_captcha_element'));
58.                    $form->setInputFilter(new Form\SuggestFilter(
59.                        new Validator\Doodle(array(
60.                            'mapper' => $sm->get('zfcuser_suggest_mapper'),
61.                            'key'    => 'addname'
62.                        )),
63.                        new Validator\Doodle(array(
64.                            'mapper' => $sm->get('zfcuser_suggest_mapper'),
65.                            'key'    => 'addtext'
66.                        )),
67.                        new Validator\Doodle(array(
68.                            'mapper' => $sm->get('zfcuser_suggest_mapper'),
69.                            'key'    => 'addcategory'
70.                        )),
71.                        new Validator\Doodle(array(
72.                            'mapper' => $sm->get('zfcuser_suggest_mapper'),
73.                            'key'    => 'addregion'
74.                        )),
75.                        $options
76.                    ));
77.
78.                    return $form;
79.                },
80.                
81.                'zfcuser_suggest_mapper' => function ($sm) {
82.                    $options = $sm->get('zfcuser_module_options');
83.                    $mapper = new Mapper\Suggetion();
84.                    $mapper->setDbAdapter($sm->get('zfcuser_zend_db_adapter'));
85.                    $entityClass = $options->getUserEntityClass();
86.                    $mapper->setEntityPrototype(new $entityClass);
87.                    $mapper->setHydrator(new Mapper\SuggetionHydrator());
88.                    return $mapper;
89.                },
90.            ),
91.
92.        );
93.    }
94.    public function getAutoloaderConfig()
95.    {
96.        return array(
97.            'Zend\Loader\StandardAutoloader' => array(
98.                'namespaces' => array(
99.                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
100.                ),
101.            ),
102.        );
103.    }
104.
105.}
106.
107.

        

Основное значение в этом сниппете для нас имеет метод "onBootstrap", - это событие MVC, запускаемое при первоначальной загрузке модуля, срабатывает данное событие сразу после события "loadModule.post" ("The Module Class"). Итак, в этот метод нам нужно добавить новый обработчик события с негативным приоритетом, это будет выглядеть примерно следующим образом:

  • Код
  • Чистый код
  • Копировать в буфер
  1.    public function onBootstrap($e)
  2.    {
  3.        $e->getApplication()->getServiceManager()->get('translator');
  4.        $eventManager        = $e->getApplication()->getEventManager();
  5.        $moduleRouteListener = new ModuleRouteListener();
  6.        $moduleRouteListener->attach($eventManager);
  7.        
  8.        $app = $e->getParam('application');
  9.        $app->getEventManager()->attach('dispatch', array($this, 'setLayout'), -100);
10.    }

        

Соответственно сам обработчик будет выглядеть так:

  • Код
  • Чистый код
  • Копировать в буфер
  1.    public function setLayout($e)
  2.    {
  3.    
  4.        $matches    = $e->getRouteMatch();
  5.        $controller = $matches->getParam('controller');
  6.        //var_dump($controller,__NAMESPACE__);    
  7.        if (0 !== strpos($controller, 'suggestform', 0)) {
  8.         // not a controller from this module
  9.            return;
10.        }
11.
12.     // Set the layout template
13.        $viewModel = $e->getViewModel();
14.        $viewModel->setTemplate('layout/suggest');
15.    }
16.

        

Для псевдонима контроллера "suggestform" (который в нашем случае является основным классом модуля, у меня это "Suggest\Controller\SuggestController") мы производим проверку, если это он, то для него изменяем стандартный шаблон на "suggest"(suggest.phtml), который находится в папке layout.

  • Код
  • Чистый код
  • Копировать в буфер
  1.    //Set the layout template
  2.    $viewModel = $e->getViewModel();
  3.    $viewModel->setTemplate('layout/suggest');

        

Второй способ очень прост, нужно добавить в файл представления (view) в самый вверх код:

  • Код
  • Чистый код
  • Копировать в буфер
  1.$this->layout('layout/suggest');

        

Например, мой шаблон выглядит следующим образом:

  • Код
  • Чистый код
  • Копировать в буфер
  1.<?php
  2.$this->layout('layout/suggest'); // меняем шаблон
  3.$form = $this->addsuggestform;
  4.
  5.$form->prepare();
  6.$form->setAttribute('action', $this->url('zfcuser/addsuggest'));
  7.$form->setAttribute('method', 'post');
  8.
  9.echo $this->form()->openTag($form);
10.
11.?>
12.
13.<dl class="zend_form">
14.
15.<?php foreach ($form->getElements() as $element) { ?>
16.    <?php if ($element->getLabel() != null) { ?>
17.    <dt><?php echo $this->formLabel($element); ?></dt>
18.    <?php } ?>
19.    <?php if ($element instanceof Zend\Form\Element\Captcha) { ?>
20.    <dd><?php echo $this->formCaptcha($element) . $this->formElementErrors($element); ?></dd>    
21.    <?php } else if ($element instanceof Zend\Form\Element\Textarea) { ?>
22.    <dd><?php echo $this->formTextarea($element) . $this->formElementErrors($element); ?></dd>    
23.    <?php } else if ($element instanceof Zend\Form\Element\Select) { ?>
24.    <dd><?php echo $this->formSelect($element) . $this->formElementErrors($element); ?></dd>    
25.    <?php } else { ?>
26.    <dd><?php echo $this->formInput($element) . $this->formElementErrors($element); ?></dd>
27.    <?php } ?>
28.<?php } ?>
29.
30.</dl>
31.
32.<?php if ($this->redirect): ?>
33.<input type="hidden" name="redirect" value="<?php echo $this->redirect; ?>" />
34.<?php endif; ?>
35.
36.</form>

        

Вот и всё, сейчас каждому модулю можно задать свой шаблон!


Александр Ермаков