laravel eloquent relationship hierarchy - php

I seem to be having a problem understanding this hierarchical relationship.
Farm > Fields > Shepherds > Sheep
It seems a pretty straightforward hierarchy - Farm hasMany fields, field hasMany shepherds, shepherd hasMany sheep.
Sheep belong to a shepherd, shepherds belongs to fields, fields belong to farms.
I have defined this model relationships thus:
class Sheep extends Model {
protected $fillable ['name'];
public function shepherd() {
return $this->belongsTo('App\Shepherd');
}
}
class Shepherd extends Model {
protected $fillable ['name'];
public function field() {
return $this->belongsTo('App\Field');
}
public function sheep() {
return $this->hasMany('App\Sheep');
}
}
class Field extends Model {
protected $fillable ['name'];
public function farm() {
return $this->belongsTo('App\Farm');
}
public function shepherd() {
return $this->hasMany('App\Shepperd');
}
}
class Farm extends Model {
protected $fillable ['name'];
public function field() {
return $this->hasMany('App\Field');
}
}
public function up()
{
Schema::create('farms', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
}
public function up()
{
Schema::create('fields', function (Blueprint $table) {
$table->increments('id');
$table->integer('farm_id');
$table->string('name');
});
}
public function up()
Schema::create('shepherds', function (Blueprint $table) {
$table->increments('id');
$table->integer('field_id');
$table->string('name');
});
}
public function up()
Schema::create('sheep', function (Blueprint $table) {
$table->increments('id');
$table->integer('shepherd_id');
$table->string('name');
});
}
I would expect to be able to save each model in the following manner.
$farm = new App\Farm;
$farm->name = 'West Farm';
$field = new App\Field;
$field->name = 'The orchard';
$shepherd = new App\Shepherd;
$shepherd->name = 'Jason';
$sheep = new App\Sheep;
$sheep->name = 'Sean';
$farm->save();
$farm->field()->save($farm);
$farm->field->shepherd()->save($shepherd);
$farm->field->shepherd->sheep()->save($sheep);
But it does not work. Once I get to $farm->field->shepherd()->save($shepherd); the process breaks down. I would appreciate some assistance in the correct manner of saving using the relationships between all the tables.
I'm pulling my hair out trying to understand this, so any help would be greatly appreciated.
thanks

Your code breaks here:
$farm->field->shepherd()->save($shepherd);
Farms have many fields, so when you reference $farm->field, you're getting a collection of Field object, not just a single Field object.
To make it work, you need to either reference $farm->field[0]
$farm->field[0]->shepherd()->save($shepherd);
or just use the $field object you created before:
$field->shepherd()->save($shepherd);
I'd also suggest to use plural names for your hasMany relations (fields, sheeps, etc.) - this way you'll always remember that the referenced fields refer to a collection, not a single object

Related

App\Tasks::first()->projects; in artisan tinker returns null, no matter what :(

The following code in tinker returns a null value while it should return the project to which the first task is linked.
App\Task::first()->projects;
Already tried renaming the method names, column names in migrations, tried exiting tinker and logging back in
Project Migration
public function up()
{
Schema::create('projects', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('title');
$table->string('description');
$table->timestamps();
});
}
Task Migration
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('project_id');
$table->string('description');
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
Project.php
use App\Task;
class Project extends Model
{
protected $fillable = ['title','description'];
public function tasks(){
return $this->hasMany(Task::class);
}
}
Task.php
use App\Project;
class Task extends Model
{
protected $fillable = [
'completed'
];
public function projects(){
return $this->belongsTo(Project::class);
}
}
If anyone could just review this piece of code and let me know where I have made any conventional\idiotic mistakes (since Im new to route model binding) it would be of great help!
A task belongs to a project, so rename projects to project as it is singular. If you keep projects then provide the column name as second parameter:
public function projects(){
return $this->belongsTo(Project::class, 'project_id');
}
// I suggest this
public function project(){
return $this->belongsTo(Project::class);
}
Your column types are different, for the id of the project you use Big Integer and for the reference you use Integer, so this:
$table->unsignedInteger('project_id');
should be this:
$table->unsignedBigInteger('project_id');
// also good to make the relationship on the Database level:
$table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade');

BelongsTo in Laravel

I have a table which is named cars with 2 fields id, matriculation.
Then, I have another table which is named series with 2 fields id, name.
I have created my fk_serie on my table cars.
public function up()
{
Schema::create('cars', function (Blueprint $table) {
$table->increments('id');
$table->string('matriculation', 25);
$table->integer('fk_serie')->unsigned();
$table->foreign('fk_serie')->references('id_serie')->on('serie');
$table->timestamps();
});
}
Here is my information about the table series.
public function up()
{
Schema::create('series', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 30);
$table->timestamps();
});
}
In my model, I only have a function on the model Car.
public function serie(){
return $this->belongsTo('App\Serie', 'fk_serie');
}
I don't have nothing in my model Serie
class Serie extends Model
{
//
}
Is it normal that the model Serie is empty?
Because, my join works.
What do you think ?
Is there an error?
As Dparoli mentioned in comments if you don't need the below query then your above structure of relationship is normal
Serie::with('cars')->find($id)
But if you want to setup relationship in Serie Model you can do something like below:
class Serie extends Model
{
public function cars() {
return $this->hasMany('App\Car', 'fk_serie'); // your relationship
}
}
And after that you can do:
$series = Serie::with('cars')->find($id); //eager loading cars
$cars = $series->first()->cars;

laravel eloquent for hasMany relation does not work

