Simple approach of route protection based on roles Laravel 5.2 - php

I want to protect my routes based on roles.
This is what I have done but I can't seem to get it to work.
Role model:
protected $table = 'roles';
protected $fillable = array(
'name', 'description'
);
public function users(){
return $this->belongsToMany('App\User', 'user_role', 'role_id', 'user_id');
}
Role migration
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('name', 40);
$table->string('description', 255);
});
RoletableSeeder file
Role::create([
'id' => 1,
'name' => 'Admin',
'description' => 'Admin User.'
]);
Role::create([
'id' => 2,
'name' => 'Vendor',
'description' => 'Vendor User.'
]);
Role::create([
'id' => 3,
'name' => 'User',
'description' => 'Simple User.'
]);
A sample route:
Route::get('/admin/dashboard', [
'uses' => 'AdminController#adminDashboard',
'as' => 'admin.dashboard',
'middleware' => ['auth', 'roles'],
'roles' => ['Admin']
]);
User model:
protected $fillable = [
'email','username', 'password', 'confirmation_code'
];
protected $hidden = [
'password', 'remember_token',
];
public function orders() {
return $this->hasMany('App\Order');
}
public function roles(){
return $this->belongsToMany('App\Role', 'user_role', 'user_id', 'role_id');
}
public function hasRole($roles){
$this->have_role = $this->getUserRole();
if($this->have_role->name == 'Admin') {
return true;
}
if(is_array($roles)){
foreach($roles as $need_role){
if($this->checkIfUserHasRole($need_role)) {
return true;
}
}
} else{
return $this->checkIfUserHasRole($roles);
}
return false;
}
private function getUserRole(){
return $this->roles()->getResults();
}
private function checkIfUserHasRole($need_role){
return (strtolower($need_role)==strtolower($this->have_role->name)) ? true : false;
}
CheckRole.php file which is inside middleware:
<?php namespace App\Http\Middleware;
use Closure;
class CheckRole{
public function handle($request, Closure $next)
{
$roles = $this->getRequiredRoleForRoute($request->route());
if($request->user()->hasRole($roles) || !$roles){
return $next($request);
}
return response([
'error' => [
'code' => 'INSUFFICIENT_ROLE',
'description' => 'You are not authorized to access this resource.'
]
], 401);
}
private function getRequiredRoleForRoute($route)
{
$actions = $route->getAction();
return isset($actions['roles']) ? $actions['roles'] : null;
}
}
and last I added one line to the kernel:
protected $routeMiddleware = [
...
'roles' => 'App\Http\Middleware\CheckRole',
];
Does anyone have any idea? Or a better/simpler way to do this? Thanks in advance!

