Intermediate Tables & Laravel - php

I'm kind of new to the Eloquent (Pivot / Intermediate Tables) idea.
I am using Laravel 5.3 and the docs are making a little sense, but not enough. Unfortunatley!
I have a few scenarios that I'd like to try get data from...
I have the following DB Tables
Companies
Company_Offers
Offers
Company_Attributes
Attributes
In my scenarios the following is said of these DB Tables...
A company can have many offers
A company can have many attributes
An Offer can be associated with many companies
An attribute can be associated with many companies
I have created the 5 models to correspond to the 5 DB Tables.
I am trying to work out, How I get these relationships into my models?
Thank You!

You want to use the belongsToMany relationship. For example:
class Company extends Model
{
public function offers()
{
return $this->belongsToMany(App\Offer::class);
}
}
If you have setup your pivot table with company_id and offer_id this relationship will work automatically, and a pivot table of company_offer (singular version of model name in alphabetical order). If you didn't follow the naming convention you can specify the pivot table and foreign keys like so:
return $this->belongsToMany('App\Offer', 'Company_Offers', 'Company_ID', 'Offer_ID');

Actually in laravel you don't have to create models for pivot tables. So you are down to three models that will look more less like this:
<?php
/* /app/Company.php */
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
/**
* The offers that belong to the company.
*/
public function offers()
{
return $this->belongsToMany('App\Offer');
}
/**
* The attributes that belong to the user.
*/
public function attributes()
{
return $this->belongsToMany('App\Attribute');
}
}
<?php
/* /app/Offer.php */
namespace App;
use Illuminate\Database\Eloquent\Model;
class Offer extends Model
{
public function companies()
{
return $this->belongsToMany('App\Company');
}
}
<?php
/* /app/Attribute.php */
namespace App;
use Illuminate\Database\Eloquent\Model;
class Attribute extends Model
{
public function companies()
{
return $this->belongsToMany('App\Company');
}
}
More on how to use it to select or update those relations you can find here:
https://laravel.com/docs/5.3/eloquent-relationships#many-to-many

Related

Laravel Relationships / attributes to common linked table

Let me just start off by saying I'm VERY new to Laravel.
I have a table for listbox items (truncated migration code below):
$table->increments('id');
$table->string('list_item');
$table->string('group');
$table->integer('sort_order')->default(1);
Group is used for e.g "TITLE", "SPECIALITIES" etc.
I'm linking user_title_li_id (in the users table) to the id of this table, as well as
provider_title_li_id, provider_speciality_li_id in the providers table etc
How do I set up the relationship in the User and List Item models, in order to get the list_item (e.g. Professor) for each Model in the controller?
In your User model, define a function like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the list items for the user.
*/
public function listItems()
{
return $this->hasMany('App\ListItem', 'foreign_key', 'list_item');
}
}

proper way to create ManyToMany relationship in laravel

I just started to work on a laravel project for my school assignment. I just have started it for about a week so my fundamental knowledge about laravel is not complete.
Today I bump into a problem with model many to many relationship in laravel. I create 2 model with migration A and B. In App\A.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class A extends Model
{
//
public function B(){
return $this->belongsToMany('App\B');
}
}
and in App\B.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class B extends Model
{
//
public function A(){
return $this->belongsToMany('App\A');
}
}
I think it should do the job. But when I use seeder to create dummy data, I got the error with is that table A_B is not created. I assume that I must create empty table A_B for 2 pivot columns which is annoying. Is there a better way, a proper way to create many to many relationship without manually create pivot table for them?
I'm afraid not. There are shortcuts to doing it, like the way they show here but you will end up doing some manual work to create the table. You will end up using a migration anyway, but depending on the amount of control you want with the pivot, you might want to use a model for that. Using a model for a pivot table is not mandatory.
https://laravel.com/docs/5.5/migrations#creating-tables
This could be what your migration would end up looking like:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateABTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('A_B', function (Blueprint $table) {
$table->increments('id');
$table->integer('a_id')->unsigned();
$table->integer('b_id')->unsigned();
$table->foreign('a_id')->references('id')->on('a')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('A_B');
}
}
But if you really wanted to, you could also create a custom table (with a custom name like ABRandomName) using a new model. Just look for the Defining Custom Intermediate Table Models header in the documentation:
https://laravel.com/docs/5.5/eloquent-relationships#many-to-many

What is the difference between BelongsTo And HasOne in Laravel

