1

I have a problem with laravel routes.

I had an old store in php and i rewrite it in laravel. The problem is with the products route. They have been indexed (google) and now those links i can`t access them.

The url structure was:

http://mydomain/product/{productName}-{productID}.html

In laravel i created a route to generate the same structure:

Route::get('/product/{productName}-{id}.html', 'ProductController@index')->name('product');

The problem is when an old url contains a dot (.) in productName it returns 404 (does not enter in Controller) - because of the (.html) in the new route.

If remove the (.html) from route i get the request in controller, but how can I better create the structure of the url?

/{productName}-{productID}.html

UPDATE

when generating the productName i use a php function to make it seo (productName):

public function makeSeoLink($string)
{
    // trim the string
    $string = trim($string);

    // remove all diacritics
    $string = str_ireplace(array("â", "î", "ă", "ș", "ț"), array("a", "i", "a", "s", "t"), $string);

    // remove all non alphanumeric characters except spaces
    $clean =  preg_replace('/[^a-zA-Z0-9\s]/', '', strtolower($string));

    // replace one or multiple spaces into single dash (-)
    $clean =  preg_replace('!\s+!', '-', $clean);

    return $clean;
}

when generating the url:

route('product', array(makeSeoLink($p->Name), $p->id));
calin24
  • 905
  • 3
  • 21
  • 43
  • I'd suggest moving the routes to something more Laravelly, and returning 301 redirects on the old routes. Carrying legacy approaches forward with rewrites isn't always ideal in the long run. – markdwhite Jun 18 '18 at 06:40
  • can i see index function ? – Supun Praneeth Jun 18 '18 at 06:57
  • I cannot reproduce this: `Route::get('/product/{productName}-{id}.html', function ($productName, $id) { dd($productName, $id); });` and url: `http://localhost:8000/product/te.st-1.html`. Can you post your controller as well? – Ivanka Todorova Jun 18 '18 at 07:01
  • @IvankaTodora try this url: http://localhost:8000/product/test-product-8932.7-asd-1.html; I have updated the question. For productName i use a function to make it seo. – calin24 Jun 18 '18 at 07:07
  • @SupunPraneeth sure. In index: ` $segment = Request::segment(2); $segment = str_replace('.html', '', $segment); $id = substr($segment, strrpos($segment, '-') + 1); ...` for getting the id from segment :) – calin24 Jun 18 '18 at 07:15
  • @calin24 it's not a problem with dot, it because you are using multiple this - – Supun Praneeth Jun 18 '18 at 07:24
  • @SupunPraneeth then why all the urls are working fine except for those with a dot in productName ? – calin24 Jun 18 '18 at 07:31

2 Answers2

0

For Laravel there is a where clause for routes. So you can add an extension and in the where clause specify it. Here is an example.

Route::get('/product/{productName}-{id}{extension}', 'ProductController@index')->name('product')->where('extension', '(?:.html)?');

I got this answer from here.

Other useful links

https://stackoverflow.com/a/22289143/6261137

https://stackoverflow.com/a/33827159/6261137

Ulrich Dohou
  • 1,509
  • 14
  • 25
  • I get the request in controller but when returning the view using this approach `ErrorException (E_ERROR) Missing required parameters for [Route: product] [URI: product/{productName}-{id}{extension}].` this means i have to go on each route `route('product', array(makeSeoLink($p->Name), $p->id));` and set the extension parameter? – calin24 Jun 18 '18 at 07:49
  • Can you `dd`in your controller the parameters your are sending over the request ? Are you sure you are sending all the parameters ? – Ulrich Dohou Jun 18 '18 at 07:53
  • For my knowledge you need to pass the parameters in the `route`method inside you view – Ulrich Dohou Jun 18 '18 at 07:54
  • like i said ... if using this approach `/product/{productName}-{id}{extension}` now it complains for the third parameter that is missing (extension) in the view (where i use the route product to generate the url ( `route('product', array('productName', id))`) – calin24 Jun 18 '18 at 08:18
  • Yeah just add that parameter and leave it blank `route('product', array('productName', id,''))) ` – Ulrich Dohou Jun 18 '18 at 08:24
  • if letting blank in view i don't get any extension. In view using blade i have to set the extension manually to work: `{{ route('product', array(makeSeoLink($product->Name), $product->id, '.html')) }}` ... i thought the where clause in route definition is setting automatically the extension .html – calin24 Jun 18 '18 at 08:35
0

since product name can contain dash(-) you have to use something like this:

Route

Route::get('/product/{productDetails}','ProductController@index')->name('product');

index function

function index(){
    $segment = Request::segment(2);
    $segment = str_replace('.html', '', $segment);
    $list =  explode('-',$segment);
    $id = end($list);
    array_pop($list);
    $text = implode("-",$list);
    return [$id,$text];
}
Supun Praneeth
  • 3,087
  • 2
  • 30
  • 33
  • i have to find another solution .... because it's a lot of changes (in blade files) if have to change the route structure from `route('product', array(makeSeoLink($p-name), $p->id))` to `route('product', makeSeoLink($p-name).'-'.$p->id.'.html')` – calin24 Jun 18 '18 at 08:42