Can a Laravel POST route return a view instead of redirecting to another route? - laravel

I have seen/worked on lot of projects where a Laravel POST route looking like this:
Route::post('/some-url', [SomeController::class, 'someMethod']);
And the controller with its method which takes care of the route looking like this:
class SomeController extends Controller
{
public function someMethod(Request $request) {
// My Logic to do something with the post data - $request
return redirect("/some-other-url");
}
}
have always redirected to a specific URL after doing something with the POST data, by convention.
I would like to know, if after processing a POST request, if it's okay to just return a view like what we do with GET requests? I know it works, but is it just convention or are there any issues in doing so?
Eg:
class SomeController extends Controller
{
public function someMethod(Request $request) {
// My Logic to do something with the post data - $request
return view("somebladeview")->with(["result" => $result ]);
}
}

The pattern is called post-redirect-get, or PRG. It is convention because POST should be used for requests that change data, whereas GET should be used to simply display data.
If you return a view after a POST, the user can hit reload, and (probably unintentionally) change data again, eg buy something a second time. By using PRG, the user hitting reload simply reloads the last GET, which just re-displays something.
NOTE: There is some advice in the comments on your question to ignore this convention. I think that is unwise and dangerous, these conventions exist for good reasons.

Related

Laravel: Multiple Route to Same Controller

May I know how can I make just a single route so I don't have to repeat it? Thanks in advance.
Route::get('/url', 'CtcFormController#index' )->name('CtcForm.ch');
Route::post('/url/submit', 'CtcFormController#submit')->name('CtcForm.submit');
Route::view('/url/submitted', 'form.submit')->name('CtcForm.submit');
Route::get('/url2','CtcFormController#store')->name('CtcForm.eng');
Route::post('/url2/submit', 'CtcFormController#submit')->name('CtcForm.submit');
Route::view('/url2/submitted', 'form.submit')->name('CtcForm.submit');
As per your given example, you want to handle the variable part of the route which is /url/ and /url12/. Yes! you can handle there both different route using a single route in ways:
Use route variable to handle dynamic url values i.e. url, url2,url3...url12 and so on.
Route::get('/{url}', 'CtcFormController#index' )->name('CtcForm.ch');
Route::post('/{url}/submit', 'CtcFormController#submit')->name('CtcForm.submit');
Route::view('/{url}/submitted', 'form.submit')->name('CtcForm.submit');
Now in your controller methods handing above routes receive extra parameter $url like:
In controller CtcFormController.php class:
public function index(Request $request, string $url) {
//$url will gives you value from which url request is submitted i.e. url or url12
//method logic goes here ...
}
Similarly, method handling /{url}/submit route will be like:
public function submit(Request $request, string $url) {
//method logic goes here ...
}
Let me know if you have any further query regarding this or you face any issue while implementing it.

Laravel route difference between {id} vs {tag}

I am new in Laravel pardon me if question is silly. I have seen a doc where they used
For get request
Route::get("tags/{id}","TagsController#show");
For put request
Route::put("tags/{tag}","TagsController#update");
What is the difference and benefit between this ? I understood 1st one, confusion on put route.
There’s no real difference as it’s just a parameter name, but you’d need some way to differential parameters if you had more than one in a route, i.e. a nested resource controller:
Route::get('articles/{article}/comments/{comment}', 'ArticleCommentController#show');
Obviously you couldn’t use just {id} for both the article and comment parameters. For this reason, it’s best to use the “slug” version of a model for a parameter name, even if there’s just one in your route:
Route::get('articles/{article}', 'ArticleController#show');
You can also use route model binding. If you add a type-hint to your controller action for the parameter name, Laravel will attempt to look up an instance of the given class with the primary key in the URL.
Given the route in the second code example, if you had a controller that looked like this…
class ArticleController extends Controller
{
public function show(Article $article)
{
//
}
}
…and you requested /articles/123, then Laravel would attempt to look for an Article instance with the primary key of 123.
Route model binding is great as it removes a lot of find / findOrFail method calls in your controller. In most instances, you can reduce your controller actions to be one-liners:
class ArticleController extends Controller
{
public function show(Article $article)
{
return view('article.show', compact('article'));
}
}
Generally there's no practical difference unless you define a custom binding for a route parameter. Typically these bindings are defined in RouteServiceProvider as shown in the example in the docs
public function boot()
{
parent::boot();
Route::model('tag', App\Tag::class);
}
When you bind tag this way then your controller action can use the variable via model resultion:
public function update(Tag $tag) {
// $tag is resolved based on the identifier passed in the url
}
Usually models are automatically bound so doing it manually doesn't really need to be done however you can customise resolution logic if you do it manually
Normal way
Route::get("tags/{id}","TagsController#show");
function($id)
{
$tag = Tag::find($id);
dd($tag); // tag
}
With route model bindings
Route::put("tags/{tag}","TagsController#update");
function(Tag $tag) // Tag model binding
{
dd($tag); // tags
}
ref link https://laravel.com/docs/5.8/routing#implicit-binding
It's just a convention. You can call it all you want. Usually, and {id} refers to the id in your table. A tag, or similarly, a slug, is a string value. A tag could be 'entertainment' for video categories, while 'my-trip-to-spain' is a slug for the description of a video.
You have to chose the words what you are comfortable with. The value will be used to find in your database what record is needed to show the correct request in the view. Likewise you can use video/view/{id}/{slug} or any combination thereof.
Just make sure your URLs don't get too long. Because search engines won't show your website nicely in search results if you do. Find the balance between the unambiguous (for your database) and logic (for your visitors).
Check this out: Route model bindings
Use id, Laravel will get the id from route, and it will be the tag's id, it is integer.
function show($id) {
$tag = Tag::find($id);
}
Use tag, Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name.
In URL, your tag parameter is integer, however in your controller action $tag will be a model object:
function action(Tag $tag) {
$tag->name;
}
So you don't need to get the $tag by eloquent in your controller action. You just need to specify it is From model Tag $tag
It will do it automatically.

