Laravel list routes in the view - php

How can I list routes specifically the api routes in my view?
For example These:
...api/user
...api/Information
The artisan command for example does list them like this:
php artisan route:list

In your controller you can get the list of routes using Artisan facade. I assume all your api routes have api string in its path.:
public function showRoutes($request) {
$routes = Artisan::call('route:list', ['--path' => 'api']);
return view('your_view', compact('routes'));
}
Edit :
You can also use Route facades getRoutes method.
$routes = [];
foreach (\Route::getRoutes()->getIterator() as $route){
if (strpos($route->uri, 'api') !== false){
$routes[] = $route->uri;
}
}
return view('your_view', compact('routes'));

Related

Getting 404 not found on adding NEW ROUTES

Everything was working fine before I installed a package https://github.com/kreait/firebase-php.
Now I get 404 error on adding new Routes.
Old Routes are working fine, but new routes are not working
Web.php
//old routes
Route::get('/', function () {
return view('welcome'); //working
});
Route::get('email', 'EmailController#sendEmail'); /working
Route::get('/counter',function() {
$counter = Redis::incr('counter'); //working
return $counter;
});
//new routes
//Firebase admin SDK
Route::get("fire","FirebaseSdkController#fire");
Route::get("say-hello", function(){
return "hello";
});
FirebaseSdkController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Kreait\Firebase;
use Kreait\Firebase\Messaging\CloudMessage;
class FirebaseSdkController extends Controller
{
public function fire()
{
$firebase = (new Firebase\Factory())->create();
$messaging = $firebase->getMessaging();
$topic = 'News';
$message = CloudMessage::withTarget('topic', $topic)
->withNotification("Hello") // optional
// ->withData($data) // optional
;
$message = CloudMessage::fromArray([
'topic' => $topic,
'notification' => [/* Notification data as array */], // optional
'data' => [/* data array */], // optional
]);
$messaging->send($message);
}
}
This is what I have tried so far -
php artisan route:list
shows the new routes in the list
php artisan route:clear
php artisan config:clear
composer dump-autoload
None of them solved the issue.
Update
Now, if I delete any route and do php artisan route:clear, I still can access the route. I don't know what's happening please help.

Laravel Validation - Rule to disallow request parameters

In my Laravel 5.8 app I have many API routes which return paginated results. If I make a request to my API appending the following query string I can disable pagination.
http://api.test/users/?no_paginate=1
My question is... how can I disable no_paginate from being used on certain routes? I'd preferbly want some validation to go in the request class but I can't find anything in the docs for that.
You can do this using a Global Middleware.
Create a DisableNoPaginate Middleware:
php artisan make:middleware DisableNoPaginate
Then define what the middleware should do (DisableNoPaginate.php):
<?php
namespace App\Http\Middleware;
use Closure;
class DisableNoPaginate
{
public function handle($request, Closure $next)
{
//remove no_paginate param from request object
unset($request['no_paginate']);
return $next($request);
}
}
Arrange for the middleware to run on all routes (routes.php):
$app->middleware([
App\Http\Middleware\DisableNoPaginate::class
]);
Now the no_paginate query param should be stripped from all your incoming requests.
For the best approach to get users either paginate or get all listing by below code in UsersController
public function index($type = null, Request $request)
{
$builder = User::where(/*query*/);
if($type == "paginate") {
$items = $builder->paginate(10);
} else {
$items = $builder->get();
}
return view("users.index", ['users' => $items]);
}
Here is the route in web.php/api.php file
Route::get('/{type?}', ['as' => 'users.index', 'uses' => 'UsersController#index']);
Here url will be
http://api.test/users/paginate // get pagination response.
http://api.test/users // get response without pagination
I think this will help you.

/posts/{id} route is blocking /posts/create in Laravel

