链路中的ZF2路由无法正常工作

时间:2017-06-16 13:35:07

标签: php zend-framework zend-framework2 config standards

我正在开发一个Zend Framework 2应用程序,我似乎无法正确路由或知道在哪里路由它。

我有一个主机名=> webapp.foo-bar.com。我们决定添加一个Subhost => / app /到最后,这个应用程序的名称叫做>应用程序。我在页面上有一个链接,它的路线会说=> /图/页名。但当我将鼠标悬停在看起来像的链接上时:

<a href="/graph/page-name">FooBar</a>

我得到webapp.foo-bar.com/graph/page-name而不是webapp.foo-bar.com/app/graph/page-name。

我的应用程序配置是:

<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/ZendSkeletonApplication for the canonical source repository
 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

return array(
    'router' => array(
        'routes' => array(
            'home' => array(
                'type' => 'hostname',
                'options' => array(
                    'route'    => 'webapp.foo-bar.com/app',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller',
                        'controller' => 'Index',
                        'action'     => 'index',
                    ),
                ),
            ),
        // The following is a route to simplify getting started creating
        // new controllers and actions without needing to create a new
        // module. Simply drop new controllers in, and you can access them
        // using the path /application/:controller/:action
        'application' => array(
            'type'    => 'Literal',
            'options' => array(
                'route'    => '/application',
                'defaults' => array(
                    '__NAMESPACE__' => 'Application\Controller',
                    'controller'    => 'Index',
                    'action'        => 'index',
                ),
            ),
            'may_terminate' => true,
            'child_routes' => array(
                'default' => array(
                    'type'    => 'Segment',
                    'options' => array(
                        'route'    => '/[:controller[/:action]]',
                        'constraints' => array(
                            'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                            'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                        ),
                        'defaults' => array(
                        ),
                    ),
                ),
            ),
        ),
    ),
),
'service_manager' => array(
    'abstract_factories' => array(
        'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
        'Zend\Log\LoggerAbstractServiceFactory',
    ),
    'aliases' => array(
        'translator' => 'MvcTranslator',
    ),
),
'translator' => array(
    'locale' => 'en_US',
    'translation_file_patterns' => array(
        array(
            'type'     => 'gettext',
            'base_dir' => __DIR__ . '/../language',
            'pattern'  => '%s.mo',
        ),
    ),
),
'controllers' => array(
    'invokables' => array(
        'Application\Controller\Index' => 'Application\Controller\IndexController'
    ),
),
'view_manager' => array(
    'display_not_found_reason' => true,
    'display_exceptions'       => true,
    'doctype'                  => 'HTML5',
    'not_found_template'       => 'error/404',
    'exception_template'       => 'error/index',
    'template_map' => array(
        'layout/layout'           => __DIR__ . '/../view/layout/layout.phtml',
        'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
        'error/404'               => __DIR__ . '/../view/error/404.phtml',
        'error/index'             => __DIR__ . '/../view/error/index.phtml',
    ),
    'template_path_stack' => array(
        __DIR__ . '/../view',
    ),
),
// Placeholder for console routes
'console' => array(
    'router' => array(
        'routes' => array(
        ),
    ),
),
);

我看到有一个选项:

<a href="<?=$this->url('application/default', array('controller' => 'graph', 'action' => 'page-name')?>">FooBar</a>

这需要在每个链接上完成,还是我们能够在配置级别完成?

谢谢!

更新

我设法让客户端使用this-&gt; url()方法,事情看起来很好。即使在jQuery部分,链接也在起作用。关于链接到另一个没有在链接中显示操作的控制器,我遇到了一个小问题。

<a href="<?php echo $this->url('foo-bar', array('action' => 'bar-foo'))?>?year=2015"</a>

带回webapp.foo-bar.com/app/foo-bar?year=2015。我希望它返回webapp.foo-bar.com/app/foo-bar/bar-foo?year=2015。这是foo-bar控制器中的配置还是可以在this-url()中完成?

