Re: [Catalyst] One App, multiple databases

2008-11-20 Thread Jonathan Rockway
* On Wed, Nov 19 2008, Jose Luis Martinez wrote:

 sub ACCEPT_CONTEXT {
 my ($self, $c) = @_;

 my $user_db = $c-lookup_the_users_db();
 $self-{'dsn'} =~ s/#DATABASE#/$user_db/;

 return $self;
 }


I am really surprised that this works at all.  When do you actually ever
connect to the database with the DSN in $self-{dsn}?  (I am also
surprised that the DBIC version works.)

Anyway, mutating objects is wrong.  You should do things like this:

  package MyApp::Model::UsersDatabase;
  ...
  sub ACCEPT_CONTEXT {
  my ($self, $c) = @_;

  return $c-user-get_database($c-config-database_info);
  }

Then your user class should do something like:

  sub get_database {
  my ($self, $database_info) = @_;

  $self-database_connection($self-connect_to_database($database_info))
unless $self-has_database_connection;

  return $self-database_connection;
  }

(You can write cleaner code with a before method modifier, if you use
Moose.)

The idea is that each user has his own database connection, stored in
the user object, and Catalyst just returns the right thing when you say
$c-model('UsersDatabase').  This is much easier to reason about.

Regards,
Jonathan Rockway

--
print just = another = perl = hacker = if $,=$

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] One App, multiple databases

2008-11-20 Thread Jose Luis Martinez

Jonathan Rockway escribió:

* On Wed, Nov 19 2008, Jose Luis Martinez wrote:

sub ACCEPT_CONTEXT {
my ($self, $c) = @_;

my $user_db = $c-lookup_the_users_db();
$self-{'dsn'} =~ s/#DATABASE#/$user_db/;

return $self;
}



I am really surprised that this works at all.  When do you actually ever
connect to the database with the DSN in $self-{dsn}?  (I am also
surprised that the DBIC version works.)


It looks like the models don't connect to the database until it is first 
needed, so changing the properties with which they connect lets me get 
away with it. I think the fact that I'm working with app_server.pl -f 
helps me start each request without preestablished db connection.



Anyway, mutating objects is wrong.  You should do things like this:

  package MyApp::Model::UsersDatabase;
  ...
  sub ACCEPT_CONTEXT {
  my ($self, $c) = @_;

  return $c-user-get_database($c-config-database_info);
  }

Then your user class should do something like:

  sub get_database {
  my ($self, $database_info) = @_;

  $self-database_connection($self-connect_to_database($database_info))
unless $self-has_database_connection;

  return $self-database_connection;
  }
The idea is that each user has his own database connection, stored in
the user object, and Catalyst just returns the right thing when you say
$c-model('UsersDatabase').  This is much easier to reason about.


But I'll still have to change Model::DBI and/or Model::DBIC::Schema 
connection information on the fly... how should I do this in a clean way?


Regards,

Jose Luis Martinez
[EMAIL PROTECTED]

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] One App, multiple databases

2008-11-20 Thread Tomas Doran


On 20 Nov 2008, at 14:51, Jose Luis Martinez wrote:


Jonathan Rockway escribió:

* On Wed, Nov 19 2008, Jose Luis Martinez wrote:

sub ACCEPT_CONTEXT {
my ($self, $c) = @_;

my $user_db = $c-lookup_the_users_db();
$self-{'dsn'} =~ s/#DATABASE#/$user_db/;

return $self;
}

I am really surprised that this works at all.  When do you  
actually ever

connect to the database with the DSN in $self-{dsn}?  (I am also
surprised that the DBIC version works.)


It looks like the models don't connect to the database until it is  
first needed, so changing the properties with which they connect  
lets me get away with it. I think the fact that I'm working with  
app_server.pl -f helps me start each request without preestablished  
db connection.



Anyway, mutating objects is wrong.  You should do things like this:
  package MyApp::Model::UsersDatabase;
  ...
  sub ACCEPT_CONTEXT {
  my ($self, $c) = @_;
  return $c-user-get_database($c-config-database_info);
  }
snip
The idea is that each user has his own database connection, stored in
the user object, and Catalyst just returns the right thing when  
you say

$c-model('UsersDatabase').  This is much easier to reason about.


But I'll still have to change Model::DBI and/or Model::DBIC::Schema  
connection information on the fly... how should I do this in a  
clean way?


No, you don't.

In your application code, instead of saying $c-model('DB')-dbh,  
with the example above, you would say $c-model('UsersDatabase'), and  
that would return you the dbh which the user object had generated.