This was my solution and i'm not saying it's the best practice nor it's better than yours.
i have created this middleware:
<?php
namespace App\Http\Middleware;
use Closure;
class MustHaveRole
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $role)
{
if(auth()->check() && auth()->user()->active && (auth()->user()->hasRole($role) || auth()->user()->hasRole('admin')) ){
return $next($request);
} else {
abort(403);
}
}
}
inside app/Http/Kernel.php added the last line:
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'role' => \App\Http\Middleware\MustHaveRole::class,
];
and inside user model created 2 methods:
// define connection with roles table
public function roles()
{
return $this->belongsToMany(Role::class);
}
// check if user has that $role
public function hasRole($role)
{
return $this->roles->contains('name', $role);
}
and i have a model called Role:
<?php
namespace App;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
use SoftDeletes;
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
}
and a seeder for that table:
<?php
use Illuminate\Database\Seeder;
class RolesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
// check if table roles is empty
if(DB::table('roles')->get()->count() == 0){
// multiple insertion
DB::table('roles')->insert([
['name' => 'admin'],
['name' => 'agency'],
['name' => 'endcustomer'],
]);
} else { echo "\e[31mTable is not empty, therefore NOT "; }
}
}
and now inside my Controller constructor i can call that middleware:
class ItemsController extends Controller
{
public function __construct() {
$this->middleware('auth');
$this->middleware('role:endcustomer');
}
...
This is all done without any additional packages...just plain laravel...if you have any more questions feel free to ask.

Well this is what I did and actually worked.
RoleTableSeeder, Role migration, Role model and the middleware register remain the same as the original post.
In CheckRole.php:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckRole{
public function handle($request, Closure $next){
if ($request->user()=== null) //for guests
return redirect()->route('product.index');
$actions = $request->route()->getAction();
$roles = isset($actions['roles']) ? $actions['roles'] : null;
if ($request->user()->hasAnyRole($roles) || !$roles)
return $next($request);
return redirect()->route('product.index'); //for unauthorized users
}
}
In User model: (the relations is exactly as the original post)
public function hasAnyRole($roles){
if (is_array($roles)){
foreach ($roles as $role) {
if ($this->hasRole($role)) {
return true;
}
}
} else if ($this->hasRole($roles)) {
return true;
}
return false;
}
public function hasRole($role){
if ($this->roles()->where('name', $role)->first()){
return true;
}
return false;
}
And an example of a route:
Route::get('...', [
...
'middleware' => 'roles',
'roles' => 'Admin' //or whatever you have in `RolesTableSeeder` in name column
]);

Related

Laravel 7 change name of login credentials

I have a fresh installation of Laravel 7 without composer require laravel / ui. My goal is to change the default login as username/email and password.
Controller AuthController.php :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Validator,Redirect,Response;
Use App\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Session;
class AuthController extends Controller
{
public function index()
{
return view('login');
}
public function registration()
{
return view('registration');
}
public function getAuthPassword()
{
return 'sms_code';
}
public function postLogin(Request $request)
{
request()->validate([
'id_message' => 'required',
'sms_code' => 'required',
]);
$credentials = $request->only('id_message', 'sms_code');
if (Auth::attempt($credentials)) {
return redirect()->intended('dashboard');
}
return Redirect::to("login");
}
public function postRegistration(Request $request)
{
request()->validate([
'id_message' => 'required',
'sms_code' => 'required|min:6',
'url_attribute' => 'required|min:6',
'mail_from' => 'required',
'mail_to' => 'required',
]);
$data = $request->all();
$check = $this->create($data);
return Redirect::to("dashboard");
}
public function dashboard()
{
if(Auth::check())
{
return view('dashboard');
}
return Redirect::to("login");
}
public function create(array $data)
{
return User::create([
'id_message' => $data['id_message'],
'sms_code' => Hash::make($data['sms_code']),
'url_attribute' => $data['url_attribute'],
'mail_from' => $data['mail_from'],
'mail_to' => $data['mail_to'],
]);
}
public function logout()
{
Session::flush();
Auth::logout();
return Redirect('login');
}
}
Metod App\Http\User.php
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'mail_from',
'mail_to',
'url_attribute',
'sms_code',
'id_message',
];
protected $hidden = [
'sms_code', 'remember_token',
];
protected $casts = [
];
}
When i try fill login form with datas from database -> username as id_message and password as sms_code
Return this error:
ErrorException
Undefined index: password
Illuminate\Foundation\Bootstrap\HandleExceptions::handleError
vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php:156
line 156 of EloquentUserProvider.php->
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
Did i missing something ?
you can use simple login by this way :
public function postLogin(Request $request)
{
request()->validate([
'id_message' => 'required',
'sms_code' => 'required',
]);
$credentials = $request->only('id_message', 'sms_code');
if ($user=User::where($credentials)->first()) {
auth()->login($user)
return redirect()->intended('dashboard');
}
return Redirect::to("login");
}

Laravel: LogicException in Model.php line 2673: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

