Laravel: What are functions in routes doing? - laravel

Can anyone tell why the documentation of Laravel, and others, show functions in routes that return / do something? In what context can you use this?
For example, I try to figure out Molly Connect.
Here is the corresponding code from https://github.com/mollie/laravel-mollie/blob/master/docs/mollie_connect.md
Route::get('login', function () {
return Socialite::with('mollie')
->scopes(['profiles.read']) // Additional permission: profiles.read
->redirect();
});
Route::get('login_callback', function () {
$user = Socialite::with('mollie')->user();
Mollie::api()->setAccessToken($user->token);
return Mollie::api()->profiles()->page(); // Retrieve payment profiles available on the obtained Mollie account
});

Its just a shortcut, to avoid having to create separate controller files and indirectly referencing those functions. Functionally, your example is no different from doing this:
Route::get('login_callback', 'LoginController#callback')
And then, LoginController.php
class LoginController
{
public function callback()
{
$user = Socialite::with('mollie')->user();
Mollie::api()->setAccessToken($user->token);
return Mollie::api()->profiles()->page();
}
}
See here

Related

Sending different data from different method on same route - laravel 8

I am trying to get order data in order tab and profile details data in profile tab.
Is it possible to achieve ???
If Yes, then please tell me how ?
If No, then please tell me, laravel is the most advance framework of PHP, why we can't send multiple data from multiple methods in same View ?
Controller
public function GetOrders()
{
$gtord = DB::table('orders')->where('email',Session::get('email'))->get();
return view('/my-account')->with('gtord',$gtord);
}
public function ProfileEdit()
{
$data = DB::table('customers')->where('email',Session::get('email'))->first();
return view('/my-account')->with('data',$data);
}
Routes
Route::get('/my-account', 'App\Http\Controllers\CustomerController#ProfileEd');
Route::get('/my-account', 'App\Http\Controllers\CustomerController#GetOrders');
Thank you in advance
You can't have multiple routes with the same 'signature', ie method and url.
If you're just showing/hiding tabs using JS, what you can do is return the view with two variables, eg:
public function AccountView()
{
$data = DB::table('customers')->where('email',Session::get('email'))->first();
$gtord = DB::table('orders')->where('email',Session::get('email'))->get();
return view('/my-account')->with(['data' => $data, 'gtord' => $gtord]);
}
And then just use one route:
Route::get('/my-account', 'App\Http\Controllers\CustomerController#AccountView');
If the two tabs are different urls, or you're using Vue or similar you would have two distinct routes with different signatures.
First, you can't have 2 same routes with the same method. It's quite logical and necessary. Otherwise, the whole routing system would collapse.
On the other hand, you can have a function in the controller, and call the other functions to collect data.
// web.php
Route::get('/my-account', 'App\Http\Controllers\CustomerController#index');
// controller
public function index()
{
$orders = $this->getOrders();
$profile = $this->getProfiles();
return view('yourView', compact(['orders', 'profile']));
}
public function getOrders()
{
//
}
public function getProfiles()
{
//
}
BTW, it's a better practice to move custom function to models, services or traits, and keep only the functions of 7 verbs in the contoller.

Route not defined when passing parameter to a route

I have a named route with a parameter which looks like this...
Route::get('/profile/{user_id}', [ProfileController::class, 'profile'])->name('profile');
Now in one of my controller,
I have a function that calls this route like this
public function _myFunction($some_data) {
return redirect()->route('profile', [$some_data->user_id]);
}
and in my ProfileController's profile() function, I have this.
public function profile() {
return view('modules.profile.profile');
}
I've followed the documentation and some guides I found in SO, but I got the same error,
"Route [profile] not defined."
can somebody enlighten me on where I went wrong?
Here's what my routes/web.php looks like...
Route::middleware(['auth:web'])->group(function ($router) {
Route::get('/profile/{user_id}', [ProfileController::class, 'profile'])->name('profile');
});
When calling the route, you should pass the name of the attribute along with the value (as key vaue pairs). In this case, your route is expecting user_id so your route generation should look like this:
return redirect()->route('profile', ['user_id' => $some_data->user_id]);
Read more on Generating URLs To Named Routes in Laravel.
I solved the issue, and its really my bad for not providing a more specific case information and made you guys confused.
I was using socialite and called _myFunction() inside the third party's callback..
After all, the problem was the socialite's google callback, instead of placing the return redirect()->route('profile', [$user->id]) inside _myFunction(), what I did was transfer it to the callback function.
So it looked like this now...
private $to_pass_user_id;
public function handleGoogleCallback()
{
try {
$user = Socialite::driver('google')->user();
$this->_myFunction($user);
return redirect()->route('profile', [$this->to_pass_user_id]);
} catch (Exception $e) {
dd($e->getMessage());
}
}
public function _myFunction($some_data) {
... my logic here
$this->to_pass_user_id = $some_value_from_the_logic
}

Returning same variable to every controller in laravel

