Construct routes(urls) with slugs separated by dash in laravel - laravel

I am about to make more SEO-friendly URLs on my page and want a pattern looking like this for my products:
www.example.com/product-category/a-pretty-long-seo-friendly-product-name-12
So what are we looking at here?
www.example.com/{slug1}/{slug2}-{id}
The only thing I will care about from the URL in my controller is the {id}. The rest two slugs are just of SEO purpose. So to my question. How can I get the 12 from a-pretty-long-seo-friendly-product-name-12?
I have tried www.mydomain.com/{slug}/{slug}-{id} and in my controller to try and get $id. Id does not work. I am not able to able to separate it from from a-pretty-long-seo-friendly-product-name. So in my controller no matter how I do I get {slug2} and {id} concatenated.
Coming from rails it is a piece of cake there but can't seem to figure out how to do that here in laravel.
EDIT:
I am sorry I formulated my question very unclear. I am looking for a way to do this in the routes file. Like in rails.

You're on the right track, but you can't really logically separate /{slug}-{id} if you're using dash-separated strings. To handle this, you can simply explode the chunks and select the last one:
// routes/web.php
Route::get('/{primarySlug}/{secondarySlugAndId}', [ExampleController::class, 'example']);
// ExampleController.php
public function example($primarySlug, $secondarySlugAndId){
$parts = collect(explode('-', $secondarySlugAndId));
$id = $parts->last();
$secondarySlug = $parts->slice(0, -1)->implode('-');
... // Do anything else you need to do
}
Given the URL example.com/primary-slug/secondary-slug-99, you would have the following variables:
dd($primarySlug, $secondarySlug, $id);
// "primary-slug"
// "secondary-slug"
// "99"
The only case this wouldn't work for is if your id had a dash in it, but that's another layer of complexity that I hope you don't have to handle.

Route::get('/test/{slug1}/{slug2}','IndexController#index');
public function index($slug1, $slug2)
{
$id_slug = last(explode('-',$slug2));
$second_slug = str_replace('-'.$id_slug,'',$slug2);
dd($slug1, $second_slug,$id_slug);
}

Related

Laravel 8 multilanguage routes and how get the translated link of the same page

I'm trying to make my test app in multilanguage way.
This question has two correlated questions:
First question:
I followed the second answer in How to create multilingual translated routes in Laravel and this help me having a multilanguage site and the route cached, but I've a question and some misunderstanding.
It's a good practice overwrite an app config as they do int the AppServiceProver.php, making:
Config::set('app.locale_prefix', Request::segment(1));
Isn't better to work with the Session::locale in any case?
Second question:
In my case I've two languages, and in the navbar I want to print just ENG when locale is original language, and ITA when session locale is English.
If I'm in the Italian page, the ENG link in the navbar should point to the same English translated page.
Working with the method used in the other question, I hade many problems caused by the:
Config::set('app.locale_prefix', Request::segment(1));
We overwrite the variable in the config file local_prefix, and every time I switch to English language the locale_prefix will change to 'eng' and this sounds me strange, another thing I did is this:
if ( $lang && in_array($lang, config('app.alt_langs')) ){
return app('url')->route($lang . '_' . $name, $parameters, $absolute);
}
We use the alt_langs where are defined only the alternative languages, and this is a problem cause if I pass the local lang, in my case 'it', like lang parameter, this will not be found cause, from the description, the alt_lang should not contain the locale language and you will be able to get only the translated string.
If I change the:
if ( $lang && in_array($lang, config('app.alt_langs')) ){
return app('url')->route($lang . '_' . $name, $parameters, $absolute);
}
in:
if ( $lang && in_array($lang, config('app.all_langs')) ){
return app('url')->route($lang . '_' . $name, $parameters, $absolute);
}
Now using app.all_langs I'm able to choose which URL you want and in which language I want.
How do I get the translated URL?
In the blade file I need to get the translated URL of the page, and if read the other question, we used the $prefix for caching the routes and giving to the route a new name ->name($prefix.'_home'); in this way I can cache all the route and I can call the routes using blade without prefix {{ route('name') }} but, needing the translated url of the actual page a made this on the top of the view:
#php
$ThisRoute = Route::currentRouteName();
$result = substr($ThisRoute, 0, 2);
if ($result =='it' ){
$routeName = str_replace('it_', '', $ThisRoute);
$url = route($routeName,[],true,'en');
} else {
$routeName = str_replace('en_', '', $ThisRoute);
$url = route($routeName,[],true,'it');
}
#endphp
Doing this I get the actual route name that should be it_home I check if start with it_ or en_, I remove the it_ or en_ prefix and I get the translated URL, now you can use the $url as <a href="{{ $url" }}>text</a> cause if I call the {{ route('page') }} I get the link, with the locale language.
This code is not very good, I know, but I written in 5 minutes, need more implementation, and check, but for the moment is just to play with Laravel.
It's a good way?? How can I do it better (except the blade link retrieving)?? Many solution I found used middleware, but I would like to avoid a link in the navbar like mysite.com/changelang?lang=en
Is a good approach overriding the app.locale_prefix?
First
according to your question, it's a bad practice to save the preferences into .env or session because as soon as the session is finished the saved language will be removed also it's common when you need to store any preferences related to your website such as (Color, Font, Language, ...etc) you must store any of them into the cache.
Second
honestly, your code is a very strange and NOT common way and there are two ways to handle what do you need
First
There is a very helpful and awesome package called mcamara it'll help you too much (I recommend this solution).
Second
you can do it from scratch using the lang folder located in the resource folder and you must create files with the same count of the needed languages then use the keys that you'll define into these files into views and you can prefix your routes with the selected language you can use group method like so
Route::group(['prefix' => 'selected_lang'], function() {
Route::get('first_route', [Controller::class, 'your_method']);
});
or you can add the selected language as a query string like so localhost:8000/your_route?lang=en you can follow this tutorial for more info.