I have one DB which has 3 tables: user, statuses and friends.
My status table has a relationship column "parent id" which is NULL but stores the user_id of a user that replies to a status. Below is my Status.php code:
namespace Pictogram\Models;
use Illuminate\Database\Eloquent\Model;
class Status extends Model
{
protected $table = 'statuses';
protected $fillable = [
'body'
];
public function user()
{
return $this->belongsTo('Pictogram\Models\User', 'user_id');
}
public function scopeNotReply($query)
{
return $query->whereNull('parent_id');
}
public function replies()
{
return $this->hasMany('Pictogram\Models\Status', 'parent_id');
}
}
And blow is from my route file: This controls replies to status
Route::post('/status', [
'uses' => '\Pictogram\Http\Controllers\StatusController#postStatus',
'as' => 'status.post',
'middleware' => ['auth'],
]);
Route::post('/status/{statusId}/reply', [
'uses' => '\Pictogram\Http\Controllers\StatusController#postReply',
'as' => 'status.reply',
'middleware' => ['auth'],
]);
And my status controller .php
class StatusController extends Controller
{
public function postStatus(Request $request)
{
$this->validate($request, [
'status' => 'required',
]);
Auth::user()->statuses()->create([
'body' => $request->input('status'),
]);
return redirect()
->route('home')
->with('info', 'Status updated.');
}
public function postReply(Request $request, $statusId)
{
$this->validate($request, [
"reply-{$statusId}" => 'required',
], [
'required' => 'The reply body is required.'
]);
$status = Status::notReply()->find($statusId);
if (!$status) {
return redirect()->route('home');
}
if (!Auth::user()->isFriendsWith($status->user) && Auth::user()->id !== $status->user->id)
{
return redirect()->route('home');
}
$reply = Status::create([
'body' => $request->input("reply-{$statusId}"),
])->user()->associate(Auth::user());
$status->replies()->save($reply);
return redirect()->back();
}
}
And lastly this is the line 2673 of models .php below:
protected function getRelationshipFromMethod($method)
{
$relations = $this->$method();
if (! $relations instanceof Relation) {
throw new LogicException('Relationship method must return an object of type '
.'Illuminate\Database\Eloquent\Relations\Relation');
}
return $this->relations[$method] = $relations->getResults();
}
I am using Laravel 5.2. Now my issue is that the reply gets save to the table because the empty parent_id then takes the user_id of the user who replied but then it brings up an error page that has these errors below.
Error1/2
Error2/2
Make sure your relationship name is proper in Status model.
check your replies() realtion in Status model.
it return the Status Relationship i should be the realtion of replies i.e Reply
public function replies()
{
return $this->hasMany('Pictogram\Models\Reply', 'parent_id');
}

ErrorException Argument 1 passed to (Laravel 5.2)

