Laravel - Eloquent relationship (hasMany) issues - laravel

Yet another eloquent relationship issue :) I hope somebody can help me out!
ProductionOrder.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ProductionOrder extends Model
{
public function workOrders()
{
return $this->hasMany('App\WorkOrder');
}
}
WorkOrder.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class WorkOrder extends Model
{
public function productionOrder()
{
return $this->belongsTo('App\ProductionOrder');
}
}
So a ProductionOrder should have one or more WorkOrders.
Production order migration
public function up()
{
Schema::create('production_orders', function (Blueprint $table)
{
$table->bigIncrements('id');
$table->unsignedBigInteger('production_order_id')->unique();
$table->longText('notes')->nullable();
$table->timestamps();
});
}
Work order migration
public function up()
{
Schema::create('work_orders', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('work_order_id')->unique();
$table->unsignedBigInteger('production_order_id');
});
}
The reason the ID names are not just 'id' is because i am importing the order data from a external API. I think this is the reason why the relationship does not work but I can't seem to fix it.
ProductionOrder::with('workOrders')->get();
The above returns an empty array in the work_orders attribute for each production order, however there are definitely work orders located in the database with existing production_order_id.

Fixed it, had to add two times the production_order_id to the hasMany relationship:
public function workOrders()
{
return $this->hasMany('App\WorkOrder', 'production_order_id', 'production_order_id');
}

use query like this you will get data surely
class ProductionOrder extends Model
{
public function workOrders()
{
//use this
//return $this->hasMany(WorkOrder::class, 'id of workorder table which forigne key of', 'primary key of this table');
return $this->hasMany(WorkOrder::class, 'production_order_id', 'id');
//instead of
//return $this->hasMany('App\WorkOrder');
}
}
ProductionOrder::where('production_order_id', '=', 70600)->with('workOrders')->first();

Related

Laravel creates a one-to-many relationship instead of one-to-one

When I create a one-to-one relationship migration, laravel creates a one-to-many relationship. I tried to solve this in different ways and nothing worked.
How can I solve this?
Company:
class Company extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
...
}
User:
class User extends Authenticatable
{
public function company(){
return $this->belongsTo(Company::class);
}
...
}
Migrations:
Schema::create('Company', function (Blueprint $table) {
$table->mediumIncrements('idCompany');
...
});
Schema::create('User', function (Blueprint $table) {
$table->id();
$table->increments('idUser');
$table->unsignedMediumInteger('Company_idCompany')
->unique()
->nullable();
$table->foreign('Company_idCompany')
->references('idCompany')
->on('company')
->onDelete('set null');
...
});
Laravel is creating nothing (on the migration), you always have to manually create the Model relationship (you are using hasOne and belongsTo, so that is 1-to-1) and migrations (you are creating User and Company not following the standards).
So, update your migrations to:
Schema::create('company', function (Blueprint $table) {
$table->id();
...
});
Schema::create('user', function (Blueprint $table) {
$table->id();
$table->increments('user_id');
$table->foreignId('company_id')
->unique()
->nullable();
$table->foreign('company_id')
->references('id')
->on('company')
->onDelete('set null');
...
});
See that I have moved everything to lowercase and snake case, remember to follow Laravel conventions or you are going to have a harder time working with Models...
Then, your relationships are correct:
class Company extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
...
}
class User extends Authenticatable
{
public function company(){
return $this->belongsTo(Company::class);
}
...
}
So, when you do access a relationship, it will work out of the box now.
If you do Company::first()->user, that will return User or null, and if you do User::first()->company, that will return Company or null, there is no 1-to-N.

Laravel Models and displaying them on view together