Laravel 5.1 translate an array pass to blade

I have this in my controller
public function editProfile(Request $request){
$question1 = Question::where('group',1)->lists('question', 'id');
$question2 = Question::where('group',2)->lists('question', 'id');
return view('user', compact(''question1', 'question2'));
}
$question = {\"1\":\"What is the first name of your best friend in high school?\",\"2\":\"What was the name of your first pet?\",\"3\":\"What was the first thing you learned to cook?\",\"4\":\"What was the first film you saw in the theater?\"}
$question2 = {\"5\":\"Where did you go the first time you flew on a plane?\",\"6\":\"What is the last name of your favorite elementary school teacher?\",\"7\":\"In What city or town does your nearest sibling live?\"}
I would like to translate the value in both question 1 and question 2 and pass it to user blade without changing the key, Any suggestions?
As specified at the localization doc, you need to populate a lang file with translation strings. So, let's say you want to show both Spanish and English strings. In this case you'd need to create two files: /resources/lang/en/messages.php and /resources/lang/es/messages.php. The content of one of those files would be somewhat like this:
<?php
// resources/lang/es/messages.php
return [
'welcome' => 'Bienvenido'
];
This way, you could access the strings in there with the following method: __('messages.welcome'), which would return the string for the language set on your config/app.php -- the default entry is en, by the way, but you can set it to whatever you want. The value in there will define which language will be chosen when selecting strings.
Another method to create translation strings is using the string itself as key, storing them in a JSON file instead of PHP. For example, the following translation string:
{
"I love programming.": "Me encanta programar."
}
would be accessible through this: __('I love programming.').
Having said that, you may solve your problem through the two methods presented above. You could store in your DB keywords for the questions instead of the whole text, and create translation for as many languages as you want. Also, you could keep the questions in your database and create translation strings for those questions. Finally, you'd need to iterate over the fetched entries and translate each one of them, or use some Collection helper to do the hard work for you, like transform or map.

Get segment from url CodeIgniter but not first

I know i can get all segments from url like this
Lets say i have this example link
www.example.com/de/products.html
Using url_helper like this:
$data['url'] = $this->uri->uri_string();
I will get value like this
de/products
But i dont need first segment de, only products, the problem is that
i dont know how many segments it will be, i only need to remove the first
Is there possible to forget first segment with url helper in CI?
Try like this...
Use the php's explode() function to make the url string as array.Then apply array's array_shift() function which always removes the first element from array.
Code is looks like as below
$data= $this->uri->uri_string();
$arr=explode('/', $data);
array_shift($arr);
//print_r($arr);
Then use the php's implode() method to get the URI without first segment.Hope it will works...
$uri=implode('/',$arr);
echo $uri;
There is no URL helper in the CI to forget the first segment. However you can easily make a custom one and put #Hikmat's answer below it in the application/helpers/MY_url_helper.php in the Core folder.
e.g.
function my_forget_first_segment() {
$data= $this->uri->uri_string();
$arr=explode('/', $data);
array_shift($arr);
$uri=implode('/',$arr);
return $uri;
}
Before Edit answer.
You need to try this
$second_segment = $this->uri->segment(2);
From Codeigniter documentation -
$this->uri->segment(n);
Permits you to retrieve a specific segment. Where n is the segment number you wish to retrieve. Segments are numbered from left to right. For example, if your full URL is this:
http://example.com/index.php/news/local/metro/crime_is_up
The segment numbers would be this:
1. news
2. local
3. metro
4. crime_is_up
The optional second parameter defaults to NULL and allows you to set the return value of this method when the requested URI segment is missing. For example, this would tell the method to return the number zero in the event of failure:
$product_id = $this->uri->segment(3, 0);
example:
<?php
$data=$this->uri->segment(2);
$val=explode('.', $data);
echo $val[0];
?>

Best practice in handling invalid parameter CodeIgniter

Let's say I have a method at Controller named
book($chapter,$page);
where $chapter and $page must be integer. To access the method, the URI will look like
book/chapter/page
For example,
book/1/1
If user try to access the URI without passing all parameter, or wrong parameter, like
book/1/
or
book/abcxyz/1
I can do some if else statements to handle, like
if(!empty($page)){
//process
}else{
//redirect
}
My question is, is there any best practice to handle those invalid parameters passed by user? My ultimate goal is to redirect to the main page whenever there is an invalid parameter? How can I achieve this?
Using the CodeIgniter routing in config/routes.php is pretty useful here, something like this:
$route['book/(:num)/(:num)'] = "book/$1/$2";
$route['book/(:any)'] = "error";
$route['book'] = "error";
Should catch everything. You can have pretty much any regular expressions in the routes, so can validate that the parameters are numeric, start with a lowercase letter, etc..
The best logic here seems to be adding the default values:
book($chapter = 1, $page = 1);
and then checking if they are numeric
So it automatically opens the 1st page of the 1st chapter if there are parameter missing or non-numeric.

Mutliple URL Segments to Index Function With CodeIgniter

Please excuse me if this is an incredibly stupid question, as I'm new to CodeIgniter.
I have a controller for my verification system called Verify. I'd like to be able to use it something like site.com/verify/123/abcd, but I only want to use the index function, so both URL segments need to go to it.
I'm sure this can be done with URL routing somehow, but I can't figure out how to pass both URL segments into Verify's index function..
Something like this in routes.php should do the job:
$route['verify/(:any)/(:any)'] = "verify/index/$1/$2";
I'm pretty sure you can just pass any controller method in CodeIgniter multiple arguments without modifying routes or .htaccess unless I misunderstood the problem.
function index($arg_one, $arg_two)
{
}
$arg_one representing the 123 and $arg_two representing the abcd in your example URI.
You will either need to edit the routes or write an htaccess rule, however i didn't understand why you want to limit to just the index function.
If you didnt wanna use routes for some reason, then you could add this function to the controller in question.
public function _remap($method_in, $params = array()) {
$method = 'process_'.$method_in;
if (method_exists($this, $method)) {
return call_user_func_array(array($this, $method), $params);
}
array_unshift($params, $method_in);
$this->index($params);
}
Basically it does the same as default behavior in CI, except instead of sending a 404 on 'cant find method', it sends unfound method calls to the index.
You would need to alter your index function to take an array as the first argument.
OR if you know that you only ever want 2 arguments, you could change the last 2 lines to
$this->index($method_in, $params[0]);
Of course both solutions fail in someone uses an argument which is the same as a method in your controller.

Resources