So i'm trying to "like" a status and when I do, I get this error in return
ErrorException in User.php line 107:
Argument 1 passed to SCM\User::hasLikedStatus() must be an instance of Status, instance of SCM\Status given, called in C:\xampp\htdocs\app\Http\Controllers\StatusController.php on line 66 and defined
When I remove "use Status;" from my User.php the function works and it updated my database with the like ID. Could this be because I linked my status's public function like "SCM\Status"?
Routes.php
<?php
/*
|--------------------------------------------------------------------------
| Routes File
|--------------------------------------------------------------------------
|
| Here is where you will register all of the routes in an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| This route group applies the "web" middleware group to every route
| it contains. The "web" middleware group is defined in your HTTP
| kernel and includes session state, CSRF protection, and more.
|
*/
Route::group(['middleware' => ['web']], function () {
Route::get('/login', function () {
return view('auth/login');
});
Route::get('/register', function () {
return view('auth/login');
});
/**
*User Profile
*/
Route::get('/user/{username}', [
'as' => 'profile.index', 'uses' => 'ProfileController#getProfile'
]);
Route::get('/profile/edit', [
'uses' => 'ProfileController#getEdit', 'as' => 'profile.edit', 'middleware' => ['auth'],
]);
Route::post('/profile/edit', [
'uses' => 'ProfileController#postEdit', 'middleware' => ['auth'],
]);
Route::get('/settings', [
'uses' => 'ProfileController#getEdit', 'as' => 'layouts.-settings', 'middleware' => ['auth'],
]);
Route::post('/settings', [
'uses' => 'ProfileController#postEdit', 'middleware' => ['auth'],
]);
/**
* Friends
*/
Route::get('/friends', [
'uses' => 'FriendController#getIndex', 'as' => 'friend.index', 'middleware' => ['auth'],
]);
Route::get('/friends/add/{username}', [
'uses' => 'FriendController#getAdd', 'as' => 'friend.add', 'middleware' => ['auth'],
]);
Route::get('/friends/accept/{username}', [
'uses' => 'FriendController#getAccept', 'as' => 'friend.accept', 'middleware' => ['auth'],
]);
/**
* Statuses
*/
Route::post('/status', [
'uses' => 'StatusController#postStatus', 'as' => 'status.post', 'middleware' => ['auth'],
]);
Route::post('/status/{statusId}/reply', [
'uses' => 'StatusController#postReply', 'as' => 'status.reply', 'middleware' => ['auth'],
]);
Route::get('/status/{statusId}/like', [
'uses' => 'StatusController#getLike', 'as' => 'status.like', 'middleware' => ['auth'],
]);
});
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::get('/', [
'as' => 'welcome', 'uses' => 'WelcomeController#index'
]);
Route::get('/profile', function () {
return view('layouts/-profile');
});
Route::get('profile/{username}', function () {
return view('layouts/-profile');
});
Route::get('/home', 'HomeController#index');
});
/**
* Search
*/
Route::get('/search', [
'as' => 'search.results', 'uses' => 'SearchController#getResults'
]);
User.php (model)
<?php
namespace SCM;
use Status;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'username', 'email', 'password',
];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
protected $primaryKey = 'id';
public function getAvatarUrl()
{
return "http://www.gravatar.com/avatar/{{ md5 ($this->email)}}?d=mm&s=40 ";
}
public function statuses()
{
return $this->hasMany('SCM\Status', 'user_id');
}
public function likes()
{
return $this->hasMany('SCM\Like', 'user_id');
}
public function friendsOfMine()
{
return $this->belongsToMany('SCM\User', 'friends', 'user_id', 'friend_id');
}
public function friendOf()
{
return $this->belongsToMany('SCM\User', 'friends', 'friend_id', 'user_id');
}
public function friends()
{
return $this->friendsOfMine()->wherePivot('accepted', true)->get()->
merge($this->friendOf()->wherePivot('accepted', true)->get());
}
public function friendRequests()
{
return $this->friendsOfMine()->wherePivot('accepted', false)->get();
}
public function friendRequestsPending()
{
return $this->friendOf()->wherePivot('accepted', false)->get();
}
public function hasFriendRequestPending(User $user)
{
return (bool) $this->friendRequestsPending()->where('id', $user->id)->count();
}
public function hasFriendRequestReceived(User $user)
{
return (bool) $this->friendRequests()->where('id', $user->id)->count();
}
public function addFriend(User $user)
{
$this->friendOf()->attach($user->id);
}
public function acceptFriendRequest(User $user)
{
$this->friendRequests()->where('id', $user->id)->first()->pivot->update([
'accepted' => true,
]);
}
public function isFriendsWith(User $user)
{
return (bool) $this->friends()->where('id', $user->id)->count();
}
public function hasLikedStatus(Status $status)
{
return (bool) $status->likes
->where('likeable_id', $status->id)
->where('likeable_type', get_class($status))
->where('user_id', $this->id)
->count();
}
}
Status.php (model)
<?php
namespace SCM;
use Illuminate\Database\Eloquent\Model;
class Status extends Model
{
protected $table = 'statuses';
protected $fillable = [
'body'
];
public function user()
{
return $this->belongsTo('SCM\User', 'user_id');
}
public function scopeNotReply($query)
{
return $query->whereNull('parent_id');
}
public function replies()
{
return $this->hasMany('SCM\Status', 'parent_id');
}
public function likes()
{
return $this->morphMany('SCM\Like', 'likeable');
}
}
Likes.php (model)
<?php
namespace SCM;
use Illuminate\Database\Eloquent\Model;
class Like extends Model
{
protected $table = 'likeable';
public function likeable()
{
return $this->morphTo();
}
public function user ()
{
return $this->belongsTo('SCM\User', 'user_id');
}
}
StatusController.php
<?php
namespace SCM\Http\Controllers;
use Flash;
use Auth;
use Illuminate\Http\Request;
use SCM\User;
use SCM\Status;
class StatusController extends Controller
{
public function postStatus(Request $request)
{
$this->validate($request, [
'status' => 'required|max:1000',
]);
Auth::user()->statuses()->create([
'body' => $request->input('status'),
]);
return redirect()->route('welcome')->with('info', 'Status posted.');
}
public function postReply(Request $request, $statusId)
{
$this->validate($request, [
"reply-{$statusId}" => 'required|max:1000',
], [
'required' => 'The reply body is required.'
]);
$status = Status::notReply()->find($statusId);
if (!$status) {
return redirect()->route('welcome');
}
if (!Auth::user()->isFriendsWith($status->user) && Auth::user()->id !==
$status->user->id) {
return redirect()->route('welcome');
}
$reply = Status::create([
'body' => $request->input("reply-{$statusId}"),
])->user()->associate(Auth::user());
$status->replies()->save($reply);
return redirect()->back();
}
public function getLike($statusId)
{
$status = Status::find($statusId);
if (!$status) {
return redirect()->route('welcome');
}
if (!Auth::user()->isFriendsWith($status->user)) {
return redirect()->route('welcome');
}
if (Auth::user()->hasLikedStatus($status)) {
return redirect()->back();
}
$like = $status->likes()->create([]);
Auth::user()->likes()->save($like);
return redirect()->back();
}
}
Remove the use statement for Status in your Users.php. When you're doing that, you're actually trying to use \Status. Your file is already in the namespace SCM, so you don't need any use statement to use classes in the same namespace.
So in your method definition you're saying you want an instance of \Status as your parameter, but are passing in a SCM\Status.

