Getting the name of the foreign key with eloquent - laravel

This must be very basic stuff but I can't seem to find out how to do it.
I have a one to many relationship between to tables: Unit and Army (an army contains many units) and these are my models:
class Army extends Eloquent {
protected $guarded = array();
public static $armies = array();
protected $table = 'armies';
public function units()
{
return $this->hasMany('Unit');
}
}
and:
class Unit extends Eloquent {
protected $guarded = array();
public static $units = array();
protected $table = 'units';
public function armies()
{
return $this->belongsTo('Army', 'army');
}
}
So, in my Unit table I have a row called"army" that contains the id of the army related to that unit and I want to show in my view a simple ul list in the following fashion (I want this to show on the unit index view):
<ul>
<li>Army 1 name
<li>Unit 1 of Army 1</li>
<li>Unit 2 of Army 1</li>
</li>
<li>Army 2 name
<li>Unit 1 of Army 2</li>
<li>Unit 2 of Army 2</li>
</li>
</ul>
To do this I have my unit controller like so:
class UnitsController extends BaseController {
protected $layout = 'master';
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$units = Unit::all();
$this->layout->content = View::make('units.index', compact('units'));
}
/*Other stuff*/
}
And in my view (index.blade.php inside views/units):
<ul class="units">
#foreach($units as $unit)
{{$unit->army}}
<li>
{{ HTML::link(route('units.show', ['units' => $unit->id]), $unit->name)}}
</li>
#endforeach
</ul>
But {{$unit->army}} is just (of course) showing the id of the army, and I want the name, how do I do this?

Assuming you have set up your schema correctly: armies table has at least id(auto-increment) and units table has at least id(auto-increment) and army_id (integer, unsigned), then, try this:
Models
class Army extends Eloquent {
public function units()
{
return $this->hasMany('Unit');
}
}
class Unit extends Eloquent {
public function armies()
{
return $this->belongsTo('Army');
}
}
In your Controller
You want to get all armies with units:
$armies = Army::with('units')->get();
In your View you want to loop through the result set outputting the name of each army and its respective units
#foreach($armies as $army)
{{$army->name}}
<ul>
#foreach($army->units as $aunit)
<li>
{{ $aunit->name }}
</li>
#endforeach
</ul>
#endforeach
If that doesn't work, I'll eat my head.

Related

Why can't I use method on relation in laravel?

I wanna using method on relation in laravel but show error[Method Illuminate\Database\Eloquent\Collection::getMessage does not exist.].
Error was changed to Call to a member function getMessage() on null when I rewrite {{$item->board2->getMessage()}} to {{$item->aaaaaaaa->getMessage()}} so I think relation was succeed.
I have no Idea what's wrong.
please give me advice.
Board2.php(model)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Board2 extends Model
{
protected $table = 'boards2';
protected $fillable = [
'person2_id',
'message'
];
public function person2()
{
return $this->belongsTo('App\Person2');
}
public function getMessage()
{
return $this->message;
}
}
Person2(model)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Person2 extends Model
{
protected $table = 'people2';
protected $fillable = [
'name'
];
public function board2()
{
return $this->hasMany('App\Board2', 'person2_id');
}
}
View
<ul>
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
{{$item->board2->getMessage()}}
</li>
#endforeach
</ul>
controller
・
・
・
public function show2()
{
$items_p2 = Person2::all();
$data = [
'items_p2' => $items_p2
];
return view('Review.show2', $data);
}
migration files
class CreatePeople2Table extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('people2', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBoards2Table extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('boards2', function (Blueprint $table) {
$table->increments('id');
$table->integer('person2_id');
$table->text('message');
$table->timestamps();
});
}
first:
in order to get the relation data you should load it first ...
$items_p2 = Person2::with('board2')-> all();
second: in your blade file
{{$item->board2->getMessage()}}
$item->board2 return a collection not a single board, so you should put it in foreach as well
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
#foreach($item->board2 as $board)
<li>
{{$item->board2->getMessage()}}
<li>
#endforeach
</li>
#endforeach
</ul>
Inside Board2.php(model) file, you have defined the method getMessage(), the method is loaded on the instance of the model and not the array of models (in Laravel's case, multiple models are loaded in a collection).
Inside Person2(model) file, you have defined the relation board2() which is linked to Board2 model via HasMany Relation. The catch is that HasMany relation, as the name suggests will load collection from the db and not a single instance of the model.
Try changing HasMany to HasOne inside Person2 model, your error should be resolved.
Accoring to the code you have written, each board2 record is connected to a single instance of person2, but on the other side, each person2 record is connected to a collection/array of board2 (not connected to single board2). This is the point keep in mind. Now let's proceed to next step.
Let's take a look in your view file. The code you wrote in view is
<ul>
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
{{$item->board2->getMessage()}}
</li>
#endforeach
</ul>
Here in $item->board2 , the board2 is not a single instance/record/model, rather it is a collection/array of multiple board2 instances/records/models. And each of that record/model will have the method "getmessage()" as you expected. So, the thing you have to do is, iterate through the records/models by making foreach to $item->board2, this way you will have the access to each single board2 record/model, then call the getMessage() method from that record/model. Let's modify the view code like this.
<ul>
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
#foreach( $item->board2 as $board )
{{$board->getMessage()}}
//this echo is just to break the line
echo '<br>';
#endforeach
</li>
#endforeach
</ul>
Hope it will work now. :)
You have to change this location. You write this in Person2 model
public function getMessage(){
return $this->message;
}

