Search code examples
perlmoose

What is the most efficient way to override an attribute in lots of my Moose based sub classes?


I am using HTML::FormHandler. To use it one is supposed to subclass from it and then you can override some attributes such as field_name_space or attribute_name_space.

However, I now have lots of forms all extending HTML::FormHandler or its DBIC based variant HTML::FormHandler::Model::DBIC and therefore have these overidden attributes repeated many times.

I tried to put them in a role but get an error that +attr notation is not supported in Roles. Fair enough.

What is the best way of eliminating this repetition? I thought perhaps subclassing but then I would have to do it twice for HTML::FormHandler and HTML::FormHandler::Model::DBIC, plus I believe general thought was that subclassing is generally better achieved with Roles instead.

Update: I thought it would be a good idea to give an example. This is what I am currently doing - and it involves code repetition. As you can see one form uses a different parent class so I cannot create one parent class to put the attribute overrides in. I would have to create two - and that also adds redundancy.

package MyApp::Form::Foo;

# this form does not interface with DBIC
extends 'HTML::Formhandler';

has '+html_prefix'          => (default => 1); 
has '+field_traits'         => (default => sub { ['MyApp::Form::Trait::Field'] }); 
has '+field_name_space'     => (default => 'MyApp::Form::Field');
has '+widget_name_space'    => (default => sub { ['MyApp::Form::Widget'] }); 
has '+widget_wrapper'       => (default => 'None');

...

package MyApp::Form::Bar;

# this form uses a DBIC object
extends 'HTML::Formhandler::Model::DBIC';

has '+html_prefix'          => (default => 1); 
has '+field_traits'         => (default => sub { ['MyApp::Form::Trait::Field'] }); 
has '+field_name_space'     => (default => 'MyApp::Form::Field');
has '+widget_name_space'    => (default => sub { ['MyApp::Form::Widget'] }); 
has '+widget_wrapper'       => (default => 'None');

...

package MyApp::Form::Baz;

# this form also uses a DBIC object
extends 'HTML::Formhandler::Model::DBIC';

has '+html_prefix'          => (default => 1); 
has '+field_traits'         => (default => sub { ['MyApp::Form::Trait::Field'] }); 
has '+field_name_space'     => (default => 'MyApp::Form::Field');
has '+widget_name_space'    => (default => sub { ['MyApp::Form::Widget'] }); 
has '+widget_wrapper'       => (default => 'None');

...

Solution

  • The code for HTML::FormHandler::Model::DBIC is actually in a Moose trait in order to help with this situation. You can inherit from your base class, and in your forms that use the DBIC model, you can do

    with 'HTML::FormHandler::TraitFor::Model::DBIC';