Laravel 7 Binding Routes - php

I have this route declared on laravel:
Route::get('pages/{page}/{slug}', 'Common\Pages\CustomPageController#show')
->middleware(['web', 'prerenderIfCrawler']);
This route works fine and works if you make requests to:
https://example.com/pages/1/test-page
https://example.com/pages/2/other-page
https://example.com/pages/3/url-test
The problem is that I need a more friendly url as well as.
https://example.com/test-page
https://example.com/other-page
https://example.com/url-test
I want remove the suffix called pages, The numbers for the pages will never change and will be static for each one.
I've tried to make static routes for each one but can't get it to work.
Route::get('other-page', array('as' => 'other-page', function() {
return App::make('Common\Pages\CustomPageController')->show(2);
}))->middleware(['web', 'prerenderIfCrawler']);
I would appreciate a little help.

You could always get the URL segment in the Controller and use that to know what page you are on. If you don't want to do that you could pass extra information in the 'action' to specify the page:
Route::middleware(['web', 'prerenderIfCrawler'])->group(function () {
Route::get('test-page', [
'uses' => 'Common\Pages\CustomPageController#show',
'page' => 'test-page',
]);
...
});
Then you can get this extra information in the Controller:
public function show(Request $request)
{
$page = $request->route()->getAction('page');
...
}
If you knew all the pages you can use a route parameter with a regex constraint to restrict it to only those page names:
Route::get('{page:slug}', ...)->where('page', 'test-page|other-page|...');
public function show(Page $page)
{
...
}

You could just make use of a wildcard to catch your routes like this:
Route::get('/{slug}', 'Common\Pages\CustomPageController#show')
->middleware(['web', 'prerenderIfCrawler']);
Then in your controller:
public function show($slug)
{
$page = Page::where('slug', $slug)->first();
// ...
}
Just be careful with where you place the route. It should be at the end of your routes otherwise it will catch all the request of your app.
// ...
// my other routes
// ...
Route::get('/{slug}', ...);
By the way, if you want to bind your page models using the slug attribute do this:
Route::get('/{page:slug}', 'Common\Pages\CustomPageController#show')->//...
^^^^^^^^^
Then in your controller:
public function show(Page $page)
{ ^^^^^^^^^^
// ...
}
Check this section of the docs.

Related

Laravel empty route parameter

I have multiple routes which will directed to the same controller and method. I want the second route will have an empty customParams, but the first one will use the custom params. What should i do? Thanks
Route::get('{customParams?}/{slug}/{registrationCode}/detail', [SubmissionController::class, 'submissionDetail'])->name('submission.detail');
public function submissionDetail($customParams = '', $slug, $registrationCode)
{
//
}
First route was running perfectly
Detail
Second route did not work and produce 404 page
Detail
Make 2 routes for it, because in your case first, param is your optional.
in web.php
Route::get('{customParams?}/{slug}/{registrationCode}/detail', 'HomeController#details');
Route::get('{slug}/{registrationCode}/detail', 'HomeController#detail'); // add new route with different function name
in controller
/* your default function will call when your customParams having some value */
public function details($customParams = null, $slug, $registrationCode) {
dd($customParams, $slug, $registrationCode);
}
/* when your customParams will empty which is your 2nd case */
public function detail($slug, $registrationCode) {
$this->details(null, $slug, $registrationCode);
}
So as a result...
when URL calls with this http://127.0.0.1:8000/welcome/slug/r-code/detail
when URL calls with http://127.0.0.1:8000/slug/r-code/detail

Laravel 5.2 subdomain dynamical routes to controllers

Lets assume I have a site with cars: cars.com on Laravel 5.
I want to set up my routes.php so a user could type in a browser ford.cars.com/somethingOrnothing and get to the controller responsible for Ford™ cars (FordController).
Of course I could use something like this code:
Route::group(['middleware' => 'web'], function () {
Route::group(['domain' => 'ford.cars.com'], function(\Illuminate\Routing\Router $router) {
return $router->resource('/', 'FordController');
});
});
But I am not happy about writing and maintaining routes for hundreds of car brands.
I would like to write something like this:
Route::group(['domain' => '{brand}.cars.com'], function(\Illuminate\Routing\Router $router) {
return $router->get('/', function($brand) {
return Route::resource('/', $brand.'Controller');
});
});
So the question is: Is it possible to dynamically set routes for sub-domains and how to achieve this?
upd:
the desirable outcome is to have subdomains that completely repeat controllers structure. Like Route::controller() did (but it is now deprecated)
To emulate Route::controller() behaviour you could do this:
Route::group(['domain' => '{carbrand}.your.domain'], function () {
foreach (['get', 'post'] as $request_method) {
Route::$request_method(
'{action}/{one?}/{two?}/{three?}/{four?}',
function ($carbrand, $action, $one = null, $two = null, $three = null, $four = null) use ($request_method) {
$controller_classname = '\\App\\Http\\Controllers\\' . Str::title($carbrand).'Controller';
$action_name = $request_method . Str::title($action);
if ( ! class_exists($controller_classname) || ! method_exists($controller_classname, $action_name)) {
abort(404);
}
return App::make($controller_classname)->{$action_name}($one, $two, $three, $four);
}
);
}
});
This route group should go after all other routes, as it raises 404 Not found exception.
Probably this is what you need:
Sub-Domain Routing
Route groups may also be used to route wildcard sub-domains.
Sub-domains may be assigned route parameters just like route URIs,
allowing you to capture a portion of the sub-domain for usage in your
route or controller. The sub-domain may be specified using the domain
key on the group attribute array:
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
From:
Laravel 5.2 Documentation
upd.
If you want to call your controller method you can do it like this:
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
$controllerName = $account . 'Controller' //...or any other Controller Name resolving logic goes here
app('App\Http\Controllers\\' . $controllerName)->controllerMethod‌​($id);
});
});

