it seems that I need to save the original model on the newly generated model in order to save the relation correctly.
I hope the below test case illustrates my problem:
// migrations
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->bigInteger('user_id')->nullable();
$table->timestamps();
});
//models
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class)
->withDefault(['name' => 'Guest User']);
}
}
//test
public function test_foreign_key()
{
$post = factory(Post::class)->create();
$user = $post->user; // created from ->withDefault()
$user->save();
$this->assertNotNull($post->user);
$this->assertNotNull($post->user_id);
}
With additional association of the original model the test passes:
public function test_foreign_key_associates()
{
$post = factory(Post::class)->create();
$post->user->save();
$this->assertNotNull($post->user);
$post->user()->associate($post);
$this->assertNotNull($post->user_id);
}
edit: what I'm doing right now is the following for the withDefault relationship:
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class)
->withDefault(function (User $user, Post $post) {
$user->name = "Guest User";
$user->save();
$post->user_id = $user->id;
});
}
}
Related
I use Laravel with UserAuth and Roles. All works fine. Now I want to add many Roles.
The Roles Should be Recursive.
Schema::create('role_user', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedBigInteger('role_id');
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
});
Schema::create('role_role', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('parent_id');
$table->foreign('parent_id')->references('id')->on('roles')->onDelete('cascade');
$table->unsignedBigInteger('child_id');
$table->foreign('child_id')->references('id')->on('roles')->onDelete('cascade');
});
$user->roles(); give me all roles where the user is direct asigned.
Example:
User is in Role1 in role_user table
Role 1 is in Role 2 in role_role table
Role 2 is in Role 3 in role_role table
$user->roles(); Result is Role1.
$user->roles(); Result should contain Role1, Role2, Role3. Not as text. It should be an array
I've to manipulate
public function roles()
{
return $this->belongsToMany(Role::class);
}
But how?
Very Thanks.
You need to do a recursive relationship:
public function childrenRoles()
{
return $this->hasMany(Role::class, 'parent_id', 'id');
}
public function allChildrenRoles()
{
return $this->childrenRoles()->with('allChildrenRoles');
}
You can then access all your roles using
$role = Role::with('allChildrenRoles')->first();
$role->allChildrenRoles->first()->allChildrenRoles; // .. and so on
I've made my own Solutions and it works good.
Role.php:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
public function users()
{
return $this->belongsToMany(User::class);
}
public function belongsToUser(User $user,$int)
{
if ($this->hasUser($user)) {
return true;
}
$children = $this->childrenRoles();
if ($int > 10) {
return false;
}
foreach ($children->get() as $child)
{
if ($child->belongsToUser($user,$int+1)) {
return true;
}
}
return false;
}
public function childrenRoles()
{
return $this->belongsToMany(Role::class, 'role_role', 'child_id', 'parent_id');
}
public function hasUser(User $user)
{
return null !== $this->users()->where('user_id', $user->id)->first();
}
}
User.php
public function roles()
{
$r = Role::where('id','<>', 'null');
foreach ($r->get() as $role)
{
if (! $role->belongsToUser($this,0)) {
$r = $r->where('id', '<>', $role->id);
}
}
return $r->get();
}
I'm New to laravel and I'm trying to achieve something very basic stuff but still getting stuck.
I have two models namely Post.php and Like.php
I'm trying to fetch all the likes linked to a post using eloquent relationship but it is returning an empty array. Here is my code-
Post.php
public function likes(){
return $this->hasMany('App\Like');
}
Route.php
Route::get('/', function(){
$posts = Post::all()->sortByDesc("post_id");
return view('index')->with(['posts' => $posts]);
});
View.blade.php
#foreach($posts as $post)
{{ $post->likes }}
#endforeach
What am I doing wrong here?
Update-
likes table migration
public function up()
{
Schema::create('likes', function (Blueprint $table) {
$table->increments('like_id');
$table->integer('post_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->foreign('post_id')->references('post_id')->on('posts')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
});
}
Post Migration
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('post_id');
$table->integer('user_id')->unsigned();
$table->string('post_message');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
Post Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function user(){
return $this->belongsTo('App\User');
}
public function likes(){
return $this->hasMany('App\Like');
}
}
Laravel expects the primary key to be id, but you are using the custom post_id.
Specify it in your model and adjust the relationship:
class Post extends Model {
protected $primaryKey = 'post_id';
public function likes() {
return $this->hasMany('App\Like', 'post_id');
}
}
I hope this thread find everyone healthy.
What is wrong with the following code? I am getting an error on my many to many relationship. For the past 4 hours i am stuck with this problem. I would be very thankful if you find the bug or source of problem.
Here is my code and tables:
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->integer('category');
$table->string('thumbnail');
$table->string('images');
$table->string('logo');
$table->string('main_photo');
$table->timestamps();
});
//categories table
Schema::create('product_categories', function(Blueprint $table)
{
$table->increments('id');
$table->string('category');
});
//relationship table
Schema::create('product_productcategory', function(Blueprint $table)
{
$table->increments('id');
$table->integer('product_id'); // the id of the bear
$table->integer('productcategories_id'); // the id of the picnic that this bear is at
});
products model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'App\product_productcategory', 'product_id', 'productcategories_id');
}
}
And pivot model
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'App\product_productcategory', 'productcategories_id', 'product_id');
}
}
Thanks in advance!
Updates: The problem is solved thanks to #mimo.
But now i want to translate the categories in different languages so i created a table like this:
Schema::create('category_translations', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('product_categories')->onDelete('cascade');
$table->integer('locale_id')->unsigned();
$table->foreign('locale_id')->references('id')->on('locales')->onDelete('cascade');
$table->unique(['category_id', 'locale_id']);
});
And my product categories with new relationship to the translations
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
//return $this->belongsToMany('App\Product', 'App\product_productcategory', 'productcategories_id', 'product_id');
return $this->belongsToMany('App\Product', 'product_productcategory');
}
public function translation($lang) {
return $this->hasMany('App\Category_Translation')->where('locale_id', '=', $lang);
}
}
And in category translation:
class Category_Translation extends Model
{
protected $table = 'category_translations';
public function product_category() {
return $this->belongsTo('App\product_category');
}
}
And finally my Product:
class Product extends Model
{
protected $table = 'products';
public function translation($lang) {
return $this->hasMany('App\Product_Translation')->where('locale_id', '=', $lang);
}
public function product_category() {
//return $this->belongsToMany('App\product_category', 'App\product_productcategory', 'product_id', 'productcategories_id');
//return $this->belongsToMany('App\product_category', 'product_productcategory');
return $this->belongsToMany('App\product_category', 'product_productcategory')->translation(1);
}
}
Now when i run:
$product = App\Product::find(1)->first();
echo $product->product_category;
I get error:
Call to undefined method Illuminate\Database\Query\Builder::translation()
Your migration file is wrong:
//relationship table
Schema::create('product_productcategory', function(Blueprint $table)
{
$table->integer('product_id')->unsigned()->index(); // the id of the bear
$table->foreign('product_id')->references('id')->on('products');
$table->integer('productcategories_id')->unsigned()->index(); // the id of the picnic that this bear is at
$table->foreign('productcategories_id')->references('id')->on('product_categories');
});
This code will made the relationship on the database level.
When you have 12 min free time you can check out this tutorial about many to many relationships in laravel:
https://laracasts.com/series/laravel-5-fundamentals/episodes/21
Update:
you need to update your relationships too:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory');
}
}
and:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
}
I have a many to many relationship between products and a product_categories tables. Now I want to create a translation table for categories.
But how do I relate them in eloquent? i am learning database relationships so forgive my ignorance.
Here is my tables:
//languages
Schema::create('locales', function(Blueprint $table)
{
$table->increments('id');
$table->string('code', 2);
$table->string('name');
});
//products
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->string('thumbnail');
$table->timestamps();
});
//categories
Schema::create('product_categories', function(Blueprint $table)
{
$table->increments('id');
$table->string('category');
});
//relationship table
Schema::create('product_productcategory', function(Blueprint $table)
{
$table->integer('product_id')->unsigned()->index(); // the id of the bear
$table->foreign('product_id')->references('id')->on('products');
$table->integer('product_category_id')->unsigned()->index(); // the id of the picnic that this bear is at
$table->foreign('product_category_id')->references('id')->on('product_categories');
});
//category translations
Schema::create('category_translations', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('product_categories')->onDelete('cascade');
$table->integer('locale_id')->unsigned();
$table->foreign('locale_id')->references('id')->on('locales')->onDelete('cascade');
$table->unique(['category_id', 'locale_id']);
});
Product Model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory')->translation(1);
}
}
Product categories:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
}
Category Translations
class Category_Translation extends Model
{
protected $table = 'category_translations';
public function product_category() {
return $this->belongsTo('App\product_category');
}
}
But when i run:
$product = App\Product::find(1)->first();
echo $product->product_category;
I get error:
Call to undefined method Illuminate\Database\Query\Builder::translation()
You should not call translation in the Product model category relation (because you still interacting with the query builder), instead you should access the translation as a property on the category object:
echo $product->product_category->first()->getTranslatedIn(1)->name;
So you could refactor your code like this:
Product Model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory');
}
}
Product categories:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
public function translations() {
return $this->hasMany('App\Category_Translation', 'category_translations');
}
// relation filtered by language (cannot be accessed as a property unless you define the parameter as optional)
public function translatedIn($language) {
return $this->hasOne('App\Category_Translation', 'category_id')->where('locale_id', $language);
}
// access translated object
public function getTranslatedIn($language) {
return $this->translatedIn($language)->getResults();
}
}
I have a User class with the following:
public function school()
{
return $this->belongsToMany('School');
}
I have a School class with the following:
public function user()
{
return $this->belongsToMany('User');
}
I create my pivot table use the pivot generator, here is the migrate for it:
public function up()
{
Schema::create('school_user', function(Blueprint $table) {
$table->increments('id');
$table->integer('school_id')->unsigned()->index();
$table->foreign('school_id')->references('id')->on('schools')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->boolean('admin');
$table->timestamps();
});
}
There is only one item in the user table, the school table, and the pivot table. When I do
$user = User::where('email', '=', Input::get('email'))->first();
$schools = $user->schools;
return Response::json([
'success' => true,
'user' => $user->toArray(),
'schools' => $schools
]);
It returns a null for the schools. Am I missing something?
You have declared:
public function school()
{
return $this->belongsToMany('School');
}
But using $user->schools, you should change the function declaration to schools:
public function schools()
{
//...
}
Also make sure that, you are using the right relationship, I'm confussed because one user may belongs to only one school (logically).