Line # Revision Author
1 8 ahitrov@rambler.ru package Contenido::Init;
2
3 # ----------------------------------------------------------------------------
4 # Здесь будут храниться все инициализирующие методы Contenido...
5 # Это НЕ объект, это просто пакет с процедурами...
6 # ----------------------------------------------------------------------------
7
8 use strict;
9 use warnings;
10 use locale;
11
12 use vars qw($VERSION);
13 $VERSION = '4.1';
14
15 # Подключение модулей... общих...
16 use Utils;
17 use IO::File;
18 use Image::Size;
19 use Data::Dumper;
20 use Convert::Cyrillic;
21 use POSIX qw(:locale_h);
22
23
24 # Подключение модулей Contenido...
25 use Contenido::Globals;
26 use Contenido::Logger;
27 use Contenido::User;
28 use Contenido::Project;
29 use Contenido::Request;
30 use Contenido::State;
31 use Contenido::Document;
32 use Contenido::Link;
33 use Contenido::Section;
34 use Contenido::Keeper;
35 use Contenido::Image;
36 # Типы данных
37 use Contenido::Type::File;
38
39 # Процедура возвращает модульную структуру Contenido/ElTexto/Arte
40 # По идее именно она должна патчиться, если нужно просканировать дополнительные директории.
41 sub module_structure {
42 return (
43 ['documents', 'модули документов', 'Contenido::Document'],
44 ['sections', 'модули секций', 'Contenido::Section'],
45 ['users', 'модули пользователей', 'Contenido::User'],
46 ['links', 'модули связей', 'Contenido::Link'],
47 );
48 }
49
50
51 sub init {
52 warn "Contenido Init: Инициализация Contenido\n" if $DEBUG;
53
54 my $R = contenido_init();
55
56 if ($state->locale) {
57 setlocale(LC_COLLATE, $state->locale);
58 setlocale(LC_CTYPE, $state->locale);
59 }
60
61 $keeper = Contenido::Keeper->new($state);
62 # если не стоит keepalive имеет смысл соединиться с базой, если она используется проектом
63 unless ($state->db_type eq 'none') {
64 $keeper->db_connect unless $keeper->is_connected;
65 }
66
67 $log->info("Создание объекта Contenido::Project") if $DEBUG;
68 $project = Contenido::Project->new($state);
69
70 $R += plugins_load();
71 $R += modules_load();
72 utils_load();
73
74 init_classes();
75 clear_not_available();
76
77 # PREAMBLE_HANDLER stuff - load and initialize
78 #
79 if ( $state->{preamble_handler} ) {
80 my $module = $state->{preamble_handler}; # main preamble hanler
81 my $path = $state->{preamble_handler_path}; # extra preamble handlers relative path
82 eval "use $module";
83 if ( $@ ) {
84 $R++; $log->error("Cannot load module $module because of '$@'");
85 }
86 $state->{preamble_handler_obj} = $module->new( $path ? (load_modules => $path) : () );
87 }
88
89 unless ($state->db_type eq 'none') {
90 $keeper->shutdown;
91 }
92
93 if ($R) {
94 $log->error("При инициализации Contenido произошли ошибки (количество - $R)") if $DEBUG;
95 } else {
96 $log->info("Инициализация Contenido прошла успешно") if $DEBUG;
97 }
98
99 return ($R ? 1 : 0);
100 }
101
102 sub init_classes {
103 foreach (&module_structure, ['locals', 'проектные модули', $keeper->state()->project() ]) {
104 my $tag = $_->[0];
105 $state->{'available_'.$tag} ||= [];
106 if (ref($state->{'available_'.$tag}) eq 'ARRAY') {
107 foreach my $class (@{$state->{'available_'.$tag}}) {
108 $class->class_init;
109 }
110 } else {
111 $log->error("Wrong structure in \$state->{available_$tag} (".$state->{'available_'.$tag}."), must be ARRAY REF");
112 die;
113 }
114 }
115 }
116
117 sub clear_not_available {
118 foreach (&module_structure, ['locals', 'проектные модули', $keeper->state()->project() ]) {
119 my $tag = $_->[0];
120 next unless ref $state->{'available_'.$tag} eq 'ARRAY';
121 for (my $i = 0; $i <= $#{$state->{'available_'.$tag}} ; $i++) {
122 my $class = $state->{'available_'.$tag}->[$i];
123 unless ($class->contenido_is_available) {
124 splice(@{$state->{'available_'.$tag}}, $i--, 1);
125 $log->debug('Удален класс ' . $class . ' из $state->{available_' . $tag . '}') if $DEBUG;
126 }
127 }
128 }
129 }
130
131 sub load_classes {
132 shift;
133 for (@_) {
134 eval "use $_";
135 #зачем делать eval если не проверять потом $@ ?
136 $log->error("Cannot load class $_ because of $@") if ($@);
137 if ($_->can('class_init')) {
138 eval {$_->class_init};
139 $log->error("Error on class_init for class $_ because of $@") if ($@);
140 }
141 $log->info("Загружен класс $_") if $DEBUG;
142 }
143 }
144
145 sub plugins_load {
146 my $LR = 0;
147
148 # ----------------------------------------------------------------------------
149 # Теперь нам надо подключить все сторонние модули...
150 for my $plugin ($state->project, split(/\s+/, $state->plugins)) {
151 my $class = $plugin.'::Init';
152 eval ("use $class");
153 $log->error("Ошибка при загрузке модуля.\n$@!") if $@;
154
155 {
156 package HTML::Mason::Commands;
157 eval ("use $class");
158 }
159
160
161 if ( $@ ) {
162 $log->error("Не могу подключить плагин $plugin (инициализатор $class) по причине '$@'");
163 $LR++;
164 } else {
165 $log->info("Загружен класс $class для плагина $plugin") if $DEBUG;
166 eval {
167 $LR += $class->init( $keeper );
168 };
169 if ( $@ ) {
170 $log->error("Не могу выполнить инициализацию плагина $plugin (инициализатор $class) по причине '$@'");
171 $LR++;
172 }
173 }
174 }
175
176 return $LR;
177 }
178
179 sub utils_load {
180 Utils::load_modules( ['Utils::HTML'] );
181 }
182
183
184 sub modules_load {
185 my $path = __FILE__;
186 $path =~ s|/[^/]*$||;
187 $path =~ s|/Contenido$||;
188
189 my $LR = 0;
190
191 my @ms = ();
192
193 # Добавляем проверку локальных модулей...
194 push (@ms, ['locals', 'проектные модули', $keeper->state()->project() ] );
195
196
197 foreach my $ms (@ms) {
198 $log->info("Подключаем ".$ms->[1]) if $DEBUG;
199
200 my $pathlib = $path.'/'.$ms->[2];
201 $pathlib =~ s|::|/|gi;
202 if (! -s $pathlib) {
203 $log->warning("Директории ${pathlib} не существует. Непорядок!");
204 } else {
205 opendir(DIR, $pathlib) || do { $log->error("Не могу открыть директорию ${pathlib} для подключения модулей"); die };
206 my @modules = grep {/\.pm$/} readdir(DIR);
207 closedir(DIR);
208
209 foreach my $module (@modules) {
210 $module =~ s/\.pm$//;
211
212 my $class = $ms->[2]."::".$module;
213
214 eval("
215 package TestPackage::$class;
216 use $class;
217 1;
218 ");
219
220 if ( $@ ) {
221 $log->error("Не могу подключить модуль $module (класс $class) по причине '$@'");
222 $LR++;
223 } else {
224 $log->info("Загружен класс $class") if $DEBUG;
225 next unless $class->isa('Contenido::Object');
226 foreach (&module_structure()) {
227 my ($tag, $name, $proto) = @$_;
228 if ($class->isa($proto)) {
229 push (@{ $state->{'available_'.$tag} }, $class);
230 $log->info("Класс $class типа $name '".$class->class_name()."' (прототип $proto)") if $DEBUG;
231 }
232 }
233 }
234 }
235 }
236 }
237
238 # Еще загрузим специально ряд модулей - Contenido::User, Contenido::Section... Вернее добавим их в список возможностей
239 push (@{ $state->{'available_sections'} }, 'Contenido::Section');
240 push (@{ $state->{'available_users'} }, 'Contenido::User');
241 push (@{ $state->{'available_links'} }, 'Contenido::Link');
242
243 return $LR;
244 }
245
246 # Создание объектов Contenido...
247 sub contenido_init {
248 warn "Contenido Init: Создание объекта Contenido::State\n" if $DEBUG;
249 $state = Contenido::State->new();
250 $log = Contenido::Logger->new(
251 log_format => $state->{__debug_format__} || '%d %C:%L (%P) [%l]: "%m"%n',
252 max_level => $state->{__debug_max_level__} || 'emergency',
253 min_level => $state->{__debug_min_level__} || 'debug',
254 stack_trace => $state->{__debug_stack_trace__} || 0,
255 );
256
257 return 1 unless ref $state && ref $log;
258 $log->info("Создан объект Contenido::Logger") if $DEBUG;
259
260 $state->debug($DEBUG);
261 $state->info() if $DEBUG;
262
263 return 0;
264 }
265
266 1;
267