Redirect using get and then redirect to the response - laravel

Lets start off with the code
if($request->berbix == true || $request->berbix == 'true'){
THIS IS WHERE I NEED THE LOGIC TO GO
}
else {
session()->flash('flash.banner', 'Profile updated!');
session()->flash('flash.bannerStyle', 'success');
return Redirect::route('dashboard');
}
In the if statement this is what needs to happen.
user needs to be send to /verification/create with their user model
When that is completed, it will provide a URL
user then needs to be redirected to said URL
I know this should be simple but I am having a HECK of a time wrapping my head around the simple logic. The main thing I am struggling with (and I know why, but don't know how to solve it), is when I do for example Http::get() it isnt sending it as the user so the request doesn't know the user info
Any help either a solution or a nudge on what I need to do would be very nice right now!

While I would still consider redirecting to a different route/controller to handle this, since you said you want it all in one place, it is possible to call controller methods directly and retrieve a response without leaving the current method or creating another HTTP request.
You could do something like this.
$url = app()->call('App\Http\Controllers\VerificationController#create', [
'user' => auth()->user()
]);
if ($url) {
return redirect($url);
}

Related

How to send a response from a method that is not the controller method?

I've got a Controller.php whose show($id) method is hit by a route.
public function show($id)
{
// fetch a couple attributes from the request ...
$this->checkEverythingIsOk($attributes);
// ... return the requested resource.
return $response;
}
Now, in checkEverythingIsOk(), I perform some validation and authorization stuff. These checks are common to several routes within the same controller, so I'd like to extract these checks and call the method everytime I need to perform the same operations.
The problem is, I'm unable to send some responses from this method:
private function checkEverythingIsOk($attributes)
{
if (checkSomething()) {
return response()->json('Something went wrong'); // this does not work - it will return, but the response won't be sent.
}
// more checks...
return response()->callAResponseMacro('Something else went wrong'); // does not work either.
dd($attributes); // this works.
abort(422); // this works too.
}
Note: Yes, I know in general one can use middleware or validation services to perform the checks before the request hits the controller, but I don't want to. I need to do it this way.
As of Laravel 5.6 you can now use for example response()->json([1])->send();.
There is no need for it to be the return value of a controller method.
Note that calling send() will not terminate the output. You may want to call exit; manually after send().
You are probably looking for this:
function checkEverythingIsOk() {
if (checkSomething()) {
return Response::json('Something went wrong');
}
if(checkSomethingElse()) {
return Response::someMacro('Something else is wrong')
}
return null; // all is fine
}
And in the controller method:
$response = $this->checkEverythingIsOk();
if($response !== null) { // $response instanceof Response
return $response;
}
It's probably overkill, but I will throw it in anyway. You might want to look into internal requests. Also this is just pseudoish code, I have not actually done this, so take this bit of information with caution.
// build a new request
$returnEarly = Request::create('/returnearly');
// dispatch the new request
app()->handle($newRequest);
// have a route set up to catch those
Route::get('/returnearly', ...);
Now you can have a Controller sitting at the end of that route and interpret the parameters, or you use multiple routes answered by multiple Controllers/Methods ... up to you, but the approach stays the same.
UPDATE
Ok I just tried that myself, creating a new request and dispatching that, it works this way. Problem is, the execution does not stop after the child-request has exited. It goes on in the parent request. Which makes this whole approach kind of useless.
But I was thinking about another way, why not throw an Exception and catch it in an appropriate place to return a specified response?
Turns out, thats already built into Laravel:
// create intended Response
$response = Response::create(''); // or use the response() helper
// throw it, it is a Illuminate\Http\Exception\HttpResponseException
$response->throwResponse();
Now usually an Exception would be logged and you if you are in Debug mode, you would see it on screen etc. etc. But if you take a look into \Illuminate\Foundation\Exceptions\Handler within the render method you can see that it inspects the thrown Exception if it is an instance of HttpResponseException. If it is then the Response will be returned immediately.
To me the most simple and elegant way is:
response()->json($messages_array, $status_code)->throwResponse();
(you don`t need return)
It can be called from a private function or another class...
I use this in a helper class to check for permissions, and if the user doesn`t have it I throw with the above code.

Laravel 5.2 4 rolle

I need help how to make laravel 5.2 authenticate with 4 rolls?
guest
registered
support
admin
I make something but every time I get
ERR_TOO_MANY_REDIRECTS.
Route::group(['middleware' => ['web','isAdmin']], function () {
Route::get('/', function(){
return view('admin');
});
});
Route::group(['middleware' => ['web','isSupport']], function () {
Route::get('/support', function(){
return view('support');
});
});
Middleware
public function handle($request, Closure $next)
{
if (Auth::user()->role == '3') {
return $next($request);
}
if(Auth::guest()){
redirect('login');
}else
return redirect('/');
}
}
If I assume, you add isAdmin middleware to path /. isAdmin middleware is checking that user have a proper role (role with id === 3). If not, then redirect to /.
So only user with role 3 can access to path / but system still try redirect to this path. Infinite loop.
Yes, #grzegorz has the correct answer already posted on here I believe. But I will try to explain it clearly.
So in your route for the root of your application ('/') you tell Laravel to process middleware to authenticate users. This in and of itself is not unusual. The middleware runs a function to see if a user basically has level 3 authority and if they do then you return the request url (which is also '/' and the process continues in an infinite loop, because they are sent to the '/' url, then it processes and returns the same url again, causing it to process middleware again, going forever. This is why you are getting an error saying that there are too many redirects, because it redirects a whole bunch of times with no end in sight and eventually Laravel stops it for you and returns an error.
How to fix this problem?
Easy, you have a good start already. But what I would do is that when you check to see if a user has auth level 3 and they do, then simply return true. There is no need to return the requesting url, because this is middleware, so its running when someone requests a URL. So the purpose of your middleware would be to return true meaning "don't do anything, just continue". Then if the user does not have authority level 3, then you would want to redirect them away from this page. Do an actual redirect though (as opposed to returning a url string like you are now). So you would want to do something like this:
return redirect()->route('login');
You could also add some flash data to this with an error message to display to the user something telling them that they do not have access to this route.
Last note:
It would be strange to only allow high level authority users to be the only ones that can access a homepage. Maybe this is what you want, but it seems weird so I wanted to mention it in case it is unintended. What I wonder you are doing is maybe trying to display different information on the homepage depending if someone is logged in or not. if this is the case, then you don't want to use middleware, you want to move this to the controller and then conditionally add html for logged in users or something like that.

Laravel 5 and Socialite - New Redirect After Login

Another newb question here, but hopefully someone can shed some light:
I am using Socialite with Laravel 5, and I want to be able to redirect the user to a page on the site after they have logged in. The problem is that using
return redirect('any-path-I-put-here');
simply redirects back to 'social-site/login?code=afkjadfkjdslkfjdlkfj...' (where 'social-site' is whatever site is being used i.e. facebook, twitter, google, etc.)
So, what appears to me to be happening is that the redirect() function in the Socialite/Contracts/Provider interface is overriding any redirect that I attempt after the fact.
Just for clarification, my routes are set up properly. I have tried every version of 'redirect' you can imagine ('to', 'back', 'intended', Redirect::, etc.), and the method is being called from my Auth Controller (though I have tried it elsewhere as well).
The question is, how do I override that redirect() once I am done storing and logging in the user with socialite? Any help is appreciated! Thank you in advance.
The code that contains the redirect in question is:
public function socialRedirect( $route, $status, $greeting, $user )
{
$this->auth->login( $user, true );
if( $status == 'new_user' ) {
// This is a new member. Make sure they see the welcome modal on redirect
\Session::flash( 'new_registration', true );
return redirect()->to( $route );// This is just the most recent attempt. It originated with return redirect($route);, and has been attempted every other way you can imagine as well (as mentioned above). Hardcoding (i.e., 'home') returns the exact same result. The socialite redirect always overrides anything that is put here.
}
else {
return redirect()->to( $route )->with( [ 'greeting' => $greeting ] );
}
}
... The SocialAuth class that runs before this, however, is about 500 lines long, as it has to determine if the user exists, register new users if necessary, show forms for different scenarios, etc. Meanwhile, here is the function that sends the information through from the Social Auth class:
private function socialLogin( $socialUser, $goto, $provider, $status, $controller )
{
if( is_null( $goto ) ) {
$goto = 'backlot/' . $socialUser->profile->custom_url;
}
if( $status == 'new_user' ) {
return $controller->socialRedirect($goto, $status, null, $socialUser);
}
else {
// This is an existing member. Show them the welcome back status message.
$message = 'You have successfully logged in with your ' .
ucfirst( $provider ) . ' credentials.';
$greeting =
flash()->success( 'Welcome back, ' . $socialUser->username . '. ' . $message );
return $controller->socialRedirect($goto, $status, $greeting, $socialUser);
}
}
I managed to workaround this problem, but I am unsure if this is the best way to fix it. Similar to what is stated in question, I got authenticated callback from the social media, but I was unable to redirect current response to another url.
Based on the callback request params, I was able to create and authenticate the user within my Laravel app. It worked good so far but the problems occured after this step when I tried to do a return redirect()->route('dashboard');. I tried all the flavours of redirect() helper and Redirect facade but nothing helped.
The blank page just stared at my face for over 2 days, before I checked this question. The behaviour was very similar. I got redirect from social-media to my app but could not further redirect in the same response cycle.
At this moment (when the callback was recieved by the app and user was authenticated), if I refreshed the page manually (F5), I got redirected to the intended page. My interpretation is similar to what's stated in this question earlier. The redirect from social-media callback was dominating the redirects I was triggering in my controller (May be redirect within Laravel app got suppressed because the redirect from social-media was still not complete). It's just my interpretation. Experts can throw more light if they think otherwise or have a better explaination.
To fix this I issued a raw http redirect using header("Location /dashboard"); and applied auth middleware to this route. This way I could mock the refresh functionality ,redirect to dashboard (or intended url) and check for authentication in my DashboardController.
Once again, this is not a perfect solution and I am investigating the actual root of the problem, but this might help you to move ahead if you are facing similar problem.
I believe you are overthinking this. Using Socialite is pretty straight forward:
Set up config/services.php. For facebook I have this:
'facebook' => [
'client_id' => 'your_fb_id',
'client_secret' => 'your_fb_secret',
'redirect' => '>ABSOLUTE< url to redirect after login', //like: 'http://stuff'
],
Then set up two routes, one for login and one for callback (after login).
In the login controller method:
return \Socialize::with('facebook')->redirect();
Then in the callback function
$fb_user = \Socialize::with('facebook')->user();
// check if user exists, create it and whatnot
//dd($fb_user);
return redirect()->route('some.route');
It should be pretty much similar for all other providers.
We are using the Socialite login in our UserController as a trait. We simply overrode the AuthenticatesSocialiteLogin::loginSuccess() in our controller.
use Broco\SocialiteLogin\Auth\AuthenticatesSocialiteLogin;
class UserController extends BaseController
{
use AuthenticatesSocialiteLogin;
public function loginSuccess($user)
{
return redirect()->intended(url('/#login-success'));
}
....

laravel 4.2. user permissions and hiding link source

I am a total newbie with Laravel and learning it now for a week. I have some basic questions that I can't find an answer to. Next week I will start with developing CRM system and I need some info from experienced developers who could tell me is the approach I am attending to make a good one.
I will need some authentication system, like 4 groups of users (Admin, Basic, Manager, Office) where Manager and Admin will add the Basic users. There will be few view and features and every groups will have defined access to each view and feature. Since few days I am searching for packages, watching the tutorials and learning. I found an interesting package for which I think it could help me with this user-group-permission things.The package is Sentry. Could this help me with my requirements?
What is the case when for example I have a user in group Basic and he deletes for example some comment with the button. On the left side down in the browser the user can see the link to this comment when he hovers the link. For example www.test.com/comments/345/delete where the id is 345. What if user types that with another id, that means he can delete another comment. I found some suggestions on how to solve this, to make it with jQuery and javascript so the link wouldn't be shown and POST would be made with for example with AJAX. But since I am a newbie, I am thinking how much time would this take and is this a good approach at all? Could package Sentry from 1. question help me with the permission on what route each group can access?
Any help or advice would be appreciated.
Sentry does what you want, yes. Here's a question with some answers explaining the permissions part.
The visible link part can be avoided by doing a POST request instead of a GET request.
When you open your form, you add a method attribute.
Form::open(array('url' => 'foo/bar', 'method' => 'post'))
A GET request will put the parameters in the URL, hence the visible ID. Using a POST request will put the parameters in the headers, thus hiding it from the URL.
An example could be deleting a comment. A GET request could look like this:
http://www.example.com/comments/delete/1
And the parameters would be defined in your method signature:
public function getDelete ($id) {
Comment::find($id)->delete();
}
Where the POST equivalent would be
http://www.example.com/comments/delete
And the parameters would be defined in your Input class, you would get them using the get method
public function postDelete() {
Comment::find(Input::get('id'))->delete();
}
1) The best package to help you with that is Sentry indeed.
2) To make sure an user can delete only his comments you can do something like this (but there are more solutions either you do it with Ajax or not):
public function destroy($id) {
$user = Sentry::getUser();
$comment = Comment::find($id);
if($comment) {
if($comment->user_id != $user->id) {
return Response::back(); // optional message: Permission denied!
}
$comment->delete();
return Response::back(); // optional with message: Deleted!
}
return Response::back(); // optional message: Comment not found!
}
You can use Sentry in this case to get the logged in user and check for user id. I think you should let user delete their own comments always but if you need special roles (Admins for example) to be able to delete any comment, or special permission comments.delete (For some Managers) - you can use Sentry as well:
public function destroy($id) {
$user = Sentry::getUser();
$comment = Comment::find($id);
if($comment) {
if($comment->user_id != $user->id && !$user->hasRole('Admin') && !$user->hasPermission('comments.delete'))) {
return Response::back(); // optional message: Permission denied!
}
$comment->delete();
return Response::back(); // optional with message: Deleted!
}
return Response::back(); // optional message: Comment not found!
}
A nicer way of making the DELETE thru a Form request check this:
Laravel RESTfull deleting

