I'm brand new to Laravel, and I'm tinkering with it in different ways to understand how it works.
One of the first things that I've tried is to create routes dynamically by creating a routes config file that is essentially an array of views, and loop through them to create the route. It looks like this:
// Loop through the routes
foreach( config("routes.web") as $route ){
$GLOBALS["tmp_route"] = $route;
// set the path for home
$path = ($route == "home" ? '/' : $route);
Route::get( $path, function() {
return view($GLOBALS["tmp_route"]);
});
// foreach
}
I know the loop is working fine, but what I get is 'Undefined index: tmp_route'.
I'm confused as to why this isn't working? Any ideas? If I echo out the tmp_route it echos out the value, but fails at the return view(.
We don't use loops in routes usually. Actually, I've never used a loop in routes if I remember correctly. My suggestion is create a route with paramater and assign it to a controller method. e.g:
// Note that if you want a route like this, just with one parameter,
// put it to end of your other routes, otherwise it can catch other
// single hard-coded routes like Route::get('contact')
Route::get('{slug}')->uses('PageController#show')->name('pages.show');
Then in your PageController
public function show($slug) {
$view = $slug == '/'?'home':$slug;
return view($view);
}
With this, http://example.com/my-page will render views/my-page.blade.php view. As you can see I also gave him a name, pages.show. You can use route helper to create links with this helper. e.g.
echo route('pages.show','about-us'); // http://example.com/about-us
echo route('pages.show','contact'); // http://example.com/contact
In blade templates:
About Us
Please look at the documentation for more and other cool stuff
Related
I am having issues getting the page to render when using a parameter in a create controller. My show controller works but my create controller doesn't. The error thrown is a 404.
Sorry, the page you are looking for could not be found.
The URL is:
http://myapp.test/country/us/state/create
My controller looks like:
// Show
public function show(Country $country, State $state){
return view('state.show', compact('state'));
}
// Create
public function create(Country $country) {
return view('state.create', compact('country'));
}
My route looks like:
Route::get('country/{country}/state/{state}', 'StateController#show');
Route::get('country/{country}/state/create', 'StateController#create');
You need to flip your routes around to be
Route::get('country/{country}/state/create', 'StateController#create');
Route::get('country/{country}/state/{state}', 'StateController#show');
Laravel processes routes in the order that they are defined, so in your current code Laravel was seeing create as a state.
I have a PagesController with one action: view.
This action accepts a page argument.
What I want to achieve:
Have a routes example.com/about and example.com/foobar.
When one of this routes is triggered, pass a value predefined in routes file to PagesController#view.
In my routes file:
Route::get('about', function () {
return App::make('App\Http\Controllers\PagesController')->view('about');
})->name('aboutPage');
Route::get('foobar', function () {
return App::make('App\Http\Controllers\PagesController')->view('foobar');
})->name('foobarPage');
It works as expected, but I want to know is there a better and more proper way to achieve the same functionality?
Pass your pages as route parameter:
Route::get('{page}', 'PagesController#view');
//controller
public function view($page)
{
//$page is your value passed by route;
return view($page);
}
So you just want an argument to your action. You can use optional parameters if that argument can be empty. You can read more about it here.
Route::get('{argument?}', 'PagesController#view')->name('page');
And in your PagesController:
public function view($argument = 'default') {
// Your logic
}
The accepted answer is what you want based on what you are doing.
If you really wanted a hardcoded value you can use the 'actions' array part of the route if you wanted.
Route::get('something', ['uses' => 'Controller#page', 'page' => 'something']);
public function page(Request $request)
{
$page = $request->route()->getAction()['page'];
...
}
asklagbox - blog - random tips and tricks
If you don't need the names of the routes like in your example
->name('foobarPage');
you can use something like this
Route::get('{page_name}','PagesController#view')->where('page_name', '(about)|(foobar)');
This will accept only the values passed in the regular expression for the page_name parameter. Other routes will throw a 404 error. I should mention that this technique seems to be valid for applications with one level of url nesting only and should NOT be used as a pattern.
From what I can see above if all you are doing is showing the correct view I would go for
Route::get('{page}', function($page)
{
if (view()->exists($page)) {
return view($page);
}
return abort(404);
});
This prevents you even needing a method in your controller.
I want to create dynamic pages CMS for my Laravel app. Admin is allowed to provide any URI for any page, so for example, he can create page with one/two/three URI and http://example.com/one/two/three will point to this site. I already figured out it's possible to add single route for multiple level URLs like this:
get('{uri}', 'PageController#view')->where('uri', '.+');
Now, I also want to have /{username} URLs to point to users profiles. That means, if I need to make it work together. For me, the perfect code would be something like this:
get('{username}', 'ProfileController#view');
get('{uri}', 'PageController#view')->where('uri', '.+');
Then, in ProfileController I'd like to make my route go further just like it wasn't there. Something like this:
// ProfileController
public function view()
{
$user = User::whereUsername($username)->first();
if ($user === null) {
// Go to the next route.
}
}
Can it be done with Laravel?
I can think of another solution, just to have dynamic routing controller for both usernames and page uris mapping, but I would prefer to have it as separate routes.
You can resolve a new PageController instance out of the Service Container if $user is null.
// ProfileController
public function view()
{
$user = User::whereUsername($username)->first();
if ($user === null) {
// Go to the next route.
$params = []; // If your view method on the PageController has any parameters, define them here
$pageController = app(PageController::class);
return $pageController->callAction('view', $params)
}
}
This way, the {username} route will stay but will show custom content defined by the admin.
Edit:
If you don't want to call a controller manually, you could analyze the current URL segments and check for an existing user before you define your route. In order to not make your routes.php file too complex, I'd add a dedicated service class that analyzes your URL segments:
App\Services\RouteService.php:
<?php
namespace App\Services;
class RouteService {
public static function isUserRoute()
{
if(count(Request::segments()) == 1)
return !! User::whereUsername(Request::segment(1))->first();
}
return false;
}
}
routes.php:
<?php
use App\Services\RouteService;
if(RouteService::isUserRoute())
{
get('{username}', 'ProfileController#view');
}
get('{uri}', 'PageController#view')->where('uri', '.+');
I have not tested this, but it should work. Adjust the RouteService class to your needs.
I'm using the first approach in my CMS and it works realy well. The only difference is that I have written a Job that handles all incoming requests and calls the controller actions respectively.
I use :
Route::controller('home', 'HomeController');
in my routes to link all routes to my controller.
I have a getIndex() function in my controller that's executed when I go to '/home'.
I have a case where I'd like to route to '/home/slug', but not always.
I tried using getIndex($slug), but it always asks for '/home/index/{slug?}'. I don't want index to appear.
Not possible using implicit controllers, as far as the documentation goes (as it seems to enforce RESTFUL pattern).
But your can create a new route just for that:
Route::get('home/{slug}','HomeController#slugedIndex');
Route::controller('home', 'HomeController');
Edit: as pointed by Steve the controller method must come after the get method so one does not overwrite the other.
Arthur's answer was :
Route::get('home/{slug}','HomeController#slugedIndex');
Route::controller('home', 'HomeController');
Although it doesn't work, because anything written after 'home/' will now go into the first route (and HomeController#slugedIndex).
I found a workaround though. I took out the route in routes.php :
Route::controller('home', 'HomeController');
Then in my HomeController, I used the missingmethod() that's called whenever a method isn't found in the controller.
Here's the missing method :
public function missingMethod($parameters = array())
{
$sSlug = is_string($parameters) ? $parameters : '';
$oObject = Object::where('slug', $sSlug)->first();
if ($oObject) {
// slug code
}
else {
// 404 code
}
}
I'm looking for help to know which route my Codeigniter application goes through.
In my application folder in config/routes.php i got some database generated routes, could look like this:
$route["user/:any"] = "user/profile/$1";
$route["administration/:any"] = "admin/module/$1";
If i for example to go domain.net/user/MYUSERNAME, then i want to know that i get through the route "user/:any".
Is it possible to know which route it follows?
One way to know the route could be using this:
$this->uri->segment(1);
This would give you 'user' for this url:
domain.net/user/MYUSERNAME
By this way you can easily identify the route through which you have been through.
I used #Ochi's answer to come up with this.
$routes = array_reverse($this->router->routes); // All routes as specified in config/routes.php, reserved because Codeigniter matched route from last element in array to first.
foreach ($routes as $key => $val) {
$route = $key; // Current route being checked.
// Convert wildcards to RegEx
$key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key);
// Does the RegEx match?
if (preg_match('#^'.$key.'$#', $this->uri->uri_string(), $matches)) break;
}
if ( ! $route) $route = $routes['default_route']; // If the route is blank, it can only be mathcing the default route.
echo $route; // We found our route
looking at the latest version it's not possible without using custom router as ROUTEKEY is used and overwritten trying to parse the route
if you would like to create and use custom class it's only a matter of saving original $key to another variable and setting it as a class property for later use when you have a match (line 414 before "return" - you can get that key later as e.g. $this->fetch_current_route_key()) - other thing to remember is that this kind of code modification is easy to break if original class will change (update) so keep that in mind
For CodeIgniter 4:
var_dump(service('router')->getMatchedRoute());
It will return something like this:
[
"{locale}/(.*)",
"\App\Controllers\Home_controller::any/home"
];