什么是 symfony 路由组件?
Symfony 路由组件是一个非常流行的路由组件,它适用于多个框架,如果您希望在 php 应用程序中设置路由,它提供了很大的灵活性。
如果您已经构建了一个定制的 PHP 应用程序并且正在寻找一个功能丰富的路由库,那么 Symfony 路由组件是最好的候选者之一。它还允许您以 YAML 格式为您的应用程序定义路由。
从安装和配置开始,我们将通过真实世界的示例来演示组件用于路由配置的各种选项。在本文中,您将学习:
Symfony 路由组件的安装和配置
如何设置基本路线
如何从 YAML 文件加载路由
创建路由作为注解:推荐的方式
安装和配置
在本节中,我们将安装在 PHP 应用程序中设置路由所需的库。我假设您已经在系统中安装了 Composer,因为我们需要它来安装 Packagist 上可用的必要库。
安装 Composer 后,继续使用以下命令安装核心路由组件。
1 | $composer require symfony/routing |
尽管 Routing 组件本身足以在您的应用程序中提供全面的路由功能,但我们将继续安装一些其他组件,以使我们的生活更轻松并丰富现有的核心路由功能。
首先,我们将继续安装 HttpFoundation 组件,它为 PHP 全局变量和响应相关函数提供了一个面向对象的包装器。它确保您不需要直接访问诸如$_GET,$_post之类的全局变量。
1 | $composer require symfony/http-foundation |
接下来,如果您想在 YAML 文件而不是 PHP 代码中定义您的应用程序路由,那么 YAML 组件可以帮助您将 YAML 字符串转换为 PHP 数组,反之亦然。
1 | $composer require symfony/yaml |
最后,我们将安装 Config 组件,它提供了几个实用程序类来初始化和处理在 YAML、INI、XML 等不同类型文件中定义的配置值。在我们的例子中,我们将使用它来加载路由来自 YAML 文件。
1 | $composer require symfony/config |
这就是安装部分,但你应该如何使用它呢?实际上,只需将 Composer 创建的autoload.php文件包含在您的应用程序中即可,如下面的代码片段所示。
<?php require_once './vendor/autoload.php'; // application code ?
设置基本路线
在上一节中,我们完成了必要路由组件的安装。现在,您可以立即在 PHP 应用程序中设置路由。
让我们继续创建具有以下内容的basic_routes.php文件。
<?php require_once './vendor/autoload.php'; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Generator\UrlGenerator; use Symfony\Component\Routing\Exception\ResourceNotFoundException; try { // Init basic route $foo_route = new Route( '/foo', array('controller' => 'FooController') ); // Init route with dynamic placeholders $foo_placeholder_route = new Route( '/foo/{id}', array('controller' => 'FooController', 'method'=>'load'), array('id' => '[0-9]+') ); // Add Route object(s) to RouteCollection object $routes = new RouteCollection(); $routes->add('foo_route', $foo_route); $routes->add('foo_placeholder_route', $foo_placeholder_route); // Init RequestContext object $context = new RequestContext(); $context->fromRequest(Request::createFromGlobals()); // Init UrlMatcher object $matcher = new UrlMatcher($routes, $context); // Find the current route $parameters = $matcher->match($context->getPathInfo()); // How to generate a SEO URL $generator = new UrlGenerator($routes, $context); $url = $generator->generate('foo_placeholder_route', array( 'id' => 123, )); echo '<pre>'; print_r($parameters); echo 'Generated URL: ' . $url; exit; } catch (ResourceNotFoundException $e) { echo $e->getMessage(); }
使用 Symfony Routing 组件设置路由通常要经过一系列步骤,如下所示。
Route为每个应用程序路由初始化 对象。
将所有Route对象添加到RouteCollection对象。
初始化RequestContext保存当前请求上下文信息的对象。
UrlMatcher通过传递RouteCollection对象和对象来初始化RequestContext对象。
为不同的路由初始化路由对象
让我们继续定义一个非常基本的foo路线。
$foo_route = new Route( '/foo', array('controller' => 'FooController') );
构造函数的第一个参数Route是 URI 路径,第二个参数是您希望在匹配此特定路由时返回的自定义属性数组。通常,它将是您希望在请求此路由时调用的控制器和方法的组合。
接下来,我们来看看参数化路由。
$foo_placeholder_route = new Route( '/foo/{id}', array('controller' => 'FooController', 'method'=>'load'), array('id' => '[0-9]+') );
上面的路由可以匹配类似foo/1,foo/123和类似的 URI。请注意,我们{id}仅将参数限制为数值,因此它不会像 URI 那样匹配,foo/bar因为{id}参数是作为字符串提供的。
将所有路由对象添加到 RouteCollection 对象
下一步是将我们在上一节中初始化的路由对象添加到RouteCollection对象中。
$routes = new RouteCollection(); $routes->add('foo_route', $foo_route); $routes->add('foo_placeholder_route', $foo_placeholder_route);
如您所见,这非常简单,您只需要使用对象的add方法RouteCollection来添加路由对象即可。该add方法的第一个参数是路由的名称,第二个参数是路由对象本身。
初始化RequestContext对象
接下来,我们需要初始化RequestContext对象,该对象保存当前的请求上下文信息。当我们初始化对象时,我们将需要这个对象,UrlMatcher因为我们稍后会介绍它。
$context = new RequestContext(); $context->fromRequest(Request::createFromGlobals());
初始化UrlMatcher对象
最后,我们需要UrlMatcher连同路由和上下文信息一起初始化对象。
1 2 | // Init UrlMatcher objec t$matcher = new UrlMatcher($routes, $context); |
现在,我们拥有了可以匹配路线的所有东西。
如何匹配路线
它是允许您将任何路由与一组预定义路由匹配match的对象的方法。UrlMatcher
该match方法将 URI 作为其第一个参数,并尝试将其与预定义的路由进行匹配。如果找到路由,它会返回与该路由关联的自定义属性。另一方面,ResourceNotFoundException如果没有与当前 URI 关联的路由,它会抛出异常。
1 | $parameters = $matcher->match($context->getPathInfo()); |
在我们的例子中,我们通过从$context对象中获取当前 URI 来提供它。因此,如果您正在访问https://your-domain/basic_routes.php/foo URL,则$context->getPathInfo()返回foo,并且我们已经为fooURI 定义了一个路由,因此它应该返回以下内容。
Array ( [controller] => FooController [_route] => foo_route )
现在,让我们继续通过访问http://your-domain/basic_routes.php/foo/123 URL 来测试参数化路由。
Array ( [controller] => FooController [method] => load [id] => 123 [_route] => foo_placeholder_route )
如果您可以看到该id参数与适当的值绑定,它就会起作用123。
接下来,让我们尝试访问一个不存在的路由,例如http://your-domain/basic_routes.php/unknown-route,您应该会看到以下消息。
1 | No routes found for "/unknown-route". |
这就是您可以使用该match方法查找路线的方式。
除此之外,您还可以使用 Routing 组件在应用程序中生成链接。提供RouteCollection和RequestContext对象,UrlGenerator允许您为特定路线建立链接。
$generator = new UrlGenerator($routes, $context); $url = $generator->generate('foo_placeholder_route', array( 'id' => 123, ));
该generate方法的第一个参数是路由名称,第二个参数是数组,如果它是参数化路由,则可以包含参数。上面的代码应该生成/basic_routes.php/foo/123 URL。
从 YAML 文件加载路由
在上一节中,我们使用 Route和RouteCollection对象构建了自定义路由。事实上,路由组件提供了不同的方式来实例化路由。您可以从各种加载程序中进行选择,例如YamlFileLoader、XmlFileLoader和PhpFileLoader.
在本节中,我们将通过YamlFileLoader加载器来了解如何从 YAML 文件中加载路由。
路由 YAML 文件
继续创建带有以下内容的routes.yaml文件。
foo_route: path: /foo controller: App\Controller\FooController::index methods: GET foo_placeholder_route: path: /foo/{id} controller: App\Controller\FooController::load methods: GET requirements: id: '[0-9]+'
示例文件
接下来,继续使用以下内容制作load_routes_from_yaml.php文件。
<?php require_once './vendor/autoload.php'; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Generator\UrlGenerator; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\Exception\ResourceNotFoundException; try { // Load routes from the yaml file $fileLocator = new FileLocator(array(__DIR__)); $loader = new YamlFileLoader($fileLocator); $routes = $loader->load('routes.yaml'); // Init RequestContext object $context = new RequestContext(); $context->fromRequest(Request::createFromGlobals()); // Init UrlMatcher object $matcher = new UrlMatcher($routes, $context); // Find the current route $parameters = $matcher->match($context->getPathInfo()); // How to generate a SEO URL $generator = new UrlGenerator($routes, $context); $url = $generator->generate('foo_placeholder_route', array( 'id' => 123, )); echo '<pre>'; print_r($parameters); echo 'Generated URL: ' . $url; exit; } catch (ResourceNotFoundException $e) { echo $e->getMessage(); }
在这种情况下,唯一不同的是我们初始化路由的方式!
$fileLocator = new FileLocator(array(__DIR__)); $loader = new YamlFileLoader($fileLocator); $routes = $loader->load('routes.yaml');
我们使用YamlFileLoader加载器从routes.yaml文件加载路由,而不是直接在 PHP 本身中初始化它。除此之外,一切都是一样的,并且应该产生与basic_routes.php文件相同的结果。
多合一路由器
在本节中,我们将学习Router该类,它允许您使用更少的代码行快速设置路由。
继续使用以下内容制作all_in_one_router.php文件。
<?php require_once './vendor/autoload.php'; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Router; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Generator\UrlGenerator; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\Exception\ResourceNotFoundException; try { $fileLocator = new FileLocator(array(__DIR__)); $requestContext = new RequestContext(); $requestContext->fromRequest(Request::createFromGlobals()); $router = new Router( new YamlFileLoader($fileLocator), 'routes.yaml', array('cache_dir' => __DIR__.'/cache'), $requestContext ); // Find the current route $parameters = $router->match($requestContext->getPathInfo()); // How to generate a SEO URL $routes = $router->getRouteCollection(); $generator = new UrlGenerator($routes, $requestContext); $url = $generator->generate('foo_placeholder_route', array( 'id' => 123, )); echo '<pre>'; print_r($parameters); echo 'Generated URL: ' . $url; exit; } catch (ResourceNotFoundException $e) { echo $e->getMessage(); }
一切都几乎相同,除了我们已经实例化了Router对象以及必要的依赖项。
$router = new Router( new YamlFileLoader($fileLocator), 'routes.yaml', array('cache_dir' => __DIR__.'/cache'), $requestContext );
有了这些,您可以直接使用matchRouter 对象的方法进行路由映射。
1 | $parameters = $router->match($requestContext->getPathInfo()); |
此外,您将需要使用getRouteCollectionRouter 对象的方法来获取路由。
1 | $routes = $router->getRouteCollection(); |
创建路由作为注解:推荐的方式
在本节中,我们将讨论如何实现基于注释的路由。它正在成为在不同框架之间定义路由的最流行的方法之一。
在我们继续实现基于注释的路由之前,我们需要安装几个包。让我们快速完成,如以下代码段所示。
$composer require symfony/framework-bundle $composer require doctrine/annotations $composer require doctrine/cache
如您所见,我们已经安装了三个不同的组件。
在您的composer.json文件中,添加以下内容:
"autoload": { "psr-4": { "App\\": "app/" } }
现在,运行以下命令。
1 | $composer dump-autoload |
现在,我们准备好准备文件了。
继续并使用以下内容创建index.php文件。
<?php use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Bundle\FrameworkBundle\Routing\AnnotatedRouteControllerLoader; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader; use Composer\Autoload\ClassLoader; use Doctrine\Common\Annotations\AnnotationRegistry; use Symfony\Component\Routing\RequestContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Matcher\UrlMatcher; /** @var ClassLoader $loader */ $loader = require __DIR__ . '/vendor/autoload.php'; AnnotationRegistry::registerLoader([$loader, 'loadClass']); $loader = new AnnotationDirectoryLoader( new FileLocator(__DIR__ . '/src/Controller/'), new AnnotatedRouteControllerLoader( new AnnotationReader() ) ); $routes = $loader->load(__DIR__ . '/src/Controller/'); $context = new RequestContext(); $context->fromRequest(Request::createFromGlobals()); $matcher = new UrlMatcher($routes, $context); $parameters = $matcher->match($context->getPathInfo()); $controllerInfo = explode('::',$parameters['_controller']); $controller = new $controllerInfo[0]; $action = $controllerInfo[1]; $controller->$action();
现在,让我们在src/Controller/FooController.php使用以下内容创建控制器文件。
<?php namespace App\Controller; use Symfony\Component\Routing\Annotation\Route; class DefaultController { /** * @Route("/",name="index") */ public function index() { echo "Index action"; } /** * @Route("/hello",name="hello") */ public function hello() { echo "Hello action"; } }
您可能已经注意到,我们以注解的形式为每个方法定义了路由。这种方法的好处是它允许您在与这些路由关联的控制器代码旁边定义路由。
继续访问https://your-domain/index.php/ URL。根据以下路由配置,它应该调用该index方法。
/** * @Route("/",name="index") */
另一方面,如果您尝试访问http://your-domain/index.php/hello URL,它应该调用控制器类的hello方法。DefaultController
这就是基于注释的路由的工作原理!
结论
继续探索路由组件中可用的其他选项。
今天,我们探索了 Symfony 路由组件,它使 PHP 应用程序中的路由实现变得轻而易举。在此过程中,我们创建了一些示例来演示路由组件的各个方面。
- 为不同的路由初始化路由对象
- 将所有路由对象添加到 RouteCollection 对象
- 初始化RequestContext对象
- 初始化UrlMatcher对象
- 如何匹配路线
- 路由 YAML 文件
- 示例文件
发表评论