I created a table fields with costume fields names fld_ID, fld_Username, fld_Password but i can't use this fields type on simple laravel Authentication, so i defined my ID field name on user model except laravel-4:
protected $primaryKey = 'fld_ID';
and for Password name:
public function getAuthPassword() {
return $this->attributes['fld_Password'];
}
and finally for my username on Post Action Defined a username type for attempt:
$input = Input::all();
$user['fld_Username'] = $input['fld_Username'];
$user['fld_Password'] = $input['fld_Password'];
if (Auth::attempt($user)){
....Some Code Here... :)
}
but still i have problem with and Auth::attempt return false, my last Query log is this:
Array ( [query] => select * from `tbl_users` where `fld_Username` = ? and `fld_Password` = ? limit 1 [bindings] => Array ( [0] => username [1] => password )
and password is Hashed before save.
Because you changed the password field's name, you need to make a custom user provider and register it in config file.
As you can see in vendor\laravel\framework\src\Illuminate\Auth\EloquentUserProvider.php line 138 the password field is hard coded and there is no other way to change it.
So make a class somewhere is app folder like this:
class CustomUserProvider extends EloquentUserProvider
{
public function retrieveByCredentials(array $credentials)
{
if (isset($credentials['fld_Password'])) {
unset($credentials['fld_Password']);
}
return parent::retrieveByCredentials($credentials);
}
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['fld_Password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
}
Now you need to introduce this user provider to laravel. just add this to app\Providers\AuthServiceProvider.php:
class AuthServiceProvider extends ServiceProvider
//...
public function boot()
{
\Auth::provider('CustomUserProvider', function ($app, array $config) {
return new CustomUserProvider($app['hash'], $config['model']);
});
}
//...
}
Just one more step. in config/auth.php edit the providers section like this:
'providers' => [
'users' => [
'driver' => 'CustomUserProvider', // make sure you change this
'model' => CustomUserModel::class, // here is your custom model
],
],
I hope this will help you.
The array you pass to attempt is simply an array; it has nothing to do with your database table. you don't have to use 'fld_Username', and 'fld_Password'. Instead just use $user['username'] and $user['password'].
Laravel is looking for the word "password" as the key in the array you pass to see which is the password.
(Proof)
Simply override the username function from LoginController and return your username field, just like this:
class LoginController extends Controller
{
.
.
.
public function username()
{
return "fld_Username";
}
}
No need to change anything else except the getAuthPassword method that you just did correctly.
I hope this will help you.
Related
I am creating an API using Laravel.
I created a table called transaction. I also created a resource called transactionresource.
I want to change the id column to be the key column in the API, and I don't want id to show in the API; instead key should show.
My code
class TransactionResource extends JsonResource
{
public function toArray($request)
{
$array = parent::toArray($request);
// set the new key with data
$array['key'] = $array['id'];
// unset the old key
unset($array['id']);
return $array;
}
}
I am getting this error
{"success":false,"message":"Undefined array key \"id\""}
you can return array of custom fields like this
public function toArray($request){
return [
'key' => $this->id,
...
];}
see documentation
Can I set a default value to a not-existing field in a FormRequest in Laravel?
For example, if a field called "timezone" does not exist in the incoming request, it get set to "America/Toronto".
Well I wrote a trait for this, which checks a function called 'defaults' exist in the form request it will replace the default values
trait RequestDefaultValuesTrait {
protected function prepareForValidation(){
// add default values
if( method_exists( $this, 'defaults' ) ) {
foreach ($this->defaults() as $key => $defaultValue) {
if (!$this->has($key)) $this->merge([$key => $defaultValue]);
}
}
}
}
the thing that you need to do is adding this trait to FormRequest class and then add a function like this:
protected function defaults()
{
return [
'country' => 'US',
'language' => 'en',
'timezone' => 'America/Toronto',
];
}
Being honest I don't link this method, but It works.
Try this
if(!$request->has('timezone') {
$request->merge(['timezone' =>'America/Toronto']);
}
I'm not so sure if you need to do it in this way, but if you want to:
class CreateUpdateDataFormRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
protected function getValidatorInstance()
{
$data = $this->all();
if(!isset($data['timezone'])) {
$data['timezone'] = 'America/Toronto';
$this->getInputSource()->replace($data);
}
// modify data before sending to validator
return parent::getValidatorInstance();
}
in request class add
public function prepareForValidation()
{
$this->mergeIfMissing([
'timezone' => 'America/Toronto'
]);
}
I'm migrating from Laravel 4 to 5.7 and having trouble with my custom auth provider. I've followed various walkthroughs (e.g. 1, 2, 3) as well as quite a bit of googling.
I've attempted to get this working by the following:
Set the guards and providers and link to my target model.
'defaults' => [
'guard' => 'custom_auth_guard',
'passwords' => 'users',
],
'guards' => [
'custom_auth_guard' => [
'driver' => 'session',
'provider' => 'custom_auth_provider',
],
],
'providers' => [
'custom_auth_provider' => [
'driver' => 'custom',
'model' => App\UserAccount::class,
],
],
Register the driver defined in the above provider. I'm piggybacking off AuthServiceProvider for ease
...
public function boot()
{
$this->registerPolicies();
\Auth::provider('custom',function() {
return new App\Auth\CustomUserProvider;
});
}
...
Created my custom provider which has my retrieveByCredentials, etc. I've replaced the logic with some die() to validate if it is making it here. In Laravel 4, it used to go to validateCredentials().
class CustomUserProvider implements UserProviderInterface {
public function __construct()
{
die('__construct');
}
public function retrieveByID($identifier)
{
die('retrieveByID');
}
public function retrieveByCredentials(array $credentials)
{
die('retrieveByCredentials');
}
public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
{
die('validateCredentials');
}
For reference, App/UserAccount looks like so
class UserAccount extends Authenticatable
{
use Notifiable;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'public.user_account';
// no updated_at, created_at
public $timestamps = false;
private $_roles = [];
private $_permissions = [];
}
Finally, I am calling it via my controller.
if(\Auth::attempt($credentials){
return \Redirect::intended('/dashboard');
}
I have also tried to call the guard direct
if(\Auth::guard('custom_auth_guard')->attempt($credentials){
return \Redirect::intended('/dashboard');
}
This results in the following error: "Auth guard [custom_auth_guard] is not defined."
I've tried a few other commands to make sure there is no cache issue:
composer update
php artisan cache:clear
The results: when I call Auth::attempt($credentials) Laravel is trying to run a query on the users table. the expected result is that it would hit one of the die()'s in CustomUserProvider... or at lease try and query public.user_account as defined in the model.
I've been messing with this for some time and I must be missing something simple... hopefully someone with a bit more experience in Laravel 5 can see what I am doing wrong.
Thanks in advance!!
Managed to work it out. Couple little problems but the main one was that I was trying to piggyback on AuthServiceProvider as opposed to my own provider. Below is what I did to get a custom auth provider working in Laravel 5.7
Set the provider in config.auth.php.
'providers' => [
'user' => [
'driver' => 'eloquent',
'model' => \UserAccount::class,
],
],
Create a new provider in app/providers/ . This links the listed provider above with the correct User Provider Code.
namespace App\Providers;
use Auth;
use App\Auth\CustomUserProvider;
use Illuminate\Support\ServiceProvider;
class CustomAuthProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
Auth::provider('eloquent',function()
{
return new CustomUserProvider(new \UserAccount());
});
}
}
Created my custom provider in app/auth/. This is the logic for validating the user and replaces the laravel functions for auth. I had an issue here where it was validating but not populating the user object. I originally had a test to see if the object was null and if it was, populate... however it was always populated with an empty object. removing the test allowed me to call Auth::user() functions.
namespace App\Auth;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Auth\EloquentUserProvider;
class CustomUserProvider implements EloquentUserProvider{
public function __construct()
{
$this->user = $user;
}
public function retrieveByID($identifier)
{
$this->user = \UserAccount::find($identifier);
return $this->user;
}
public function retrieveByCredentials(array $credentials)
{
// find user by username
$user = \UserAccount::where('name', $credentials['username'])->first();
// validate
return $user;
}
public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
{
//logic to validate user
}
Updated App/Models/UserAccount looks like so
use Illuminate\Foundation\Auth\User as Authenticatable;
class UserAccount extends Authenticatable
{
protected $table = 'public.user_account';
// no updated_at, created_at
public $timestamps = false;
private $_roles = [];
private $_permissions = [];
}
That's it. I can now validate via the below call
if(\Auth::attempt($credentials){
return \Redirect::intended('/dashboard');
}
there is a UpdateUserRequest form request that verify fields value against its rules defined in rules mathod .it has rules() and authorize() methods by default. i want prevent verifying and updating empty fields (such as password) .
using sometimes in rules is not useful as html inputs will be present in POST request even if they are empty.
array:6 [▼
"_method" => "PATCH"
"_token" => "Cz79rRez2f6MG0tTU17nVwXD0X1lNGH1hA7OORjm"
"name" => "john"
"email" => "mymail#gmail.com"
"password" => ""
"password_confirmation" => ""
]
so i should remove empty keys of POST request before using sometimes in rules.
the question is : Where is the best place to purge Request array?
is there any laravel build in method to manage such situations?
P.S :Solution:
#Bogdon solution is still valid and works, but there is another simple ,nice ,neat solution adopted from here:
just override all() method inside form request
class RegistrationRequest extends Request
{
...
public function all()
{
$attributes = parent::all();
if(isset($attributes['password']) && empty($attributes['password']))
{
unset($attributes['password']);
}
$this->replace($attributes);
return parent::all();
}
...
}
To make this work you'll need to modify the contents of the App\Http\Requests\Request class to allow a way to sanitize the input (class code taken from this Laracasts post):
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest
{
/**
* Validate the input.
*
* #param \Illuminate\Validation\Factory $factory
* #return \Illuminate\Validation\Validator
*/
public function validator($factory)
{
return $factory->make(
$this->sanitizeInput(), $this->container->call([$this, 'rules']), $this->messages()
);
}
/**
* Sanitize the input.
*
* #return array
*/
protected function sanitizeInput()
{
if (method_exists($this, 'sanitize'))
{
return $this->container->call([$this, 'sanitize']);
}
return $this->all();
}
}
After that you just need to write add sanitize method in the UpdateUserRequest class that removes the password field from the input when it's empty:
public function sanitize()
{
if (empty($this->get('password'))) {
// Get all input
$input = $this->all();
// Remove the password field
unset($input['password']);
// Replace the input with the modified one
$this->replace($input);
}
return $this->all();
}
Now using the sometimes rule for the password field will work:
public function rules()
{
return [
// Other rules go here
'password' => 'sometimes|required|confirmed'
];
}
I'm not sure about the best way to purge the fields, but this is how I currently handle user updates on my system.
I find the user based on the $id passed through and then update the appropriate records. I assume that name and email will never be empty, it is only the password that can be empty - and so we can just set the name and email fields to the values passed in and then use an if statement to check if the password field is empty or not and update accordingly.
Something along the lines of this is what I use:
public function update($id)
{
$user = User::find($id);
$user->name = Input::get('name');
$user->email = Input::get('email');
if (Input::get('password') != "")
{
$user->password = Hash::make(Input::get('password'));
}
$user->save();
}
I am using form request validation and there are some rules that needs external values as a parameters.
Here are my validation rules for editing a business profile inside a form request class,
public function rules()
{
return [
'name' => 'required|unique:businesses,name,'.$business->id,
'url' => 'required|url|unique:businesses'
];
}
I can use this on the controller by type hinting it.
public function postBusinessEdit(BusinessEditRequest $request, Business $business)
{
//
}
But how to pass the $business object as a parameter to the rules method?
Lets say this is your model binding:
$router->model('business', 'App\Business');
Then you can reference the Business class from within the FormRequest object like this:
public function rules()
{
$business = $this->route()->getParameter('business');
// rest of the code
}
Note that if you use your form request both for create and update validation, while creating the record, the business variable will be null because your object does not exists yet. So take care to make the needed checks before referencing the object properties or methods.
There can be many ways to achieve this. I do it as below.
You can have a hidden field 'id' in your business form like bellow,
{!! Form::hidden('id', $business->id) !!}
and you can retrieve this id in FormRequest as below,
public function rules()
{
$businessId = $this->input('id');
return [
'name' => 'required|unique:businesses,name,'.$businessId,
'url' => 'required|url|unique:businesses'
];
}
For those who switched to laravel 5 :
public function rules()
{
$business = $this->route('business');
// rest of the code
}
Let say if we have a scenario like we want to change our validation rules depends on the type that we pass in with the route. For example:
app.dev/business/{type}
For different type of business, we have different validation rules. All we need to do is type-hint the request on your controller method.
public function store(StoreBusiness $request)
{
// The incoming request is valid...
}
For the custom form request
class StoreBussiness extends FormRequest
{
public function rules()
{
$type = $this->route()->parameter('type');
$rules = [];
if ($type === 'a') {
}
return rules;
}
}
In Laravel 5.5 at least (haven't checked older versions), once you did your explicit binding (https://laravel.com/docs/5.5/routing#route-model-binding), you can get your model directly through $this:
class StoreBussiness extends FormRequest
{
public function rules()
{
$rules = [];
if ($this->type === 'a') {
}
return rules;
}
}
Since Laravel 5.6 you may type hint it in the rules method:
public function rules(Business $business)
{
return [
'name' => 'required|unique:businesses,name,'.$business->id,
'url' => 'required|url|unique:businesses'
];
}
See the docs for more:
You may type-hint any dependencies you need within the rules method's signature. They will automatically be resolved via the Laravel service container.