laravel relaion many to many - laravel

hello family I am working on a school management project but I have a problem with relations:
I have a table of years, students, level
now a pupil can register only once in a level during a school year,
during a school year several pupils can register for a level
table eleves belongToMany table niveaux
table niveau belongToMany table eleves
table eleve_niveau belongTo table annees
table annees has many eleve_niveau
Now at the level of my models I made his:
model annee
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* #property integer $id
* #property string $debut_annee
* #property string $fin_annee
* #property string $annee_scolaire
* #property string $created_at
* #property string $updated_at
* #property EleveNiveau[] $eleveNiveaus
* #property Niveau[] $niveauxes
*/
class Annee extends Model
{
/**
* The "type" of the auto-incrementing ID.
*
* #var string
*/
protected $keyType = 'integer';
/**
* #var array
*/
protected $fillable = ['debut_annee', 'fin_annee', 'annee_scolaire', 'created_at', 'updated_at'];
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function eleveNiveaus()
{
return $this->hasMany('App\EleveNiveau');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function niveauxes()
{
return $this->hasMany('App\Niveau');
}
}
model niveau
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* #property integer $id
* #property integer $annee_id
* #property string $nom_niveau
* #property string $branche
* #property string $created_at
* #property string $updated_at
* #property Annee $annee
* #property EleveNiveau[] $eleveNiveaus
*/
class Niveau extends Model
{
/**
* The "type" of the auto-incrementing ID.
*
* #var string
*/
protected $keyType = 'integer';
/**
* #var array
*/
protected $fillable = ['annee_id', 'nom_niveau', 'branche', 'created_at', 'updated_at'];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function annee()
{
return $this->belongsTo('App\Annee');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function eleveNiveaus()
{
return $this->hasMany('App\EleveNiveau');
}
}
model eleves
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* #property integer $id
* #property string $pv
* #property string $nom
* #property string $prenom
* #property string $created_at
* #property string $updated_at
* #property EleveNiveau[] $eleveNiveaus
*/
class Eleve extends Model
{
/**
* The "type" of the auto-incrementing ID.
*
* #var string
*/
protected $keyType = 'integer';
/**
* #var array
*/
protected $fillable = ['pv', 'nom', 'prenom', 'created_at', 'updated_at'];
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function eleveNiveaus()
{
return $this->hasMany('App\EleveNiveau', 'eleve_id');
}
}
I did a model for the pivot table
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* #property integer $eleve_id
* #property integer $niveau_id
* #property integer $annee_id
* #property string $date_inscription
* #property string $created_at
* #property string $updated_at
* #property Annee $annee
* #property Elefe $elefe
* #property Niveau $niveau
*/
class EleveNiveau extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'eleve_niveau';
/**
* #var array
*/
protected $fillable = ['date_inscription', 'created_at', 'updated_at'];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function annee()
{
return $this->belongsTo('App\Annee');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function elefe()
{
return $this->belongsTo('App\Elefe', 'eleve_id');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function niveau()
{
return $this->belongsTo('App\Niveau');
}
}
the problem I can't manage to insert into the pivot table I don't know which model to start with
if I use the high model to register a pupil at a level, I have to go through the pivot model
is there a possibility ????

Did you reed the documentaion? Which version of laravel are you using?

I use version 7 in laravel
I read the laravel documentation I found an attached method so at the level of my models I went
the foreign key attribute has my two models
hasMany('App\EleveNiveau', 'eleve_id');
// }
public function niveaux()
{
return $this->belongsToMany(Niveau::class)->withPivot('annee_id');
}
}
belongsTo('App\Annee');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
// public function eleveNiveaus()
// {
// return $this->hasMany('App\EleveNiveau');
// }
public function eleves()
{
return $this->belongsToMany(Eleve::class)->withPivot('annee_id');
}
}
I think it works now there is another method to manage a pivot table which contains 3 secondary keys

Related

How to limit device login for SPA web app using Laravel Sanctum

I'm building REST API authentication using Laravel sanctum, I wanna make the user can login in multiple device and it is limited by 2 devices, let's say User A and User B are logged in when the user C log in, the user A is logged out and so on. How to achieve this and what is the concept?
Usually I make a login api when the email and password are correct then return the token.
I've learned this from netflix which is it has limited device to watch movie.
You can simply check how many tokens you've issued to this user from within your personal_access_tokens table, as shown below:
So just run such query when you are signing in the user just before issueing a new token for them:
$issuedTokens = PersonalAccessToken::where('tokenable_type', User::class)
->where('tokenable_id', $userId)
->get();
if ($issuedTokens->count() > 1) {
$returnMessage = 'You have to remove on of the following devices:';
$deviceNames = $issuedTokens->pluck('name')->toArray();
}
// Things are fine, proceed
And if you would like to enhance things even further you might want to extend the PersonalAccessToken model by adding the mobile details of the person who is entering and perhaps their country/city of access.
To extend it, add migration & model files like the following:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
// Remember to change this line, if you wish, back to the old way.
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->string('country_name')->nullable();
$table->text('abilities')->nullable();
$table->json('mobile_app_details')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('personal_access_tokens');
}
};
And your model:
<?php
namespace App\Models;
use Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
use Laravel\Sanctum\PersonalAccessToken as PersonalAccessTokenAlias;
/**
* App\Models\PersonalAccessToken
*
* #property int $id
* #property string $tokenable_type
* #property int $tokenable_id
* #property string $name
* #property string $token
* #property array|null $abilities
* #property object|null $mobile_app_details
* #property string|null $country_name
* #property Carbon|null $last_used_at
* #property Carbon|null $created_at
* #property Carbon|null $updated_at
* #property-read Model|\Eloquent $tokenable
* #method static Builder|PersonalAccessToken newModelQuery()
* #method static Builder|PersonalAccessToken newQuery()
* #method static Builder|PersonalAccessToken query()
* #method static Builder|PersonalAccessToken whereAbilities($value)
* #method static Builder|PersonalAccessToken whereCreatedAt($value)
* #method static Builder|PersonalAccessToken whereId($value)
* #method static Builder|PersonalAccessToken whereLastUsedAt($value)
* #method static Builder|PersonalAccessToken whereMobileAppDetails($value)
* #method static Builder|PersonalAccessToken whereName($value)
* #method static Builder|PersonalAccessToken whereToken($value)
* #method static Builder|PersonalAccessToken whereTokenableId($value)
* #method static Builder|PersonalAccessToken whereTokenableType($value)
* #method static Builder|PersonalAccessToken whereUpdatedAt($value)
* #mixin Eloquent
* #noinspection PhpFullyQualifiedNameUsageInspection
* #noinspection PhpUnnecessaryFullyQualifiedNameInspection
*/
class PersonalAccessToken extends PersonalAccessTokenAlias
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'token',
'abilities',
'mobile_app_details',
'country_name',
];
protected $casts = [
'abilities' => 'json',
'last_used_at' => 'datetime',
'mobile_app_details' => 'object'
];
}
One last important step is to tell Laravel to ignore original migrations and to load the custom model, so in your AppServiceProvider:
<?php
namespace App\Providers;
use App\Models\PersonalAccessToken;
use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
Sanctum::ignoreMigrations();
// other lines go here
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
// other lines go here
}
}

