Populate a Select Box with Eagerloading - php

Any idea what the best way would be to populate a select box with eagerloading?
For example: I can eagerload a hasOne relation like so which works fine for showing the initial status.
Order Model
public function status()
{
return $this->hasOne('OrderStatus','id','status');
}
But then on the order page I also need to populate a select box with all statuses so a user can change the order status.
Order Status Model
public function allStatuses()
{
return OrderStatuses::all();
}
and then I try calling with the dot notation, but that does not work
$order::with('orderStatus','orderStatus.allStatuses')->whereId(1000)->get();
Basically, my views contain a lot of drop-down for things like country, state, etc. I know I can send them through the view with multiple variables, but I would like to just call everything in one collection to the view if possible.
I know the above is probably wrong, but any suggestion on the best way to do this would be appreciated.
Right now I am calling all my common selects from a service provider and then import my repos into that so I can call directly from my view like FormList::getStates(), FormList::getCountries(), etc.. Not sure if this is the best way.

Related

Laravel: How to dynamically create and name views?

I am making a website for college administration where professors log in and assign marks to the students they are teaching.
There's a table, called "IA_Marks" in my database:
|Student_ID|Subject_Code|Name|Marks1|Marks2|Marks3|Semester|Division|
There's also a table called "Classroom_Mapper" in my database, that helps map a professor to a classroom, with a subject:
|Prof_ID|Subject_Code|Semester|Division|
This is a method in my controller:
public function showTable(){
$sem = DB::table('classroom_mappers')->where('Prof_ID', auth()->user()->PID)->pluck('semester');
$division = DB::table('classroom_mappers')->where('Prof_ID', auth()->user()->PID)->pluck('division');
$data = DB::table('iamarks')->where([['semester','=',$sem],['division','=',$division]])->get();
return view('ia',compact('data'));
}
Using this, I can fetch rows that belong to the professor who has logged in.
But, there's a problem.
Say the professor teaches two subjects, in two semesters. Then, the where clause will return multiple results from the mapper table.
For example:
select semester from classroom_mapper where Prof_ID=auth()->user()->Prof_ID
output:
8
5
Then the students from both 5th and 8th semester will be shown on his dashboard. Our target semester was, say 5th. Then it'll be a problem.
Registering for a subject, is done as shown here:
form screenshot
Let's call the subject being registered in the screenshot "SUBJECT 4".
It is a subject for the 5th semester, division A.
I want to dynamically make a button(SUBJECT 4) on the dashboard, which when clicked, sends the semester(5) and division(A) of choice to the controller.
Dashboard Screenshot
This button should open a newly made page with name of the subject(subject4.blade.php), where the database table contents for target semester and division(5 and A) will be shown.
How do I make this dynamic view creating button which sends specific info to controller? Is it even possible?
There are a few ways to do this with Laravel, but my goto is usually to create a single blade template for each view (dashboard, subject, etc.) that can be dynamically populated -- assuming that the layout for each subject view is the same.
In your dashboard view, you could generate a url for each button that uses a format like this: http://cas.jce.in/subject/semester/5/division/a/
Next, create a route that uses a couple of paramaters, something like this:
Route::get('/subject/semester/{semester_id}/division/{division_id}', 'ControllerName#showSubject');
More info here: https://laravel.com/docs/5.8/routing#required-parameters
Then in your controller, add a showSemester function like this:
function showSubject($semester_id, $division_id){
$data = DB::table('table_name')->where('semester', '=', $semester_id)->where('division', '=', $division_id)->first();
return view('subject', ['data'=>$data, 'semester'=>$semester_id, 'division'=>$division_id]);
}
Your route parameters are available to the controller, in order of appearance. So we can add $semester_id and $division_id as the first two parameters of our function. Next, we'll to the database work to retrieve the data we need before returning everything to a view.
Note here that we're using a single view rather than dynamically selecting one. You could create individual views for each subject, but im thinking you probably don't need to unless the layout of each one is unique in some way. In that case, you can simply do something like this, but I'd generally try to avoid it.
$view = 'subject'.$data->subject_id;
return view($view, ['data'=>$data, 'semester'=>$semester_id, 'division'=>$division_id]);
Also, just a quick note ... you may consider adjusting your database queries from above to use a select statement rather than pluck. The end result is the same, but using a select can boost performance by only loading the data you want ... rather than loading everything up front and throwing most of it away.
$sem = DB::table('classroom_mappers')->where('Prof_ID', Auth()->user()->PID)->pluck('semester');
... becomes ...
$sem = DB::table('classroom_mappers')->select('semester')->where('Prof_ID', auth()->user()->PID)->get();

Laravel sort and save position in database

