seboettg /
citeproc-php
| 1 | <?php |
||
| 2 | /* |
||
| 3 | * citeproc-php |
||
| 4 | * |
||
| 5 | * @link http://github.com/seboettg/citeproc-php for the source repository |
||
| 6 | * @copyright Copyright (c) 2016 Sebastian Böttger. |
||
| 7 | * @license https://opensource.org/licenses/MIT |
||
| 8 | */ |
||
| 9 | |||
| 10 | namespace Seboettg\CiteProc\Rendering; |
||
| 11 | |||
| 12 | use Seboettg\CiteProc\CiteProc; |
||
| 13 | use Seboettg\CiteProc\Exception\CiteProcException; |
||
| 14 | use Seboettg\CiteProc\RenderingState; |
||
| 15 | use Seboettg\CiteProc\Styles\AffixesTrait; |
||
| 16 | use Seboettg\CiteProc\Styles\ConsecutivePunctuationCharacterTrait; |
||
| 17 | use Seboettg\CiteProc\Styles\DisplayTrait; |
||
| 18 | use Seboettg\CiteProc\Styles\FormattingTrait; |
||
| 19 | use Seboettg\CiteProc\Styles\QuotesTrait; |
||
| 20 | use Seboettg\CiteProc\Styles\TextCaseTrait; |
||
| 21 | use Seboettg\CiteProc\Terms\Locator; |
||
| 22 | use Seboettg\CiteProc\Util\CiteProcHelper; |
||
| 23 | use Seboettg\CiteProc\Util\NumberHelper; |
||
| 24 | use Seboettg\CiteProc\Util\PageHelper; |
||
| 25 | use Seboettg\CiteProc\Util\StringHelper; |
||
| 26 | use SimpleXMLElement; |
||
| 27 | use stdClass; |
||
| 28 | use function Seboettg\CiteProc\ucfirst; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * Class Term |
||
| 32 | * |
||
| 33 | * @package Seboettg\CiteProc\Node\Style |
||
| 34 | * |
||
| 35 | * @author Sebastian Böttger <[email protected]> |
||
| 36 | */ |
||
| 37 | class Text implements Rendering |
||
| 38 | { |
||
| 39 | use FormattingTrait, |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 40 | AffixesTrait, |
||
| 41 | TextCaseTrait, |
||
| 42 | DisplayTrait, |
||
| 43 | ConsecutivePunctuationCharacterTrait, |
||
| 44 | QuotesTrait; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * @var string |
||
| 48 | */ |
||
| 49 | private string $toRenderType; |
||
| 50 | |||
| 51 | /** |
||
| 52 | * @var string |
||
| 53 | */ |
||
| 54 | private string $toRenderTypeValue; |
||
| 55 | |||
| 56 | /** |
||
| 57 | * @var string |
||
| 58 | */ |
||
| 59 | private string $form = "long"; |
||
| 60 | |||
| 61 | /** |
||
| 62 | * Text constructor. |
||
| 63 | * |
||
| 64 | * @param SimpleXMLElement $node |
||
| 65 | */ |
||
| 66 | public function __construct(SimpleXMLElement $node) |
||
| 67 | { |
||
| 68 | foreach ($node->attributes() as $attribute) { |
||
| 69 | $name = $attribute->getName(); |
||
| 70 | if (in_array($name, ['value', 'variable', 'macro', 'term'])) { |
||
| 71 | $this->toRenderType = $name; |
||
| 72 | $this->toRenderTypeValue = (string) $attribute; |
||
| 73 | } |
||
| 74 | if ($name === "form") { |
||
| 75 | $this->form = (string) $attribute; |
||
| 76 | } |
||
| 77 | } |
||
| 78 | $this->initFormattingAttributes($node); |
||
| 79 | $this->initDisplayAttributes($node); |
||
| 80 | $this->initTextCaseAttributes($node); |
||
| 81 | $this->initAffixesAttributes($node); |
||
| 82 | $this->initQuotesAttributes($node); |
||
| 83 | } |
||
| 84 | |||
| 85 | /** |
||
| 86 | * @param stdClass $data |
||
| 87 | * @param int|null $citationNumber |
||
| 88 | * @return string |
||
| 89 | */ |
||
| 90 | public function render($data, $citationNumber = null) |
||
| 91 | { |
||
| 92 | $lang = (isset($data->language) && $data->language != 'en') ? $data->language : 'en'; |
||
| 93 | |||
| 94 | $renderedText = ""; |
||
| 95 | switch ($this->toRenderType) { |
||
| 96 | case 'value': |
||
| 97 | $renderedText = $this->applyTextCase($this->toRenderTypeValue, $lang); |
||
| 98 | break; |
||
| 99 | case 'variable': |
||
| 100 | if ($this->toRenderTypeValue === "locator" && CiteProc::getContext()->isModeCitation()) { |
||
| 101 | $renderedText = $this->renderLocator($data, $citationNumber); |
||
| 102 | // for test sort_BibliographyCitationNumberDescending.json |
||
| 103 | } elseif ($this->toRenderTypeValue === "citation-number") { |
||
| 104 | $renderedText = $this->renderCitationNumber($data, $citationNumber); |
||
| 105 | break; |
||
| 106 | } elseif (in_array($this->toRenderTypeValue, ["page", "chapter-number", "folio"])) { |
||
| 107 | $renderedText = !empty($data->{$this->toRenderTypeValue}) ? |
||
| 108 | $this->renderPage($data->{$this->toRenderTypeValue}) : ''; |
||
| 109 | } else { |
||
| 110 | $renderedText = $this->renderVariable($data, $lang); |
||
| 111 | } |
||
| 112 | if (CiteProc::getContext()->getRenderingState()->getValue() === RenderingState::SUBSTITUTION) { |
||
| 113 | unset($data->{$this->toRenderTypeValue}); |
||
| 114 | } |
||
| 115 | if (!CiteProcHelper::isUsingAffixesByMarkupExtentsion($data, $this->toRenderTypeValue)) { |
||
| 116 | $renderedText = $this->applyAdditionalMarkupFunction($data, $renderedText); |
||
| 117 | } |
||
| 118 | break; |
||
| 119 | case 'macro': |
||
| 120 | $renderedText = $this->renderMacro($data); |
||
| 121 | break; |
||
| 122 | case 'term': |
||
| 123 | $term = CiteProc::getContext() |
||
| 124 | ->getLocale() |
||
| 125 | ->filter("terms", $this->toRenderTypeValue, $this->form) |
||
| 126 | ->single; |
||
| 127 | $renderedText = !empty($term) ? $this->applyTextCase($term, $lang) : ""; |
||
| 128 | } |
||
| 129 | if (!empty($renderedText)) { |
||
| 130 | $renderedText = $this->formatRenderedText($data, $renderedText); |
||
| 131 | } |
||
| 132 | return $renderedText; |
||
| 133 | } |
||
| 134 | |||
| 135 | /** |
||
| 136 | * @return string |
||
| 137 | */ |
||
| 138 | public function getSource() |
||
| 139 | { |
||
| 140 | return $this->toRenderType; |
||
| 141 | } |
||
| 142 | |||
| 143 | /** |
||
| 144 | * @return string |
||
| 145 | */ |
||
| 146 | public function getVariable() |
||
| 147 | { |
||
| 148 | return $this->toRenderTypeValue; |
||
| 149 | } |
||
| 150 | |||
| 151 | private function renderPage($page) |
||
| 152 | { |
||
| 153 | if (preg_match(NumberHelper::PATTERN_COMMA_AMPERSAND_RANGE, $page)) { |
||
| 154 | $page = $this->normalizeDateRange($page); |
||
| 155 | $ranges = preg_split("/[-–]/", trim($page)); |
||
| 156 | if (count($ranges) > 1) { |
||
| 157 | if (!empty(CiteProc::getContext()->getGlobalOptions()) |
||
| 158 | && !empty(CiteProc::getContext()->getGlobalOptions()->getPageRangeFormat()) |
||
| 159 | ) { |
||
| 160 | return PageHelper::processPageRangeFormats( |
||
| 161 | $ranges, |
||
| 162 | CiteProc::getContext()->getGlobalOptions()->getPageRangeFormat() |
||
| 163 | ); |
||
| 164 | } |
||
| 165 | list($from, $to) = $ranges; |
||
| 166 | return $from . "–" . $to; |
||
| 167 | } |
||
| 168 | } |
||
| 169 | return $page; |
||
| 170 | } |
||
| 171 | |||
| 172 | private function renderLocator($data, $citationNumber) |
||
| 173 | { |
||
| 174 | $citationItem = CiteProc::getContext()->getCitationItemById($data->id); |
||
| 175 | if (!empty($citationItem->label)) { |
||
| 176 | $locatorData = new stdClass(); |
||
| 177 | $propertyName = Locator::mapLocatorLabelToRenderVariable($citationItem->label); |
||
| 178 | $locatorData->{$propertyName} = trim($citationItem->locator); |
||
| 179 | $renderTypeValueTemp = $this->toRenderTypeValue; |
||
| 180 | $this->toRenderTypeValue = $propertyName; |
||
| 181 | $result = $this->render($locatorData, $citationNumber); |
||
| 182 | $this->toRenderTypeValue = $renderTypeValueTemp; |
||
| 183 | return $result; |
||
| 184 | } |
||
| 185 | return isset($citationItem->locator) ? trim($citationItem->locator) : ''; |
||
| 186 | } |
||
| 187 | |||
| 188 | private function normalizeDateRange($page) |
||
| 189 | { |
||
| 190 | if (preg_match("/^(\d+)\s?--?\s?(\d+)$/", trim($page), $matches)) { |
||
| 191 | return $matches[1]."-".$matches[2]; |
||
| 192 | } |
||
| 193 | return $page; |
||
| 194 | } |
||
| 195 | |||
| 196 | /** |
||
| 197 | * @param $data |
||
| 198 | * @param $renderedText |
||
| 199 | * @return mixed |
||
| 200 | */ |
||
| 201 | private function applyAdditionalMarkupFunction($data, $renderedText) |
||
| 202 | { |
||
| 203 | return CiteProcHelper::applyAdditionMarkupFunction($data, $this->toRenderTypeValue, $renderedText); |
||
| 204 | } |
||
| 205 | |||
| 206 | /** |
||
| 207 | * @param $data |
||
| 208 | * @param $lang |
||
| 209 | * @return string |
||
| 210 | */ |
||
| 211 | private function renderVariable($data, $lang) |
||
| 212 | { |
||
| 213 | // check if there is an attribute with prefix short or long e.g. shortTitle or longAbstract |
||
| 214 | // test case group_ShortOutputOnly.json |
||
| 215 | $value = ""; |
||
| 216 | if (in_array($this->form, ["short", "long"])) { |
||
| 217 | $attrWithPrefix = $this->form . ucfirst($this->toRenderTypeValue); |
||
| 218 | $attrWithSuffix = $this->toRenderTypeValue . "-" . $this->form; |
||
| 219 | if (isset($data->{$attrWithPrefix}) && !empty($data->{$attrWithPrefix})) { |
||
| 220 | $value = $data->{$attrWithPrefix}; |
||
| 221 | } else { |
||
| 222 | if (isset($data->{$attrWithSuffix}) && !empty($data->{$attrWithSuffix})) { |
||
| 223 | $value = $data->{$attrWithSuffix}; |
||
| 224 | } else { |
||
| 225 | if (isset($data->{$this->toRenderTypeValue})) { |
||
| 226 | $value = $data->{$this->toRenderTypeValue}; |
||
| 227 | } |
||
| 228 | } |
||
| 229 | } |
||
| 230 | } else { |
||
| 231 | if (!empty($data->{$this->toRenderTypeValue})) { |
||
| 232 | $value = $data->{$this->toRenderTypeValue}; |
||
| 233 | } |
||
| 234 | } |
||
| 235 | return $this->applyTextCase( |
||
| 236 | StringHelper::clearApostrophes( |
||
| 237 | htmlspecialchars($value, ENT_HTML5) |
||
| 238 | ), |
||
| 239 | $lang |
||
| 240 | ); |
||
| 241 | } |
||
| 242 | |||
| 243 | /** |
||
| 244 | * @param $data |
||
| 245 | * @param $renderedText |
||
| 246 | * @return string |
||
| 247 | */ |
||
| 248 | private function formatRenderedText($data, $renderedText) |
||
| 249 | { |
||
| 250 | $text = $this->format($renderedText); |
||
| 251 | $res = $this->addAffixes($text); |
||
| 252 | if (CiteProcHelper::isUsingAffixesByMarkupExtentsion($data, $this->toRenderTypeValue)) { |
||
| 253 | $res = $this->applyAdditionalMarkupFunction($data, $res); |
||
| 254 | } |
||
| 255 | if (!empty($res)) { |
||
| 256 | $res = $this->removeConsecutiveChars($res); |
||
| 257 | } |
||
| 258 | $res = $this->addSurroundingQuotes($res); |
||
| 259 | return $this->wrapDisplayBlock($res); |
||
| 260 | } |
||
| 261 | |||
| 262 | /** |
||
| 263 | * @param $data |
||
| 264 | * @param $citationNumber |
||
| 265 | * @return int|mixed |
||
| 266 | */ |
||
| 267 | private function renderCitationNumber($data, $citationNumber) |
||
| 268 | { |
||
| 269 | $renderedText = property_exists($data, "citationNumber") ? $data->citationNumber : $citationNumber + 1; |
||
| 270 | if (!CiteProcHelper::isUsingAffixesByMarkupExtentsion($data, $this->toRenderTypeValue)) { |
||
| 271 | $renderedText = $this->applyAdditionalMarkupFunction($data, $renderedText); |
||
| 272 | } |
||
| 273 | return $renderedText; |
||
| 274 | } |
||
| 275 | |||
| 276 | /** |
||
| 277 | * @param $data |
||
| 278 | * @return string |
||
| 279 | */ |
||
| 280 | private function renderMacro($data) |
||
| 281 | { |
||
| 282 | $macro = CiteProc::getContext()->getMacro($this->toRenderTypeValue); |
||
| 283 | if (is_null($macro)) { |
||
| 284 | try { |
||
| 285 | throw new CiteProcException("Macro \"".$this->toRenderTypeValue."\" does not exist."); |
||
| 286 | } catch (CiteProcException $e) { |
||
| 287 | $renderedText = ""; |
||
| 288 | } |
||
| 289 | } else { |
||
| 290 | $renderedText = $macro->render($data); |
||
| 291 | } |
||
| 292 | return $renderedText; |
||
| 293 | } |
||
| 294 | } |
||
| 295 |