Skip to content

Commit 3bd4fbd

Browse files
committed
✨ Next.js like route loading
thanks @tobimori for the idea and code Signed-off-by: bnomei <[email protected]>
1 parent a1072ff commit 3bd4fbd

File tree

14 files changed

+192
-19
lines changed

14 files changed

+192
-19
lines changed

README.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Helper to automatically load various Kirby extensions in a plugin
1515
> If my work helped you to make some cash it seems fair to me that I might get a little reward as well, right?<br><br>
1616
> Be kind. Share a little. Thanks.<br><br>
1717
> &dash; Bruno<br>
18-
> &nbsp;
18+
> &nbsp;
1919
2020
| M | O | N | E | Y |
2121
|---|----|---|---|---|
@@ -46,14 +46,18 @@ The following extensions can be autoloaded:
4646
- [x] controllers (php)
4747
- [x] blockModels (php)
4848
- [x] pageModels (php)
49+
- [x] routes (php)
50+
- [x] api/routes (php)
4951
- [x] userModels (php)
5052
- [x] snippets (php)
5153
- [x] templates (php)
5254
- [X] translations (php or yml or json)
5355

54-
> NOTE: Loading translations from yaml or json files is added by this package and not originally part of kirby core.
56+
#### Notes
5557

56-
> NOTE: The `classes` autoloader is very basic. Using a custom array with kirby's `load()`-helper or composers psr-4 autoloading is recommended.
58+
- Loading translations from yaml or json files is added by this package and not originally part of kirby core.
59+
- The `classes` autoloader is very basic. Using a custom array with kirby's `load()`-helper or composers psr-4 autoloading is recommended.
60+
- The `routes` and `apiRoutes` autoloader is based on code from @tobimori and needs a file structure similar to Next.js [see examples](https://github.com/bnomei/autoloader-for-kirby/blob/main/tests/site/plugins/routastic).
5761

5862
## Usage
5963

@@ -63,6 +67,25 @@ After requiring it as a dependency in either your project or plugin `composer.js
6367
```php
6468
<?php
6569

70+
// only autoloader
71+
Kirby::plugin('bnomei/example', autoloader(__DIR__)->toArray());
72+
```
73+
74+
```php
75+
<?php
76+
77+
// merge autoloader with custom config
78+
Kirby::plugin('bnomei/example', autoloader(__DIR__)->toArray([
79+
'options' => [
80+
// options
81+
],
82+
// other extensions
83+
]));
84+
```
85+
86+
```php
87+
<?php
88+
6689
// optionally change some settings
6790
/*
6891
autoloader(__DIR__, [
@@ -76,6 +99,7 @@ autoloader(__DIR__)->classes();
7699
// use a different folder
77100
// autoloader(__DIR__)->classes('src');
78101

102+
// set each option explicitly without merging
79103
Kirby::plugin('bnomei/example', [
80104
'options' => [
81105
// options
@@ -85,6 +109,7 @@ Kirby::plugin('bnomei/example', [
85109
'controllers' => autoloader(__DIR__)->controllers(),
86110
'blockModels' => autoloader(__DIR__)->blockModels(),
87111
'pageModels' => autoloader(__DIR__)->pageModels(),
112+
'routes' => autoloader(__DIR__)->routes(),
88113
'userModels' => autoloader(__DIR__)->userModels(),
89114
'snippets' => autoloader(__DIR__)->snippets(),
90115
'templates' => autoloader(__DIR__)->templates(),

classes/Autoloader.php

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ public function __construct(array $options = [])
8080
'lowercase' => true,
8181
'map' => [],
8282
],
83+
'routes' => [
84+
'folder' => 'routes',
85+
'name' => static::ANY_PHP,
86+
'key' => 'route',
87+
'require' => true,
88+
'lowercase' => false,
89+
],
90+
'apiroutes' => [
91+
'folder' => 'api/routes',
92+
'name' => static::ANY_PHP,
93+
'key' => 'route',
94+
'require' => true,
95+
'lowercase' => false,
96+
],
8397
'usermodels' => [
8498
'folder' => 'models',
8599
'name' => static::USER_PHP,
@@ -146,7 +160,7 @@ private function registry(string $type): array
146160
$class = '';
147161
$split = explode('.', $file->getPathname());
148162
$extension = array_pop($split);
149-
if ($options['key'] === 'relativepath') {
163+
if ($options['key'] === 'relativepath' || $options['key'] === 'route') {
150164
$key = $file->getRelativePathname();
151165
$key = str_replace('.' . $extension, '', $key);
152166
$key = str_replace('\\', '/', $key); // windows
@@ -190,6 +204,24 @@ private function registry(string $type): array
190204

191205
if ($options['key'] === 'classname') {
192206
$this->registry[$type][$key] = $class;
207+
} elseif ($options['key'] === 'route') {
208+
// Author: @tobimori
209+
$pattern = strtolower($file->getRelativePathname());
210+
$pattern = preg_replace('~(.*)' . preg_quote('.php', '~') . '~', '$1' . '', $pattern, 1); // replace extension at end
211+
$pattern = preg_replace('~(.*)' . preg_quote('index', '~') . '~', '$1' . '', $pattern, 1); // replace index at end, for root of folder, but not in paths etc.
212+
213+
$route = require $file->getRealPath();
214+
215+
// check if return is actually an array (if additional stuff is specified, e.g. method or language) or returns a function
216+
if (is_array($route) || $route instanceof \Closure) {
217+
$this->registry[$type][] = array_merge(
218+
[
219+
'pattern' => /*'/' . */ $pattern,
220+
'action' => $route instanceof \Closure ? $route : null
221+
],
222+
is_array($route) ? $route : []
223+
);
224+
}
193225
} elseif ($options['require'] && $extension && strtolower($extension) === 'php') {
194226
$path = $file->getPathname();
195227
$this->registry[$type][$key] = require_once $path;
@@ -261,6 +293,16 @@ public function pageModels(): array
261293
return $this->registry('pagemodels');
262294
}
263295

