Use foreign key id to get a foreign table name - php

I have some tables, all estate have an category_id, I put a foreign key to do the relationship, but won't work now, How can I list my estate with the equivalent category name
Category Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = 'categories';
protected $fillable = ['name'];
public function estate()
{
return $this->belongsTo('App\Estate');
}
}
Estate Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Estate extends Model
{
protected $table = 'estates';
protected $fillable = ['categories_id'];
public function category()
{
return $this->hasMany('App\Category');
}
}
Create Estate table
Schema::create('estates', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
$table->string('name');
$table->string('estate_photo')->nullable(true);
$table->double('value');
$table->integer('label_id');
});
Create Category table
Schema::create('categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
Add category foreign key to estate
Schema::table('estates', function (Blueprint $table) {
$table->unsignedBigInteger('categories_id');
$table->unsignedBigInteger('sub_categories_id');
$table->foreign('categories_id')->references('id')->on('categories');
$table->foreign('sub_categories_id')->references('id')->on('sub_categories');
});
My object have not foreign key data to get $object->categories_id->name

According to your models, you have to use :
// get all estates for the example
$estates = Estate::get();
foreach ($estates as $estate) {
// use the name of the relation to get your category - first
dump($etate->category[0]->name);
// or to get all categories
foreach ($etate->category as $category) {
dump($category->name);
}
}

I'm sure this would work .. correct me if I'm wrong
Estate::with('category')->get();
It will bring back all the estates, each one with its categories attached.

Related

How to seed a separate table with foreign keys in Laravel

I have three tables with genres, movies and their relationship. I want to create a seed for the relationship table but don't really know how to do it exactly so the genre_id and movie_id would have the same number id. Here's the migration for the genres:
public function up()
{
Schema::create('genres', function (Blueprint $table) {
$table->id();
$table->string('name');
});
}
Movies:
public function up()
{
Schema::create('movies', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('status')->nullable()->default(0);
$table->string('image_path')->default('images/default.png');
});
}
Relationship:
public function up()
{
Schema::create('genre_movie', function (Blueprint $table) {
$table->foreignId('genre_id')->constrained();
$table->foreignId('movie_id')->constrained();
});
}
Here's the movie model:
class Movie extends Model
{
use HasFactory;
protected $fillable = ['name', 'status', 'image_path'];
public function genres()
{
return $this->belongsToMany(Menu::class, 'genre_movie');
}
}
Here's the genre model:
class Genre extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function movies()
{
return $this->belongsToMany(Movie::class, 'genre_movie');
}
}
Seed your genres and movies tables initially, then you can use those to seed your genre_movie table. So for example:
// Seed 10 genres
Genere::factory(10)->create();
// Seed 50 movies
Movie::factory(50)->create();
// Seed some relationships
foreach (Genre::all() as $genre) {
$movies = Movie::inRandomOrder()->take(random_int(1, Movie::count())->get();
$genre->movies()->attach($movies);
}
Update 1
is there a way to control how many records its gonna create for the genre_movie table?
Yup.
$movies = Movie::inRandomOrder()->take(10)->get();
Altering the parameter value provided to take(x) will define how many records are created in the genre_movie table for each Genre. In the above example it will create 10 records per Genre. That could be set to two with take(2) etc.
Alternatively you could always just grab the first() Movie record if you just want a single Movie per Genre in your genre_movie table.
$movies = Movie::inRandomOrder()->first();

Laravel Model relationship "Page have many Attachments"

I have models:
Page:
id
slug
Image
id
file
Video
id
file
I need the Page model to have a relation with several Image and Video models through one relationship, like
foreach($page->attachments as $attachment)
{
// $attachment can be Image or Video
}
And inserts like
$attachments = [$image, $video];
$page->attachments()->saveMany($attachments);
I tried to make a morph relationship, but nothing comes of it, please help.
Create an Attachment Model and attachments Table with the following columns/properties:
id
file
page_id
type (video/image)
then you could add hasmany relationship to your page model
public function attachments()
{
return $this->hasMany(Attachment::class);
}
Then you can fetch the attachment like you tried
In order to achieve this you have to make table for relations. This table should be defined like this:
page_image_video
id
page_id
image_id
video_id
And fields page_id, image_id and video_id should be a foreign keys. This is a table where you will save you attachments for your page. After that, you can define method attachments() in you Page Model with hasMany().
Create Migration :
Page Table :
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string("slug");
$table->timestamps();
});
Image Table :
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string("file");
$table->timestamps();
});
Videos Table :
Schema::create('video', function (Blueprint $table) {
$table->increments('id');
$table->string("file");
$table->timestamps();
});
Pageables Table :
Schema::create('pageables', function (Blueprint $table) {
$table->integer("pages_id");
$table->integer("pageable_id");
$table->string("pageable_type");
});
Create Model :
Now, we will create Pages, Images and Video model. we will also use morphToMany() and morphedByMany() for relationship of both model.
Video Model :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
use HasFactory;
protected $table='video';
protected $primaryKey='id';
protected $guarded = [];
public function pages()
{
return $this->morphToMany(Pages::class, 'pageable');
}
}
Images Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Images extends Model
{
use HasFactory;
protected $table='image';
protected $primaryKey='id';
protected $guarded = [];
public $timestamps = false;
public function pages()
{
return $this->morphToMany(Pages::class, 'pageable');
}
}
Pages Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
class Pages extends Model
{
use HasFactory;
protected $table='page';
protected $primaryKey='id';
protected $guarded = [];
public $timestamps = false;
public function posts()
{
return $this->morphedByMany(Images::class, 'pageable');
}
/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany(Video::class, 'pageable');
}
}
Retrieve Records :
$pages = Pages::find(1);
foreach ($pages->posts as $post) {
var_dump($post);
}
foreach ($pages->videos as $video) {
print_r('<br>');
//var_dump($video);
}
Create Records :
$page = Pages::find(1);
$img = new Images();
$img->file = "test insert";
$page->posts()->save($img);
All done.

