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);
Related
In my search for clean code i'm working with single action controllers in laravel. In those single action controllers i have a __invoke and a __construct. They look like this:
public function __construct()
{
$this->middleware('auth');
$this->middleware(['permission:create documents']);
}
public function __invoke($id)
{
$machine = Machine::find($id);
return view('document.create', compact('machine'));
}
And i define the create document route in the web.php file like this:
Route::get('/document/create/{id}', CreateDocument::class)->name('document.create');
Because i use single action controllers this results in a lot of routes in the web.php file and this causes a problem that its hard to find routes sometimes.
Is it possible to define the route within the __construct function of a controller instead of placing it in the web.php file? And if its possible how can i do that.
I've researched if it is possible and can't find a awnser to my question.
I don't know is StackOverflow is the best place to ask this question, if i should place it somewhere else instead of StackOverflow please let me know.
If u are having problem finding routes and you want to place your routes somewhere else rather than web.php Follow the steps
Step1:
Go to RouteServiceProvider in App\Providers
and inside there after mapApiRoutes() just define a function
public function mapCustomWebRoutes()
{
Route::middleware('web') // or any other middleware if u want to use
->namespace($this->namespace) // By default namespace is define as the
// App\Http\Controllers in the top of this file. If u want to change
// can change it
->group(base_path('routes/new_web.php')); // new_web is the name of
// another file inside routes
}
Then in the map function call this function like this
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
// calling the function
$this->mapCustomWebRoutes();
}
Now in your routes folder create a file called new_web.php
and Now you can define your routes there like this
<?php
Route::get('/something','SomethingController#something');
Hope this helps you
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
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')):
});
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);
});
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();