【问题标题】:ZF2 - Injecting pages to navigation before controller is calledZF2 - 在调用控制器之前将页面注入导航
【发布时间】:2013-05-18 08:24:13
【问题描述】:

我正在创建一个动态应用程序,其中内容是通过 CMS 添加的。在 CMS 中,我设置了一个 db 条目,用于说明每个内容页面要使用的模块。

节点ID, 父节点 ID, 名称_de, Name_en, 模块名称, foreignkey_ContentLinks,

此表中的条目如下所示: 6、 1、 Veranstaltung-21-02-2013, 事件-21-02-2013, 活动, 682

整个树应该最终出现在我的导航中(并且完美地出现在我的路由中)。我不想将它添加到某个控制器中,因为我的应用程序由一大堆模块组成,我想在我的所有模块中访问该信息。

我已经尝试在 global.php 中注入它,但无济于事,因为在那个阶段我无法使用我的数据库适配器或任何其他重要的类。

任何想法或最佳实践链接?

【问题讨论】:

    标签: zend-framework2 zend-route zend-navigation zend-config


    【解决方案1】:

    导航容器由工厂类组成。最简单的方法是编写自己的工厂并让getPages() 方法从数据库而不是从配置中获取页面。如果您从 AbstractNavigationFactory 扩展,您只需要编写几个方法。

    <?php
    namespace Application\Navigation\Service;
    
    use Zend\Navigation\Service\AbstractNavigationFactory;
    use Zend\ServiceManager\ServiceLocatorInterface;
    
    class CmsNavigationFactory extends AbstractNavigationFactory
    {
        /**
         * @param ServiceLocatorInterface $serviceLocator
         * @return array
         * @throws \Zend\Navigation\Exception\InvalidArgumentException
         */
        protected function getPages(ServiceLocatorInterface $serviceLocator)
        {
            if (null === $this->pages) {
    
                $application = $serviceLocator->get('Application');
                $routeMatch  = $application->getMvcEvent()->getRouteMatch();
                $router      = $application->getMvcEvent()->getRouter();
    
                // get your pages from wherever...
                $pages       = $this->getPagesFromDB();
    
                $this->pages = $this->injectComponents($pages, $routeMatch, $router);
            }
            return $this->pages;
        }
    
        public function getName()
        { 
             // this isn't used if fetching from db, it's just here to keep the abstract factory happy
             return 'cms';
        }
    }
    

    将工厂添加到服务管理器中,就像添加其他容器一样

    'service_manager' => array(
        'factories' => array(
            'CmsNavigation' => 'Application\Navigation\Service\CmsNavigationFactory',
        ),
    ),
    

    并以相同的方式将其与导航视图助手一起使用

    <?php echo $this->navigation()->menu('CmsNavigation'); ?>
    

    【讨论】:

    • 谢谢老兄!我假设,我以类似的方式从数据库中注入我的路由?
    • 感谢清脆!写 getPagesFromDB() 方法的正确位置在哪里?
    【解决方案2】:

    回应您对@Crisp 的回答的评论,以及对于未来的谷歌员工,我将解释如何为路由做类似的事情。

    通常您会希望创建一个自定义路由器,该路由器可以将 URL 与数据库中的页面相匹配,类似于标准的 Segment 路由器。为此,您必须实现Zend\Mvc\Router\RouteInterface 接口。例如:

    namespace Application\Router;
    
    use Zend\Mvc\Router\RouteInterface;
    use Application\Model\CMSTable;
    
    class CmsRoute implements RouteInterface, ServiceLocatorAwareInterface
    {
        protected $table;
    
        // Service locator injection code
    
        public function getCmsTable()
        {
            // Retrieve the table from the service manager
        }
    
        public function match(Request $request)
        {
            // Match the request on some route field, etc.
        }
    
        public function assemble(array $params = array(), array $options = array())
        {
            // Assemble a URL based on the given parameters (e.g. page ID).
        }
    
        public static function factory($options = array())
        {
            // Construct a new route, based on the options.
        }
    }
    

    然后您可以将此路由注册为模块配置中RoutePluginManager 的可调用对象:

    'route_manager' => array(
      'invokables' => array(
        'Cms' => 'Application\Router\CmsRoute'
      ),
    ),
    

    然后,您可以创建一个类型为Cms 的新路线(就像创建任何其他路线一样)。路由插件管理器会创建你的路由实例,并且由于CmsRoute 实现了ServiceLocatorAwareInterface,插件管理器会将自己注入到路由中。反过来,插件管理器设置了主服务管理器,这样你就可以从那里获取数据库表!

    当然,您可以在页面 ID 上进行匹配,但如果您有分层结构,最好在您的 URL 中反映这一点。因此,我建议将 route 字段添加到数据库架构并匹配它,从树根开始并向下处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多