1 package C4::AuthoritiesMarc;
2 # Copyright 2000-2002 Katipo Communications
4 # This file is part of Koha.
6 # Koha is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
11 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License along with
16 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
17 # Suite 330, Boston, MA 02111-1307 USA
27 use vars qw($VERSION @ISA @EXPORT);
29 # set the version for version checking
36 &AUTHfind_authtypecode
52 &MARCaddword &MARCdelword
58 my ($dbh, $tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode) = @_;
59 # build the sql request. She will look like :
61 # from auth_subfield_table as m1, auth_subfield_table as m2
62 # where m1.authid=m2.authid and
63 # (m1.subfieldvalue like "Des%" and m2.subfieldvalue like "27%")
65 # the marclist may contain "mainentry". In this case, search the tag_to_report, that depends on
66 # the authtypecode. Then, search on $a of this tag_to_report
67 for (my $i=0;$i<$#{$tags};$i++) {
68 if (@$tags[$i] eq "mainentry") {
69 my $sth = $dbh->prepare("select auth_tag_to_report from auth_types where authtypecode=?");
70 $sth->execute($authtypecode);
71 my ($tag_to_report) = $sth->fetchrow;
72 @$tags[$i] = $tag_to_report."a";
77 # quote marc fields/subfields
78 for (my $i=0;$i<=$#{$tags};$i++) {
80 @$tags[$i] = $dbh->quote(@$tags[$i]);
84 my @normal_and_or = ();
85 my @normal_operator = ();
86 my @normal_value = ();
87 # Extracts the NOT statements from the list of statements
88 for(my $i = 0 ; $i <= $#{$value} ; $i++)
90 if(@$operator[$i] eq "contains") # if operator is contains, splits the words in separate requests
92 foreach my $word (split(/ /, @$value[$i]))
94 unless (C4::Context->stopwords->{uc($word)}) { #it's NOT a stopword => use it. Otherwise, ignore
95 my $tag = substr(@$tags[$i],0,3);
96 my $subf = substr(@$tags[$i],3,1);
97 push @normal_tags, @$tags[$i];
98 push @normal_and_or, "and"; # assumes "foo" and "bar" if "foo bar" is entered
99 push @normal_operator, @$operator[$i];
100 push @normal_value, $word;
106 push @normal_tags, @$tags[$i];
107 push @normal_and_or, @$and_or[$i];
108 push @normal_operator, @$operator[$i];
109 push @normal_value, @$value[$i];
113 # Finds the basic results without the NOT requests
114 my ($sql_tables, $sql_where1, $sql_where2) = create_request($dbh,\@normal_tags, \@normal_and_or, \@normal_operator, \@normal_value);
119 $sth = $dbh->prepare("select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where2 and ($sql_where1)");
120 warn "Q2 : select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where2 and ($sql_where1)";
122 $sth = $dbh->prepare("select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where1");
123 warn "Q : select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where1";
125 $sth->execute($authtypecode);
127 while (my ($authid) = $sth->fetchrow) {
128 push @result,$authid;
131 # we have authid list. Now, loads summary from [offset] to [offset]+[length]
132 my $counter = $offset;
133 my @finalresult = ();
135 while (($counter <= $#result) && ($counter <= ($offset + $length))) {
136 # warn " HERE : $counter, $#result, $offset, $length";
137 # get MARC::Record of the authority
138 my $record = AUTHgetauthority($dbh,$result[$counter]);
139 # then build the summary
140 my $authtypecode = AUTHfind_authtypecode($dbh,$result[$counter]);
141 my $authref = getauthtype($authtypecode);
142 my $summary = $authref->{summary};
143 my @fields = $record->fields();
144 foreach my $field (@fields) {
145 my $tag = $field->tag();
148 my @subf = $field->subfields;
149 for my $i (0..$#subf) {
150 my $subfieldcode = $subf[$i][0];
151 my $subfieldvalue = $subf[$i][1];
152 my $tagsubf = $tag.$subfieldcode;
153 $summary =~ s/\[(.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
157 $summary =~ s/\[(.*?)]//g;
158 $summary =~ s/\n/<br>/g;
160 # find biblio MARC field using this authtypecode (to jump to biblio)
161 my $authtypecode = AUTHfind_authtypecode($dbh,$result[$counter]);
162 my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
163 $sth->execute($authtypecode);
164 my $tags_using_authtype;
165 while (my ($tagfield) = $sth->fetchrow) {
166 # warn "TAG : $tagfield";
167 $tags_using_authtype.= $tagfield."9,";
169 chop $tags_using_authtype;
171 # then add a line for the template loop
173 $newline{summary} = $summary;
174 $newline{authid} = $result[$counter];
175 $newline{used} = &AUTHcount_usage($result[$counter]);
176 $newline{biblio_fields} = $tags_using_authtype;
178 push @finalresult, \%newline;
180 my $nbresults = $#result + 1;
181 return (\@finalresult, $nbresults);
184 # Creates the SQL Request
187 my ($dbh,$tags, $and_or, $operator, $value) = @_;
189 my $sql_tables; # will contain marc_subfield_table as m1,...
190 my $sql_where1; # will contain the "true" where
191 my $sql_where2 = "("; # will contain m1.authid=m2.authid
192 my $nb_active=0; # will contain the number of "active" entries. and entry is active is a value is provided.
193 my $nb_table=1; # will contain the number of table. ++ on each entry EXCEPT when an OR is provided.
196 for(my $i=0; $i<=@$value;$i++) {
199 # warn " @$tags[$i]";
201 if (@$operator[$i] eq "start") {
202 $sql_tables .= "auth_subfield_table as m$nb_table,";
203 $sql_where1 .= "(m1.subfieldvalue like ".$dbh->quote("@$value[$i]%");
205 $sql_where1 .=" and m1.tag+m1.subfieldcode in (@$tags[$i])";
208 } elsif (@$operator[$i] eq "contains") {
209 $sql_tables .= "auth_word as m$nb_table,";
210 $sql_where1 .= "(m1.word like ".$dbh->quote("@$value[$i]%");
212 $sql_where1 .=" and m1.tagsubfield in (@$tags[$i])";
217 $sql_tables .= "auth_subfield_table as m$nb_table,";
218 $sql_where1 .= "(m1.subfieldvalue @$operator[$i] ".$dbh->quote("@$value[$i]");
220 $sql_where1 .=" and m1.tag+m1.subfieldcode in (@$tags[$i])";
225 if (@$operator[$i] eq "start") {
227 $sql_tables .= "auth_subfield_table as m$nb_table,";
228 $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue like ".$dbh->quote("@$value[$i]%");
230 $sql_where1 .=" and m$nb_table.tag+m$nb_table.subfieldcode in (@$tags[$i])";
233 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
234 } elsif (@$operator[$i] eq "contains") {
235 if (@$and_or[$i] eq 'and') {
237 $sql_tables .= "auth_word as m$nb_table,";
238 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]%");
240 $sql_where1 .=" and m$nb_table.tagsubfield in(@$tags[$i])";
243 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
245 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]%");
247 $sql_where1 .=" and m$nb_table.tag+m$nb_table.subfieldid in (@$tags[$i])";
250 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
254 $sql_tables .= "auth_subfield_table as m$nb_table,";
255 $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue @$operator[$i] ".$dbh->quote(@$value[$i]);
257 $sql_where1 .=" and m$nb_table.tag+m$nb_table.subfieldcode in (@$tags[$i])";
259 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
266 if($sql_where2 ne "(") # some datas added to sql_where2, processing
268 $sql_where2 = substr($sql_where2, 0, (length($sql_where2)-5)); # deletes the trailing ' and '
271 else # no sql_where2 statement, deleting '('
275 chop $sql_tables; # deletes the trailing ','
277 return ($sql_tables, $sql_where1, $sql_where2);
281 sub AUTHcount_usage {
283 my $dbh = C4::Context->dbh;
284 # find MARC fields using this authtype
285 my $authtypecode = AUTHfind_authtypecode($dbh,$authid);
286 my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
287 $sth->execute($authtypecode);
288 my $tags_using_authtype;
289 while (my ($tagfield) = $sth->fetchrow) {
290 # warn "TAG : $tagfield";
291 $tags_using_authtype.= "'".$tagfield."9',";
293 chop $tags_using_authtype;
294 if ($tags_using_authtype) {
295 $sth = $dbh->prepare("select count(*) from marc_subfield_table where concat(tag,subfieldcode) in ($tags_using_authtype) and subfieldvalue=?");
297 $sth = $dbh->prepare("select count(*) from marc_subfield_table where subfieldvalue=?");
299 # warn "Q : select count(*) from marc_subfield_table where concat(tag,subfieldcode) in ($tags_using_authtype) and subfieldvalue=$authid";
300 $sth->execute($authid);
301 my ($result) = $sth->fetchrow;
302 # warn "Authority $authid TOTAL USED : $result";
306 # merging 2 authority entries. After a merge, the "from" can be deleted.
308 # my ($auth_merge_from,$auth_merge_to) = @_;
309 # my $dbh = C4::Context->dbh;
310 # # find MARC fields using this authtype
311 # my $authtypecode = AUTHfind_authtypecode($dbh,$authid);
313 # my $record_from = AUTHgetauthority($dbh,$auth_merge_from);
314 # my $record_to = AUTHgetauthority($dbh,$auth_merge_to);
315 # my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
316 # $sth->execute($authtypecode);
317 # my $tags_using_authtype;
318 # while (my ($tagfield) = $sth->fetchrow) {
319 # warn "TAG : $tagfield";
320 # $tags_using_authtype.= "'".$tagfield."9',";
322 # chop $tags_using_authtype;
323 # # now, find every biblio using this authority
324 # $sth = $dbh->prepare("select bibid,tag,tag_indicator,tagorder from marc_subfield_table where tag+subfieldid in ($tags_using_authtype) and subfieldvalue=?");
325 # $sth->execute($authid);
326 # # and delete entries before recreating them
327 # while (my ($bibid,$tag,$tag_indicator,$tagorder) = $sth->fetchrow) {
328 # &MARCdelsubfield($dbh,$bibid,$tag);
334 sub AUTHfind_authtypecode {
335 my ($dbh,$authid) = @_;
336 my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
337 $sth->execute($authid);
338 my ($authtypecode) = $sth->fetchrow;
339 return $authtypecode;
344 my ($dbh,$forlibrarian,$authtypecode)= @_;
345 $authtypecode="" unless $authtypecode;
347 my $libfield = ($forlibrarian eq 1)? 'liblibrarian' : 'libopac';
348 # check that framework exists
349 $sth=$dbh->prepare("select count(*) from auth_tag_structure where authtypecode=?");
350 $sth->execute($authtypecode);
351 my ($total) = $sth->fetchrow;
352 $authtypecode="" unless ($total >0);
353 $sth=$dbh->prepare("select tagfield,$libfield as lib,mandatory,repeatable from auth_tag_structure where authtypecode=? order by tagfield");
354 $sth->execute($authtypecode);
355 my ($lib,$tag,$res,$tab,$mandatory,$repeatable);
356 while ( ($tag,$lib,$mandatory,$repeatable) = $sth->fetchrow) {
357 $res->{$tag}->{lib}=$lib;
358 $res->{$tab}->{tab}=""; # XXX
359 $res->{$tag}->{mandatory}=$mandatory;
360 $res->{$tag}->{repeatable}=$repeatable;
363 $sth=$dbh->prepare("select tagfield,tagsubfield,$libfield as lib,tab, mandatory, repeatable,authorised_value,value_builder,seealso from auth_subfield_structure where authtypecode=? order by tagfield,tagsubfield");
364 $sth->execute($authtypecode);
367 my $authorised_value;
368 my $thesaurus_category;
374 while ( ($tag, $subfield, $lib, $tab, $mandatory, $repeatable,$authorised_value,$value_builder,$seealso) = $sth->fetchrow) {
375 $res->{$tag}->{$subfield}->{lib}=$lib;
376 $res->{$tag}->{$subfield}->{tab}=$tab;
377 $res->{$tag}->{$subfield}->{mandatory}=$mandatory;
378 $res->{$tag}->{$subfield}->{repeatable}=$repeatable;
379 $res->{$tag}->{$subfield}->{authorised_value}=$authorised_value;
380 $res->{$tag}->{$subfield}->{thesaurus_category}=$thesaurus_category;
381 $res->{$tag}->{$subfield}->{value_builder}=$value_builder;
382 $res->{$tag}->{$subfield}->{seealso}=$seealso;
383 $res->{$tag}->{$subfield}->{hidden}=$hidden;
384 $res->{$tag}->{$subfield}->{isurl}=$isurl;
389 sub AUTHaddauthority {
390 # pass the MARC::Record to this function, and it will create the records in the marc tables
391 my ($dbh,$record,$authid,$authtypecode) = @_;
392 my @fields=$record->fields();
393 # warn "IN AUTHaddauthority $authid => ".$record->as_formatted;
394 # adding main table, and retrieving authid
395 # if authid is sent, then it's not a true add, it's only a re-add, after a delete (ie, a mod)
396 # if authid empty => true add, find a new authid number
398 $dbh->do("lock tables auth_header WRITE,auth_subfield_table WRITE, auth_word WRITE, stopwords READ");
399 my $sth=$dbh->prepare("insert into auth_header (datecreated,authtypecode) values (now(),?)");
400 $sth->execute($authtypecode);
401 $sth=$dbh->prepare("select max(authid) from auth_header");
403 ($authid)=$sth->fetchrow;
407 # now, add subfields...
408 foreach my $field (@fields) {
410 if ($field->tag() <10) {
411 &AUTHaddsubfield($dbh,$authid,
420 my @subfields=$field->subfields();
421 foreach my $subfieldcount (0..$#subfields) {
422 &AUTHaddsubfield($dbh,$authid,
424 $field->indicator(1).$field->indicator(2),
426 $subfields[$subfieldcount][0],
428 $subfields[$subfieldcount][1]
433 $dbh->do("unlock tables");
438 sub AUTHaddsubfield {
439 # Add a new subfield to a tag into the DB.
440 my ($dbh,$authid,$tagid,$tag_indicator,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalues) = @_;
441 # if not value, end of job, we do nothing
442 if (length($subfieldvalues) ==0) {
445 if (not($subfieldcode)) {
448 my @subfieldvalues = split /\|/,$subfieldvalues;
449 foreach my $subfieldvalue (@subfieldvalues) {
450 my $sth=$dbh->prepare("insert into auth_subfield_table (authid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue) values (?,?,?,?,?,?,?)");
451 $sth->execute($authid,(sprintf "%03s",$tagid),$tagorder,$tag_indicator,$subfieldcode,$subfieldorder,$subfieldvalue);
453 warn "ERROR ==> insert into auth_subfield_table (authid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue) values ($authid,$tagid,$tagorder,$tag_indicator,$subfieldcode,$subfieldorder,$subfieldvalue)\n";
455 &AUTHaddword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalue);
459 sub AUTHgetauthority {
460 # Returns MARC::Record of the biblio passed in parameter.
461 my ($dbh,$authid)=@_;
462 my $record = MARC::Record->new();
463 #---- TODO : the leader is missing
464 $record->leader(' ');
465 my $sth=$dbh->prepare("select authid,subfieldid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue
466 from auth_subfield_table
467 where authid=? order by tag,tagorder,subfieldcode
469 $sth->execute($authid);
473 my $field; # for >=10 tags
474 my $prevvalue; # for <10 tags
475 while (my $row=$sth->fetchrow_hashref) {
476 if ($row->{tagorder} ne $prevtagorder || $row->{tag} ne $prevtag) {
479 $record->add_fields((sprintf "%03s",$prevtag),$prevvalue) unless $prevtag eq "XXX"; # ignore the 1st loop
481 $record->add_fields($field) unless $prevtag eq "XXX";
484 $prevtagorder=$row->{tagorder};
485 $prevtag = $row->{tag};
486 $previndicator=$row->{tag_indicator};
487 if ($row->{tag}<10) {
488 $prevvalue = $row->{subfieldvalue};
490 $field = MARC::Field->new((sprintf "%03s",$prevtag), substr($row->{tag_indicator}.' ',0,1), substr($row->{tag_indicator}.' ',1,1), $row->{'subfieldcode'}, $row->{'subfieldvalue'} );
493 if ($row->{tag} <10) {
494 $record->add_fields((sprintf "%03s",$row->{tag}), $row->{'subfieldvalue'});
496 $field->add_subfields($row->{'subfieldcode'}, $row->{'subfieldvalue'} );
498 $prevtag= $row->{tag};
499 $previndicator=$row->{tag_indicator};
502 # the last has not been included inside the loop... do it now !
503 if ($prevtag ne "XXX") { # check that we have found something. Otherwise, prevtag is still XXX and we
504 # must return an empty record, not make MARC::Record fail because we try to
505 # create a record with XXX as field :-(
507 $record->add_fields($prevtag,$prevvalue);
509 # my $field = MARC::Field->new( $prevtag, "", "", %subfieldlist);
510 $record->add_fields($field);
516 sub AUTHgetauth_type {
517 my ($authtypecode) = @_;
518 my $dbh=C4::Context->dbh;
519 my $sth=$dbh->prepare("select * from auth_types where authtypecode=?");
520 $sth->execute($authtypecode);
521 return $sth->fetchrow_hashref;
523 sub AUTHmodauthority {
524 my ($dbh,$authid,$record,$delete)=@_;
525 my $oldrecord=&AUTHgetauthority($dbh,$authid);
526 if ($oldrecord eq $record) {
529 # 1st delete the authority,
531 &AUTHdelauthority($dbh,$authid,1);
532 &AUTHaddauthority($dbh,$record,$authid,AUTHfind_authtypecode($dbh,$authid));
533 # save the file in localfile/modified_authorities
534 my $filename = C4::Context->config("intranetdir")."/localfile/modified_authorities/$authid.authid";
535 open AUTH, "> $filename";
540 sub AUTHdelauthority {
541 my ($dbh,$authid,$keep_biblio) = @_;
542 # if the keep_biblio is set to 1, then authority entries in biblio are preserved.
543 # This flag is set when the delauthority is called by modauthority
544 # due to a too complex structure of MARC (repeatable fields and subfields),
545 # the best solution for a modif is to delete / recreate the record.
547 my $record = AUTHgetauthority($dbh,$authid);
548 $dbh->do("delete from auth_header where authid=$authid") unless $keep_biblio;
549 $dbh->do("delete from auth_subfield_table where authid=$authid");
550 $dbh->do("delete from auth_word where authid=$authid");
551 # FIXME : delete or not in biblio tables (depending on $keep_biblio flag)
554 sub AUTHmodsubfield {
555 # Subroutine changes a subfield value given a subfieldid.
556 my ($dbh, $subfieldid, $subfieldvalue )=@_;
557 $dbh->do("lock tables auth_subfield_table WRITE");
558 my $sth=$dbh->prepare("update auth_subfield_table set subfieldvalue=? where subfieldid=?");
559 $sth->execute($subfieldvalue, $subfieldid);
560 $dbh->do("unlock tables");
562 $sth=$dbh->prepare("select authid,tag,tagorder,subfieldcode,subfieldid,subfieldorder from auth_subfield_table where subfieldid=?");
563 $sth->execute($subfieldid);
564 my ($authid,$tagid,$tagorder,$subfieldcode,$x,$subfieldorder) = $sth->fetchrow;
566 &AUTHdelword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder);
567 &AUTHaddword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalue);
568 return($subfieldid, $subfieldvalue);
571 sub AUTHfindsubfield {
572 my ($dbh,$authid,$tag,$subfieldcode,$subfieldorder,$subfieldvalue) = @_;
576 my $query="select subfieldid from auth_subfield_table where authid=? and tag=? and subfieldcode=?";
577 my @bind_values = ($authid,$tag, $subfieldcode);
578 if ($subfieldvalue) {
579 $query .= " and subfieldvalue=?";
580 push(@bind_values,$subfieldvalue);
582 if ($subfieldorder<1) {
585 $query .= " and subfieldorder=?";
586 push(@bind_values,$subfieldorder);
588 my $sti=$dbh->prepare($query);
589 $sti->execute(@bind_values);
590 while (($subfieldid) = $sti->fetchrow) {
592 $lastsubfieldid=$subfieldid;
594 if ($resultcounter>1) {
595 # Error condition. Values given did not resolve into a unique record. Don't know what to edit
596 # should rarely occur (only if we use subfieldvalue with a value that exists twice, which is strange)
599 return $lastsubfieldid;
603 sub AUTHfindsubfieldid {
604 my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
605 my $sth=$dbh->prepare("select subfieldid from auth_subfield_table
606 where authid=? and tag=? and tagorder=?
607 and subfieldcode=? and subfieldorder=?");
608 $sth->execute($authid,$tag,$tagorder,$subfield,$subfieldorder);
609 my ($res) = $sth->fetchrow;
611 $sth=$dbh->prepare("select subfieldid from auth_subfield_table
612 where authid=? and tag=? and tagorder=?
613 and subfieldcode=?");
614 $sth->execute($authid,$tag,$tagorder,$subfield);
615 ($res) = $sth->fetchrow;
620 sub AUTHfind_authtypecode {
621 my ($dbh,$authid) = @_;
622 my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
623 $sth->execute($authid);
624 my ($authtypecode) = $sth->fetchrow;
625 return $authtypecode;
628 sub AUTHdelsubfield {
629 # delete a subfield for $authid / tag / tagorder / subfield / subfieldorder
630 my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
631 $dbh->do("delete from auth_subfield_table where authid='$authid' and
632 tag='$tag' and tagorder='$tagorder'
633 and subfieldcode='$subfield' and subfieldorder='$subfieldorder'
638 my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
640 my $record = MARC::Record->new();
641 # my %subfieldlist=();
642 my $prevvalue; # if tag <10
643 my $field; # if tag >=10
644 for (my $i=0; $i< @$rtags; $i++) {
645 # rebuild MARC::Record
646 if (@$rtags[$i] ne $prevtag) {
649 $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
653 $record->add_fields($field);
656 $indicators{@$rtags[$i]}.=' ';
657 if (@$rtags[$i] <10) {
658 $prevvalue= @$rvalues[$i];
660 $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
662 $prevtag = @$rtags[$i];
664 if (@$rtags[$i] <10) {
665 $prevvalue=@$rvalues[$i];
668 $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
671 $prevtag= @$rtags[$i];
674 # the last has not been included inside the loop... do it now !
675 $record->add_fields($field);
676 # warn $record->as_formatted;
681 # split a subfield string and adds it into the word table.
683 my ($dbh,$authid,$tag,$tagorder,$subfieldid,$subfieldorder,$sentence) =@_;
684 $sentence =~ s/(\.|\?|\:|\!|\'|,|\-|\"|\(|\)|\[|\]|\{|\})/ /g;
685 my @words = split / /,$sentence;
686 my $stopwords= C4::Context->stopwords;
687 my $sth=$dbh->prepare("insert into auth_word (authid, tagsubfield, tagorder, subfieldorder, word, sndx_word)
688 values (?,concat(?,?),?,?,?,soundex(?))");
689 foreach my $word (@words) {
690 # we record only words longer than 2 car and not in stopwords hash
691 if (length($word)>2 and !($stopwords->{uc($word)})) {
692 $sth->execute($authid,$tag,$subfieldid,$tagorder,$subfieldorder,$word,$word);
694 warn "ERROR ==> insert into auth_word (authid, tagsubfield, tagorder, subfieldorder, word, sndx_word) values ($authid,concat($tag,$subfieldid),$tagorder,$subfieldorder,$word,soundex($word))\n";
701 # delete words. this sub deletes all the words from a sentence. a subfield modif is done by a delete then a add
702 my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
703 my $sth=$dbh->prepare("delete from auth_word where authid=? and tagsubfield=concat(?,?) and tagorder=? and subfieldorder=?");
704 $sth->execute($authid,$tag,$subfield,$tagorder,$subfieldorder);
708 # converts ISO 5426 coded string to ISO 8859-1
709 # sloppy code : should be improved in next issue
710 my ($string,$encoding) = @_ ;
712 # $encoding = C4::Context->preference("marcflavour") unless $encoding;
713 if ($encoding eq "UNIMARC") {
775 # this handles non-sorting blocks (if implementation requires this)
776 $string = nsb_clean($_) ;
777 } elsif ($encoding eq "USMARC" || $encoding eq "MARC21") {
830 # this handles non-sorting blocks (if implementation requires this)
831 $string = nsb_clean($_) ;
838 my $NSB = '\x88' ; # NSB : begin Non Sorting Block
839 my $NSE = '\x89' ; # NSE : Non Sorting Block end
840 # handles non sorting blocks
844 s/[ ]{0,1}$NSE/) /gm ;
850 my ($record,$authtypecode)=@_;
851 warn "IN for ".$record->as_formatted;
852 my $dbh = C4::Context->dbh;
854 # warn "".$record->as_formatted;
855 my $sth = $dbh->prepare("select auth_tag_to_report,summary from auth_types where authtypecode=?");
856 $sth->execute($authtypecode);
857 my ($auth_tag_to_report,$taglist) = $sth->fetchrow;
859 # build a request for authoritysearch
860 my (@tags, @and_or, @excluding, @operator, @value, $offset, $length);
861 # search on biblio.title
862 # warn " tag a reporter : $auth_tag_to_report";
863 # warn "taglist ".$taglist;
864 my @subfield = split /\[/, $taglist;
866 for (my $i=1; $i<$max;$i++){
867 warn " ".$subfield[$i];
868 $subfield[$i]=substr($subfield[$i],3,1);
869 # warn " ".$subfield[$i];
872 if ($record->fields($auth_tag_to_report)) {
873 my $sth = $dbh->prepare("select tagfield,tagsubfield from auth_subfield_structure where tagfield=? and authtypecode=? ");
874 $sth->execute($auth_tag_to_report,$authtypecode);
875 # warn " field $auth_tag_to_report exists";
876 while (my ($tag,$subfield) = $sth->fetchrow){
877 if ($record->field($tag)->subfield($subfield)) {
878 warn "tag :".$tag." subfield: $subfield value : ".$record->field($tag)->subfield($subfield);
879 push @tags, $tag.$subfield;
880 # warn "'".$tag.$subfield."' value :". $record->field($tag)->subfield($subfield);
884 push @value, $record->field($tag)->subfield($subfield);
889 my ($finalresult,$nbresult) = authoritysearch($dbh,\@tags,\@and_or,\@excluding,\@operator,\@value,0,10,$authtypecode);
890 # there is at least 1 result => return the 1st one
892 warn "XXXXX $nbresult => ".@$finalresult[0]->{authid},@$finalresult[0]->{summary};
893 return @$finalresult[0]->{authid},@$finalresult[0]->{summary};
895 # no result, returns nothing
900 END { } # module clean-up code here (global destructor)
906 Koha Developement team <info@koha.org>
908 Paul POULAIN paul.poulain@free.fr
914 # Revision 1.16 2005/05/04 15:43:43 tipaul
915 # synch'ing 2.2 and head
917 # Revision 1.9.2.3 2005/04/28 08:45:33 tipaul
918 # porting FindDuplicate feature for authorities from HEAD to rel_2_2, works correctly now.
920 # Revision 1.9.2.2 2005/02/28 14:03:13 tipaul
921 # * adding search on "main entry" (ie $a subfield) on a given authority (the "search everywhere" field is still here).
922 # * adding a select box to requet "contain" or "begin with" search.
923 # * fixing some bug in authority search (related to "main entry" search)
925 # Revision 1.9.2.1 2005/02/24 13:12:13 tipaul
926 # saving authority modif in a text file. This will be used soon with another script (in crontab). The script in crontab will retrieve every authorityid in the directory localfile/authorities and modify every biblio using this authority. Those modifs may be long. So they can't be done through http, because we may encounter a webserver timeout, and kill the process before end of the job.
927 # So, it will be done through a cron job.
928 # (/me agree we need some doc for command line scripts)
930 # Revision 1.9 2004/12/23 09:48:11 tipaul
931 # Minor changes in summary "exploding" (the 3 digits AFTER the subfield were not on the right place).
933 # Revision 1.8 2004/11/05 10:11:39 tipaul
934 # export auth_count_usage (bugfix)
936 # Revision 1.7 2004/09/23 16:13:00 tipaul
937 # Bugfix in modification
939 # Revision 1.6 2004/08/18 16:00:24 tipaul
940 # fixes for authorities management
942 # Revision 1.5 2004/07/05 13:37:22 doxulting
943 # First step for working authorities
945 # Revision 1.4 2004/06/22 11:35:37 tipaul
946 # removing % at the beginning of a string to avoid loooonnnngggg searchs
948 # Revision 1.3 2004/06/17 08:02:13 tipaul
949 # merging tag & subfield in auth_word for better perfs
951 # Revision 1.2 2004/06/10 08:29:01 tipaul
952 # MARC authority management (continued)
954 # Revision 1.1 2004/06/07 07:35:01 tipaul
955 # MARC authority management package
957 package C4::AuthoritiesMarc;
958 # Copyright 2000-2002 Katipo Communications
960 # This file is part of Koha.
962 # Koha is free software; you can redistribute it and/or modify it under the
963 # terms of the GNU General Public License as published by the Free Software
964 # Foundation; either version 2 of the License, or (at your option) any later
967 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
968 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
969 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
971 # You should have received a copy of the GNU General Public License along with
972 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
973 # Suite 330, Boston, MA 02111-1307 USA
983 use vars qw($VERSION @ISA @EXPORT);
985 # set the version for version checking
992 &AUTHfind_authtypecode
1008 &MARCaddword &MARCdelword
1013 sub authoritysearch {
1014 my ($dbh, $tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode) = @_;
1015 # build the sql request. She will look like :
1017 # from auth_subfield_table as m1, auth_subfield_table as m2
1018 # where m1.authid=m2.authid and
1019 # (m1.subfieldvalue like "Des%" and m2.subfieldvalue like "27%")
1021 # the marclist may contain "mainentry". In this case, search the tag_to_report, that depends on
1022 # the authtypecode. Then, search on $a of this tag_to_report
1023 for (my $i=0;$i<$#{$tags};$i++) {
1024 if (@$tags[$i] eq "mainentry") {
1025 my $sth = $dbh->prepare("select auth_tag_to_report from auth_types where authtypecode=?");
1026 $sth->execute($authtypecode);
1027 my ($tag_to_report) = $sth->fetchrow;
1028 @$tags[$i] = $tag_to_report."a";
1032 # "Normal" statements
1033 # quote marc fields/subfields
1034 for (my $i=0;$i<=$#{$tags};$i++) {
1035 # warn " $i: ".@$tags[$i];
1037 @$tags[$i] = $dbh->quote(@$tags[$i]);
1038 # warn " $i After process: ".@$tags[$i];
1041 my @normal_tags = ();
1042 my @normal_and_or = ();
1043 my @normal_operator = ();
1044 my @normal_value = ();
1045 # Extracts the NOT statements from the list of statements
1046 for(my $i = 0 ; $i <= $#{$value} ; $i++)
1048 if(@$operator[$i] eq "contains") # if operator is contains, splits the words in separate requests
1050 foreach my $word (split(/ /, @$value[$i]))
1052 unless (C4::Context->stopwords->{uc($word)}) { #it's NOT a stopword => use it. Otherwise, ignore
1053 my $tag = substr(@$tags[$i],0,3);
1054 my $subf = substr(@$tags[$i],3,1);
1055 push @normal_tags, @$tags[$i];
1056 push @normal_and_or, "and"; # assumes "foo" and "bar" if "foo bar" is entered
1057 push @normal_operator, @$operator[$i];
1058 push @normal_value, $word;
1064 push @normal_tags, @$tags[$i];
1065 push @normal_and_or, @$and_or[$i];
1066 push @normal_operator, @$operator[$i];
1067 push @normal_value, @$value[$i];
1071 # Finds the basic results without the NOT requests
1072 my ($sql_tables, $sql_where1, $sql_where2) = create_request($dbh,\@normal_tags, \@normal_and_or, \@normal_operator, \@normal_value);
1077 $sth = $dbh->prepare("select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where2 and ($sql_where1)");
1078 warn "Q2 : select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where2 and ($sql_where1)";
1080 $sth = $dbh->prepare("select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where1");
1081 warn "Q : select distinct m1.authid from auth_header,$sql_tables where m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where1";
1083 $sth->execute($authtypecode);
1085 while (my ($authid) = $sth->fetchrow) {
1086 push @result,$authid;
1089 # we have authid list. Now, loads summary from [offset] to [offset]+[length]
1090 my $counter = $offset;
1091 my @finalresult = ();
1093 while (($counter <= $#result) && ($counter <= ($offset + $length))) {
1094 # warn " HERE : $counter, $#result, $offset, $length";
1095 # get MARC::Record of the authority
1096 my $record = AUTHgetauthority($dbh,$result[$counter]);
1097 # then build the summary
1098 my $authtypecode = AUTHfind_authtypecode($dbh,$result[$counter]);
1099 my $authref = getauthtype($authtypecode);
1100 my $summary = $authref->{summary};
1101 my @fields = $record->fields();
1102 foreach my $field (@fields) {
1103 my $tag = $field->tag();
1106 my @subf = $field->subfields;
1107 for my $i (0..$#subf) {
1108 my $subfieldcode = $subf[$i][0];
1109 my $subfieldvalue = $subf[$i][1];
1110 my $tagsubf = $tag.$subfieldcode;
1111 $summary =~ s/\[(.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
1115 $summary =~ s/\[(.*?)]//g;
1116 $summary =~ s/\n/<br>/g;
1118 # find biblio MARC field using this authtypecode (to jump to biblio)
1119 my $authtypecode = AUTHfind_authtypecode($dbh,$result[$counter]);
1120 my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
1121 $sth->execute($authtypecode);
1122 my $tags_using_authtype;
1123 while (my ($tagfield) = $sth->fetchrow) {
1124 # warn "TAG : $tagfield";
1125 $tags_using_authtype.= $tagfield."9,";
1127 chop $tags_using_authtype;
1129 # then add a line for the template loop
1131 $newline{summary} = $summary;
1132 $newline{authid} = $result[$counter];
1133 $newline{used} = &AUTHcount_usage($result[$counter]);
1134 $newline{biblio_fields} = $tags_using_authtype;
1135 $newline{marcrecord} = $record;
1137 push @finalresult, \%newline;
1139 my $nbresults = $#result + 1;
1140 return (\@finalresult, $nbresults);
1143 # Creates the SQL Request
1145 sub create_request {
1146 my ($dbh,$tags, $and_or, $operator, $value) = @_;
1148 my $sql_tables; # will contain marc_subfield_table as m1,...
1149 my $sql_where1; # will contain the "true" where
1150 my $sql_where2 = "("; # will contain m1.authid=m2.authid
1151 my $nb_active=0; # will contain the number of "active" entries. and entry is active is a value is provided.
1152 my $nb_table=1; # will contain the number of table. ++ on each entry EXCEPT when an OR is provided.
1155 for(my $i=0; $i<=@$value;$i++) {
1158 # warn " @$tags[$i]";
1159 if ($nb_active==1) {
1160 if (@$operator[$i] eq "start") {
1161 $sql_tables .= "auth_subfield_table as m$nb_table,";
1162 $sql_where1 .= "(m1.subfieldvalue like ".$dbh->quote("@$value[$i]%");
1164 $sql_where1 .=" and m1.tag+m1.subfieldcode in (@$tags[$i])";
1167 } elsif (@$operator[$i] eq "contains") {
1168 $sql_tables .= "auth_word as m$nb_table,";
1169 $sql_where1 .= "(m1.word like ".$dbh->quote("@$value[$i]%");
1171 $sql_where1 .=" and m1.tagsubfield in (@$tags[$i])";
1176 $sql_tables .= "auth_subfield_table as m$nb_table,";
1177 $sql_where1 .= "(m1.subfieldvalue @$operator[$i] ".$dbh->quote("@$value[$i]");
1179 $sql_where1 .=" and m1.tag+m1.subfieldcode in (@$tags[$i])";
1184 if (@$operator[$i] eq "start") {
1186 $sql_tables .= "auth_subfield_table as m$nb_table,";
1187 $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue like ".$dbh->quote("@$value[$i]%");
1189 $sql_where1 .=" and m$nb_table.tag+m$nb_table.subfieldcode in (@$tags[$i])";
1192 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
1193 } elsif (@$operator[$i] eq "contains") {
1194 if (@$and_or[$i] eq 'and') {
1196 $sql_tables .= "auth_word as m$nb_table,";
1197 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]%");
1199 $sql_where1 .=" and m$nb_table.tagsubfield in(@$tags[$i])";
1202 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
1204 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]%");
1206 $sql_where1 .=" and m$nb_table.tag+m$nb_table.subfieldid in (@$tags[$i])";
1209 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
1213 $sql_tables .= "auth_subfield_table as m$nb_table,";
1214 $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue @$operator[$i] ".$dbh->quote(@$value[$i]);
1216 $sql_where1 .=" and m$nb_table.tag+m$nb_table.subfieldcode in (@$tags[$i])";
1218 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
1225 if($sql_where2 ne "(") # some datas added to sql_where2, processing
1227 $sql_where2 = substr($sql_where2, 0, (length($sql_where2)-5)); # deletes the trailing ' and '
1230 else # no sql_where2 statement, deleting '('
1234 chop $sql_tables; # deletes the trailing ','
1236 return ($sql_tables, $sql_where1, $sql_where2);
1240 sub AUTHcount_usage {
1242 my $dbh = C4::Context->dbh;
1243 # find MARC fields using this authtype
1244 my $authtypecode = AUTHfind_authtypecode($dbh,$authid);
1245 my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
1246 $sth->execute($authtypecode);
1247 my $tags_using_authtype;
1248 while (my ($tagfield) = $sth->fetchrow) {
1249 # warn "TAG : $tagfield";
1250 $tags_using_authtype.= "'".$tagfield."9',";
1252 chop $tags_using_authtype;
1253 if ($tags_using_authtype) {
1254 $sth = $dbh->prepare("select count(*) from marc_subfield_table where concat(tag,subfieldcode) in ($tags_using_authtype) and subfieldvalue=?");
1256 $sth = $dbh->prepare("select count(*) from marc_subfield_table where subfieldvalue=?");
1258 # warn "Q : select count(*) from marc_subfield_table where concat(tag,subfieldcode) in ($tags_using_authtype) and subfieldvalue=$authid";
1259 $sth->execute($authid);
1260 my ($result) = $sth->fetchrow;
1261 # warn "Authority $authid TOTAL USED : $result";
1265 # merging 2 authority entries. After a merge, the "from" can be deleted.
1267 # my ($auth_merge_from,$auth_merge_to) = @_;
1268 # my $dbh = C4::Context->dbh;
1269 # # find MARC fields using this authtype
1270 # my $authtypecode = AUTHfind_authtypecode($dbh,$authid);
1271 # # retrieve records
1272 # my $record_from = AUTHgetauthority($dbh,$auth_merge_from);
1273 # my $record_to = AUTHgetauthority($dbh,$auth_merge_to);
1274 # my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
1275 # $sth->execute($authtypecode);
1276 # my $tags_using_authtype;
1277 # while (my ($tagfield) = $sth->fetchrow) {
1278 # warn "TAG : $tagfield";
1279 # $tags_using_authtype.= "'".$tagfield."9',";
1281 # chop $tags_using_authtype;
1282 # # now, find every biblio using this authority
1283 # $sth = $dbh->prepare("select bibid,tag,tag_indicator,tagorder from marc_subfield_table where tag+subfieldid in ($tags_using_authtype) and subfieldvalue=?");
1284 # $sth->execute($authid);
1285 # # and delete entries before recreating them
1286 # while (my ($bibid,$tag,$tag_indicator,$tagorder) = $sth->fetchrow) {
1287 # &MARCdelsubfield($dbh,$bibid,$tag);
1293 sub AUTHfind_authtypecode {
1294 my ($dbh,$authid) = @_;
1295 my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
1296 $sth->execute($authid);
1297 my ($authtypecode) = $sth->fetchrow;
1298 return $authtypecode;
1302 sub AUTHgettagslib {
1303 my ($dbh,$forlibrarian,$authtypecode)= @_;
1304 $authtypecode="" unless $authtypecode;
1306 my $libfield = ($forlibrarian eq 1)? 'liblibrarian' : 'libopac';
1307 # check that framework exists
1308 $sth=$dbh->prepare("select count(*) from auth_tag_structure where authtypecode=?");
1309 $sth->execute($authtypecode);
1310 my ($total) = $sth->fetchrow;
1311 $authtypecode="" unless ($total >0);
1312 $sth=$dbh->prepare("select tagfield,$libfield as lib,mandatory,repeatable from auth_tag_structure where authtypecode=? order by tagfield");
1313 $sth->execute($authtypecode);
1314 my ($lib,$tag,$res,$tab,$mandatory,$repeatable);
1315 while ( ($tag,$lib,$mandatory,$repeatable) = $sth->fetchrow) {
1316 $res->{$tag}->{lib}=$lib;
1317 $res->{$tab}->{tab}=""; # XXX
1318 $res->{$tag}->{mandatory}=$mandatory;
1319 $res->{$tag}->{repeatable}=$repeatable;
1322 $sth=$dbh->prepare("select tagfield,tagsubfield,$libfield as lib,tab, mandatory, repeatable,authorised_value,value_builder,seealso from auth_subfield_structure where authtypecode=? order by tagfield,tagsubfield");
1323 $sth->execute($authtypecode);
1326 my $authorised_value;
1327 my $thesaurus_category;
1333 while ( ($tag, $subfield, $lib, $tab, $mandatory, $repeatable,$authorised_value,$value_builder,$seealso) = $sth->fetchrow) {
1334 $res->{$tag}->{$subfield}->{lib}=$lib;
1335 $res->{$tag}->{$subfield}->{tab}=$tab;
1336 $res->{$tag}->{$subfield}->{mandatory}=$mandatory;
1337 $res->{$tag}->{$subfield}->{repeatable}=$repeatable;
1338 $res->{$tag}->{$subfield}->{authorised_value}=$authorised_value;
1339 $res->{$tag}->{$subfield}->{thesaurus_category}=$thesaurus_category;
1340 $res->{$tag}->{$subfield}->{value_builder}=$value_builder;
1341 $res->{$tag}->{$subfield}->{seealso}=$seealso;
1342 $res->{$tag}->{$subfield}->{hidden}=$hidden;
1343 $res->{$tag}->{$subfield}->{isurl}=$isurl;
1348 sub AUTHaddauthority {
1349 # pass the MARC::Record to this function, and it will create the records in the marc tables
1350 my ($dbh,$record,$authid,$authtypecode) = @_;
1351 my @fields=$record->fields();
1352 # warn "IN AUTHaddauthority $authid => ".$record->as_formatted;
1353 # adding main table, and retrieving authid
1354 # if authid is sent, then it's not a true add, it's only a re-add, after a delete (ie, a mod)
1355 # if authid empty => true add, find a new authid number
1357 $dbh->do("lock tables auth_header WRITE,auth_subfield_table WRITE, auth_word WRITE, stopwords READ");
1358 my $sth=$dbh->prepare("insert into auth_header (datecreated,authtypecode) values (now(),?)");
1359 $sth->execute($authtypecode);
1360 $sth=$dbh->prepare("select max(authid) from auth_header");
1362 ($authid)=$sth->fetchrow;
1366 # now, add subfields...
1367 foreach my $field (@fields) {
1369 if ($field->tag() <10) {
1370 &AUTHaddsubfield($dbh,$authid,
1379 my @subfields=$field->subfields();
1380 foreach my $subfieldcount (0..$#subfields) {
1381 &AUTHaddsubfield($dbh,$authid,
1383 $field->indicator(1).$field->indicator(2),
1385 $subfields[$subfieldcount][0],
1387 $subfields[$subfieldcount][1]
1392 $dbh->do("unlock tables");
1397 sub AUTHaddsubfield {
1398 # Add a new subfield to a tag into the DB.
1399 my ($dbh,$authid,$tagid,$tag_indicator,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalues) = @_;
1400 # if not value, end of job, we do nothing
1401 if (length($subfieldvalues) ==0) {
1404 if (not($subfieldcode)) {
1407 my @subfieldvalues = split /\|/,$subfieldvalues;
1408 foreach my $subfieldvalue (@subfieldvalues) {
1409 my $sth=$dbh->prepare("insert into auth_subfield_table (authid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue) values (?,?,?,?,?,?,?)");
1410 $sth->execute($authid,(sprintf "%03s",$tagid),$tagorder,$tag_indicator,$subfieldcode,$subfieldorder,$subfieldvalue);
1412 warn "ERROR ==> insert into auth_subfield_table (authid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue) values ($authid,$tagid,$tagorder,$tag_indicator,$subfieldcode,$subfieldorder,$subfieldvalue)\n";
1414 &AUTHaddword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalue);
1418 sub AUTHgetauthority {
1419 # Returns MARC::Record of the biblio passed in parameter.
1420 my ($dbh,$authid)=@_;
1421 my $record = MARC::Record->new();
1422 #---- TODO : the leader is missing
1423 $record->leader(' ');
1424 my $sth=$dbh->prepare("select authid,subfieldid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue
1425 from auth_subfield_table
1426 where authid=? order by tag,tagorder,subfieldcode
1428 $sth->execute($authid);
1432 my $field; # for >=10 tags
1433 my $prevvalue; # for <10 tags
1434 while (my $row=$sth->fetchrow_hashref) {
1435 if ($row->{tagorder} ne $prevtagorder || $row->{tag} ne $prevtag) {
1436 $previndicator.=" ";
1438 $record->add_fields((sprintf "%03s",$prevtag),$prevvalue) unless $prevtag eq "XXX"; # ignore the 1st loop
1440 $record->add_fields($field) unless $prevtag eq "XXX";
1443 $prevtagorder=$row->{tagorder};
1444 $prevtag = $row->{tag};
1445 $previndicator=$row->{tag_indicator};
1446 if ($row->{tag}<10) {
1447 $prevvalue = $row->{subfieldvalue};
1449 $field = MARC::Field->new((sprintf "%03s",$prevtag), substr($row->{tag_indicator}.' ',0,1), substr($row->{tag_indicator}.' ',1,1), $row->{'subfieldcode'}, $row->{'subfieldvalue'} );
1452 if ($row->{tag} <10) {
1453 $record->add_fields((sprintf "%03s",$row->{tag}), $row->{'subfieldvalue'});
1455 $field->add_subfields($row->{'subfieldcode'}, $row->{'subfieldvalue'} );
1457 $prevtag= $row->{tag};
1458 $previndicator=$row->{tag_indicator};
1461 # the last has not been included inside the loop... do it now !
1462 if ($prevtag ne "XXX") { # check that we have found something. Otherwise, prevtag is still XXX and we
1463 # must return an empty record, not make MARC::Record fail because we try to
1464 # create a record with XXX as field :-(
1466 $record->add_fields($prevtag,$prevvalue);
1468 # my $field = MARC::Field->new( $prevtag, "", "", %subfieldlist);
1469 $record->add_fields($field);
1475 sub AUTHgetauth_type {
1476 my ($authtypecode) = @_;
1477 my $dbh=C4::Context->dbh;
1478 my $sth=$dbh->prepare("select * from auth_types where authtypecode=?");
1479 $sth->execute($authtypecode);
1480 return $sth->fetchrow_hashref;
1482 sub AUTHmodauthority {
1483 my ($dbh,$authid,$record,$delete)=@_;
1484 my $oldrecord=&AUTHgetauthority($dbh,$authid);
1485 if ($oldrecord eq $record) {
1488 # 1st delete the authority,
1490 &AUTHdelauthority($dbh,$authid,1);
1491 &AUTHaddauthority($dbh,$record,$authid,AUTHfind_authtypecode($dbh,$authid));
1492 # save the file in localfile/modified_authorities
1493 my $filename = C4::Context->config("intranetdir")."/localfile/modified_authorities/$authid.authid";
1494 open AUTH, "> $filename";
1499 sub AUTHdelauthority {
1500 my ($dbh,$authid,$keep_biblio) = @_;
1501 # if the keep_biblio is set to 1, then authority entries in biblio are preserved.
1502 # This flag is set when the delauthority is called by modauthority
1503 # due to a too complex structure of MARC (repeatable fields and subfields),
1504 # the best solution for a modif is to delete / recreate the record.
1506 my $record = AUTHgetauthority($dbh,$authid);
1507 $dbh->do("delete from auth_header where authid=$authid") unless $keep_biblio;
1508 $dbh->do("delete from auth_subfield_table where authid=$authid");
1509 $dbh->do("delete from auth_word where authid=$authid");
1510 # FIXME : delete or not in biblio tables (depending on $keep_biblio flag)
1513 sub AUTHmodsubfield {
1514 # Subroutine changes a subfield value given a subfieldid.
1515 my ($dbh, $subfieldid, $subfieldvalue )=@_;
1516 $dbh->do("lock tables auth_subfield_table WRITE");
1517 my $sth=$dbh->prepare("update auth_subfield_table set subfieldvalue=? where subfieldid=?");
1518 $sth->execute($subfieldvalue, $subfieldid);
1519 $dbh->do("unlock tables");
1521 $sth=$dbh->prepare("select authid,tag,tagorder,subfieldcode,subfieldid,subfieldorder from auth_subfield_table where subfieldid=?");
1522 $sth->execute($subfieldid);
1523 my ($authid,$tagid,$tagorder,$subfieldcode,$x,$subfieldorder) = $sth->fetchrow;
1525 &AUTHdelword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder);
1526 &AUTHaddword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalue);
1527 return($subfieldid, $subfieldvalue);
1530 sub AUTHfindsubfield {
1531 my ($dbh,$authid,$tag,$subfieldcode,$subfieldorder,$subfieldvalue) = @_;
1532 my $resultcounter=0;
1535 my $query="select subfieldid from auth_subfield_table where authid=? and tag=? and subfieldcode=?";
1536 my @bind_values = ($authid,$tag, $subfieldcode);
1537 if ($subfieldvalue) {
1538 $query .= " and subfieldvalue=?";
1539 push(@bind_values,$subfieldvalue);
1541 if ($subfieldorder<1) {
1544 $query .= " and subfieldorder=?";
1545 push(@bind_values,$subfieldorder);
1547 my $sti=$dbh->prepare($query);
1548 $sti->execute(@bind_values);
1549 while (($subfieldid) = $sti->fetchrow) {
1551 $lastsubfieldid=$subfieldid;
1553 if ($resultcounter>1) {
1554 # Error condition. Values given did not resolve into a unique record. Don't know what to edit
1555 # should rarely occur (only if we use subfieldvalue with a value that exists twice, which is strange)
1558 return $lastsubfieldid;
1562 sub AUTHfindsubfieldid {
1563 my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
1564 my $sth=$dbh->prepare("select subfieldid from auth_subfield_table
1565 where authid=? and tag=? and tagorder=?
1566 and subfieldcode=? and subfieldorder=?");
1567 $sth->execute($authid,$tag,$tagorder,$subfield,$subfieldorder);
1568 my ($res) = $sth->fetchrow;
1570 $sth=$dbh->prepare("select subfieldid from auth_subfield_table
1571 where authid=? and tag=? and tagorder=?
1572 and subfieldcode=?");
1573 $sth->execute($authid,$tag,$tagorder,$subfield);
1574 ($res) = $sth->fetchrow;
1579 sub AUTHfind_authtypecode {
1580 my ($dbh,$authid) = @_;
1581 my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
1582 $sth->execute($authid);
1583 my ($authtypecode) = $sth->fetchrow;
1584 return $authtypecode;
1587 sub AUTHdelsubfield {
1588 # delete a subfield for $authid / tag / tagorder / subfield / subfieldorder
1589 my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
1590 $dbh->do("delete from auth_subfield_table where authid='$authid' and
1591 tag='$tag' and tagorder='$tagorder'
1592 and subfieldcode='$subfield' and subfieldorder='$subfieldorder'
1597 my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
1599 my $record = MARC::Record->new();
1600 # my %subfieldlist=();
1601 my $prevvalue; # if tag <10
1602 my $field; # if tag >=10
1603 for (my $i=0; $i< @$rtags; $i++) {
1604 # rebuild MARC::Record
1605 if (@$rtags[$i] ne $prevtag) {
1606 if ($prevtag < 10) {
1608 $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
1612 $record->add_fields($field);
1615 $indicators{@$rtags[$i]}.=' ';
1616 if (@$rtags[$i] <10) {
1617 $prevvalue= @$rvalues[$i];
1619 $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
1621 $prevtag = @$rtags[$i];
1623 if (@$rtags[$i] <10) {
1624 $prevvalue=@$rvalues[$i];
1626 if (@$rvalues[$i]) {
1627 $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
1630 $prevtag= @$rtags[$i];
1633 # the last has not been included inside the loop... do it now !
1634 $record->add_fields($field);
1635 # warn $record->as_formatted;
1640 # split a subfield string and adds it into the word table.
1642 my ($dbh,$authid,$tag,$tagorder,$subfieldid,$subfieldorder,$sentence) =@_;
1643 $sentence =~ s/(\.|\?|\:|\!|\'|,|\-|\"|\(|\)|\[|\]|\{|\})/ /g;
1644 my @words = split / /,$sentence;
1645 my $stopwords= C4::Context->stopwords;
1646 my $sth=$dbh->prepare("insert into auth_word (authid, tagsubfield, tagorder, subfieldorder, word, sndx_word)
1647 values (?,concat(?,?),?,?,?,soundex(?))");
1648 foreach my $word (@words) {
1649 # we record only words longer than 2 car and not in stopwords hash
1650 if (length($word)>2 and !($stopwords->{uc($word)})) {
1651 $sth->execute($authid,$tag,$subfieldid,$tagorder,$subfieldorder,$word,$word);
1653 warn "ERROR ==> insert into auth_word (authid, tagsubfield, tagorder, subfieldorder, word, sndx_word) values ($authid,concat($tag,$subfieldid),$tagorder,$subfieldorder,$word,soundex($word))\n";
1660 # delete words. this sub deletes all the words from a sentence. a subfield modif is done by a delete then a add
1661 my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
1662 my $sth=$dbh->prepare("delete from auth_word where authid=? and tagsubfield=concat(?,?) and tagorder=? and subfieldorder=?");
1663 $sth->execute($authid,$tag,$subfield,$tagorder,$subfieldorder);
1667 # converts ISO 5426 coded string to ISO 8859-1
1668 # sloppy code : should be improved in next issue
1669 my ($string,$encoding) = @_ ;
1671 # $encoding = C4::Context->preference("marcflavour") unless $encoding;
1672 if ($encoding eq "UNIMARC") {
1734 # this handles non-sorting blocks (if implementation requires this)
1735 $string = nsb_clean($_) ;
1736 } elsif ($encoding eq "USMARC" || $encoding eq "MARC21") {
1789 # this handles non-sorting blocks (if implementation requires this)
1790 $string = nsb_clean($_) ;
1797 my $NSB = '\x88' ; # NSB : begin Non Sorting Block
1798 my $NSE = '\x89' ; # NSE : Non Sorting Block end
1799 # handles non sorting blocks
1803 s/[ ]{0,1}$NSE/) /gm ;
1809 my ($record,$authtypecode)=@_;
1810 my $dbh = C4::Context->dbh;
1812 # warn "".$record->as_formatted;
1813 # search duplicate on ISBN, easy and fast...
1814 my $sth = $dbh->prepare("select auth_tag_to_report,summary from auth_types where authtypecode=?");
1815 $sth->execute($authtypecode);
1816 my ($auth_tag_to_report,$taglist) = $sth->fetchrow;
1818 # a more complex search : build a request for authoritysearch
1819 my (@tags, @and_or, @excluding, @operator, @value, $offset, $length);
1820 # search on biblio.title
1821 # warn " tag a reporter : $auth_tag_to_report";
1822 warn "taglist ".$taglist;
1823 my @subfield = split /\[/, $taglist;
1824 my $max = @subfield;
1825 for (my $i=1; $i<$max;$i++){
1826 warn " ".$subfield[$i];
1827 $subfield[$i]=substr($subfield[$i],3,1);
1828 warn " ".$subfield[$i];
1831 if ($record->fields($auth_tag_to_report)) {
1832 # foreach my $subfieldcount (1..$#subfield){
1833 # if ($record->field($auth_tag_to_report)->subfields($subfield[$subfieldcount])) {
1834 # # warn "tag :".$tag." subfield: $subfield value : ".$record->field($tag)->subfield($subfield);
1835 # push @tags, $auth_tag_to_report.$subfield[$subfieldcount];
1836 # # warn "'".$tag.$subfield."' value :". $record->field($tag)->subfield($subfield);
1837 # push @and_or, "and";
1838 # push @excluding, "";
1839 # push @operator, "contains";
1840 # push @value, $record->field($auth_tag_to_report)->subfield($subfield[$subfieldcount]);
1844 my $sth = $dbh->prepare("select tagfield,tagsubfield from auth_subfield_structure where tagfield=? and authtypecode=? ");
1845 $sth->execute($auth_tag_to_report,$authtypecode);
1846 # warn " field $auth_tag_to_report exists";
1847 while (my ($tag,$subfield) = $sth->fetchrow){
1848 if ($record->field($tag)->subfield($subfield)) {
1849 # warn "tag :".$tag." subfield: $subfield value : ".$record->field($tag)->subfield($subfield);
1850 push @tags, $tag.$subfield;
1851 # warn "'".$tag.$subfield."' value :". $record->field($tag)->subfield($subfield);
1852 push @and_or, "and";
1853 push @excluding, "";
1854 push @operator, "contains";
1855 push @value, $record->field($tag)->subfield($subfield);
1860 my ($finalresult,$nbresult) = authoritysearch($dbh,\@tags,\@and_or,\@excluding,\@operator,\@value,0,10,$authtypecode);
1861 # there is at least 1 result => return the 1st one
1863 warn "$nbresult => ".@$finalresult[0]->{authid},$record->field($auth_tag_to_report)->subfield('a');
1864 return @$finalresult[0]->{authid},@$finalresult[0]->{authid},$record->field($auth_tag_to_report)->subfield('a');
1866 # no result, returns nothing
1870 END { } # module clean-up code here (global destructor)
1876 Koha Developement team <info@koha.org>
1878 Paul POULAIN paul.poulain@free.fr
1884 # Revision 1.16 2005/05/04 15:43:43 tipaul
1885 # synch'ing 2.2 and head
1887 # Revision 1.15 2005/05/04 14:18:39 hdl
1888 # adding Marc Record to authoritysearch report
1890 # Revision 1.14 2005/04/05 17:07:46 hdl
1891 # Scanning every the Subfields of auth_tag_to_report for FindDuplicate
1893 # Revision 1.13 2005/04/05 15:23:41 hdl
1894 # Searching for double entries when adding a new authority.
1896 # Revision 1.12 2005/04/05 09:58:48 hdl
1897 # Adding double authority search before creating a new authority
1899 # Revision 1.11 2005/03/07 08:55:29 tipaul
1900 # synch'ing with 2.2
1902 # Revision 1.9.2.2 2005/02/28 14:03:13 tipaul
1903 # * adding search on "main entry" (ie $a subfield) on a given authority (the "search everywhere" field is still here).
1904 # * adding a select box to requet "contain" or "begin with" search.
1905 # * fixing some bug in authority search (related to "main entry" search)
1907 # Revision 1.9.2.1 2005/02/24 13:12:13 tipaul
1908 # saving authority modif in a text file. This will be used soon with another script (in crontab). The script in crontab will retrieve every authorityid in the directory localfile/authorities and modify every biblio using this authority. Those modifs may be long. So they can't be done through http, because we may encounter a webserver timeout, and kill the process before end of the job.
1909 # So, it will be done through a cron job.
1910 # (/me agree we need some doc for command line scripts)
1912 # Revision 1.9 2004/12/23 09:48:11 tipaul
1913 # Minor changes in summary "exploding" (the 3 digits AFTER the subfield were not on the right place).
1915 # Revision 1.8 2004/11/05 10:11:39 tipaul
1916 # export auth_count_usage (bugfix)
1918 # Revision 1.7 2004/09/23 16:13:00 tipaul
1919 # Bugfix in modification
1921 # Revision 1.6 2004/08/18 16:00:24 tipaul
1922 # fixes for authorities management
1924 # Revision 1.5 2004/07/05 13:37:22 doxulting
1925 # First step for working authorities
1927 # Revision 1.4 2004/06/22 11:35:37 tipaul
1928 # removing % at the beginning of a string to avoid loooonnnngggg searchs
1930 # Revision 1.3 2004/06/17 08:02:13 tipaul
1931 # merging tag & subfield in auth_word for better perfs
1933 # Revision 1.2 2004/06/10 08:29:01 tipaul
1934 # MARC authority management (continued)
1936 # Revision 1.1 2004/06/07 07:35:01 tipaul
1937 # MARC authority management package