Can any body tell me what is the main difference between
the BelongsTo and HasOne relationship in eloquent.
The main difference is which side of the relation holds relationship's foreign key. The model that calls $this->belongsTo() is the owned model in one-to-one and many-to-one relationships and holds the key of the owning model.
Example one-to-one relationship:
class User extends Model {
public function car() {
// user has at maximum one car,
// so $user->car will return a single model
return $this->hasOne('Car');
}
}
class Car extends Model {
public function owner() {
// cars table has owner_id field that stores id of related user model
return $this->belongsTo('User');
}
}
Example one-to-many relationship:
class User extends Model {
public function phoneNumbers() {
// user can have multiple phone numbers,
// so $user->phoneNumbers will return a collection of models
return $this->hasMany('PhoneNumber');
}
}
class PhoneNumber extends Model {
public function owner() {
// phone_numbers table has owner_id field that stores id of related user model
return $this->belongsTo('User');
}
}
BelongsTo is a inverse of HasOne.
We can define the inverse of a hasOne relationship using the belongsTo method.
Take simple example with User and Phone models.
I'm giving hasOne relation from User to Phone.
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne('App\Phone');
}
}
Using this relation, I'm able to get Phone model data using User model.
But it is not possible with Inverse process using HasOne. Like Access User model using Phone model.
If I want to access User model using Phone, then it is necessary to add BelongsTo in Phone model.
class Phone extends Model
{
/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User');
}
}
You can refer this link for more detail.
One-to-one relationship: You, as a User, can have one (hasOne) Profile. And of course the inverse also applies. Profile (belongsTo) a User. A user can't have more than one profile and a profile can't belong to multiple users.
If you want to make One TO one relationship between two table then first you have to make "hasOne" Relation and If you want to make inversely table relationship then you make " "Belongs to"... IT is a simple difference between HasOne and Belongs to the relationship if you want to know about this
One To Many (Inverse)
Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship function on the child model which calls the belongsTo method:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}
Here you can see a good example and see what the difference is between BelongsTo and HasOne relationship in eloquent.
Eloquent Relationships Cheat Sheet by Mahmoud Zalt https://link.medium.com/9lj9BAG8lR

Eloquent doesn't get the "belongsTo" item

I have the Project model and the Contract model. When i execute Project:all() it gets me only the projects without the contract, same for contract. I tried to dd() inside contract and doesn't do anything, like is never executed. I also tried with App\ prefix and without.
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
protected $table = 'project';
public function contract() {
return $this->belongsTo('Contract');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Contract extends Model
{
protected $table = 'contract';
public function project() {
return $this->hasMany('Project', 'ContractID', 'ContractID');
}
}
I try to retrieve them like this:
$projects = Project::all()->take(10);
You have a few problems here.
Project::all()->take(10);
This only returns a collection of projects. You havent specified that you want the contracts also.
$projects = Project::with('contract')->get();
In your belongsTo - You havent specified the column that the table should join on. You need to do this, because you have not used a standard id for primary key and contract_id for foreign key.
unrelated to specific question, but your relationship in contract model is also wrong.
public function project() {
return $this->hasMany('Project', 'ContractID', 'ContractID');
}
If one contract has many projects, then your public function project() should be public function projects();
Finally - Why are you using non-standard table / column naming conventions? What's wrong with contract_id? Are you aware that mysql is non-case sensitive? Also the project table could be renamed projects and the contract table could be renamed contracts. It will make you writing your eloquent relations much easier and makes more sense!
If you used standard naming conventions, then you could just do this to declare your model relations.
namespace App;
use Illuminate\Database\Eloquent\Model;
class Contract extends Model
{
public function projects() {
return $this->hasMany('Project');
}
}
Notice you dont need to specify the table name in the model, or how the table is related to the Project.

Laravel 4 Polymorphic Relationship with Namespaced Models

I created an Seo table with Eloquent's polymorphic relationship. So for Seo table, I have something like this
title
description
seoble_id
seoble_type
timestamps
Then for all the models that will have custom SEO, I added the morphOne relationship while the Seo model will have morphMany relationship. So for Post model I will have something like this
namespace App\Models;
class Post extends Eloquent {
public function seo()
{
return $this->morphOne('App\Models\Seo', 'seoble');
}
}
However, the relationship will only work if I the seoble_type is filled with the fully namespaced model class name. So the seoble_type must be 'App\Models\Post' (model name like 'Post' or table name like 'posts' will not work) for the polymorphic relationship to work. The problem is, if I somehow want to change the namespace, I will have to update all the seo table to update the seoble_type field, which will be a hassle.
Now, before I tried the polymorphic relationship, I usually created the equivalent table something like this:
title
description
object_id
type
timestamps
And for the relationship, for each model I will have something like this:
namespace App\Models;
class Post extends Eloquent {
public function seo()
{
return $this->hasOne('App\Models\Seo', 'object_id')->where('type', 'post');
}
}
My question is, are these 2 methods equivalent?
if you using morph it mean you wish single table can be used as relations to any table with indication by object_id and type_id. so the answer for your question, is not equivalent.
I thought at your case (for save seo table) the recommended ways as my opinions is using morphOne.
and then, for your problem in morph you can fill your seoable_type with whatever do you like, not should fill with your namespace
here is simple code when using morph :
namespace App\Models;
class Seo extends Eloquent {
public function seoable()
{
return $this->morphTo();
}
public function post()
{
return $this->belongsTo('App\Models\Seo', 'seoable_id');
}
}
/*----*/
namespace App\Models;
class Post extends Eloquent {
public function getSeo($type)
{
return $this->morphOne('App\Models\Seo', 'seoable');
}
}
// you can using like this :
$seo = \Seo::where('seoable_type', 'post');
$seo->post->first();
// or like this :
$post = \Post::with('getSeo')->findOrFail($id)->toArray();
wish this helped you.

Categories