1c3437056SNickeau<?php 2c3437056SNickeau 3c3437056SNickeau 4c3437056SNickeaunamespace ComboStrap; 5c3437056SNickeau 6c3437056SNickeau 7*04fd306cSNickeauuse ComboStrap\Meta\Api\Metadata; 8*04fd306cSNickeauuse ComboStrap\Meta\Api\MetadataStore; 9*04fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore; 10c3437056SNickeauuse syntax_plugin_combo_frontmatter; 11c3437056SNickeau 12*04fd306cSNickeau/** 13*04fd306cSNickeau * A page represented as a frontmatter 14*04fd306cSNickeau * 15*04fd306cSNickeau * By giving a page to the constructor, you can: 16*04fd306cSNickeau * * change the content of the frontmatter 17*04fd306cSNickeau * * add a header/frontmatter to the content 18*04fd306cSNickeau * * and persist 19*04fd306cSNickeau * MetadataFrontmatterStore 20*04fd306cSNickeau * @package ComboStrap 21*04fd306cSNickeau */ 22c3437056SNickeauclass MetadataFrontmatterStore extends MetadataSingleArrayStore 23c3437056SNickeau{ 24c3437056SNickeau 25c3437056SNickeau const NAME = "frontmatter"; 26c3437056SNickeau const CANONICAL = self::NAME; 27*04fd306cSNickeau public const CONF_ENABLE_FRONT_MATTER_ON_SUBMIT = "enableFrontMatterOnSubmit"; 28c3437056SNickeau 29c3437056SNickeau /** 30c3437056SNickeau * @var bool Do we have a frontmatter on the page 31c3437056SNickeau */ 32*04fd306cSNickeau private bool $isPresent = false; 33c3437056SNickeau /** 34c3437056SNickeau * @var string 35c3437056SNickeau */ 36*04fd306cSNickeau private string $contentWithoutFrontMatter; 37c3437056SNickeau 38c3437056SNickeau /** 39*04fd306cSNickeau * @throws ExceptionCompile 40c3437056SNickeau */ 41c3437056SNickeau private function syncData() 42c3437056SNickeau { 43c3437056SNickeau 44c3437056SNickeau /** 45*04fd306cSNickeau * @var MarkupPath $resourceCombo 46c3437056SNickeau */ 47c3437056SNickeau $resourceCombo = $this->getResource(); 48c3437056SNickeau 49c3437056SNickeau /** 50c3437056SNickeau * Resource Id special 51c3437056SNickeau */ 52c3437056SNickeau $guidObject = $resourceCombo->getUidObject(); 53*04fd306cSNickeau try { 54*04fd306cSNickeau $guidValue = $guidObject->getValue(); 55*04fd306cSNickeau } catch (ExceptionNotFound $e) { 56*04fd306cSNickeau $guidValue = null; 57*04fd306cSNickeau } 58c3437056SNickeau if ( 59c3437056SNickeau !$this->hasProperty($guidObject::getPersistentName()) 60c3437056SNickeau && 61*04fd306cSNickeau $guidValue !== null 62c3437056SNickeau ) { 63*04fd306cSNickeau $this->setFromPersistentName($guidObject::getPersistentName(), $guidValue); 64c3437056SNickeau } 65c3437056SNickeau 66c3437056SNickeau /** 67c3437056SNickeau * Read store 68c3437056SNickeau */ 69c3437056SNickeau $dokuwikiStore = MetadataDokuWikiStore::getOrCreateFromResource($resourceCombo); 70c3437056SNickeau $metaFilePath = $dokuwikiStore->getMetaFilePath(); 71c3437056SNickeau if ($metaFilePath !== null) { 72c3437056SNickeau $metaModifiedTime = FileSystems::getModifiedTime($metaFilePath); 73*04fd306cSNickeau $pageModifiedTime = FileSystems::getModifiedTime($resourceCombo->getPathObject()); 74*04fd306cSNickeau $older = Iso8601Date::createFromDateTime($pageModifiedTime)->olderThan($metaModifiedTime); 75*04fd306cSNickeau if (!$older) { 76*04fd306cSNickeau /** 77*04fd306cSNickeau * Weird case that may happen 78*04fd306cSNickeau */ 79c3437056SNickeau $resourceCombo->renderMetadataAndFlush(); 80c3437056SNickeau } 81c3437056SNickeau } 82*04fd306cSNickeau 83c3437056SNickeau /** 84c3437056SNickeau * Update the mutable data 85c3437056SNickeau * (ie delete insert) 86c3437056SNickeau */ 87*04fd306cSNickeau foreach (Meta\Api\MetadataSystem::getMutableMetadata() as $metadata) { 88*04fd306cSNickeau 89c3437056SNickeau $metadata 90c3437056SNickeau ->setResource($resourceCombo) 91c3437056SNickeau ->setReadStore($dokuwikiStore) 92c3437056SNickeau ->setWriteStore($this); 93c3437056SNickeau 94c3437056SNickeau $sourceValue = $this->get($metadata); 95*04fd306cSNickeau try { 96c3437056SNickeau $targetValue = $metadata->getValue(); 97*04fd306cSNickeau } catch (ExceptionNotFound $e) { 98*04fd306cSNickeau $targetValue = null; 99*04fd306cSNickeau } 100*04fd306cSNickeau try { 101c3437056SNickeau $defaultValue = $metadata->getDefaultValue(); 102*04fd306cSNickeau } catch (ExceptionNotFound $e) { 103*04fd306cSNickeau $defaultValue = null; 104*04fd306cSNickeau } 105c3437056SNickeau /** 106*04fd306cSNickeau * Strict because otherwise the comparison `false == null` is true 107c3437056SNickeau */ 108c3437056SNickeau $targetValueShouldBeStore = !in_array($targetValue, [$defaultValue, null], true); 109c3437056SNickeau if ($targetValueShouldBeStore) { 110c3437056SNickeau if ($sourceValue !== $targetValue) { 111c3437056SNickeau $this->set($metadata); 112c3437056SNickeau } 113c3437056SNickeau } else { 114c3437056SNickeau if ($sourceValue !== null) { 115c3437056SNickeau $this->remove($metadata); 116c3437056SNickeau } 117c3437056SNickeau } 118c3437056SNickeau } 119c3437056SNickeau } 120c3437056SNickeau 121c3437056SNickeau /** 122c3437056SNickeau * Update the frontmatter with the managed metadata 123c3437056SNickeau * Used after a submit from the form 124c3437056SNickeau * @return Message 125c3437056SNickeau */ 126c3437056SNickeau public function sync(): Message 127c3437056SNickeau { 128c3437056SNickeau 129c3437056SNickeau /** 130c3437056SNickeau * Default update value for the frontmatter 131c3437056SNickeau */ 132*04fd306cSNickeau $updateFrontMatter = SiteConfig::getConfValue(self::CONF_ENABLE_FRONT_MATTER_ON_SUBMIT, syntax_plugin_combo_frontmatter::CONF_ENABLE_FRONT_MATTER_ON_SUBMIT_DEFAULT); 133c3437056SNickeau 134c3437056SNickeau 135c3437056SNickeau if ($this->isPresent()) { 136c3437056SNickeau $updateFrontMatter = 1; 137c3437056SNickeau } 138c3437056SNickeau 139c3437056SNickeau 140c3437056SNickeau if ($updateFrontMatter === 0) { 141c3437056SNickeau return Message::createInfoMessage("The frontmatter is not enabled") 142c3437056SNickeau ->setStatus(syntax_plugin_combo_frontmatter::UPDATE_EXIT_CODE_NOT_ENABLED); 143c3437056SNickeau } 144c3437056SNickeau 145c3437056SNickeau try { 146c3437056SNickeau $this->syncData(); 147*04fd306cSNickeau } catch (ExceptionCompile $e) { 148*04fd306cSNickeau if (PluginUtility::isDevOrTest()) { 149*04fd306cSNickeau throw new ExceptionRuntime("Error while synchronizing data in the frontmatter", self::CANONICAL, 1, $e); 150*04fd306cSNickeau } 151c3437056SNickeau return Message::createInfoMessage($e->getMessage()) 152c3437056SNickeau ->setStatus(syntax_plugin_combo_frontmatter::UPDATE_EXIT_CODE_ERROR); 153c3437056SNickeau } 154c3437056SNickeau 155c3437056SNickeau 156c3437056SNickeau /** 157c3437056SNickeau * Same ? 158c3437056SNickeau */ 159c3437056SNickeau if (!$this->hasStateChanged()) { 160c3437056SNickeau return Message::createInfoMessage("The frontmatter are the same (no update)") 161c3437056SNickeau ->setStatus(syntax_plugin_combo_frontmatter::UPDATE_EXIT_CODE_NOT_CHANGED); 162c3437056SNickeau } 163c3437056SNickeau 164c3437056SNickeau $this->persist(); 165c3437056SNickeau 166c3437056SNickeau return Message::createInfoMessage("The frontmatter was changed") 167c3437056SNickeau ->setStatus(syntax_plugin_combo_frontmatter::UPDATE_EXIT_CODE_DONE); 168c3437056SNickeau 169c3437056SNickeau } 170c3437056SNickeau 171c3437056SNickeau 172c3437056SNickeau public function isPresent(): bool 173c3437056SNickeau { 174c3437056SNickeau return $this->isPresent; 175c3437056SNickeau } 176c3437056SNickeau 177c3437056SNickeau /** 178c3437056SNickeau * MetadataFrontmatterStore constructor. 179c3437056SNickeau * @param ResourceCombo $page 180c3437056SNickeau * @param array|null $data 181c3437056SNickeau */ 182c3437056SNickeau public function __construct(ResourceCombo $page, array $data = null) 183c3437056SNickeau { 184c3437056SNickeau parent::__construct($page, $data); 185c3437056SNickeau } 186c3437056SNickeau 187c3437056SNickeau /** 188c3437056SNickeau * @param $match 189c3437056SNickeau * @return array|null - null if decodage problem, empty array if no json or an associative array 190c3437056SNickeau * @deprecated used {@link MetadataFrontmatterStore::loadAsString()} instead 191c3437056SNickeau */ 192c3437056SNickeau public static function frontMatterMatchToAssociativeArray($match): ?array 193c3437056SNickeau { 194c3437056SNickeau $jsonString = self::stripFrontmatterTag($match); 195c3437056SNickeau 196c3437056SNickeau // Empty front matter 197c3437056SNickeau if (trim($jsonString) == "") { 198c3437056SNickeau return []; 199c3437056SNickeau } 200c3437056SNickeau 201c3437056SNickeau // Otherwise you get an object ie $arrayFormat-> syntax 202c3437056SNickeau $arrayFormat = true; 203c3437056SNickeau return json_decode($jsonString, $arrayFormat); 204c3437056SNickeau } 205c3437056SNickeau 206c3437056SNickeau public static function stripFrontmatterTag($match) 207c3437056SNickeau { 208c3437056SNickeau // strip 209c3437056SNickeau // from start `---json` + eol = 8 210c3437056SNickeau // from end `---` + eol = 4 211c3437056SNickeau return substr($match, 7, -3); 212c3437056SNickeau } 213c3437056SNickeau 214c3437056SNickeau 215c3437056SNickeau public static function getOrCreateFromResource(ResourceCombo $resourceCombo): MetadataStore 216c3437056SNickeau { 217c3437056SNickeau return new MetadataFrontmatterStore($resourceCombo, null); 218c3437056SNickeau } 219c3437056SNickeau 220c3437056SNickeau public static function createFromArray(ResourceCombo $page, array $jsonArray): MetadataFrontmatterStore 221c3437056SNickeau { 222c3437056SNickeau return new MetadataFrontmatterStore($page, $jsonArray); 223c3437056SNickeau } 224c3437056SNickeau 225c3437056SNickeau /** 226*04fd306cSNickeau * @throws ExceptionBadSyntax 227c3437056SNickeau */ 228c3437056SNickeau public static function createFromFrontmatterString($page, $frontmatter = null): MetadataFrontmatterStore 229c3437056SNickeau { 230c3437056SNickeau if ($frontmatter === null) { 231c3437056SNickeau return new MetadataFrontmatterStore($page, []); 232c3437056SNickeau } 233c3437056SNickeau $jsonArray = self::frontMatterMatchToAssociativeArray($frontmatter); 234c3437056SNickeau if ($jsonArray === null) { 235*04fd306cSNickeau throw new ExceptionBadSyntax("The frontmatter is not valid"); 236c3437056SNickeau } 237*04fd306cSNickeau $frontmatter = new MetadataFrontmatterStore($page, $jsonArray); 238*04fd306cSNickeau $frontmatter->setContentWithoutFrontMatter(''); 239*04fd306cSNickeau return $frontmatter; 240c3437056SNickeau } 241c3437056SNickeau 242c3437056SNickeau /** 243*04fd306cSNickeau * @throws ExceptionBadSyntax - if the content has a syntax problem 244*04fd306cSNickeau * @throws ExceptionNotFound - if the page does not exist 245c3437056SNickeau */ 246*04fd306cSNickeau public static function createFromPage(MarkupPath $page): MetadataFrontmatterStore 247c3437056SNickeau { 248*04fd306cSNickeau $content = FileSystems::getContent($page->getPathObject()); 249c3437056SNickeau $frontMatterStartTag = syntax_plugin_combo_frontmatter::START_TAG; 250c3437056SNickeau if (strpos($content, $frontMatterStartTag) === 0) { 251c3437056SNickeau 252c3437056SNickeau /** 253c3437056SNickeau * Extract the actual values 254c3437056SNickeau */ 255c3437056SNickeau $pattern = syntax_plugin_combo_frontmatter::PATTERN; 256c3437056SNickeau $split = preg_split("/($pattern)/ms", $content, 2, PREG_SPLIT_DELIM_CAPTURE); 257c3437056SNickeau 258c3437056SNickeau /** 259c3437056SNickeau * The split normally returns an array 260c3437056SNickeau * where the first element is empty followed by the frontmatter 261c3437056SNickeau */ 262c3437056SNickeau $emptyString = array_shift($split); 263c3437056SNickeau if (!empty($emptyString)) { 264*04fd306cSNickeau throw new ExceptionBadSyntax("The frontmatter is not the first element"); 265c3437056SNickeau } 266c3437056SNickeau 267c3437056SNickeau $frontMatterMatch = array_shift($split); 268c3437056SNickeau /** 269c3437056SNickeau * Building the document again 270c3437056SNickeau */ 271c3437056SNickeau $contentWithoutFrontMatter = ""; 272c3437056SNickeau while (($element = array_shift($split)) != null) { 273c3437056SNickeau $contentWithoutFrontMatter .= $element; 274c3437056SNickeau } 275c3437056SNickeau 276c3437056SNickeau return MetadataFrontmatterStore::createFromFrontmatterString($page, $frontMatterMatch) 277c3437056SNickeau ->setIsPresent(true) 278c3437056SNickeau ->setContentWithoutFrontMatter($contentWithoutFrontMatter); 279c3437056SNickeau 280c3437056SNickeau } 281c3437056SNickeau return (new MetadataFrontmatterStore($page)) 282c3437056SNickeau ->setIsPresent(false) 283c3437056SNickeau ->setContentWithoutFrontMatter($content); 284c3437056SNickeau 285c3437056SNickeau } 286c3437056SNickeau 287c3437056SNickeau 288c3437056SNickeau public function __toString() 289c3437056SNickeau { 290c3437056SNickeau return self::NAME; 291c3437056SNickeau } 292c3437056SNickeau 293c3437056SNickeau 294c3437056SNickeau public function getJsonString(): string 295c3437056SNickeau { 296c3437056SNickeau 297c3437056SNickeau $jsonArray = $this->getData(); 298c3437056SNickeau ksort($jsonArray); 299c3437056SNickeau return self::toFrontmatterJsonString($jsonArray); 300c3437056SNickeau 301c3437056SNickeau } 302c3437056SNickeau 303c3437056SNickeau /** 304c3437056SNickeau * This formatting make the object on one line for a list of object 305c3437056SNickeau * making the frontmatter compacter (one line, one meta) 306c3437056SNickeau * @param $jsonArray 307c3437056SNickeau * @return string 308c3437056SNickeau */ 309c3437056SNickeau public static function toFrontmatterJsonString($jsonArray): string 310c3437056SNickeau { 311c3437056SNickeau 312c3437056SNickeau if (sizeof($jsonArray) === 0) { 313c3437056SNickeau return "{}"; 314c3437056SNickeau } 315c3437056SNickeau $jsonString = ""; 316c3437056SNickeau self::jsonFlatRecursiveEncoding($jsonArray, $jsonString); 317c3437056SNickeau 318c3437056SNickeau /** 319c3437056SNickeau * Double Guard (frontmatter should be quick enough) 320c3437056SNickeau * to support this overhead 321c3437056SNickeau */ 322c3437056SNickeau $decoding = json_decode($jsonString); 323c3437056SNickeau if ($decoding === null) { 324*04fd306cSNickeau throw new ExceptionRuntime("The generated frontmatter json is no a valid json"); 325c3437056SNickeau } 326c3437056SNickeau return $jsonString; 327c3437056SNickeau } 328c3437056SNickeau 329c3437056SNickeau private static function jsonFlatRecursiveEncoding(array $jsonProperty, &$jsonString, $level = 0, $endOfFieldCharacter = DOKU_LF, $type = Json::TYPE_OBJECT, $parentType = Json::TYPE_OBJECT) 330c3437056SNickeau { 331c3437056SNickeau /** 332c3437056SNickeau * Open the root object 333c3437056SNickeau */ 334c3437056SNickeau if ($type === Json::TYPE_OBJECT) { 335c3437056SNickeau $jsonString .= "{"; 336c3437056SNickeau } else { 337c3437056SNickeau $jsonString .= "["; 338c3437056SNickeau } 339c3437056SNickeau 340c3437056SNickeau /** 341c3437056SNickeau * Level indentation 342c3437056SNickeau */ 343c3437056SNickeau $levelSpaceIndentation = str_repeat(" ", ($level + 1) * Json::TAB_SPACES_COUNTER); 344c3437056SNickeau 345c3437056SNickeau /** 346c3437056SNickeau * Loop 347c3437056SNickeau */ 348c3437056SNickeau $elementCounter = 0; 349c3437056SNickeau foreach ($jsonProperty as $key => $value) { 350c3437056SNickeau 351c3437056SNickeau $elementCounter++; 352c3437056SNickeau 353c3437056SNickeau /** 354c3437056SNickeau * Close the previous property 355c3437056SNickeau */ 356c3437056SNickeau $isFirstProperty = $elementCounter === 1; 357c3437056SNickeau if ($isFirstProperty && $parentType !== Json::PARENT_TYPE_ARRAY) { 358c3437056SNickeau // go the line if this is not a list of object 359c3437056SNickeau $jsonString .= DOKU_LF; 360c3437056SNickeau } 361c3437056SNickeau if (!$isFirstProperty) { 362c3437056SNickeau $jsonString .= ",$endOfFieldCharacter"; 363c3437056SNickeau } 364c3437056SNickeau if ($endOfFieldCharacter === DOKU_LF) { 365c3437056SNickeau $tab = $levelSpaceIndentation; 366c3437056SNickeau } else { 367c3437056SNickeau $tab = " "; 368c3437056SNickeau } 369c3437056SNickeau $jsonString .= $tab; 370c3437056SNickeau 371c3437056SNickeau /** 372c3437056SNickeau * Recurse 373c3437056SNickeau */ 374c3437056SNickeau $jsonEncodedKey = json_encode($key); 375c3437056SNickeau if (is_array($value)) { 376c3437056SNickeau $childLevel = $level + 1; 377c3437056SNickeau if (is_numeric($key)) { 378c3437056SNickeau /** 379c3437056SNickeau * List of object 380c3437056SNickeau */ 381c3437056SNickeau $childType = Json::TYPE_OBJECT; 382c3437056SNickeau $childEndOField = ""; 383c3437056SNickeau } else { 384c3437056SNickeau /** 385c3437056SNickeau * Array 386c3437056SNickeau */ 387c3437056SNickeau $jsonString .= "$jsonEncodedKey: "; 388c3437056SNickeau $childType = Json::TYPE_OBJECT; 389c3437056SNickeau if ($value[0] !== null) { 390c3437056SNickeau $childType = Json::PARENT_TYPE_ARRAY; 391c3437056SNickeau } 392c3437056SNickeau $childEndOField = $endOfFieldCharacter; 393c3437056SNickeau } 394c3437056SNickeau self::jsonFlatRecursiveEncoding($value, $jsonString, $childLevel, $childEndOField, $childType, $type); 395c3437056SNickeau 396c3437056SNickeau } else { 397c3437056SNickeau /** 398c3437056SNickeau * Single property 399c3437056SNickeau */ 400c3437056SNickeau $jsonEncodedValue = json_encode($value); 401c3437056SNickeau $jsonString .= "$jsonEncodedKey: $jsonEncodedValue"; 402c3437056SNickeau 403c3437056SNickeau } 404c3437056SNickeau 405c3437056SNickeau } 406c3437056SNickeau 407c3437056SNickeau /** 408c3437056SNickeau * Close the object or array 409c3437056SNickeau */ 410c3437056SNickeau $closingLevelSpaceIndentation = str_repeat(" ", $level * Json::TAB_SPACES_COUNTER); 411c3437056SNickeau if ($type === Json::TYPE_OBJECT) { 412c3437056SNickeau if ($parentType !== Json::PARENT_TYPE_ARRAY) { 413c3437056SNickeau $jsonString .= DOKU_LF . $closingLevelSpaceIndentation; 414c3437056SNickeau } else { 415c3437056SNickeau $jsonString .= " "; 416c3437056SNickeau } 417c3437056SNickeau $jsonString .= "}"; 418c3437056SNickeau } else { 419c3437056SNickeau /** 420c3437056SNickeau * The array is not going one level back 421c3437056SNickeau */ 422c3437056SNickeau $jsonString .= DOKU_LF . $closingLevelSpaceIndentation . "]"; 423c3437056SNickeau } 424c3437056SNickeau } 425c3437056SNickeau 426c3437056SNickeau 427c3437056SNickeau public function toFrontmatterString(): string 428c3437056SNickeau { 429c3437056SNickeau $frontmatterStartTag = syntax_plugin_combo_frontmatter::START_TAG; 430c3437056SNickeau $frontmatterEndTag = syntax_plugin_combo_frontmatter::END_TAG; 431c3437056SNickeau $jsonArray = $this->getData(); 432c3437056SNickeau ksort($jsonArray); 433c3437056SNickeau $jsonEncode = self::toFrontmatterJsonString($jsonArray); 434c3437056SNickeau 435c3437056SNickeau return <<<EOF 436c3437056SNickeau$frontmatterStartTag 437c3437056SNickeau$jsonEncode 438c3437056SNickeau$frontmatterEndTag 439c3437056SNickeauEOF; 440c3437056SNickeau 441c3437056SNickeau 442c3437056SNickeau } 443c3437056SNickeau 444c3437056SNickeau private function setIsPresent(bool $bool): MetadataFrontmatterStore 445c3437056SNickeau { 446c3437056SNickeau $this->isPresent = $bool; 447c3437056SNickeau return $this; 448c3437056SNickeau } 449c3437056SNickeau 450c3437056SNickeau public function persist() 451c3437056SNickeau { 452*04fd306cSNickeau if (!isset($this->contentWithoutFrontMatter)) { 453c3437056SNickeau LogUtility::msg("The content without frontmatter should have been set. Did you you use the createFromPage constructor"); 454c3437056SNickeau return $this; 455c3437056SNickeau } 456*04fd306cSNickeau $newPageContent = $this->toMarkup(); 457*04fd306cSNickeau $resourceCombo = $this->getResource(); 458*04fd306cSNickeau if ($resourceCombo instanceof MarkupPath) { 459*04fd306cSNickeau $resourceCombo->setContentWithLog($newPageContent, "Metadata frontmatter store upsert"); 460*04fd306cSNickeau } 461*04fd306cSNickeau return $this; 462*04fd306cSNickeau } 463*04fd306cSNickeau 464*04fd306cSNickeau private function setContentWithoutFrontMatter(string $contentWithoutFrontMatter): MetadataFrontmatterStore 465*04fd306cSNickeau { 466*04fd306cSNickeau $this->contentWithoutFrontMatter = $contentWithoutFrontMatter; 467*04fd306cSNickeau return $this; 468*04fd306cSNickeau } 469*04fd306cSNickeau 470*04fd306cSNickeau 471*04fd306cSNickeau /** 472*04fd306cSNickeau * @return string - the new markup (ie the new frontmatter and the markup) 473*04fd306cSNickeau */ 474*04fd306cSNickeau public function toMarkup(): string 475*04fd306cSNickeau { 476*04fd306cSNickeau 477c3437056SNickeau $targetFrontMatterJsonString = $this->toFrontmatterString(); 478c3437056SNickeau 479c3437056SNickeau /** 480c3437056SNickeau * EOL for the first frontmatter 481c3437056SNickeau */ 482c3437056SNickeau $sep = ""; 483c3437056SNickeau if (strlen($this->contentWithoutFrontMatter) > 0) { 484c3437056SNickeau $firstChar = $this->contentWithoutFrontMatter[0]; 485c3437056SNickeau if (!in_array($firstChar, ["\n", "\r"])) { 486c3437056SNickeau $sep = "\n"; 487c3437056SNickeau } 488c3437056SNickeau } 489c3437056SNickeau 490c3437056SNickeau /** 491c3437056SNickeau * Build the new document 492c3437056SNickeau */ 493*04fd306cSNickeau return <<<EOF 494c3437056SNickeau$targetFrontMatterJsonString$sep$this->contentWithoutFrontMatter 495c3437056SNickeauEOF; 496*04fd306cSNickeau 497c3437056SNickeau } 498c3437056SNickeau 499*04fd306cSNickeau public function getContentWithoutFrontMatter(): string 500c3437056SNickeau { 501*04fd306cSNickeau return $this->contentWithoutFrontMatter; 502c3437056SNickeau } 503c3437056SNickeau 504c3437056SNickeau 505c3437056SNickeau} 506