@@ -507,10 +507,11 @@ to the ``{page}`` parameter.
507
507
| /blog/my-blog-post| blog| {page} = my-blog-post|
508
508
+--------------------+-------+-----------------------+
509
509
510
- The answer to the problem is to add route *requirements *. The routes in this
511
- example would work perfectly if the ``/blog/{page} `` path *only * matched
512
- URLs where the ``{page} `` portion is an integer. Fortunately, regular expression
513
- requirements can easily be added for each parameter. For example:
510
+ The answer to the problem is to add route *requirements * or route *conditions *
511
+ (see:ref: `book-routing-conditions `). The routes in this example would work
512
+ perfectly if the ``/blog/{page} `` path *only * matched URLs where the ``{page} ``
513
+ portion is an integer. Fortunately, regular expression requirements can easily
514
+ be added for each parameter. For example:
514
515
515
516
..configuration-block ::
516
517
@@ -717,6 +718,95 @@ You can also match on the HTTP *host* of the incoming request. For more
717
718
information, see:doc: `/components/routing/hostname_pattern ` in the Routing
718
719
component documentation.
719
720
721
+ .. _book-routing-conditions :
722
+
723
+ Completely Customized Route Matching with Conditions
724
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
725
+
726
+ ..versionadded ::2.4
727
+ Route conditions were introduced in Symfony 2.4.
728
+
729
+ As you've seen, a route can be made to match only certain routing wildcards
730
+ (via regular expressions), HTTP methods, or host names. But the routing system
731
+ can be extended to almost an infinite flexibility with ``conditions ``:
732
+
733
+ ..configuration-block ::
734
+
735
+ ..code-block ::yaml
736
+
737
+ contact :
738
+ path :/contact
739
+ defaults :{ _controller: AcmeDemoBundle:Main:contact }
740
+ condition :" context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'"
741
+
742
+ ..code-block ::xml
743
+
744
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
745
+ <routes xmlns =" http://symfony.com/schema/routing"
746
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
747
+ xsi : schemaLocation =" http://symfony.com/schema/routing
748
+ http://symfony.com/schema/routing/routing-1.0.xsd" >
749
+
750
+ <route id =" contact"
751
+ path =" /contact"
752
+ condition =" context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'"
753
+ >
754
+ <default key =" _controller" >AcmeDemoBundle:Main:contact</default >
755
+ </route >
756
+ </routes >
757
+
758
+ ..code-block ::php
759
+
760
+ use Symfony\Component\Routing\RouteCollection;
761
+ use Symfony\Component\Routing\Route;
762
+
763
+ $collection = new RouteCollection();
764
+ $collection->add('contact', new Route(
765
+ '/contact', array(
766
+ '_controller' => 'AcmeDemoBundle:Main:contact',
767
+ ),
768
+ array(),
769
+ array(),
770
+ '',
771
+ array(),
772
+ array(),
773
+ 'context.getMethod() in ["GET", "HEAD"] and request.headers.get("User-Agent") matches "/firefox/i"'
774
+ ));
775
+
776
+ return $collection;
777
+
778
+ The ``condition `` is an expression, and you can learn more about it syntax
779
+ here::doc: `/components/expression_language/syntax `. With this, the route
780
+ won't match unless the HTTP method is either GET or HEAD *and * if the ``User-Agent ``
781
+ header matches ``firefox ``.
782
+
783
+ You can do any complex logic you need here by leveraging two variables that
784
+ are passed into the expression:
785
+
786
+ * ``context ``: An instance of:class: `Symfony\\ Component\\ Routing\\ RequestContext `,
787
+ which holds the most fundamental information about the route being matched;
788
+ * ``request ``: The Symfony:class: `Symfony\\ Component\\ HttpFoundation\\ Request` `
789
+ object (see:ref: `component-http-foundation-request `).
790
+
791
+ ..caution ::
792
+
793
+ Conditions are *not * taken into account when generating a URL.
794
+
795
+ ..sidebar ::Expressions are Compiled to PHP
796
+
797
+ Behind the scenes, expressions are compiled down to raw PHP. Our example
798
+ would generate the following PHP in the cache directory::
799
+
800
+ if (rtrim($pathinfo, '/contact') === '' && (
801
+ in_array($context->getMethod(), array(0 => "GET", 1 => "HEAD"))
802
+ && preg_match("/firefox/i", $request->headers->get("User-Agent"))
803
+ )) {
804
+ // ...
805
+ }
806
+
807
+ Because of this, using the ``condition `` key causes no extra roverhead
808
+ beyond the time it takes for the underlying PHP to execute.
809
+
720
810
..index ::
721
811
single: Routing; Advanced example
722
812
single: Routing; _format parameter