For a school assignment we have two tables and models players and countries
I know its either my models or my controller (I've had this problem before but in another assignment their was only one country so i just looped through a country variable and used arrays instead but this wont work for multiple countries)
When I try to display in the view i get "Trying to get property of non-object 'name' on the {{$player->country->name}} and this is the way the teacher has explicitly said we are to display it.
Currently before anything else id like to display all my players and their country names
Models
class Country extends Model
{
//
protected $table = 'countries';
protected $fillable=['name','flag'];
public function player(){
return $this->hasMany(Player::class);
}
}
class Player extends Model
{
//
protected $fillable =['name','age','role','batting','bowling','image','odiRuns','countries_id'];
public function country()
{
return $this->belongsTo(Country::class);
}
}
Tables
public function up()
{
Schema::create('countries', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('flag');
$table->timestamps();
});
}
public function up()
{
Schema::create('players', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('age');
$table->string('role');
$table->string('batting');
$table->string('bowling');
$table->string('image');
$table->string('odiRuns');
$table->integer('countries_id')->unsigned();
$table->foreign('countries_id')->references('id')->on('countries');
$table->timestamps();
});
}
Controller
use App\Player;
use App\Country;
use Illuminate\Http\Request;
class PlayerController extends Controller
{
public function index()
{
//
$players=Player::all();
return view('index',compact('players'));
}
View
#extends('layout')
#section('content')
#foreach ($players as $player )
{{$player->name}}
{{$player->age}}
{{$player->role}}
{{$player->batting}}
{{$player->bowling}}
{{$player->odiRuns}}
{{$player->country->name}}
#endforeach
#endsection
Edit
players all have country id's relating to the countries table
Tables
players table
countries table
The problem is your missing foreign key in relation. When you are defining a relationship, if you explicitly don't tell which foreign key to use for the relationship, Laravel looks for a foreign key like relationname_primarykeyoftheparenttable. In your case its country_id but in your players table the column name is countries_id. So relationship is not building and you are getting error. Change the column name or tell the relationship which foreign key to use to build the relationship.
class Player extends Model
{
protected $fillable =['name','age','role','batting','bowling','image','odiRuns','countries_id'];
public function country()
{
return $this->belongsTo(Country::class,'countries_id');
}
}
Laravel Doc

Eloquent - How to match data between tables of a single ID

Having multiple tables with data that relates to each other, i'm trying to display that data in a view using Laravel.
I must be confused with how Laravel runs its queries and I need help to sort how to do, what in PHP&SQL would be a left join.
My Asset Model:
public function category(){
return $this->hasOne(Category::class);
}
My Category Model:
public function asset()
{
return $this->belongsTo(Asset::class);
}
My Country Model:
public function country()
{
return $this->belongsTo(Asset::class);
}
And my AssetsController:
public function asset($id)
{
$asset = Asset::find($id);
return view('admin.assets.asset')->with('assets', $asset);
}
And the Router:
Route::get('/admin/assets/asset/{id}', [
'uses' => 'AssetsController#asset',
'as' => 'assets.asset'
//Show the Asset
]);
And the View:
<p><strong>Price:</strong>{{$assets->price}} €</p>
<p><strong>Description:</strong>{{$assets->description}}</p>
<p><strong>Country:</strong>{{$assets->country}}</p>
<p><strong>Category:</strong>{{$assets->name}}</p>
So in the 'asset.blade.php' I get the id from a previous index.blade.php that has a list of all the assets. I want to get via the ID, an asset page that displays the category name and the country name, instead of the ID that belongs to the Asset table.
So it should echo something like $assets->country->country_name and $assets->category->name
dd($asset);
EDIT: Additional information about migrations
categories_table migration
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('url');
$table->timestamps();
});
}
assets_table migration:
public function up()
{
Schema::create('assets', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->double('price',15,2);
$table->mediumText('description');
$table->integer('country');
$table->integer('category');
$table->integer('subcategory');
$table->integer('subsubcategory');
$table->integer('broker');
$table->string('featured');
$table->string('slug');
$table->timestamps();
});
}
Got it working.
class Category
{
public function asset()
{
return $this->hasMany(Asset::class);
}
}
class Asset
{
public function category()
{
return $this->belongsTo(Category::class);
}
}
use App\Asset;
use App\Category;
use App\Country;
use App\Subcategory;
use Illuminate\Http\Request;
class AssetController extends Controller
{
public function asset($id)
{
$asset = Asset::find($id);
return view('admin.assets.asset')
->with('asset', $asset)
->with('category', Category::all())
->with('subcategory', Subcategory::all())
->with('country', Country::all());
}
}
The other models have the same relationship towards the Asset model and vice-versa.
The View:
<p><strong>Category:</strong>{{$asset->category->name}}</p>
<p><strong>Sub-Category:</strong>{{$asset->subcategory->name}}</p>
It now shows the name matching the id of the corresponding tables.

Why does Laravel Combine query is not working?

