Laravel - passing parameters from web.php routes to controller - php

I am trying to pass a parameter to my UserController but i can't seem to find a method to do this. All other topics give examples where the parameter is already defined in the url but that is not what i want.
$my_var = "some data";
Route::get('/login', 'Auth\UserController#login');
I need $my_var in my UserController
class UserController extends Controller
{
public function login()
{
// Retreive $my_var somehow
return view("login");
}
}
Sorry for my bad english, it's not my native language

In some cases using hardcoded parameters might be reasonable way to go, and one such could be case where you need to get different kinds of entities from single controller.
For an example you could have restful "users/" -route, which fetches all users from UserModel. Next you wish to separate "normal" users and admin-users by having "admin-users/" -route. Now one way to go is to represent both routes to web.php, and make them point to same controller:
Route::resource('users', 'UserController');
Route::resource('admin-users', 'UserController');
One way to solve this separation is by not passing an argument, but by detecting which route was called:
$sqlFilters['user_is_admin'] = $request->is('admin-users') || $request->is('admin-users/*');
This checks whether controller was accessed via "admin-users". Asterisk is wildcard for any route under "admin-users" path.
This method has been existing at least since Laravel 6.0, probably even before that: https://laravel.com/docs/8.x/requests#inspecting-the-request-path

You are doing it wrong. That's not how you work with an MVC framework and it's better not to define a variable or constant in web.php which is for your routes and middlewares only. By the way, if you need to do it this way, you have two ways:
1) Use a trait:
web.php:
trait TestTrait {
public static $my_var = 'some data';
}
Route::get(/login', 'Auth\UserController#login');
UserConroller.php:
use TestTrait;
class UserController extends Controller
{
use TestTrait;
public function login()
{
// You can retrieve it as a variable: $my_var
echo TestTrait::$my_var;
}
}
2) Use a constant instead of a variable:
web.php:
define('MY_VAR', 'some data');
Route::get('/login', 'Auth\UserController#login');
UserConroller.php:
public function login()
{
// You can retrieve it as a constant: MY_VAR
echo MY_VAR;
}

If the variable is hardcoded, why not state it as a constant?
If no other logic is needed, the variable can be passed through the routes file.
$my_var = "some data";
Route::get('/login', function(){
Return view('login', compact('my_var')):
});

Related

Routes inside controllers with laravel?

