When i try to log in , it redirects me to www.example.com/admin/{username} but it shows a NotFoundHttpException error. Thank you in advance!
The routes.php file
Route::get('/admin', 'SessionsController#create');
Route::get('/logout', 'SessionsController#destroy');
Route::get('profile', function()
{
return "welcome! Your username is" . Auth::admin()->username;
});
Route::resource('sessions', 'SessionsController', ['only' => ['index', 'create', 'destroy', 'store']]);
here is the controller SessionsController.php
<?php
class SessionsController extends \BaseController {
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
return View::make('admins');
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
$rules = array('username' => 'required', 'password' => 'required');
$validator = Validator::make(Input::all(), $rules);
if($validator -> passes()){
$credentials = array(
'username' => Input::get('username'),
'password' => Input::get('password')
);
if(Auth::admin($credentials,true)){
$username = Input::get('username');
return Redirect::to("admin/{$username}");
} else {
return Redirect::to('/admin')->withErrors('Username or password invalid');
}
} else {
return Redirect::to('/admin')->withErrors($validator->messages());
}
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
Auth::logout();
return Redirect::home();
}
}
the admins.blade.php
{{Form::open(array('route' => 'sessions.store'))}}
<h1>ADMIN LOGIN </h1>
{{Form::label('username', 'Username')}}
{{Form::text('username')}}
{{Form::label('password', 'Password')}}
{{Form::password('password')}}
{{Form::submit('Login')}}
{{$errors->first()}}
{{Form::close()}}
and here is the model Admin.php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class Admin extends Eloquent implements UserInterface, RemindableInterface {
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'admins';
}
I also installed ollieread multiauth
and here is auth.php file
return array(
'multi' => array(
'admin' => array(
'driver' => 'database',
'model' => 'Admin',
'table' => 'admins'
),
'user' => array(
'driver' => 'eloquent',
'model' => 'User',
'table' => 'users'
)
),
'reminder' => array(
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
),
);
You haven't declared any routes pointing to /admin/{username} . That's the reason it can't be found by laravel.
Here is an example:
In your route files
Route::get('/admin/{username}', 'SessionsController#getByUserName');
I strongly advice you to use named routes. They are a lot easier to manage, even if your application gets bigger.
For example
In your route files
Route::get('/admin/{username}',array('as' => 'admin.username', 'uses'=>'SessionsController#getByUserName'));
Then you can call the url that points to the certain controller either using
URL::route('admin.username')(inside views) or
Redirect::route('admin.username') (inside controller)
You can also pass variables using an array. like this
URL::route('admin.username',array($user->username))
More about routing here
Related
I am trying to create multiple authentication laravel 5.8. i have two tabels one is users and admins. i have configured the guards for admin. the admin login works fine if i use App\User::class but when i try to login through the App\Admin::class, the admin login doesn't work even if I login with correct credentials. Please help me to solve this problem.
this is my admin model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use Notifiable;
protected $guard = 'admin';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'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',
];
}
This is my guard setting
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'admin-api' => [
'driver' => 'token',
'provider' => 'admins',
'hash' => false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
This is my admin login controller
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
use Route;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
// use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/admin/cpanel';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest:admin')->except('logout');
}
/**
* Show the admin login form.
*
* #return \Illuminate\Http\Response
*/
public function showLoginForm()
{
return view('admin.login');
}
/**
* Get the guard to be used during authentication.
*
* #return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('admin');
}
public function login(Request $request)
{
// validate the inputs
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:8'
]);
/* Check the guard is admin,
and all credentials are matching with database records
*/
if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember)) {
// Credentials are matching
// redirect the admin to cpanel
return redirect()->intended(route('admin.cpanel'));
}
// Credntials are not matching
// redirect the admin to login page
return redirect()->back()->withInput($request->only('email', 'remember'));
}
// function for logout
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->invalidate();
return $this->loggedOut($request) ?: redirect('/admin/login');
}
}
This is exception handler
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Support\Arr;
use Auth;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* #var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* #var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* #param \Exception $exception
* #return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
/**
* Convert an authentication exception into a response.
*
* #param \Illuminate\Http\Request $request
* #param \Illuminate\Auth\AuthenticationException $exception
* #return \Symfony\Component\HttpFoundation\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
$guard = Arr::get($exception->guards(),0);
switch ($guard) {
case 'admin':
$redirect = route('admin.login');
break;
default:
$redirect = route('login');
break;
}
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest($redirect);
}
}
I'm using the default Laravel 5.1 user registration. I have two tables: users and shops. When user registers, the app should insert a user in the table users, get the id and use it to register a shop. I've been reading the default AuthController.php but i didn't find anything. Here is the AuthController if it helps.
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Create a new authentication controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'getLogout']);
}
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
//'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
return User::create([
//'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
/**
* Get the path to the login route.
*
* #return string
*/
public function loginPath()
{
return route('login');
}
/**
* Get the post register / login redirect path.
*
* #return string
*/
public function redirectPath()
{
return route('home');
}
}
Solved, but now I have a Integrity constraint violation. Is this code correct?
protected function create(array $data)
{
$user = new User([
'email' => $data['email'],
'password' => bcrypt($data['password'])
]);
$user->role = 'shop_owner';
$user->remember_token = str_random(10);
$user->save();
$userId = $user->id;
Shop::create([
'name' => $data['s_name'],
'address' => $data['s_address'],
'CP' => $data['s_pcode'],
'Telephone' => $data['s_tlf'],
'contact_name' => $data['cp_name'],
'contact_num' => $data['cp_tlf'],
'id_user' => $userId
]);
return $user;
}
There you go:
protected function create(array $data)
{
$user = User::create([
//'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
$userId = $user->id;
Shop::create([... use $userId here ...]);
return $user;
}
This goes to your controller:
public function store(Request $request) {
$user = User::create(Input::all());
$user->save();
$shop = Shop::create([..enter shop attributes or leave blank..]);
$user->shop()->save($shop);
}
You need to place the following code at the top of the Auth Controller
use App\Shop;
I have to implement login functionality in Laravel 5.2. I have successfully done so using the official Laravel documentation except that I do not know how to authenticate the user using different database table column names, namely st_usernameand st_password.
I have searched the Internet for clues but to no avail.
I don't know which class I need to use (like, use Illuminate.......) for Auth. If any one knows the answer, please let me know.
Here is my code:
Login View
#extends('layouts.app')
#section('content')
<div class="contact-bg2">
<div class="container">
<div class="booking">
<h3>Login</h3>
<div class="col-md-4 booking-form" style="margin: 0 33%;">
<form method="post" action="{{ url('/login') }}">
{!! csrf_field() !!}
<h5>USERNAME</h5>
<input type="text" name="username" value="abcuser">
<h5>PASSWORD</h5>
<input type="password" name="password" value="abcpass">
<input type="submit" value="Login">
<input type="reset" value="Reset">
</form>
</div>
</div>
</div>
</div>
<div></div>
#endsection
AuthController
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
$this->username = 'st_username';
$this->password = 'st_password';
}
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
Route File
Route::get('/', function () {
return view('index');
});
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::get('/home', 'HomeController#index');
});
config/auth.php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
'passwords' => [
'users' => [
'provider' => 'users',
'email' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
],
];
I searched a lot how to customize Laravel 5.2 authorisation form and this is what is working for me 100%.
Here is from bottom to top solution.
This solution is originally from here: https://laracasts.com/discuss/channels/laravel/replacing-the-laravel-authentication-with-a-custom-authentication
but i had to make couple changes to make it work.
My web app is for the DJs so my custom column names are with 'dj_', for example name is dj_name
config/auth.php
// change this
'driver' => 'eloquent',
// to this
'driver' => 'custom',
in config/app.php add your custom provider to the list
...
'providers' => [
...
// add this on bottom of other providers
App\Providers\CustomAuthProvider::class,
...
],
Create CustomAuthProvider.php inside folder app\Providers
namespace App\Providers;
use Illuminate\Support\Facades\Auth;
use App\Providers\CustomUserProvider;
use Illuminate\Support\ServiceProvider;
class CustomAuthProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
Auth::provider('custom', function($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new CustomUserProvider($app['custom.connection']);
});
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
Create CustomUserProvider.php also inside folder app\Providers
<?php
namespace App\Providers;
use App\User; use Carbon\Carbon;
use Illuminate\Auth\GenericUser;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
class CustomUserProvider implements UserProvider {
/**
* Retrieve a user by their unique identifier.
*
* #param mixed $identifier
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
// TODO: Implement retrieveById() method.
$qry = User::where('dj_id','=',$identifier);
if($qry->count() >0)
{
$user = $qry->select('dj_id', 'dj_name', 'first_name', 'last_name', 'email', 'password')->first();
$attributes = array(
'id' => $user->dj_id,
'dj_name' => $user->dj_name,
'password' => $user->password,
'email' => $user->email,
'name' => $user->first_name . ' ' . $user->last_name,
);
return $user;
}
return null;
}
/**
* Retrieve a user by by their unique identifier and "remember me" token.
*
* #param mixed $identifier
* #param string $token
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
{
// TODO: Implement retrieveByToken() method.
$qry = User::where('dj_id','=',$identifier)->where('remember_token','=',$token);
if($qry->count() >0)
{
$user = $qry->select('dj_id', 'dj_name', 'first_name', 'last_name', 'email', 'password')->first();
$attributes = array(
'id' => $user->dj_id,
'dj_name' => $user->dj_name,
'password' => $user->password,
'email' => $user->email,
'name' => $user->first_name . ' ' . $user->last_name,
);
return $user;
}
return null;
}
/**
* Update the "remember me" token for the given user in storage.
*
* #param \Illuminate\Contracts\Auth\Authenticatable $user
* #param string $token
* #return void
*/
public function updateRememberToken(Authenticatable $user, $token)
{
// TODO: Implement updateRememberToken() method.
$user->setRememberToken($token);
$user->save();
}
/**
* Retrieve a user by the given credentials.
*
* #param array $credentials
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
// TODO: Implement retrieveByCredentials() method.
$qry = User::where('email','=',$credentials['email']);
if($qry->count() > 0)
{
$user = $qry->select('dj_id','dj_name','email','password')->first();
return $user;
}
return null;
}
/**
* Validate a user against the given credentials.
*
* #param \Illuminate\Contracts\Auth\Authenticatable $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials)
{
// TODO: Implement validateCredentials() method.
// we'll assume if a user was retrieved, it's good
// DIFFERENT THAN ORIGINAL ANSWER
if($user->email == $credentials['email'] && Hash::check($credentials['password'], $user->getAuthPassword()))//$user->getAuthPassword() == md5($credentials['password'].\Config::get('constants.SALT')))
{
//$user->last_login_time = Carbon::now();
$user->save();
return true;
}
return false;
}
}
in App/Http/Controllers/Auth/AuthController.php change all
'name' to 'dj_name' and add your custom fields if you have them...you can also change 'email' to your email column name
In Illuminate\Foundation\Auth\User.php add
protected $table = 'djs';
protected $primaryKey = 'dj_id';
In App/User.php change 'name' to 'dj_name' and add your custom fields.
For changing 'password' column to your custom column name add
public function getAuthPassword(){
return $this->custom_password_column_name;
}
Now backend is all done, so you only have to change layouts login.blade.php, register.blade.php, app.blade.php...here you only have to change 'name' to 'dj_name', email, or your custom fields...
!!! password field NEEDS to stay named password !!!
Also, to make unique email validation change AuthController.php
'custom_email_field' => 'required|email|max:255|unique:users',
to
'custom_email_field' => 'required|email|max:255|unique:custom_table_name',
Also, if you want to make custom created_at an updated_at fields change global variables in Illuminate\Database\Eloquent\Model.php
const CREATED_AT = 'dj_created_at';
const UPDATED_AT = 'dj_updated_at';
A custom Auth::attempt() doesn't work for me by changing the model in auth.php like this:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Person::class,
],
],
If I try to authenticate a Person via custom column names in Auth::attempt:
if (Auth::attempt(['persUsername' => $request->user, 'persPassword' => $request->pass])) {
return redirect()->intended('/');
}
I get the same error:
ErrorException in EloquentUserProvider.php line 112: Undefined index:
password
But I can authenticate a Person like this:
$person = Person
::where('persUsername', $request->user)
->where('persPassword', $request->pass)
->first();
if (! is_null($person)) {
if ($person->persUsername === $request->user && $person->persPassword === $request->pass) {
Auth::login($person, false);
return redirect()->intended('/');
}
}
But that's not the way it should be, I guess.
In the mentioned File (EloquentUserProvider.php), I see 'password' is hardcoded.
public function retrieveByCredentials(array $credentials)
{
$query = $this->createModel()->newQuery();
foreach ($credentials as $key => $value) {
if (! Str::contains($key, 'password')) {
$query->where($key, $value);
}
}
return $query->first();
}
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
So there is actually no way to use a custom column name for passwords the easy way?
This is easy simply use the desired column names in Auth::attempt()/method like so:
if (Auth::attempt(['st_username' =>$username,'st_password' => $password])) {
// Authentication passed...
return redirect()>intended('dashboard');
}
Updated:
If you also wish to change default authentication table which is users by default or change the model name or path App\User by default, you can find these settings in config\auth.php
/*
|--------------------------------------------------------------------------
| Authentication Table
|--------------------------------------------------------------------------
|
| When using the "Database" authentication driver, we need to know which
| table should be used to retrieve your users. We have chosen a basic
| default value but you may easily change it to any table you like.
|
*/
//'table' => 'users',
'table' => 'new_tables_for_authentication',
/*
|--------------------------------------------------------------------------
| Authentication Model
|--------------------------------------------------------------------------
|
| When using the "Eloquent" authentication driver, we need to know which
| Eloquent model should be used to retrieve your users. Of course, it
| is often just the "User" model but you may use whatever you like.
|
*/
//'model' => App\User::class,
'model' => App\Models\User::class,
I edited the store method , now the problem is that when i try to login it redirect to www.example.com/admin but it shows a NotFoundHttpException.
The routes.php file
Route::get('/admin', 'SessionsController#create');
Route::get('/logout', 'SessionsController#destroy');
Route::get('profile', function()
{
return "welcome! Your username is" . Auth::admin()->username;
});
Route::resource('sessions', 'SessionsController', ['only' => ['index', 'create', 'destroy', 'store']]);
here is the controller SessionsController.php
<?php
class SessionsController extends \BaseController {
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
return View::make('admins');
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
$rules = array('username' => 'required', 'password' => 'required');
$validator = Validator::make(Input::all(), $rules);
if($validator -> passes()){
$credentials = array(
'username' => Input::get('username'),
'password' => Input::get('password')
);
if(Auth::admin($credentials,true)){
$username = Input::get('username');
return Redirect::to("admin/{$username}");
} else {
return Redirect::to('/admin')->withErrors('Username or password invalid');
}
} else {
return Redirect::to('/admin')->withErrors($validator->messages());
}
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
Auth::logout();
return Redirect::home();
}
}
the admins.blade.php
{{Form::open(array('route' => 'sessions.store'))}}
<h1>ADMIN LOGIN </h1>
{{Form::label('username', 'Username')}}
{{Form::text('username')}}
{{Form::label('password', 'Password')}}
{{Form::password('password')}}
{{Form::submit('Login')}}
{{$errors->first()}}
{{Form::close()}}
and here is the model Admin.php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class Admin extends Eloquent implements UserInterface, RemindableInterface {
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'admins';
}
I also installed ollieread multiauth
and here is auth.php file
return array(
'multi' => array(
'admin' => array(
'driver' => 'database',
'model' => 'Admin',
'table' => 'admins'
),
'user' => array(
'driver' => 'eloquent',
'model' => 'User',
'table' => 'users'
)
),
'reminder' => array(
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
),
);
In your admin template you set the goto url as sessions.store which hits SessionsController::store in that method you have a debug function dd() which is throwing that string. It get's called because auth::attempt() returns false as by your own code:
if($attempt) return Redirect::intended('/');
So the behavior is exactly doing what it should. If you are succesfully logged in, you are redirected otherwise it will dump through dd()
What you have to do is filter. You have to add custom error message on app/filter.php
Like the following
Route::filter('auth', function()
{
if (Auth::guest())
{
if (Request::ajax())
{
return Response::make('Unauthorized', 401);
}
else
{
return Redirect::guest('/')->with('message', 'Please login first');
}
}
});
Above code, I redirect to / and gave Please login first message.
My app is built on the 'advanced' Yii2 application template and my User class is built on the Yii2-user module.
The app seems to use the custom User model class dektrium\user\Module to handle registration as the custom fields I've added are being stored in the database on signup, using the register() method of the vendor User class to do the database persistence operations.
When I access the account settings page, using the action /user/settings/account the model class being used to display the User data is actually common/model/User, as shown by using get_class() and I can't use any of the new methods defined in the custom model class.
Main config file.
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=DBNAME',
'username' => 'DBUSER',
'password' => 'DBPASS',
'charset' => 'utf8',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '#common/mail',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => false,
],
],
'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
],
'rbac' => [
'class' => 'dektrium\rbac\Module'
],
],
];
And the SettingsForm class which has a User as a property.
<?php
/*
* This file is part of the Dektrium project.
*
* (c) Dektrium project <http://github.com/dektrium/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace dektrium\user\models;
use dektrium\user\helpers\Password;
use dektrium\user\Mailer;
use dektrium\user\Module;
use yii\base\Model;
use yii\base\NotSupportedException;
/**
* SettingsForm gets user's username, email and password and changes them.
*
* #property User $user
*
* #author Dmitry Erofeev <dmeroff#gmail.com>
*/
class SettingsForm extends Model
{
/** #var string */
public $email;
/** #var string */
// public $username;
/** #var string */
public $new_password;
/** #var string */
public $current_password;
/** #var Module */
protected $module;
/** #var Mailer */
protected $mailer;
/** #var User */
private $_user;
/** #return User */
public function getUser()
{
if ($this->_user == null) {
$this->_user = \Yii::$app->user->identity;
}
return $this->_user;
}
/** #inheritdoc */
public function __construct(Mailer $mailer, $config = [])
{
$this->mailer = $mailer;
$this->module = \Yii::$app->getModule('user');
$this->setAttributes([
//'username' => $this->user->username,
'email' => $this->user->unconfirmed_email ?: $this->user->email
], false);
parent::__construct($config);
}
/** #inheritdoc */
public function rules()
{
return [
// 'usernameRequired' => ['username', 'required'],
// 'usernameTrim' => ['username', 'filter', 'filter' => 'trim'],
// 'usernameLenth' => ['username', 'string', 'min' => 3, 'max' => 20],
// 'usernamePattern' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.#]+$/'],
'emailRequired' => ['email', 'required'],
'emailTrim' => ['email', 'filter', 'filter' => 'trim'],
'emailPattern' => ['email', 'email'],
// 'emailUsernameUnique' => [['email', 'username'], 'unique', 'when' => function ($model, $attribute) {
// return $this->user->$attribute != $model->$attribute;
// }, 'targetClass' => $this->module->modelMap['User']],
'newPasswordLength' => ['new_password', 'string', 'min' => 6],
'currentPasswordRequired' => ['current_password', 'required'],
'currentPasswordValidate' => ['current_password', function ($attr) {
if (!Password::validate($this->$attr, $this->user->password_hash)) {
$this->addError($attr, \Yii::t('user', 'Current password is not valid'));
}
}]
];
}
/** #inheritdoc */
public function attributeLabels()
{
return [
'email' => \Yii::t('user', 'Email'),
'username' => \Yii::t('user', 'Username'),
'new_password' => \Yii::t('user', 'New password'),
'current_password' => \Yii::t('user', 'Current password')
];
}
/** #inheritdoc */
public function formName()
{
return 'settings-form';
}
/**
* Saves new account settings.
*
* #return bool
*/
public function save()
{
if ($this->validate()) {
// $this->user->scenario = 'settings';
// $this->user->username = $this->username;
$this->user->password = $this->new_password;
if ($this->email == $this->user->email && $this->user->unconfirmed_email != null) {
$this->user->unconfirmed_email = null;
} else if ($this->email != $this->user->email) {
switch ($this->module->emailChangeStrategy) {
case Module::STRATEGY_INSECURE:
$this->insecureEmailChange(); break;
case Module::STRATEGY_DEFAULT:
$this->defaultEmailChange(); break;
case Module::STRATEGY_SECURE:
$this->secureEmailChange(); break;
default:
throw new \OutOfBoundsException('Invalid email changing strategy');
}
}
return $this->user->save();
}
return false;
}
/**
* Changes user's email address to given without any confirmation.
*/
protected function insecureEmailChange()
{
$this->user->email = $this->email;
\Yii::$app->session->setFlash('success', \Yii::t('user', 'Your email address has been changed'));
}
/**
* Sends a confirmation message to user's email address with link to confirm changing of email.
*/
protected function defaultEmailChange()
{
$this->user->unconfirmed_email = $this->email;
/** #var Token $token */
$token = \Yii::createObject([
'class' => Token::className(),
'user_id' => $this->user->id,
'type' => Token::TYPE_CONFIRM_NEW_EMAIL
]);
$token->save(false);
$this->mailer->sendReconfirmationMessage($this->user, $token);
\Yii::$app->session->setFlash('info', \Yii::t('user', 'A confirmation message has been sent to your new email address'));
}
/**
* Sends a confirmation message to both old and new email addresses with link to confirm changing of email.
* #throws \yii\base\InvalidConfigException
*/
protected function secureEmailChange()
{
$this->defaultEmailChange();
/** #var Token $token */
$token = \Yii::createObject([
'class' => Token::className(),
'user_id' => $this->user->id,
'type' => Token::TYPE_CONFIRM_OLD_EMAIL
]);
$token->save(false);
$this->mailer->sendReconfirmationMessage($this->user, $token);
// unset flags if they exist
$this->user->flags &= ~User::NEW_EMAIL_CONFIRMED;
$this->user->flags &= ~User::OLD_EMAIL_CONFIRMED;
$this->user->save(false);
\Yii::$app->session->setFlash('info', \Yii::t('user', 'We have sent confirmation links to both old and new email addresses. You must click both links to complete your request'));
}
}
The module property is showing the type to be the custom User but the _user is from the /common/models/User.
Have I missed something to say that any User objects should be of the custom class, so I can access the new properties/methods?
At the moment I have changed the common/models/User class to simply extend the User in dektrium/user/models/User with no actual code in the common User class.
class User extends \dektrium\user\models\User {}
It has solved my problem for now, but it feels like a really bad solution. Any further input would be gratefully received...
Edit:
I'd forgotten about this Q&A...
in my common/config/main.php where the user module is declared, in the modelMap I'm able to specify to use my own custom User model, something like the following.
'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
'modelMap' => [
'User' => 'common\models\User',
],
Where there is an entry for each model used by the dektrium user module.