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.
Related
I am a laravel beginner. In my laravel CRUD project, I have these migration table
GroupTable
class Group extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('group', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('group_code');
$table->string('group_desc');
$table->timestamps();
});
}
CategoryTable
class Category extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('category', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('category_code');
$table->string('category_desc');
$table->timestamps();
});
}
ItemTable
class Item extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('item', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('item_code');
$table->string('item_desc');
$table->string('item_picture');
$table->string('item_cost');
$table->string('item_price');
$table->string('group_desc');
$table->string('category_desc');
$table->timestamps();
});
}
The group_desc and category_desc from ItemTable are foreign key from GroupTable and CategoryTable.
GroupController
public function destroy($id)
{
Group::find($id)->delete();
return response()->json(['success'=>'Group deleted successfully.']);
}
CategoryController
public function destroy($id)
{
Category::find($id)->delete();
return response()->json(['success'=>'Category deleted successfully.']);
}
This is the ajax delete function in my view of group
//Delete
$('body').on('click', '.deleteRecord', function () {
var id = $(this).data("id");
if(confirm("Are you sure want to delete? "))
{
$.ajax({
type: "DELETE",
url: "{{ url('group/delete') }}" + '/' + id,
success: function (data) {
table.draw();
},
error: function (data) {
console.log('Error:', data);
}
});
}
});
Before user want to delete the row on GroupTable or CategoryTable, how to display a message shows that the row are not allow to delete if ItemTable have data from GroupTable or CategoryTable?
If you are using the foreign key and if it is not a 'cascade' delete, then laravel won't allow you to delete the row when If the same Id used somewhere. for example,
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); //inside item table. (CASCADE delete).
$table->foreign('category_id')->references('id')->on('categories');// non-cascade
assume, If you are using cascade delete, and you are trying to delete the category which is used in the item table, this will delete the category and related item lists in item table.
If you are using non-cascade method, It won't allow you to delete the category when it is used in item table.
If you follow Laravel's convention, things will be a lot easier to do. Might be longer at first but it gets better
(I am assuming you are using Laravel 8)
1: Table names are usually in plural forms, so your tables should be groups, categories and items
2: Next is to properly define foreign keys for groups and categories tables in items table like this
Schema::create('item', function (Blueprint $table) {
//...
$table->foreignId('group_id')->constrained();
$table->foreignId('category_id')->constrained();
//...
});
3: Define the respective relations in the 3 models
Group Model
namespace App\Models;
class Group extends Model
{
//...
public function items(){
return $this->hasMany(Item::class);
}
//...
}
Category model
namespace App\Models;
class Category extends Model
{
//...
public function items(){
return $this->hasMany(Item::class);
}
//...
}
Item Model
namespace App\Models;
class Item extends Model
{
//...
public function category(){
return $this->belongsTo(Category::class);
}
public function group(){
return $this->belongsTo(Group::class);
}
//...
}
All the above, while kind of long, will make your work easier later.
From here you can implement the following
GroupController
public function destroy($id)
{
$group = Group::withCount('items')
->find($id);
if($group->items_count < 1){
$group->delete()
return response()->json(['success'=>'Group deleted successfully.']);
}
return response()->json(['fail'=> 'Group has items, cannot be deleted.' ]);
}
CategoryController
public function destroy($id)
{
$category = Category::withCount('items')
->find($id);
if($category->items_count < 1){
$category->delete()
return response()->json(['success'=>'Category deleted successfully.']);
}
return response()->json(['fail'=> 'Category has items, cannot be deleted.' ]);
}
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();
I had used many to many relationship.i have three table named:product,tag,productstag. in here I want whenever I am going to delete a product it will also delete the relationship it had on productstag table.
public function up()
{
Schema::create('productstags', function (Blueprint $table) {
$table->integer('product_id');
$table->integer('tag_id');
$table->primary(['product_id','tag_id']);
$table->timestamps();
});
}
as you can see I have used product_id and tag_id as the primary key.
so I can't use this
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('tag_id')->references('id')->on('products')->onDelete('cascade');
so what's the alternative?
on my product model
public function tags()
{
return $this->belongsToMany('App\Tag','productstags','product_id','tag_id')->withTimestamps();
}
on my tag model:
public function products()
{
return $this->belongsToMany('App\Product','Productstags','tag_id','product_id');
}
on my produduct destroy function:
public function destroy(Request $request,$id)
{
$product=Product::findOrFail($id);
if($request->file('image')==''){
$input=$request->except('photo_id');
}
else{
$input=$request->all();
unlink(public_path()."/images/".$product->image->name);
}
$product->delete($input);
Session::flash('deleted_user','the user has been deleted');
return redirect(route('product.index'));
}
It's not as pretty as cascade but you could override the delete method and do this:
public function delete(){
$this->name_of_the_relationship()->delete();
return parent::delete();
}
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 :)
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');
}
}