/** * Tests whether the item matches the given types. * * @param string $variable * @return boolean */ protected function validateVariable($variable) { if (Container::getData()->getVariable('type') == $variable) { return true; } return false; }
/** * Tests if the variable is numeric. * * @param string $variable * @return boolean */ protected function validateVariable($variable) { if (preg_match('/^[0-9]+([ ]{0,1}[&|\\-|,][ ]{0,1}[0-9]+)*$|^[A-z]{0,1}[0-9]+[A-z]{0,1}$|^[0-9]+[A-z]{2,3}$/', Container::getData()->getVariable($variable)) == 1) { return true; } return false; }
/** * Disambiguate citations by the name properties. * * @param array $citations */ private function disambiguateByName($citations) { $identical = array(); $last = false; $lastNames = false; foreach ($citations as $id => $citation) { Container::getData()->moveToId($id); $actualNames = $this->names->render(''); if ($last === false) { $identical = array(); $lastNames = $actualNames; $last = $citation; $identical[] = array('id' => $id, 'citation' => $citation, 'position' => $this->getSortedPosition($id), 'names' => $actualNames); } elseif ($last == $citation || $lastNames == $actualNames) { $identical[] = array('id' => $id, 'citation' => $citation, 'position' => $this->getSortedPosition($id), 'names' => $actualNames); } else { if (count($identical) > 1) { $this->disambiguateIdentical($identical); } $last = $citation; $lastNames = $actualNames; $identical = array(); $identical[] = array('id' => $id, 'citation' => $citation, 'position' => $this->getSortedPosition($id), 'names' => $actualNames); } } if (count($identical) > 1) { $this->disambiguateIdentical($identical); } Container::getContext()->leave(); }
/** * Retrieve a variable from the actual entry. * * @param string $name * @return string|integer|null */ public function getVariable($name) { if (isset($this->data[$this->position]) == true && array_key_exists($name, $this->data[$this->position]) == true) { $return = $this->data[$this->position][$name]; if (Container::getAbbreviation() !== false && Container::getAbbreviation()->get($name, $return) !== null) { return Container::getAbbreviation()->get($name, $return); } return $return; } elseif ($name == 'citation-number') { if (Container::getContext()->in('sort') == true) { // index (starting at 1) of the cited reference in the bibliography (generated by the CSL processor) $number = Container::getData()->getPosition(); if (Container::getContext()->get('sort') == 'descending') { $number = Container::getData()->getLength() - $number; } else { $number++; } $this->setVariable('citation-number', (int) $number); return (int) $number; } else { // return position in bibliography if no citation-number is set return (int) $this->position + 1; } } return null; }
/** * Test if label is equal to the variable. * * @param string $variable * @return bool */ protected function validateVariable($variable) { if (Container::getData()->getVariable('label') == $variable || is_object(Container::getCitationItem()) == true && Container::getCitationItem()->get('label') == $variable) { return true; } return false; }
/** * Parses the date-values. * * @param string $variable Variable name * @return boolean */ public function format($variable) { $data = Container::getData()->getVariable($variable); if (isset($data['date-parts']) == true && count($data['date-parts']) > 0) { $this->data = array(); foreach ($data['date-parts'] as $values) { $this->data[] = $this->extractDate($values); } // use season as month if (isset($data['season']) == true) { $this->data[0]['month'] = $this->extractSeason($data['season']); } if (isset($data['raw']) == true) { $this->data[0]['raw'] = $this->formatRaw($data['raw']); } return true; } elseif (is_array($data) == true) { if (isset($data['literal']) == true) { $this->data = array($data); return true; } elseif (isset($data['raw']) == false) { $this->data = array($this->extractDate($data)); return true; } elseif (strtotime($data['raw']) !== false) { $date = new \DateTime($data['raw']); $this->data = array(array('year' => $date->format('Y'), 'month' => $date->format('m'), 'day' => $date->format('d'))); return true; } else { $this->data = array(array('raw' => $data['raw'])); return true; } } return false; }
/** * A date is uncertain if it contains the key "circa". * * @param string $variable * @return boolean */ protected function validateVariable($variable) { $date = Container::getData()->getVariable($variable); if (is_array($date) == true && isset($date['circa']) == true) { return true; } return false; }
/** * With cite grouping, cites in in-text citations with identical rendered names are grouped together. * * @param array $data * @return array */ public function apply(array $data) { $names = Container::getContext()->get('layout', 'layout')->getChildElement('\\Geissler\\CSL\\Names\\Names'); if ($this->active == false || is_object($names) == false || Container::getCitationItem() === false) { return $data; } Container::getCitationItem()->moveToFirst(); $delimiter = Container::getContext()->get('delimiter', 'layout'); if (isset($this->citeGroupDelimiter) == false) { $this->citeGroupDelimiter = $delimiter; $this->citeGroupDelimiter = ', '; } $length = count($data); $newData = array(); for ($i = 0; $i < $length; $i++) { // get all names in citation group $namesAsArray = array(); $namesFull = array(); do { Container::getData()->moveToId(Container::getActualId()); $namesAsArray[] = $names->renderAsArray(''); $namesFull[] = $names->render(''); } while (Container::getCitationItem()->nextInGroup() == true); $newData[$i] = array(); $citeLength = count($namesAsArray); for ($j = 0; $j < $citeLength; $j++) { $actualName = $namesAsArray[$j][0]; // check if name already used if ($actualName !== '' && isset($data[$i][$j]) == true) { $actualGroup = array($data[$i][$j]); $groupPosition = 0; for ($k = $j + 1; $k < $citeLength; $k++) { if ($actualName == $namesAsArray[$k][0] && $namesFull[$j] == $namesFull[$k] && isset($data[$i][$k]) == true) { // replace delimiter in previous group entry with cite group delimiter $actualGroup[$groupPosition]['delimiter'] = $this->citeGroupDelimiter; $actualGroup[] = $data[$i][$k]; $namesAsArray[$k][0] = ''; $groupPosition++; // Add delimiter to values without one if ($actualGroup[$groupPosition]['delimiter'] == '') { $actualGroup[$groupPosition]['delimiter'] = $delimiter; } } } $newData[$i] = array_merge($newData[$i], $actualGroup); } } // remove delimiter from last entry in group $newData[$i][count($newData[$i]) - 1]['delimiter'] = ''; Container::getCitationItem()->next(); } return $newData; }
/** * Try to disambiguate the ambiguous values. If not possible, pass the values to the successor and try to * disambiguate with the successor. If possible, store ambiguous and disambiguated values. */ public function disambiguate() { Container::getContext()->removeDisambiguationOptions('Geissler\\CSL\\Names\\Name'); Container::getContext()->setChooseDisambiguateValue(true); $layout = Container::getContext()->get('layout', 'layout'); $secondary = Container::getCitationItem()->getWithIds(array_keys($this->getAmbiguous())); foreach ($secondary as $entry) { Container::getCitationItem()->moveTo($entry['id'], $entry['citationID']); Container::getData()->moveToId($entry['id']); Container::getRendered()->set($entry['id'], $entry['citationID'], $layout->renderById($entry['id'], '')); } }
/** * Renders, if no previous data has been renderd and a month is required a given season instead. * * @return string */ private function renderSeason() { $data = Container::getData()->getVariable($this->variable); if (isset($data['season']) == true) { $month = false; foreach ($this->dateParts as $datePart) { if ($datePart['name'] == 'month') { $month = true; break; } } if ($month == true) { return Container::getLocale()->getTerms('season-0' . (int) $data['season']); } } return ''; }
/** * Add an alphabetic year-suffix to ambiguous cites. * * @return void */ private function addYearSuffix() { // test if year is rendered, if not try if year is rendered through choose disambiguate $layout = Container::getContext()->get('layout', 'layout'); if (preg_match($this->regExp, current($this->tmpAmbiguous)) == 0 && Container::getContext()->isChooseDisambiguationActive() == true) { Container::getContext()->setChooseDisambiguateValue(true); foreach (array_keys($this->tmpAmbiguous) as $id) { $reRendered = $layout->renderById($id, ''); if (isset($this->tmpAmbiguous[$id]) == true && $reRendered !== $this->tmpAmbiguous[$id]) { $this->tmpAmbiguous[$id] = $reRendered; } } } if (array_values($this->tmpAmbiguous) > array_unique(array_values($this->tmpAmbiguous))) { $useYearSuffix = $layout->isAccessingVariable('year-suffix'); $suffix = 'a'; foreach (array_keys($this->tmpAmbiguous) as $id) { Container::getData()->moveToId($id); $actualSuffix = Container::getData()->getVariable('year-suffix'); if ($actualSuffix === null) { // store year-suffix variable Container::getData()->setVariable('year-suffix', $suffix); $actualSuffix = $suffix; } if (Container::getCitationItem() !== false) { $cites = Container::getCitationItem()->getWithIds(array($id)); foreach ($cites as $entry) { Container::getCitationItem()->moveTo($id, $entry['citationID']); if ($useYearSuffix == true) { Container::getRendered()->clearById($id); Container::getRendered()->set($id, $entry['citationID'], $layout->renderById($id, '')); } else { Container::getRendered()->set($id, $entry['citationID'], $this->addYearSuffixToValue($this->tmpAmbiguous[$id], $actualSuffix)); } } } else { $cites = Container::getRendered()->getAllById(); foreach ($cites as $itemId => $value) { if ($itemId == $id) { if ($useYearSuffix == true) { Container::getRendered()->clearById($id); Container::getRendered()->set($id, 0, $layout->renderById($id, '')); } else { $newValue = $this->addYearSuffixToValue($value, $actualSuffix); Container::getRendered()->set($id, 0, $newValue); $this->tmpDisambiguate[$id] = $newValue; } } } } unset($this->tmpAmbiguous[$id]); $suffix++; } } }
/** * Renders the names for the given ids as array or string. * * @param array $data * @param bool $asArray * @return array */ protected function renderNames($data, $asArray = false) { $names = Container::getContext()->get('layout', 'layout')->getChildElement('\\Geissler\\CSL\\Names\\Names'); if (is_object($names) == false) { return array(); } $ids = array_keys($data); $length = count($ids); $values = array(); for ($i = 0; $i < $length; $i++) { $id = $ids[$i]; Container::getData()->moveToId($id); if ($asArray == false) { $values[$id] = $names->render(''); } else { $values[$id] = $names->renderAsArray(''); } } return $values; }
/** * Render title cases. * * @param string $data * @return string */ private function renderTitle($data) { if (Container::getLocale()->getLanguage() == 'en' && Container::getData()->getVariable('language') == null || Container::getData()->getVariable('language') == 'en') { // In both cases, stop words are lowercased, unless they are the first or last word in the string, // or follow a colon. $stopWords = array('a', 'an', 'and', 'as', 'at', 'but', 'by', 'down', 'for', 'from', 'in', 'into', 'nor', 'of', 'on', 'onto', 'or', 'over', 'so', 'the', 'till', 'to', 'up', 'via', 'with', 'yet'); $values = explode(' ', $data); $length = count($values); if (preg_match('/^[A-Z| |\\.|,]+$/', $data) == 1) { // For uppercase strings, the first character of each word remains capitalized. // All other letters are lowercase. for ($i = 0; $i < $length; $i++) { if ($i > 0 && $i < $length - 1 && in_array(mb_strtolower($values[$i]), $stopWords) == true) { $values[$i] = mb_strtolower($values[$i]); } else { $values[$i] = mb_substr($values[$i], 0, 1) . mb_strtolower(mb_substr($values[$i], 1)); } } } else { // For lower or mixed case strings, the first character of each lowercase word is capitalized. // The case of words in mixed or uppercase stays the same. for ($i = 0; $i < $length; $i++) { if ($i > 0 && $i < $length - 1 && in_array(mb_strtolower($values[$i]), $stopWords) == true) { $values[$i] = mb_strtolower($values[$i]); } else { $values[$i] = mb_strtoupper(mb_substr($values[$i], 0, 1)) . mb_substr($values[$i], 1); } } } return implode(' ', $values); } return $data; }
/** * Renders the variable. * * @param string $data * @return string */ public function render($data) { if ($this->form !== '') { $return = Container::getData()->getVariable($this->name . '-' . $this->form); if ($return !== null) { return $return; } if (is_object(Container::getAbbreviation()) == true) { $return = Container::getAbbreviation()->get($this->name, $this->form); } if ($return !== null) { return $return; } } // special cases switch ($this->name) { case 'title-short': $return = Container::getData()->getVariable('shortTitle'); if ($return !== null) { return $return; } break; case 'title': if ($this->form == 'short') { $return = Container::getData()->getVariable('shortTitle'); if ($return !== null) { return $return; } } break; case 'citation-label': $return = Container::getData()->getVariable($this->name); if ($return !== null) { return $return; } // first 4 letters from the first two author family names and last to year digits $authors = Container::getData()->getVariable('author'); $format = new Format(); if (isset($authors[0]['family']) == true && $format->format('issued') == true) { $year = $format->getData(); if (isset($year[0]['year']) == true) { switch (count($authors)) { case 1: $author = substr($authors[0]['family'], 0, 4); break; case 2: $author = substr($authors[0]['family'], 0, 2) . substr($authors[1]['family'], 0, 2); break; default: $author = ''; for ($i = 0; $i < 4; $i++) { if (preg_match('/[A-Z]/', $authors[$i]['family'], $match) == 1) { $author .= $match[0]; } } break; } $length = strlen($year[0]['year']); return $author . substr($year[0]['year'], $length - 2, $length); } } break; case 'page': $format = Container::getContext()->getValue('pageRangeFormat'); if (is_object($format) == true) { return $format->format(Container::getData()->getVariable($this->name)); } break; case 'first-reference-note-number': // number of a preceding note containing the first reference to the item if (Container::getCitationItem()->get('noteIndex') !== null || Container::getCitationItem()->get('index') !== null) { $first = Container::getRendered()->getPositionOfFirstId(Container::getActualId()); if ($first !== null && $first < Container::getRendered()->getLength()) { return $first; } } break; } $return = Container::getData()->getVariable($this->name); if ($return !== null) { return $return; } // retrieve variables form citations if (Container::getContext()->getName() == 'citation' && Container::getCitationItem() !== false) { $return = Container::getCitationItem()->get($this->name); if ($return !== null) { return $return; } } return ''; }
/** * Render a bibliography. * * @param string $data * @return string */ public function render($data) { // sort $this->sort(); // render citation to create year-suffix if necessary if (Container::getContext()->getValue('disambiguateAddYearSuffix', 'citation') == true) { Container::getContext()->setName('citation'); Container::getData()->moveToFirst(); Container::getCitation()->render($data); Container::getContext()->setName('bibliography'); // re-sort with bibliography keys $this->sort(); } // render Container::getContext()->enter('bibliography'); $result = $this->layout->render($data); Container::getContext()->leave(); // format return $return = '<div class="csl-bib-body"><div class="csl-entry">'; if (is_array($result) == true && count($result) > 0) { $return .= implode('</div><div class="csl-entry">', $result); } else { $return .= $result; } return $return . '</div></div>'; }
/** * Tests whether the cite position matches the given positions * * @param string $variable * @return boolean */ protected function validateVariable($variable) { if (Container::getContext()->getName() == 'bibliography' || Container::getContext()->in('bibliography') == true) { return false; } if (Container::getCitationItem() === false) { if ($variable == 'first') { if (Container::getData()->getPosition() == 0) { return true; } else { return false; } } else { return false; } } switch ($variable) { // position of cites that are the first to reference an item case 'first': $length = Container::getCitationItem()->getPosition(); $actual = Container::getCitationItem()->get('id'); for ($i = 0; $i < $length; $i++) { if (Container::getCitationItem()->getAtPosition('id', $i) == $actual) { return false; } } return true; break; case 'subsequent': $length = Container::getCitationItem()->getPosition(); $actual = Container::getCitationItem()->get('id'); for ($i = 0; $i < $length; $i++) { if (Container::getCitationItem()->getAtPosition('id', $i) == $actual) { return true; } } break; case 'ibid': if ($this->isIbid() == true && (Container::getCitationItem()->get('locator') == $this->getVariableForPrevious('locator') || $this->isIbidWithLocator() == true)) { return true; } return false; break; case 'ibid-with-locator': return $this->isIbidWithLocator(); break; case 'near-note': $nearNote = Container::getCitationItem()->get('near-note'); if ($nearNote !== null) { return $nearNote; } $maxDistance = Container::getContext()->getValue('nearNoteDistance', 'citation'); $position = Container::getCitationItem()->getPosition(); $id = Container::getCitationItem()->get('id'); $start = 0; if ($position > $maxDistance) { $start = $position - $maxDistance; } for ($i = $start; $i < $position; $i++) { $groupPosition = 0; $inGroup = true; while ($inGroup == true) { $actual = Container::getCitationItem()->getAtPosition('id', $i, $groupPosition); if ($actual == null) { $inGroup = false; } elseif ($actual == $id) { return true; } else { $groupPosition++; } } } break; } return false; }
/** * If a Renderable object has tried to use a empty variable it returns true otherwise and when no variable * is used false. Needed for the Group element. * * @return boolean */ public function hasAccessEmptyVariable() { foreach ($this->variables as $variable) { if (Container::getData()->getVariable($variable) !== null) { return false; } } if (isset($this->substitute) == true) { return $this->substitute->hasAccessEmptyVariable(); } return true; }
/** * If a Renderable object has tried to use a empty variable it returns true otherwise and when no variable * is used false. Needed for the Group element. * * @return boolean */ public function hasAccessEmptyVariable() { if (Container::getData()->getVariable($this->variable) === null) { return true; } return false; }
/** * As "partial-each", but substitution is limited to the first name of the name variable. * * @param array $bibliography * @return array */ private function partialFirst($bibliography) { $previous = $this->names->renderAsArray(''); $length = count($bibliography); for ($i = 1; $i < $length; $i++) { Container::getData()->next(); $names = $this->names->renderAsArray(''); if (isset($names[0]) == true && in_array($names[0], $previous) == true) { $bibliography[$i] = preg_replace('/' . preg_quote($names[0], '/') . '/', $this->value, $bibliography[$i]); } $previous = $names; } return $bibliography; }
/** * Generate the actual sorting data based on the bibliography data with the given sorting key. * * @return array */ private function generateBibliographySort() { $sort = array(); $length = count($this->keys); for ($i = 0; $i < $length; $i++) { Container::getData()->moveToFirst(); $position = 0; do { $id = Container::getData()->getVariable('id'); if (isset($sort[$id]) == false) { $sort[$id] = array(); } $sort[$id][] = array($this->removeFormatting($this->keys[$i]['generate']->render(Container::getData()->get())), $position++, $this->keys[$i]['sort'] == 'ascending' ? 'asc' : 'desc', $id); } while (Container::getData()->next() == true); } return $sort; }
/** * Render the entries for the bibliography. * * @param $data * @return array */ private function bibliography($data) { Container::getData()->moveToFirst(); $result = array(); // add year-suffix to the first year rendered through cs:date in the bibliographic entry if (Container::getContext()->getValue('disambiguateAddYearSuffix', 'citation') == true && $this->isAccessingVariable('year-suffix') == false) { $this->modifyChildElement('Geissler\\CSL\\Date\\Date', new \SimpleXMLElement('<date add-year-suffix="true" />')); } do { $entry = array(); foreach ($this->children as $child) { $entry[] = $child->render($data); } $result[] = $this->format($this->applyOptions($entry, true)); } while (Container::getData()->next() == true); return $this->applyOptions($result); }
/** * Render the element. * * @param string $data * @return string */ public function render($data) { switch ($this->variable) { case 'author': case 'collection-editor': case 'composer': case 'container-author': case 'director': case 'editor': case 'editorial-director': case 'illustrator': case 'interviewer': case 'original-author': case 'recipient': case 'reviewed-author': case 'translator': $name = new Name(new \SimpleXMLElement('<name form="long" name-as-sort-order="all"/>')); return $name->render(Container::getData()->getVariable($this->variable)); break; case 'accessed': case 'container': case 'event-date': case 'issued': case 'original-date': case 'submitted': // 00000000 represent the first date and if existing a second date of a date range $format = new Format(); if ($format->format($this->variable) == true) { $data = $format->getData(); $first = $this->formatDate($data[0]); $second = '00000000'; if (isset($data[1]) == true) { $second = $this->formatDate($data[1]); if ($second < $first) { return $second . $first; } return $first . $second; } return $first . $second; } // put empty dates in bibliographies at the end if (Container::getContext()->getName() == 'bibliography') { return ''; } return '0000000000000000'; break; case 'chapter-number': case 'collection-number': case 'edition': case 'issue': case 'number': case 'number-of-pages': case 'number-of-volumes': case 'volume': return (int) Container::getData()->getVariable($this->variable); break; default: return preg_replace('/(<.*?>)(.*?)(<\\/.*?>)/', '$2', Container::getData()->getVariable($this->variable)); break; } }