Eloquent Multiple Foreign Keys from same table in two columns - php

I am having issues calling a departure ICAO and arrival ICAO from my schedules table. Laravel keeps giving me errors that my relationships are screwed up. Here is the code.
Schema::create('airports', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('city');
$table->string('country');
$table->string('iata');
$table->string('icao');
$table->double('lat');
$table->double('lon');
$table->longText('data')->nullable(); //JSON Data for All gate information for the system.
$table->softDeletes();
});
Schema::create('schedule_templates', function (Blueprint $table) {
$table->increments('id');
$table->string('code');
$table->string('flightnum');
$table->integer('depicao')->unsigned();
$table->foreign('depicao')->references('id')->on('airports')->onDelete('cascade');
$table->integer('arricao')->unsigned();
$table->foreign('arricao')->references('id')->on('airports')->onDelete('cascade');
$table->string('aircraft')->nullable();
$table->boolean('seasonal');
$table->date('startdate');
$table->date('enddate');
$table->time('deptime');
$table->time('arrtime');
$table->integer('type');
$table->boolean('enabled');
$table->text('defaults');
$table->timestamps();
$table->softDeletes();
});
Here are the Models
class ScheduleTemplate extends Model
{
public $table = "schedule_templates";
public function depicao()
{
return $this->hasOne('App\Models\Airport', 'depicao');
}
public function arricao()
{
return $this->hasOne('App\Models\Airport', 'arricao');
}
}
class Airport extends Model
{
//
public $timestamps = false;
public function schedules()
{
return $this->belongsToMany('App\ScheduleTemplate');
}
}
When I attempt to query using the following code, I get the error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'vaos_airports.depicao' in 'where clause' (SQL: select * from vaos_airports where vaos_airports.depicao in (1))
$schedules = ScheduleTemplate::with('depicao')->with('arricao')->get();
The end goal is to pull the results into a table. Here is that code if interested.
#foreach($schedules as $s)
<tr>
<td>{{$s->code}}</td>
<td>{{$s->flightnum}}</td>
<td>{{$s->depicao()->name}}</td>
<td>{{$s->arricao()->name}}</td>
<td>{{$s->aircraft}}</td>
<td>{{$s->seasonal}}</td>
<td>{{$s->type}}</td>
</tr>
#endforeach
EDIT:
I fixed the relationship problem Apparently I had them swapped. Here are the updated Model classes
class ScheduleTemplate extends Model
{
public $table = "schedule_templates";
public function depicao()
{
return $this->belongsTo('App\Models\Airport', 'depicao');
}
public function arricao()
{
return $this->belongsTo('App\Models\Airport', 'arricao');
}
}
class Airport extends Model
{
//
public $timestamps = false;
public function schedules()
{
return $this->hasMany('App\ScheduleTemplate');
}
}
The error now lies in the view file. I will either get a BelongsTo error:
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$name
or this if I have arricao or depicao without "()"
Trying to get property of non-object

The point is, that the second argument of a relationship should be the foreign key, and the second the local key.
From the docs:
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
So in your case, try this:
public function depicao()
{
return $this->hasOne('App\Models\Airport', 'id', 'depicao');
}
public function arricao()
{
return $this->hasOne('App\Models\Airport', 'id', 'arricao');
}
Update
The errors are thrown because you have the same column name for this relationship. In my opinion, two solutions:
Try to get the first object out of the relationship, like this. But note here: eager loading will not work!
<td>{{$s->depicao()->first()->name}}</td>
<td>{{$s->arricao()->first()->name}}</td>
Rename your relationships or the columns, so they don't overlap current column names. This is by far the best option.
For example, you could change the columns to depeciao_id and arricao_id, this also indicates that the columns are referenced to another table with corresponding ID, which is more descriptive.

Related

eloquent only get first Active query