万分感谢所有帮助。真的很喜欢它!

4 个答案:

答案 0 :(得分:1)

如果两个应用共享同一个域,则您的配置无效。我的配置文件版本如下。

P.S。我创建了单独的模块Sample,因此它不会干扰Application config。

use Zend\Router\Http\Literal;
use Zend\Router\Http\Segment;
use \Sample\Controller\IndexController;
use Zend\ServiceManager\Factory\InvokableFactory;


return [
    'router' => [
        'routes' => [
            'v2' => [
                'type' => Segment::class,
                'options' => [
                    'route' => '/v2/app',
                    'defaults' => [
                        'controller' => IndexController::class,
                        'action' => 'index',
                    ],
                ],
                'child_routes' => [
                    'index' => [
                        'type' => Literal::class,
                        'options' => [
                            'route' => '/',
                            'defaults' => [
                                'controller' => IndexController::class,
                                'action' => 'index',
                            ],
                        ],
                    ],
                    'application' => [
                        'type' => Segment::class,
                        'options' => [
                            'route' => '[/:action]',
                            'defaults' => [
                                'controller' => IndexController::class,
                                'action' => 'index',
                            ],
                        ],
                    ]
                ],
            ],
        ],
    ],
    'controllers' => [
        'factories' => [
            IndexController::class => InvokableFactory::class,
        ],
    ],
    'view_manager' => [
        'template_path_stack' => [
            __DIR__ . '/../view',
        ],
    ],
];

这是您创建指向该应用程序的链接的方式:

<?php echo $this->url("v2/application", ['action' => 'page-name']) ?>

答案 1 :(得分:1)

在ZF2中,路由映射到特定的控制器类及其操作或方法,因此它们可以是任何模块。例如,此路线graph/page-name可能会映射到GraphController及其方法pageNameAction()。但那可以是任何其他控制器及其动作。这取决于您的需求。

现在让我们来看一个路线的类型。 ZF中有一些路由插件。这些可用于指定路线的类型。例如,Hostname指定域名和子域名subdomain.domain.tld。但是您正在使用domain.tld/v2/appHostname类型不允许/中的'route' => 'subdomain.domain.tld'。所以在这种情况下这不起作用。

您可以在不创建线程中所述的任何子域的情况下获得此类端点(domain.tld/v2/app)。这就是为什么MVC模式,Framework更方便。您可以在ZF应用程序中为不同目的(domain.tld/v1/abc domain.tld/v2/mno domain.tld/v3/xyz等)创建大量端点。它们可以映射到不同模块的不同控制器和动作。 所以你不需要像你问的那样依赖子域名。

你还说你需要domain.tld/graph/page-name,它实际上是domain.tld/v2/app/graph/page-name。这意味着如果我没有错,你想要从网址隐藏这个部分v2/app。但这仍然是一个挑战。

如果您在此graph/page-name下使用v2/app/graph/page-name,则可以按如下方式定义路线

// Top key of a route
'v2app' => [
    'type' => 'Segment',
    'options' => [
        'route' => '/v2/app',                   
        'defaults' => [
            '__NAMESPACE__' => 'Application\Controller',
            'controller'    => 'Index',
            'action'        => 'index',
        ],
    ],
    'may_terminate' => true,
    'child_routes' => [
        'default' => [
            'type' => 'Segment',
            'options' => [
                'route' => '/',
                'defaults' => [
                    'controller' => 'Application\Controller\Index',
                    'action' => 'index',
                ],
            ],
        ],                              
        'graph' => [
            'type' => 'Segment',
            'options' => [
                'route' => '[/:controller/:action]',
                'defaults' => [
                    'controller' => 'Application\Controller\Graph',
                    'action' => 'pageName',
                ],
            ],
        ],
    ],
],

您可以通过更正模块名称,控制器名称等将其添加到任何module.config.php的任何路段部分。但请注意,多条路线的相同配置会让您不满意

现在要输出这些路线,请使用以下代码片段

