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