Laravel - Implement eloquent relations in repository - php

I have 3 models for managing user permissions.
class User extends Authenticatable
{
public function roles()
{
return $this->belongsToMany('App\Models\Role');
}
}
class Role extends Model
{
public function users()
{
return $this->belongsToMany('App\Models\User');
}
public function permissions()
{
return $this->belongsToMany('App\Models\Permission');
}
}
class Permission extends Model
{
public function roles()
{
return $this->belongsToMany('App\Models\Role');
}
public function roleHavePermission(Role $role)
{
if ($this->roles()->find($role->id)) {
return true;
}
return false;
}
public function userHavePermission(User $user = null)
{
$roles = [];
if (is_null($user)) {
$roles[] = Role::where('slug', 'guest')->first();
} else {
foreach ($user->roles as $role) {
$roles[] = $role;
}
}
foreach ($roles as $role) {
if ($this->roleHavePermission($role)) {
return true;
}
}
return false;
}
}
Now because my application is grown, I'm moving to repositories. For example this is my PermissionRepository:
class PermissionRepository implements PermissionRepositoryInterface
{
protected $roleRepository;
/**
* PermissionRepository constructor.
* #param RoleRepositoryInterface $roleRepository
*/
public function __construct(RoleRepositoryInterface $roleRepository)
{
$this->roleRepository = $roleRepository;
}
public function action($routeName)
{
return Permission::where('action', $routeName)->first();
}
}
How can I implement roleHavePermission and userHavePermission in this repository? I tried implementing roles method with this syntax:
public function roles()
{
return Permission::roles();
}
But it wont work since Permission's roles method can not called statically. Thanks.

In fact in my opinion you shouldn't implement it in repository. When you call
$permission = $permissionRepository->action('abc.name');
you are getting permission object, so there is no point to implement it in repository. All you need is running:
$roles = $permission->roles;
In theory you could add for example into PermissionRepository method like this:
public function getRoles(Permission $permission)
{
return $permission->roles;
}
so you could now run
$roles = $permissionRepository->getRoles($permission);
to get roles of given permission but I don't see any point to do it like this.

Related

Call to a member function toArray() on integer

User.php
public function role()
{
return $this->belongsToMany('App\Models\Role','user_role','user_id','role_id');
}
//проверка принадлежит ли пользователь к какой либо роли
public function isEmloyee(){
$role=$this->role->toArray();
return !empty($role);
}
//проверка имеетли пользователь определению роли
public function hasRole($check){
return in_array($check,array_pluck($this->role->toArray(),'name'));
}
//получение идентификатора роли
private function getIdinArray($array,$term){
foreach ($array as $key => $value){
if ($value == $term){
return $key +1;
}
return false;
}
}
//добавление роли пользователя
public function makeEmployee($title){
$assiqned_role = array();
$role = array_pluck(Role::all()->toArray(),'name');
switch ($title){
case 'admin':
$assiqned_role[] = $this->getIdinArray($role,'admin');
case 'client':
$assiqned_role[] = $this->getIdinArray($role,'client');
break;
default:
$assiqned_roles[] = false;
}
$this->role()->attach($assiqned_role);
}
Role.php
class Role extends Model
{
public function users()
{
return $this->belongsToMany('App\Models\User','user_role','role_id');
}
}
OwnerMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
class OwnerMiddleware
{
public function handle($request, Closure $next,$role)
{
if(!$request->user()->hasRole($role)) {
return redirect('/');
}
return $next($request);
}
}
You have role column in database. It preserves access to your role relation collection. You should delete it or rename role() relation for example to roles(). Moreover, belongsToMany implies that user can have many roles.
In addition, I want to note that the collection has its own methods in_array => contains, array_pluck => pluck. You could optimize your code like that:
public function roles()
{
return $this->belongsToMany(Role::class, 'user_role');
}
public function isEmloyee(){
return $this->roles->isNotEmpty();
}
public function hasRole($name){
return $this->roles->pluck('name')->contains($name);
}
public function makeEmployee($name){
$role = Role::where('name', $name)->first();
if($role){
$this->role()->attach($role->id);
}
}

How to associate a model with two or more other models in Laravel

