Mercurial > pub > Impl
diff Lib/DOM/Providers/Page.pm @ 49:16ada169ca75
migrating to the Eclipse IDE
author | wizard@linux-odin.local |
---|---|
date | Fri, 26 Feb 2010 10:49:21 +0300 |
parents | 03e58a454b20 |
children |
line wrap: on
line diff
--- a/Lib/DOM/Providers/Page.pm Fri Feb 26 01:43:42 2010 +0300 +++ b/Lib/DOM/Providers/Page.pm Fri Feb 26 10:49:21 2010 +0300 @@ -1,258 +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 +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