Laravel: Which relationship to use? - php

I have the following scenario:
I'm building a site where Artists show their favorite spots in a city.
So:
There are some Cities and some Artists. A City hasMany Spots.
Artists and Spots also are related together via belongsToMany, because one Spot could have been featured by multiple Artists.
I now want to define a relation in City that gives me all the artists that have something featured in that City (so basically look for artists that are related to a spot from that City)
Is there a relationship type that I can use?
I've tried hasManyThrough but that's looking up spot_id in Artist which is obviously not existent because Artist<>Spot is many to many.

when you have relationship many to many you need to do normalisation for both table, create new table to store spot_id and artist_id. I think in laravel already handle that. This link might be helpful
https://laravel.com/docs/5.5/eloquent-relationships#many-to-many
https://www.captechconsulting.com/blogs/resolve-your-many-to-manys-for-accurate-requirements

Though it's many to many relationship so you have to use belongsToMany
Ex:
In city Model :
class City extends Model{
public function artists(){
return $this->belongsToMany('App\Artist')
}
}
In Artist Model :
class Artist extends Model{
public function city(){
return $this->belongsToMany('App\City')
}
}

Related

Nested one to many relationships in Eloquent

Let's say I have three models with this relationsship
USER
hasMany (app/organisation)
ORGANISATION
hasMany (app/order)
ORDER
For one level I could just go
user->organisations()->get()
And get all the organisations tied to the user. But every organisation also have 0..many ORDER entities. So I want to do this:
user->organisations()->orders()->get()
To get a list of all the orders from all the organisations from a certain user. Is that possible this way?
What you can simply do is implement hasManyThrough() relationship on User model.
public function orders()
{
return $this->hasManyThrough(Order::class, organisation::class);
}
then you can query like,
$user->orders()->get();

Laravel 5.2 Eloquent - Finding all id's through multiple relationships

So here are my relationships:
A fund belongs to a planCode
A planCode belongs to a planType
What I need to do is find the fund_id's that are a part of certain plan types. I tried something like this:
$plans = (new 'App\PlanType')->with('planCode.fund')->whereIn('code', ['PENS', 'ANN', 'WEL'])->get();
With this I get the three plan codes with their relationships eager loaded. What I want is a list of all the fund_id's. I tried $plans->lists('planCode.fund.fund_id', 'code') but this returns null for the fund_id. Any ideas?
So if your relationships are like this -
PlanCode has many Funds
Fund belongs to a PlanCode
PlanType has many PlanCodes
PlanCode belongs to a PlanType
Then you can add another relationship like this -
PlanType has many Funds through PlanCodes
UPDATE
After adding a function like this to your PlanType class -
public function funds() {
return $this->hasManyThrough('fund', 'planCode', PT, PC);
}
You can simply access Funds on your PlanType model like this -
$planType->Funds
Take a look at the docs here.
Yep, atefth has it in one. Laravel has a really useful relationship so that you don't have to make repeated queries to the database to get relations of relations. This is the hasManyThrough relationship.
So here, for example, your planType model has many fund models through the planCode model. Your planType model should contain a funds method that looks like this, where PC is the planCode->id column name in the fund table, and PT is the planType->id column in the planCode table:
public function funds() {
return $this->hasManyThrough('fund', 'planCode', PT, PC);
}
You may have to fully namespace your models, depending on the structure of your application.

Laravel-Many-to-one Polymorphic relationship

