Line # Revision Author
1 599 ahitrov package sphinx::Keeper;
2
3 use strict;
4 use warnings 'all';
5 use base qw(Contenido::Keeper);
6 use Contenido::Globals;
7 603 ahitrov use Data::Dumper;
8 599 ahitrov
9 ######################
10 # Отправить объект в поиск:
11 # Вызов: $keeper->set_search( $object );
12 # Объект должен обязательно иметь метод
13 # ->get_search_data,
14 # возвращающий структуру:
15 # {
16 # id => $object->id,
17 # class => $object->class,
18 # name => $object_name,
19 # text => $search_text
20 # }
21 # Кроме того, метод чувствителен к полю status и предполагает,
22 # что status=1 - документ активен; status=0 - документ не активен.
23 ##########################################################################
24 sub send
25 {
26 my $self = shift;
27 my $doc = shift;
28 return undef unless ref $doc && $doc->id;
29
30 603 ahitrov my ($object) = $keeper->get_documents(
31 599 ahitrov class => 'sphinx::Search',
32 object_id => $doc->id,
33 object_class => $doc->class,
34 );
35 if ( $doc->status == 1 ) {
36 my $data = $doc->get_search_data;
37 return undef unless $data;
38 unless ( ref $object ) {
39 603 ahitrov $object = sphinx::Search->new( $keeper );
40 599 ahitrov $object->status( 1 );
41 $object->is_deleted( 0 );
42 $object->object_id( $doc->id );
43 $object->object_class( $doc->class );
44 $object->name( $data->{name} );
45 $object->search( $data->{text} );
46 $object->store;
47 } else {
48 639 ahitrov if ( $data->{name} ne $object->name || $data->{text} ne $object->search || $object->is_deleted || $object->status <= 0 ) {
49 599 ahitrov $object->status( 1 );
50 $object->is_deleted( 0 );
51 $object->name( $data->{name} );
52 $object->search( $data->{text} );
53 $object->store;
54 }
55 }
56 } else {
57 if ( ref $object ) {
58 $object->status( 0 );
59 $object->is_deleted( 1 );
60 $object->store;
61 }
62 }
63 }
64
65
66 603 ahitrov # Методы поиска
67 ####################################################################
68 sub search {
69 my $self = shift;
70 my $text = shift;
71 return unless $text;
72 my (%opts) = @_;
73
74 my $result;
75 my $db_table = delete $opts{db_table} || $self->state->table_name;
76 my @wheres = ("MATCH(?)");
77 my @values = ($text);
78 658 ahitrov my @orders;
79 603 ahitrov my $count = delete $opts{count};
80 my $limit = delete $opts{limit};
81 return if $limit && ($limit =~ /\D/ || $limit < 0);
82 605 ahitrov my $offset = delete $opts{offset};
83 return if $offset && ($offset =~ /\D/ || $offset < 0);
84 603 ahitrov my $no_limit = delete $opts{no_limit};
85 unless ( $no_limit ) {
86 $limit ||= 1000;
87 }
88 605 ahitrov if ( $count ) {
89 $limit = 0;
90 $offset = 0;
91 }
92 603 ahitrov my $return_value = delete $opts{return_value} || 'array_ref';
93 my $hash_by = delete $opts{hash_by} || 'object_id';
94
95 605 ahitrov if ( exists $opts{object_class} ) {
96 push @wheres, "object_class in (".join( ',', map { '?' } ref $opts{object_class} eq 'ARRAY' ? @{$opts{object_class}} : ($opts{object_class}) ).")";
97 push @values, ref $opts{object_class} ? @{$opts{object_class}} : $opts{object_class};
98 603 ahitrov }
99 605 ahitrov
100 658 ahitrov if ( exists $opts{order_by} ) {
101 push @orders, $opts{order_by};
102 } elsif ( !$count ) {
103 push @orders, 'weight desc, last_edited desc';
104 }
105
106 my $query = "select ".($count ? 'count(*) as cnt' : '*, weight() as weight')." from $db_table where ".join( ' and ', @wheres ).(@orders ? " order by ".join(', ', @orders) : '');
107 605 ahitrov if ( $limit && $offset ) {
108 $query .= " limit $offset, $limit ";
109 } elsif ( $limit ) {
110 $query .= " limit 0, $limit ";
111 603 ahitrov }
112 warn "SEARCH QUERY: $query\n" if $DEBUG;
113 warn "SEARCH VALUES: ".Dumper( \@values ) if $DEBUG;
114 605 ahitrov my $sth = $self->SQL->prepare( $query );
115 661 ahitrov if ( $sth->execute( @values ) ) {
116 if ( $count ) {
117 $result = $sth->fetchrow_arrayref;
118 warn "COUNT: ". Dumper( $result ) if $DEBUG;
119 $result = $result->[0];
120 } else {
121 $result = [];
122 while ( my $row = $sth->fetchrow_hashref ) {
123 push @$result, $row;
124 }
125 }
126 603 ahitrov } else {
127 661 ahitrov warn "ERROR in statement: ".$sth->errstr."\n";
128 warn "SEARCH QUERY: $query\n";
129 warn "SEARCH VALUES: ".Dumper( \@values );
130 603 ahitrov }
131 764 ahitrov $sth->finish
132 603 ahitrov return $result;
133 }
134
135 sub stemmed {
136 my $self = shift;
137 my $db_table = $self->state->table_name_stemmed;
138 return $self->search( @_, db_table => $db_table );
139 }
140
141 # МЕТОДЫ ДОСТУПА К СОЕДИНЕНИЯМ С БАЗОЙ УМНЫЕ
142 ####################################################################
143 # получение соединения с базой или установка нового если его не было
144 sub SQL {
145 my $self = shift;
146 return ($self->connect_check() ? $self->{SQL} : undef);
147 }
148
149 # -------------------------------------------------------------------------------------------------
150 # Открываем соединение с базой данных
151 # -------------------------------------------------------------------------------------------------
152 sub connect {
153 my $self = shift;
154 #соединение уже есть
155 if ($self->is_connected) {
156 } else {
157 unless ($self->{SQL} = $self->db_connect) {
158 warn "Не могу соединиться с базой данных";
159 die;
160 }
161 $self->{SQL}->do("SET NAMES '".$self->state->db_client_encoding."'") if ($self->state->db_client_encoding);
162 }
163
164 $self->{_connect_ok} = 1;
165 return 1;
166 }
167
168 #проверка соединения с базой кеширующая состояние соединения
169 sub connect_check {
170 my $self = shift;
171 return 1 if ($self->{_connect_ok});
172 if ($self->is_connected) {
173 $self->{_connect_ok} = 1;
174 return 1;
175 } else {
176 if ($self->connect) {
177 return 1;
178 } else {
179 #сюда по логике попадать не должно так как die вылететь должен
180 warn "Connect failed\n";
181 return 0;
182 }
183 }
184 }
185
186 sub db_connect {
187 my $self = shift;
188 my $dbh = DBI->connect('DBI:mysql:host='.$self->{db_host}.';port='.$self->{db_port}.';mysql_enable_utf8=1')
189 || die "Contenido Error: Не могу соединиться с Sphinx базой данных\n";
190
191 658 ahitrov $dbh->{mysql_auto_reconnect} = 1;
192 603 ahitrov # $dbh->{'AutoCommit'} = 1;
193
194 return $dbh;
195 }
196
197 sub is_connected {
198 my $self = shift;
199 if ( ref $self->{SQL} and $self->{SQL}->can('ping') and $self->{SQL}->ping() ) {
200 $self->{_connect_ok} = 1;
201 return 1;
202 } else {
203 $self->{_connect_ok} = 0;
204 return 0;
205 }
206
207 # warn 'Check if MySQL DB connected: '.(ref $self && exists $self->{SQL} && ref $self->{SQL} ? 1 : 0 ) if $DEBUG;
208 # return ( ref($self) && exists $self->{SQL} && ref $self->{SQL} );
209 }
210 599 ahitrov 1;