display data from multiple tables and foreign keys in laravel - laravel

I have two tables :
bonhomme
+----+--------------+
| id | name |
+----+--------------+
| 1 | Alec Badwin |
| 2 | Maria Quiban |
+----+--------------+
serie
+----+---------------+
| id | name |
+----+---------------+
| 1 | 30 Rock |
| 2 | Good Day L.A. |
+----+---------------+
I have another one called : serie_personnage
+----+-------------+----------+--------------+
| id | bonhomme_id | serie_id | personnage |
+----+-------------+----------+--------------+
| 1 | 1 | 1 | Jack Donaghy |
| 2 | 2 | 2 | Maria Quiban |
+----+-------------+----------+--------------+
I want to display the personnage from serie_personnage and link it in my blade with the name of the bonhomme (in my table bonhomme) associated.
In other words, I want a table in my blade with rows where there is in column 1, the name of the bonhomme and in column 2, the personnage associated.
How can I do that with the relationships in Laravel ? I've tried it but it's not working well.
Controller
public function show($id)
{
$serie = Serie::where('id', $id)->first();
return view('admin.series.castings.show')->withSerie($serie);
}
Model - Serie
public function personnages()
{
return $this->hasMany('App\Models\Admin\SeriePersonnage');
}
public function acteurs()
{
return $this->belongsToMany('App\Models\Admin\Bonhomme', 'serie_personnage', 'serie_id', 'bonhomme_id');
}
Blade
<tbody>
#foreach($serie->acteurs as $acteur)
#foreach($serie->personnages as $personnage)
<tr>
<td>{{ $acteur->nom }}</td>
<td>{{ $personnage->personnage }}</td>
<td>bla</td>
<td>{{ $personnage->rang }}</td>
<td class="has-text-right">
<a class="button is-outlined" href="{{ route('series.show', $serie->id) }}">
Voir
</a>
<a class="button is-outlined" href="#">Editer</a>
</td>
</tr>
#endforeach
#endforeach
</tbody>
My Table in view

I have to help you as French developer as-well! First of all, I would change your controller for a more simple way to get the Serie :
public function show($id)
{
$serie = Serie::findOrFail($id);
return view('admin.series.castings.show')->withSerie($serie);
}
EDIT: I use Model::findOrFail($id); because it throws a Illuminate\Database\Eloquent\ModelNotFoundException. If you don't catch the exception, Laravel will automatically send a 404 HTTP response. It prevent the user to have an error using an obsolete link. See the doc for more informations.
Then I don't think it is a good idea to use foreach loop twice... I would rather use only one foreach loop on the personnages. Then, I would get the actor of the character from the Personnage model. It should looks like the code below:
App\Models\Admin\SeriePersonnage.php
<?php
namespace App\Models\Admin;
use App\Models\Admin\Bonhomme;
use Illuminate\Database\Eloquent\Model;
class SeriePersonnage extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
//Whatever you want to put here
];
/**
* Gets the actor of the character
*/
public function actor() {
return $this->belongsTo(Bonhomme::class);
}
}
Then in your blade view:
<tbody>
#foreach($serie->personnages as $personnage)
<tr>
<td>{{$personnage->actor->nom}}</td>
<td>{{$personnage->personnage}}</td>
<td>bla</td>
<td>{{$personnage->rang}}</td>
<td class="has-text-right"><a class="button is-outlined" href="{{route('series.show', $serie->id)}}">Voir</a> <a class="button is-outlined" href="#">Editer</a></td>
</tr>
#endforeach
</tbody>
You might also add a personnages() methods in your actor model so that you would be able to get all the characters this actor is playing.
Also I would advice you to use English words for variable names, class names and in fact every word in your code, especially if you post for help on English websites. I would also recommend you to change SeriePersonnage to only Personnage if you only manage series (you might also handle movies, Japanese Anime etc, in this case you can ignore my message). Also it would be great to change the row name of serie_personnage from personnage to nom.
Hope it helped you and I didn't do mistakes :P

Related

How to count rows in another table which contains foreign key and loop it foreach collection instance?

