How to automatically register validators in Fluent Validation only when they implement a certain interface? - fluentvalidation

I have some validation classes like:
public class AnimalValidator : AbstractValidator<AnimalDTO>
{
// ...
}
And I would like to automatically register only the ones that implement an IAutomaticValidation interface to be used to validate DTOs received by the controllers.
I tried doing:
builder.Services.AddController( /* ... */ ).AddFluentValidation(options =>
{
options.RegisterValidatorsFromAssemblyContaining<IAutomaticValidation>();
});
But it still looks for the AbstractValidator class instead.

Managed to do it with:
options.RegisterValidatorsFromAssemblyContaining<MyEntityValidator>
(
x => x.ValidatorType.GetInterfaces().Any(x => x == typeof(IAutomaticValidation))
);
But then decided to use annotations instead:
options.RegisterValidatorsFromAssemblyContaining<MyEntityValidator>
(
x => x.ValidatorType.CustomAttributes
.Any(x => x.AttributeType == typeof(AutomaticValidationAction))
);

Related

Laravel 6: How to change the URL of the password reset email link in custom class

I'm building API with Laravel and working on resetting password. Everything is working fine but I want to change the URL which will handle the reset link to be different than the API domain
Route::group(['namespace' => 'Api', 'middleware' => 'guest'], function () {
Route::post('password/reset', 'ResetPasswordController')->name('password.reset');
public function forgotPassword($data) {
Password::sendResetLink(['email' => $data['email']]);
}
Laravel reset password class (class ResetPassword extends Notification)
return (new MailMessage)
....
->action(Lang::get('Reset Password'), url(route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
....
}
I want to change the URL
http://api.test:8000/api/password/reset?token=dced9b55a73fcd0692ce4157d2685826f51c332d0dcce613cad108a8599881d7&email=user#mail.com
to be
http://frontend.test:8000/reset-password?token=dced9b55a73fcd0692ce4157d2685826f51c332d0dcce613cad108a8599881d7&email=user#mail.com
I managed to change it in the original class
// ->action(Lang::get('Reset Password'), url(route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
->action(Lang::get('Reset Password'), 'http://frontend.test:8000/reset-password?token='.$this->token.'&email='.$notifiable->getEmailForPasswordReset())
But how can I override this function in my own class that would be better to keep the original function as it is but don't know how.
Thanks in advance
There is a static helper in Laravel's ResetPassword notification, you can add following code in the App\Providers\AuthServiceProvider class:
use App\Notifications\Auth\ResetPasswordNotification;
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
ResetPasswordNotification::createUrlUsing(function ($notifiable, $token) {
return config('app.frontend_url')."/password/reset/$token?email={$notifiable->getEmailForPasswordReset()}";
});
//
}
I found a simple answer here by creating a custom notification and using it in CanResetPassword trait https://laracasts.com/discuss/channels/laravel/how-to-override-the-tomail-function-in-illuminateauthnotificationsresetpasswordphp

Laravel 8 factory class is not overriding the parameters while creating the factories

I am developing a web application using Laravel 8. I have noticed that quite a lot of things have changed in Laravel 8 including factories.
I have a factory class MenuCategoryFactory for my MenuCategory model class with the following definition.
<?php
namespace Database\Factories;
use App\Models\Menu;
use App\Models\MenuCategory;
use Illuminate\Database\Eloquent\Factories\Factory;
class MenuCategoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = MenuCategory::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory()->create(),
];
}
}
In my code (database seeder class), I am trying to override the menu_id as follow while I am creating the factories.
$restaurant = Restaurant::first();
MenuCategory::factory()->create([
'menu_id' => $restaurant->menu->id
]);
But it is not using the value I passed, $restaurant->menu->id. Instead, it is creating a new menu. What is wrong missing in my code and how can I fix it?
In your factory definition, don't call ->create(), instead set it up like this:
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory(),
];
}
Then you you should be able to set up related models (assuming you the relationships setup in the model) like this:
$restaurant = Restaurant::first();
MenuCategory::factory()->for($restaurant)->create();
Change the definition to
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => function() {
Menu::factory()->create()->id,
}
];
}
then you can replace the value

Check if entity is loaded using AsNoTracking

