How do I connect 4 tables in Laravel 7? - mysql

So basically I have 4 tables
The employees, payrolls and employees_payrolls(pivot table) table are already connected through a many-to-many relationship and is working fine. Is it possible to fetch the basic_pay(from positions table) column through positions_id at employees table(which is already connected through the many-to-many relationship) so that I can perform calculation on payroll table that will base on employees basic pay?

you can not use $payroll->employees->positions->basic_pay because $payroll->employees
this gives you a collection of employees, each employee has many positions, so if you perform $payroll->employees->positions->basic_pay it makes collections in a collection, like below :
Payroll
Employee-1
Position-1->basic_pay
Position-2->basic_pay
Employee-2
Position-1->basic_pay
Position-2->basic_pay
.
.
.
if you perform $payroll->employees->positions->basic_pay the structure does not make sense in Laravel collection so you first perform $payroll->employees then loop through each and perform second loop on $employee->positions and next you will get $position->basic_pay

You will need to add a belongsTo relationship in your Employee model:
/**
* Get the employee's position.
*/
public function position()
{
return $this->belongsTo(Position::class,'positions_id');
}
Now if you wish to access it you will need to do the folllowing:
//get a payroll from database
$payroll = Position::find(1);
//get your payroll employees then iterate through each one
foreach($payroll->employees as $employee) {
//access to this employee position attributes
$employee->position;
}

Related

Laravel Eloquent - auto-numbering on has many relationship

I'm very much a beginner when it comes to database relationships hence what I suspect is a basic question! I have two database tables as follows:
Projects
id
company_id
name
etc...
rfis
id
project_id (foreign key is id on the Projects table above)
Number (this is the column I need help with - more below)
question
The relationships at the Model level for these tables are as follows:
Project
public function rfi()
{
return $this->hasMany('App\Rfi');
}
RFI
public function project()
{
return $this->belongsTo('App\Project');
}
What I'm trying to achieve
In the RFI table I need a system generated number or essentially a count of RFI's. Where I'm finding the difficulty is that I need the RFI number/count to start again for each project. To clarify, please see the RFI table below which I have manually created with the the 'number' how I would like it displayed (notice it resets for each new project and the count starts from there).
Any assistance would be much appreciated!
Todd
So the number field depends on the number of project_id in the RFI table. It is exactly the number of rows with project_id plus one.
So when you want to insert a new row, you calculate number based on project_id and assign it.
RFI::create([
'project_id' => $project_id,
'number' => RFI::where('project_id', $project_id)->count() + 1,
...
]);
What I understood is that you want to set the value of the "number" field to "1" if it's a new project and "increment" if it's an existing project. And you want to automate this without checking for it every time you save a new row for "RFI" table.
What you need is a mutator. It's basically a method that you will write inside the desired Model class and there you will write your own logic for saving data. Laravel will run that function automatically every time you save something. Here you will learn more about mutators.
Use this method inside the "RFI" model class.
public function setNumberAttribute($value)
{
if(this is new project)
$this->attributes['number'] = 1;
else
$this->attributes['number']++;
}
Bonus topic: while talking about mutators, there's also another type of method called accessor. It does the same thing as mutators do, but just the opposite. Mutators get called while saving data, accessors get called while fetching data.

In MySQL how can I check through array of sub ids?

I have a table in MySQL called bundles, this table has a column called attractions_array which is a comma separated list of "attraction ids" e.g 41,13,60
attractions is another table in the database that has all the info about each of these attractions.
I have figured out how to get the first id from the array using: substring_index(attractions_array,',',1) but this isn't too helpful.
I somehow need to check through each of these ids from their own attractions table to do things like:
Average & total price for all of the attractions
Make sure the attraction is still available
etc...
How would this be possible in MySQL? I don't even know where to start looking.
If MySQL was PHP I would probably write something like this to get the job done:
foreach ($bundles as $bundle) {
// init pricing
$bundle->price_count = 0;
$bundle->price_total = 0;
// each of the attractions
$attractions = explode(",", $bundle->attractions_array);
foreach ($attractions as $attraction) {
// no longer available
if (!$attraction->available) {
continue 2;
}
// count pricing
$bundle->price_count++;
$bundle->price_total += $attraction->price;
}
// average pricing
$bundle->price_average = $bundle->price_total / $bundle->price_count;
}
My current statement
SELECT * FROM `bundles` LIMIT 0,10
Is something like this even possible in MySQL?
Following relational-model approach, you should create a relation between the table 'bundles' and the table 'attractions' that is not based on a list of ids in a field like you did. If the relation between 'bundles' and 'attractions' is many to many, that means bundles can have many attractions and attractions can be related to many bundles, you need to do something like this:
table bundles pivot table table attractions
id name id_bundles id_attract id name
where in your pivot table the id_bundles and id_attract have foreign key constraint relative to bundles and attractions.
With a simple join you will be able at this point to retrieve what you need easily.
A MySQL query example to retrieve all the attractions related to one bundle could be:
SELECT * FROM attractions JOIN pivot_table ON (pivot_table.id = attractions.id) where pivot_table.id = customIdbundles
where customIdbundles is the id of the bundle you need info about.