I have been declaring all the routes for my application inside web.php , but it is now getting quite large. I find that I am losing a lot of time shifting between web.php and each controller and this is hurting productivity.
I feel like it would be better to define routes inside of the controller, perhaps ideally delegating some URL to a controller and then allowing the controller to handle the "sub routes" since this would allow me to use inheritance when I have two similar controllers with similar routes.
It is not possible given how laravel works. Every request is passed onto router to find its designated spot viz. the controller with the method. If it fails to find the route within the router, it just throws the exception. So the request never reaches any controller if the route is not found. It was possible in earlier versions on Symphony where you would configure the route in the comment of a particular controller method.
Sadly with laravel it works how it works.
But for me, I just like to have the routes in a separate file.
Alternate solution, easier way to sort all the routes.
You can move your route registration into controllers if you use static methods for this. The code below is checked in Laravel 7
In web.php
use App\Http\Controllers\MyController;
.....
MyController::registerRoutes('myprefix');
In MyController.php
(I use here additional static methods from the ancestor controller also posted below)
use Illuminate\Support\Facades\Route;
.....
class MyController extends Controller {
......
static public function registerRoutes($prefix)
{
Route::group(['prefix' => $prefix], function () {
Route::any("/foo/{$id}", self::selfRouteName("fooAction"));
Route::resource($prefix, self::selfQualifiedPath());
}
public function fooAction($id)
{
........
}
In Controller.php
class Controller extends BaseController {
....
protected static function selfAction($actionName, $parameters = [], $absolute = false)
{
return action([static::class, $actionName], $parameters, $absolute);
}
protected static function selfQualifiedPath()
{
return "\\".static::class;
}
protected static function selfRouteName($actionName)
{
//classic string syntax return "\\".static::class."#".$actionName;
// using tuple syntax for clarity
return [static::class, $actionName];
}
}
selfAction mentioned here is not related to your question, but mentioned just because it allows making correct urls for actions either by controller itself or any class using it. This approach helps making action-related activity closer to the controller and avoiding manual url-making. I even prefer making specific functions per action, so for example for fooAction
static public function fooActionUrl($id)
{
return self::selfAction('foo', ['id' => $id]);
}
Passing prefix into registerRoutes makes controller even portable in a sense, so allows inserting it into another site with a different prefix in case of conflict

How to get a slug to controller?

I'm new in Laravel. I would like to ask, how can I find a slug in controller?
For example, my actually url is www.example.com/contact-us
I need to get a "contact-us" value in a variable in controller. Is there any simple way?
On another url, for example www.example.com/faq I need to have the value "faq" in the same variable. How can I do it? Thank you a lot
Using laravel 5.5
This is, what is in my routes file:
Route::get('/home', 'HomeController#index')->name('home');
Route::get('/podmienky-pouzitia', 'StaticController#index');
Route::get('/faq', 'StaticController#index');
Route::get('/o-projekte', 'StaticController#index');
This is, what is in my StaticController file:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\StaticModel;
class StaticController extends Controller
{
public function index($slug) {
var_dump($slug); // I need to get a variable with value of my actual slug
}
}
You can make the static page slug a parameter:
Route::get('/home', 'HomeController#index')->name('home');
Route::get('/{slug}', 'StaticController#index'); //This replaces all the individual routes
In Static controller:
public class StaticController extends Controller {
public function index($slug) {
// if the page was /faq then $slug = "faq"
}
}
However be wary that the order you declare the routes matters. Therefore you must declare all other routes before the general "catch-all" route at the end.
Instead of declaring several routes for each page/slug, you should just declare one route with a route parameter, so for example:
Route::get('/{slug}', 'StaticController#index');
In this case, the index method will receive the slug in $slug parameter, for example:
public function index($slug)
{
var_dump($slug);
}
So now, you can make requests using something like the following:
http://example.com/faq // for faq page
http://example.com/contact-us // for contact page
So, the $slug will now contain the faq/contact-us and so on. But, in this case, you'll have problem, for example, http://exampe.com/home will also similar to the dynamic route with slug so, if you declare the home route before the dynamic route (one with {slug}) then the StaticController#index will be invoked so either, you declare the dynamic route with slug under a parent namespace, for example:
Route::get('/static/{slug}', 'StaticController#index');
So, you can easily differentiate the routes or declare the dynamic route with slug parameter and add a where constraint in your route declaration if you have some predefined static pages with those slugs. Here is a somewhat similar answer, could be helpful. Also, check more about route constraints.
Update: You can also add a route constraint using something like the following:
Route::get('/{slug}', 'StaticController#index')->where('slug', 'faq|contact|something');
The above declaration will only match the following urls:
http://example.com/faq
http://example.com/contact
http://example.com/something
You can use the action() helper function to get the URL that points to a given Controller & Method.
routes.php:
Route::get('/home', 'HomeController#index')->name('home');
HomeController.php:
class HomeController extends Controller {
public function index (Request $request) {
$url = action('HomeController#index');
// $url === 'http://www.example.com/home'
// OR
$path = $request->path();
// $path === 'home';
}
}
If you use the first way, you can then use the request() helper (or the Request instance) to remove the domain from the string:
$url = str_replace(request()->root(), '', $url);

How to make Generic Route in Laravel 4

How can I make a router like this
Route::any("/{controller}/{method}/{param}", "$controller#$method");
So that instead of specifing every single method in the routes file, I would be able to define a route for most cases for the convention http://example.com/controller/method/param
In Laravel 4.2 you can use [implicit controller][1].
Laravel allows you to easily define a single route to handle every action in a controller. First, define the route using the Route::controller method:
Route::controller('users', 'UserController');
The controller method accepts two arguments. The first is the base URI the controller handles, while the second is the class name of the controller. Next, just add methods to your controller, prefixed with the HTTP verb they respond to:
class UserController extends BaseController {
public function getIndex()
{
//
}
public function postProfile()
{
//
}
}
https://laravel.com/docs/4.2/controllers#implicit-controllers
Like this:
Route::any('{controller}/{method}/{param}', function ($controller, $method, $param) {
return call_user_func_array($controller.'::'.$method, $param);
});

Access current route name in Slim3 controller's class constructor

With Slim I group my controllers and generally have an abstract BaseController I extend for each group. I use class based routing:
/* SLIM 2.0 */
// Users API - extends BaseApiController
$app->post('/users/insert/' , 'Controller\Api\UserApiController:insert');
.
.
// Campaigns - extends BaseAdminController
$app->get('/campaigns/', 'Controller\CampaignController:index')->name('campaigns');
and needed to password protect some routes, at other times I needed to have a slightly different configuration. BaseApiController, BaseAdminController... etc. There were times I needed to know which route I was in so I could execute a certain behavior for just that route. In those cases I would have a helper function like so:
/* SLIM 2.0 */
// returns the current route's name
function getRouteName()
{
return Slim\Slim::getInstance()->router()->getCurrentRoute()->getName();
}
This would give me the route name that is currently being used. So I could do something like...
namespace Controller;
abstract class BaseController
{
public function __construct()
{
/* SLIM 2.0 */
// Do not force to login page if in the following routes
if(!in_array(getRouteName(), ['login', 'register', 'sign-out']))
{
header('Location: ' . urlFor('login'));
}
}
}
I cannot find a way to access the route name being executed. I found this link
Slim 3 get current route in middleware
but I get NULL when I try
$request->getAttribute('routeInfo');
I have also tried the suggested:
'determineRouteBeforeAppMiddleware' => true
I've inspected every Slim3 object for properties and methods, I can't seem to find the equivalent for Slim3, or get access to the named route. It doesn't appear that Slim3 even keeps track of what route it executed, it just... executes it.
These are the following methods the router class has and where I suspect this value would be:
//get_class_methods($container->get('router'));
setBasePath
map
dispatch
setDispatcher
getRoutes
getNamedRoute
pushGroup
popGroup
lookupRoute
relativePathFor
pathFor
urlFor
I was hoping someone has done something similar. Sure, there are other hacky ways I could do this ( some I'm already contemplating now ) but I'd prefer using Slim to give me this data. Any Ideas?
NOTE: I'm aware you can do this with middleware, however I'm looking for a solution that will not require middleware. Something that I can use inside the class thats being instantiated by the triggered route. It was possible with Slim2, was hoping that Slim3 had a similar feature.
It's available via the request object, like this:
$request->getAttribute('route')->getName();
Some more details available here
The methods in your controller will all accept request and response as parameters - slim will pass them through for you, so for example in your insert() method:
use \Psr\Http\Message\ServerRequestInterface as request;
class UserApiController {
public function insert( request $request ) {
// handle request here, or pass it on to a getRouteName() method
}
}
After playing around I found a way to do it. It may not be the most efficient way but it works, and although it uses Middleware to accomplish this I think there are other applications for sharing data in the Middleware with controller classes.
First you create a middleware but you use a "Class:Method" string just like you would in a route. Name it whatever you like.
//Middleware to get route name
$app->add('\Middleware\RouteMiddleware:getName');
Then your middleware:
// RouteMiddleware.php
namespace Middleware;
class RouteMiddleware
{
protected $c; // container
public function __construct($c)
{
$this->c = $c; // store the instance as a property
}
public function getName($request, $response, $next)
{
// create a new property in the container to hold the route name
// for later use in ANY controller constructor being
// instantiated by the router
$this->c['currentRoute'] = $request->getAttribute('route')->getName();
return $next($request, $response);
}
}
Then in your routes you create a route with a route name, in this case I'll use "homePage" as the name
// routes.php
$app->get('/home/', 'Controller\HomeController:index')->setName('homePage');
And in your class controller
// HomeController.php
namespace Controller;
class HomeController
{
public function __construct($c)
{
$c->get('currentRoute'); // will give you "homePage"
}
}
This would allow you to do much more then just get a route name, you can also pass values from the middleware to your class constructors.
If anyone else has a better solution please share!
$app->getCurrentRoute()->getName();
$request->getAttribute('route')->getName();

Laravel4 routing to method with arguments

I just started working with Laravel after CodeIgniter and there some things that just confuse me.
I have a PagesController which takes care of displaying static pages such as about, contact, privacy etc'.
Now, instead of creating 3-4 methods on my PagesController, I would like to create one method thats called ShowPage($which) { } and knows which page to display.
The thing is > I can't understand the route issue:
Route::get('about','PagesController#ShowPage'); <--- I need to pass 'about' here
Route::get('contact','PagesController#ShowPage');
Route::get('about','PagesController#ShowPage');
Is that possible or should I need to create a method for each one of these cases?
Here is my exact code:
Controller:
class PagesController extends BaseController {
function showPage($which) {
echo $which;
}
}
Routes:
Route::get('about','PagesController#showPage');
Route::get('contact','PagesController#showPage');
Route::get('about','PagesController#showPage');`
You can access the route directly inside your controller by using
switch(Request::path()){}
which resolves to about, contact etc.
Another way to go about it would be to use
Route::get('{page}', 'PagesController#ShowPage');
which will pass the variable in the controller like
public function showPage($page){}
but be aware that this route will match any path,
if there is not another match above it.
They're already being passed down to the method:
public function ShowPage($which){
switch($which){
case 'about':
// do something
break;
case 'contact':
// do something else
break;
default:
break;
}
}
You may try this:
// In your routes.php (This route will match only this route because of "where")
Route::get('{page}','PagesController#showPage')->where('page', 'about|contact');
If you use http://example.com/about (or contact) it'll work but with other values it won't work, in other words, this route won't match without about or contact.
Then in your controller, try this:
class PagesController extends BaseController {
public function showPage($page) {
// use $page, don't use use switch, $page will be either about or contact
}
}

Categories