How to use multiple models in one controller - laravel

I have six models that I need to get in one instance in my controller. How can I do that?
I have my six models:
CommentaireCritique
CommentaireNews
CommentaireDossier
CommentaireEpisode
CommentaireSerie
CommentaireTrailer
They all have the same structure in my database, and I would like to show the latest comms on one single page. I don't know if it's possible to bind them in a single controller. I tried that, but it's not working.
public function index()
{
$comms = CommentaireCritique::all() && CommentaireNews::all()
&& CommentaireDossier::all() && CommentaireEpisode::all()
&& CommentaireSerie::all() && CommentaireTrailer::all()
->get();
return view('admin.commentaires.index', compact('comms'));
}

just after the namespace , before the class declaration
use yourAppNameSpace/modelName

There is no limits to the number of models you can instantiate in your controller as long as you declare them above correctly.I think what you need is way to merge the result of all the models if that is so, then you have to use the merge method, otherwise can you please clarify a little bit your question.

yes, you can retrieve them at one controller,
you're already halfway there, you should separate on different variable
public function index()
{
$comms = CommentaireCritique::all()
$news = CommentaireNews::all()
$dossier = CommentaireDossier::all()
$episodes = CommentaireEpisode::all()
$series = CommentaireSerie::all()
$trailers = CommentaireTrailer::all()
return view('admin.commentaires.index', compact('comms','news','dossier','episodes','series','trailers'));
}
if you want put them in one variable, you can use collection docs

All of the results from all() function returns laravel collections. So use concat() function to concatenate all those into one collection
public function index()
{
$coms = CommentaireCritique::all()
->concat(CommentaireNews::all())
->concat(CommentaireDossier::all())
->concat(CommentaireEpisode::all())
->concat(CommentaireSerie::all())
->concat(CommentaireTrailer::all());
return view('admin.commentaires.index', compact('comms'));
}

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.

How do I call `with` directly on an object thats been fetched through a route with the same results as if it were fetched through `where`?

How do I call with directly on an object thats been automagically fetched through a route with the same results as if it were fetched through where?
Let me explain through code!
My route (same in both):
Route::get('post/{post}', 'PostsController#show');
Alternative 1:
My Controller:
public function show(Post $post){
$postWithComments = Post::where('id', $post->id)->with('comments')->first();
}
Output: The comments of the intended post.
Alternative 2:
My Controller:
public function show(Post $post){
$postWithComments = $post->with('comments')->first();
}
Output: The comments from the first of ALL posts.
Desired output: Same as alternative one.
How can I modify the query in alternative 2 to output the same as alternative 1?
I am thinking that it is unnecessary to make first the where-request as I already have the object loaded. So I am thinking that I would want to do this to reduce DB calls. Or am I thinking wrong?
There are two ways to solve this:
Query related data with lazy loading:
$post->comments; // this did the trick - comments for post will queried here
return $post; // here posts already has comments collection
Setup model binding and use eager loading:
At your Post model add resolveRouteBinding method:
class Post extends Model
{
public function resolveRouteBinding($id)
{
return $this->where('id', $id)->with(['comments'])->first();
}
}
Then your controller will recieve Post instance with already loaded comments

Returning other entry in the url includes the first entry as well

public function show(Criminal $criminal){
$profile = Criminal::with(['profile','crimes'])->findOrFail($criminal);
dd($profile);
}
I have this method and it should return like this when I type localhost:8000/criminal/1
But when I say like criminal/3
it also returns the criminal/1 json output like this :
the first entry looks like this :
try this
public function show(Criminal $criminal, $id){
$profile = Criminal::with(['profile','crimes'])->findOrFail($id);
dd($profile);
}
There is no need to query the database again, the model passed to your function is already an eloquent model.
public function show(Criminal $criminal) {
dd($criminal);
}
If you really want to lazy load the relations, this can be done as follows:
public function show(Criminal $criminal) {
$criminal->load('profile', 'crimes')
dd($criminal);
}
This should not be necessary however as Laravel loads relations when needed.

Refactor Repeated Controller Methods in Laravel

I'm a bit confused about my code in Laravel. I have a member that can subscribe to one or more lessons. I have three tables: members, lessons, and lesson_member.
I created a member form, and from this form, I can register the member in the lesson (I need to get the lesson id, and I put the record in the pivot table).
Then I have the lesson form; I can create a new lesson and put inside one or more members (in this case I need the member code).
Those two functions are nearly the same, but the parameters are different. In my solution, I created two different controllers with two different functions.
LessonController
<?php
public function addMember(Request $request)
{
$lessonMember = new LessonMember();
$lessonId = $request->session()->get('lessonId', 1);
if ((!($lessonMember::where('lesson_id', '=', $lessonId)
->where('license_member_id', '=', $request->memberId)
->exists()))) {
$lessonMember->lesson_id = $lessonId;
$lessonMember->license_member_id = $request->memberId;
$lessonMember->save();
$member = LicenseMember::find($request->memberId)->member;
return response()->json(['user_saved' => $member, 'llm' => $lessonMember, 'actualMembers' => $actualMembers]);
}
}
MemberController
<?php
public function addLesson(Request $request)
{
$lessonMember = new LessonMember();
$memberId = $request->session()->get('memberId', 1);
if ((!($lessonMember::where('lesson_id', $request->lessonId)
->where('license_member_id', $memberId)
->exists()))) {
$lessonMember->lesson_id = $request->lessonId;
$lessonMember->license_member_id = $memberId;
$lessonMember->save();
$member = LicenseMember::find($memberId)->member;
return response()->json(['user_saved' => $member, 'llm' => $lessonMember]);
}
}
I have the same problem with the removeFromLesson() method and in the updateLessonMember method, but the solution should be similar. It is for sure not DRY, and I think I have to put some code in the model (or somewhere else), but I don't know how to proceed. I want to refactor to have a clean solution. I read about traits, but I don't know if it's the right way to follow.
LessonController and MemberController extends a BaseController.
Inside that base controller, create a function called add_lesson_member(you can call it whatever you want)
Then you just need to call this function using $this->add_lesson_member() inside your LessonController or MemberController.

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.

Resources