In my ChallengesController I have these routes:
public function show($id) {
$challenge = Challenge::find($id);
if (!$challenge) {
return back()->with('error', 'Challenge does not exist');
}
$projects = $challenge->projects;
return view('challenges.show')->with(['challenge' => $challenge, 'projects' => $projects]);
}
public function create() {
if (auth()->user()->role === 'user') {
return back()->with('error', 'You are unauthorized to do that');
}
return view('challenges.create');
}
In my web.php routes I have these routes:
Route::get('/challenges/{id}', 'ChallengesController#show');
Route::get('/challenges/create', 'ChallengesController#create');
Whenever I want to go to /challenges/create it thinks I have to go to /challenges/{id} and is thinking the {id} is "create". But in my other controller where I just specified
Route::resource('projects', 'ProjectsController');
it has the same route structure when I do php artisan route:list, but it's working and my custom /challenge routes are not.
Is there a way to override the /challenges/create or am I doing something wrong. I am using Laravel version 5.7.20.
or even more simpler, change the order of declaration:
Route::get('/challenges/create', 'ChallengesController#create');
Route::get('/challenges/{id}', 'ChallengesController#show');
From Laravel documentation
You may constrain the format of your route parameters using the where
method on a route instance. The where method accepts the name of the
parameter and a regular expression defining how the parameter should
be constrained:
Route::get('challenges/{id}', function ($id) {
//
})->where('id', '[0-9]+');
Now only numeric values will be accepted as the parameter id.

Cache entire HTML response in Laravel 5

I am trying to cache entire response using middleware
Steps i followed
Generated two middleware
AfterCacheMiddleware
BeforeCacheMiddleware
With in BeforeCacheMiddleware:
public function handle($request, Closure $next)
{
$key = $request->url();
if(Cache::has($key)) return Cache::get($key);
return $next($request);
}
With in AfterCacheMiddleware
public function handle ($request, Closure $next)
{
$response = $next($request);
$key = $request->url();
if (!Cache::has($key)) Cache::put($key, $response->getContent(), 60);
return $response;
}
Registered middleware in $routeMiddleware array of kernal.php
'cacheafter' => 'App\Http\Middleware\AfterCacheMiddleware',
'cachebefore' => 'App\Http\Middleware\BeforeCacheMiddleware',
With in routes.php i am calling this dummy routes like this
Route::get('middle', ['middleware' => 'cachebefore', 'cacheafter', function()
{
echo "From route";
}]);
Issue:
only cachebefore middleware is getting called. cacheafter is not getting called at all
Can anyone suggest what i am missing here ?
I found this question while I was looking for solution myself. I am aware that there is the Flatten package which does this caching, but I couldn't find nice examples on how to do this by myself. The solution attempt in this question contains ideas that were useful for my own solution, although I chose to go with a single middleware only.
Although the question is old and asker probably doesn't need the answer anymore, I will share my solution here as I feel that SO (and internet) lacks this caching sample for Laravel 5. I will try to explain as much as I can, but for most benefit you should be familiar with Routing, Caching and Middlewaring in Laravel 5. So here goes the solution:
Middleware
Create a middleware, those are usually placed in app/Http/Middleware folder and I will call the file CachePage.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Cache;
class CachePage
{
public function handle($request, Closure $next)
{
$key = $request->fullUrl(); //key for caching/retrieving the response value
if (Cache::has($key)) //If it's cached...
return response(Cache::get($key)); //... return the value from cache and we're done.
$response = $next($request); //If it wasn't cached, execute the request and grab the response
$cachingTime = 60; //Let's cache it for 60 minutes
Cache::put($key, $response->getContent(), $cachingTime); //Cache response
return $response;
}
}
Change $key according to your needs... You have all the $request with all the parameters... Change Cache::put($key, $value, $minutes) to Cache::forever($key, $value) if you will clear the cache manually and don't want it to ever expire.
Using the URL as key for storing cache is usable in most cases, but one might think of something more appropriate for a certain project.
Registering middleware
Register it in app/Http/Kernel.php by adding the middleware to $routeMiddleware array like this:
protected $routeMiddleware = [
/* ... */
/* Other middleware that you already have there */
/* ... */
'cachepage' => \App\Http\Middleware\CachePage::class,
];
Of course, you should change \App\Http\Middleware\CachePage if you placed it elsewhere or gave it another name. Also the key name cachepage is up to you - it will be used to invoke the middleware.
Usage
In your app/Http/routes.php use the middleware just like auth or other middlewares, for example, you might make a route group for all the pages that should be cached:
Route::group(['middleware' => 'cachepage'], function ()
{
Route::get('/', 'HomeController#home');
Route::get('/contacts', 'SectionController#contacts');
});
The list of middlewares has to be inside square brackets:
Route::get('middle', ['middleware' => ['cachebefore', 'cacheafter'], function()
{
echo "From route";
}]);

