Laravel get items based on a many to many relation - mysql

How do I query in Laravel Eloquent the following criteria
having project, employees tables and a many to many binder project_member table, I want to get projects where a project is owned by logged in user as a team member.
in my Project model I have
/**
* #return mixed
*/
public function members()
{
return $this->belongsToMany('App\User', 'project_team', 'id', 'project');
}
and user table
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function team()
{
return $this->belongsToMany('App\Project', 'project_team', 'employee', 'project');
}
and I want to get all projects where logged in user is a member of a given project

Related

How to join two table in laravel 8 with no duplicate

I have two tables. Customer and address. The relationship of the table is that a CUSTOMER can have many ADDRESSES. So what I want as a result to my query is to get the list of customer and only one latest address
ADDRESS TABLE
id : 1
city:"cebu"
zip_code:"600"
cus_id:1
id:2
city:"mandaue"
zip_code:"6001"
cus_id:1
CUSTOMER TABLE
id: 1
name:"JOHN DOE"
What I want to get the customer "JOHN DOE" and the address with ID "2"
I'm using laravel query builder
If you want to get only one latest address, you can use hasOne same as :
// Customer model relation
public function lastestAddress()
{
return $this->hasOne(Address::class, 'customer_id')->orderBy('id', 'desc');
}
And
$model = Customer::with('lastestAddress')
you can use Eloquent ORM in laravel.
Eloquent :
You must setting in your customer model
Class Customer(){
public function address()
{
return $this->hasMany(Address::class, 'cuss_id', 'id')->latest();
}
in your Adress model :
Class Address(){
public function customer()
{
return $this->belongsTo(Customer::class, 'id', 'cuss_id')
}
Then in your controller you can call the model :
$data = Customer::with('address')->get();
So you have two tables: customers and addresses, with a "one customer can have many addresses" relationship.
In Laravel, we normally use Eloquent models to query the database. So to get a customer and all its addresses, we must first model the database; each table with its own Eloquent model. (See details in the docs.)
class Address extends Model
{
// although empty for now, this class definition is still important
}
class Customer extends Model
{
/**
* Get the latest address.
*/
public function currentAddress()
{
return $this->hasOne(Address::class, 'cus_id')->latestOfMany();
}
}
In the Customer model, our currentAddress() method defines how a Customer instance related to the Address instances.
It's like we're saying,
"A customer may have many Addresses. Just get one which is the latestOfMany. That's how we'll get the customer's currentAddress.
Now that we have the necessary Eloquent models setup, we can lookup John Doe and his current address.
$johnDoeId = 1;
// query the database for customer 1, including its current address
$johnDoe = Customer::with('currentAddress')->find($johnDoeId);
$johnDoe->currentAddress; // 👈 John's latest address, at Mandaue

Query multiple table relationships using Laravel Eloquent Models

I'm trying to query multiple tables using Laravel Eloquent Models with one to one, one to many and many to many relationships.
I have a forms table, a brands table a users table and a brand_groups pivot table.
Each form has one brand and one user:
forms
ID
user_id
brand_id
Brands do not have any foreign keys:
brands
ID
Users do not have any foreign keys:
users
ID
And there is a pivot table to create a many to many relationship for creating brand groups that have many users like brand members:
brand_groups
brand_id
user_id
I'm trying to get all the forms that belong to a user either by a direct ownership (forms.user_id) or by brand membership, all the forms from all the brands that the user is a member through brand_groups many to many pivot table.
For example, we have 2 brands, 2 users and 1 user is a member of 1 brand:
brand(ID: 1)
brand(ID: 2)
user(ID: 1)
user(ID: 2)
brand_group(brand_id: 1, user_id: 1)
form(ID: 1, user_id: 1, brand_id: null)
form(ID: 2, user_id: null, brand_id: 1)
form(ID: 3, user_id: 2, brand_id: 1)
form(ID: 4, user_id: 1, brand_id: 2)
Using Laravel Eloquent Models (not direct DB facade calls), I'd like to retrieve all the forms that belong to a user. For the user(ID:1) there are 3 forms:
form(ID:1) direct user ownership
form(ID:2) user is a member of brand(ID:1) group which is the brand of form(ID:2)
form(ID:3) user is a member of brand(ID:1) group which is the brand of form(ID:3)
I gave it a shot using Eloquent: Relationships - Has Many Through:
Has Many Through
The "has-many-through" relationship provides a convenient way to access distant relations via an intermediate relation.
I have tried it like this:
class User extends Model
{
public function forms()
{
return Forms::hasManyThrough(
Form::class,
BrandGroups::class,
'brand_id',
'brand_id',
'id',
'form_id',
)->where('id', $this->id);
}
}
But I get errors like:
BadMethodCallException with message 'Call to undefined method App\Models\Form::brand_groups()'
EDIT
After some digging, I have managed to come up with the working MySQL code that will return all the forms for a user:
SELECT * FROM `forms`
WHERE EXISTS (
SELECT `brand_id`, `user_id`
FROM `brand_groups`
WHERE `forms`.`brand_id` = `brand_groups`.`brand_id`
AND `brand_groups`.`user_id` = 1
) OR `forms`.`user_id` = 1
Now I just need to convert that query to an eloquent model relation.
Eloquent Models
User.php
class User extends Authenticatable implements MustVerifyEmail
{
public function brands()
{
return $this
->belongsToMany(Brand::class, 'brand_groups')
->using(BrandGroups::class)
->as('member');
}
public function forms()
{
return $this->hasMany(Form::class, 'user_id');
}
}
Brand.php
class Brand extends Model
{
protected $table = 'brands';
public function forms()
{
return $this->hasMany(Form::class);
}
public function members()
{
return $this
->belongsToMany(User::class, 'brand_groups')
->using(BrandGroups::class)
->as('member');
}
}
Form.php
class Form extends Model
{
protected $table = 'forms';
public function owner()
{
return $this->belongsTo(User::class);
}
public function brand()
{
return $this->belongsTo(Brand::class);
}
}
UPDATE
I manage to find a query to get all forms related to a user like this:
class User extends Authenticatable implements MustVerifyEmail
{
...
public function allForms()
{
return Form::where(function ($q) {
$q->whereExists(function ($q) {
$q->from('brand_groups')
->where('forms.brand_id', DB::raw('brand_groups.brand_id'))
->where('brand_groups.user_id', $this->id);
})->orWhere('owner_id', $this->id);
});
}
}
How this can be converted to a direct User model eloquent relationship?
Have you tried to Eager Load the User model relationships?
Edit
Firstly: the pivot table name should be the singular -snake_case- name of both tables and should be in alphabetical order (brand_user)
Next, try the following:
return User::where(‘id’, $this->id)->with([‘forms’,‘brands.forms’)->get();
This should return the Forms with direct ownership plus the user Brands and their associated Forms

Select related rows in Yii2

I have related tables (table train_schedule have departute_station_id and arrival_station_id) linked on Station:
enter image description here
I want select records from train_schedule with stations name:
$trainsTchedule = TrainSchedule::find()
->joinWith('getArrivalStation')
->joinWith('getDepartuteStation()')
->all();
In TrainSchedule class:
/**
* #return \yii\db\ActiveQuery
*/
public function getArrivalStation()
{
return $this->hasOne(Station::className(), ['id' => 'arrival_station_id']);
}
And
/**
* #return \yii\db\ActiveQuery
*/
public function getDepartuteStation()
{
return $this->hasOne(Station::className(), ['id' => 'departute_station_id']);
}
Error:
Relation names are case sensitive. app\models\TrainSchedule has a
relation named "arrivalStation" instead of "ArrivalStation".
Howe get data wrom linked tables?
You have defined your relations correctly but, you are calling them incorrectly. Your relation
getArrivalStation should be specified as arrivalStation
getDepartuteStation() should be departuteStation
when specifying in the joinWith, and you need to provide an array if you need to specify multiple relations when calling joinWith as currently your second call ->joinWith('getDepartuteStation()') is overriding the previous one ->joinWith('getArrivalStation').
So the query should look like below
$trainsTchedule = TrainSchedule::find()
->joinWith(['arrivalStation','departuteStation'])
->all();
You should read about Working with Relational Data

Symfony / Doctrine ManyToMany with conditions and limit

I've created a concept of a Person model having many e-mails. I also have a Company model that can share the same e-mails with People (Person model).
In short:
People OneToMany PeopleEmail ManyToOne Email (classic manytomany unidirectional with a join table)
people { id, firstname, lastname, created }
people_emails { person_id, email_id, main, created }
emails { id, email, created }
as well as:
companies { id, name, employee_count, created }
companies_emails { company_id, email_id, main, created }
emails { id, email, created }
The problem is, that I'd like to store a boolean value called "main" in the join table as follows:
person_id | email_id | main | created
8 | 5 | true | 2014-10-21 16:54:21
...so that I can do this:
Mark Wilson (Person) has 5 emails.
3 of them are his company e-mails (shared): contact#company.com, office#company.com, it#company.com
2 of them are his own.
1 he answers only in his leisure time
1 is his MAIN email: i.e. m.wilson#company.com
Instead of fetching all those 5 emails, I'd like to easily get the primary email just as if it was a regular Person model column:
firstname: Mark (string)
lastname: Wilson (string)
emails: (array)
primary_email: (email object)
I cannot store the "main" property anywhere else, as I want to point, that the relation between Mark and his Email is "main", not the email itself.
Now, I do have this value stored, but the problem is, how to make an entity property like:
class Person {
(...)
/**
* #ORM\ManyToMany(targetEntity="Email")
* #ORM\JoinTable(name="people_emails",
* joinColumns={#ORM\JoinColumn(name="person_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="email_id", referencedColumnName="id", unique=true)}
* )
*/
private $primary_email;
/**
* #ORM\ManyToMany(targetEntity="Email")
* #ORM\JoinTable(name="people_emails",
* joinColumns={#ORM\JoinColumn(name="person_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="email_id", referencedColumnName="id", unique=true)} // A condition?
* )
*/
private $emails;
public function getPrimaryEmail() {
return $this->primary_email; // Single row limit?
}
public function getEmails() {
return $this->emails;
}
(...)
}
The thing is, I would really love to have it as an entity property, just for use in any case possible without the need to write custom repostory functions for the whole Person model.
Or maybe that is a completely wrong way. I'd like to use that property in Twig like:
{{person.primary_email.email}}
To sum up:
I'd like to store a ManyToMany single row relationship depending on joinTable column.
How to do that?
There are many ways to do this and there are also many critical things to say about your design choices. Either way here is an example of one way you could achieve this using two join tables (you need two if you want to use foreign keys).
<?php
interface AddressLink
{
public function getEmail();
public function isMain();
}
trait EmailAddressOwner
{
protected abstract function getAddressLinks();
public function getPrimaryEmailAddress()
{
return $this->getAddressLinks()->filter(function (AddressLink $addressLink) {
return $addressLink->isMain();
})->first();
}
public function getEmailAddresses()
{
return $this->getAddressLinks()->map(function (AddressLink $addressLink) {
return $addressLink->getEmail();
});
}
}
class PersonEmailAddress implements AddressLink
{
private $person; // ManyToOne
private $email; // ManyToOne
private $main; // bool
}
class CompanyEmailAddress implements AddressLink
{
private $company; // ManyToOne
private $email; // ManyToOne
private $main; // bool
}
class Email
{
private $id;
private $address;
}
class Person
{
/**
* #ORM\OneToMany(targetEntity="PersonEmailAddress")
*/
private $emailAddressLinks;
use EmailAddressOwner;
public function getAddressLinks()
{
return $this->emailAddressLinks;
}
}
class Company
{
/**
* #ORM\OneToMany(targetEntity="CompanyEmailAddress")
*/
private $emailAddressLinks;
use EmailAddressOwner;
public function getAddressLinks()
{
return $this->emailAddressLinks;
}
}
Another way would be to include one ManyToMany relation to your Email entity and one ManyToOne relation for the primary e-mail address.
To answer you question in the comments if in twig you do
{{ person.primaryEmail.email }}
It wil actually call the getPrimaryEmail() method on your Person object. Which you can implement like I've outlined above. That way you don't need to have this extra property.

Laravel 5.1 Distant relationships with one-to-many and many-to-many models

I have 5 models configured. Customer, Environment, Object, ServiceRole and Service. I've set up the appropriate eloquent relationships in each of the models.
Customers have many Environments.
//Customer Model
public function environments()
{
return $this->hasMany('App\Environment');
}
Environments belong to one Customer.
Environments belong to many Objects.
//Environment Model
public function customer()
{
return $this->belongsTo('App\Customer');
}
public function objects()
{
return $this->belongsToMany('App\Object');
}
Objects belong to many Environments.
Objects belong to many ServiceRoles.
//Object Model
public function environments()
{
return $this->belongsToMany('App\Environment');
}
public function serviceRoles()
{
return $this->belongsToMany('App\ServiceRole');
}
ServiceRoles belong to many Objects.
ServiceRoles belong to one Service.
//ServiceRole Model
public function objects()
{
return $this->belongsToMany('App\Object');
}
public function service()
{
return $this->belongsTo('App\Service');
}
Services belong to many ServiceRoles.
public function serviceRoles()
{
return $this->hasMany('App\ServiceRole');
}
--SQL--
customers: id, name
objects: id, name
environments: id, name, customer_id
environment_object: id, environment_id, object_id
service_roles: id, name, service_id
object_service_role: id, object_id, service_role_id
services: id, name
1) What would be the simplest method to retrieve all of the Objects that associated to the Customer (across all of the related Environments)?
Looking to do something like: $customer->objects
2) How can I then retrieve all the Services of the Objects associated to the Customer, as each Object has a ServiceRole that maps to a Service.
Looking to do something like: $customer->services
It will be good to post all your relationships. But if you say you have appropriatly set up your relationships then the following should work.
1. Customer::with('environments.objects')->get();
but if its for only a customer do
Custmer::with('environments.objects')->find($id);
2. Customer::with('environments.objects.roles')->get();
for only a customer do
Customer::with('environments.objects.roles')->find($id);