I need to associate some models with at least two other models in an app that I'm developing, but I can't do the association in the controllers.
Here's the code.
UserModel
public function prices() {
return $this->hasMany(PriceClass::class);
}
PriceModel
public function user() {
return $this->belogsTo(ClassOfTheUser::class);
}
public function price_lines() {
return $this->hasMany(PriceLinesClass::class);
}
AreaModel
public function price_lines() {
return $this->hasMany(PriceLineClass::class);
}
PriceLinesModel
public function area() {
return $this->belongsTo(AreaClass::class);
}
public function price() {
return $this->belongsTo(PriceClass::class);
}
How may I do the creation of the Price, if I can't do something like:
public function store(Request $request) {
if ($request->ajax()) {
$user = UserClass::findOfFail($request->input("user_id"));
$user->prices()->save(new PriceClass());
$price = $user->prices()->lastest()->first();
foreach($request->input("price_lines") as $price_line) {
$area = AreaClass::findOrFail($price_line["area_id"]);
$area->price_lines()->save(new PriceLineClass());
$price_line_instance = $area->price_lines()->lastest()->first();
$price->price_lines()->save($price_line_instance);
}
}
}

Laravel 5.2 Nested Eloquent relationships

I have a User which is of type Player and has several Equipments
I want to request a piece of Equipment and see if the User is it's owner before returning it to the user. If they do not own it they will get an unauthorized response
Here are the relationships I have for the models:
App\User.php
class User extends Authenticatable
{
protected $table = 'user';
public function player()
{
return $this->hasOne(Player::class);
}
}
App\Player.php
class Player extends Model
{
protected $table = 'player';
public function equipment()
{
return $this->hasMany(Equipment::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
App\Equipment.php
class Equipment extends Model
{
protected $table = 'equipement';
public function player()
{
return $this->belongsTo(Player::class);
}
}
EquipmentController.php
With my attempt which is working... just very ugly.
class EquipmentController extends Controller
{
public function show($id)
{
$equipment = Equipment::find($id);
if ( ! $equipment ) {
return 'Equipment does not exist');
}
// my attempt
$test = Equipment::with('player.user')->findOrFail($id);
if ($test->toArray()['player']['user']['id'] != Auth::user()->id){
return 'Unauthorized';
}
//
return $equipment;
}
}
Is there a neater way to do this?
I want something readable in the controller like:
if(!$equipment->ownedBy(Auth::user())){
return 'Unauthorized';
}
Or something similarly as readable.
And once the relationship is found, I'm not sure where the logic should be placed. Should it be in the Equipment model?
Any help would be much appreciated!
In your Equipment model:
public function authorized()
{
return ($this->player->user->id == auth()->user()->id())
}
Then from your controller, try:
$equipment->authorized() //returns true or false

Eager loading on polymorphic relations

class Admin {
public function user()
{
return $this->morphOne('App\Models\User', 'humanable');
}
public function master()
{
return $this->hasOne('App\Models\Master');
}
}
class Master {
public function admin()
{
return $this->hasOne('App\Models\Admin');
}
}
class User {
public function humanable()
{
return $this->morphTo();
}
public function images()
{
return $this->hasOne('\App\Models\Image');
}
}
class Image {
public function user()
{
return $this->belongsTo('\App\Models\User');
}
}
Now if I dump this:
return \App\Models\Admin::where('id',1)->with(array('user.images','master'))->first();
I get the perfect result one master, one user and one image record.
But if I do this
return $user = \App\Models\User::where('id',1)->with(array('humanable','humanable.master'))->first();
I only get one Admin record, the query get * from masters doesn't even run.
Any idea what I'm doing wrong, I'm sure this is possible.
If I remember correctly Laravel has lots of pitfall. You can try to use the protected $with var in Admin model instead of query builder with function.
class Admin {
protected $with = ['master'];
public function user() {
return $this->morphOne('App\Models\User', 'humanable');
}
public function master() {
return $this->hasOne('App\Models\Master');
}
}
In query builder, only need to include humanable. Now you should see master inside the humanable object.
return $user = \App\Models\User::where('id',1)->with('humanable')->first();
Hope this help.

Laravel model object chaining

For some reason, I cannot chain model objects. I'm trying to eager load 'Location' for an 'Order' and would prefer the logic to be contained in the models themselves. But past one chain, it does not work.
class Order extends Eloquent {
protected $table = 'orders';
public function customer() {
return $this->belongsTo('Customer');
public function location() {
return $this->customer()->location(); // this does not work
}
}
class Customer extends Eloquent {
protected $table = 'customers';
public function user() {
return $this->belongsTo('User');
}
public function orders() {
return $this->hasMany('Order');
}
public function location() {
return $this->user()->location();
// return $this->user(); // WORKS!!
}
}
class User extends Eloquent {
protected $table = 'users';
public function locations() {
return $this->hasMany('Location');
}
public function location() {
return $this->locations()->first();
}
}
I eventually want to do this:
class ChefController extends BaseController {
public function get_orders() {
$chef = $this->get_user_chef(); // this already works
return $chef->orders()->with('location')->get(); // does not work
}
}
Try to reference relation (user table) by adding user_id as second argument, like this:
public function user() {
return $this->belongsTo('User',"user_id");
}
Maybe you called that id field different, but you know what I mean.

Categories