I am new to laravel and now trying to learn policies so I created the following models:
class group extends Model
{
protected $fillable = [
'id','book_id',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
public function users(){
return $this->belongsToMany('BOOK_DONATION\User')->withPivot('last_seen_id');
}
}
and :
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email','country','state/provience','city', 'token', 'password','postal_code',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password','verfied', 'remember_token',
];
public function Book(){
return $this->hasMany('App\Book');
}
public function groups(){
return $this->belongsToMAny('BOOK_DONATION\group')->withPivot('last_seen_id');
}
}
and :
class group_user extends Model
{
//
protected $table='group_user';
protected $fillable = [
'user_id','group_id','last_seen_id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
}
now the group_user is model for the intermidate table required for the many to many relation between users and groups
and here is my policy:
class group_userPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the group_user.
*
* #param \BOOK_DONATION\User $user
* #param \BOOK_DONATION\group_user $groupUser
* #return mixed
*/
public function view(User $user, group_user $groupUser)
{
//
return in_array($user->id,$groupUser->user_id);
}
}
and here is the specific programming lines from controller related :
$grouUser=group_user::where('group_id',$group_id)->pluck('user_id');
if(Auth::user()->cant('joinChat',$grouUser)) return redirect('/sorry');
now I always get redirected to sorry page but I have the right yo join chat so what is wrong?
Related
I try to create a function using round robin where all user in a group will be moderator for every meeting created.For example, a group have 2 users, I managed to create the first two meeting with the two users, but when I created the third meeting, it become null.
public function addsession(Request $req)
{
$mod = null;
$latestUserId=Meeting::where('groupID', $req->groupID)
->latest('id')
->first()
?->meetingModerator;
//the first meeting or all the users have already had their turn
$firstUserId=DB::table('group_user')
->where('group_id', $req->groupID)
->orderBy('user_id')
->first()
?->user_id;
//second time meeting is being held
if ($latestUserId) {
$nextUserId=DB::table('group_user')
->where('group_id', $req->groupID)
->where('user_id', ">", $latestUserId)
->orderBy('user_id')
->first()
?->user_id;
$mod = $nextUserId;
} else {
$mod = $firstUserId;
}
$data = new Meeting;
$data->groupID = $req->groupID;
$data->meetingDate = $req->meetingDate;
$data->meetingTime = $req->meetingTime;
$data->meetingModerator = $mod;
$data->save();
}
Model group.php
class Group extends Model
{
use SoftDeletes;
use HasFactory;
public $timestamps=true;
protected $dates = ['deleted_at'];
public function creators()
{
return $this->belongsToMany(User::class);
}
}
Model user.php
class User extends Authenticatable
{
use SoftDeletes;
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'name',
'email',
'password',
'role'
];
protected $dates = ['deleted_at'];
public function grp()
{
return $this->belongsToMany(Group::class);
}
/**
* The attributes that should be hidden for serialization.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = [
'profile_photo_url',
];
}
Model meeting.php
class Meeting extends Model
{
use HasFactory;
public function gr()
{
return $this->belongsTo('App\Models\Group','groupID');
}
}
I have a model called Address. It has an 'additional' attribute. Although the attribute is filled, the model returns an empty array. I use an API resource to get the data.
This is the Address model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Address extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'addresses';
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model's ID is auto-incrementing.
*
* #var bool
*/
public $incrementing = true;
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps = false;
/**
* The database connection that should be used by the model.
*
* #var string
*/
protected $connection = 'solarium';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
//
];
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = [];
/**
* The model's default values for attributes.
*
* #var array
*/
protected $attributes = [
//
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
//
];
public function addressable()
{
return $this->morphTo();
}
}
This is the Address API resource:
<?php
namespace App\Http\Resources;
use App\Models\Address;
use Illuminate\Http\Resources\Json\JsonResource;
class AddressResource extends JsonResource
{
/**
* The resource that this resource collects.
*
* #var string
*/
public $collects = Address::class;
/**
* Indicates if the resource's collection keys should be preserved.
*
* #var bool
*/
public $preserveKeys = true;
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'cep' => $this->cep,
'street' => $this->street,
'number' => $this->number,
'district' => $this->district,
'city' => $this->city,
'state' => $this->state,
'additional' => $this->additional,
];
}
}
As I said, the 'additional' attribute returns an empty array although it is filled with a string value.
The JsonResource has a public property named additional which has a default value of [], an empty array. That is what you are accessing since $this->additional is asking for that property. This is not forwarding that access to the model (resource) since this is an accessible property on this instance, (how PHP's OOP works).
You would probably have to access the underlying resource from the property of the JsonResource to then access that particular property (attribute):
$this->resource->additional
I get this error after clicking 'New Post' button the frontend of the app:
Posts view
Line from my log file:
[2020-09-27 14:41:03] local.ERROR: Call to undefined method App\Models\User::identifiableAttribute() {"exception":"[object] (BadMethodCallException(code: 0): Call to undefined method App\Models\User::identifiableAttribute() at C:\xampp\htdocs\backpack-demo\vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php:50)
I am using Laravel 7 + Backpack CRDU generator
Posts Controller:
<?php
namespace App\Http\Controllers;
use App\Events\NewPost;
use App\Http\Requests\PostStoreRequest;
use App\Jobs\SyncMedia;
use App\Mail\ReviewPost;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
class PostController extends Controller
{
/**
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index(Request $request)
{
$posts = Post::all();
return view('post.index', compact('posts'));
}
/**
* #param \App\Http\Requests\PostStoreRequest $request
* #return \Illuminate\Http\RedirectResponse
*/
public function store(PostStoreRequest $request)
{
$post = Post::create($request->validated());
Mail::to($post->author->email)->send(new ReviewPost($post));
SyncMedia::dispatch($post);
event(new NewPost($post));
$request->session()->flash('post.title', $post->title);
return redirect()->route('post.index');
}
}
Posts Model:
class Post extends Model
{
use CrudTrait;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'title',
'content',
'published_at',
'author_id',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'author_id' => 'integer',
];
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = [
'published_at',
];
public static function create(array $validated)
{
}
public function author()
{
return $this->belongsTo(User::class);
}
}
User model:
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',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
your have forgotten to use 'CrudTrait' in your User Model:
use Backpack\CRUD\app\Models\Traits\CrudTrait;
class User extends Authenticatable
{
use Notifiable,CrudTrait
.......
}
I have implemented the relationship without Eloquent but I was wondering is there was a way to define this relationship in Eloquent so that my application can have more consistency.
table User
-id
-other user attributes
table friend_requests:
-id
-sender_id
-reciever_id
table friends
-id
-first
-second
The friendRequest relation has been easily implemented in the Eloquent but the problem lies in Friends.
If I do this in the User model class:
public function friends(){
return $this->belongsToMany(User::class,'friends','first','second');
}
This wouldn't work as you would have noticed. Let me explain with example:
Table: friends
id | first | second
1 | 1 | 2
2 | 3 | 1
you see that user_1 is friends with user_2 as well as user_3 as the relationship is bi-directional. But Eloquent will naturally return that user_1 is friends with user_2 only. After thinking for a while I tweaked the statement but made little progress'
public function friends(){
return $this->belongsToMany(User::class,'friends','first','second')
->orWhere('second',$this->id);
}
That is because now it selects both rows but the Users it returns are those whose id = second which means that in the second case it will return the user itself.
I implemented the relations with my own methods in User model class which use DB::table('friends')-> to addFriend(User $user), removeFriend(user $user) and returns list of friends(), but I'm disappointed that this isn't as eloquent as Eloquent relationships.
Perhaps some more experienced developers here would have come across this kind of problem and would have dealt better than I did. How do you propose I deal with this problem. Should I stick with my approach or is there a better way to deal with it?
A more manageable way to implement bidirectional relations would be to create two entries for each confirmed friendship.
So a user would make a friend request to another user. When the second user confirms the friend request, two friendships are created.
Example Controller
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use App\FriendRequest;
use App\Friendship;
class FriendshipController extends Controller
{
public function friendRequest(Request $request)
{
$receiver_id = $request->input('receiver_id');
$request->user()->friend_offers()->create([
'receiver_id' => $receiver_id
]);
}
public function friendshipConfirmation(Request $request)
{
$friend_request_id = $request->input('friend_request_id');
$friend_request = FriendRequest::find($friend_request_id);
$friend_request->receiver->friendships()->create([
'user_2_id' => $friend_request->sender->id
]);
$friend_request->sender->friendships()->create([
'user_2_id' => $friend_request->receiver->id
]);
}
}
Database Tables
(Note the proper spelling of receiver and plural users table)
table users
- id
- other user attributes
table friend_requests:
- id
- sender_id
- receiver_id
table friendships
- id
- user_1_id
- user_2_id
User Model
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable
{
use SoftDeletes;
public $timestamps = true;
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = ['id'];
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
//
];
/**
* Return friend requests from other users
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function friend_requests()
{
return $this->hasMany(FriendRequest::class, 'receiver_id');
}
/**
* Return friend requests sent to other users
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function friend_offers()
{
return $this->hasMany(FriendRequest::class, 'sender_id');
}
/**
* Return friendships with other users
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function friendships()
{
return $this->hasMany(Friendship::class, 'user_1_id');
}
}
FriendRequest Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class FriendRequest extends Model
{
use SoftDeletes;
public $timestamps = true;
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = ['id'];
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'sender_id',
'receiver_id'
];
/**
* Return the requesting user
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function sender()
{
return $this->belongsTo(User::class, 'sender_id');
}
/**
* Return the receiving user
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function receiver()
{
return $this->belongsTo(User::class, 'receiver_id');
}
}
Friendship Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Friendship extends Model
{
use SoftDeletes;
public $timestamps = true;
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = ['id'];
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'user_1_id',
'user_2_id'
];
/**
* Return user_1
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function first()
{
return $this->belongsTo(User::class, 'user_1_id');
}
/**
* Return user_2
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function second()
{
return $this->belongsTo(User::class, 'user_2_id');
}
}
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.