Laravel 4 Eager Loading filtering and selecting only matching results

I'm trying to output the filter results with only matching elements.
I have two tables (in the real project, which will be 5), let's say companies and projects. A company may have more than one project or may not have any.
These are the relations:
/app/models/Company.php
<?php
class Company extends Eloquent {
public function projects() {
return $this->hasMany('Project','companyID');
}
protected $table = 'companies';
}
/app/models/Project.php
<?php
class Project extends Eloquent {
public function companies() {
return $this->belongsTo('Company','companyID');
}
}
What I want to do is, I want to get results of them both but only with matching parameters.
I've tried this:
return Company::with(array('projects'=>function($query){
$query->where('id',99); //project's id is 99
}))->get();
This is the output JSON
If I change the value from 99 to 1 (there is a result with products.id of 1), it changes into this:
I only want to get the second result from the second JSON i've posted.
As you can see in the second JSON (I'm using this parser to check), all companies are loaded regardless of the project, and only the rows matched have the object projects.
There will be more 'with's and I don't know how to filter only matching elements.
I also tried having() inside closure, but it's still same:
$query->having('projects.id','=',99);
Is there a way to filter only matching results (without using a loop) which the output will only include the results having the matched projects object?
Edit: Actually, 5 tables will be filtered.
companies, projects, works, users and user_works
Let's say;
"Companies" have many projects.
"Projects" have many works
"Works" have many users, also "Users" may have more than one work (pivot table user_works).
All relations are set correctly from models.
I want to do a global searching to these.
Something like: "Bring me the user id 1's works which has company id of 5 and project id of 4", but none of the fields are mandatory.
So these are also valid for searching: "Bring me everyone's works on project id of 2", or "bring me id 2's works", or "bring me all the works starting from today", "bring me the id 1's works on project 2", "Bring me this year's works done of company id 1".
Thanks in advance
Using whereHas() is the solution on my case. It filters relation and affects the results returned in the main query.
If you have the id of the project, would it make more sense to go that route? $project = Project::find(99); and then the company variables would be accessible with $project->companies->name;
It would make more sense to rename the companies() function to company() because a project will only ever belong to one.

Using LINQ and Entity how do I return values of a many-to-many relationship

I have two entities, Account and Subscription with a many-to-many association between them. I can't seem to find in the tutorials anywhere how to do the following:
I want to find all the Accounts with a Subscription of type x. If I wasn't using the Entity framework I could join to the AccountSubscription table, but that isn't accessible via Entity. Do I have to create a special entity if I need to query on a many-to-many relationship?
EF should create a navigation property for a many-to-many relationship. Then you should be able to do something like this:
var accounts = from a in Accounts
where a.Subscriptions.Any(s => s.SubscriptionType == "something")
select a;
For example, I have a simple db with a many to many relationship between Products and Groups:
And EF creates the association in the model:
So I can create a query like this (here including the Groups so I can see the Category):
What about something like this:
List<Accounts> myAccounts = //get accounts;
foreach(Accounts a in myAccounts)
{
foreach(Subscriptions s in a)
{
//add it to a global list?
}
}

Logical Column in MySQL - How?

I have a datamodel, let's say: invoices (m:n) invoice_items
and currently I store the invoice total, calculated in PHP by totalling invoice_items, in a column in invoices. I don't like storing derived data as it paves the way for errors later.
How can I create a logical column in the invoices table in MySql? Is this something I would be better handling in the PHP (in this case CakePHP)?
There's something called Virtual Fields in CakePHP which allows you to achieve the same result from within your Model instead of relying on support from MySQL. Virtual Fields allow you to "mashup" various data within your model and provide that as an additional column in your record. It's cleaner than the other approaches here...(no afterFind() hacking).
Read more here: http://book.cakephp.org/view/1608/Virtual-fields
Leo,
One thing you could do is to modify the afterFind() method in your model. This would recalculate the total any time you retrieve an invoice (costing runtime processing), but would mean you're not storing it in the invoices table, which is apparently what you want to avoid (correct if I'm wrong).
Try this:
class Invoice extends AppModel {
// .. other stuff
function afterFind() {
parent::afterFind();
$total = 0;
foreach( $this->data['Invoice']['InvoiceItems'] as $item )
$total += ($item['cost'] * $item['quantity']);
$this->data['Invoice']['total'] = $total;
}
}
I may have messed up the arrays on the hasMany relationship (the foreach line), but I hope you get the jist of it. HTH,
Travis
Either you can return the derived one when you want it via
SELECT COUNT(1) as total FROM invoice_items
Or if invoices can be multiple,
//assuming that invoice_items.num is how many there are per row
SELECT SUM(num) as total FROM invoice_items
Or you can use a VIEW, if you have a certain way you want it represented all the time.
http://forge.mysql.com/wiki/MySQL_virtual_columns_preview
It's not implemented yet, but it should be implemented in mysql 6.0
Currently you could create a view.