A Catalyst model is simply a package in the MyApp::Model namespace.
$c->model('DBIC')
simply returns
"MyApp::Model::DBIC"
I recently spent some time at work trying to work out quite how Catalyst models work with relation to, well, everything else.
Our app structure is based on CatalystX::AppBuilder, and I needed to add a model to one of the components, in order to provide a caching layer in the right place.
The mistake I'd been making was that the Schema subclass is not the same thing as the model. Rather, the model is an interface into the Schema class. Essentially, I had one class too few.
You can determine that by creating a new Catalyst application and then running the helper script that creates a model from an existing schema. You get a class like this:
package MyApp::Model::FilmDB; use strict; use base 'Catalyst::Model::DBIC::Schema'; __PACKAGE__->config( schema_class => 'MyApp::Schema::FilmDB', connect_info => { dsn => 'dbi:mysql:filmdb', user => 'dbusername', password => 'dbpass', } );
A Model
class is created and it points to the Schema
class, being your actual DBIC schema.
Once I'd realised the above rule it was easy enough to create MyApp::Extension::Model::DBIC
to go alongside MyApp::Extension::Schema
.
Further confusion arose with the configuration. There appeared to be no existing configuration that matched any of the extant classes in the application or its components. However, it was clear which was the DBIC model configuration because of the DSN.
I wanted to follow suit with the new module, which meant that some how I had to map the real name to the config name.
<Model::DBIC> </Model::DBIC>
This makes sense; if I do $c->model('DBIC')
I'll get "MyApp::Model::DBIC"
, and that'll be configured with the Model::DBIC
part of the config.
What I'd missed here was that we were mixing CatalystX::AppBuilder with CatalystX::InjectComponent:
package MyApp::Extension; use CatalystX::InjectComponent; after 'setup_components' => sub { my $class = shift; ... CatalystX::InjectComponent->inject( into => $class, component => __PACKAGE__ . '::Model::DBIC', as => 'Model::DBIC', ); }
This was the missing part - the stuff inside the CatalystX::AppBuilder component was itself built up out of other components, aliasing their namespace-specific models so that $c->model
would return the appropriate class.
Now, Model::DBIC
refers to MyApp::Extension::Model::DBIC
, which is an interface into MyApp::Extension::Schema
.