Wildcard first pathame only in Lumen route - php

Is it possible to wildcard only the first pathname of a route in lumen / laravel? A type of wildcard like this would only work for routes that do not have a proceeding forward slash, for example:
The route path: /purple or /green would match the wildcard but if the route was prefixed, like /purple/green or proceeded with a forward slash, like /purple/ it would not match the wildcard route.
Currently I am using this wildcard which is matching all routes in the application and conflicting with prefixed and post routes:
$router->get('[{name}]', function () use ($router) {
return view('index');
});
From my understanding this can be achieved with Regular Expression matching in Lumen, but how I'm not sure.

Related

Is there a way to partially match a route in laravel?

I want to match every route ending with -xyz suffix to the same router.
is there a way I can achieve it in laravel?
example:
abc.com/abc-xyz
abc.com/pqr-xyz
Both routes should lead to the same controller function. The urls will be dynamically generated in the blade file, so anything with -xyz need to be redirected to the same controller.
You can use the where method to define regex to match the routes.
Route::get('{page}', function ($page) {
dd($page);
})->where('page', '[A-Z-0-9_a-z]+\-xyz');
Tested for the below samples:
asdasd-xyz
2523_ewrew65s-ad5sd4ad-xyz
123-xyz

subdomain grouping misses slash in laravel

I am trying to write a simple REST API backend that resides on
http://api.stan.test/.
Got laravel/framework:v7.21.0 and PHP:7.2.30.
Can't get the route matched.
The problem:
when I am accessing the http://api.stan.test/api/t.json URL
With api.stan.test string as domain group, my route in \Illuminate\Routing\RouteCollection::match is compared to api.stan.testapi/user alias and route is not found obviously.
With api.stan.test/ string as domain group, my route in \Illuminate\Routing\RouteCollection::match is compared against api.stan.test/api/user alias, match is found but it fails domain validation in \Illuminate\Routing\Route::matches.
preg_match($hostRegex, $request->getHost()) fails because
preg_match("{^api\.stan\.test/$}sDiu", "api.stan.test") are the values.
This is my RouteServiceProvider
# \App\Providers\RouteServiceProvider::mapApiRoutes
Route::domain('api.stan.test')
->prefix('/api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
and here is included routes file
# routes/api.php
Route::get('t.json','TController#api');
In Laravel, route parameters matching uses Symfony's Route compiler. Actually route compiler was finding dot (.) as a segment separator. This is the reason why in your case it cannot find the route.
You can do something like this :
Route::get('t_json','TController#api');

Optional trainling slash for optional slugs in POST route

I am using Symfony 4.2. When I set a route with an optional parameter, can I still use the route without a trailing slash?
api_post:
path: /api/drive/{slug?}
controller: App\Controller\Api::load
methods: POST
My problem is, that the above route works WITH a trailing slash only.
This is quite obvious, because I set this slash right after the word "drive" in the path. But how can I make the trailing slash optional too?
You can try with something like this:
api_post:
path: /api/{drive}{slug?}
controller: App\Controller\Api::load
methods: POST
requirements:
drive: "drive?"
slug: '[a-zA-Z0-9]*'
Since by default the slash character is a route parameter separator, you need to rewrite the route so that the drive is a parameter that can optionally accept / as the last character.
I've used a simple regular expression for slug, you'd need to find one that works for your use case.
This is not pretty at all, but it works.
Personally, I would simply have two different routes:
api_post_root:
path: /api/drive
controller: App\Controller\Api::load
methods: POST
api_post:
path: /api/drive/{slug?}
controller: App\Controller\Api::load
methods: POST
Easier on the eyes, easier to understand, and you could even handle it with the same controller if you really wanted.

Dynamic url issue in Laravel

Hi I have project structured in 2 parts: frontend urls and backend urls. The backend urls are like base-url/admin/pagename the frontend urls are like base-url/pagename.
I want to create some dynamic pages. The url name are came from the database.
this is my route from the web.php file:
Route::any('{slug}', 'PageController#show');
This is my controller
public function show($slug = null)
{
if('admin' != $slug){
$page = Pages::where('route', $slug)->where('active', 1);
$page = $page->firstOrFail();
return view($page->template)->with('page', $page);
}
}
Somehow I want to avoid to take into consideration every url starting with baseurl/admin/. I am wondering if I can do it from the web.php. If yes , how ?
Define all your static routes first for precedence issues. Then define your any route at the end, with some regular expressions
Route::any('{slug}', 'PageController#show')->where('slug', '^[a-zA-Z0-9-]*$');
This is telling the url to only allow alphanumeric and dashes -. So any url with a forward slash wont work.
/my-first-page-1 --> should work
/my/first/page/2 --> shouldn't work
this way you know baseurl/admin/ will never work. You can search online for more regular expressions.
try this:
Route::any('/base-url/admin/{slug}', 'SomeController#someMethod');
Route::any('{slug}', 'PageController#show');
laravel routes are matched from top to bottom and it will stop when it finds the first match, so routes defined first take precedence over those defined later, in this case, the first route will match any request for url starting with /base-url/admin/ and the second route will match everything else.
you just need to replace 'SomeController#someMethod' with the controller in charge of that functionality

Laravel route not matching pattern

In my Laravel routes/web.php file I have defined the following two routes:
Route::get('transaction/{id}', ['uses' => 'PaynlTransactionController#show'])->name('transaction.show');
Route::get('transaction/{txId}', ['uses' => 'PaynlTransactionController#showByTxId'])->name('transaction.showByTxId');
In my RouteServicesProvider I have defined the following two patterns:
Route::pattern('id', '[0-9]+');
Route::pattern('txId', '/^(TX(1[0-9]\d|[2-9]\d\d)-(1[0-9]\d\d\d\d|[2-9]\d\d\d\d\d))$/');
Whenever I go to transaction/<id> the routing works correctly, as long as id is an integer. However, when I go to transaction/TX874-152268, for example, it doesn't match any route and I receive the NotFoundHttpException in RouteCollection.php error.
I've validated the txId regex and it gives a full match: https://regex101.com/r/kDZR4L/1
My question: how come only my id pattern is working correctly, whereas my txId pattern isn't?
In the route
Route::pattern('txId', '/^(TX(1[0-9]\d|[2-9]\d\d)-(1[0-9]\d\d\d\d|[2-9]\d\d\d\d\d))$/');
I had included the forward slashes at the start and end of the string. This should not be included when passing a pattern to Route::pattern. Thus the following works:
Route::pattern('txId', '^(TX(1[0-9]\d|[2-9]\d\d)-(1[0-9]\d\d\d\d|[2-9]\d\d\d\d\d))$');
Because the urls are both /transaction/{value} it will get the last on.
If you change /transaction/{txId} to /transaction/tx/{txId} it will be clear for the routes.
Routes can only get one, so when you assign the prefix (at this time /transaction) to both of the urls it doesn't work.
You can also use /transaction/TX{txId}, in your controller you can past TX before the txId variable.
public function showByTxId($txId) {
$txid = "TX".$txid;
}
Edit:
Remove the / add the start.
Route::pattern('txId', '^(TX(1[0-9]\d|[2-9]\d\d)-(1[0-9]\d\d\d\d|[2-9]\d\d\d\d\d))$');
Hope this works!

Categories