I have two tables which are connected each other.
their structures look like this.
modul_table
id | user_id | title | slug | platform
lecture_table
id | user_id | modul_id | title | content
I want to count how many rows in lecture_table where its modul_id = $id.
So this $id are the ids of my collection which retrieved from controller.
here's my controller:
public function index()
{
$modul = Modul::get();
$arr_lecture = [];
foreach ($modul as $key) {
$lecture = Lecture::where('modul_id', $key->id)->count();
array_push($arr_lecture, $lecture);
}
return view('func.lihatModul', compact('modul', 'arr_lecture'));
}
and in my view :
#php $i = 0 #endphp
#foreach($modul as $key)
<tr>
<td>{{$key->id}}</td>
<td>{{$key->title}}</td>
<td>{{substr($key->desc, 0, 75)}}</td>
<td>{{ $arr_lecture[$i++] }}</td>
#endforeach
and the result:
all my codes are working well, but is there any way just by using query builder or a function to do the same approach?
If you have defined the lectures relationship in your Modul model like so:
# Modul.php
public function lectures()
{
return $this->hasMany(Lecture::class);
}
Then, you could simple do this in your ModulController:
public function index()
{
$moduls = Modul::withCount('lectures')->get();
// ^^^^^^^^^^^^^^^^^^^^
return view('func.lihatModul')->withModuls($moduls);
} ^^^^^^^^^^^^^^^^^^^^^
This will add the lectures_count attribute to each $modul, so you can access it in your Blade view like this:
#foreach($moduls as $modul)
<tr>
<td>{{ $modul->id }}</td>
<td>{{ $modul->title }}</td>
<td>{{ substr($modul->desc, 0, 75) }}</td>
<td>{{ $modul->lectures_count }}</td> // <-----
#endforeach
Check the docs regarding this section: Counting related models.
If you have the one-to-many relationships set up properly as it explains in the docs https://laravel.com/docs/master/eloquent-relationships#one-to-many
So in your Modul.php model
public function lectures()
{
return $this->hasMany('App\Lecture');
}
and in your Lecture.php model
public function modul()
{
return $this->belongsTo('App\Modul');
}
then you should just be able to do
$modul = Modul::with('lectures')->get();
Then in blade
#foreach($modul as $key)
<tr>
<td>{{$key->id}}</td>
<td>{{$key->title}}</td>
<td>{{substr($key->desc, 0, 75)}}</td>
<td>{{ $key->lectures->count() }}</td>
#endforeach
If u want to leave your variant u don't need to use array_push better store value in array with $key
public function index()
{
$modul = Modul::get();
$arr_lecture = [];
foreach ($modul as $key) {
$lecture = Lecture::where('modul_id', $key->id)->count();
$arr_lecture[$key->id] = $lecture;
}
return view('func.lihatModul', compact('modul', 'arr_lecture'));
}
now $arr_lecture will have correct keys. Next in view
#foreach($modul as $key)
<tr>
<td>{{$key->id}}</td>
<td>{{$key->title}}</td>
<td>{{substr($key->desc, 0, 75)}}</td>
<td>{{ count($arr_lecture[key->id]) }}</td>
#endforeach
but Kennys version is really good

laravel 6 calling post route to return to the same page for sorting table

I am trying to create a table which the user can sort
I created the following two routes
route::get('/manager', 'Manager\DeadlineController#index')->middleware(['auth', 'auth.manager'])->name('manager.index');
route::post('/manager/{name_id}', 'Manager\DeadlineController#sortByName')->middleware(['auth', 'auth.manager'])->name('manager.sortByName');
from my php artisan route:list
| | GET|HEAD | manager | manager.index | App\Http\Controllers\Manager\DeadlineController#index | web,auth,auth.manager |
| | POST | manager/{name_id} | manager.sortByName | App\Http\Controllers\Manager\DeadlineController#sortByName | web,auth,auth.manager |
and set up my controller as follows
public function index()
{
return view('deadline.index')
->with([
'modules' => Module::all(),
'name_id' => 0
]);
}
public function sortByName($name_id){
if($name_id == 0){
$sortedModule = Module::orderBy('name', 'DESC')->get();
}
else{
$sortedModule = Module::orderBy('name', 'ASC')->get();
}
return view('deadline.index')
->with([
'modules' => $sortedModule,
'name_id' => 1
]);
}
in my view i use the following link to sort
<th scope="col">NAME</th>
but when i use this link in my view I am somehow redirected to my GET route because i get the following error
The GET method is not supported for this route. Supported methods: POST.
What am I missing or doing wrong? Any help or tips will be appreciated. Please ask if I need to provide more details
Update
I change the link in my view to a form tag with a submit button and now it works
<th scope="col">
<form action="{{ route('manager.sortByName', $name_id) }}" method="POST">
#csrf
<button type="submit">NAAM</button>
</form>
</th>
When you click on <a> tag it does GET request, so you need to change your route from POST to GET, also returning view as a response to post method is not good idea,the best solution is GET route

Laravel 5.8 isAdmin Gate?

I'm learning how to use the Gate and #can stuff
in my AuthServiceProvider I have
public function boot()
{
$this->registerPolicies();
$this->registerPostPolicies();
}
public function registerPostPolicies()
{
Gate::define('isAdmin', function($user) {
return $user->roles->where('title', 'like', '%' . 'Admin')->count();
});
}
and in my blade I have
...
#can('isAdmin')
<a aria-disabled="false" href="{{ route('admin.home')}}" target="_self" class="dropdown-item" role="menuitem" ><i class="fa fa-upload"></i> Admin Menu</a>
#endcan
...
For roles I have
| id | title |
+----+-------------+-
| 1 | Admin |
| 2 | User |
| 3 | Group Admin |
| 4 | Site Admin |
+----+-------------+-
Which is why the like %Admin query...
but what I am finding is that the gate doesn't seem to work.. it simply blocks everyone.. I want to enable the Admin menu for anyone with a role title that has Admin in it..
Any suggestions?
You should be using $user->roles() with brackets instead to indicate you are querying from database.
return $user->roles()->where('title', 'like', '%' . 'Admin')->count();
Without (), it has become Collection and you cannot use LIKE with where() when filtering a collection. Refer Collections - Laravel Docs