You then work with it in exactly the same way as if you were using  
Catalyst::Model::DBI.


This means that you have to re-implement the connection logic of  
Catalst::Model::DBI in your user class. The only tricky bit is the  
stay_connected function, which is 16 lines long.


I don't think the code police will break down your door if you pinch  
this function verbatim. ;)


Cheers
t0m


___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


RE: [Catalyst] One App, multiple databases

2008-11-19 Thread Mesdaq, Ali
Are these db's exact copies as far as schema from each other? Or is it 
different tables and structure as well? 

Reason I am asking is because if its exactly the same and all your queries work 
the same and your logic works the same as well and the only difference is if 
user1 is connected then connect to one schema and if user2 is connected connect 
to another schema you might be able to more cleanly determine the db in your 
controller code. You would also then create a model for each user. This would 
give you granular control over if the user db's ever move or if you need to 
configure specific connection data per users db like different user accounts 
and passwords etc.

So instead of something like:
$c-model('DB::Blah')-all

You could do:
$c-model($user:Blah)-all

But I think knowing a little more about your exact situation might help 
understand the issue more.

Thanks,
--
Ali Mesdaq (CISSP, GIAC-GREM)
Sr. Security Researcher
Websense Security Labs
http://www.WebsenseSecurityLabs.com
--


-Original Message-
From: Jose Luis Martinez [mailto:[EMAIL PROTECTED] 
Sent: Wednesday, November 19, 2008 9:54 AM
To: The elegant MVC web framework
Subject: [Catalyst] One App, multiple databases

Hello,

This question has been asked a couple of times on the list, and I have 
found yet another solution to it, but I would like to hear if maybe I'm 
doing something wrong, or I will suffer serious pain by doing it my way :)

We have an app that will connect to one database or another depending on 
the logged in user.

My solution:

package App::Model::DB;

use strict;
use base 'Catalyst::Model::DBIC::Schema';
...
sub ACCEPT_CONTEXT {
 my ($self, $c) = @_;

 my $user_db = $c-lookup_the_users_db();
 $self-config-{'connect_info'}-[0] =~ s/#DATABASE#/$user_db/;
 $self-schema-connection(@{$self-config-{'connect_info'}});

 return $self;
}


1;

I've done the same with Catalyst::Model::DBI:

package App::Model::AnotherDB;

use strict;
use base 'Catalyst::Model::DBI';

sub ACCEPT_CONTEXT {
 my ($self, $c) = @_;

 my $user_db = $c-lookup_the_users_db();
 $self-{'dsn'} =~ s/#DATABASE#/$user_db/;

 return $self;
}

1;

And the two seem to be working OK, but I'm worried about what will 
happen when we fire it up in a FastCGI environment (I suspect the 
connection to  user1's database will be kept live, and the next user 
will get the connection to it). Am I right? Any pointers?

Does this way of using the models trigger any warning lights to Catalyst 
gurus?

Thanks in advance,

Jose Luis Martinez
[EMAIL PROTECTED]

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


 Protected by Websense Hosted Email Security -- www.websense.com 

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] One App, multiple databases

2008-11-19 Thread Jose Luis Martinez

Mesdaq, Ali escribió:
Are these db's exact copies as far as schema from each other? Or is it different tables and structure as well? 


Reason I am asking is because if its exactly the same and all your queries work 
the same and your logic works the same as well and the only difference is if 
user1 is connected then connect to one schema and if user2 is connected connect 
to another schema you might be able to more cleanly determine the db in your 
controller code. You would also then create a model for each user. This would 
give you granular control over if the user db's ever move or if you need to 
configure specific connection data per users db like different user accounts 
and passwords etc.

So instead of something like:
$c-model('DB::Blah')-all


Yes, they are exactly the same. But I'm not really all that keen on 
creating one model per user (because the users would be created and 
deleted), and that would mean that will have to be added and deleted, 
and app servers restarted.



But I think knowing a little more about your exact situation might help 
understand the issue more.


Basically we giving multi-tentant capability to our app (which was 
ported from some old CGIs). The CGIs where setup to load config files 
based on the REMOTE_USER, so we gave each user a separate DB just by 
changing the connect string. Now in Catayst we want the same effect ;), 
as sharing one database between all users is a step we don't want to 
take (for the moment).


Hope that explains a bit more.

Thanks,

Jose Luis Martinez
[EMAIL PROTECTED]

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/