Returning a variable from a filter. Laravel 4

I am new to Laravel and I am trying to set up some basic routing logic. I have a route that will process a certain URL pattern. These URLs will usually be an ajax request (returning data for a popup window). However, search engines and users with javascript disabled will follow a normal link, so I want the data to be returned on a separate page. To do this, I need to determine if the request is ajax. I understand I can do this using:
if(Request::ajax()){
//
}
My plan was to do this as part of a 'before' filter attached to the route. If my thinking is correct, I would need to return a boolean ajax=true/false back from the filter. Maybe this is a very simple question, but I can't find anywhere that explains how you actually return a value like this from a filter? Everything I can find seems to assume that the default outcome of any filter logic must be a redirect.
Thanks
EDIT: I've come to the conclusion that I am simply not using the filtering method in the way it was intended, and simply placing the handler in my controller method. But I would still like to know if it is possible to return data from a filter.
In a controller:
if(Request::ajax()){
return Response::json(['message' => 'Hi. Your request was ajax!', 'status' => 1]);
}
The simple solution I found for that is to use Session::flash which populates data for the next request only and you can easily get the result anywhere. So for example :
Route::filter('something', function() {
if(false) {
View:make('error); // or whenever you want
} else {
return Session:flash('result_var', $my_result_var);
}
});

Resources