diff Lib/DOM/Providers/Page.pm @ 0:03e58a454b20

Создан репозитарий
author Sergey
date Tue, 14 Jul 2009 12:54:37 +0400
parents
children 16ada169ca75
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/DOM/Providers/Page.pm	Tue Jul 14 12:54:37 2009 +0400
@@ -0,0 +1,258 @@
+use strict;
+
+package DOM::Providers::Page;
+use Template::Provider;
+#use PerfCounter;
+use DOM::Page;
+use Common;
+use Encode;
+
+our @ISA= qw(Object Exporter);
+
+our $UseIndexPage;  #optional
+our $PagesPath;     #required
+our $IncludesPath;  #optional
+our $CacheSize;     #optional
+our $CachePath;     #optional
+our $Encoding;      #optional
+our $AllowExtPath;  #optional
+our $PageResolver;  #optional
+
+
+BEGIN {
+    DeclareProperty('PageResolver');
+    DeclareProperty('PagesBase');
+    DeclareProperty('IndexPage');
+    DeclareProperty('TemplatesProvider');
+    DeclareProperty('PageEnc');
+}
+
+sub as_list {
+    return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ );
+}
+
+sub GetProviderInfo {
+    return {
+        Name => 'Page',
+        Host => 'DOM::Site',
+        Methods => {
+            LoadPage => \&SiteLoadPage,
+            ReleasePage => \&SiteReleasePage,
+        }
+    }
+}
+
+sub CTOR {
+    my ($this,%args) = @_;
+    
+    $this->{$PageResolver} = $args{'PageResolver'};
+    $this->{$PagesBase} = $args{'TemplatesPath'};
+    $this->{$IndexPage} = $args{'IndexPage'} || 'index.html';
+    $this->{$PageEnc} = $args{'Encoding'};
+    $this->{$TemplatesProvider} = new Template::Provider( INCLUDE_PATH => [$this->{$PagesBase}, as_list($args{'IncludePath'}) ], COMPILE_DIR => $args{'CachePath'}, CACHE_SIZE => $args{'CacheSize'}, ENCODING => $args{'Encoding'}, ABSOLUTE => $AllowExtPath, RELATIVE => $AllowExtPath, INTERPOLATE => 1, PRE_CHOMP => 3);
+}
+
+sub ResolveId {
+    my ($this,$pageId) = @_;
+    
+    if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'ResolveId')) {
+        return $this->{$PageResolver}->ResolveId($pageId);
+    } else {
+        return grep { $_ } split /\//,$pageId;
+    }
+}
+
+sub MakePageId {
+    my ($this,$raPath) = @_;
+    
+    if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'MakeId')) {
+        return $this->{$PageResolver}->MakeId($raPath);
+    } else {
+        return join '/',@$raPath;
+    }
+}
+
+sub PageIdToURL {
+    my ($this,$pageId) = @_;
+    
+    if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'PageIdToURL')) {
+        return $this->{$PageResolver}->PageIdToURL($pageId);
+    } else {
+        return '/'.$pageId;
+    }
+}
+
+sub SiteLoadPage {
+    my ($this,$site,$pageId) = @_;
+    
+    return $site->RegisterObject('Page', $this->LoadPage($pageId, Site => $site));
+}
+sub LoadPage {
+    my ($this,$pageId,%args) = @_;
+    
+    #StartTimeCounter('LoadPageTime');
+
+    my @pathPage = $this->ResolveId($pageId);
+
+    my $pageNode = $this->LoadNode(\@pathPage);
+    
+    pop @pathPage;
+    
+    my @pathNode;
+    
+    # ïîñêîëüêó ïóòü óêàçàí îòíîñèòåëüíî êîðíåâîãî êîíòåéíåðà, òî íóæíî åãî äîáàâèòü â íà÷àëî
+    my @NavChain = map { push @pathNode, $_; $this->LoadNode(\@pathNode); } ('.',@pathPage);
+    
+    if ($pageNode->{'Type'} eq 'Section') {
+        push @NavChain,$pageNode;
+        $pageNode = $this->LoadNode($pageNode->{'pathIndexPage'});
+    }
+    
+    # ôîðìèðóåì ìåíþ ñòðàíèöû
+    my %PageMenus;
+    foreach my $MenuSet (map { $_->{'Menus'}} @NavChain, $pageNode->{'Menus'} ) {
+        foreach my $menuName (keys %$MenuSet) {
+            if ($PageMenus{$menuName}) {
+                $PageMenus{$menuName}->Merge($MenuSet->{$menuName});
+            } else {
+                $PageMenus{$menuName} = $MenuSet->{$menuName};
+            }
+        }
+    }
+    
+    # ôîðìèðóåì êëþ÷åâûå ñëîâà è ñâîéñòâà
+    my @keywords;
+    my %Props;
+    foreach my $PropSet ( (map { $_->{'Props'}} @NavChain), $pageNode->{'Props'} ) {
+        if(ref $PropSet->{'Keywords'} eq 'ARRAY') {
+            push @keywords, @{$PropSet->{'Keywords'}};
+        } elsif (not ref $PropSet->{'Keywords'} and exists $PropSet->{'Keywords'}) {
+            push @keywords, $PropSet->{'Keywords'};
+        }
+        
+        while (my ($prop,$value) = each %$PropSet) {
+            next if $prop eq 'Keywords';
+            $Props{$prop} = $value;
+        }
+    }
+        
+    #StopTimeCounter('LoadPageTime');
+    # çàãðóæàåì øàáëîí
+    
+    #StartTimeCounter('FetchTime');
+    my ($Template,$error) = $this->{$TemplatesProvider}->fetch($pageNode->{'TemplateFileName'});
+    die new Exception("Failed to load page $pageId",$Template ? $Template->as_string : 'Failed to parse') if $error;
+    #StopTimeCounter('FetchTime');
+    
+    my $page = new DOM::Page(TemplatesProvider => $this->{$TemplatesProvider}, Properties => \%Props, Menus => \%PageMenus, NavChain => \@NavChain, Template => $Template, %args);
+    $page->Properties->{url} = $this->PageIdToURL($pageId);
+    return $page;
+}
+
+sub LoadNode {
+    my ($this,$refNodePath) = @_;
+    
+    my $fileNameNode = $this->{$PagesBase} . join('/',grep $_, @$refNodePath);
+    my $fileNameMenus;
+    my $fileNameProps; 
+    
+    my %Node;
+
+    if ( -d $fileNameNode ) {
+        $Node{'Type'} = 'Section';
+        $fileNameMenus = $fileNameNode . '/.menu.pl';
+        $fileNameProps = $fileNameNode . '/.prop.pl';
+    } elsif ( -e $fileNameNode ) {
+        $Node{'Type'} = 'Page';
+        $Node{'TemplateFileName'} = join('/',@$refNodePath);;
+        $fileNameMenus = $fileNameNode . '.menu.pl';
+        $fileNameProps = $fileNameNode . '.prop.pl';
+    } else {
+        die new Exception("Page not found: $fileNameNode");
+    }
+    
+    if ( -f $fileNameProps ) {
+        local ${^ENCODING};
+        my $dummy = '';
+        open my $hnull,'>>',\$dummy;
+        local (*STDOUT,*STDIN) = ($hnull,$hnull);
+        $Node{'Props'} = do $fileNameProps or warn "can't parse $fileNameProps: $@";
+    }
+    
+    if ( -f $fileNameMenus ) {
+        local ${^ENCODING};
+        my $dummy = '';
+        open my $hnull,'>>',\$dummy;
+        local (*STDOUT,*STDIN) = ($hnull,$hnull);
+        $Node{'Menus'} = do $fileNameMenus or warn "can't parse $fileNameMenus: $@";
+    }
+    
+    if ($Node{'Menus'}) {
+        my %Menus;
+        foreach my $menu (keys %{$Node{'Menus'}}) {
+            $Menus{$menu} = new DOM::PageMenu( DATA => $Node{'Menus'}->{$menu} );
+        }
+        $Node{'Menus'} = \%Menus;
+    }
+    
+    $Node{'pathIndexPage'} = [@$refNodePath, $Node{'Props'}->{'IndexPage'} || $this->{$IndexPage}] if $Node{'Type'} eq 'Section';
+    
+    return \%Node;
+}
+
+sub SiteReleasePage {
+    my ($this,$site) = @_;
+    
+    my $page = $site->Objects()->{'Page'};
+    $page->Release() if $page;
+    
+    return 1;
+}
+
+sub construct {
+    my $self = shift;
+    
+    return new DOM::Providers::Page(TemplatesPath => $PagesPath, IncludePath => $IncludesPath, IndexPage => $UseIndexPage, CachePath => $CachePath, CacheSize => $CacheSize, Encoding => $Encoding);
+}
+
+sub DecodeData {
+    my ($Encoding, $data) = @_;
+    
+    if (ref $data) {
+        if (ref $data eq 'SCALAR') {
+            my $decoded = Encode::decode($Encoding,$$data,Encode::LEAVE_SRC);
+            return \$decoded;
+        } elsif (UNIVERSAL::isa($data, 'HASH')) {
+            return {map {Encode::decode($Encoding,$_,Encode::LEAVE_SRC),DecodeData($Encoding,$data->{$_})} keys %$data };
+        } elsif (UNIVERSAL::isa($data, 'ARRAY')) {
+            return [map {DecodeData($Encoding,$_)} @$data];
+        } elsif (ref $data eq 'REF') {
+            my $decoded = DecodeData($Encoding,$$data);
+            return \$decoded;
+        } else {
+            die new Exception('Cant decode data type', ref $data);
+        }
+    } else {
+        return Encode::decode($Encoding,$data,Encode::LEAVE_SRC);
+    }
+}
+
+1;
+
+=pod
+Õðàíèëèùå øàáëîíîâ íà îñíîâå ôàéëîâîé ñèñòåìû.
+
+Õðàíèëèùå ñîñòîèò èç ðàçäåëîâ, êàæäûé ðàçäåë èìååò íàáîð ñâîéñòâ è ìåíþ
+Ñïåöèàëüíû ñâîéñòâà ðàçäåëîâ
+    Keywords Êëþ÷åâûå ñëîâà
+    Name Íàçâàíèå
+    IndexPage ñòðàíèöà ïî óìîë÷àíèþ
+
+Â ðàçäåëàõ íàõîäÿòñÿ ñòðàíèöû, êàæäàÿ ñòðàíèöà èìååò íàáîð ñâîéñòâ è ìåíþ
+
+Ïðè çàãðóçêå ñòðàíèöû ïîëíîñòüþ çàãðóæàþòñÿ âñå ðîäèòåëüñêèå êîíòåéíåðû,
+Ïðè ýòîì îäíîèìåííûå ìåíþ ñëèâàþòñÿ,
+Ñâîéñòâà keywords îáúåúåäèíÿþòñÿ,
+Åñëè èìÿ ñòðàíèöû íå çàäàíî, òî èñïîëüçóåòñÿ èìÿ ðàçäåëà
+
+=cut
\ No newline at end of file