edem
edem

Reputation: 3272

How to create global var $schema for connection to DB in Catalyst app?

I've created a model lib/MyApp/Model/Foo.pm. Inside it:

...
sub bar {
  my $schema = MyApp::Schem->connect("dbi:SQLite:data.db");
}
...

It works fine but when I write so:

...
my $schema = MyApp::Schema->connect("dbi:SQLite:data.db");
sub bar {}
...

it doesn't work and write this:

Can't locate object method "connect" via package "MyApp::Schema" (perhaps you forgot to load "MyApp::Schema"?) at ...

I'd like to create global $schema var to use it in different methods. How can I reach it?

Upvotes: 0

Views: 892

Answers (3)

Alexander Hartmaier
Alexander Hartmaier

Reputation: 2204

Catalyst::Model::DBIC::Schema handles connecting to the database automatically for every process that might be started.

If you create your MyApp::Model::DBIC using the helper as shown in the synopsis it will work out-of-the-box. Database credentials or the database filename in case of SQLite are usually put inside the Catalyst config file loaded by Catalyst::Plugin::ConfigLoader.

Note that you normally don't add any methods to the Catalyst model nor the DBIx::Class schema.

To access the model, regardless of its type (DBIC, LDAP, ...), you have to use $c->model($modelname) in Catalyst. So if you named your model MyApp::Model::DBIC this would be $c->model('DBIC'). To access a DBIC resultset you can either use $c->model('DBIC')->resultset('Foo') or $c->model('DBIC::Foo') which is a special syntax Catalyst::Model::DBIC::Schema supports.

Upvotes: 2

edem
edem

Reputation: 3272

I read in Catalyst::Model::DBIC::Schema that we can us $self->schema to get access to db schema from anywhere. So this variant works fine:

sub bar {
  my ($self) = @_;
  my $schema = $self->schema;
}

Upvotes: 0

mob
mob

Reputation: 118625

Did you forget to load MyApp::Schema?

When you call MyApp::Schema->connect inside a subroutine, it is likely that some other Catalyst component has already loaded the MyApp::Schema module and made the connect method available.

Outside the subroutine, your application will try to call MyApp::Schema::connect at the time your MyApp::Model::Foo module is loaded, and whether it will succeed or not will depend on the order that other packages are loaded. So writing use MyApp::Schema; at the top of your MyApp::Model::Foo package might solve your problem.


Another thing that might solve your problem is lazy initialization of your schema. Replace all instances of $schema in your model with a function call, say, schema(), and include this code:

my $_schema;
sub schema {
    $_schema //= MyApp::Schem->connect("dbi:SQLite:data.db")
}

Now your schema object gets initialized once, when it's needed, and probably after all the other relevant modules your application depends on have been loaded.

Upvotes: 0

Related Questions