Revision 599
- Date:
- 2016/10/19 16:17:37
- Files:
-
- /utf8/plugins/sphinx/comps
- /utf8/plugins/sphinx/comps/contenido
- /utf8/plugins/sphinx/comps/contenido/sphinx
- /utf8/plugins/sphinx/comps/contenido/sphinx/autohandler (Diff) (Checkout)
- /utf8/plugins/sphinx/comps/contenido/sphinx/dhandler (Diff) (Checkout)
- /utf8/plugins/sphinx/comps/contenido/sphinx/index.html (Diff) (Checkout)
- /utf8/plugins/sphinx/config.proto (Diff) (Checkout)
- /utf8/plugins/sphinx/lib
- /utf8/plugins/sphinx/lib/sphinx
- /utf8/plugins/sphinx/lib/sphinx/Apache.pm (Diff) (Checkout)
- /utf8/plugins/sphinx/lib/sphinx/Init.pm (Diff) (Checkout)
- /utf8/plugins/sphinx/lib/sphinx/Keeper.pm (Diff) (Checkout)
- /utf8/plugins/sphinx/lib/sphinx/SQL
- /utf8/plugins/sphinx/lib/sphinx/SQL/SearchTable.pm (Diff) (Checkout)
- /utf8/plugins/sphinx/lib/sphinx/Search.pm (Diff) (Checkout)
- /utf8/plugins/sphinx/lib/sphinx/State.pm.proto (Diff) (Checkout)
- /utf8/plugins/sphinx/sql
- /utf8/plugins/sphinx/sql/TOAST
- /utf8/plugins/sphinx/sql/TOAST/search.sql (Diff) (Checkout)
Legend:
- Added
- Removed
- Modified
-
utf8/plugins/sphinx/comps/contenido/sphinx/autohandler
1 <%init> 2 3 $r->content_type('text/html'); 4 $m->call_next(); 5 6 </%init> -
utf8/plugins/sphinx/comps/contenido/sphinx/dhandler
1 <& $call, %ARGS &> 2 <%init> 3 4 my $call; 5 if ( $r->uri eq '/contenido/sphinx/' ) { 6 $call = 'index.html'; 7 } else { 8 &abort404; 9 } 10 11 </%init> -
utf8/plugins/sphinx/comps/contenido/sphinx/index.html
1 <& "/contenido/components/header.msn" &> 2 <& "/contenido/components/naviline.msn" &> 3 4 <p>PLugin [sphinx]</p> 5 6 </body> 7 </html> -
utf8/plugins/sphinx/config.proto
1 ############################################################################# 2 # 3 # Параметры данного шаблона необходимо ВРУЧНУЮ добавить в config.mk проекта 4 # и привести в соответствие с требованиями проекта 5 # 6 ############################################################################# 7 8 PLUGINS += sphinx 9 10 SPHINX_HOST = localhost 11 SPHINX_PORT = 9306 12 13 REWRITE += SPHINX_HOST SPHINX_PORT -
utf8/plugins/sphinx/lib/sphinx/Apache.pm
1 package sphinx::Apache; 2 3 use strict; 4 use warnings 'all'; 5 6 use sphinx::State; 7 use Contenido::Globals; 8 9 10 sub child_init { 11 # встраиваем keeper плагина в keeper проекта 12 $keeper->{sphinx} = sphinx::Keeper->new($state->sphinx); 13 } 14 15 sub request_init { 16 } 17 18 sub child_exit { 19 } 20 21 1; -
utf8/plugins/sphinx/lib/sphinx/Init.pm
1 package sphinx::Init; 2 3 use strict; 4 use warnings 'all'; 5 6 use Contenido::Globals; 7 use sphinx::Apache; 8 use sphinx::Keeper; 9 10 11 # загрузка всех необходимых плагину классов 12 # sphinx::SQL::SomeTable 13 # sphinx::SomeClass 14 Contenido::Init::load_classes(qw( 15 )); 16 17 sub init { 18 0; 19 } 20 21 1; -
utf8/plugins/sphinx/lib/sphinx/Keeper.pm
1 package sphinx::Keeper; 2 3 use strict; 4 use warnings 'all'; 5 use base qw(Contenido::Keeper); 6 use Contenido::Globals; 7 8 ###################### 9 # Отправить объект в поиск: 10 # Вызов: $keeper->set_search( $object ); 11 # Объект должен обязательно иметь метод 12 # ->get_search_data, 13 # возвращающий структуру: 14 # { 15 # id => $object->id, 16 # class => $object->class, 17 # name => $object_name, 18 # text => $search_text 19 # } 20 # Кроме того, метод чувствителен к полю status и предполагает, 21 # что status=1 - документ активен; status=0 - документ не активен. 22 ########################################################################## 23 sub send 24 { 25 my $self = shift; 26 my $doc = shift; 27 return undef unless ref $doc && $doc->id; 28 29 my ($object) = $self->get_documents( 30 class => 'sphinx::Search', 31 object_id => $doc->id, 32 object_class => $doc->class, 33 ); 34 if ( $doc->status == 1 ) { 35 my $data = $doc->get_search_data; 36 return undef unless $data; 37 unless ( ref $object ) { 38 $object = sphinx::Search->new( $self ); 39 $object->status( 1 ); 40 $object->is_deleted( 0 ); 41 $object->object_id( $doc->id ); 42 $object->object_class( $doc->class ); 43 $object->name( $data->{name} ); 44 $object->search( $data->{text} ); 45 $object->store; 46 } else { 47 if ( $data->{name} ne $object->name || $data->{text} ne $object->search || $doc->is_deleted || $doc->status <= 0 ) { 48 $object->status( 1 ); 49 $object->is_deleted( 0 ); 50 $object->name( $data->{name} ); 51 $object->search( $data->{text} ); 52 $object->store; 53 } 54 } 55 } else { 56 if ( ref $object ) { 57 $object->status( 0 ); 58 $object->is_deleted( 1 ); 59 $object->store; 60 } 61 } 62 } 63 64 65 1; -
utf8/plugins/sphinx/lib/sphinx/Search.pm
1 package sphinx::Search; 2 3 use base 'Contenido::Document'; 4 use Contenido::Globals; 5 6 sub extra_properties 7 { 8 return ( 9 ) 10 } 11 12 13 sub sections 14 { 15 return (); 16 } 17 18 sub class_name 19 { 20 return 'Sphinx: поисковый объект'; 21 } 22 23 sub class_description 24 { 25 return 'Sphinx: поисковый объект'; 26 } 27 28 sub class_table 29 { 30 return 'sphinx::SQL::SearchTable'; 31 } 32 33 sub search_fields { 34 return ('name', 'object_id'); 35 } 36 37 sub pre_store 38 { 39 my $self = shift; 40 41 return 1; 42 } 43 44 45 1; -
utf8/plugins/sphinx/lib/sphinx/SQL/SearchTable.pm
1 package sphinx::SQL::SearchTable; 2 3 use base 'SQL::ProtoTable'; 4 5 sub db_table 6 { 7 return 'search'; 8 } 9 10 sub db_id_sequence { 11 return 'search_id_seq'; 12 } 13 14 sub available_filters { 15 my @available_filters = qw( 16 _class_filter 17 _status_filter 18 _in_id_filter 19 _id_filter 20 _name_filter 21 _class_excludes_filter 22 23 _object_id_filter 24 _object_class_filter 25 _excludes_filter 26 ); 27 return \@available_filters; 28 } 29 30 # ---------------------------------------------------------------------------- 31 # Свойства храним в массивах, потому что порядок важен! 32 # Это общие свойства - одинаковые для всех документов. 33 # 34 # attr - обязательный параметр, название атрибута; 35 # type - тип аттрибута, требуется для отображдения; 36 # rusname - русское название, опять же требуется для отображения; 37 # hidden - равен 1, когда 38 # readonly - инициализации при записи только без изменения в дальнейшем 39 # db_field - поле в таблице 40 # default - значение по умолчанию (поле всегда имеет это значение) 41 # ---------------------------------------------------------------------------- 42 sub required_properties 43 { 44 return ( 45 { # Идентификатор документа, сквозной по всем типам... 46 'attr' => 'id', 47 'type' => 'integer', 48 'rusname' => 'Идентификатор документа', 49 'hidden' => 1, 50 'auto' => 1, 51 'readonly' => 1, 52 'db_field' => 'id', 53 'db_type' => 'integer', 54 'db_opts' => "not null default nextval('public.documents_id_seq'::text)", 55 }, 56 { # Класс документа... 57 'attr' => 'class', 58 'type' => 'string', 59 'rusname' => 'Класс документа', 60 'hidden' => 1, 61 'readonly' => 1, 62 'column' => 3, 63 'db_field' => 'class', 64 'db_type' => 'varchar(48)', 65 'db_opts' => 'not null', 66 }, 67 { 68 'attr' => 'name', 69 'type' => 'string', 70 'rusname' => 'Название документа', 71 'column' => 2, 72 'db_field' => 'name', 73 'db_type' => 'text', 74 }, 75 { 76 'attr' => 'status', 77 'type' => 'status', 78 'rusname' => 'Статус', 79 'db_field' => 'status', 80 'db_type' => 'smallint', 81 }, 82 { 83 'attr' => 'is_deleted', 84 'type' => 'checkbox', 85 'rusname' => 'Документ удален', 86 'db_field' => 'is_deleted', 87 'db_type' => 'boolean', 88 }, 89 { # Время создания документа 90 'attr' => 'ctime', 91 'type' => 'datetime', 92 'rusname' => 'Дата/время создания', 93 'readonly' => 1, 94 'auto' => 1, 95 'hidden' => 1, 96 'db_field' => 'ctime', 97 'db_type' => 'timestamp', 98 'db_opts' => 'not null default now()', 99 'default' => 'CURRENT_TIMESTAMP', 100 }, 101 { # Время изменения документа 102 'attr' => 'mtime', 103 'type' => 'datetime', 104 'rusname' => 'Дата/время изменения', 105 'auto' => 1, 106 'hidden' => 1, 107 'db_field' => 'mtime', 108 'db_type' => 'timestamp', 109 'db_opts' => 'not null default now()', 110 'default' => 'CURRENT_TIMESTAMP', 111 }, 112 { 113 'attr' => 'object_class', 114 'type' => 'string', 115 'rusname' => 'Класс объекта', 116 'column' => 4, 117 'db_field' => 'object_class', 118 'db_type' => 'text', 119 }, 120 { 121 'attr' => 'object_id', 122 'type' => 'string', 123 'rusname' => 'ID объекта', 124 'column' => 5, 125 'db_field' => 'object_id', 126 'db_type' => 'integer', 127 }, 128 { 129 'attr' => 'search', 130 'type' => 'text', 131 'rusname' => 'Текст', 132 'db_field' => 'search', 133 'db_type' => 'text', 134 }, 135 ); 136 } 137 138 139 ########### FILTERS DESCRIPTION #################################################################################### 140 sub _excludes_filter { 141 my ($self,%opts)=@_; 142 if (exists $opts{excludes}) { 143 # - исключение из отбора 144 my @eids = (); 145 if (ref($opts{excludes}) eq 'ARRAY') { 146 @eids = @{ $opts{excludes} }; 147 } elsif ($opts{excludes} =~ /[^\d\,]/) { 148 warn "Contenido Warning: В списке идентификаторов для исключения встречаются нечисловые элементы. Параметр excludes игнорируется (".$opts{excludes}.").\n"; 149 } else { 150 @eids = split(',', $opts{excludes}); 151 } 152 153 my $excludes = join(',', @eids); 154 155 # Меняется логика запроса, если это join-запрос. 156 # Потому что в этом случае гораздо лучше ограничить выборку по таблице links, 157 # чем производить полную склейку таблиц. 158 if (@eids) { 159 if (exists($opts{ldest}) || exists($opts{lsource})) { 160 if (exists($opts{ldest})) { 161 return " (l.source_id not in ($excludes)) "; 162 } elsif (exists($opts{lsource})) { 163 return " (l.dest_id not in ($excludes)) "; 164 } 165 } else { 166 return " (d.id not in ($excludes)) "; 167 } 168 } 169 } 170 return undef; 171 } 172 173 174 sub _get_orders { 175 my ($self, %opts) = @_; 176 177 if ($opts{order_by}) { 178 return ' order by '.$opts{order_by}; 179 } else { 180 return ' order by mtime desc'; 181 } 182 return undef; 183 } 184 185 sub _object_id_filter { 186 my ($self, %opts)=@_; 187 return undef unless ( exists $opts{object_id} ); 188 return &SQL::Common::_generic_int_filter('d.object_id', $opts{object_id}); 189 } 190 191 sub _object_class_filter { 192 my ($self, %opts)=@_; 193 return undef unless ( exists $opts{object_class} ); 194 return &SQL::Common::_generic_text_filter('d.object_class', $opts{object_class}); 195 } 196 197 1; -
utf8/plugins/sphinx/lib/sphinx/State.pm.proto
1 package sphinx::State; 2 3 use strict; 4 use warnings 'all'; 5 use vars qw($AUTOLOAD); 6 7 8 sub new { 9 my ($proto) = @_; 10 my $class = ref($proto) || $proto; 11 my $self = {}; 12 bless $self, $class; 13 14 # configured 15 $self->{debug} = (lc('') eq 'yes'); 16 $self->{project} = ''; 17 $self->{contenido_notab} = 0; 18 $self->{tab_name} = 'sphinx'; 19 20 # зашитая конфигурация плагина 21 $self->{db_type} = 'none'; ### For REAL database use 'remote' 22 $self->{db_keepalive} = 0; 23 $self->{db_host} = ''; 24 $self->{db_name} = ''; 25 $self->{db_user} = ''; 26 $self->{db_password} = ''; 27 $self->{db_port} = ''; 28 $self->{store_method} = 'toast'; 29 $self->{cascade} = 1; 30 $self->{db_prepare} = 0; 31 32 $self->{memcached_enable} = lc( '' ) eq 'yes' ? 1 : 0; 33 $self->{memcached_enable_compress} = 1; 34 $self->{memcached_backend} = ''; 35 $self->{memcached_servers} = [qw()]; 36 $self->{memcached_busy_lock} = 60; 37 $self->{memcached_delayed} = lc('') eq 'yes' ? 1 : 0; 38 39 $self->{serialize_with} = 'json'; ### or 'dumper' 40 41 # not implemented really (core compatibility) 42 $self->{binary_directory} = '/nonexistent'; 43 $self->{data_directory} = '/nonexistent'; 44 $self->{images_directory} = '/nonexistent'; 45 $self->{preview} = '0'; 46 47 $self->_init_(); 48 $self; 49 } 50 51 sub info { 52 my $self = shift; 53 return unless ref $self; 54 55 for (sort keys %{$self->{attributes}}) { 56 my $la = length $_; 57 warn "\t$_".("\t" x (2-int($la/8))).": $self->{$_}\n"; 58 } 59 } 60 61 sub _init_ { 62 my $self = shift; 63 64 # зашитая конфигурация плагина 65 $self->{attributes}->{$_} = 'SCALAR' for qw( 66 debug 67 project 68 tab_name 69 70 db_type 71 db_keepalive 72 db_host 73 db_port 74 db_name 75 db_user 76 db_password 77 store_method 78 cascade 79 db_prepare 80 db_client_encoding 81 82 memcached_enable 83 memcached_enable_compress 84 memcached_backend 85 memcached_servers 86 memcached_busy_lock 87 memcached_delayed 88 89 binary_directory 90 data_directory 91 images_directory 92 preview 93 ); 94 } 95 96 sub AUTOLOAD { 97 my $self = shift; 98 my $attribute = $AUTOLOAD; 99 100 $attribute =~ s/.*:://; 101 return unless $attribute =~ /[^A-Z]/; # Отключаем методы типа DESTROY 102 103 if (!exists $self->{attributes}->{$attribute}) { 104 warn "Contenido Error (sphinx::State): Вызов метода, для которого не существует обрабатываемого свойства: ->$attribute()\n"; 105 return; 106 } 107 108 $self->{$attribute} = shift @_ if $#_>=0; 109 $self->{$attribute}; 110 } 111 112 1; -
utf8/plugins/sphinx/sql/TOAST/search.sql
1 create sequence search_id_seq; 2 select setval('search_id_seq', 1, true); 3 4 create table search 5 ( 6 id integer not null primary key default nextval('public.search_id_seq'::text), 7 class text not null, 8 ctime timestamp not null default now(), 9 mtime timestamp not null default now(), 10 status smallint not null default 1, 11 object_id integer not null, 12 object_class text not null, 13 name text, 14 search text, 15 data text 16 ); 17 create index search_object on search (object_class, object_id); 18 create index search_mtime on search (mtime);