Skip to content

Commit

Permalink
Adding Ertuo\UnfoldedRoute
Browse files Browse the repository at this point in the history
  • Loading branch information
kktsvetkov committed Jan 4, 2022
1 parent 61cf568 commit b39da4a
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 14 deletions.
48 changes: 38 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,13 +413,8 @@ whether some details have already been collected in the result or not.
You can dump of all of the routes as array using `Route::toArray()`. This is
helpful in situations when you need to work with the whole complete set of routes.

This is used internally by the "builders". You can read more about them in the section below.

One exotic thing I used `Route::toArray()` for is a benchmark comparing reading
from a completely unfolded tree vs. progressively exploring the tree at runtime.
As you might have guessed it, runtime is faster. This was again to prove the
point that routes declaration eats up a lot of time in advance of the actual
routing process.
This is used internally by the "builders" and the unfolded routes.
You can read more about them in the section below.

# Builders

Expand Down Expand Up @@ -458,8 +453,7 @@ generators.

The generated code for the route tree looks something like this:

```
<?php
```php

use Ertuo\Route;

Expand All @@ -473,7 +467,41 @@ return $routes = Route::add('_app', [])
->rule('enum', ['en', 'de', ], [])->default('en', [])
->group(function()
{
return array( ...
return array( ... );
})
);
});
```

# Unfolded Routes

There are benefits in working with "constant" arrays when `opcache` is enabled.
The "constant" arrays are such that are only read and they are never changed.

To take advantage of this, you can use the `UnfoldedRoute` class. It stores a
fully unfolded routes tree that is a complete set of routes created from
`Route::toArray()` or other implementations of `ExportInterface`.

```php
use Ertuo\Route;
use Ertuo\UnfoldedRoute;

$unfoldedRoutesFilename = '/somewhere/where/routes/live/unfolded.php';

if (!is_file($unfoldedRoutesFilename))
{
$routes = Route::add('_locale')->rule( ... );

file_put_contents(
$unfoldedRoutesFilename,
'<?php return '
. var_export($routes->toArray(), true)
. ';'
);
}

$unfolded = include $unfoldedRoutesFilename;
$routes = UnfoldedRoute::fromArray($unfolded);
```

# A Better Example
Expand Down
72 changes: 72 additions & 0 deletions src/UnfoldedRoute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Ertuo;

use Ertuo\RouteAbstract;
use Ertuo\ExportInterface;

/**
* Route class that stores the complete unfolded tree inside it
*/
class UnfoldedRoute extends RouteAbstract implements ExportInterface
{
/**
* @var array the completely unfolded route tree
*/
protected $unfolded;

/**
* Creates a new {@link UnfoldedRoute} from $tree
*
* @param array $tree routes tree array, like the output
* from {@link ExportInterface::toArray()}
* @return self
*
* @see ExportInterface::toArray()
*/
static function fromArray(array $tree) : self
{
static $prototype;
if (!$prototype)
{
$prototype = new self;
}

// cloning is faster than instantiating,
// check Ertuo\Lab\New_vs_Clone
//
$route = clone $prototype;
$route->unfolded = $tree;

$route->key = $route->unfolded['key'];
$route->attributes = $route->unfolded['attributes'];
$route->rule = $route->unfolded['rule'];
$route->default = $route->unfolded['default'];

return $route;
}

/**
* Read a nested route identified by $step
*
* @param string $step value of current step from the source array
* @return null|RouteAbstract
*/
function readRoute(string $step) : ?RouteAbstract
{
if (empty( $this->unfolded['routes'][ $step ] ))
{
return null;
}

return static::fromArray( $this->unfolded['routes'][ $step ] );
}

/**
* @see ExportInterface::toArray()
*/
function toArray() : array
{
return $this->unfolded;
}
}
5 changes: 3 additions & 2 deletions tests/Unabridged/API_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

namespace Ertuo\Tests\Unabridged;

use Ertuo\Route;
use Ertuo\Route;
use Ertuo\RouteAbstract;

class API_Test extends Web_Test
{
function getRoutes() : Route
function getRoutes() : RouteAbstract
{
return Route::add('_app')
->rule('enum', ['api', 'admin'])->default('web')
Expand Down
3 changes: 2 additions & 1 deletion tests/Unabridged/Admin_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
namespace Ertuo\Tests\Unabridged;

use Ertuo\Route;
use Ertuo\RouteAbstract;

class Admin_Test extends Web_Test
{
function getRoutes() : Route
function getRoutes() : RouteAbstract
{
return Route::add('_app')
->rule('enum', ['admin', 'api'])
Expand Down
3 changes: 2 additions & 1 deletion tests/Unabridged/Web_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
namespace Ertuo\Tests\Unabridged;

use Ertuo\Route;
use Ertuo\RouteAbstract;
use Ertuo\Dispatcher;

use PHPUnit\Framework\TestCase;

class Web_Test extends TestCase
{
function getRoutes() : Route
function getRoutes() : RouteAbstract
{
return Route::add('_app')
->rule('enum', ['api', 'admin'])->default('web')
Expand Down
39 changes: 39 additions & 0 deletions tests/UnfoldedRouteTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Ertuo\Tests;

use Ertuo\RouteAbstract;
use Ertuo\Tests\Unabridged\Web_Test;
use Ertuo\UnfoldedRoute;
use PHPUnit\Framework\TestCase;

use function file_put_contents;
use function sys_get_temp_dir;
use function tempnam;
use function unlink;

class UnfoldedRouteTest extends Web_Test
{
function getRoutes() : RouteAbstract
{
file_put_contents(
$unfolded = tempnam(sys_get_temp_dir(), 'unfolded'),
'<?php return '
. var_export(parent::getRoutes()->toArray(), 1)
. ';'
);

$routes = UnfoldedRoute::fromArray(include $unfolded);
unlink($unfolded);

return $routes;
}

function testCompareExportedArrays()
{
$parent = parent::getRoutes()->toArray();
$unfolded = $this->getRoutes()->toArray();

$this->assertEquals($parent, $unfolded);
}
}

0 comments on commit b39da4a

Please sign in to comment.