How to properly forward parameters from a POST result and avoid refresh (re-submit), with Laravel 5?

This is a basic issue, when submitting and performing a post, you normally want to avoid giving the user the chance to re-iterate the submit by refreshing or going back and forth with browser history.
(Backend re-submit, controls and checking is not questioned here. Of course they should be in place for security)
My solution was to have in Laravel web routes defined a post and a get route.
Like:
Route::post('/action', 'ActionController#doAction')->name('do.action');
Route::get('/action', 'ActionController#doActionConfirm')->name('do.action.confirm');
In ActionController something like:
public function doAction(Request $request)
{
....
return redirect()->route('do.action.confirm', [ 'data' =>
base64_encode(json_encode([
'action_id'=> $action_id,
'sent_to'=> $email,
'sent_success'=> $sent_success,
'sent_errors'=> $sent_errors,
]))]);
}
....
public function doActionConfirm(Request $request)
{
return view('confirmation')->with('data',$request->input('data'));
}
Then in my confirmation.blade.php get that $data decoded and displayed.
Is this the correct way to do it with Laravel?
What I don't like here:
is there's a better and more elegant way to forward data from the redirect()
is there a better way to manage get parameters to the GET route just to avoid people understanding and trying to inject unwanted data to the confirmation blade? (even if they will obtain nothing but no-sense views..because the page is doing nothing, it's simply displaying data in HTML blade)

Call an index controller with parameter

So basically, I have a setup of restful controller in my route. Now my problem is how can I call the Index page if there is a parameter.. it gives me an error of Controller not found
Im trying to call it like this www.domain.com/sign-up/asdasdasd
Route::controller('sign-up','UserRegisterController');
then in my Controller
class UserRegisterController extends \BaseController {
protected $layout = 'layouts.unregistered';
public function getIndex( $unique_code = null )
{
$title = 'Register';
$this->layout->content = View::make( 'pages.unregistred.sign-up', compact('title', 'affiliate_ash'));
}
By registering:
Route::controller('sign-up','UserRegisterController');
You're telling the routes that every time the url starts with /sign-up/ it should look for corresponding action in UserRegisterController in verbAction convention.
Suppose you have:
http://domain.com/sign-up/social-signup
Logically it'll be mapped to UserRegister#getSocialSignup (GET verb because it is a GET request). And if there is nothing after /sign-up/ it'll look for getIndex() by default.
Now, consider your example:
http://domain.com/sign-up/asdasdasd
By the same logic, it'll try looking for UserRegister#getAsdasdasd which most likely you don't have. The problem here is there is no way of telling Route that asdasdasd is actually a parameter. At least, not with a single Route definition.
You'll have to define another route, perhaps after your Route::controller
Route::controller('sign-up','UserRegisterController');
// If above fail to find correct controller method, check the next line.
Route::get('sign-up/{param}', 'UserRegisterController#getIndex');
You need to define the parameter in the route Route::controller('sign-up/{unique_code?}','UserRegisterController');. The question mark makes it optional.
Full documentation here: http://laravel.com/docs/routing#route-parameters

Should I call redirect() from within my Controller or Model in an MVC framework?

I'm using the MVC PHP framework Codeigniter and I have a straight forward question about where to call redirect() from: Controller or Model?
Scenario:
A user navigates to www.example.com/item/555. In my Model I search the item database for an item with the ID of 555. If I find the item, I'll return the result to my controller. However, if an item is not found, I want to redirect the user somewhere. Should this call to redirect() come from inside the model or the controller? Why?
No your model should return false and you should check in your controller like so:
class SampleModel extends Model
{
//Construct
public function FetchItem($id)
{
$result = $this->db->select("*")->from("table")->where("item_id",$id)->get();
if($result->num_rows() == 0)
{
return false;
}
//return result
}
}
and within your controller do:
function item($id)
{
$Item = $this->SampleModel->FetchItem($id);
if(!$Item)
{
redirect("class/error/no_item");
}
}
Models are for data only either return a standard result such as an key/value object or a boolean.
all logic should be handled / controlled by the Controller.
Models are not page specific, and are used globally throughout the whole application, so if another class / method uses the model, it might get redirect to the incorrect location as its a different part of your site.
It seems like the controller would be the best place to invoke your redirect because the controller typically delegates calls to the model, view, or in your case, another controller.
However, you should use whatever makes the most sense for your application and for what will be easier to maintain in the future, but also consider that rules do exist for a reason.
In short, if a coworker were to try to fix a bug in your code, what would the "reasonable person" standard say? Where would most of them be most likely to look for your redirect?
Plus, you said you're returning the result to your controller already... perhaps that's where you should make your redirect...

Resources