MarkdownFile.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. namespace RocketTheme\Toolbox\File;
  3. use Symfony\Component\Yaml\Exception\ParseException;
  4. use Symfony\Component\Yaml\Yaml as YamlParser;
  5. use RocketTheme\Toolbox\Compat\Yaml\Yaml as FallbackYamlParser;
  6. /**
  7. * Implements Markdown File reader.
  8. *
  9. * @package RocketTheme\Toolbox\File
  10. * @author RocketTheme
  11. * @license MIT
  12. */
  13. class MarkdownFile extends File
  14. {
  15. /**
  16. * @var string
  17. */
  18. protected $extension = '.md';
  19. /**
  20. * @var array|File[]
  21. */
  22. static protected $instances = [];
  23. /**
  24. * Get/set file header.
  25. *
  26. * @param array $var
  27. *
  28. * @return array
  29. */
  30. public function header(array $var = null)
  31. {
  32. $content = $this->content();
  33. if ($var !== null) {
  34. $content['header'] = $var;
  35. $this->content($content);
  36. }
  37. return $content['header'];
  38. }
  39. /**
  40. * Get/set markdown content.
  41. *
  42. * @param string $var
  43. *
  44. * @return string
  45. */
  46. public function markdown($var = null)
  47. {
  48. $content = $this->content();
  49. if ($var !== null) {
  50. $content['markdown'] = (string) $var;
  51. $this->content($content);
  52. }
  53. return $content['markdown'];
  54. }
  55. /**
  56. * Get/set frontmatter content.
  57. *
  58. * @param string $var
  59. *
  60. * @return string
  61. */
  62. public function frontmatter($var = null)
  63. {
  64. $content = $this->content();
  65. if ($var !== null) {
  66. $content['frontmatter'] = (string) $var;
  67. $this->content($content);
  68. }
  69. return $content['frontmatter'];
  70. }
  71. /**
  72. * Check contents and make sure it is in correct format.
  73. *
  74. * @param array $var
  75. * @return array
  76. */
  77. protected function check($var)
  78. {
  79. $var = (array) $var;
  80. if (!isset($var['header']) || !is_array($var['header'])) {
  81. $var['header'] = array();
  82. }
  83. if (!isset($var['markdown']) || !is_string($var['markdown'])) {
  84. $var['markdown'] = '';
  85. }
  86. return $var;
  87. }
  88. /**
  89. * Encode contents into RAW string.
  90. *
  91. * @param string $var
  92. * @return string
  93. */
  94. protected function encode($var)
  95. {
  96. // Create Markdown file with YAML header.
  97. $o = (!empty($var['header']) ? "---\n" . trim(YamlParser::dump($var['header'], 20)) . "\n---\n\n" : '') . $var['markdown'];
  98. // Normalize line endings to Unix style.
  99. $o = preg_replace("/(\r\n|\r)/", "\n", $o);
  100. return $o;
  101. }
  102. /**
  103. * Decode RAW string into contents.
  104. *
  105. * @param string $var
  106. * @return array mixed
  107. */
  108. protected function decode($var)
  109. {
  110. $content = [
  111. 'header' => false,
  112. 'frontmatter' => ''
  113. ];
  114. $frontmatter_regex = "/^---\n(.+?)\n---\n{0,}(.*)$/uis";
  115. // Normalize line endings to Unix style.
  116. $var = preg_replace("/(\r\n|\r)/", "\n", $var);
  117. // Parse header.
  118. preg_match($frontmatter_regex, ltrim($var), $m);
  119. if(!empty($m)) {
  120. // Normalize frontmatter.
  121. $content['frontmatter'] = $frontmatter = preg_replace("/\n\t/", "\n ", $m[1]);
  122. // Try native PECL YAML PHP extension first if available.
  123. if ($this->setting('native') && function_exists('yaml_parse')) {
  124. // Safely decode YAML.
  125. $saved = @ini_get('yaml.decode_php');
  126. @ini_set('yaml.decode_php', 0);
  127. $content['header'] = @yaml_parse("---\n" . $frontmatter . "\n...");
  128. @ini_set('yaml.decode_php', $saved);
  129. }
  130. if ($content['header'] === false) {
  131. // YAML hasn't been parsed yet (error or extension isn't available). Fall back to Symfony parser.
  132. try {
  133. $content['header'] = (array) YamlParser::parse($frontmatter);
  134. } catch (ParseException $e) {
  135. if (!$this->setting('compat', true)) {
  136. throw $e;
  137. }
  138. $content['header'] = (array) FallbackYamlParser::parse($frontmatter);
  139. }
  140. }
  141. $content['markdown'] = $m[2];
  142. } else {
  143. $content['header'] = [];
  144. $content['markdown'] = $var;
  145. }
  146. return $content;
  147. }
  148. }