Eloquent Query: All News with same categories. Pivot table

I need to get all the news that has the same (one or more) categories as a specific new in an Eloquent query. And I dont know with pivot table.
I have 3 tables:
News
id | title | content
NewsxCategory (Pivot Table)
news_id | category_id
NewsCategory
id | name
Eloquent Models
// NewsCategory model
class NewsCategory extends Model
{
}
// News Model
class News extends Model
{
public function categories()
{
return $this->belongsToMany(NewsCategory::class, 'news_x_category', 'news_id', 'category_id');
}
}
I tried this.
In helper:
/**
* only related news
*
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public static function relatedNews(News $new)
{
$categories = $new->categories(); //obtain all categories of $new
return News::whereHas('categories', function ($query) use ($categories) {
$query->whereIn('new_id', $categories);
});
}
And in view:
<div class="related-articles">
<h5>{{ __('RELATED ARTICLES') }}</h5>
<ul class="articles">
#foreach ( App\Helpers\News::relatedNews($newsItem) as $new)
<li>
<h6>{{ $new->title }}</h6>
<p>{{ $new->publication_date }}</p>
</li>
#endforeach
</ul>
</div>
But helper always return null.
Also I tried in helper:
return News::with('categories')->where('category_id',$categories )->get();
But this option return all news.
I need all news related, I mean news with similar categories. Pivot tables give me a headache.
Thanks in advance!
In whereIn clause, you need to pass array of ids. But you are not passing correct.
So here is the correct one.
/**
* only related news
*
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public static function relatedNews(News $new)
{
$categoryIds = $new->categories->pluck('category_id')->toArray(); //obtain all categories of $new
return News::whereHas('categories', function ($query) use ($categoryIds) {
$query->whereIn('category_id', $categoryIds);
});
}
I think after change above function changes. you will get related news.
Updated
If you want to print related news then use this:
#foreach ( App\Helpers\News::relatedNews($newsItem)->get() as $new)
{{ $new->title }}
#endforeach

How to show comments with commented user name and photo

I'm trying to show the name of user alongside with their comment, as Tour does not belong to a user, I'm facing [user] issue here. Failed to pass the user information with comments. In my code, I can show only comments that belong to tour but not the users who comment.
Tour
class Tour extends Model{
protected $table = 'tour';
public function disTour()
{
return $this->hasMany('App\District');
}
public function review()
{
return $this->hasMany(TourReview::class);
}
TourReview Model
class TourReview extends Model{
protected $table = 'tour_review';
public function tour()
{
return $this->belongsTo('App\Tour');
}
public function user()
{
return $this->belongsTo('App\Users');
}
Users Model
class Users extends Model{
protected $table = 'users';
public function userBlogs()
{
return $this->hasMany('App\Blog');
}
public function tourReview()
{
return $this->hasMany('App\TourReview');
}
Controller
public function singleDetails($id)
{
$tour = Tour::find($id);
$comments = Tour::find($id)->review;
$users = TourReview::with('user')->where('id', $comments->pluck('id'))->get();
foreach ($users as $user){
dd($user);
}
//$blogs = Blog::with('images')->where('user_id', $user_id)->paginate(10);
dd($comments);
return view('Tours.single_tour')
->with(compact('tour', 'comments'));
}
Blade View
#foreach($comments as $comment)
<div class="review_strip_single">
<img src="{{asset('wanna show commented user photo')}}" height="78" width="78" alt="Image" class="img-circle">
<small> - {{$comment->created_at->format('d M Y')}} -</small>
<h4>{{wanna show user name}}</h4>
<p> {{$comment->tourreview_desc}} </p>
</div>
#endforeach
you can do nested query in controller
public function singleDetails($id)
{
$tour = Tour::with(['review.user'])->find($id);
return view('Tours.single_tour')
->with(compact('tour'));
or if you want only comments
$comments = Review::with('user')->whereHas('tour', function ($q)use($id){
$q->where('id', $id);
});
return view('Tours.single_tour')
->with(compact('comments'));
}
Blade View
#foreach($tour->comments as $comment)
<div class="review_strip_single">
<img src="{{asset('wanna show commented user photo')}}" height="78" width="78" alt="Image" class="img-circle">
<small> - {{$comment->created_at->format('d M Y')}} -</small>
<h4>{{$comment->user->name}}</h4>
<p> {{$comment->tourreview_desc}} </p>
</div>
#endforeach
or
#foreach($comments as $comment)
<div class="review_strip_single">
<img src="{{asset('wanna show commented user photo')}}" height="78" width="78" alt="Image" class="img-circle">
<small> - {{$comment->created_at->format('d M Y')}} -</small>
<h4>{{$comment->user->name}}</h4>
<p> {{$comment->tourreview_desc}} </p>
</div>
#endforeach

Laravel Eloquent group by with pivot table & relations

I have this platform I'm creating for foodtruck events. There is a pool of exhibitors who attend several events. Each foodtruck has it's own menu of dishes that they serve, in several categories.
The problem / what I'd like to achieve
I would like to make a menu for each event, looping through all
exhibitors (who attend) and then showing the dishes by category.
Something like this;
/menu/{eventid}
Dish category 1
dish from exhibitor A
dish from exhibitor B
Dish category 2
dish from exh A
dish from exh C
dish from exh D
...
Models
Event model
class Event extends Model
{
protected $table = "events";
public function exhibitors()
{
return $this->belongsToMany('App\Exhibitor', 'events_exhibitors');
}
Dish model
class Dish extends Model
{
//
protected $table = "dishes";
public function category()
{
return $this->hasOne('App\Category', 'id', 'category_id');
}
public function exhibitor()
{
return $this->belongsTo('App\Exhibitor');
}
}
Exhibitor model
class Exhibitor extends Model
{
protected $table = "exhibitors";
public function events()
{
return $this->belongsToMany('App\Event', 'events_exhibitors');
}
public function dishes()
{
return $this->hasMany('App\Dish');
}
}
Database structure
There is a pivot table to register which foodtrucks go to which events. So far, I think (hope) my relations are working. I hope this image shows enough;
What I've tried
I've tried several things but I think my insight in Laravel eloquent lacks to understand the logic behind this issue.
$dishes = Event::where('id', $id)
->with(['exhibitors.dishes' => function($q) {
$q->select('dishes.dish_data');
}])->get();
Or
$dishes = Event::with(array('exhibitor.dish') => function($query) use ($sub){
$query->where('name',$sub);}))->get();
I have absolutely no clue how to accomplish this by Eloquent or how this would work in the view.
Try something like this:
It will get all the ids of the exhibitors that are connected to the event.
Then it will get all categories where the connected dishes have an exhibitor_id that is in the array of exhibitor ids.
Category Model
class Category extends Model
{
protected $table = "categories";
public function dishes()
{
return $this->hasMany('App\Dish', 'category_id');
}
}
Controller Action
$event = Event::findOrFail($id);
$exhibitorIds = $event->exhibitors()->select('exhibitors.id')->get()->pluck('id')->all();
$categories = Category::whereHas('dishes', function($query) use ($exhibitorIds) {
$query->whereIn('exhibitor_id', $exhibitorIds);
})->with(['dishes' => function($query) use ($exhibitorIds) {
$query->whereIn('exhibitor_id', $exhibitorIds);
}])->get();
return view('events.menu', compact('event', 'categories') );
View
#foreach($categories as $category)
<h2>{{ $category->name }}</h2>
<ul>
#foreach($category->dishes as $dish)
<li>{{ $dish->dish_data }}</li>
#endforeach
</ul>
#endforeach

Laravel Category Model Relationships

I have the following table structure in my database.
Table Name: tiles
Columns: id, tile_name, tile_thumb, tile_snippet
Table Name: tags
Columns: id, tag_title
Table Name: tile_tags
Columns: id, tile_id, tag_id
Models:
Tile, Tag, TileTag
In my main model class for entries I am specifying the following relationship to a model called TileTag which is a pivot table.
<?php namespace Tiles;
use Illuminate\Database\Eloquent\Model;
class Tile extends Model {
protected $table = 'tiles';
public function tags() {
return $this->belongsTo('Tiles\TileTag');
}
}
During my foreach loop it returns the tile_name and any other columns from my table, except the ones joined by the relatipnship.
#foreach($tiles as $tile)
<a href="tile/{{$tile->tile_name}}">
<li class="col-md-4 mix" data-category="{{ $tile->tags->tag_title }}">
{!! HTML::image($tile->tile_thumb, null, array('class' => 'img-responsive')) !!}
</li>
</a>
#endforeach
How can I get my categories/tags linked to my primary entries when they are sorted during each loop?
I try returning the data during the loop by {{ $tile->tags->tag_title }} but it returns an empty string.
Controller Method:
class TileController extends Controller {
/**
* Display a listing of tiles from the database.
*
* #return Response
*/
public function index() {
// Get tile data from the model
$tiles = \Tiles\Tile::all();
return view('pages.index', compact('tiles'));
}
Returned Array:
I think that you don't have to create a model for Tile_Tag. Laravel can handle ManyToMany relationships out of the box (I suppose that this is the type of the relationship because you use pivot table). Your models should be
class Tile extends Model {
protected $table = 'tiles';
public function tags() {
return $this->belongsToMany('Tiles\Tag');
}
}
and
class Tag extends Model {
protected $table = 'tags';
public function tiles() {
return $this->belongsToMany('Tiles\Tile');
}
}
Laravel will know that you have a pivot table named "tag_tile" with columns "tag_id" and "tile_id". Check the relevant documentation here
Then you can iterate through tags collection for each tile like this
#foreach ($tiles as $tile)
{!!$tile->tile_name!!}
#foreach ($tile->tag as $tag)
{!!$tag->tag_title!!}
#endforeach
#endforeach
Hope it helps.

Resources