296+
public function routes(): array
297+
{
298+
return $this->registry('routes');
299+
}
300+
301+
public function apiRoutes(): array
302+
{
303+
return $this->registry('apiroutes');
304+
}
305+
264306
public function userModels(): array
265307
{
266308
return $this->registry('usermodels');
@@ -281,6 +323,26 @@ public function translations(): array
281323
return $this->registry('translations');
282324
}
283325

326+
public function toArray(array $merge = []): array
327+
{
328+
$this->classes();
329+
330+
return array_merge_recursive([
331+
'blueprints' => $this->blueprints(),
332+
'collections' => $this->collections(),
333+
'controllers' => $this->controllers(),
334+
'blockModels' => $this->blockModels(),
335+
'pageModels' => $this->pageModels(),
336+
'userModels' => $this->userModels(),
337+
'snippets' => $this->snippets(),
338+
'templates' => $this->templates(),
339+
'translations' => $this->translations(),
340+
341+
'api' => ['routes' => $this->routes('api')],
342+
'routes' => $this->routes(),
343+
], $merge);
344+
}
345+
284346
public static function singleton(array $options = []): self
285347
{
286348
if (self::$singleton && self::$singleton->dir() === $options['dir']) {

composer.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "bnomei/autoloader-for-kirby",
33
"type": "project",
4-
"version": "1.5.0",
4+
"version": "1.6.0",
55
"license": "MIT",
66
"description": "Helper to automatically load various Kirby extensions in a plugin",
77
"authors": [
@@ -25,7 +25,12 @@
2525
"controllers",
2626
"snippets",
2727
"templates",
28-
"routes"
28+
"routes",
29+
"languages",
30+
"translations",
31+
"blockmodels",
32+
"pagemodels",
33+
"usermodels"
2934
],
3035
"autoload": {
3136
"psr-4": {
@@ -43,7 +48,7 @@
4348
}
4449
},
4550
"require": {
46-
"php": ">=7.3.0",
51+
"php": ">=7.4.0",
4752
"mustangostang/spyc": "^0.6.3",
4853
"symfony/finder": "^5.4"
4954
},

composer.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/AutoloaderTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function setUp(): void
1616
{
1717
$this->dir = __DIR__ . '/site/plugins/example';
1818
$this->dir2 = __DIR__ . '/site/plugins/another';
19+
$this->dir3 = __DIR__ . '/site/plugins/routastic';
1920
}
2021

2122
public function testSingleton()
@@ -134,6 +135,26 @@ public function testUserModels()
134135
$this->assertTrue(class_exists('EditorUser'));
135136
}
136137

138+
public function testRoutes()
139+
{
140+
$autoloader = autoloader($this->dir3);
141+
$routes = $autoloader->routes();
142+
143+
$this->assertIsArray($routes);
144+
$this->assertCount(3, $routes);
145+
$this->assertEquals('routastic/(:any)/register', $routes[0]['pattern']);
146+
$this->assertEquals('register', $routes[0]['action']());
147+
$this->assertEquals('routastic/(:any)/unregister', $routes[1]['pattern']);
148+
$this->assertEquals('unregister', $routes[1]['action']());
149+
$this->assertEquals('routastic', $routes[2]['pattern']);
150+
$this->assertEquals('index', $routes[2]['action']());
151+
152+
$apiRoutes = $autoloader->apiRoutes();
153+
$this->assertCount(1, $apiRoutes);
154+
$this->assertEquals('routastic/(:any)', $apiRoutes[0]['pattern']);
155+
$this->assertEquals('api.index.hello', $apiRoutes[0]['action']('hello'));
156+
}
157+
137158
public function testSnippets()
138159
{
139160
$autoloader = autoloader($this->dir);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
return [
4+
'pattern' => 'routastic/(:any)',
5+
'action' => function (string $any) {
6+
return 'api.index.' . $any;
7+
}
8+
];
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
// The following line is just necessary in this test setup.
4+
// the classes and helpers will be available from composer autoload in a production setup.
5+
@include_once __DIR__ . '/../../../vendor/autoload.php';
6+
7+
use Kirby\Cms\App as Kirby;
8+
9+
Kirby::plugin('bnomei/routastic', autoloader(__DIR__)->toArray([
10+
'options' => [
11+
'merged' => true,
12+
],
13+
'routes' => [
14+
[
15+
'pattern' => 'merged',
16+
'action' => function () {
17+
return [];
18+
},
19+
],
20+
],
21+
]));
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
return function () {
4+
return 'register';
5+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
return function () {
4+
return 'unregister';
5+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
return [
4+
'pattern' => 'routastic',
5+
'action' => function () {
6+
return 'index';
7+
}
8+
];

0 commit comments

Comments
 (0)