Laravel routing: static text in optional url segment - php

I'm migrating the forum section of my website to Laravel 4. I manage the pagination myself. (Not the Laravel built-in one)
My urls currently use the following format:
example.com/forum
example.com/forum/page-1
I'd like to keep it like that after the migration.
My route looks like that:
Route::get('/forum/page-{page?}',
array('uses' => 'ForumController#showForum', 'as' => 'forum'));
But of course it doesn't work when I request the page without a page number.
I can do it like /forum/{pagetext?}-{page?} but I dont want to have to catch the pagetext parameter in my Controller, and I want to only give the $page parameter when I build urls for the page with URL::route().
I've found many examples on Internet but it was always with multiple parameters, no static optional text.
How can I make this "static" portion optional as well ?
I'm thinking to something like an optional group in a regular expression, like /forum/(page-{page})? but how do I do that in Laravel ?

If you truly need the parameter to be optional, I would make the whole segment of that route a single parameter, and you can use a regular expression to enforce it:
Route::get('/forum/{page?}', function($page = null) {
echo 'On page ' . $page;
})->where('page', 'page-[\d]+');
The drawback here is you'll have to get the numeric page number from within your route.
As #Jarek mentioned in the comments, you can also split this up into two different routes:
Route::get('/forum', function() {
echo 'Forum Index';
});
Route::get('/forum/page-{page}', function($page) {
echo 'On page ' . $page;
})->where('page', '[\d]+');

Related

How to use optional route parameters properly with Laravel 5.6?

I am trying to create an API with Laravel 5.6, however, it seems to me that it's not possible to use optional route parameters before/after the parameter.
I'd like to achieve the following:
Route::get('api/lists/{id?}/items',
[
'as' => 'api/lists/items/get',
'uses' => 'ListsController#getListItems'
]);
With the above scenario, if I'm trying to visit api/lists/1/items it shows the page. On the other hand, if I'm trying to visit api/lists/items it says that the page is not found.
What I basically want is if there's no List ID specified, Laravel should fetch all the List ID's items, otherwise it should only fetch the specific ID's items.
Q: How is it possible to the optional parameter in between the 'route words'? Is it even possible? Or is there an alternative solution to this?
As far as I know, it's not possible to use optional parameters in the middle of your url.
You could try a workaround by allowing 0 for the optional parameter and loading all items in this case, as described here.
However, I'd recommend going with two different routes here to match everything you want:
api/lists/items
api/lists/{id?}/items
You have to give default value for optional parameter in the controller:
Route
Route::get('api/lists/{id?}/items', 'ListsController#getListItems');
ListsController
public function getListItems($id = null) {
---your code----
}
Reference

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

Generating language changing urls in laravel

