Apache-Voodoo/lib/Apache/Voodoo/Application.pm
package Apache::Voodoo::Application;
$VERSION = "3.0200";
use strict;
use warnings;
use Apache::Voodoo::Constants;
use Apache::Voodoo::Application::ConfigParser;
use Apache::Voodoo::Session;
use Apache::Voodoo::Debug;
use Data::Dumper;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
# $self->{'debug'} = 1;
$self->{'id'} = shift;
$self->{'constants'} = shift || Apache::Voodoo::Constants->new();
die "ID is a required parameter." unless (defined($self->{'id'}));
$self->{'parser'} = Apache::Voodoo::Application::ConfigParser->new($self->{'id'},$self->{'constants'});
$self->refresh(1);
return $self;
}
sub config {
return $_[0]->{'parser'}->config();
}
sub databases {
return $_[0]->{'parser'}->databases();
}
sub bootstrapped {
my $self = shift;
$self->{debug_handler}->bootstrapped();
}
sub refresh {
my $self = shift;
my $initial = shift;
# If this is the initial load, or the config file has changed continue.
unless ($initial || $self->{'parser'}->changed()) {
return;
}
my $config = $self->{'parser'};
my %old_m = %{$config->models()};
my %old_v = %{$config->views()};
my %old_c = %{$config->controllers()};
my %old_i = %{$config->includes()};
my $old_ns = $config->old_ns();
$config->parse();
$self->_reload_modules('m',\%old_m,$config->models());
$self->_reload_modules('v',\%old_v,$config->views());
if (defined($old_ns) && $old_ns != $config->old_ns()) {
# They've swapped from the old style name for controller to the new syle
# (or vice versa). Drop all the old controllers.
$self->_debug("**Controller namespace has changed**");
foreach (keys %{$self->{'controllers'}}) {
$self->_debug("Removing old module: $_");
delete $self->{'controllers'}->{$_};
}
%old_c = ();
%old_i = ();
}
# load the new includes
$self->_reload_modules('c',\%old_i,$config->includes());
foreach (sort keys %{$config->controllers()}) {
unless (exists($old_c{$_})) {
# new module
$self->_debug("Adding new module: $_");
$self->_prep_page_module($_);
}
delete $old_c{$_};
}
foreach (keys %old_c) {
$self->_debug("Removing old module: $_");
delete $self->{'controllers'}->{$_};
}
# If they didn't define their own HTML view, then we'll use our own;
# this is a web server after all :)
unless (defined($self->{'views'}->{'HTML'})) {
require Apache::Voodoo::View::HTML;
$self->{'views'}->{'HTML'} = Apache::Voodoo::View::HTML->new();
}
# Same idea for JSON. What website these days doesn't use even
# a little AJAX?
unless (defined($self->{'views'}->{'JSON'})) {
require Apache::Voodoo::View::JSON;
$self->{'views'}->{'JSON'} = Apache::Voodoo::View::JSON->new();
}
# models get the config and every model except themselves
# to prevent accidental circular references
foreach my $key (keys %{$self->{'models'}}) {
my %m = map { $_ => $self->{models}->{$_} }
grep { $_ ne $key }
keys %{$self->{'models'}};
eval {
$self->{models}->{$key}->init($config->config(),\%m);
};
if ($@) {
warn "$@\n";
$self->{'errors'}++;
}
}
# views get just the config
foreach (values %{$self->{'views'}}) {
eval {
$_->init($config->config());
};
if ($@) {
warn "$@\n";
$self->{'errors'}++;
}
}
# controllers get the config and all the models
foreach (values %{$self->{'controllers'}}) {
eval {
$_->init($config->config(),$self->{'models'});
};
if ($@) {
warn "$@\n";
$self->{'errors'}++;
}
}
eval {
$self->{'session_handler'} = Apache::Voodoo::Session->new($config->config());
};
if ($@) {
warn "$@\n";
$self->{'errors'}++;
}
eval {
$self->{'debug_handler'} = Apache::Voodoo::Debug->new($config->config());
};
if ($@) {
warn "$@\n";
$self->{'errors'}++;
}
}
sub map_uri {
my $self = shift;
my $uri = shift;
if (defined($self->{'controllers'}->{$uri})) {
return [$uri,"handle"];
}
else {
no warnings 'uninitialized';
my $p='';
my $m='';
my $o='';
($p,$m,$o) = ($uri =~ /^(.*?)([a-z]+)_(\w+)$/);
return ["$p$o",$m];
}
}
sub resolve_conf_section {
my $self = shift;
my $uri = shift;
my $template_conf = $self->{'parser'}->template_conf();
if (exists($template_conf->{$uri})) {
# one specific to this page
return $template_conf->{$uri};
}
foreach (sort { length($b) <=> length($a) } keys %{$template_conf}) {
if ($uri =~ /^$_$/) {
# match by uri regexp
return $template_conf->{$_};
}
}
# not one, return the default
return $template_conf->{'default'};
}
sub _reload_modules {
my $self = shift;
my $ns = shift;
my $old = shift;
my $new = shift;
# check the new list of modules against the old list
foreach (sort keys %{$new}) {
unless (exists($old->{$_})) {
# new module (wasn't in the old list).
$self->_debug("Adding new $ns module: $_");
$self->_prep_module($ns,$_);
}
# still a valid module, so remove it from this list.
delete $old->{$_};
}
# whatever is left in old are ones that weren't in the new list.
foreach (keys %{$old}) {
$self->_debug("Removing old module: $_");
$_ =~ s/::/\//g;
delete $self->{'controllers'}->{$_};
}
}
sub _prep_module {
my $self = shift;
my $ns = shift;
my $module = shift;
my $obj = $self->_load_module($ns,$module);
$ns = ($ns eq "m")?"models":
($ns eq "v")?"views":"controllers";
$self->{$ns}->{$module} = $obj;
}
sub _prep_page_module {
my $self = shift;
my $module = shift;
my $obj = $self->_load_module('c',$module);
$module =~ s/::/\//g;
$self->{'controllers'}->{$module} = $obj;
}
sub _load_module {
my $self = shift;
my $ns = shift;
my $module = shift;
unless ($ns eq "c" and $self->{'parser'}->old_ns()) {
$module = uc($ns)."::".$module;
}
$module = $self->{'parser'}->config()->{'base_package'}."::".$module;
my $obj;
if ($self->{'parser'}->config()->{'dynamic_loading'}) {
require Apache::Voodoo::Loader::Dynamic;
$obj = Apache::Voodoo::Loader::Dynamic->new($module);
}
else {
require Apache::Voodoo::Loader::Static;
$obj = Apache::Voodoo::Loader::Static->new($module);
if (ref($obj) eq "Apache::Voodoo::Zombie") {
# doh! the module went boom
$self->{'errors'}++;
}
}
return $obj;
}
sub _debug {
my $self = shift;
return unless $self->{'debug'};
if (ref($_[0])) {
warn Dumper(@_);
}
else {
warn join("\n",@_),"\n";
}
}
1;
################################################################################
# Copyright (c) 2005-2010 Steven Edwards (maverick@smurfbane.org).
# All rights reserved.
#
# You may use and distribute Apache::Voodoo under the terms described in the
# LICENSE file include in this package. The summary is it's a legalese version
# of the Artistic License :)
#
################################################################################