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

Php 链接中的ZF2路由无法正常工作,php,zend-framework,zend-framework2,config,standards,Php,Zend Framework,Zend Framework2,Config,Standards,我正在开发一个Zend Framework 2应用程序,在这个应用程序中,我似乎无法正确路由,也不知道路由到哪里 我有一个主机名=>webapp.foo-bar.com。我们决定在末尾添加一个子标题=>/app/,该应用程序的名称为=>app。我在一个页面上有一个链接,它的路径应该是=>/graph/page name。但当我将鼠标悬停在链接上时,它看起来像: <a href="/graph/page-name">FooBar</a> 我会得到webapp.foo-

我正在开发一个Zend Framework 2应用程序,在这个应用程序中,我似乎无法正确路由,也不知道路由到哪里

我有一个主机名=>webapp.foo-bar.com。我们决定在末尾添加一个子标题=>/app/,该应用程序的名称为=>app。我在一个页面上有一个链接,它的路径应该是=>/graph/page name。但当我将鼠标悬停在链接上时,它看起来像:

<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(
        ),
    ),
),
);

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

另外,我创建了单独的模块示例,所以它不会干扰应用程序配置

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']) ?>

在ZF2中,路由映射到特定的控制器类及其操作或方法,因此它们可以是任何模块。例如,此路由
图形/页面名称
可以映射到
图形控制器
及其方法
pageNameAction()
。但这可以是任何其他控制器及其操作。这取决于你的需要

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

您可以获得这种类型的端点(
domain.tld/v2/app
),而无需创建线程中所述的任何子域。这就是为什么MVC模式、框架更方便的原因。您可以在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
。这意味着如果我没有错的话,您希望从url中隐藏此部分
v2/app
。但这仍然是一个挑战

如果在此
v2/app/graph/page name
下使用了
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
是它的子路由

现在您已经谈到了应该如何实现链接。如果您想将它们显示为菜单,则不必像您所说的那样编写代码。你可以。但请记住,在为导航构建数组时,为路由键提供值(路由的顶键)。 下面是此路由的上面示例
图形/页面名称

[
    'label' => 'Graph',
    // route name not route pattern
    'route' => 'graph', // not /graph/page-name
],
否则,如果要在页面正文中显示链接,请使用上面使用的
$this->url()
帮助程序

有关
Hostname
类型,请参阅此

如果我们无法在这里帮助您,请创建一个包含自己的
url
实现的剪辑

/**
 * @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);

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

这里的
graph/page name
将作为
v2/app/graph/page name
工作,这意味着以下链接将按照您的预期工作

<a href="/graph/page-name">FooBar</a>
现在将
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');

希望这对你有帮助

谁拥有
控制器-主主机还是子主机?你到底想要什么?图形控制器属于子标题。我想做的主要事情是能够在应用程序的更高层配置href链接,如href=“/graph/page name”(单击该链接时,我会看到webapp.foo-bar.com/graph/page name),使其与webapp.foo-bar.com/v2/app/graph/page-name类似。希望我解释得更好一点,因为$this->url()方法不需要,因为大多数链接都是硬编码的。非常感谢您的帮助@jobaer感谢akond的回答。我回去工作后再试试看。是否所有链接都使用v2/应用程序?也应该在所有模块中进行更改,还是可以将应用程序模块更改为使用完整的链接更改来正确使用v2/app?我忘了只添加一行。请看我帖子的底部。啊,很酷,谢谢!是否需要该行才能创建链接?我需要链接保持原样,因为已经有许多链接使用href=“graph/page name”格式添加,我需要保持原样。希望能更改配置以添加v2/app更改。是否可以在不接触链接的情况下执行此操作?同时感谢您的时间:)如果
graph/page name
移动到
v2/app/graph/page name
,那么我恐怕答案是否定的:您必须点击所有这些链接。很抱歉延迟!这是一个信息量很大的回答。我想试试这个,也去zend论坛看看还有什么可以做的。另一种解决方案是虚拟H
<a href="/graph/page-name">FooBar</a>
'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',
                ],
            ],
        ],
    ],
],
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');