morphToMany real many to many relation

All polymorh examples I found are one to many if I get it correct. (Tag to Post / Video e.g)
In my Case the parent class is multiple and the child class also. Therefore i set up the pivot table
Tables
Person
id
Venture
id
Capital
id
Estate
id
PIVOT TABLE
Revenues
emitter_id //ID of the revenue emitting class (Venture, Capital, Estate)
emitter_type // Class of the Emitter (App\Models\Venture App\Models\Estate)
receiver_id // Id of Receiver (Venture or Person)
receiver_type // type of Receiver (App\Models\Venture or App\Models\Person)
revenue
In the Estate Model i try this
public function revenuePersons()
{
// searched type, own type/id ,tabel own ID to search id
return $this->morphToMany(Person::class, 'emitter' ,'revenues' ,'emitter_id','receiver_id')
->withPivot('revenue');
}
One the Person Model
public function estaterevenues(){
// searched type, own type/id ,tabel own ID to search id
return $this->morphToMany(Estate::class, 'receiver' ,'revenues' ,'receiver_id','emitter_id')
->withPivot('revenue');
}
The Code works but in some cases i get additional relations back. So it seams the searched _type is not correctly considered.
So i started to implement a own database query function that gives me the Revenue Entry back. It works correctly.
Revenue Model
public function getRevenue($ownside, $emitter_id = Null, $emitter_type,$receiver_id=Null, $receiver_type ){
$revenue = DB::table('revenues')
->where('emitter_id', $emitter_id)
.....()->get()}
But I am not able to do something like
$persons->getRevenues
because a Relationship is expected as return value
So if anyone has an idea how to do that correctly I would be very happy. Or some other best practices for this many to many approach.
The second Question is how to get all revenue receiver at once.
Instead of
$estate->revenuepersons
$estate->revenueventures
Have something like
$estate->revenues //that list both, Ventures and Persons
And here a Class Diagram
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
/**
* Get all of the posts that are assigned this tag.
*/
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany(Video::class, 'taggable');
}
}
$post = Post::find(1);
dd($post->tags);
$video = Video::find(1);
dd($video->tags);
$tag = Tag::find(1);
dd($tag->posts);
$tag = Tag::find(1);
dd($tag->videos);
posts table migration:
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
videos table migration:
Schema::create('videos', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
tags table migration:
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
taggables table migration:
Schema::create('taggables', function (Blueprint $table) {
$table->integer("tag_id");
$table->integer("taggable_id");
$table->string("taggable_type");
});

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();

Laravel: Retrieving table results by category name instead of id

So I have this relationship between products and productcategories, one product belongs to a category and a category can hold many products, problem is I want to retrieve all products belonging to a productcategory by name instead of using id.
Something similary looking to this??
public function index()
{
Product::where(productcategory->name, 'Starters')->get();
}
These are my migrations:
//CREATE PRODUCTS TABLE
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('productcategory_id')->index();
$table->foreign('productcategory_id')->references('id')->on('productcategories')->onDelete('cascade');
$table->string('name');
$table->string('description')->nullable();
$table->string('image')->nullable();
$table->boolean('available')->default(true);
$table->string('half');
$table->string('full');
$table->timestamps();
});
//CREATE PRODUCT CATEGORIES TABLE
Schema::create('productcategories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('description')->nullable();
$table->string('image')->nullable();
$table->timestamps();
});
DB::table('productcategories')->insert([
'name' => 'Starters'),
]);
DB::table('productcategories')->insert([
'name' => 'Salads'),
]);
DB::table('productcategories')->insert([
'name' => 'Soups'),
]);
And my models:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ProductCategory extends Model
{
protected $table = 'productcategories';
public function products()
{
return $this->HasMany('App\Product');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = 'products';
public function orders()
{
return $this->belongsToMany('App\Order');
}
public function productcategory()
{
return $this->belongsTo('App\ProductCategory');
}
}
Any help?
Start with the product category and get its products:
$products = ProductCategory::where('name', 'Starters')->first()->products;
Or use whereHas():
$products = Product::whereHas('productcategory', function($query) {
$query->where('name', 'Starters');
})->get();

Categories