FAQ
Hi,

I'm sure there is a way but it's not jumping out at me.

I have a list of countries and their associated database ID's that I
need to stash in the header of (almost) every page on a site. I have
no problems creating a controller that can do
$c->model(DB::Countries)->search({foo=>1}) and stick that into a
$c->stash but I don't want to make repeated DB calls. I'd like to
create a hash at startup and make it available to
root/lib/site/header. Is it possible to create a hash within
lib/MyApp.pm that will be available throughout and how would my
templates access it?

TIA,
Dp.

Search Discussions

  • Ido Perlmuter at Mar 17, 2010 at 5:54 pm
    Catalyst applications are Perl applications just like anyone else. If you
    want to access a hash variable (or any variable) which is declared (and
    possibly defined) in MyApp.pm (or any module for that matter), then all you
    need to do is refer to that variable from external sources (like templates)
    by its full name. So, for example, if the name of your variable is %HASH,
    then you can access it from your templates as %MyApp::HASH.

    As a matter of fact, if when declaring the %HASH variable in MyApp.pm you do
    so by its full name, i.e. %MyApp::HASH, you don't even have to use "my
    %HASH" but just "%MyApp::HASH". Not that it's any better, but anyway...

    Ido.
    On Wed, Mar 17, 2010 at 7:43 PM, Dermot wrote:

    Hi,

    I'm sure there is a way but it's not jumping out at me.

    I have a list of countries and their associated database ID's that I
    need to stash in the header of (almost) every page on a site. I have
    no problems creating a controller that can do
    $c->model(DB::Countries)->search({foo=>1}) and stick that into a
    $c->stash but I don't want to make repeated DB calls. I'd like to
    create a hash at startup and make it available to
    root/lib/site/header. Is it possible to create a hash within
    lib/MyApp.pm that will be available throughout and how would my
    templates access it?

    TIA,
    Dp.

    _______________________________________________
    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/
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100317/e4e2fec8/attachment.htm
  • Jay Shirley at Mar 17, 2010 at 6:04 pm

    On Wed, Mar 17, 2010 at 9:43 AM, Dermot wrote:
    Hi,

    I'm sure there is a way but it's not jumping out at me.

    I have a list of countries and their associated database ID's that I
    need to stash in the header of (almost) every page on a site. I have
    no problems creating a controller that can do
    $c->model(DB::Countries)->search({foo=>1}) and stick that into a
    $c->stash but I don't want to make repeated DB calls. I'd like to
    create a hash at startup and make it available to
    root/lib/site/header. Is it possible to create a hash within
    lib/MyApp.pm that will be available throughout and how would my
    templates access it?

    TIA,
    Dp.

    You can quite easily create accessors off the schema, and use lazy_build.

    Something like this:

    package MyApp::Schema;

    use Moose;
    extends 'DBIx::Class::Schema';

    has something => (
    is => ro,
    lazy_build => 1
    );

    sub _build_something {
    my ( $self ) = @_;
    [ $self->resultset('Countries')->search({ foo => 1 })->all ];
    }

    no Moose;

    Then after that if you wish, you can do clear_something and it will be
    refetched.

    -J

    (Code untested, typed out quickly)
  • Ram Dobson at Mar 17, 2010 at 6:48 pm
    I might do it a little different, but i like this Jshirley
    On 3/17/2010 2:04 PM, J. Shirley wrote:
    [snip]
    >
    -package MyApp::Schema;
    +package MyApp;
    use Moose;
    extends 'DBIx::Class::Schema';
    -has something => (

    +has my_hash => (
    is => ro,
    lazy_build => 1
    );

    sub _build_something {
    my ( $self ) = @_;
    -[ $self->resultset('Countries')->search({ foo => 1 })->all ];
    +[ $self->model('Countries')->search({ foo => 1 })->all;
    +#TODO hashify that
    }
    no Moose;
    now getting your hash is as simple as $c->my_hash;
    or if you're using TT [% c.myhash %]

    I'm kinda new to Catalyst too, but i believe this is what one might call
    a "helper" function. Anybody who knows more have an opinion on the
    relative merit of my change?



    Then after that if you wish, you can do clear_something and it will be
    refetched.

    -J

    (Code untested, typed out quickly)

    _______________________________________________
    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/
  • Tomas Doran at Mar 17, 2010 at 11:04 pm

    On 17 Mar 2010, at 18:48, Ram Dobson wrote:
    I'm kinda new to Catalyst too, but i believe this is what one might
    call a "helper" function. Anybody who knows more have an opinion on
    the relative merit of my change?

    Crapping stuff into the top level context class like that works,
    however as you do this you're throwing away reusability (as that stuff
    can now only be used inside Catalyst, not in anything else reusing the
    same database schema), and you're going towards making a 'god object'.

    I'm not saying that doing something like this isn't _sometimes_ fine,
    but in this case, my mental model would consider the caching of some
    data values (which is basically what you're doing here) a function of
    the domain model layer, not of the web application per-se.

    In fact, generally - you don't want to be calling the generic ->search
    method in your controllers _at all_.

    The specific search functionality should instead be pushed down into
    your ResultSet classes, so that you say:

    $c->model('DB::Books')->find_all_books_by_author($author_name);

    Rather than $c->model('DB::Books')-
    search({ %stuff_including_author_name }, { %ordering_stuff });
    The former is your controller declaratively asking the domain model
    for what it wants. The latter is for controller manipulating the
    domain model directly by having knowledge of it's implementation.

    Which tables you join (and how you join / sort / order / filter them)
    to get a set of data _IS NOT_ something controller code should know or
    care about, as that takes away your ability to alter the data
    representation (e.g. changing the table structure) without changing
    every place that knows about that representation...

    When you need to change your schema (and this will happen!), then only
    having to change the implementation details in the model is
    significantly less work (and testing), especially when you have dozens
    of controllers!

    Cheers
    t0m
  • Alexander Hartmaier at Mar 18, 2010 at 8:50 am

    Am Donnerstag, den 18.03.2010, 00:08 +0100 schrieb Tomas Doran:
    In fact, generally - you don't want to be calling the generic ->search
    method in your controllers _at all_.

    The specific search functionality should instead be pushed down into
    your ResultSet classes, so that you say:

    $c->model('DB::Books')->find_all_books_by_author($author_name);

    Rather than $c->model('DB::Books')-
    search({ %stuff_including_author_name }, { %ordering_stuff });
    The former is your controller declaratively asking the domain model
    for what it wants. The latter is for controller manipulating the
    domain model directly by having knowledge of it's implementation.

    Which tables you join (and how you join / sort / order / filter them)
    to get a set of data _IS NOT_ something controller code should know or
    care about, as that takes away your ability to alter the data
    representation (e.g. changing the table structure) without changing
    every place that knows about that representation...

    When you need to change your schema (and this will happen!), then only
    having to change the implementation details in the model is
    significantly less work (and testing), especially when you have dozens
    of controllers!

    Cheers
    t0m
    We should add that somewhere at the very top of some DBIC doc!

    ( no, I don't wanna hear a 'well volunteered' this time! )

    --
    Best regards, Alex


    *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
    T-Systems Austria GesmbH Rennweg 97-99, 1030 Wien
    Handelsgericht Wien, FN 79340b
    *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
    Notice: This e-mail contains information that is confidential and may be privileged.
    If you are not the intended recipient, please notify the sender and then
    delete this e-mail immediately.
    *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
  • Dermot at Mar 30, 2010 at 12:09 pm

    On 17 March 2010 23:08, Tomas Doran wrote:
    On 17 Mar 2010, at 18:48, Ram Dobson wrote:

    I'm kinda new to Catalyst too, but i believe this is what one might call a
    "helper" function. Anybody who knows more have an opinion on the relative
    merit of my change?

    Crapping stuff into the top level context class like that works, however as
    you do this you're throwing away reusability (as that stuff can now only be
    used inside Catalyst, not in anything else reusing the same database
    schema), and you're going towards making a 'god object'.

    I'm not saying that doing something like this isn't _sometimes_ fine, but in
    this case, my mental model would consider the caching of some data values
    (which is basically what you're doing here) a function of the domain model
    layer, not of the web application per-se.

    In fact, generally - you don't want to be calling the generic ->search
    method in your controllers _at all_.

    The specific search functionality should instead be pushed down into your
    ResultSet classes, so that you say:

    $c->model('DB::Books')->find_all_books_by_author($author_name);

    Rather than $c->model('DB::Books')->search({ %stuff_including_author_name },
    { %ordering_stuff });

    I had to take a rather difficult learning curve through DBIx::Class
    and move from load_classes to load_namespaces(). I'm fortunate enough
    to have had Aperion to hold my hand through the process. This has
    enabled me to make a first step towards what I think t0m was driving
    at. So what I have at the moment is

    package MyApp::Local::Schema::Resultset::Country;
    use strict;
    use warnings;
    use parent qw/DBIx::Class::ResultSet/;

    my @confirmed_countries;
    sub get_confirmed_countries {
    my $self = shift;
    return \@confirmed_countries if ($confirmed_countries[1]) || do {
    # return if the array has members
    @confirmed_countries = $self->search({ foo=> 1});
    };
    }

    1;

    Then in my Root controller it is pushed into the stash. The DBIC_trace
    shows only one call to the DB which is smashing, marvellous and
    fantastic. I think in this case I fall into that __sometimes__ area
    because this structure is required in 90% of all pages. I have also
    managed to keep the method available to non-cat applications. Ido is
    correct though, sometimes I simply forget that Catalyst is perl and
    loose my way.

    Thanks for all the help.
    Dp.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedMar 17, '10 at 5:43p
activeMar 30, '10 at 12:09p
posts7
users6
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2022 Grokbase