Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 116 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
CargoBibtexFormat | |
0.00% |
0 / 116 |
|
0.00% |
0 / 6 |
2756 | |
0.00% |
0 / 1 |
allowedParameters | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
generateTitleKey | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
42 | |||
generateAuthorKey | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
12 | |||
generateEntryKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
generateBibtexEntries | |
0.00% |
0 / 76 |
|
0.00% |
0 / 1 |
1332 | |||
queryAndDisplay | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | /** |
3 | * @author Tomás Bolaño |
4 | * @ingroup Cargo |
5 | */ |
6 | |
7 | class CargoBibtexFormat extends CargoDeferredFormat { |
8 | |
9 | public static function allowedParameters() { |
10 | return [ |
11 | 'default entry type' => [ 'type' => 'string' ], |
12 | 'link text' => [ 'type' => 'string' ] |
13 | ]; |
14 | } |
15 | |
16 | /** |
17 | * Returns the first word from $title with a length equal or greater than |
18 | * $numChars. If no word exists, it repeats the process for $numChars-1, |
19 | * $numChars-2, etc., until a word is found. Before returning the word, it |
20 | * removes all non-alphabetic characters. |
21 | * |
22 | * @param string $title |
23 | * @param int $numChars |
24 | */ |
25 | private static function generateTitleKey( $title, $numChars = 5 ) { |
26 | $titleKey = ''; |
27 | if ( $title != '' && $numChars > 0 ) { |
28 | $titleWords = explode( ' ', str_replace( '-', ' ', strtolower( $title ) ) ); |
29 | for ( $i = $numChars; $i > 0; $i-- ) { |
30 | foreach ( $titleWords as $titleWord ) { |
31 | if ( strlen( $titleWord ) >= $i ) { |
32 | $titleKey = preg_replace( "/[^a-zA-Z]/", '', $titleWord ); |
33 | break 2; |
34 | } |
35 | } |
36 | } |
37 | } |
38 | return $titleKey; |
39 | } |
40 | |
41 | /** |
42 | * Returns the last name of the first author. Before returning the last |
43 | * name, removes all non-alphabetic characters. |
44 | * |
45 | * @param string $author The list of authors in bibtex format. |
46 | */ |
47 | private static function generateAuthorKey( $author ) { |
48 | $authorKey = ''; |
49 | if ( $author != '' ) { |
50 | $authorList = explode( ' and ', $author ); |
51 | $firstAuthor = trim( $authorList[0] ); |
52 | |
53 | // A bibtex author can be in different formats: |
54 | // - First von Last |
55 | // - von Last, First |
56 | // - von Last, Jr, First |
57 | // where von is a lowercase particle such as "de" or "de la" |
58 | if ( strpos( $firstAuthor, ',' ) != false ) { |
59 | $vonLast = trim( strtok( $firstAuthor, ',' ) ); |
60 | $nameElems = explode( ' ', $vonLast ); |
61 | } else { |
62 | $nameElems = explode( ' ', $firstAuthor ); |
63 | } |
64 | $lastName = end( $nameElems ); |
65 | |
66 | // If the name has an hyphen ('-') we will keep only the first part |
67 | $authorKey = preg_replace( "/[^a-zA-Z]/", '', strtok( $lastName, '-' ) ); |
68 | $authorKey = strtolower( $authorKey ); |
69 | } |
70 | |
71 | return $authorKey; |
72 | } |
73 | |
74 | /** |
75 | * Returns a key for an entry given the author, the title, and the year. |
76 | */ |
77 | private static function generateEntryKey( $author, $title, $year ) { |
78 | return self::generateAuthorKey( $author ) . $year . self::generateTitleKey( $title ); |
79 | } |
80 | |
81 | /** |
82 | * BibTeX month abbreviations |
83 | * |
84 | * @var string[] |
85 | */ |
86 | private static $monthStrings = [ 'jan', 'feb', 'mar', 'apr', 'may', |
87 | 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ]; |
88 | |
89 | /** |
90 | * This is the list of BibTeX fields that do not have special cases for |
91 | * generating the output. Fields that have special cases are: title, author, |
92 | * editor, pages, month, and year. |
93 | * |
94 | * @var string[] |
95 | */ |
96 | private static $bibtexFields = [ 'address', 'annote', 'booktitle', |
97 | 'chapter', 'crossref', 'doi', 'edition', 'howpublished', 'institution', |
98 | 'journal', 'key', 'note', 'number', 'organization', 'publisher', |
99 | 'school', 'series', 'type', 'volume' ]; |
100 | |
101 | public static function generateBibtexEntries( $valuesTable, $fieldDescriptions, $displayParams ) { |
102 | $defaultEntryType = strtolower( $displayParams['default entry type'] ?? 'article' ); |
103 | |
104 | // We check here the existing fields so that we do not need later |
105 | // to call the array_key_exists function in the for loop |
106 | $bibtexkeyExists = array_key_exists( 'bibtexkey', $fieldDescriptions ); |
107 | $entryTypeExists = array_key_exists( 'entrytype', $fieldDescriptions ); |
108 | |
109 | $dateExists = array_key_exists( 'date', $fieldDescriptions ); |
110 | $yearExists = array_key_exists( 'year', $fieldDescriptions ); |
111 | $monthExists = array_key_exists( 'month', $fieldDescriptions ); |
112 | |
113 | $authorExists = array_key_exists( 'author', $fieldDescriptions ); |
114 | $editorExists = array_key_exists( 'editor', $fieldDescriptions ); |
115 | $titleExists = array_key_exists( 'title', $fieldDescriptions ); |
116 | |
117 | $pagesExists = array_key_exists( 'pages', $fieldDescriptions ); |
118 | $initialPageExists = array_key_exists( 'initialpage', $fieldDescriptions ); |
119 | $lastPageExists = array_key_exists( 'lastpage', $fieldDescriptions ); |
120 | |
121 | // generate array of bibtex fields to output |
122 | $bibtexOutputFields = []; |
123 | foreach ( self::$bibtexFields as $bibtexField ) { |
124 | if ( array_key_exists( $bibtexField, $fieldDescriptions ) ) { |
125 | $bibtexOutputFields[] = $bibtexField; |
126 | } |
127 | } |
128 | |
129 | // Define several strings that will be used to generate the output |
130 | $tabString = ' '; |
131 | $newlineString = "\n"; |
132 | $bibtexEntryBeforeString = ''; |
133 | $bibtexEntryAfterString = "\n\n"; |
134 | |
135 | $text = ''; |
136 | foreach ( $valuesTable as $value ) { |
137 | if ( $entryTypeExists && $value['entrytype'] != '' ) { |
138 | $entryType = $value['entrytype']; |
139 | } else { |
140 | $entryType = $defaultEntryType; |
141 | } |
142 | |
143 | // Obtain values for the fields year, month, author, editor, and title |
144 | if ( $dateExists && $value['date'] != '' ) { |
145 | $year = strtok( $value['date'], '-' ); |
146 | if ( $value['date__precision'] <= 2 ) { |
147 | $month = ltrim( strtok( '-' ), '0' ); |
148 | } else { |
149 | $month = ''; |
150 | } |
151 | } else { |
152 | $year = $yearExists ? $value['year'] : ''; |
153 | $month = $monthExists ? $value['month'] : ''; |
154 | } |
155 | |
156 | if ( $authorExists && $value['author'] != '' ) { |
157 | if ( $fieldDescriptions['author']->mIsList ) { |
158 | $delimiter = $fieldDescriptions['author']->getDelimiter(); |
159 | $author = str_replace( $delimiter, ' and ', $value['author'] ); |
160 | } else { |
161 | $author = $value['author']; |
162 | } |
163 | } else { |
164 | $author = ''; |
165 | } |
166 | |
167 | if ( $editorExists && $value['editor'] != '' ) { |
168 | if ( $fieldDescriptions['editor']->mIsList ) { |
169 | $delimiter = $fieldDescriptions['editor']->getDelimiter(); |
170 | $editor = str_replace( $delimiter, ' and ', $value['editor'] ); |
171 | } else { |
172 | $editor = $value['editor']; |
173 | } |
174 | } else { |
175 | $editor = ''; |
176 | } |
177 | |
178 | $title = $titleExists ? $value['title'] : ''; |
179 | |
180 | // Generate the entry header (entry type and key) |
181 | $text .= $bibtexEntryBeforeString; |
182 | $text .= '@' . $entryType . '{'; |
183 | if ( $bibtexkeyExists && $value['bibtexkey'] != '' ) { |
184 | $text .= $value['bibtexkey']; |
185 | } else { |
186 | $text .= self::generateEntryKey( $author, $title, $year ); |
187 | } |
188 | $text .= ',' . $newlineString; |
189 | |
190 | // Generate title, author, and editor fields |
191 | if ( $title != '' ) { |
192 | $text .= $tabString . 'title={' . $title . '},' . $newlineString; |
193 | } |
194 | |
195 | if ( $author != '' ) { |
196 | $text .= $tabString . 'author={' . $author . '},' . $newlineString; |
197 | } |
198 | |
199 | if ( $editor != '' ) { |
200 | $text .= $tabString . 'editor={' . $editor . '},' . $newlineString; |
201 | } |
202 | |
203 | // Generate remaining fields (except pages, year, and month) |
204 | foreach ( $bibtexOutputFields as $bibtexOutputField ) { |
205 | if ( $value[$bibtexOutputField] != '' ) { |
206 | $text .= $tabString . $bibtexOutputField . '={' . $value[$bibtexOutputField] . '},' . $newlineString; |
207 | } |
208 | } |
209 | |
210 | // Generate pages, year, and month fields |
211 | if ( $pagesExists && $value['pages'] != '' ) { |
212 | $text .= $tabString . 'pages={' . $value['pages'] . '}' . $newlineString; |
213 | } elseif ( $initialPageExists && $lastPageExists && $value['initialpage'] != '' ) { |
214 | $pages = $value['initialpage']; |
215 | if ( $value['lastpage'] != '' && $value['initialpage'] != $value['lastpage'] ) { |
216 | $pages .= '--' . $value['lastpage']; |
217 | } |
218 | $text .= $tabString . 'pages={' . $pages . '},' . $newlineString; |
219 | } |
220 | |
221 | if ( $year != '' ) { |
222 | $text .= $tabString . 'year={' . $year . '},' . $newlineString; |
223 | } |
224 | |
225 | if ( $month != '' ) { |
226 | // For the month field, if it is passed as a number between 1 |
227 | // and 12 we use the three letter month abbreviation (i.e., jan, |
228 | // feb, mar, etc.). If it is passed as any other string, then |
229 | // that string will be used. |
230 | if ( $month >= 1 && $month <= 12 ) { |
231 | $text .= $tabString . 'month=' . self::$monthStrings[$month - 1] . ',' . $newlineString; |
232 | } else { |
233 | $text .= $tabString . 'month={' . $month . '},' . $newlineString; |
234 | } |
235 | } |
236 | |
237 | $text .= '}'; |
238 | $text .= $bibtexEntryAfterString; |
239 | } |
240 | |
241 | return $text; |
242 | } |
243 | |
244 | /** |
245 | * This function creates a link for the query. The query and the bibtex |
246 | * generation are actually executed by the function displayBibtexData of the |
247 | * CargoExport class. |
248 | * |
249 | * @param array $sqlQueries |
250 | * @param array $displayParams |
251 | * @param array|null $querySpecificParams Unused |
252 | * @return string HTML |
253 | */ |
254 | public function queryAndDisplay( $sqlQueries, $displayParams, $querySpecificParams = null ) { |
255 | $ce = SpecialPage::getTitleFor( 'CargoExport' ); |
256 | $queryParams = $this->sqlQueriesToQueryParams( $sqlQueries ); |
257 | $queryParams['format'] = 'bibtex'; |
258 | if ( array_key_exists( 'default entry type', $displayParams ) && $displayParams['default entry type'] != '' ) { |
259 | $queryParams['default entry type'] = $displayParams['default entry type']; |
260 | } |
261 | if ( array_key_exists( 'link text', $displayParams ) && $displayParams['link text'] != '' ) { |
262 | $linkText = $displayParams['link text']; |
263 | } else { |
264 | $linkText = wfMessage( 'cargo-viewbibtex' )->text(); |
265 | } |
266 | $linkAttrs = [ |
267 | 'href' => $ce->getFullURL( $queryParams ), |
268 | 'target' => '_blank' // link will open in a new tab |
269 | ]; |
270 | $text = Html::rawElement( 'a', $linkAttrs, $linkText ); |
271 | |
272 | return $text; |
273 | } |
274 | |
275 | } |