I am using laravel 5.1. The scenario is as follows(this is an example. The real scenario is similar to this example)
I have 3 models
College
Student
Teacher
A college can have many students but a student can belong to only 1 college.
A college can have many teachers but a teacher can belong to only 1 college.
I want to establish relationships between these tables in laravel.
One of the methods for this is to place a college_id foreign key on the Students and Teachers table. But in my case, this foreign key will be null a lot of times. So rather than have separate columns in 3-4 tables with mostly null values, I wanted to explore the option of having a polymorphic relationship for College table.
This is what I tried:
The example given in the laravel docs(link below) depict a one-to-many relationship whereas my scenario is more of a many to one relationship.
http://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations
As given in the example, having collegeable_id and collegeable_type columns on the College table would not have fulfilled my requirement as a college can contain many students/teachers so I created a pivot table:
Schema::create('collegeables', function (Blueprint $table) {
$table->integer('college_id')->unsigned();
$table->integer('collegeable_id')->unsigned();
$table->string('collegeable_type');
});
And I have the following models
College Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class College extends Model
{
public function students()
{
return $this->morphedByMany('App\Student', 'collegeable');
}
}
Student Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
public function college()
{
return $this->morphOne('App\Colleges', 'collegeable');
}
}
With this arrangement, I am able to store students using College model instance like this
$college = \App\College::find(1);
$student = new \App\Student;
$student->name = 'John Doe';
$college->students()->save($student);
But when I try to retrieve a College model instance using a student model instance as specified below, it gives me an error:-
public function index()
{
return \App\Student::find(1)->college;
}
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'colleges.collegeable_id'
This is kind of expected as morphOne works with columns in a table I suppose.
If I change the morphOne function in Student Model to morphToMany, the code starts working and I am able to retrieve values as well. But that make this relationship a many to many which again is not what I want.
So my question is this:-
Is their a morphSomething function I can use in the student model to be able to retrieve values for the student's college while maintaining the relationship as a one-to-many?
Any help would be really appreciated. Thanks.
There's no reason to use Polymorphic relationships here. Instead, just add a foreign key to your colleges table on both your students and teachers tables. Like this:
colleges
id
name
teachers
id
name
college_id
students
id
name
college_id
Then your models can use the belongsTo() and hasMany() relations, like so:
class College extends Model {
public function students() {
return $this->hasMany(App\Student::class);
}
public function teachers() {
return $this->hasMany(App\Teacher::class);
}
}
class Teacher extends Model {
public function colleges() {
return $this->belongsTo(App\College::class);
}
}
class Student extends Model {
public function colleges() {
return $this->belongsTo(App\College::class);
}
}
Polymorphic one-to-many relations are for the opposite of this relationship where you have a model that can only be related to a single record, but that record can be many different models.
Edit: To further explain why a polymorphic relationship isn't needed here, let's take a look at where it would be needed. Say you have a simple CRM style website. There are Customers and Projects and you want to have Comments on both. In this case, you would make Comments a polymorphic relationship because Comments belong to a single Customer or a single Project, but not both.
Your relationship is the exact opposite. In your case, Students and Teachers belong to a college. If you were to follow the previous example's pattern, a college would have belonged to a single student or teacher.
I had a similar need and managed to improvise in another way, taking advantage of morph's table structure.
You will need a Collegeable class to be Pivot (https://laravel.com/docs/9.x/eloquent-relationships#defining-custom-intermediate-table-models)
And then the magic:
public function college(){
return $this->hasOneThrough(Colleges::class,
Collegeable::class,
'collegeable_id',
'id',
'id',
'college_id',
);
}
And on the Collegeable Pivot class:
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\Pivot;
class Collegeable extends Pivot
{
protected $table = 'collegeables';
}

Can two Eloquent ORM instances manipulate same DB table

I've been working with PHP for years but have never really ventured out of procedural programming except when working with things like IPB and Magento. I'm trying to advance to the next level and get a better understanding of application structures, OOP, and some common PHP frameworks. That being said, I apologize if my question sounds immature or technically incorrect, I'm new to all of this.
Anyway, I was thinking about the structure of a simple forum. Forgetting about categories, tags, users, roles, advanced editors/bbcode, etc for now and just focusing on the topics and posts...
Because a topic is essentially a series of linked posts ordered by their created_at column, is there a necessity for an actual topics table or could one not simply have a parent column in the posts table? Topics would be identified as posts with a parent equal to their own id, null or 0; something that would otherwise be unused.
If that were the db schema, how would it be laid out in the code, and if relevant, Laravel? Could you still create a Topic model? What would be the pros and cons to having two models working from a single table?
Lastly, how would you approach it if you were creating it? Would you use two tables? A pivot table? Something else? Please explain why you would implement it that way.
For the database design, self referencing tables are a valid design pattern and useful in cases of nested hierarchies such as Categories that can contain sub-categories that can also contain sub-categories ect ect... In this case sub-categories are categories that have a parent but there is no other distinction between them.
It's up to you to decide if a Topic and Post is an identical entity with a parent-child relationship. Personally the way I define the objects I don't feel they are.
The topic-post relationship you're describing is probably more of a One to Many relationship with the topic being the owner or maybe even a Many to Many relationship. This depends on the answer to, "can your topic have many posts? Can your posts be part of many topics?"
If you answered yes and no, then it is a One to Many with topics being the parent aka owner in the relationship.
If you answered yes and yes, then you have a Many to Many relationship. In SQL these are represented by a table with two columns that reference id's from two tables.
If you answered no and yes, then you have a One to Many with posts being the parent aka owner in the relationship.
In laravel, depending on the relationship, your models would include a method that looks like this:
One to Many:
class Topic extends Eloquent
{
public function posts()
{
return $this->hasMany('Post');
}
}
Laravel One-to-Many Relationships
Many to Many:
In laravel the term "pivot table" refers to the table with references to the other objects.
class Post extends Eloquent
{
public function topics()
{
return $this->belongsToMany('Topic');
}
}
class Topic extends Eloquent
{
public function posts()
{
return $this->belongsToMany('Post');
}
}
Laravel Many-to-Many
Self referencing model:
For a self referencing parent child relationship like I explained before you could create something like this, as you can see it's just a one-to-many and the many-to-one in the same model.
class Category extends Eloquent
{
public function parent()
{
return $this->belongsTo('Category', 'parent_id');
}
public function children()
{
return $this->hasMany('Category', 'parent_id');
}
}
There is also the Polymorphic Relation.
This is useful when you have the same entity with just a different type. For example in this table you can have an insurance policy for an employee and a manager. The personType column in the insurancePolicies table defines who the insurance policy belongs to.
Image from codecommit.com
Our laravel models in this case would look like:
class InsurancePolicy extends Eloquent
{
public function insurable()
{
return $this->morphTo();
}
}
class Manager extends Eloquent
{
public function insurance()
{
return $this->morphMany('InsurancePolicy', 'person');
}
}
class Employee extends Eloquent
{
public function insurance()
{
return $this->morphMany('InsurancePolicy', 'person');
}
}
Most everything of what I've explained can also be found in the laravel docs

How to build a Laravel relationship between these entities?

I have three tables in my database: Users, Books, and Reading. The structure of Reading is:
id, user_id, book_id
Now, I need to access to all the books that the user is reading.
First, I would like to know which kind of relationship is, one to many, many to many, Has Many Through, etc. And what do I have to specify in each model? I mean, in the users model hasMany('Reading') or whatever.
I want to access with something like this: Auth::user()->reading()->books()->get() or something similar.
The kind of relationship where one User can be reading several books and one Book can be read by many users is Many-to-Many relationship.
So, to define such a relation in Laravel you should use belongsToMany method:
class User extends Eloquent
{
function books()
{
return $this->belongsToMany("Book", "Reading", "user_id", "book_id");
}
}
class Book extends Eloquent
{
function users()
{
return $this->belongsToMany("User", "Reading", "book_id", "user_id");
}
}
$books = Auth::user()->books;
Notice, you don't need to call method ->books() but use a property ->books, otherwise you'd have to call it like Auth::user()->books()->get().

Categories