I have these relations in my database
Schema::create('my_users', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('fullName');
$table->string('userName');
$table->string('password');
$table->string('photo');
$table->string('email');
});
and
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('photo');
$table->text('caption');
$table->integer('like');
$table->integer('my_user_id');
});
my models :
class myUser extends Model
{
public function post()
{
return $this->hasMany('App\post');
}
}
class post extends Model
{
public function user()
{
return $this->belongsTo('App\myUser');
}
}
now I'm trying to get a user's data using the following code :
$post = post::find(1);
$user = $post->user;
but it doesn't work and $user is NULL.
I'm sure that in posts table there is a record with id 1.
the weird part is this that I get no error when I change the method's name like this :
$post = post::find(1);
$user = $post->somethingBullshit;
I'm using laravel 5.3.
help please.
Confirm that you are naming your class files starting with upper case letters, and modify your class declarations accordingly, such as:
class MyUser extends Model
{
public function post()
{
return $this->hasMany('App\Post');
}
}
class Post extends Model
{
public function user()
{
return $this->belongsTo('App\MyUser');
}
}
You can then select the user when you obtain the post by utilizing eloquent's with() method, and obtain your $user variable from your $post variable, OR just use the user property of post as follows:
$post = Post::with('user')->find(1);
$user = $post->user;

Laravel Many To Many Polymorphic Relation doesn't work

hi I'm trying to use many to many polymorphic but somehow it doesnt work I attach my code can you find out what I do wrong?
my migration :
Schema::create('stickers', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('type');
$table->timestamps();
});
Schema::create('stickables', function (Blueprint $table) {
$table->integer('sticker_id')->nullable();
$table->integer('stickable_id');
$table->string('stickable_type');
$table->primary(['sticker_id', 'stickable_id', 'stickable_type']);
$table->foreign('sticker_id')
->references('id')->on('stickers')
->onDelete('cascade');
$table->timestamps();
});
and my models
Trip model:
public function stickables()
{
return $this->morphToMany(Stickable::class, 'stickable');
}
Stickable model:
public function trips()
{
return $this->morphedByMany(Trip::class, 'stickable');
}
controller:
public function store(Request $request)
{
$trip = new Trip();
$trip->name = $request->name;
$trip->desc = $request->desc;
$trip->creator_id = Auth::user()->id;
$trip->save();
$tags=$request->tags;
$trip->stickables()->attach($tags);
$trip->save();
return redirect('/trip');
}
Here is how you should define your relationship:
Trip Model:
public function stickers()
{
return $this->morphToMany(Sticker::class, 'stickable');
}
Sticker Model:
public function trips()
{
return $this->morphedByMany(Trip::class, 'stickable');
}
You don't need a model for your relationship (Stickable).You should create a model for stickers and define your relationship on that.
Stickable can refer to Trip or any other type of model you need to create a relationship with stickers. However in your code you have a stickable method on the Trip model, which does not make sense.
Eloquent Many to Many Polymorphic Relationships

Laravel One to many CRUD Example

I am new to Laravel. I want to insert data to certain master detail tables with Laravel4. I searched all over the internet and could not find a proper solution.
I have two (plus one) tables as shown below.
PO_HEADER
PO_HEADER_ID
SUBJECT
PO_DATE
PO_DETAIL
PO_DETAIL_ID
PO_HEADER_ID
DESCRIPTION
AMOUNT
QTY
UNIT_OF_MEASURE_ID
UNIT_OF_MEASURE
UNIT_OF_MEASURE_ID
UNIT_OF_MEASURE
I should be able to insert the PO master along with as many PO detail records in one shot while pressing a SAVE BUTTON. Unit of measure in the detail section should be a drop down list (filled from the UNIT_OF_MEASURE table)
Kindly suggest how to achieve this easily. Thanks in advance!
This depends on your models being set up correctly:
class PurchaseOrder extends \Eloquent
{
protected $fillable = [
'subject',
'date'
];
public function detail()
{
return $this->hasMany('PurchaseOrderDetail');
}
}
class PurchaseOrderDetail extends \Eloquent
{
protected $fillable = [
'description',
'amount',
'qty'
];
protected $with = [
'unitOfMeasure',
];
public function header()
{
return $this->belongsTo('PurchaseOrder');
}
public function unitOfMeasure()
{
return $this->hasOne('UnitOfMeasure');
}
}
class UnitOfMeasure extends \Eloquent
{
protected $fillable = [
'name'
];
public function lineItems()
{
return $this->belongsToMany('PurchaseOrderDetail');
}
}
You also need to set up your migrations using the proper settings, like so:
//migration for purchaseorder table
public function up()
{
Schema::create('purchaseorders', function(Blueprint $table)
{
$table->increments('id');
$table->string('subject');
$table->string('date');
$table->timestamps();
});
}
//migration for purchaseorderdetail table
public function up()
{
Schema::create('purchaseorderdetails', function(Blueprint $table)
{
$table->increments('id');
$table->integer('purchaseorder_id')->unsigned()->index();
$table->integer('unitofmeasure_id')->unsigned()->index();
$table->foreign('purchaseorder_id')->references('id')->on('purchaseorders');
$table->string('description');
$table->float('amount');
$table->float('qty');
$table->timestamps();
});
}
//migration for unitsofmeasure table
public function up()
{
Schema::create('unitsofmeasure', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
That should get you fairly close to what you need, I hope. :) You can then query for your items like so:
$po-details = PurchaseOrderDetail::with(['purchaseOrder', 'unitOfMeasure')->find($id);
This is what an overly simplified controller method may look like:
class PurchaseOrderController
{
public function show($id)
{
$purchaseOrders = PurchaseOrder::with('detail')->find($id);
return View::make('purchaseOrder.show', compact('purchaseOrders'));
}
}
And then your view:
#foreach ($purchaseOrders as $purchaseOrder)
#foreach ($purachseOrder->detail as $lineItem)
#endforeach
#endforeach

Categories