Mercurial > pub > Impl
comparison Lib/DOM/Providers/Page.pm @ 0:03e58a454b20
Создан репозитарий
| author | Sergey | 
|---|---|
| date | Tue, 14 Jul 2009 12:54:37 +0400 | 
| parents | |
| children | 16ada169ca75 | 
   comparison
  equal
  deleted
  inserted
  replaced
| -1:000000000000 | 0:03e58a454b20 | 
|---|---|
| 1 use strict; | |
| 2 | |
| 3 package DOM::Providers::Page; | |
| 4 use Template::Provider; | |
| 5 #use PerfCounter; | |
| 6 use DOM::Page; | |
| 7 use Common; | |
| 8 use Encode; | |
| 9 | |
| 10 our @ISA= qw(Object Exporter); | |
| 11 | |
| 12 our $UseIndexPage; #optional | |
| 13 our $PagesPath; #required | |
| 14 our $IncludesPath; #optional | |
| 15 our $CacheSize; #optional | |
| 16 our $CachePath; #optional | |
| 17 our $Encoding; #optional | |
| 18 our $AllowExtPath; #optional | |
| 19 our $PageResolver; #optional | |
| 20 | |
| 21 | |
| 22 BEGIN { | |
| 23 DeclareProperty('PageResolver'); | |
| 24 DeclareProperty('PagesBase'); | |
| 25 DeclareProperty('IndexPage'); | |
| 26 DeclareProperty('TemplatesProvider'); | |
| 27 DeclareProperty('PageEnc'); | |
| 28 } | |
| 29 | |
| 30 sub as_list { | |
| 31 return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ ); | |
| 32 } | |
| 33 | |
| 34 sub GetProviderInfo { | |
| 35 return { | |
| 36 Name => 'Page', | |
| 37 Host => 'DOM::Site', | |
| 38 Methods => { | |
| 39 LoadPage => \&SiteLoadPage, | |
| 40 ReleasePage => \&SiteReleasePage, | |
| 41 } | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 sub CTOR { | |
| 46 my ($this,%args) = @_; | |
| 47 | |
| 48 $this->{$PageResolver} = $args{'PageResolver'}; | |
| 49 $this->{$PagesBase} = $args{'TemplatesPath'}; | |
| 50 $this->{$IndexPage} = $args{'IndexPage'} || 'index.html'; | |
| 51 $this->{$PageEnc} = $args{'Encoding'}; | |
| 52 $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); | |
| 53 } | |
| 54 | |
| 55 sub ResolveId { | |
| 56 my ($this,$pageId) = @_; | |
| 57 | |
| 58 if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'ResolveId')) { | |
| 59 return $this->{$PageResolver}->ResolveId($pageId); | |
| 60 } else { | |
| 61 return grep { $_ } split /\//,$pageId; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 sub MakePageId { | |
| 66 my ($this,$raPath) = @_; | |
| 67 | |
| 68 if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'MakeId')) { | |
| 69 return $this->{$PageResolver}->MakeId($raPath); | |
| 70 } else { | |
| 71 return join '/',@$raPath; | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 sub PageIdToURL { | |
| 76 my ($this,$pageId) = @_; | |
| 77 | |
| 78 if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'PageIdToURL')) { | |
| 79 return $this->{$PageResolver}->PageIdToURL($pageId); | |
| 80 } else { | |
| 81 return '/'.$pageId; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 sub SiteLoadPage { | |
| 86 my ($this,$site,$pageId) = @_; | |
| 87 | |
| 88 return $site->RegisterObject('Page', $this->LoadPage($pageId, Site => $site)); | |
| 89 } | |
| 90 sub LoadPage { | |
| 91 my ($this,$pageId,%args) = @_; | |
| 92 | |
| 93 #StartTimeCounter('LoadPageTime'); | |
| 94 | |
| 95 my @pathPage = $this->ResolveId($pageId); | |
| 96 | |
| 97 my $pageNode = $this->LoadNode(\@pathPage); | |
| 98 | |
| 99 pop @pathPage; | |
| 100 | |
| 101 my @pathNode; | |
| 102 | |
| 103 # ïîñêîëüêó ïóòü óêàçàí îòíîñèòåëüíî êîðíåâîãî êîíòåéíåðà, òî íóæíî åãî äîáàâèòü â íà÷àëî | |
| 104 my @NavChain = map { push @pathNode, $_; $this->LoadNode(\@pathNode); } ('.',@pathPage); | |
| 105 | |
| 106 if ($pageNode->{'Type'} eq 'Section') { | |
| 107 push @NavChain,$pageNode; | |
| 108 $pageNode = $this->LoadNode($pageNode->{'pathIndexPage'}); | |
| 109 } | |
| 110 | |
| 111 # ôîðìèðóåì ìåíþ ñòðàíèöû | |
| 112 my %PageMenus; | |
| 113 foreach my $MenuSet (map { $_->{'Menus'}} @NavChain, $pageNode->{'Menus'} ) { | |
| 114 foreach my $menuName (keys %$MenuSet) { | |
| 115 if ($PageMenus{$menuName}) { | |
| 116 $PageMenus{$menuName}->Merge($MenuSet->{$menuName}); | |
| 117 } else { | |
| 118 $PageMenus{$menuName} = $MenuSet->{$menuName}; | |
| 119 } | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 # ôîðìèðóåì êëþ÷åâûå ñëîâà è ñâîéñòâà | |
| 124 my @keywords; | |
| 125 my %Props; | |
| 126 foreach my $PropSet ( (map { $_->{'Props'}} @NavChain), $pageNode->{'Props'} ) { | |
| 127 if(ref $PropSet->{'Keywords'} eq 'ARRAY') { | |
| 128 push @keywords, @{$PropSet->{'Keywords'}}; | |
| 129 } elsif (not ref $PropSet->{'Keywords'} and exists $PropSet->{'Keywords'}) { | |
| 130 push @keywords, $PropSet->{'Keywords'}; | |
| 131 } | |
| 132 | |
| 133 while (my ($prop,$value) = each %$PropSet) { | |
| 134 next if $prop eq 'Keywords'; | |
| 135 $Props{$prop} = $value; | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 #StopTimeCounter('LoadPageTime'); | |
| 140 # çàãðóæàåì øàáëîí | |
| 141 | |
| 142 #StartTimeCounter('FetchTime'); | |
| 143 my ($Template,$error) = $this->{$TemplatesProvider}->fetch($pageNode->{'TemplateFileName'}); | |
| 144 die new Exception("Failed to load page $pageId",$Template ? $Template->as_string : 'Failed to parse') if $error; | |
| 145 #StopTimeCounter('FetchTime'); | |
| 146 | |
| 147 my $page = new DOM::Page(TemplatesProvider => $this->{$TemplatesProvider}, Properties => \%Props, Menus => \%PageMenus, NavChain => \@NavChain, Template => $Template, %args); | |
| 148 $page->Properties->{url} = $this->PageIdToURL($pageId); | |
| 149 return $page; | |
| 150 } | |
| 151 | |
| 152 sub LoadNode { | |
| 153 my ($this,$refNodePath) = @_; | |
| 154 | |
| 155 my $fileNameNode = $this->{$PagesBase} . join('/',grep $_, @$refNodePath); | |
| 156 my $fileNameMenus; | |
| 157 my $fileNameProps; | |
| 158 | |
| 159 my %Node; | |
| 160 | |
| 161 if ( -d $fileNameNode ) { | |
| 162 $Node{'Type'} = 'Section'; | |
| 163 $fileNameMenus = $fileNameNode . '/.menu.pl'; | |
| 164 $fileNameProps = $fileNameNode . '/.prop.pl'; | |
| 165 } elsif ( -e $fileNameNode ) { | |
| 166 $Node{'Type'} = 'Page'; | |
| 167 $Node{'TemplateFileName'} = join('/',@$refNodePath);; | |
| 168 $fileNameMenus = $fileNameNode . '.menu.pl'; | |
| 169 $fileNameProps = $fileNameNode . '.prop.pl'; | |
| 170 } else { | |
| 171 die new Exception("Page not found: $fileNameNode"); | |
| 172 } | |
| 173 | |
| 174 if ( -f $fileNameProps ) { | |
| 175 local ${^ENCODING}; | |
| 176 my $dummy = ''; | |
| 177 open my $hnull,'>>',\$dummy; | |
| 178 local (*STDOUT,*STDIN) = ($hnull,$hnull); | |
| 179 $Node{'Props'} = do $fileNameProps or warn "can't parse $fileNameProps: $@"; | |
| 180 } | |
| 181 | |
| 182 if ( -f $fileNameMenus ) { | |
| 183 local ${^ENCODING}; | |
| 184 my $dummy = ''; | |
| 185 open my $hnull,'>>',\$dummy; | |
| 186 local (*STDOUT,*STDIN) = ($hnull,$hnull); | |
| 187 $Node{'Menus'} = do $fileNameMenus or warn "can't parse $fileNameMenus: $@"; | |
| 188 } | |
| 189 | |
| 190 if ($Node{'Menus'}) { | |
| 191 my %Menus; | |
| 192 foreach my $menu (keys %{$Node{'Menus'}}) { | |
| 193 $Menus{$menu} = new DOM::PageMenu( DATA => $Node{'Menus'}->{$menu} ); | |
| 194 } | |
| 195 $Node{'Menus'} = \%Menus; | |
| 196 } | |
| 197 | |
| 198 $Node{'pathIndexPage'} = [@$refNodePath, $Node{'Props'}->{'IndexPage'} || $this->{$IndexPage}] if $Node{'Type'} eq 'Section'; | |
| 199 | |
| 200 return \%Node; | |
| 201 } | |
| 202 | |
| 203 sub SiteReleasePage { | |
| 204 my ($this,$site) = @_; | |
| 205 | |
| 206 my $page = $site->Objects()->{'Page'}; | |
| 207 $page->Release() if $page; | |
| 208 | |
| 209 return 1; | |
| 210 } | |
| 211 | |
| 212 sub construct { | |
| 213 my $self = shift; | |
| 214 | |
| 215 return new DOM::Providers::Page(TemplatesPath => $PagesPath, IncludePath => $IncludesPath, IndexPage => $UseIndexPage, CachePath => $CachePath, CacheSize => $CacheSize, Encoding => $Encoding); | |
| 216 } | |
| 217 | |
| 218 sub DecodeData { | |
| 219 my ($Encoding, $data) = @_; | |
| 220 | |
| 221 if (ref $data) { | |
| 222 if (ref $data eq 'SCALAR') { | |
| 223 my $decoded = Encode::decode($Encoding,$$data,Encode::LEAVE_SRC); | |
| 224 return \$decoded; | |
| 225 } elsif (UNIVERSAL::isa($data, 'HASH')) { | |
| 226 return {map {Encode::decode($Encoding,$_,Encode::LEAVE_SRC),DecodeData($Encoding,$data->{$_})} keys %$data }; | |
| 227 } elsif (UNIVERSAL::isa($data, 'ARRAY')) { | |
| 228 return [map {DecodeData($Encoding,$_)} @$data]; | |
| 229 } elsif (ref $data eq 'REF') { | |
| 230 my $decoded = DecodeData($Encoding,$$data); | |
| 231 return \$decoded; | |
| 232 } else { | |
| 233 die new Exception('Cant decode data type', ref $data); | |
| 234 } | |
| 235 } else { | |
| 236 return Encode::decode($Encoding,$data,Encode::LEAVE_SRC); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 1; | |
| 241 | |
| 242 =pod | |
| 243 Õðàíèëèùå øàáëîíîâ íà îñíîâå ôàéëîâîé ñèñòåìû. | |
| 244 | |
| 245 Õðàíèëèùå ñîñòîèò èç ðàçäåëîâ, êàæäûé ðàçäåë èìååò íàáîð ñâîéñòâ è ìåíþ | |
| 246 Ñïåöèàëüíû ñâîéñòâà ðàçäåëîâ | |
| 247 Keywords Êëþ÷åâûå ñëîâà | |
| 248 Name Íàçâàíèå | |
| 249 IndexPage ñòðàíèöà ïî óìîë÷àíèþ | |
| 250 | |
| 251 Â ðàçäåëàõ íàõîäÿòñÿ ñòðàíèöû, êàæäàÿ ñòðàíèöà èìååò íàáîð ñâîéñòâ è ìåíþ | |
| 252 | |
| 253 Ïðè çàãðóçêå ñòðàíèöû ïîëíîñòüþ çàãðóæàþòñÿ âñå ðîäèòåëüñêèå êîíòåéíåðû, | |
| 254 Ïðè ýòîì îäíîèìåííûå ìåíþ ñëèâàþòñÿ, | |
| 255 Ñâîéñòâà keywords îáúåúåäèíÿþòñÿ, | |
| 256 Åñëè èìÿ ñòðàíèöû íå çàäàíî, òî èñïîëüçóåòñÿ èìÿ ðàçäåëà | |
| 257 | |
| 258 =cut | 