Laravel-admin: relation many-to-many does't work

I use laravel-admin (https://laravel-admin.org) in my laravel project. I wish to show on User admin panel role names of user. But I get error message:
SQLSTATE[42703]: Undefined column: 7 ERROR: column users_roles.role___id does not exist LINE 1: ...les" inner join "users_roles" on "roles"."__id" = "users_rol... ^ (SQL: select "roles".*, "users_roles"."user___id" as "pivot_user___id", "users_roles"."role___id" as "pivot_role___id" from "roles" inner join "users_roles" on "roles"."__id" = "users_roles"."role___id" where "users_roles"."user___id" in (1, 2, 3))
Here are my classes and controller:
User.php:
namespace App\Models;
/**
* Class User
* #package App\Models
*
* #property integer $__id
* #property string $email
* #property string $password
* #property string|null $firstname
* #property string|null $lastname
* #property \DateTime|null $visited_at
* #property string|null $phone
* #property string|null $avatar
* #property string|null $remember_token
* #property \DateTime $created_at
* #property \DateTime $updated_at
*/
class User extends Authenticatable
{
use Notifiable;
protected $primaryKey = '__id';
public function roles() :BelongsToMany
{
return $this->belongsToMany(Role::class,'users_roles');
}
}
Role.php:
<?php
namespace App\Models;
/**
* Class Role
* #package App\Models
*
* #property integer $__id
* #property string $key
* #property string $name
*/
class Role extends Model
{
protected $primaryKey = '__id';
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class,'users_roles');
}
}
UserController.php:
<?php
namespace App\Admin\Controllers;
class UserController extends AdminController
{
protected $title = 'User';
protected function grid()
{
$grid = new Grid(new User());
$grid->column('__id', __(' id'));
$grid->column('email', __('Email'));
$grid->column('password', __('Password'));
$grid->column('firstname', __('Firstname'));
$grid->column('lastname', __('Lastname'));
$grid->roles()->display(function($roles) {
$roles = array_map(function ($role) {
return "<span class='label label-success'>{$role['name']}</span>";
}, $roles);
return join(' ', $roles);
});
.......
.........
}
Pivot table users_roles:
create table if not exists users_roles
(
__user_id bigint not null
constraint users_roles___user_id_foreign
references users,
__role_id bigint not null
constraint users_roles___role_id_foreign
references roles,
become_at timestamp(0) not null,
left_at timestamp(0)
);
I have noticed that name of column __role_id the pivot table is transformed in the query as role___id (as error message tells me: "ERROR: column users_roles.role___id"). How to solve this problem?
I had to make some correction:
public function roles() :BelongsToMany
{
return $this->belongsToMany(Role::class,'users_roles',
'__user_id','__role_id');
}
and error message disappeared.

Laravel Group results of a query and show them grouped in a Form :: select

could you help me with the next problem I have, I give you details of what I have so far:
I have 3 models, with a One to Many relationship:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Province;
/**
* Class Currency
*
* #property $id
* #property $abbreviation
* #property $description
* #property $active
* #property $created_at
* #property $updated_at
*
* #package App
* #mixin \Illuminate\Database\Eloquent\Builder
*/
class Country extends Model
{
/**
* Attributes that should be mass-assignable.
*
* #var array
*/
protected $fillable = ['name','abbreviation','active'];
public function provinces()
{
return $this->hasMany(Province::class);
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Country;
use App\Models\Entity;
/**
* Class Province
*
* #property $id
* #property $name
* #property $active
* #property $created_at
* #property $updated_at
*
* #package App
* #mixin \Illuminate\Database\Eloquent\Builder
*/
class Province extends Model
{
/**
* Attributes that should be mass-assignable.
*
* #var array
*/
protected $fillable = ['name', 'country_id', 'active'];
public function country()
{
return $this->belongsTo(Country::class);
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Province;
class Entity extends Model
{
/**
* Attributes that should be mass-assignable.
*
* #var array
*/
protected $fillable = ['name', 'province_id', 'active'];
public function province()
{
return $this->belongsTo(Province::class);
}
}
I want to show in a view with Blade a select with grouped options, in this case:
-- Country 1
-- Province 1
-- Province 2
-- Province 3
-- Country 2
-- Province 1
-- Province 2
-- Province 3
I am passing the $provinces variable in sight with Blade as follows:
public function edit($id)
{
$entity = Entity::find($id);
$provinces = Province::get(['id', 'name', 'country_id'])->groupBy(['country.name', 'name'])->toArray();
return view('entity.edit', [
'entity' => $entity,
'provinces' => $provinces
]);
}
<div class="form-group">
{{ Form::label('Provinces') }}
{!!Form::select('province_id', $provinces, $entity->province->id ?? null, ['class' => 'form-control'])!!}
</div>
but I don't achieve the expected result, I suppose that as I have been reading, the second parameter passed to Form::select must be of the 2-dimensional array type
Please, if you could help me get through eloquent to get all the provinces and group them by countries, to get an array of 2 dimensions as I need it. Thank you very much in advance
Start with a Country rather than Province.
Give this a try:
$countries = Country::with('provinces')->get()->transform(function($country) {
return [$country->name => $country->provinces->pluck('name','id')];
});
This should return a structure like this:
"Country 1" =>
1 => "Province 1"
2 => "Province 2"
3 => "Province 3"
N.B. This may require a little bit of refactoring as I haven't been able to run this yet!

I want to combine two separate pagination models in laravel

I want to combine two separate pagination model in laravel, but errors in the view and paging does not work.
my controller code ,I also tried different methods, data comes but paging is not my goal paging
<?php
namespace App\Http\Controllers\Frontend\News;
use App\Http\Controllers\Controller;
use App\Models\Blog;
use App\Models\Company\CompanyEvent;
class NewsController extends Controller
{
function news()
{
$blogs = Blog::sort()->with('company')->paginate(15);
$events = CompanyEvent::sort()->with('company')->paginate(15);
$events=collect($events)->merge($blogs);
return view('news.news',compact('events'));
}
function detail()
{
return "detail";
}
}
blog model
<?php
namespace App\Models;
use App\Models\Company\Company;
use App\Models\Interfaces\CreatedAt;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Carbon;
use Illuminate\Http\Request;
/**
* Class Blog
* #package App\Models
* #mixin Builder
* #property boolean $active
* #property int $company_id
* #property string $title
* #property string $url
* #property string $context
* #property string $tags
* #property string $main
* #property string $seo_title
* #property string seo_description
* #property string $seo_keyword
* #property string $image
* #property-read CreatedAt|Carbon $created_at
* #property-read CreatedAt|Carbon $updated_at
* #property-read CreatedAt|Carbon $deleted_at
* #method static Builder|Blog find(int $id)
* #method static Builder|Blog where($column, $operator = null, $value = null, $boolean = 'and')
* #method static Builder|Blog findOrFail($id)
* #method static Builder|Blog active()
* #method Builder|Blog filter(Request $request) bind to scopeFilter method
* #method static Builder|Blog sort() laravel query bind to scopeSort method
* #method static Builder|Blog latest() laravel query bind to scopeSort method
*
*/
class Blog extends Model
{
use SoftDeletes;
protected $table = 'blogs';
/**
* #return bool
*/
public function isActive(): bool
{
return (bool)$this->active;
}
/**
* #param bool $save
* #return bool
*/
public function toggleActive($save = false)
{
$this->active = !$this->active;
if ($save == true)
return $this->save();
return false;
}
/**
* #return MorphToMany
*/
function comments()
{
return $this->morphToMany('App\Models\Blog', 'commentable');
}
/**
* #return string
*/
function getAgoTimeAttribute()
{
return Carbon::parse($this->created_at)->diffForHumans();
}
/**
* #param $value
* #return array
*
*/
function getTagsAsArrayAttribute($value)
{
return explode(',', $this->tags);
}
/**
* #param Builder|Blog $query
* #return mixed
*
*/
function scopeActive($query)
{
return $query->where('active', 1);
}
/**
* #return BelongsTo
*/
function company()
{
return $this->belongsTo(Company::class, 'company_id', 'id');
}
/**
* #return string
*/
function getTimeAgoAttribute()
{
return Carbon::parse($this->created_at)->diffForHumans();
}
/**
* #return false|string
*/
function getShortContextAttribute()
{
return substr($this->context, 0, 250);
}
/**
* #param Blog|Builder $query
* #param Request $request
* #return mixed
*/
function scopeFilter($query, $request)
{
$requests = $request->except('page');
foreach ($requests as $key => $val)
$query = $query->where($key, 'like', '%' . $val . '%');
return $query;
}
/**
* #param Builder|Blog $query
* #return mixed
*/
function scopeSort($query)
{
return $query->orderBy('created_at', 'desc');
}
}
company event model
<?php
namespace App\Models\Company;
use App\Calendar\Day\Day;
use App\Calendar\Month\Month;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
/**
* Class CompanyEvent
* #mixin Builder
* #package App\Models\Company
* #property \DateTime $date
* #method static Builder|CompanyEvent get()
* #method static Builder|CompanyEvent find($id)
* #method static Builder|CompanyEvent findOrFail($id)
* #method static Builder|CompanyEvent active() bind to scopeActive
* #method static Builder|CompanyEvent sort()
* #method static Builder|CompanyEvent latest()
*
*/
class CompanyEvent extends Model
{
use SoftDeletes;
protected $table = 'company_events';
/**
* get day name from date column
* #return string
*
*/
function getDayNameAttribute()
{
$dayIndex = (int)date('w', strtotime($this->date));
return ucfirst(Day::DAY_NAMES[$dayIndex]);
}
/**
* get month from date column
* #return string
*/
function getMonthAttribute()
{
$monthIndex = (int)date('m', strtotime($this->date));
return ucfirst(Month::MONTH_NAMES[$monthIndex - 1]);
}
/**
* #return false|string
*/
function getDayAttribute()
{
return date('d', strtotime($this->date));
}
/**
* #return bool
*
*/
function getIsExpireDateAttribute()
{
$date = date('Y-m-d', strtotime($this->date));
$todayDateAsTime = strtotime(date('Y-m-d'));
$eventDateAsTime = strtotime($date);
if ($todayDateAsTime > $eventDateAsTime)
return true;
return false;
}
/**
* #return bool
*
*/
function getIsEventTodayAttribute()
{
$date = date('Y-m-d', strtotime($this->date));
$todayDateAsTime = strtotime(date('Y-m-d'));
$eventDateAsTime = strtotime($date);
return (boolean)($eventDateAsTime == $todayDateAsTime);
}
/**
* #return string
*/
function getAgoTimeAttribute()
{
return Carbon::parse($this->date)->diffForHumans();
}
/**
* #return BelongsTo
*/
function company()
{
return $this->belongsTo(Company::class, 'company_id', 'id');
}
/**
* #param Builder|CompanyEvent $query
* #return mixed
*/
function scopeActive($query)
{
return $query->where('active', 1);
}
/**
* #param Builder|CompanyEvent $query
* #return mixed
*/
function scopeSort($query)
{
return $query->orderBy('created_at','desc');
}
}
I also tried different methods, data comes but paging is not my goal paging
my view code
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Mr. Burhan</title>
</head>
<body>
{{$events->total()}} adet bulundu
<ul>
#foreach( $events as $value )
<li>{{$value}}</li>
#endforeach
</ul>
{{$events->appends(request()->all())->render()}}
</body>
</html>

Laravel 5 Querying Relationship

Here is the relationship 1 code:
/**
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function address()
{
return $this->hasMany('App\IPAddress', 'group_id');
}
and relationship 2 code:
/**
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function group()
{
return $this->belongsTo('App\IPGroups');
}
I want to get all ip addresses that belongs to specified group. I don't want to write raw queries, I need to be done with querying relationship. Does anyone has an idea?
I tried to do something like this:
/**
* Get IP Addresses of specified group
* #param Request $request
* #return mixed
*/
public function getIP(Request $request)
{
$group = IPGroups::findOrFail($request->group_id);
return $group->address;
}
but I need to add one where statement where I can pick only active ip addresses.
Here is the model 1 code:
namespace App;
use Illuminate\Database\Eloquent\Model;
class IPGroups extends Model
{
/**
* Working Table
* #var string
*/
protected $table = 'ip_groups';
/**
* Guarded Values From Mass Assignment
* #var array
*/
protected $guarded = [ 'id' ];
/**
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function address()
{
return $this->hasMany('App\IPAddress', 'group_id');
}
}
and the second model code:
namespace App;
use Illuminate\Database\Eloquent\Model;
class IPAddress extends Model
{
/**
* Working Table
* #var string
*/
protected $table = 'ips';
/**
* Protected Values From Mass Assignment
* #var array
*/
protected $fillable = [ 'group_id', 'ip', 'description', 'status' ];
/**
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function group()
{
return $this->belongsTo('App\IPGroups');
}
}
Try this, getting only the addresses with status as 'Active':
return $group->address->where('status','Active');
The reason this doesn't work:
return $group->address->where('status','=','Active');
is that the where we are using here is the where of the class Collection, which doesn't accept a comparator as second parameter as the where of the Models do.

Resources