Eloquent Relationship returning empty array - laravel-5

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');
}
}

Related

Need to save foreign key manually on belongsTo relationship with withDefault()?

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

Get category and Sub_subcategories list using query builder

How to get a list of Category and subcategories like this:
1 mobile
apple
samsung
nokia
2:Laptops
Mac
HP
Dell
Sony
3:Tvs
Samsung
using query builder in controller and foreach loop in view
My Controller
$sub_catagories = DB::table('books_categories')
->join('sub_catagories','sub_catagories.catId','=','books_categories.catId')->get();
return view('index',compact('sub_catagories'));
My category table
public function up()
{
Schema::create('books_categories', function (Blueprint $table) {
$table->increments('catId');
$table->string('catName', 50)->nullable(false);
$table->timestamps();
});
}
My sub_catagory table
public function up()
{
Schema::create('sub_catagories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('catId');
$table->timestamps();
});
}
I've written some example of whole cycle. There is convention in laravel to use unique auto increment 'id's, and have foreign keys like RELATION_id. So if you want to change the table and column names anyway, you can do that with following to this example:
Category Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = 'categories';
protected $fillable = [
'id',
'name',
];
public function subcategories(){
return $this->hasMany(Subcategory::class, 'category_id', 'id');
}
}
Subcategory Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Subcategory extends Model
{
protected $table = 'subcategories';
protected $fillable = [
'id',
'category_id',
'name',
];
public function category(){
return $this->belongsTo(Category::class, 'category_id');
}
}
categories table Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCategoriesTable extends Migration
{
public function up()
{
Schema::create('categories', function (Blueprint $table) {
// PRIMARY
$table->bigIncrements('id');
// ADDITIONAL
$table->string('name');
// TIME
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('categories');
}
}
subcategories table Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSubcategoriesTable extends Migration
{
public function up()
{
Schema::create('subcategories', function (Blueprint $table) {
// PRIMARY
$table->bigIncrements('id');
// FOREIGN
$table->unsignedBigInteger('category_id')->nullable();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade')->onUpdate('cascade');
// ADDITIONAL
$table->string('name');
// TIME
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('subcategories');
}
}
usage in controller
// 1
public function categories()
{
$categories = Category::all()->get();
return view('categories', [
'categories' => $categories,
]);
}
// 2
public function catsWithSubcats()
{
$cats_with_subcats = Category::with('subcategories')->get();
return view('cats_with_subcats', [
'categories' => $cats_with_subcats,
]);
}
// 3
public function subcatsWithCats()
{
$subcats_with_cats = Subcategory::with('category')->get();
return view('subcats_with_cats', [
'subcategories' => $subcats_with_cats,
]);
}
If you want to show all categories with their subcategories in the blade, you don't need to use 2nd or 3rd method, just use 1st method. Create "categories.blade.php" inside of "resources/views/..." and write there something like this:
#foreach($categories as $category)
#foreach($category->subcategories as $subcategory)
<p>{{ $subcategory->name }}</p>
#endforeach
#endforeach

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.

Laravel Eloquent Relationship Many-to-one is not working

[Laravel 5.7] I have a relationship between two entities (User, Voices) as Many-to-One relationship and it is not working in my project.
Users migration:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('n_name');
$table->string('n_photo');
$table->string('n_gender');
});
Voices migration:
Schema::create('voices', function (Blueprint $table) {
$table->increments('id');
$table->string('voice');
$table->integer('n_id')->unsigned();
$table->foreign('n_id')->references('id')
->on('users')->onDelete('cascade');
});
Users Model:
class User extends Model
{
public function voices(){
return $this->hasMany(Voice::class);
}
}
Voices Model:
class Voice extends Model
{
public function user(){
return $this->belongsTo(User::class, 'n_id');
}
}
And the function "index" in my controller as below:
public function index()
{
$user= User::all();
$voices = $user->voices()::get(); -- error <described below>
return view('index', compact('user', 'voices'));
}
when I want to get the voices for each user it gives me an error says:
"Method Illuminate\Database\Eloquent\Collection::voices does not exist."
My view looks like this:
#if($n->voices)
#foreach($n->voices as $voice)
<audio controls src="voices/{{$voice->voice}}"></audio><br/>
#endforeach
#endif
I hope that I explained the issue very well and Ia waiting for a solution.
Sorry for my previous message, I've just got the issue you had.
You can't fetch relationship on a COLLECTION of entities.
Your controller should look like so:
public function index()
{
$user= User::with('voices')->get();
return view('index', compact('user'));
}
And your blade should look like:
#foreach($users as $user)
#foreach($user->voices as $voice)
<audio controls src="voices/{{$voice->voice}}"></audio><br/>
#endforeach
#endif
Does it work for you?
Try in your controller:
$users = User::with('voices')->get();
I use it that way and it works properly for me.

Laravel Relations, Models and Migrations

I have a problem with my relations in laravel:
I have two tables, Languages and Customers.The customer just can have 1 language. These are my migrations and Models:
Migrations:
Schema::create('tbl_customers', function (Blueprint $table){
$table->increments('id');
$table->string('first_name',255);
$table->string('last_name',255);
$table->date('date_of_birth');
$table->string('email',255);
$table->string('phone_number',255);
$table->string('phone_number2',255);
$table->string('password', 255);
$table->unsignedInteger('dealer_id');
$table->string('picture_profile',255);
$table->string('occupation',255);;
//Foreign key
$table->unsignedInteger('language_id');
$table->string('about_me',255);
});
Schema::create('tbl_languages', function (Blueprint $table){
$table->increments('id');
$table->string('language',255);
});
This is the foreign Key:
Schema::table('tbl_customers', function (Blueprint $table){
$table->foreign('language_id')->references('id')
->on('tbl_languages')->onDelete('cascade');
});
These are my Models.
Customer:
class Customer extends Model{
protected $table='tbl_customers';
protected $primaryKey="id";
protected $fillable=['address_id','first_name','last_name','gender_id','date_of_birth','email','phone_number','phone_number2',
'dealer_id','picture_profile','occupation','time_zone_id','language_id','about_me'];
protected $hidden=['password'];
public $timestamps = false;
public function language(){
return $this->hasMany(Language::class);
}}
Language
class Language extends Model{
protected $table='tbl_languages';
protected $primaryKey="id";
protected $fillable=['language'];
public $timestamps=false;
public function customers(){
return $this->belongsToMany(Customer::class);
}}
So, If I make a query I have the next error:
error
why? If the migrations have the standard that Laravel says
If I change the Customer model like this:
public function language(){
return $this->hasMany(Language::class,'id','language_id');
}
It works good, but Languages no.
I wish you guys can help me.
add this to your Customer model:
public function language(){
return $this->belongsTo('App\Language');
}
and this to your Language model:
public function customers(){
return $this->hasMany('App\Customer');
}

Resources