Laravel 5 Route binding and Hashid

I am using Hashid to hide the id of a resource in Laravel 5.
Here is the route bind in the routes file:
Route::bind('schedule', function($value, $route)
{
$hashids = new Hashids\Hashids(env('APP_KEY'),8);
if( isset($hashids->decode($value)[0]) )
{
$id = $hashids->decode($value)[0];
return App\Schedule::findOrFail($id);
}
App::abort(404);
});
And in the model:
public function getRouteKey()
{
$hashids = new \Hashids\Hashids(env('APP_KEY'),8);
return $hashids->encode($this->getKey());
}
Now this works fine the resource displays perfectly and the ID is hashed.
BUT when I go to my create route, it 404's - if I remove App::abort(404) the create route goes to the resource 'show' view without any data...
Here is the Create route:
Route::get('schedules/create', [
'uses' => 'SchedulesController#create',
'as' => 'schedules.create'
]);
The Show route:
Route::get('schedules/{schedule}', [
'uses' => 'Schedules Controller#show',
'as' => 'schedules.show'
]);
I am also binding the model to the route:
Route::model('schedule', 'App\Schedule');
Any ideas why my create view is not showing correctly? The index view displays fine.
Turns out to solve this, I had to rearrange my crud routes.
Create needed to come before the Show route...
There's a package that does exactly what you want to do: https://github.com/balping/laravel-hashslug
Also note, that it's not a good idea to use APP_KEY as salt because it can be exposed.
Using the above package all you need to do is add a trait and typehint in controller:
class Post extends Model {
use HasHashSlug;
}
// routes/web.php
Route::resource('/posts', 'PostController');
// app/Http/Controllers/PostController.php
public function show(Post $post){
return view('post.show', compact('post'));
}

pass multiple parameters to controller from route in laravel5

I want to pass multiple parameters from route to controller in laravel5.
ie,My route is ,
Route::get('quotations/pdf/{id}/{is_print}', 'QuotationController#generatePDF');
and My controller is,
public function generatePDF($id, $is_print = false) {
$data = array(
'invoice' => Invoice::findOrFail($id),
'company' => Company::firstOrFail()
);
$html = view('pdf_view.invoice', $data)->render();
if ($is_print) {
return $this->pdf->load($html)->show();
}
$this->pdf->filename($data['invoice']->invoice_number . ".pdf");
return $this->pdf->load($html)->download();
}
If user want to download PDF, the URL will be like this,
/invoices/pdf/26
If user want to print the PDF,the URL will be like this,
/invoices/pdf/26/print or /invoices/print/26
How it is possibly in laravel5?
First, the url in your route or in your example is invalid, in one place you use quotations and in the other invoices
Usually you don't want to duplicate urls to the same action but if you really need it, you need to create extra route:
Route::get('invoices/print/{id}', 'QuotationController#generatePDF2');
and add new method in your controller
public function generatePDF2($id) {
return $this->generatePDF($id, true);
}

Passing arguments to a filter - Laravel 4

Is it possible to access route parameters within a filter?
e.g. I want to access the $agencyId parameter:
Route::group(array('prefix' => 'agency'), function()
{
# Agency Dashboard
Route::get('{agencyId}', array('as' => 'agency', 'uses' => 'Controllers\Agency\DashboardController#getIndex'));
});
I want to access this $agencyId parameter within my filter:
Route::filter('agency-auth', function()
{
// Check if the user is logged in
if ( ! Sentry::check())
{
// Store the current uri in the session
Session::put('loginRedirect', Request::url());
// Redirect to the login page
return Redirect::route('signin');
}
// this clearly does not work..? how do i do this?
$agencyId = Input::get('agencyId');
$agency = Sentry::getGroupProvider()->findById($agencyId);
// Check if the user has access to the admin page
if ( ! Sentry::getUser()->inGroup($agency))
{
// Show the insufficient permissions page
return App::abort(403);
}
});
Just for reference i call this filter in my controller as such:
class AgencyController extends AuthorizedController {
/**
* Initializer.
*
* #return void
*/
public function __construct()
{
// Apply the admin auth filter
$this->beforeFilter('agency-auth');
}
...
Input::get can only retrieve GET or POST (and so on) arguments.
To get route parameters, you have to grab Route object in your filter, like this :
Route::filter('agency-auth', function($route) { ... });
And get parameters (in your filter) :
$route->getParameter('agencyId');
(just for fun)
In your route
Route::get('{agencyId}', array('as' => 'agency', 'uses' => 'Controllers\Agency\DashboardController#getIndex'));
you can use in the parameters array 'before' => 'YOUR_FILTER' instead of detailing it in your constructor.
The method name has changed in Laravel 4.1 to parameter. For example, in a RESTful controller:
$this->beforeFilter(function($route, $request) {
$userId = $route->parameter('users');
});
Another option is to retrieve the parameter through the Route facade, which is handy when you are outside of a route:
$id = Route::input('id');

Categories