Laravel 5 Eloquent relationship get the data

I have two table.
(Persons)
+------+------+
| id | name |
+------+------+
| 1 | John |
+------+------+
| 2 |Albert|
+------+------+
(Motors)
+------+------+------+
| id | name | age |
+------+------+------+
| 1 | 1 | 20 |
+------+------+------+
| 2 | 2 | 21 |
+------+------+------+
| 3 | 1 | 20 |
+------+------+------+
In "motors.name" i have the ids of people.
I have two models.
(Motors)
class Motors extends Eloquent
{
public function person(){
return $this->hasMany('App\Persons', 'id');
}
}
(Persons)
class Persons extends Eloquent
{
protected $table = 'persons';
public function motors(){
return $this->belongsTo('App\Motors', 'name', 'id');
}
}
1 controller
class PrototypeController extends Controller
{
public function names(Request $request) {
$res = Motors::get()->person->name;
return view('pages.prototype', compact('res'));
}
}
1 view
<ul class="list">
#foreach ($res as $row)
#if (!empty($row->name))
<li class="list-group-item">
{!! $row->name !!}
</li>
#endif
#endforeach
</ul>
I'd like tosee the rerelational dara in view, not the ids. How can it be solved?
This code isn't good:
$res = Motors::get()->person->name;
Thanks in advance for your help.
Let me try to answer this. You should try to follow conventions to make it easier to work with Laravel.
Your motors.name column should be called person_id. Your model for motors table should be called Motor.php (singular of motors). The same for persons table, Person.php.
In your Motor.php file, your relationship will be:
public function person(){
return $this->belongsTo('App\Person');
}
If you follow conventions, you don't need to add the second parameter to the relationship name. Note that I put App\Person, you should have App\Persons if you decide to maintain the file naming you are using.
In your Person.php file, your relationship will be:
public function motors(){
return $this->hasMany('App\Motor');
}
Your foreach will be:
#foreach ($res as $row)
#if (!empty($row->person))
<li class="list-group-item">
{!! $row->person->name !!}
</li>
#endif
#endforeach
Note how I check:
#if (!empty($row->person))
and not:
#if (!empty($row->person->name))
It has to be done like this, because if $row->person is null, it will throw an error when you do $row->person->name

Laravel 5 and understanding MVC - How do I get the db data to my views?

I’m new to Laravel 5 and the world of MVC.
I’ve installed Laravel 5 boilerplate project and everything works fine, out of the box. I can register and then login to the app.
I kind of understand the roles of Routes, Controllers, Models and Views, but I can’t figure out the syntax to simply retrieve data from my users database table, and display it in my home view (using HomeController).
I’m not sure which piece of code goes where, and how the syntax should be coded. In the code below, I'm logged in as a user, and I'm simply trying to display all the users from the user table.
Can you help? If I can understand how to the get the data from my database to my views, I’ll be good to go. I'm looking for simple examples. I've seen I lot of examples on the web, but for most, I don't even know where (controller, route, etc.) to copy the code provided.
I get the following error with the code below:
FatalErrorException in HomeController.php line 52: Class 'App\Http\Controllers\User' not found
routes.php
Route::get('home', 'HomeController#index');
HomeController.php
<?php namespace App\Http\Controllers;
class HomeController extends Controller {
/*
|--------------------------------------------------------------------------
| Home Controller
|--------------------------------------------------------------------------
|
| This controller renders your application's "dashboard" for users that
| are authenticated. Of course, you are free to change or remove the
| controller as you wish. It is just here to get your app started!
|
*/
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard to the user.
*
* #return Response
*/
public function index()
{
$users = User::all();
return View::make('user.index', ['users' => $users]);
}
Home.blade.php
#extends('app')
#section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">List of users</div>
<div class="panel-body">
<table>
#foreach($users as $key => $value)
<tr>
<td>{{ $value->id }}</td>
<td>{{ $value->name }}</td>
<td>{{ $value->email }}</td>
</tr>
#endforeach
</table>
</div>
</div>
</div>
</div>
</div>
#endsection
Laravel 5 is namespaced and PSR-4 autoloaded, so in your controller $users = User::all(); should be App\User::all(); or use App\User; on the top of the file after the namespace declaration.
Your view is also incorrect. This #foreach($users as $key => $value) should be #foreach($users as $user) then you access the users attributes as normal fields: $user->id, $user->name, etc.
Another thing, the laravel 5 way to make a view is this (yours is not incorrect, it's just different syntax):
return view('user.index')->with(['users' => $users]);
or with some sorcery:
return view('user.index')->withUsers($users);
Another tip that will really make you understand how stuff works: use tinker. Open up a console, go to the laravel folder and type php artisan tinker. There you can execute php code and check the output. Type User::all() and check the error. Then type App\User::all() and check the response.

Resources