I have decided to prefix all my routes with a $locale-variable. This is code found from googling:
$locale = Request::segment(1);
if (in_array($locale, Config::get('app.available_locales'))) {
App::setLocale($locale);
} else {
$locale = null;
}
Route::group(array('prefix' => $locale), function() {
//All my routes
});
Now, I would like to generate URL:s dynamically for jumping between locales. I want a way to generate the current url or route, but replace the $locale-parameter. You should be able to write something similar to this pseudocode:
route(Route::Current(), [$locale => 'foo'])
Question:
I want to take my current URL and replace one argument in it. How do I do that?
Update 1:
Giving my route a name, I'm able to do this:
route('index', 'foo') //Gives mywebsite.com?foo
This however, does not produce the wanted result, mywebsite.com/foo. It instead generates mywebsite.com?foo. My guess is that route doesn't understand that this route is nested and prefixed with a fragment, so it treats my argument as a parameter instead. Specifying that it is the locale I want to change does not help:
route('index', ['locale' => 'foo']) //Gives mywebsite.com?locale=foo
Update 2:
Changing the prefix to instead say:
Route::group(array('prefix' => '{locale?}'), function() {
Makes route() work:
route('index', ['locale' => 'foo']) //Gives mywebsite.com/foo
It does however ruin some url:s inside the group, as some of them start with variables. The following route inside the route-group stops working:
Route::get('/{id}', 'FooController#showFoo');
As routes.php interprets the url mywebsite.com/foo as 'foo' now being the language. If there is some way to set a default value in routes.php for locale so that you could write it as {route} instead of {route?} and have it redirect to a default locale if it was missing, the problem would be solved.
Update 3:
Moving in the direction of having 'prefix' => '{locale?}' instead leads into way too many sub-problems to be worth pursuing. The issue comes back to generating urls from the current url but inserting language into the url. I am currently considering doing this with just a regex replacement because it is the most straight-forward solution.
I didn't test this, but you could try to do it like this way.
If no parameter is given, you can easily redirect to the default locale route. If first parameter is given, you need to check if it's a correct locale.
use Illuminate\Support\Facades\Request;
$defaultLocale = 'en';
Route::get('/', function() use ($defaultLocale) {
return redirect('/' . $defaultLocale);
});
Route::group(array('prefix' => '{locale}'), function($locale) use ($defaultLocale) {
if(!in_array($locale, Config::get('app.available_locales'))) {
return redirect('/' . $defaultLocale . '/' . Request::path());
}
// All your routes
});
So I ended up not solving this with laravel magic, I wrote my own code.
The Route::Group remains the same, the code I use to create URL:s to different languages looks like this:
<a href="{{ change_locale_url('en') }}"</a>
The change_locale_url-function is just a regex function which uses URL::Current to get the current url and then either inserts or replaces the input string as a language parameter in the url.
When I'm on mywebsite.com/about, the function outputs mywebsite.com/en/about
When I'm on www.mywebsite.com/de/about, the function outputs www.mywebsite.com/en/about
When I'm on http://mywebsite.com, the function outputs http://mywebsite.com/en
As a reminder, when using this route group you need to create links using action('HomeController#index') to have the locale follow you to the next link. Linking to /about will remove any language currently selected.

How to route the URI with parameters to a method in codeigniter?

I don't know much about the routing concept in codeigniter, I want to pass many parameters to a single method as explained in this http://www.codeigniter.com/userguide2/general/controllers.html tutorial page.
In the url I have this
http://localhost/code_igniter/products/display/2/3/4
In my routes.php I have written
$route['products/display/(:any)'] = 'Products_controller/display';
What I thought is it will pass all the parameters (here 2/3/4) to the method 'display' automatically but I am getting 404 page not found error.
In general I want to achieve something like, if the URI is controller/method I want to route to someother_controller/its_method and pass the parameters if any to that method. How can I do it?
In CI 3.x the (:any) parameter matches only a single URI segment. So for example:
$route['method/(:any)/(:any)'] = 'controller/method/$1/$2';
will match exactly two segments and pass them appropriately. If you want to match 1 or 2 you can do this (in order):
$route['method/(:any)/(:any)'] = 'controller/method/$1/$2';
$route['method/(:any)'] = 'controller/method/$1';
You can pass multiple segments with the (.+) parameter like this:
$route['method/(.+)'] = 'controller/method/$1';
In that case the $1 will contain everything past method/. In general I think its discouraged to use this since you should know what is being passed and handle it appropriately but there are times (.+) comes in handy. For example if you don't know how many parameters are being passed this will allow you to capture all of them. Also remember, you can set default parameters in your methods like this:
public function method($param=''){}
So that if nothing is passed, you still have a valid value.
You can also pass to your index method like this:
$route['method/(:any)/(:any)'] = 'controller/method/index/$1/$2';
$route['method/(:any)'] = 'controller/method/index/$1';
Obviously these are just examples. You can also include folders and more complex routing but that should get you started.
On codeigniter 3
Make sure your controller has first letter upper case on file name and class name
application > controllers > Products_controller.php
<?php
class Products_controller extends CI_Controller {
public function index() {
}
public function display() {
}
}
On Routes
$route['products/display'] = 'products_controller/display';
$route['products/display/(:any)'] = 'products_controller/display/$1';
$route['products/display/(:any)/(:any)'] = 'products_controller/display/$1/$2';
$route['products/display/(:any)/(:any)/(:any)'] = 'products_controller/display/$1/$2/3';
Docs For Codeigniter 3 and 2
http://www.codeigniter.com/docs
Maintain your routing rules like this
$route['products/display/(:any)/(:any)/(:any)'] = 'Products_controller/display/$2/$3/$4';
Please check this link Codeigniter URI Routing
In CodeIgniter 4
Consider Product Controller with Show Method with id as Parameter
http://www.example.com
/product/1
ROUTE Definition Should be
$routes->get("product/(:any)", "Com\Atoconn\Product::show/$1");

How do I generate a friendly URL in Symfony PHP?

I always tend to forget these built-in Symfony functions for making links.
If your goal is to have user-friendly URLs throughout your application, use the following approach:
1) Create a routing rule for your module/action in the application's routing.yml file. The following example is a routing rule for an action that shows the most recent questions in an application, defaulting to page 1 (using a pager):
recent_questions:
url: questions/recent/:page
param: { module: questions, action: recent, page: 1 }
2) Once the routing rule is set, use the url_for() helper in your template to format outgoing URLs.
Recent Questions
In this example, the following URL will be constructed: http://myapp/questions/recent/1.html.
3) Incoming URLs (requests) will be analyzed by the routing system, and if a pattern match is found in the routing rule configuration, the named wildcards (ie. the :/page portion of the URL) will become request parameters.
You can also use the link_to() helper to output a URL without using the HTML <a> tag.
This advice is for symfony 1.0. It probably will work for later versions.
Within your sfAction class:
string genUrl($parameters = array(), $absolute = false)
eg.
$this->getController()->genUrl('yourmodule/youraction?key=value&key2=value', true);
In a template:
This will generate a normal link.
string link_to($name, $internal_uri, $options = array());
eg.
link_to('My link name', 'yourmodule/youraction?key=value&key2=value');
In addition, if you actually want a query string with that url, you use this:
link_to('My link name', 'yourmodule/youraction?key=value&key2=value',array('query_string'=>'page=2'));
Otherwise, it's going to try to route it as part of the url and likely break your action.
You can generate URL directly without define the rule first.
If you want to generate URL in the actions, you can use generateUrl() helper:
$this->generateUrl('default', array('module'=>'[ModuleName]','action'=>'[ActionName]'))
If you want to generate URL in the templates, you can use url_for() helper:
url_for('[ModuleName]/[ActionName]', $absolute)
set $absolute as true/false, dont forget to use echo if you want to display it.
But if you want to make a link (something like ), link_to() helper will do.

Categories