I need to send the same result to almost every view page, so I need to bind the variables and return with every controller.
My sample code
public function index()
{
$drcategory = DoctorCategory::orderBy('speciality', 'asc')->get();
$locations = Location::get();
return view('visitor.index', compact('drcategory','locations'));
}
public function contact()
{
$drcategory = DoctorCategory::orderBy('speciality', 'asc')->get();
$locations = Location::get();
return view('visitor.contact', compact('drcategory','locations'));
}
But as you see, I need to write same code over and over again. How can I write it once and include it any function whenever I need?
I thought about using a constructor, but I cannot figure out how I can implement this.
You are able to achieve this by using the View::share() function within the AppServicerProvider:
App\Providers\AppServiceProvider.php:
public function __construct()
{
use View::Share('variableName', $variableValue );
}
Then, within your controller, you call your view as normal:
public function myTestAction()
{
return view('view.name.here');
}
Now you can call your variable within the view:
<p>{{ variableName }}</p>
You can read more in the docs.
There are a few ways to implement this.
You can go with a service, a provider or, like you said, within the constructor.
I am guessing you will share this between more parts of your code, not just this controller and for such, I would do a service with static calls if the code is that short and focused.
If you are absolutely sure it is only a special case for this controller then you can do:
class YourController
{
protected $drcategory;
public function __construct()
{
$this->drcategory = DoctorCategory::orderBy('speciality', 'asc')->get();
}
// Your other functions here
}
In the end, I would still put your query under a Service or Provider and pass that to the controller instead of having it directly there. Maybe something extra to explore? :)
For this, you can use View Composer Binding feature of laravel
add this is in boot function of AppServiceProvider
View::composer('*', function ($view) {
$view->with('drcategory', DoctorCategory::orderBy('speciality', 'asc')->get());
$view->with('locations', Location::get());
}); //please import class...
when you visit on every page you can access drcategory and location object every time
and no need to send drcategory and location form every controller to view.
Edit your controller method
public function index()
{
return view('visitor.index');
}
#Sunil mentioned way View Composer Binding is the best way to achieve this.

How to catch any link that came from upload/ in laravel 5?

im new in laravel 5.2, I just want to ask how you can catch a link that came from uploads like: http://sitename.com/uploads/59128.txt? I want to redirect them to login page if they tried to access any of route or link that came from uploads/{any filename}.
Yes you can achieve by protecting your route with auth middleware,
make a small FileController
class FileController extends Controller {
public function __construct()
{
$this->middleware('auth');
}
public function getFile($filename)
{
return response()->download(storage_path($filename), null, [], null);
}
}
and then in routes.php
Route::get('file/{filename}', 'FileController#getFile')->where('filename', '^[^/]+$');
And that's it. Now, your authenticated users can download files from storage folder (but not its subfolders) by calling http://yoursite.com/file/secret.jpg. Add you can use this URL in src attribute of an image tag.
answer's original source!
#xerwudjohn simple you can't.
When this file is in the public folder, everyone can access it whitout being logged in.
One method I tried for some minutes, create a new route:
Route::group(['middleware' => ['web', 'auth']], function () {
Route::get('/download/{id}', 'DownloadController#showFile');
});
create the function showFile in the DonwloadController
public function showFile($id)
{
return redirect('/image/'.$id.'.txt');
}
or use a Model to read uniqueIds out of any table and get the realfile name.
Cheers

Testing redirect links to external sites

I have a link on a page /my/example/page which links to a laravel route my.route.
Route
Route::group(['middleware' => ['auth']], function () {
Route::group(['middleware' => ['Some\Custom\Auth\Middleware:1']], function () {
Route::match(['GET', 'POST'], '/my/route/to/external/controller', 'exampleController#externalLink')->name('my.route');
}
}
Link on /my/example/page
Link
This route /my/route/to/external/controller points to this controller method externalLink in the exampleController controller, which returns the url for the href to use
public function externalLink()
{
return $this->redirect->away('www.externalsite.com');
}
My test is
$this->visit(/my/example/page)
->click('Link')
->assertRedirectedToRoute('my.route');
I constantly get the error
Symfony\Component\HttpKernel\Exception\NotFoundHttpException
when I use the click() testing method.
I can catch this using #expectedException but his doesn't help as I am expecting to see a different page.
I have also tried (not together);
->assertResponseStatus(200);
->seePageIs('www.externalsite.com');
->assertRedirect();
->followRedirects();
From browser inspection, when the url is clicked I get
http://www.example.com/my/route/to/external 302
http://www.externalsite.com 200
How can I functionally test the button being clicked and redirecting to an external site?
I am struggling with a similar problem right now, and I have just about given up on testing the endpoint directly. Opting for a solution like this...
Test that the link contains proper information in the view:
$this->visit('/my/example/page')
->seeElement('a', ['href' => route('my.route')]);
Moving the logic in the controller to something you can test directly. The Laravel\Socialite package has some interesting tests that might be helpful if you do this...
class ExternalLinkRedirect {
public function __construct($request){
$this->request = $request;
}
public function redirect()
{
return redirect()->away('exteranlsite.com');
}
}
Then test it directly
$route = route('my.route');
$request = \Illuminate\Http\Request::create($route);
$redirector = new ExternalLinkRedirect($request);
$response = $redirector->redirect();
$this->assertEquals('www.externalsite.com', $response->getTargetUrl());
A simple way is to use the get method instead of visit.
An example:
$this->get('/facebook')
->assertRedirectedTo('https://www.facebook.com/Les-Teachers-du-NET-516952535045054');

Resources