I have a table in my database called 'users', it has these columns:
id, points, rank.
Everytime I update points, I want to sort all users by points desc and save rank position in that column.
I was wondering about getting all rows from database, sort them by using collection method and using update to update rank column. But i was wondering about how intense it would be to update 100k users one by one.
Maybe some experienced Laravel developers can suggest me a best possible solution in this situation?
If you want data orderred by points you can use
$user = User::orderBy('point', 'desc')
->get();
Alright the things you need here is an Eloquent Observer so each time you update the points on update it will sort all the users by points desc and save the rank position.
However with that amout of data I would never use collections or anything simillar as it will be slow, I suggest you using raw methods to do that.
Now there are two possible options if latency matters on this case then you can place all the logic in the observer itself like below:
First of seperate the observer logic to a different class like:
namespace App\Observers;
class UserRankObserver
{
public function updated($model)
{
//check if points column its updated
//if yes then run the query to sort all user by points and save rank
}
}
Then on your User model you need to register the observer like :
public static function boot()
{
parent::boot();
User::observe(new \App\Observers\UserRankObserver);
}
Case two when the latency does not matter then I suggest on the method updated I would just pass the data to a background job to complete the action like :
namespace App\Observers;
class UserRankObserver
{
public function updated($model)
{
//check if points column its updated
//if yes then pass the data to a background job to complete the task.
(new UpdateUserRankJob($data))->dispatch();
}
}

Concept of table relations in Laravel

I have two tables:
Cards
Notes
Each Card has multiple Notes. So there is a relation between them like this:
class Card extends Model {
public function notes ()
{
return $this->hasMany(Note::class);
}
}
Ok well, all fine.
Now I need to understand the concept of these two lines:
$card()->$notes()->first();
and
$card()->$notes->first();
What's the difference between them? As you see in the first one $note() is a function and in the second one $note isn't a function. How will they be translated in PHP?
The first one points out to the card table and the second one points out to the notes table, right? or what? Anyway I've stuck to understand the concept of tham.
I don't know about $ before the $notes in your code but if you trying to say something like this.
1- $card->notes()->first();
2- $card->notes->first();
In the code in line 1, first you have a $card model and then you wanted to access all notes() related to that $card, and because of adding () after notes you simply call query builder on notes, show you can perform any other database query function after that, something like where, orderBy, groupBy, ... and any other complicated query on database.
But in the second one you actually get access to a collection of notes related to that $card, we can say that you get all related notes from database and set it into laravel collections and you are no more able to perform database query on notes.
Note: because laravel collections have some methods like where(), groupBy(), whereIn(), sort(), ... you can use them on the second one, but in that case you perform those methods on collections and not database, you already get all results from database

Laravel eager loading issue

Say I have an orders table and a users table and a guests table, for a company who accept orders from both users and guests.
I also have a is_guest boolean on the orders table which lets me know quickly whether the order has been made by a guest or a registered user.
I have a model method called customer which returns the eloquent relation like so:
public function customer()
{
return $this->is_guest ? $this->belongsTo('Guest', 'user_id') : $this->belongsTo('User', 'user_id');
}
This works very well when I pass orders to the view and access the customer's data like so:
// Maps to either $order->user->firstname OR $order->guest->firstname
echo $order->customer->firstname;
But when I try to use this functionality when using eager loading it doesn't quite work:
$orders = Order::with('customer')->get();
return Response::make($orders);
It only returns the eager loaded customer data for either the user or the guest and never both.
I'm wondering why this is and how to get round it?
Is it because of the way the eager loading works - it only calls the customer() method once just as it only hits the database once, so whatever the first result of the query is, it will use that to determine the rest of the query too?
If I am trying to get a JSON response of all the order data with all of the customer's details too, how would I do that?
Thanks.
UPDATE
Yes, turns out I was abusing the Laravel relationship method by adding a condition.
Using the polymorphic relations is a much better approach as suggested by #lukasgeiter.
http://laravel.com/docs/4.2/eloquent#polymorphic-relations
I did have trouble loading other relations based on the polymorphic relation. For example if both User and Guest had corresponding tables UserDetail and GuestDetail then I couldn't get the eager loading to work. So I added this to both the User and Guest models:
protected $with = ['detail'];
This means that whenever the customer polymorphic relation is eager loaded, then both User and Guest will load their relationships automatically. I think I could have also used the 'lazy loading' functionality $order->load('customer') but I didn't try it out.
public function detail()
{
return $this->hasOne('UserDetail');
}
Thanks guys.

additionals properties of a model in cakephp?

I'm starting to use cakePhp and I would like to know:
When I do a query(like with $this->Product->find(...)), I receive an array, right?
Then:
-If I've some non-db fields with default values that I've to display for each product, how do I do?
I saw virtual fields, but I cannot manage to put a static var into it
You can use the solution Anh Pham provided another thing you could do, if it's just setting the values to display them, is add them to the array in your controller after you have the results:
$result['Model']['desired_field_name'] = $static_field;

Categories