I'm creating a school platform where students, teachers,... can login using their credentials. To reduce duplicate data I did not make a separate table called students, instead I keep all the data in the users table.
To know if a user is a student I a have a table that is called enrolments, in this table a user_id , schoolyear_id and class_id is stored.
I already made a student model that refers to the users table, but how can I ensure that this model only passes students?
EER:
Student.php:
<?php
namespace App;
class Student extends User
{
protected $table= 'users';
public function enrollments(){
return $this->belongsToMany(Enrollment::class);
}
}
User.php:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Support\Facades\Auth;
class User extends Authenticatable
{
use Notifiable;
use HasRoles;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name','last_name', 'password'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function profiles(){
return $this->hasOne(Profile::class);
}
}
What I want to achieve is that when I call the Student::all(); function I get all the users who are enrolled in the school,hence students.
Check out model events: https://laravel.com/docs/5.5/eloquent#events
You should be able to drop this into your student model for a test:
protected static function boot(){
parent::boot();
static::retrieved(function($thisModel){
if($thisModel->isNotAStudent or whatever logic you need){
return false;
}
}
}
I'm still on 5.4, which does not have the retrieved model event built in, but returning false generally stops the call from going through. So applying that logic to the retrieved event may stop that model instance from being returned if it is not a student, but allow students to be returned. Just a thought.
Your provided solution lead me in the right direction. My problem is solved by using global scope:
<?php
namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
class Student extends User
{
protected $table= 'users';
protected static function boot()
{
parent::boot();
static::addGlobalScope('student', function (Builder $builder) {
$builder->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('enrollments')
->whereRaw('enrollments.user_id = users.id');
});
});
}
public function enrollments(){
return $this->belongsToMany(Enrollment::class);
}
}
Related
I am building a forum website using Laravel and Vue.
I have three tables: forums, posts, and users.
One forum can have multiple posts, each post has a user who created the post.
When the user clicks on one forum, I want to display the latest 10 posts to this forum with the paginate method.
Forum.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Forum extends Model {
use HasFactory;
protected $table = 'forums';
protected $guarded = [];
/**
* Get the forum posts
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function posts() {
return $this->hasMany(Post::class)->orderBy('created_at', 'DESC');
}
}
Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model {
use HasFactory;
protected $table = 'posts';
protected $guarded = [];
/**
* Get the post's user
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user() {
return $this->belongsTo(User::class);
}
}
User.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable {
use HasFactory, Notifiable;
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Get the user posts
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function posts() {
return $this->hasMany(Post::class);
}
}
Here I retrieve the forum posts with the users.
ForumService.php
<?php
namespace App\Services;
use App\Models\Forum;
class ForumService {
public static function getForumPosts($forumId) {
$forum = Forum::with('posts.user')->find($forumId);
dd($forum);
}
}
However, I want to retrieve only 10 posts and get each post's user, so how do I do that in a relationship? The posts are paginated, but how to I get now the posting user? Because the dot syntax is applying to the user, therefore I paginate the user, not the posts.
ForumService.php
<?php
namespace App\Services;
use App\Models\Forum;
class ForumService {
public static function getForumPosts($forumId) {
$forum = Forum::with(
[
'posts' => function ($query) { // How do I get the post user?
return $query->paginate(10);
}
]
)->find($forumId);
dd($forum);
}
}
Just add the with method inside the query scope of the function you have created.
$forum = Forum::with(
[
'posts' => function ($query) {
// returns posts with user
return $query->with('user')->paginate(10);
}
]
)->find($forumId);
Now you can access the first user with $forum->posts[0]->user which will not query to the database but will prefetch the users and populate it in paginator collection.
As you have already the id of the forum you can only retrieve posts which belongs to that Forum and paginate them like this
public static function getForumPosts($forumId) {
return Forum::find($forumId)->posts()->paginate(10);
}
If you want to eager load Post creator you can perform that like this
public static function getForumPosts($forumId) {
return Forum::find($forumId)->posts()->with(['user'])->paginate(10);
}
I have created a relationship between User model and StoryModel. But it give me the Error:-
Call to undefined relationship [userStories] on model [App\User].
May be I'm missing something. Following is my code which I'm using
User.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Notification;
use App\CheckIn;
use App\Travel;
use Carbon\Carbon;
use App\NewInterest;
use App\UserStory;
class User extends Authenticatable
{
use Notifiable;
protected $table = "users";
protected $primaryKey = 'id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'firstname','lastname', 'user_id','email',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function userStories(){
return $this->hasMany(UserStory::class, 'user_id', 'user_id');
}
}
Controller Logic
$usersStories = User::with('userStories')
->select('id','user_id','stories')
->get();
print_r($usersStories);
exit;
Are you wriiten mapping code in your UserStory Model that should be
public function userAccount(){
return $this->belongsTo(User::class);
}
If you already written this code then check you column names in your DB.
Can you try by changing the sequence like this:
$usersStories = User::->select('id','user_id','stories')
->with('userStories')
->get();
print_r($usersStories);
exit;
You should update your model and try:
User model
public function userStories(){
return $this->hasMany(UserStory::class);
}
UserStory model
public function users(){
return $this->belongsTo(User::class, 'user_id');
}
I want to use the User model that already in the app folder. but it seem it only extends Authenticatable and can't extend by the model Class i want to use it as a link to the other class, like user has only one employee. what else can i do to recycle the user model that is already extended by Authenticatable?
thanks for the help :)
this is the user model that extends the authenticatable
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function employee()
{
return $this->belongsTo('App\Employee');
}
}
And this is the employee model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Employee extends Model
{
// protected $table = "positions";
// public function position()
// {
// return $this->hasMany('App\Position');
// }
protected $table = "employees";
public function employee()
{
return $this->hasOne('App\User');
}
}
It already inherited Model class. If you follow Illuminate\Foundation\Auth\User you will finally find that it is inherited from a Model class. So, your User model has the same features that your other models have.
I have 4 tables:
user(id,role_id)
role(id)
permission_role(role_id,permission_id)
permission(id, name)
User model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Zizaco\Entrust\Traits\EntrustUserTrait;
class User extends Authenticatable
{
use Notifiable;
use EntrustUserTrait;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function roles()
{
return $this->hasOne('App\Role', 'id', 'role_id');
}
}
Role model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Zizaco\Entrust\EntrustRole;
class Role extends EntrustRole
{
public function users()
{
return $this->belongsTo('App\User','role_id','id');
}
public function permissions()
{
return $this->belongsToMany('App\Permission','permission_role');
}
}
Permission model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Zizaco\Entrust\EntrustPermission;
class Permission extends EntrustPermission
{
public function roles()
{
return $this->belongsToMany('App\Role','permission_role');
}
}
and i want to test in my controller to see if user have permission delete_article via if condition, any help? and thanks
In you Role model
Something like this you need to do (Many to Many)
//.......................
public function permissions()
{
return $this->belongsToMany('App\Permission','permission_role''role_id', 'permission_id');
}
//......................
See Many to Many relationship: Link
And to get the data into your controller
//..........................................
$user = get data with role and permission
$roles= $user->roles;
foreach($roles as $role){
foreach($role->permissions as $permission){
$permissiona_name = $permission->name;
}
}
//...........................
first check with var_dump($user)
Many to many with pivot (see Retrieving Intermediate Table Columns section)
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
See also "Has Many Through"
I am trying to implement a watchlist feature on my job site application. I am abit confused as to the exact eloquent queries to use to fetch the data from the job_listings table. Currently the user can add a job to their watchlist successfully.
What I want to be able to do:
View all of the jobs that the user has put in their respective watchlists with all the details e.g the Job position, description etc.
Current DB layout:
Routes:
Bigger pic of routes here
WatchlistController
<?php namespace App\Http\Controllers;
use App\Watchlist;
use App\JobListing;
use App\User;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Auth;
use Redirect;
class WatchlistController extends Controller {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
// Need to run queries in here to get the
$user = User::with('watchlist')->find(\Auth::id());
var_dump($user);
// Then return my main watchlist view which will send through an
// array so I can loop through it and display what the user
// has put in their watchlist
// return view('watchlist/viewWatchlist');
}
/**
* Adds the username of the user that is currently logged in
* and adds the job listing ID that the user clicks on to the Watchlist table.
*/
public function addToWatchlist($id)
{
$createItemInWatchlist = Watchlist::create([
'user_id' => Auth::user()->id,
'job_id' => $id
]);
return Redirect::to('watchlist');
}
Watchlist Model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Watchlist extends Model {
protected $table = 'watchlist';
protected $fillable = ['user_id', 'job_id'];
}
JobListing Model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class JobListing extends Model {
protected $table = 'job_listings';
protected $fillable = ['user_id', 'position_title', 'description', 'category', 'job_type',
'city','company_name','company_url','logo_path','how_to_apply', 'expiry_date', 'status'];
}
User Model
<?php namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['username','firstname', 'lastname', 'email', 'password', 'role'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function watchlist() {
return $this->hasMany('\App\JobListing', 'watchlist', 'user_id', 'job_id');
}
}
This is not the (direct) answer, but you may take a look at the eloquent relations -> http://laravel.com/docs/5.0/eloquent to see the advantages.
If you could use ids for your users, the solution looks like this: The watchlist table is the connection between the user and your jobs. Each user can track multiple jobs, so there is a belongsToMany relation between them. BelongsToMany takes up to four parameter:
your Model that you would like to "connect" to and
sql table that includes both ids of the user and the job to link between user and jobs
local id (user)
foreign id (job)
More here: http://laravel.com/docs/5.0/eloquent#many-to-many. Extend your user model with the following relation:
public function watchlist() {
return $this->belongsToMany('\App\JobListing', 'watchlist', 'user_id', 'job_listing_id');
}
To get the watchlist, you can use (eager loading):
$user = User::with('watchlist')->find(\Auth::id());
To access to watchlist items, use $user->watchlist
Alternatively you can retrieve the watchlist directly in the template from the user by using:
#foreach(Auth::User()->watchlist as $job)
{{$job}}
#endforeach
To read more about the relations, take a look at this: https://laracasts.com/series/laravel-5-fundamentals -> part 14, relations and something to read (version 4) http://daylerees.com/codebright/eloquent-relationships