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

Создан репозитарий
author Sergey
date Tue, 14 Jul 2009 12:54:37 +0400 (2009-07-14)
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