My Channels Model is :
class Channels extends Model
{
protected $fillable = ['title','slug'];
public function Discussion()
{
return $this->hasMany('App\Discussion');
}
}
Channel Model is:
class Channels extends Model
{
protected $fillable = ['title','slug'];
public function Discussion()
{
return $this->hasMany('App\Discussion');
}
}
Channel Migration File :
class CreateChannelsTable extends Migration
{
public function up()
{
Schema::create('channels', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('slug');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('channels');
}
}
Discusion Migraion file
class CreateDiscussionsTable extends Migration
{
public function up()
{
Schema::create('discussions', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('channel_id')->unsigned();
$table->string('title');
$table->text('content');
$table->text('slug');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('discussions');
}
}
**Controller is: **
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function channel($slug)
{
$channel= Channels::where('slug',$slug)->first();
return view('channel')->with('discussion',$channel->Discussions);
}
}
And Finnaly the route is
Route::get('channel/{slug}',[
'uses' => 'HomeController#channel',
'as' => 'channel']);
**Now i am trying to fetch the data: **
$channel->Discussions
but it's giving me the error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'discussions.channels_id' in 'where clause' (SQL: select * from discussions where discussions.channels_id = 1 and discussions.channels_id is not null)
I don't know what exactly to do now. Please Help me
First of all, it's very important to name your classes and its relationships appropriately.
Laravel makes some assumptions about your foreign keys based on your class names and relationship definitions. You could also specify the foreign keys if you want.
However, here's how i'd do it.
class Channel extends Model
{
protected $fillable = ['title','slug'];
public function discussions()
{
return $this->hasMany('App\Discussion');
}
}
Notice here the model name is called Channel. When we have this class name and relationship, Laravel will assume that the discussion model has a foreign key called channel_id which it does.
You also need to define an inverse relationship in your Discussion model
class Discussion extends Model
{
public function channel()
{
return $this->belongsTo('App\Channel');
}
}
Now, doing the following would work:
public function channel($slug)
{
$channel = Channel::whereSlug($slug)->first();
return view('channel')->with('discussion', $channel->discussions);
}
If you are tied and cannot change the model name for whatever reason, then you need to specify a foreign key on your relationship definitions.
For example:
public function discussions()
{
return $this->hasMany('App\Discussion', 'channel_id');
}
public function channel()
{
// This one can stay the same as Laravel will try to match `channel_id`
// on the discussion table to the id on the channels table
return $this->belongsTo('App\Channel');
}
Fore more information, read about Eloquent Relationships.
Sorry, I was already writing this up when #Julien Metral commented, but this is an extension of what he already said :)

One to many relationship returns NULL

I have the following Migrations:
Table: bebidas:
class CreateBebidasTable extends Migration{
public function up() {
Schema::create('bebidas', function ($table) {
$table->increments('id');
$table->integer('tipo_id')->unsigned();
$table->string('bebi_name');
$table->string('bebi_size');
$table->float('bebi_price');
$table->timestamps();
$table->foreign('tipo_id')->references('id')->on('tipobebidas');
});
}
public function down() {
Schema::drop('bebidas');
}
}
Table: tipobebidas
class CreateTiposBebidasTable extends Migration {
public function up()
{
Schema::create('tipobebidas', function($table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::drop('tipobebidas');
}
}
These are the models:
class Bebida extends Eloquent{
public function TipoBebida() {
return $this->belongsTo('TipoBebida');
}
}
class TipoBebida extends Eloquent{
protected $table = "tipobebidas";
public function Bebidas() {
return $this->hasMany('Bebida');
}
}
Each Bebida (drink) has a TipoBebida (drink type) and vive-versa. I'm trying to get a composed table showing all fields from the bebidas table and tipobebidas table.
Based on Laravel's documentation on eager loading, I'm running the following command:
$bebidas = Bebida::with('tipobebida')->get();
At this point $bebidas has the following value: (I'm removing the timestamps fields)
[
{"id":1,"bebi_name":"COCA-COLA","bebi_size":"1 litro",
"bebi_price":4,"tipo_id":1,"tipobebida":null},
{"id":2,"bebi_name":"COCA ZERO","bebi_size":"1 litro",
"bebi_price":4,"tipo_id":1,"tipobebida":null}
]
Instead of "tipobebida":null, I was expecting something like "name":"refrigerantes" or some representation of the tipobebidas table contents.
I inspected the SQL commands being run, here it is:
select * from `tipobebidas` where `tipobebidas`.`id` in (?)
How can I get this to work?
I'll be using this data on a couple nested foreach loops to show the drinks Bebida grouped by type TipoBebida.
Thank you!
I got it to work. It all came down to naming conventions.
Here's what I did:
-The name of the foreign id field must be the singular of the table name plus _id, therefore the migration for bebidas was changed to the following:
class CreateBebidasTable extends Migration{
public function up() {
Schema::create('bebidas', function ($table) {
$table->increments('id');
$table->integer('tipobebida_id')->unsigned(); // ** new field name **
$table->string('name');
$table->string('size');
$table->float('price');
$table->timestamps();
});
}
public function down() {
Schema::drop('bebidas');
}
}
Also, the foreign key relationship was producing a SQL error, tried to fix it, still nothing, so I removed the following line: $table->foreign('tipo_id')->references('id')->on('tipobebidas');
Everything else remained unaltered.
The eager loading is working.
Thanks everyone for your help!!!
First, in tables bebidas and tipobebidas I don't see and foreign keys...
I think in bebidas you should have tipobebidas_id and it is a foreign key to tipobebidas id field.
After you do that, change your model methods to:
class Bebida extends Eloquent{
protected $table = "bebidas";
public function TipoBebida() {
return $this->belongsTo('TipoBebida', 'tipobebida_id');
}
}
class TipoBebida extends Eloquent{
protected $table = "tipobebidas";
public function Bebidas() {
return $this->hasMany('Bebida');
}

Resources