Yii2 AccessControl

I am new in Yii2 and I try to make AccessControl and success
but the problem is after I success for login and redirect to other page
my Identity _attributes always are null.So if I check with Yii::$app->user->isGuest the return value is always true
this is my LoginHandler.php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
/**
* Login form
*/
class LoginHandler extends Model
{
public $user_name;
public $user_password;
public $rememberMe = true;
private $_user;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['user_name', 'user_password'], 'required'],
[['user_name', 'user_password'], 'string', 'max' => 100],
['user_password','authenticate'],
];
}
public function authenticate($attribute, $params){
// return true;
}
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
} else {
return false;
}
}
protected function getUser()
{
if ($this->_user === null) {
$this->_user = User::findByUsername($this->user_name);
}
return $this->_user;
}
}
LoginController
<?php
namespace backend\controllers;
use Yii;
use app\models\user;
use app\models\LoginHandler;
class LoginController extends \yii\web\Controller
{
public function actionIndex()
{
return $this->render('index');
}
public function actionSignin(){
$user = User::findByUsername('admin');
$model = new LoginHandler();
if(Yii::$app->request->post()){
$data = Yii::$app->request->post();
$model->attributes = $data;
if ($model->login()) {
return $this->redirect(['/user/test']);
}else{
die('test');
}
}
return $this->render('login');
}
}
My User.php as model
namespace app\models;
use Yii;
/**
* This is the model class for table "user".
*
* #property integer $user_id
* #property string $user_name
* #property string $user_password
*/
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface{
public $id;
public $authKey;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'user';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['user_name', 'user_password'], 'required'],
[['user_name', 'user_password'], 'string', 'max' => 100]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'user_id' => 'User ID',
'user_name' => 'User Name',
'user_password' => 'User Password',
];
}
public static function findIdentity($id)
{
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->authKey;
}
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
public static function findByUsername($username){
return static::findOne(['user_name' => $username]);
}
}
and the last is my configuration main.php
<?php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php')
);
return [
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'bootstrap' => ['log'],
'modules' => [],
'components' => [
'user' => [
'identityClass' => 'backend\models\User',
'loginUrl' => ['login/signin'],
'enableAutoLogin' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
],
'params' => $params,
];
Thanks in advance.
You mentioned AccessControl in your question. In Yii2 AccessControl is the special behavior class to manage access rules inside controller:
http://www.yiiframework.com/doc-2.0/yii-filters-accesscontrol.html
and I don't see AccessControl in you code.
Anyway.
Most probably the problem is in your implementation of User class.
Looking at your code I can imagine that the table structure is: user_id (PK), user_name, user_password.
If so, then the method getId() returns variable
($this->id) which is never initialized. But this method is used by Yii to store current user in session. In your case it should return $this->user_id.
And if you wish to make remember me working, you should implement correctly getAuthKey and validateAuthKey too.
Here is details:
http://www.yiiframework.com/doc-2.0/guide-security-authentication.html
If this not helps, then show your table structure and code of view which pass authentication data to LoginController
It looks you should check for
Yii::$app->user->identity

Laravel call to member function create() on a non-object

I'm trying to seed a database using some model factories but I'm getting error call to member function create() on a non-object
Below are my model factories:
$factory->define(App\Organisation::class, function ($faker) {
return [
'name' => $faker->company,
];
});
$factory->define(App\Department::class, function ($faker) {
return [
'name' => $faker->catchPhrase,
'organisation_id' => factory(App\Organisation::class)->make()->id,
];
});
$factory->define(App\User::class, function ($faker) {
return [
'email' => $faker->email,
'password' => str_random(10),
'organisation_id' => factory(App\Organisation::class)->make()->id,
'remember_token' => str_random(10),
];
});
In my seeder I'm using the following to create 2 organizations and a associate a user and a department to each organization and then to make a user the manager of that department:
factory(App\Organisation::class, 2)
->create()
->each(function ($o)
{
$user = $o->users()->save(factory(App\User::class)->make());
$department = $o->departments()->save(factory(App\Department::class)->make());
$department->managedDepartment()->create([
'organisation_id' => $o->id,
'manager_id' => $user->id,
]);
});
However I'm getting fatalerrorexception call to member function create() on a non-object
I thought $department is an object?
My department model is as follows:
class Department extends Model
{
protected $fillable = ['name','organisation_id'];
public function organisation()
{
return $this->belongsTo('App\Organisation');
}
/* a department is managed by a user */
public function managedDepartment()
{
$this->hasOne('App\ManagedDepartment');
}
}
And my managedDepartment model is as follows:
class ManagedDepartment extends Model
{
protected $table = 'managed_departments';
protected $fillable = ['organisation_id', 'department_id', 'manager_id',];
public function department()
{
$this->belongsTo('App\Department');
}
public function manager()
{
return $this->belongsTo('App\User');
}
}
Can anyone help?
Try to return your relation
public function department()
{
return $this->belongsTo('App\Department');
}
And here
/* a department is managed by a user */
public function managedDepartment()
{
return $this->hasOne('App\ManagedDepartment');
}
I think it will resolve your problem.
Firstly, do not make foreign keys fillable!
Secondly, where is your organisation function in ManagedDepartment? You should create one, otherwise the following will not work, because association is not possible.
Thirdly, I think you should change make() to create() in the following
$factory->define(App\Organisation::class, function ($faker) {
return [
'name' => $faker->company,
];
});
$factory->define(App\Department::class, function ($faker) {
return [
'name' => $faker->catchPhrase,
'organisation_id' => factory(App\Organisation::class)->create()->id,
];
});
$factory->define(App\User::class, function ($faker) {
return [
'email' => $faker->email,
'password' => str_random(10),
'organisation_id' => factory(App\Organisation::class)->create()->id,
'remember_token' => str_random(10),
];
});
Furthermore:
factory(App\Organisation::class, 2)
->create()
->each(function ($o)
{
$user = factory(App\User::class)->create();
$o->users()->attach($user->id);
$department = factory(App\Department::class)->create();
$o->departments()->attach($department);
$managedDep = new ManagedDepartment();
$managedDep->associate($o);
$managedDep->associate($user);
$managedDep->associate($department);
$managedDep->save();
});

Categories