Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Structure of a custom class (using Apache::Session)

by jeyroz (Monk)
on Jun 15, 2005 at 17:42 UTC ( [id://466987]=perlquestion: print w/replies, xml ) Need Help??

jeyroz has asked for the wisdom of the Perl Monks concerning the following question:

First and foremost, I'm wet behind the ears when it comes to OOPerl and lack confidence in my class design decisions. Any advice and or guidance is GREATLY appreciated. I have been studying Damian Conway's book and various other resources ... but have a distance to travel before I'm comfortable.

I'm currently integrating Apache::Session::MySQL into an existing project. I've created a (very simple) Session class that uses Apache::Session::MySQL giving me a singular connection to my data store, etc.

My questions in regard to my class are...

  • Am I wasting my time creating a session class on top of Apache::Session::MySQL when the only true benefit at this point is the singular data store connection? What other abilities are common in such custom “Session” classes?
  • How can I improve the data-structure of my resulting object? I feel as though blessing an anonymous hash and using a single key to point to a reference to a tied %session hash is wasteful. (ie: $self->{session} = \%session).
  • Is "init" an appropriate location to handle the interface with Apache::Session?
  • Should I be taking steps to protect my session data such as a closure? From my script I am able to do the following: my $id = $session_obj->{session}->{_session_id} – this defeats the point of OOP!
  • Is it necessary to "untie" my %session hash when closing (not deleting) the session?

Below is a link to my class code. The class functions as expected but I know it can be improved upon greatly. There are several parts of the class structure that I am not happy with which I have noted in the code.

package Local::SessionClass; use warnings; use strict; use Apache::Session::MySQL; sub new { my ($class, %args) = @_; my $self = bless {}, ref($class) || $class; $self->init(%args); return $self; } sub init { my ($self, %args) = @_; my $id = $args{id} || undef; my %session; tie %session, 'Apache::Session::MySQL', $id, { Handle => $args{dbh}, LockHandle => $args{dbh} }; # I FEEL AS THOUGH THE USEFUL DATA (%session) IS NEEDLESSLY REMOVED + FROM THE OBJECT'S MAIN DATA STRUCTURE (ITS ANONYMOUS HASH) REQUIRING + ME TO DEREF MULTIPLE REFERENCES. $self->{session} = \%session; return; } sub get_sid { my $self = shift; # AS MENTIONED ABOVE ... MULTIPLE DEREF return $self->{session}->{_session_id}; } # THIS SUB ALLOWS ME TO PASS IN MULTIPLE KEY=>VAL PAIRS FOR STORAGE PU +RPOSES sub set_sdata { my ($self, %args) = @_; map{$self->{session}->{$_} = $args{$_}} keys %args; return; } sub get_sdata { my $self = shift; return %{$self->{session}}; } # DELETE A KEY=>VAL FROM THE TIED %SESSION HASH sub delete_sdata { my ($self, $key) = @_; delete $self->{session}->{$key}; return; } # SIMPLY UNTIE THE SESSION FOR CLEAN UP ... IS THIS NECCESSARY? sub close_session { my $self = shift; untie($self->{session}); } # MANUALLY KILL THE SESSION ON LOGOUT sub kill_session { my $self = shift; tied(%{$self->{session}})->delete; untie($self->{session}); return; } # CLEAN UP UPON EXIT sub DESTROY { my $self = shift; $self->close_session; } 1; ### CREATE A NEW SESSION - CALLED FROM LOGIN SCRIPT ### use Local::SessionClass; # CREATE SESSION ID my $session_obj = Local::WPSession->new(dbh => $dbhandle); my $session_id = $session_obj->get_sid(); # ... SET COOKIE WITH SESSION ID ... # SET SESSION VALUES $session_obj->set_sdata( val_1 => 'foo', val_2 => 'bar' ); ### RELOAD EXISTING SESSION - CALLED FROM SEPARATE SCRIPTS ### use Local::SessionClass; my $session_id = $q->cookie(-name => 'previously_set_cookie'); my $session_obj = Local::WPSession->new(dbh => $dbh, id => $session_id +); # ACCESS SESSION VALUES my %sdata = $session_obj->get_sdata();

Thank you ahead of time for your help and advice. If any explanation is needed beyond what I have provided above, please just ask and I will respond immediately.

UPDATE: Added <readmore></readmore> tags.

author => jeyroz

Replies are listed 'Best First'.
Re: Structure of a custom class (using Apache::Session)
by ikegami (Patriarch) on Jun 15, 2005 at 18:34 UTC

    What do you mean by "singular data store connection"? All this class seems to do is to add a layer of indirection over Apache::Session::MySQL. That can be useful, but I fail to see what it's trying to accomplish here. Could you elaborate a bit?

    Off topic, using map in a void context is weird if not error-prone or slow. You should replace
    map{$self->{session}->{$_} = $args{$_}} keys %args;
    with
    $self->{session}->{$_} = $args{$_} foreach keys %args;

      Thanks for your reply!
      By "singular data store connection" (bad phrasing) I simply meant specifying the connection information in one location (the class) rather than in every script that uses the session data. Keeping that info in one place was the original reason for creating a "layer of indirection" ... but I absolutely agree, in its current state, the class doesn't provide much benefit. It was that realization that prompted me to post and find out if I should continue with its development or scrap it.

      Also, thank you for the "map" advice ... made the change in my code.

      author => jeyroz

        I simply meant specifying the connection information in one location (the class)

        um? The connection info isn't in the class. It's still in the class's user, just like it would be if Apache::Session::MySQL had been used directly.

        my $session_obj = Local::WPSession->new(dbh => $dbh, id => $sid); # ^^^^

        If you want to move the info needed to create the dbh into Local::WPSession (and possibly even create the dbh within the new class as well), why not make Local::WPSession inherit from Apache::Session::MySQL and simply override the constructor? That way, the user will be able to access all of Apache::Session::MySQL's methods without forcing you to recreate the interface or to create a new interface.

        I think having the connection/configuration information all in one place is a decent reason for wrapping Apache::Session::* with an class. I would still specify database connection information in a separate config file since the session isn't the only place in your code that probably needs a database right? I also prefer having an OO access rather than playing directly with the tied hash, but that may just be a personal preference.

        Before you go too far though, I would look at Apache::SessionManager and see if it's doing the same thing that you're looking for (if you're using mod_perl)

        -- More people are killed every year by pigs than by sharks, which shows you how good we are at evaluating risk. -- Bruce Schneier
Re: Structure of a custom class (using Apache::Session)
by JediWizard (Deacon) on Jun 15, 2005 at 18:42 UTC

    Should I be taking steps to protect my session data such as a closure? From my script I am able to do the following: my $id = $session_obj->{session}->{_session_id} – this defeats the point of OOP!

    In Perl5 encapsulation (by default) is semantic. Polite client code should not touch any key of an object which begins with _. If you want strictly enforced encapsulation, Perl 5 may not be for you. There are ways to create well encapsulated objects in Perl 5, but the language doesn't do it for you. Consider:

    package Encapsulated; my(%objects) = (); sub new { my $proto = shift; $proto = ref($proto) || $proto; my $junk; my $me = bless(\$junk, $proto); $objects{$me}{property} = 'something'; return $me; }

    Notice that you now have a way to store properties of an object in such a way that makes them inaccessable to the client code? I think Damian may even cover that technique in his book (he does in his class "Intermediate OO Perl")


    They say that time changes things, but you actually have to change them yourself.

    —Andy Warhol

Re: Structure of a custom class (using Apache::Session)
by Akhasha (Scribe) on Jun 16, 2005 at 01:19 UTC

    As for using a hash as a backing store but only using 1 key, its only a little wasteful if there are never more than one of these objects around, and its flexible when/if you ever need to add more fields/properties.

    Its a little more efficient to make $self a blessed reference to an array.

    I'm not sure about blessing a reference to your tied hash but you could try it. I tend to think that would be dangerous as the creation of your backing store is then out of your hands, or at least not where a reader might expect it to be.

    If you're sure you'll never need more than one field in your class, you can bless a reference to a scalar. That scalar can in turn be a reference to your tied hash. It seems a little silly if there aren't many of these objects, but probably is a little more efficient than having a hash with one key.

Re: Structure of a custom class (using Apache::Session)
by barrachois (Pilgrim) on Jun 16, 2005 at 15:13 UTC
    I've been doing similar things regularly, and finally over the last few weeks have been trying to pack my regular practice into a CPAN compatible module.

    My two modules are Object::Generic and Object::Generic::Session. Using them (in HTML::Mason, here) looks something like this:

    # -- file httpd.conf -- # (Define the session global.) PerlAddVar MasonAllowGlobals $session # -- file htdocs/autohandler - # (Retrieve the session; process webpage.) % $session = new Object::Session::Generic( % session_config => { Store=>'MySQL', ... }, % cookie_name => 'your cookie name here', % expires => '+8h', % ); % $m->call_next; % $session = undef; # -- file htdocs/file.html -- # (Use the session to access key/value pairs.) <html> % if ($username){ % $session->user( % new Object::Generic( name => $username ) % ); % } % if ($session->user){ Hi <% $session->user->name %>. Welcome back. % } else { <form> Please log in: <input type="text" name="username" /> </form> % } </html> <%args> $username => '' </%args>

    You can find Object::Generic and Object::Generic::Session at http://cs.marlboro.edu/code/perl/modules/ if you want to check them out.

    Update: I've just uploaded v0.02 of both of these to CPAN.

Re: Structure of a custom class (using Apache::Session)
by siracusa (Friar) on Jun 15, 2005 at 20:16 UTC
    Just as an aside, you might want to rethink the use of ALL CAPS in your comments...

      Thanks for the suggestion but I actually prefer comments to be in all caps. Makes the comments easier to pick out when syntax highlighting isn't available.

      Your thoughts?

      author => jeyroz

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://466987]
Approved by jbrugger
Front-paged by jbrugger
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (7)
As of 2024-03-28 10:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found