Laravel 5 Eloquent relationship get the data - laravel-5

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

Related

Laravel How to find Mutual Friends from model?

I am using laravel 8.
I want to find the mutual friends of entries and profiles.
Please ask me if it is not clear...
My friends table;
user_friends;
id | user_id | user_friend_id
1 | 10 | 20
2 | 20 | 10
In My User Model;
public function friends(){
return $this->belongsToMany(User::class, 'user_friends', 'user_id', 'user_friend_id');
}
public function friendsOf(){
return $this->belongsToMany(User::class, 'user_friends', 'user_friend_id', 'user_id');
}
How can I find mutual friends of the profile with respect to authenticated user?
Example;
#foreach($user as $entry)
{{ count( $entry->mutual(Auth::id()) ) }}
#foreach($entry->mutual(Auth::id()) as $item)
{{ $item->name }}
...
#endforeach
#endforeach
I make this work by using helpers. I create helpers.php on App folder and create a function.
function mutualFriends($id){
$profile = User::where('id', $id)->first();
$profileFriends = $profile->friends;
$profileFriendsIds = [];
foreach ($profileFriends as $entry){
$profileFriendsIds[] = $entry->id;
}
$loggedUserFriends = Auth::user()->friends->whereIn('id', $profileFriendsIds);
return $loggedUserFriends;
}
and now I am calling the function from view like;
{{count(mutualFriends(Auth::id()))}}
or
#foreach(mutualFriends($profile->id) as $entry)
...
#endforeach

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

display data from multiple tables and foreign keys in 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

How use conditional relationship in eloquent laravel

I have a 'conversation_message' table and separate sender role by column 'sender_type' (admin/user). Both of admin & user in a different table. But when I call the model, that showed error Call to a member function addEagerConstraints() on null
Table column and data
| id | id_group | id_reply | id_sender | sender_type | message
| 1 | 1 | null | 3 | admin | Hi, I'm admin
| 2 | 1 | 1 | 3 | admin | I wanna give u promo
| 3 | 1 | 2 | 18 | user | What's promo ?
I've tried if conditional with column value, but it doesn't work.
Conversation_message.php
public function sender(){
switch($this->sender_type){
case "user":
return $this->belongsTo(User::class, 'id_sender', 'id');
case "admin":
return $this->belongsTo(Admin::class, 'id_sender', 'id');
default:
return;
}
}
InboxController.php
public function message_detail_chat($groupId){
$data = [];
$data['messages'] = Conversation_message::with('replies')
->with('sender')
->with('recipients')
->where(['id_group' => $groupId])->get();
}
I expect to use conditional model by column value 'sender_type' but the actual output is wrong.
laravel provide query scope your can read it from here https://laravel.com/docs/5.8/eloquent#local-scopes
function userSender(){
$this->belongsTo(User::class, 'id_sender', 'id');
}
function adminSender(){
return $this->belongsTo(Admin::class, 'id_sender', 'id');
}
public function scopeSender($query)
{
return $query
->when($this->sender_type === 'user',function($q){
return $q->with('userSender');
})
->when($this->sender_type === 'admin',function($q){
return $q->with('adminSender');
});
}
Now you can access your Sender like this
Conversation_message::Sender()->first();
This should give you the right Sender. Hope it helps.

Share value from database in all view in laravel 5

I'm new to laravel. I'm trying to create a simple app with some variable that shouold be in every view. So I create a setting model, with many fields and a unique slug field. Now to share this variable from database I've created a middleware:
public function handle($request, Closure $next)
{
$site_settings = Cache::remember('settings', 60, function() {
return Setting::all();
});
view()->share('site_settings', $site_settings);
return $next($request);
}
Now to show this variable in view I have:
{{{ $site_settings->get(0)->value }}}
This works great, but I'd like to have a more intuitive code in my view, accessing the setting by slug. Something like:
{{{ $site_settings->findBySlug("MYVARIABLE")->value }}}
So it's possible to filter collection by an unique slug?
Info:
This assumes your settings table structure is as following:
----------------------
| id | key | value |
----------------------
| 1 | titleĀ | foo |
| 2 | asd | bar |
| 3 | qqq | zzz |
----------------------
Steps
Step 1: Put the following newCollection method into App\Setting model:
class Settings extends ... {
public function newCollection(array $models = array())
{
return new \App\Collections\SettingsCollection($models);
}
}
Step 2: Put the following lines into App\Collections\SettingsCollection class:
<?php namespace App\Collections;
use Illuminate\Database\Eloquent\Collection;
class SettingsCollection extends Collection {
public function get($name, $default = null)
{
return array_first($this->items, function($itemKey, $model) use ($name)
{
return $model->key == $name;
}, $default)->value;
}
}
Step 3: Enjoy! This is the collection I'm currently using. Instead of this:
$settings = Setting::all();
$settings->where('key', 'key_name')->first()->value;
You can simply just do this:
$settings = Setting::all();
echo $settings->get('key_name'); // returns value of the setting with the key 'title'
Maybe a query scope would fit.
In your model:
public function scopeFindBySlug($slug){
return $query->where('slug','=', $slug);
}
So you will have: $site_settings->findBySlug('your_slug')->get();

Resources