Skip to content

Commit

Permalink
bug #12329 [Routing] serialize the compiled route to speed things up …
Browse files Browse the repository at this point in the history
…(Tobion)

This PR was merged into the 2.3 branch.

Discussion
----------

[Routing] serialize the compiled route to speed things up

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | not really
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #12012, #12220
| License       | MIT
| Doc PR        | -

This also makes the CompiledRoute implement Serializable in order to:

1. make the serialization format shorter
2. have no null bytes in there, which the native serializer add for private properties, and thus would complicate saving in databases etc.
3.  Since the Route now includes the CompiledRoute in the serialization, the CompiledRoute serialization must be consistent as well. We can only ensure that in future symfony version by implementing Serializable.

We should add to our symfony BC promise, that only classes that implement Serializable are ensured to be deserializable correctly with serialized representations of the class in previous symfony versions.

Commits
-------

fd88de7 [Routing] serialize the compiled route to speed things up
  • Loading branch information
fabpot committed Oct 28, 2014
2 parents 20e7cf1 + fd88de7 commit 9a8ac52
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
35 changes: 34 additions & 1 deletion src/Symfony/Component/Routing/CompiledRoute.php
Expand Up @@ -16,7 +16,7 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CompiledRoute
class CompiledRoute implements \Serializable
{
private $variables;
private $tokens;
Expand Down Expand Up @@ -51,6 +51,39 @@ public function __construct($staticPrefix, $regex, array $tokens, array $pathVar
$this->variables = $variables;
}

/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize(array(
'vars' => $this->variables,
'path_prefix' => $this->staticPrefix,
'path_regex' => $this->regex,
'path_tokens' => $this->tokens,
'path_vars' => $this->pathVariables,
'host_regex' => $this->hostRegex,
'host_tokens' => $this->hostTokens,
'host_vars' => $this->hostVariables,
));
}

/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
$data = unserialize($serialized);
$this->variables = $data['vars'];
$this->staticPrefix = $data['path_prefix'];
$this->regex = $data['path_regex'];
$this->tokens = $data['path_tokens'];
$this->pathVariables = $data['path_vars'];
$this->hostRegex = $data['host_regex'];
$this->hostTokens = $data['host_tokens'];
$this->hostVariables = $data['host_vars'];
}

/**
* Returns the static prefix.
*
Expand Down
14 changes: 12 additions & 2 deletions src/Symfony/Component/Routing/Route.php
Expand Up @@ -95,6 +95,9 @@ public function __construct($path, array $defaults = array(), array $requirement
}
}

/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize(array(
Expand All @@ -105,19 +108,26 @@ public function serialize()
'options' => $this->options,
'schemes' => $this->schemes,
'methods' => $this->methods,
'compiled' => $this->compiled,
));
}

public function unserialize($data)
/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
$data = unserialize($data);
$data = unserialize($serialized);
$this->path = $data['path'];
$this->host = $data['host'];
$this->defaults = $data['defaults'];
$this->requirements = $data['requirements'];
$this->options = $data['options'];
$this->schemes = $data['schemes'];
$this->methods = $data['methods'];
if (isset($data['compiled'])) {
$this->compiled = $data['compiled'];
}
}

/**
Expand Down
37 changes: 36 additions & 1 deletion src/Symfony/Component/Routing/Tests/RouteTest.php
Expand Up @@ -212,12 +212,47 @@ public function testPattern()

public function testSerialize()
{
$route = new Route('/{foo}', array('foo' => 'default'), array('foo' => '\d+'));
$route = new Route('/prefix/{foo}', array('foo' => 'default'), array('foo' => '\d+'));

$serialized = serialize($route);
$unserialized = unserialize($serialized);

$this->assertEquals($route, $unserialized);
$this->assertNotSame($route, $unserialized);
}

/**
* Tests that the compiled version is also serialized to prevent the overhead
* of compiling it again after unserialize.
*/
public function testSerializeWhenCompiled()
{
$route = new Route('/prefix/{foo}', array('foo' => 'default'), array('foo' => '\d+'));
$route->setHost('{locale}.example.net');
$route->compile();

$serialized = serialize($route);
$unserialized = unserialize($serialized);

$this->assertEquals($route, $unserialized);
$this->assertNotSame($route, $unserialized);
}

/**
* Tests that the serialized representation of a route in one symfony version
* also works in later symfony versions, i.e. the unserialized route is in the
* same state as another, semantically equivalent, route.
*/
public function testSerializedRepresentationKeepsWorking()
{
$serialized = 'C:31:"Symfony\Component\Routing\Route":933:{a:8:{s:4:"path";s:13:"/prefix/{foo}";s:4:"host";s:20:"{locale}.example.net";s:8:"defaults";a:1:{s:3:"foo";s:7:"default";}s:12:"requirements";a:1:{s:3:"foo";s:3:"\d+";}s:7:"options";a:1:{s:14:"compiler_class";s:39:"Symfony\Component\Routing\RouteCompiler";}s:7:"schemes";a:0:{}s:7:"methods";a:0:{}s:8:"compiled";C:39:"Symfony\Component\Routing\CompiledRoute":568:{a:8:{s:4:"vars";a:2:{i:0;s:6:"locale";i:1;s:3:"foo";}s:11:"path_prefix";s:7:"/prefix";s:10:"path_regex";s:30:"#^/prefix(?:/(?P<foo>\d+))?$#s";s:11:"path_tokens";a:2:{i:0;a:4:{i:0;s:8:"variable";i:1;s:1:"/";i:2;s:3:"\d+";i:3;s:3:"foo";}i:1;a:2:{i:0;s:4:"text";i:1;s:7:"/prefix";}}s:9:"path_vars";a:1:{i:0;s:3:"foo";}s:10:"host_regex";s:38:"#^(?P<locale>[^\.]++)\.example\.net$#s";s:11:"host_tokens";a:2:{i:0;a:2:{i:0;s:4:"text";i:1;s:12:".example.net";}i:1;a:4:{i:0;s:8:"variable";i:1;s:0:"";i:2;s:7:"[^\.]++";i:3;s:6:"locale";}}s:9:"host_vars";a:1:{i:0;s:6:"locale";}}}}}';
$unserialized = unserialize($serialized);

$route = new Route('/prefix/{foo}', array('foo' => 'default'), array('foo' => '\d+'));
$route->setHost('{locale}.example.net');
$route->compile();

$this->assertEquals($route, $unserialized);
$this->assertNotSame($route, $unserialized);
}
}

0 comments on commit 9a8ac52

Please sign in to comment.