Can I get current route information in middleware with Lumen?

I need to have the current found controller and action in a middleware, so that I can do some authentication. But I found it impossible, because the pipe is like Middleware1 -> Middleware2-> do the dispatching -> controller#action() -> Middleware2 -> Middleware1.
Therefore before the dispatching, I cannot get the route info. It is definitely not right to do it after the $controller->action().
I did some research and found this.
$allRoutes = $this->app->getRoutes();
$method = \Request::getMethod();
$pathInfo = \Request::getPathInfo();
$currentRoute = $allRoutes[$method.$pathInfo]['action']['uses'];
But this does not work when visiting URI like app/role/1, because $allRoutes only have index of app/role/{id} instead of app/role/1.
Is there any workaround about this?
After do some research, I got solution. Here they go:
Create Custom Dispatcher
First, you have to make your own custom dispatcher, mine is:
App\Dispatcher\GroupCountBased
Stored as:
app/Dispatcher/GroupCountBased.php
Here's the content of GroupCountBased:
<?php namespace App\Dispatcher;
use FastRoute\Dispatcher\GroupCountBased as BaseGroupCountBased;
class GroupCountBased extends BaseGroupCountBased
{
public $current;
protected function dispatchVariableRoute($routeData, $uri) {
foreach ($routeData as $data) {
if (!preg_match($data['regex'], $uri, $matches)) continue;
list($handler, $varNames) = $data['routeMap'][count($matches)];
$vars = [];
$i = 0;
foreach ($varNames as $varName) {
$vars[$varName] = $matches[++$i];
}
// HERE WE SET OUR CURRENT ROUTE INFORMATION
$this->current = [
'handler' => $handler,
'args' => $vars,
];
return [self::FOUND, $handler, $vars];
}
return [self::NOT_FOUND];
}
}
Register Your Custom Dispatcher in Laravel Container
Then, register your own custom dispatcher via singleton() method. Do this after you register all your routes! In my case, I add custom dispatcher in bootstrap/app.php after this line:
require __DIR__.'/../app/Http/routes.php';
This is what it looks like:
/*
|--------------------------------------------------------------------------
| Load The Application Routes
|--------------------------------------------------------------------------
|
| Next we will include the routes file so that they can all be added to
| the application. This will provide all of the URLs the application
| can respond to, as well as the controllers that may handle them.
|
*/
require __DIR__.'/../app/Http/routes.php';
// REGISTER YOUR CUSTOM DISPATCHER IN LARAVEL CONTAINER VIA SINGLETON METHOD
$app->singleton('dispatcher', function () use ($app) {
return FastRoute\simpleDispatcher(function ($r) use ($app) {
foreach ($app->getRoutes() as $route) {
$r->addRoute($route['method'], $route['uri'], $route['action']);
}
}, [
'dispatcher' => 'App\\Dispatcher\\GroupCountBased',
]);
});
// SET YOUR CUSTOM DISPATCHER IN APPLICATION CONTEXT
$app->setDispatcher($app['dispatcher']);
Call In Middleware (UPDATE)
NOTE: I understand it's not elegant, since dispatch called after middleware executed, you must dispatch your dispatcher manually.
In your middleware, inside your handle method, do this:
app('dispatcher')->dispatch($request->getMethod(), $request->getPathInfo());
Example:
public function handle($request, Closure $next)
{
app('dispatcher')->dispatch($request->getMethod(), $request->getPathInfo());
dd(app('dispatcher')->current);
return $next($request);
}
Usage
To get your current route:
app('dispatcher')->current;
I found the correct answer to this problem. I missed one method named routeMiddleware() of Application. This method registers the route-specific middleware which is invoked after dispatching. So Just use $app->routeMiddleware() to register you middleware. And get the matched route info by $request->route() in your middleware.
$methodName = $request->getMethod();
$pathInfo = $request->getPathInfo();
$route = app()->router->getRoutes()[$methodName . $pathInfo]['action']['uses'];
$classNameAndAction = class_basename($route);
$className = explode('#', $classNameAndAction)[0];

Categories