Is there a way to check if the entity was loaded using AsNoTracking() or not?
As you know, the following code will not work for entity loaded using AsNoTracking().
ef.Entry(db).Collection(p => p.tblProducts).Load();
ef.Entry(db).Collection(p => p.tblOrders).Load();
...
...
...
Therefore, if the entity "db" was loaded using AsNoTracking() then I will do the following for loading its children.
db.tblProducts = ef.tblProducts.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
db.tblOrders = ef.tblOrders.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
...
...
...
I know it may not be a good approach, but if entity "db" was loaded using AsNoTracking(), then I know that its children do not need to be tracked too.
The question is, how to find out if the entity (that passed in the function) was loaded using AsNoTracking() or not.
POSSIBLE SOLUTION
I found this post here EntityFramework Code First - Check if Entity is attached, someone post the answer like this
public bool Exists<T>(T entity) where T : class
{
return this.Set<T>().Local.Any(e => e == entity);
}
So, can I use
if (Exists(db))
{
ef.Entry(db).Collection(p => p.tblProducts).Load();
ef.Entry(db).Collection(p => p.tblOrders).Load();
...
...
...
}
else
{
db.tblProducts = ef.tblProducts.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
db.tblOrders = ef.tblOrders.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
...
...
...
}
What do you think?
Thanks!
Thanks to this post EntityFramework Code First - Check if Entity is attached, I create a DbContext extension (as suggested on the link).
public static bool Exists<TEntity>(this DbContext ctx, TEntity entity)
where TEntity : class
{
return ctx.Set<TEntity>().Local.Any(e => e == entity);
}
And it worked nicely!
if (ef.Exists(db))
{
ef.Entry(db).Collection(p => p.tblProducts).Load();
ef.Entry(db).Collection(p => p.tblOrders).Load();
...
...
...
}
else
{
db.tblProducts = ef.tblProducts.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
db.tblOrders = ef.tblOrders.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
...
...
...
}
I hope this post could help someone with similar problem.
Cheers!

Ninject Get<T> WhenTargetHas<T>

So I'm using Ninject, specifically the contextual binding as follows :
Bind<IBlah>().ToMethod(x => FirstBlahProvider.Instance.GiveMeOne()).WhenTargetHas<FirstAttribute>().InRequestScope();
Bind<IBlah>().ToMethod(x => SecondBlahProvider.Instance.GiveMeOne()).WhenTargetHas<SecondAttribute>().InRequestScope();
I need to use the Kernel to get a given instance and would like to do it based on the Condition WhenTargetHas<T>. Something like the following would be great.
var myblah = Kernal.Get<IBlah>(x => x.HasWithTarget<FirstAttribute>)
How can you retrieve an instance based on the condition?
Worked out the answer :
Best to avoid using WhenTargetHas<T> instead use WithMetaData(key, value)
So
Bind<IBlah>().ToMethod(x => FirstBlahProvider.Instance.GiveMeOne()).WhenTargetHas<FirstAttribute>().InRequestScope();
Bind<IBlah>().ToMethod(x => SecondBlahProvider.Instance.GiveMeOne()).WhenTargetHas<SecondAttribute>().InRequestScope();
Becomes :
Bind<IBlah>().ToMethod(x => FirstBlahProvider.Instance.GiveMeOne()).WithMetaData("Provider", "First);
Bind<IBlah>().ToMethod(x => SecondBlahProvider.Instance.GiveMeOne()).WithMetaData("Provider", "Second");
You then need to create an Attribute which inherits the Ninject ConstraintAttribute and use that attribute in your constructor arguement.
As :
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)]
public class FirstProviderConstraint : ConstraintAttribute
{
public override bool Matches(IBindingMetadata metadata)
{
return metadata.Has("Provider") && metadata.Get<string>("Provider") == "First";
}
}
You then use it in a constructor arg as :
public class Consumer([FirstProviderConstraint] IBlah)
{
...
}
Or resolving from the Kernel
Get<ISession>(metaData => metaData.Get<string>(BindingKeys.Database) == BindingValues.OperationsDatabase)
I need to resolve scoping but that's how you satisfy both Constructor injection and explicit resolution from the Kernel when you have more than one binding.

mapping by code in nhibernate

I'm examin some mapping examples which uses mapping by code, and I have one simple question
If I have two properties which are mapped like this
Property(x => x.UserName, m =>
{
m.Length(50);
m.NotNullable(true);
});
Property(x => x.UpperUserName, m =>
{
m.Length(50);
m.NotNullable(true);
m.UniqueKey(“UniqueUpperUserName”);
m.Access(Accessor.Field);
});
What this m.Access(Accessor.Field); means?
And why it's used on these second property UpperUserName and not in the first one?
Thanks.
It means that NHibernate won't use the property itself when reading and writing values, but the underlying field.
// This will be used
var string upperUserName;
public string UpperUserName
{
get { return upperUserName; }
// Maybe this is a read-only property,
// so we must allow NHibernate to update the value somehow
// set { upperUserName = value; }
}
You can read more on available access types in NHibernate documentation. Just scroll down to Access and Naming strategies tables.