hey guys i have a confusing question
I have 3 tables
basket_lists (carts)
basket_items (carts_item)
products
with this migrate
'basket_lists':
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->boolean('active');
$table->timestamps();
basket_items:
$table->bigIncrements('id');
$table->unsignedBigInteger('product_Id');
$table->unsignedBigInteger('basket_list_id');
$table->timestamps();
products:
$table->bigIncrements('id');
$table->string('title');
$table->text('description');
$table->bigInteger('amount');
$table->timestamps();
I have some products in my table , when i search (query) {
BasketList::where('active', '=', 1)->with('basketItems.products')->get();
it only gives me the first basketlist products (where id = 1)
if i insert new basketlist and set the first basketlist to (active = 0) and second one to (active = 1) it will not show any products.
Here is my model classes :
class BasketList extends Model
{
public function basketItems()
{
return $this->hasMany(BasketItem::class ,'basket_list_id' );
}
}
class BasketItem extends Model
{
public function products()
{
return $this->hasMany(Product::class,'id' );
}
public function basketList()
{
return $this->belongsTo(BasketList::class);
}
}
public function basketItem()
{
return $this->belongsTo(BasketItem::class ,'product_id');
}
You must change your relationship to belongsTo()
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class BasketItem extends Model
{
//
protected $table = 'basket_items';
public function product()
{
return $this->belongsTo(Product::class, 'product_id','id' ); // Watch out for the case sensitive. how did you wright product_id in your migration. (product_id or product_Id)
}
You break Laravel default naming conventions for foreign keys 'product_Id'
It must be 'product_id'
Eloquent determines the foreign key of the relationship based on the
model name. In this case, the BasketItem model is automatically
assumed to have a 'product_id' foreign key. If you wish to override this
convention, you may pass a second argument to the hasMany method:
Fix
App\BasketItem.php
public function product()
{
return $this->belongsTo(Product::class, 'product_Id','id' );
}
Check Documentation
Usage
BasketList::where('active', '=', 1)->with('basketItems', 'basketItems.product')->get();

Can't get laravel's polymorphic relationship to work

I'm trying to get a polymorphic relationship working on laravel but every test I make returns either null or ax exception on laravel's pretended SQL query...
FYI: My laravel version is 5.8 running on a MySQLserver 5.7 (WAMP package)
According to what I read on laravel's docs, I think I must use morphTo() in the polymorphic model's class and morphMany() on it's children tables, so I coded like this:
App\Models\Company
public function accounts(){
return $this->morphMany(Accountable::class, 'accountable');
}
App\Models\Account\Accountable
public function company()
{
return $this->belongsTo(Company::class);
}
public function accountable()
{
return $this->morphTo();
}
Migrations:
companies
Schema::create($this->tableName, function (Blueprint $table) {
$table->bigIncrements('id');
...
})
bank_accounts migration
Schema::create('bank_accounts', function (Blueprint $table) {
$table->bigIncrements('id');
...
});
company_has_accounts migration
Schema::create('company_has_accounts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->morphs('accountable');
...
});
Errors:
The thing is: Whenever I try to debug BankAccount::find(1)->company I keep getting:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'company_has_accounts.company_type' in 'where clause' (SQL: select * from `company_has_accounts` where `company_has_accounts`.`c
ompany_id` = 1 and `company_has_accounts`.`company_id` is not null and `company_has_accounts`.`company_type` = Financeiro/Models/Account/BankAccount and `company_has_accounts`.`deleted_at` is null)
and when I try: Company::find(1)->accounts I keep getting an empty Collection.
My objectives are:
App\Models\Account\BankAccount
public function company()
To return a App\Models\Company Object.
App\Models\Account\Company
public function accounts()
To return a collection of mixed "App\Models\Account\BankAccount" and "App\Models\Account\CreditCard" Objects, all belonging to the current App\Models\Account\Company Model, as filtered by the "company_id" column on "company_has_accounts" table.
After some struggle I managed to get it working. But since I'm new to Laravel I don't know if it's the best approach...
App\Models\Account\Accountable
public function company(){
return $this->belongsTo(Company::class);
}
public function accountable(){
return $this->morphTo();
}
App\Models\Account\Company
public function accountables(){
return $this->hasMany(Accountable::class)->with('accountable');
}
public function accounts(){
$accountables = $this->accountables();
$accounts = [];
if ($accountables->count()) {
foreach ($accountables->get() as $accountable) {
$accounts[] = $accountable->accountable;
}
}
$accounts = collect($accounts);
return $accounts;
}
App\Models\Account\BankAccount
public function accountable(){
return $this->morphOne(Accountable::class, 'accountable');
}
public function company(){
$accountable = ($this->accountable())->with('company');
return $accountable->first()->company;
}

How to know when my relation returns an object and when an array?

I got few relations in my model Reply:
/** Reply.php */
public function thread()
{
return $this->belongsTo(Thread::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
My reply table got user_id and thread_id
And then I try to get user name I do it like this:
$reply->user->name
And it works.
But when I try to get thread title:
$reply->thread->title
I got error:
Trying to get property title of non-object
And if need to get title only method I know is:
$reply->thread['title']
What is the difference between methods I use? Why in one case I get user as an object but in another I get thread as an array?
Update:
My Reply model relations:
public function user()
{
return $this->belongsTo(User::class);
}
public function favorites()
{
return $this->morphMany(Favorite::class, 'favorited');
}
public function thread()
{
return $this->belongsTo(Thread::class);
}
My Thread model relations:
public function replies()
{
return $this->hasMany(Reply::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
And my User model relations:
public function threads()
{
return $this->hasMany(Thread::class)->latest();
}
public function replies()
{
return $this->hasMany(Reply::class)->latest();
}
When you make
one to one
relation then relation will return object
When you make
one to many
relation will return array of objects
The Model class implements the Arrayable interface, this means that you can access the attributes also as if it were an array, this is why this work:
$reply->thread['title'];
When you use a BelongsTo relationship, this expect to return an object (an instance of your model) or null in case this relation isn't set, this is why you can use "magic methods" to access attributes like this:
$reply->thread // an object
$reply->thread->title // getting attributes using magic methods
But, what happen when the relationship isn't set? well, the relationship will return null so when you do this:
$reply->thread->title
It will throw an arror:
Trying to get property title of non-object
Because you are trying to access the title attribute of null.
Update:
This is where -I think- the error is. With the newest version of Laravel (as of today: Laravel 5.8), the primmary keys types has changed from integers to bigIntegers(), and this is for all the tables:
Schema::create('replies', function (Blueprint $table)
{
$table->bigIncrements('id'); // <---- equivalent to bigInteger
$table->integer('user_id')->unsigned;
$table->integer('thread_id')->unsigned;
$table->text('body');
$table->timestamps();
});
So, your foreign keys should be also big integers, try this:
Schema::create('replies', function (Blueprint $table)
{
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id'); // <-----------
$table->unsignedBigInteger('thread_id'); // <-----------
$table->text('body');
$table->timestamps();
});
Check this article related this issue.
I think that the only reason for this error would be a null return from the relation. In that case
$reply->thread['title']
won't work, can you check it please ?
If the $reply->thread['title'] works, I would like to see the output of dd($reply->thread); please.
If it does not work and the cause of the error is indeed a null return, you just have to check that
$reply->thread is not null before using it.
Let me know if it helped you :)

Laravel foreign key relation - Unknown column in field list

I have Member and SkyMedRep models:
class SkyMedRep extends Model
{
protected $fillable = [
'id','rep_id',
];
public function members()
{
return $this->hasMany('App\Member');
}
}
class Member extends User
{
public function sky_med_rep()
{
return $this->belongsTo('App\SkyMedRep');
}
}
This is migration for Member:
public function up()
{
Schema::create('members', function (Blueprint $table) {
$table->increments('id');
$table->integer('sky_med_rep_id')->unsigned();
$table->timestamps();
});
Schema::table('members', function($table) {
$table->foreign('sky_med_rep_id')->references('id')- >on('sky_med_reps')->nullable(true);
});
}
Member model contains foreign key referencing SkyMedRep model.After defining such relationship, I am trying to assign object of SkyMedRep model to the object of Member model like:
$member->sky_med_rep = $sky_med_rep;
Here, $member is the object of Member model and $sky_med_rep is the object of SkyMedRep model.
When I try $member->save(), I am getting error "Unknown column 'sky_med_rep' in field list". It seems that sky_med_rep is not being able to treat as foreign key reference. Below is my code to save the data:
$member = new Member();
$member->sky_med_member_number = $request->input("sky_med_member")['member_number'];
$sky_med_rep = SkyMedRep::firstOrNew(['rep_id' => $request->input("sky_med_member")['rep_id']]);
$sky_med_rep->name = $request->input("sky_med_member")['name'];
$sky_med_rep->save();
$member->sky_med_rep = $sky_med_rep;
$member->save();
Instead of $member->sky_med_rep = $sky_med_rep; You should write $member->sky_med_rep->associate($sky_med_rep);.
Also have a look at http://www.php-fig.org/psr/psr-2/ coding style guide. Method names should be camelCase, not underscore.

foreign key not recognised in laravel 4.2

According to Dayle Rees
All foreign key columns follow a similar naming convention. The singular form of the related model appended with _id.
Consider this migration:
class CreateTables extends Migration {
// ...
public function up()
{
Schema::create('artists', function($table) {
$table->increments('id');
$table->string('name',64);
$table->timestamps();
});
Schema::create('albums', function($table) {
$table->increments('id');
$table->string('name',64);
$table->integer('artist_id')->unsigned();
$table->foreign('artist_id')->references('id')->on('artists');
$table->timestamps();
});
}
Here are my eloquent models:
<?php
// Artist model
class Artist extends Eloquent {
public function albums() {
return $this->hasMany('Album');
}
}
<?php
// Album model
class Album extends Eloquent {
public function artists() {
return $this->belongsTo('Artist');
}
}
I used them like this:
Route::get('/', function() {
$artist = new Artist;
$artist->name = "Morbid Angel";
$artist->save();
$album = new Album;
$album->name = "Altars of Madness";
$album->artists()->associate($artist);
$album->save();
return View::make('hello');
});
This does not seem to work, according to the logs:
[2015-06-09 06:01:12] production.ERROR: exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'artists_id' in 'field list''
But I did not create a artists_id. What does this mean? Shouldn't laravel find artist_id because it should be singular followed by _id?
This was your problem. You have named your relation artists, but it should be artist. That's why it was looking for a column named artists_id.
You should define your relations as follow as it looks to me it is a One to Many.
In your Artists Model
public function albums()
{
return $this->hasMany('Album');
}
In your Albums Model
public function artist()
{
return $this->belongsTo('Artist');
}
Then try your code.
Route::get('/', function() {
$artist = new Artist;
$artist->name = "Morbid Angel";
$artist->save();
$album = new Album;
$album->name = "Altars of Madness";
$artist->albums()->save($album);
return View::make('hello');
});
In your artist model try return $this->hasMany('Album', 'artist_id');

Categories