File Coverage

blib/lib/Jifty.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1 111     111   624 use warnings;
  111         210  
  111         3307  
2 111     111   584 use strict;
  111         251  
  111         5594  
3              
4             package Jifty;
5 111     111   231639 use IPC::PubSub 0.22;
  0            
  0            
6             use Data::UUID;
7             use encoding 'utf8';
8             use Class::Trigger;
9              
10             BEGIN {
11             # Work around the fact that Time::Local caches TZ on first require
12             local $ENV{'TZ'} = "GMT";
13             require Time::Local;
14              
15             # Declare early to make sure Jifty::Record::schema_version works
16             $Jifty::VERSION = '1.10518';
17             }
18              
19             =head1 NAME
20              
21             Jifty - an application framework
22              
23             =head1 SYNOPSIS
24              
25             # Object containing lots of web related goodies...
26             my $web = Jifty->web;
27             my $request = Jifty->web->request;
28             my $response = Jifty->web->response;
29             my $link = Jifty->web->link( label => _('W00t'), url => '/whatsit' );
30              
31             # Retrieve information from your application's etc/config.yml file.
32             my $config = Jifty->config;
33              
34             # Retrieve the Jifty::DBI handle
35             my $handle = Jifty->handle;
36              
37             # Load an application class, very handy in plugins
38             my $class = Jifty->app_class('Model', 'Foo');
39             my $foo = $class->new;
40             $foo->create( frobnicate => 42 );
41              
42             # Configure information related to your application's actions
43             my $api = Jifty->api;
44              
45             # Make parts of your page "subscribe" to information in a fragment
46             my $subs = Jifty->subs;
47              
48             # Share information via IPC::PubSub in your application
49             my $bus = Jifty->bus;
50              
51             # Retrieve general information about Mason
52             my $handler = Jifty->handler;
53              
54             =head1 DESCRIPTION
55              
56             Yet another web framework.
57              
58             =head2 What's cool about Jifty? (Buzzwords)
59              
60             =over 4
61              
62             =item DRY (Don't Repeat Yourself)
63              
64             Jifty tries not to make you say things more than once.
65              
66             =item Full-stack
67              
68             Out of the proverbial box, Jifty comes with one way to do everything
69             you should need to do: One database mapper, one templating system, one
70             web services layer, one AJAX toolkit, one set of handlers for
71             standalone or FastCGI servers. We work hard to make all the bits play
72             well together, so you don't have to.
73              
74             =item Continuations
75              
76             With Jifty, it's easy to let the user go off and do something else,
77             like fill out a wizard, look something up in the help system or go
78             twiddle their preferences and come right back to where they were.
79              
80             =item Form-based dispatch
81              
82             This is one of the things that Jifty does that we've not seen anywhere
83             else. Jifty owns your form rendering and processing. This means you
84             never need to write form handling logic. All you say is "I want an
85             input for this argument here" and Jifty takes care of the rest. (Even
86             autocomplete and validation)
87              
88             =item A Pony
89              
90             Jifty is the only web application framework that comes with a pony.
91              
92             =back
93              
94             =head2 Introduction
95              
96             If this is your first time using Jifty, L is
97             probably a better place to start.
98              
99             =cut
100              
101              
102             use base qw/Jifty::Object/;
103             use Jifty::Everything;
104              
105             use vars qw/$HANDLE $CONFIG $LOGGER $HANDLER $API $CLASS_LOADER $PUB_SUB $WEB @PLUGINS/;
106              
107             =head1 METHODS
108              
109             =head2 new PARAMHASH
110              
111             This class method instantiates a new C object. This object
112             deals with configuration files, logging and database handles for the
113             system. Before this method returns, it calls the application's C
114             method (i.e. Cstart>) to handle any application-specific startup.
115              
116             Most of the time, the server will call this for you to set up
117             your C object. If you are writing command-line programs that
118             want to use your libraries (as opposed to web services) you will need
119             to call this yourself.
120              
121             See L for details on how to configure your Jifty
122             application.
123              
124             =head3 Arguments
125              
126             =over
127              
128             =item no_handle
129              
130             If this is set to true, Jifty will not create a L and
131             connect to a database. Only use this if you're about to drop the
132             database or do something extreme like that; most of Jifty expects the
133             handle to exist. Defaults to false.
134              
135             =item logger_component
136              
137             The name that Jifty::Logger will log under. If you don't specify anything
138             Jifty::Logger will log under the empty string. See L for
139             more information.
140              
141             =back
142              
143             =cut
144              
145             sub new {
146             my $ignored_class = shift;
147              
148             # Setup the defaults
149             my %args = (
150             no_handle => 0,
151             pre_init => 0,
152             logger_component => undef,
153             @_
154             );
155              
156             # Add the application's library path
157             push @INC, File::Spec->catdir(Jifty::Util->app_root, "lib");
158              
159             # Now that we've loaded the configuration, we can remove the temporary
160             # Jifty::DBI::Record baseclass for records and insert our "real" baseclass,
161             # which is likely Record::Cachable or Record::Memcached
162             @Jifty::Record::ISA = grep { $_ ne 'Jifty::DBI::Record' } @Jifty::Record::ISA;
163              
164             # Configure the base class used by Jifty models
165             my $record_base_class = Jifty->config->framework('Database')->{'RecordBaseClass'};
166             Jifty::Util->require( $record_base_class );
167             push @Jifty::Record::ISA, $record_base_class unless $record_base_class eq 'Jifty::Record';
168              
169             # Configure the base class for Jifty::CAS
170             @Jifty::CAS::ISA = grep { $_ ne 'Jifty::CAS::Store' } @Jifty::CAS::ISA;
171             my $cas_base = Jifty->config->framework('CAS')->{'BaseClass'};
172             Jifty::Util->require( $cas_base );
173             push @Jifty::CAS::ISA, $cas_base unless $cas_base eq 'Jifty::CAS';
174              
175             # Logger turn on
176             Jifty->logger( Jifty::Logger->new( $args{'logger_component'} ) );
177              
178             # Set up plugins
179             my @plugins;
180             my @plugins_to_load = @{Jifty->config->framework('Plugins')};
181             my $app_plugin = Jifty->app_class('Plugin');
182             # we are pushing prereq to plugin, hence the 3-part for.
183             for (my $i = 0; my $plugin = $plugins_to_load[$i]; $i++) {
184             my $is_prereq = delete $plugin->{_prereq};
185              
186             # Prepare to learn the plugin class name
187             my ($plugin_name) = keys %{$plugin};
188             my $class;
189              
190             # Is the plugin name a fully-qualified class name?
191             if ($plugin_name =~ /^(?:Jifty::Plugin|$app_plugin)::/) {
192             # app-specific plugins use fully qualified names, Jifty plugins may
193             $class = $plugin_name;
194             }
195              
196             # otherwise, assume it's a short name, qualify it
197             else {
198             $class = "Jifty::Plugin::".$plugin_name;
199             }
200              
201             # avoid duplicating prereq plugins. we can't do this in the loop below
202             # because a plugin might prereq a plugin later in config.yml
203             if ($is_prereq) {
204             my $this_class = qr/^(?:Jifty::Plugin::|\Q$app_plugin\E)?\Q$plugin_name\E$/;
205              
206             next if grep { $_ =~ $this_class } @plugins_to_load;
207              
208             # already loaded plugin objects
209             next if grep { ref($_) =~ $this_class } @plugins;
210             }
211              
212             # Load the plugin options
213             my %options = (%{ $plugin->{ $plugin_name } },
214             _pre_init => $args{'pre_init'} );
215              
216             # Load the plugin code
217             Jifty::Util->require($class);
218             Jifty::ClassLoader->new(base => $class)->require;
219              
220             # Initialize the plugin and mark the prerequisites for loading too
221             my $plugin_obj = $class->new(%options);
222             push @plugins, $plugin_obj;
223             foreach my $name ($plugin_obj->prereq_plugins) {
224             push @plugins_to_load, {$name => {}, _prereq => 1};
225             }
226             }
227              
228             # All plugins loaded, save them for later reference
229             Jifty->plugins(@plugins);
230              
231             # Now that we have the config set up and loaded plugins,
232             # load the localization files.
233             Jifty::I18N->refresh();
234            
235             # Get a classloader set up
236             my $class_loader = Jifty::ClassLoader->new(
237             base => Jifty->app_class,
238             );
239              
240             # Save the class loader for later reference
241             Jifty->class_loader($class_loader);
242             $class_loader->require;
243              
244             # Configure the request handler and action API handler
245             Jifty->handler(Jifty::Handler->new()) unless Jifty->handler;
246             Jifty->api(Jifty::API->new()) unless Jifty->api;
247              
248             # We can only require view classes once we have our models and actions set.
249             $class_loader->require_views;
250              
251             # Let's get the database rocking and rolling
252             Jifty->setup_database_connection(%args);
253              
254             # Call the application's start method to let it do anything
255             # application specific for startup
256             my $app = Jifty->app_class;
257            
258             # Run the App::start() method if it exists for app-specific initialization
259             $app->start
260             if not $args{no_handle} and $app->can('start');
261              
262             # For plugins that want all the above initialization, but want to run before
263             # we begin serving requests
264             Jifty->call_trigger('post_init');
265             }
266              
267             # Explicitly destroy the classloader; if this happens during global
268             # destruction, there's a period of time where there's a bogus entry in
269             # @INC
270             END {
271             Jifty->class_loader->DESTROY if Jifty->class_loader;
272             }
273              
274             =head2 config
275              
276             An accessor for the L object that stores the
277             configuration for the Jifty application.
278              
279             =cut
280              
281             sub config {
282             my $class = shift;
283             $CONFIG = shift if (@_);
284             $CONFIG ||= Jifty::Config->new();
285             return $CONFIG;
286             }
287              
288             =head2 logger
289              
290             An accessor for our L object for the application.
291              
292             You probably aren't interested in this. See L for information on how to
293             make log messages.
294              
295             =cut
296              
297             sub logger {
298             my $class = shift;
299             $LOGGER = shift if (@_);
300             return $LOGGER;
301             }
302              
303             =head2 handler
304              
305             An accessor for our L object.
306              
307             This is another method that you usually don't want to mess with too much.
308             Most of the interesting web bits are handled by L.
309              
310             =cut
311              
312             sub handler {
313             my $class = shift;
314             $HANDLER = shift if (@_);
315             return $HANDLER;
316             }
317              
318             =head2 handle
319              
320             An accessor for the L object that stores the database
321             handle for the application.
322              
323             =cut
324              
325             sub handle {
326             my $class = shift;
327             $HANDLE = shift if (@_);
328             return $HANDLE;
329             }
330              
331             =head2 api
332              
333             An accessor for the L object that publishes and controls
334             information about the application's Ls.
335              
336             =cut
337              
338             sub api {
339             my $class = shift;
340             $API = shift if (@_);
341             return $API;
342             }
343              
344             =head2 app_class(@names)
345              
346             Return Class in application space. For example C
347             returns YourApp::Model::Foo.
348              
349             By the time you get it back, the class will have already been required
350              
351             Is you pass a hashref as the first argument, it will be treated as
352             configuration parameters. The only existing parameter is C,
353             which defaults to true.
354              
355             =cut
356              
357             sub app_class {
358             shift;
359             my $args = (ref $_[0] ? shift : { require => 1 });
360             my $val = join('::', Jifty->config->framework('ApplicationClass'), @_);
361             Jifty::Util->try_to_require($val) if $args->{require};
362             return $val;
363             }
364              
365             =head2 web
366              
367             An accessor for the L object that the web interface uses.
368              
369             =cut
370              
371             sub web {
372             return $Jifty::WEB ||= Jifty::Web->new();
373             }
374              
375             =head2 subs
376              
377             An accessor for the L object that the subscription uses.
378              
379             =cut
380              
381             sub subs {
382             return Jifty::Subs->new;
383             }
384              
385             =head2 bus
386              
387             Returns an IPC::PubSub object for the current application.
388              
389             =cut
390              
391             sub bus {
392             my $class = shift;
393             my %args = ( connect => 1, @_ );
394             if (not $PUB_SUB and $args{connect}) {
395             my @args;
396              
397             my $backend = Jifty->config->framework('PubSub')->{'Backend'};
398             if ( $backend eq 'Memcached' ) {
399             require IO::Socket::INET;
400              
401             # If there's a running memcached on the default port. this should become configurable
402             if ( IO::Socket::INET->new('127.0.0.1:11211') ) {
403             @args = ( Jifty->app_instance_id );
404             } else {
405             $backend = 'JiftyDBI';
406             }
407             }
408            
409             if ($backend eq 'JiftyDBI' and Jifty->handle ) {
410             @args = (
411             db_config => Jifty->handle->{db_config},
412             table_prefix => '_jifty_pubsub_',
413             );
414             }
415             $PUB_SUB = IPC::PubSub->new( $backend => @args );
416              
417             }
418             return $PUB_SUB;
419             }
420              
421             =head2 plugins
422              
423             Returns a list of L objects for this Jifty application.
424              
425             =cut
426              
427             sub plugins {
428             my $class = shift;
429             @PLUGINS = @_ if @_;
430             return @PLUGINS;
431             }
432              
433             =head2 find_plugin
434              
435             Find plugins by name.
436              
437             =cut
438              
439             sub find_plugin {
440             my $self = shift;
441             my $name = shift;
442              
443             my @plugins = grep { $_->isa($name) } Jifty->plugins;
444             return wantarray ? @plugins : $plugins[0];
445             }
446              
447             =head2 class_loader
448              
449             An accessor for the L object that stores the loaded
450             classes for the application.
451              
452             =cut
453              
454             sub class_loader {
455             my $class = shift;
456             $CLASS_LOADER = shift if (@_);
457             return $CLASS_LOADER;
458             }
459              
460             =head2 setup_database_connection
461              
462             Set up our database connection. Optionally takes a paramhash with a
463             single argument. This method is automatically called by L.
464              
465             =over
466              
467             =item no_handle
468              
469             Defaults to false. If true, Jifty won't try to set up a database handle
470              
471             =item pre_init
472              
473             Defaults to false. If true, plugins are notified that this is a
474             pre-init, any trigger registration in C should not happen
475             during this stage. Note that model mixins' C is
476             unrelated to this.
477              
478             =back
479              
480              
481             If C is set or our application's config file is missing a C configuration
482             section or I a C directive in its framework configuration, does nothing.
483              
484             =cut
485              
486             sub setup_database_connection {
487             my $self = shift;
488             my %args = (no_handle => 0,
489             check_opts => {},
490             @_);
491              
492             # Don't setup the database connection if we're told not to
493             unless ( $args{'no_handle'}
494             or Jifty->config->framework('SkipDatabase')
495             or not Jifty->config->framework('Database') )
496             {
497              
498             # Load the application's database handle and connect
499             my $handle_class = Jifty->app_class("Handle");
500             Jifty::Util->require( $handle_class );
501             Jifty->handle( $handle_class->new );
502             Jifty->handle->connect();
503              
504             # Clean out any stale Cache::Memcached connections
505             $Jifty::DBI::Record::Memcached::MEMCACHED->disconnect_all
506             if $Jifty::DBI::Record::Memcached::MEMCACHED;
507              
508             # Make sure the app version matches the database version
509             Jifty->handle->check_schema_version(%{$args{'check_opts'}})
510             unless $args{'no_version_check'};
511             }
512             }
513              
514              
515             =head2 app_instance_id
516              
517             Returns a globally unique id for this instance of this jifty
518             application. This value is generated the first time it's accessed
519              
520             =cut
521              
522             sub app_instance_id {
523             my $self = shift;
524             my $app_instance_id = Jifty::Model::Metadata->load("application_instance_uuid");
525             unless ($app_instance_id) {
526             require Data::UUID;
527             $app_instance_id = Data::UUID->new->create_str();
528             Jifty::Model::Metadata->store(application_instance_uuid => $app_instance_id );
529             }
530             return $app_instance_id;
531             }
532              
533             =head2 background SUB
534              
535             Forks a background process, and ensures that database connections and
536             sockets are not shared with the parent process.
537              
538             =cut
539              
540             sub background {
541             my $class = shift;
542             my $sub = shift;
543             if (my $pid = fork) {
544             return $pid;
545             } else {
546             close STDOUT;
547             close STDIN;
548             # XXX: make $Jifty::SERVER close client sockets if exists
549             Jifty->handle->dbh->{InactiveDestroy} = 1;
550             Jifty->setup_database_connection();
551             $sub->();
552             exit;
553             }
554             }
555              
556             =head2 admin_mode
557              
558             Returns true if the application is in admin mode. This should be used instead
559             of C<< Jifty->config->framework('AdminMode') >>.
560              
561             =cut
562              
563             sub admin_mode {
564             return Jifty->config->framework('AdminMode')
565             || Jifty->config->framework('SetupMode');
566             }
567              
568             =head1 SEE ALSO
569              
570             L, L, L, L, L, L, L, L, L, L, L, L, L
571              
572             =head1 AUTHORS
573              
574             Jesse Vincent, Alex Vandiver and David Glasser.
575              
576             =head1 LICENSE
577              
578             Jifty is Copyright 2005-2010 Best Practical Solutions, LLC.
579             Jifty is distributed under the same terms as Perl itself.
580              
581              
582              
583             =cut
584              
585             1;