I would like to use both ID and slug in my articles route. So instead of /articles/ID
I want /articles/ID/slug
.
I don't actually need the slug variable for anything; it's just there to make the URL more readable and SEO, so I'll be using ID
as identifier for retrieving the articles.
If the URL /articles/ID
is entered I want to redirect to /articles/ID/slug
. There has to be an exception for /articles/ID/edit
since this opens the form for editing the article.
I've googled and looked this site, but I've only found examples of replacing ID with slug, not include both.
How can I achieve this? And can I use the URL
class to get the full URL (/articles/ID/slug
) for an article?
Current route config:
Route::resource('articles', 'ArticlesController');
So, here is what I ended up doing:
routes.php
, created a custom route for show
and edit
. Used a resource for the rest:
Route::pattern('id', '[0-9]+');
Route::get('articles/{id}/{slug?}', ['as' => 'articles.show', 'uses' => 'ArticlesController@show']);
Route::get('articles/edit/{id}', ['as' => 'articles.edit', 'uses' => 'ArticlesController@edit']);
Route::resource('articles', 'ArticlesController', ['except' => ['show', 'edit']]);
Controller, added a slug
input parameter with a default value. Redirect the request if the slug is missing or incorrect, so it will redirect if the title is changed and return a HTTP 301 (permanently moved):
public function show($id, $slug = null)
{
$post = Article::findOrFail($id);
if ($slug != Str::slug($post->title))
return Redirect::route('articles.show', array('id' => $post->id, 'slug' => Str::slug($post->title)), 301);
return View::make('articles.show', [
'article' => Article::with('writer')->findOrFail($id)
]);
}
View presenter, I originally had something in my model class. But moved it to a view presenter class on the basis of this answer: https://stackoverflow.com/a/25577174/3903565, installed and used this: https://github.com/laracasts/Presenter
public function url()
{
return URL::route('articles.show', array('id' => $this->id, 'slug' => Str::slug($this->title)));
}
public function stump()
{
return Str::limit($this->content, 500);
}
View, get the url from the view presenter:
@foreach($articles as $article)
<article>
<h3>{{ HTML::link($article->present()->url, $article->title) }} <small>by {{ $article->writer->name }}</small></h3>
<div class="body">
<p>{{ $article->present()->stump }}</p>
<p><a href="{{ $article->present()->url }}"><button type="button" class="btn btn-default btn-sm">Read more...</button></a></p>
</div>
</article>
@endforeach
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With