davidsi02's avatar

It's possible to get routes URIs and Names and show them in listboxes?

Hello,

My concrete objective is to read all routes URIs and Names so the user will be able to create menus and associate it to a route. For that I'm thinking to use two checkboxes, one for selecting the URI and other the route name since i'm using the name as "global route" to check perms in the middleware.

0 likes
12 replies
ismaile's avatar

Explanation

@davidsi02: since you are mentioning only one column, I guess you only need the URI.

I would create a command for this. The idea is to get the available routes in JSON format then insert them in the database.

Luckily, there is a command to get the available routes in a JSON format. If you only want the URIs, the command would be:

php artisan route:list --columns=URI --json

You will get an array of json objects, each having a uri. Something like:

[{"uri":"users\/{user}"},{"uri":"posts"}]

Then, you will have to loop through it and store each uri in a database table.

Step by step solution

If you don't have it, create a database table called routes with a string column called uri

Then to generate the new command, run:

php artisan make:command RouteStoreCommand

Then replace the content of RouteStoreCommand.php with the following content:

<?php

namespace App\Console\Commands;

use DB;
use Illuminate\Console\Command;
use Symfony\Component\Console\Output\BufferedOutput;

class RouteStoreCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'route:store';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Store routes in the database';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->info('Fetching routes...');
        // Output used to get the result from the route:list command
        $output = new BufferedOutput();
        $this->runCommand('route:list', [
            '--json' => 1, '--columns' => ['URI']
        ], $output);

        $routes = json_decode($output->fetch());
        $this->info('Routes fetched !');

        $this->info('Deleting existing routes...');
        DB::table('routes')->delete();
        $this->info('Routes deleted !');
        $this->info('Storing routes...');
        foreach ($routes as $route) {
            DB::table('routes')->insert(['uri' => $route->uri]);
        }
        $this->info('Routes stored !');
    }
}

Then you can execute the command by running:

php artisan route:store

Each time, you want to refresh the routes in the database, you can run this same custom command.

Please note that in this example, I delete all DB values each time the command is run. Indeed, that's the simplest way to avoid having duplication.

1 like
davidsi02's avatar

Thanks for you're help @ismaile .

Right now I've changed my mind and I dont want to save them in the DB, but I want to get all different URIs and Names to show them in separated listboxes, is it possible? All of this throught Controllers, without using the console.

laracoft's avatar

@davidsi02

$routeCollection = Route::getRoutes();
            echo "<table style='width:100%'>";
            echo "<tr>";
            echo "<td width='10%'><h4>ID</h4></td>";
            echo "<td width='10%'><h4>Name</h4></td>";
            echo "<td width='10%'><h4>HTTP Method</h4></td>";
            echo "<td width='10%'><h4>Route</h4></td>";
            echo "<td width='80%'><h4>Namespace</h4></td>";
            echo "<td width='80%'><h4>Corresponding Action</h4></td>";
            echo "</tr>";
            $index = 1;
            foreach ($routeCollection as $value) {
                echo "<tr>";
                echo "<td>" . $index . "</td>";
                echo "<td>" . $value->getAction("as") . "</td>";
                echo "<td>" . implode("|", $value->methods()) . "</td>";
                echo "<td>" . $value->getAction("domain") . "/" . $value->uri() . "</td>";
                echo "<td>" . $value->getAction("namespace") . "</td>";
                echo "<td>" . $value->getActionName() . "</td>";
                echo "</tr>";
                $index++;
            }
            echo "</table>";
1 like
martinbean's avatar

@davidsi02 You don’t need to write the routes out somewhere. You can just use the Route::getRoutes method like @laracoft says. If you write routes somewhere, they’re only going to get out of date.

davidsi02's avatar

@laracoft , thanks for you're help

I've adapted you'rw code to my needs and right now it is like this:

public function getRoutes(){
     $routes = \Route::getRoutes();

     foreach ($routes as $route){
         echo $route->uri().' - ';
         echo $route->getName().'<br>';
     }


}

Now I need to filter ehat routes will appear or not, can you give me some hint on that?

davidsi02's avatar

@martinbean , understood, I've used the Route::getRoutes and selected the route name and uri from there, bur now I need to filter the information that I recieve, any hint on that?

davidsi02's avatar
davidsi02
OP
Best Answer
Level 1

Figured out how to do it!

Thanks to everyones help!

Solution:

public function getRoutes()
{
    // call getName on each route and then get unique values
    $uniqueRoutes = collect(Route::getRoutes())
        ->map(fn($route) => $route->getName())
        ->unique();

    //filter out any routes not starting with rt_
    $filteredRoutes = $uniqueRoutes->filter(fn($name) => Str::startsWith($name, 'rt_'));
    return response()->json($filteredRoutes, 200);

}
1 like

Please or to participate in this conversation.