Skip to content

Commit 843f62a

Browse files
committedFeb 19, 2022
Initial commit
0 parents  commit 843f62a

9 files changed

+414
-0
lines changed
 

‎.editorconfig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
indent_style = space
8+
indent_size = 4
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false
13+
14+
[*.{yml,yaml}]
15+
indent_size = 2

‎.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.idea
2+
.php_cs
3+
.php_cs.cache
4+
.phpunit.result.cache
5+
build
6+
composer.lock
7+
coverage
8+
docs
9+
phpunit.xml
10+
psalm.xml
11+
testbench.yaml
12+
vendor
13+
node_modules
14+
.php-cs-fixer.cache

‎LICENSE.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) Mohd Hafizuddin M Marzuki <hafizuddin_83@yahoo.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

‎README.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Laravel Route List Web
2+
3+
[![Latest Version on Packagist](https://img.shields.io/packagist/v/apih/laravel-route-list-web.svg?style=flat-square)](https://packagist.org/packages/apih/laravel-route-list-web)
4+
[![Total Downloads](https://img.shields.io/packagist/dt/apih/laravel-route-list-web.svg?style=flat-square)](https://packagist.org/packages/apih/laravel-route-list-web)
5+
[![License](https://img.shields.io/packagist/l/apih/laravel-route-list-web?style=flat-square)](https://packagist.org/packages/apih/laravel-route-list-web)
6+
7+
This package provides a way to view your Laravel app routes via a web browser.
8+
9+
![Route List Web](screenshot.png)
10+
11+
## Requirements
12+
13+
- PHP: `^8.0`
14+
- Laravel: `^8.0|^9.0`
15+
16+
## Installation
17+
18+
You can install the package via Composer:
19+
20+
```bash
21+
composer require apih/laravel-route-list-web --dev
22+
```
23+
24+
The `Apih\RouteListWeb\RouteListWebServiceProvider` class is auto-discovered and registered by default.
25+
26+
If you want to register it yourself, add the service provider in `config/app.php`:
27+
28+
```php
29+
'providers' => [
30+
/*
31+
* Package Service Providers...
32+
*/
33+
Apih\RouteListWeb\RouteListWebServiceProvider::class,
34+
],
35+
```
36+
37+
## Usage
38+
39+
To view the routes in a web browser, just open `/route:list` path. For example, if your app domain is `https://dev.test`, open `https://dev.test/route:list`.
40+
41+
## Security Vulnerabilities
42+
43+
If you discover any security related issues, please email <hafizuddin_83@yahoo.com> instead of using the issue tracker. Please prefix the subject with `Laravel Route List Web:`.
44+
45+
## Credits
46+
47+
- [Mohd Hafizuddin M Marzuki](https://github.com/apih)
48+
- [All Contributors](../../contributors)
49+
50+
## License
51+
52+
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

‎composer.json

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "apih/laravel-route-list-web",
3+
"description": "View all routes for your Laravel app via a web page in a browser",
4+
"keywords": [
5+
"apih",
6+
"php",
7+
"laravel",
8+
"route list",
9+
"gui",
10+
"browser"
11+
],
12+
"homepage": "https://github.com/apih/laravel-route-list-web",
13+
"license": "MIT",
14+
"authors": [
15+
{
16+
"name": "Mohd Hafizuddin M Marzuki",
17+
"email": "hafizuddin_83@yahoo.com",
18+
"role": "Developer"
19+
}
20+
],
21+
"require": {
22+
"php": "^8.0",
23+
"laravel/framework": "^8.0|^9.0"
24+
},
25+
"autoload": {
26+
"psr-4": {
27+
"Apih\\RouteListWeb\\": "src"
28+
}
29+
},
30+
"config": {
31+
"sort-packages": true
32+
},
33+
"extra": {
34+
"laravel": {
35+
"providers": [
36+
"Apih\\RouteListWeb\\RouteListWebServiceProvider"
37+
]
38+
}
39+
},
40+
"minimum-stability": "dev",
41+
"prefer-stable": true
42+
}

‎resources/views/index.blade.php

+209
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>Route List Web</title>
7+
8+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
9+
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500;700&display=swap" rel="stylesheet">
10+
11+
<style>
12+
[x-cloak] {
13+
display: none !important;
14+
}
15+
16+
.font-monospace {
17+
font-family: 'Roboto Mono', var(--bs-font-monospace) !important;
18+
}
19+
20+
.fw-medium {
21+
font-weight: 500;
22+
}
23+
24+
.nowrap {
25+
white-space: nowrap;
26+
}
27+
28+
.text-indigo {
29+
color: #6610f2;
30+
}
31+
32+
.text-orange {
33+
color: #fd7e14;
34+
}
35+
36+
.bg-green {
37+
background-color: #28a745;
38+
}
39+
40+
.bg-orange {
41+
background-color: #fd7e14;
42+
}
43+
</style>
44+
</head>
45+
46+
<body>
47+
<div class="container-fluid" x-data="RouteList()">
48+
<div class="row mt-3 mb-2">
49+
<div class="col-md-2">
50+
<select class="form-select" x-model="search.column">
51+
<option value="all">All</option>
52+
@foreach ($columns as $column => $label)
53+
<option value="{{ $column }}">{{ $label }}</option>
54+
@endforeach
55+
</select>
56+
</div>
57+
<div class="col-md-10">
58+
<input type="text" class="form-control" placeholder="Search here..." x-model="search.value" x-on:keydown.escape="search.value = ''">
59+
</div>
60+
</div>
61+
62+
<div class="row mb-2">
63+
<div class="col-md-10">
64+
@foreach ($columns as $column => $label)
65+
<div class="form-check form-check-inline">
66+
<input class="form-check-input" type="checkbox" id="columns.{{ $column }}" x-model="columns.{{ $column }}">
67+
<label class="form-check-label" for="columns.{{ $column }}">
68+
{{ $label }}
69+
</label>
70+
</div>
71+
@endforeach
72+
</div>
73+
<div class="col-md-2">
74+
<div class="fw-bold float-end">
75+
<span x-show="filteredCount !== routes.length" x-cloak><span x-text="filteredCount"></span> of</span> {{ $routes->count() }} routes
76+
</div>
77+
</div>
78+
</div>
79+
80+
<div class="table-responsive">
81+
<table class="table table-sm">
82+
<thead>
83+
<tr class="table-dark">
84+
<th x-show="columns.method">Method</th>
85+
<th x-show="columns.uri || columns.name" style="width: 120px">
86+
<span x-show="columns.uri">URI</span>
87+
<span x-show="columns.uri && columns.name">&amp;</span>
88+
<span x-show="columns.name">Name</span>
89+
</th>
90+
<th x-show="columns.action || columns.middleware">
91+
<span x-show="columns.action">Action</span>
92+
<span x-show="columns.action && columns.middleware">&amp;</span>
93+
<span x-show="columns.middleware">Middleware</span>
94+
</th>
95+
</tr>
96+
</thead>
97+
<tbody style="font-size: 90%">
98+
<template x-for="route in getRoutes()">
99+
<tr>
100+
<td x-show="columns.method" style="width: 120px">
101+
<template x-for="method in route.method">
102+
<span>
103+
<span class="badge" x-bind:class="getMethodColor(method)" x-text="method"></span>
104+
</span>
105+
</template>
106+
</td>
107+
<td class="font-monospace" x-show="columns.uri || columns.name">
108+
<div class="fw-medium nowrap" x-html="stylizeUri(route.domain, route.uri)" x-show="columns.uri"></div>
109+
<div x-text="route.name" x-show="columns.name"></div>
110+
</td>
111+
<td class="font-monospace" x-show="columns.action || columns.middleware">
112+
<div class="fw-medium" x-html="stylizeAction(route.action)" x-show="columns.action"></div>
113+
<template x-if="columns.middleware">
114+
<div class="small">
115+
<template x-for="item in route.middleware">
116+
<div x-text="item"></div>
117+
</template>
118+
</div>
119+
</template>
120+
</td>
121+
</tr>
122+
</template>
123+
</tbody>
124+
</table>
125+
</div>
126+
</div>
127+
128+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
129+
<script>
130+
window.RouteList = function () {
131+
return {
132+
routes: @json($routes),
133+
filteredCount: @json($routes->count()),
134+
135+
search: {
136+
column: 'all',
137+
value: '',
138+
},
139+
140+
columns: {
141+
@foreach ($columns as $column => $label)
142+
{{ $column }}: true,
143+
@endforeach
144+
},
145+
146+
getRoutes: function () {
147+
let routes = Array.from(this.routes);
148+
149+
if (this.search.value.trim().length > 0) {
150+
let filteredRoutes = [];
151+
152+
for (let i = 0; i < routes.length; i++) {
153+
const route = routes[i];
154+
let value;
155+
156+
if (this.search.column === 'all') {
157+
value = JSON.stringify(route);
158+
} else if (this.search.column === 'middleware') {
159+
value = JSON.stringify(route.middleware);
160+
} else {
161+
value = route[this.search.column];
162+
}
163+
164+
if (value !== null && value.length > 0 && value.toLowerCase().includes(this.search.value.trim().toLowerCase())) {
165+
filteredRoutes.push(route);
166+
}
167+
}
168+
169+
routes = filteredRoutes;
170+
}
171+
172+
this.filteredCount = routes.length;
173+
174+
return routes;
175+
},
176+
177+
getMethodColor: function (method) {
178+
return 'bg-' + ({
179+
get: 'green',
180+
head: 'secondary',
181+
options: 'info',
182+
post: 'primary',
183+
put: 'orange',
184+
patch: 'orange',
185+
delete: 'danger',
186+
any: 'dark',
187+
})[method.toLowerCase()];
188+
},
189+
190+
stylizeUri: function (domain, uri) {
191+
uri = (domain ? domain + '/' : '') + uri;
192+
uri = uri.replaceAll('{', '<span class="text-orange">{').replaceAll('}', '}</span>');
193+
194+
return uri;
195+
},
196+
197+
stylizeAction: function (action) {
198+
if (action.includes('@')) {
199+
action = action.replace('@', '<span class="text-primary">@') + '</span>';
200+
}
201+
202+
return action;
203+
}
204+
};
205+
};
206+
</script>
207+
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.9.0/dist/cdn.min.js" integrity="sha256-vjjhKuttMeUQkvpbjLT6aaRy4DNzz76FnPD44vKkxWk=" crossorigin="anonymous"></script>
208+
</body>
209+
</html>

‎routes/web.php

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Illuminate\Routing\Router;
4+
use Illuminate\Support\Facades\Route;
5+
6+
Route::get('route:list', function () {
7+
$router = app(Router::class);
8+
$router->flushMiddlewareGroups();
9+
10+
$routes = collect(Route::getRoutes())->map(function ($route) use ($router) {
11+
return [
12+
'domain' => $route->domain(),
13+
'method' => $route->methods(),
14+
'uri' => $route->uri(),
15+
'name' => $route->getName(),
16+
'action' => ltrim($route->getActionName(), '\\'),
17+
'middleware' => collect($router->gatherRouteMiddleware($route))->map(function ($middleware) {
18+
return $middleware instanceof Closure ? 'Closure' : $middleware;
19+
}),
20+
];
21+
})->sortBy('uri')->values();
22+
23+
$columns = [
24+
'method' => 'Method',
25+
'uri' => 'URI',
26+
'name' => 'Name',
27+
'action' => 'Action',
28+
'middleware' => 'Middleware',
29+
];
30+
31+
return view('routelistweb::index', compact('routes', 'columns'));
32+
})->name('route:list');

‎screenshot.png

47.8 KB
Loading

‎src/RouteListWebServiceProvider.php

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Apih\RouteListWeb;
4+
5+
use Illuminate\Support\ServiceProvider;
6+
7+
class RouteListWebServiceProvider extends ServiceProvider
8+
{
9+
/**
10+
* Register services.
11+
*
12+
* @return void
13+
*/
14+
public function register()
15+
{
16+
//
17+
}
18+
19+
/**
20+
* Bootstrap services.
21+
*
22+
* @return void
23+
*/
24+
public function boot()
25+
{
26+
$this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
27+
$this->loadViewsFrom(realpath(__DIR__ . '/../resources/views'), 'routelistweb');
28+
}
29+
}

0 commit comments

Comments
 (0)
Please sign in to comment.