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

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.

Related

How do I pass a value in my Route to the Controller to be used in the View in Laravel?

I have 2 entities called Match and Roster.
My Match routes are like this
http://localhost:8888/app/public/matches (index)
http://localhost:8888/app/public/matches/14 (show)
In order to view/create the teams for each specific match I added the routes for the match roster like this:
Route::get('/matches/'.'{id}'.'/roster/', [App\Http\Controllers\RosterController::class, 'index']);
Now I need that {id} i have in my URL to pass it to the Controller here:
public function index()
{
return view('roster.index');
}
I need that for a couple of things. First I need to do a search on the Roster table filtering by a column with that value, so I can display only the players that belong to that match.
Second, I need to pass it on to the view so I can use it on my store and update forms. I want to add or remove players from the roster from that same index view.
How can I do that?
#1 You can get the route parameter defined on ur routes via request()->route('parameter_name').
public function index()
{
// get {id} from the route (/matches/{id}/roster)
$id = request()->route('id');
}
#2 You can pass the data object via using return view(file_name, object)
public function index()
{
// get {id} from the route (/matches/{id}/roster)
$id = request()->route('id');
// query what u want to show
// dunno ur models specific things, so just simple example.
$rosters = Roster::where('match_id', '=', $id);
// return view & data
return view('roster.index', $rosters);
}
#3 It can be done not only index but also others (create, store, edit, update)
In addition, STRONGLY RECOMMEND learn Official Tutorial with simple example first.
Like a Blog, Board, etc..
You need to know essentials to build Laravel App.
Most of the time, I prefer named routes.
Route::get('{bundle}/edit', [BundleController::class, 'edit'])->name('bundle.edit');
In controller
public function edit(Bundle $bundle): Response
{
// do your magic here
}
You can call the route by,
route('bundle.edit', $bundle);

Route model binding with multiple wildcards

How to explicitly say to route model binding to fetch only related categories? I have my web.php file as follows:
Route::get('/catalog/{category}', [CategoryController::class, 'index'])->name('category.index');
Route::get('/catalog/{category}/{subcategory}', [SubcategoryController::class, 'index'])->name('subcategory.index');
Route::get('/catalog/{category}/{subcategory}/{subsubcategory}', [SubsubcategoryController::class, 'index'])->name('subsubcategory.index');
Subsubcategory controller:
public function index(Category $category, Subcategory $subcategory, Subsubcategory $subsubcategory)
{
$subsubcategory->load('product')->loadCount('product');
$products = Product::where('subsubcategory_id', $subsubcategory->id)->orderByRaw('product_order = 0, product_order')->get();
return view('subsubcategory.index', compact('subsubcategory', 'products'));
}
And model in question:
public function subcategory()
{
return $this->belongsTo(Subcategory::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
public function getRouteKeyName()
{
return 'slug';
}
It works partially ok. It loads all the slugs, but the problem is, let's say I have Samsung Subsubcategory with it's parent categories like:
catalog/mobile-phones/android/samsung
Whenever I modify url from catalog/mobile-phones/android/samsung to catalog/mobile-phones/ios/samsung it works, where in fact it should not. How to handle this second scenario?
PS: it also applies if I open subcategory and change category slug. But, obviously, if upper level category does not exists, it's going to throw 404.
You may want to explore the docs a bit in regard to explicit route model binding and customizing the resolution logic to get some ideas.
https://laravel.com/docs/8.x/routing#customizing-the-resolution-logic
The following is untested and I'm making some guesses about your table structures, but I think this should give you a basic concept of how you can alter route model binding to fit your needs. The same concept could also be applied to the {subcategory} binding, but with one less relationship check.
App/Providers/RouteServiceProvider.php
public function boot()
{
// ...default code...
// add custom resolution for binding 'subsubcategory'
Route::bind('subsubcategory', function($slug, $route) {
// check to see if category exists
if ($category = Category::where('slug',$route->parameter('category'))->first()) {
// check to see if subcategory exists under category
if ($subcategory = $category->subcategories()->where('slug',$route->parameter('subcategory'))->first()) {
// check to see if subsubcategory exists under subcategory
if ($subsubcategory = $subcategory->subsubcategories()->where('slug',$slug)->first()) {
// success, proper relationship exists
return $subsubcategory;
}
}
}
// fail (404) if we get here
throw new ModelNotFoundException();
});
}
I will note, however, that this makes a number of separate database calls. There may be more efficient ways to achieve the same goal through other methods if optimization is a concern.

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 make a laravel view that uses data from a controller but also still allows the controller to output raw JSON?

I have a controller that outputs data from the database in raw JSON format.
I want this to function as an API and allow anyone to make views with any technology that can consume the JSON i.e. Angular, Jquery/Ajax.
However I also want to make a view in Laravel.
So what's the best practice for creating a view from Laravel that uses data from a controller while still allowing the controller to output raw JSON?
The options I'm thinking of are to call the controller from the view(not good?) or to create extra routes.
Route::get('sample', function ()
{
$data = getDataFromSomewhere();
if (Request::ajax())
{
return Response::json($data);
}
return View::make('some.view', compact('data))
});
I would separate API controllers, but you could do something like this if you want one controller to handle all response formats:
URL:
mySite.com/getData?output=json
Controller:
public function index()
{
$data = MyModel::all();
switch(Request::query('output')){
case 'json':
return Response::json($data, $this->responseCode, $this->accessControl);
case 'xml':
return Response::make($data, '200')->header('Content-Type', 'text/xml');
default:
return View::make('data.myData', compact($data));
}
}

How to call several actions from within another action?

I'm migrating a non-MVC application to Laravel 4.2 and I'm unsure of the best way to accomplish this task. I have several reports created on routes like this:
/reports/this_report
/reports/that_report
/reports/another_report
These actions query the database, run a bunch of calculations, and generate some html tables and forms.
What I need to add now is a page like this:
/reports/dashboard
This dashboard page should display the output of all 3 reports in a condensed format, each with a "click to view details" link that takes the user to the main report page.
Is there a way for the dashboard action to call each of the report actions, and use their output as data in the dashboard view?
Here's a little code of how you would do this. I'm not exactly sure how you have everything structured, so you might have to adapt this a little.
Lets say you have a route for the dashboard like this.
Route::get('/reports/dashboard', DashboardController#showDashboard');
This route should call a controller method that will do your processing.
class DashboardController extends BaseController
{
public function showDashboard()
{
return View::make('dashboard')->with(array(
'report1_data' => $this->getReport1Data(),
'report2_data' => $this->getReport2Data(),
'report3_data' => $this->getreport3Data()
));
}
public function getReport1Data() { //calculations, return array of results }
public function getReport2Data() { //calculations, return array of results }
public function getReport3Data() { //calculations, return array of results }
public function showThisReport()
{
$data = $this->getReport1Data();
return View::make('report')->with(array('data' => $data));
}
public function showThatReport()
{
$data = $this->getReport2Data();
return View::make('report')->with(array('data' => $data));
}
public function showAnotherReport()
{
$data = $this->getReport3Data();
return View::make('report')->with(array('data' => $data));
}
}
So, this dashboard method will call the other methods (that you will also include in this controller) that will query the database and calculate the reports.
Then it returns a View with all of the data. The view will format the data and display it to the user.
Now, to make it so you can see the detailed view of each report, I suggest adding a couple more methods and routes to show detailed views.
Route::get('/reports/this_report', 'DashboardController#showThisReport');
Route::get('/reports/that_report', 'DashboardController#showThatReport');
Route::get('/reports/another_report', 'DashboardController#showAnotherReport');
I hope this helps! Good luck.

Resources