echo $this->url('v2app/graph', [], [], true);
echo $this->url(null, ['controller' => 'graph', 'action' => 'page-name']);

// outputs
// /v2/app/graph/page-name

虽然v2app是您的主要路线密钥,graph是其路径。

现在您已经说过应该如何实现链接了。如果您想将它们显示为菜单,则不必像您所说的那样编写代码。你可以follow this to implement links as menu。但请记住,在为导航构建阵列时为路径键提供值(路线的顶部键)。 以下示例来自此路线graph/page-name

[
    'label' => 'Graph',
    // route name not route pattern
    'route' => 'graph', // not /graph/page-name
],

否则,如果您想在页面正文中显示链接,请使用上面使用的$this->url()帮助程序。

请参阅此DOC了解Hostname类型。

如果我们无法帮助您,请ask this here

答案 2 :(得分:1)

只需创建一个包含自己的url实现

的cutomized ViewModel
/**
 * @param  \Zend\Mvc\MvcEvent $e The MvcEvent instance
 * @return void
 */
public function setLayout($e)
{
    // Should return your customization
    $viewModel = $e->getViewModel();

在这种情况下,您的所有$this->url()将直接执行相同的操作:

$this->url('application/default', array('controller' => 'graph', 'action' => 'page-name')

作为自定义渲染的部分示例:

$customStrategy = $app->getServiceManager()->get('{Your class name}'); 
$view->getEventManager()->attach($customStrategy, 1); // 1 - means priority

在课堂内

preg_replace_callback('/<a href=\\"([^\\"]*)\\">(.*)<\\/a>/iU', function ($matches) {
    // do whatever you need for each URL
}, $content);

或者它可以使用DOM对象(但它依赖于你的代码有效性):

$xpath = new \DOMXPath((new \DOMDocument)->loadHTML($content));
foreach ($xpath->query('//a[href]') as $link) {
    // ...
}

答案 3 :(得分:0)

为此目的有一种方法。你可以试试这个。为此,您需要创建一个自定义路由插件,然后将其设置为路由指向Graph控制器及其目标方法pageNameAction(),在本例中。请按照以下步骤操作。

此处graph/page-name将作为v2/app/graph/page-name使用,这意味着以下链接可以按预期工作。

<a href="/graph/page-name">FooBar</a>

请从here获取自定义路由插件。使用命名空间src/YourModuleName/Route将其放在此YourModuleName\Route目录下。

请注意,您需要将'template_prefix' => 'yourmodulename',替换为您自己的模块名称和所有小写字母。将通过匹配场景后面的此图案yourmodulename/controller/action-name来搜索视图模板。

'v2app' => [
    'type' => 'Segment',
    'options' => [
        'route' => '[/v2/app]',             
        'defaults' => [
            'controller' => 'YourModuleName\Controller\Index',
            'action' => 'index',
        ],
    ],
    'may_terminate' => true,
    'child_routes' => [                         
        'graph' => [

            // We call the custom route plugin thus  
            'type' => 'YourModuleName\Route\AppRoute',
            'options' => [
                'dir_name'         => __DIR__ . '/../view',
                'template_prefix'  => 'yourmodulename',
                'filename_pattern' => '/[a-z0-9_\-]+/',                     
                'defaults' => [
                    'controller' => 'YourModuleName\Controller\Graph',
                    'action' => 'pageName',
                ],
            ],
        ],
    ],
],

现在将pageNameAction()格式化为以下

public function pageNameAction()
{
    // Get path to view template from route params
    $pageTemplate = $this->params()->fromRoute('page', null);

    // If path is not valid
    if($pageTemplate == null) {
        $this->getResponse()->setStatusCode(404); 
        return;
    }       

    $viewModel = new ViewModel();

    // Here we set template to be rendered for `v2/app/graph/page-name`
    $viewModel->setTemplate($pageTemplate);

    return $viewModel;
}

如果需要在视图脚本中输出链接,请使用这种方式

echo $this->serverUrl('/graph/page-name');

希望这会对你有帮助!