<?php
namespace RocketTheme\Toolbox\File;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml as YamlParser;
use RocketTheme\Toolbox\Compat\Yaml\Yaml as FallbackYamlParser;
use function is_array;
use function is_object;
/**
* Implements Markdown File reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class MarkdownFile extends File
{
/** @var string */
protected $extension = '.md';
/** @var static[] */
static protected $instances = [];
/**
* @param array|null $var
* @return array
*/
public function content($var = null)
{
/** @var array $content */
$content = parent::content($var);
return $content;
}
/**
* Get/set file header.
*
* @param array|null $var
* @return array
*/
public function header(array $var = null)
{
$content = $this->content();
if ($var !== null) {
$content['header'] = $var;
$this->content($content);
}
return $content['header'];
}
/**
* Get/set markdown content.
*
* @param string|null $var
* @return string
*/
public function markdown($var = null)
{
$content = $this->content();
if ($var !== null) {
$content['markdown'] = (string)$var;
$this->content($content);
}
return $content['markdown'];
}
/**
* Get/set frontmatter content.
*
* @param string|null $var
* @return string
*/
public function frontmatter($var = null)
{
$content = $this->content();
if ($var !== null) {
$content['frontmatter'] = (string)$var;
$this->content($content);
}
return $content['frontmatter'];
}
/**
* Check contents and make sure it is in correct format.
*
* @param mixed $var
* @return array
*/
protected function check($var)
{
if (!(is_array($var) || is_object($var))) {
throw new \RuntimeException('Provided data is not an array');
}
$var = (array) $var;
if (!isset($var['header']) || !is_array($var['header'])) {
$var['header'] = [];
}
if (!isset($var['markdown']) || !\is_string($var['markdown'])) {
$var['markdown'] = '';
}
return $var;
}
/**
* Encode contents into RAW string.
*
* @param array $var
* @return string
*/
protected function encode($var)
{
// Create Markdown file with YAML header.
$o = (!empty($var['header']) ? "---\n" . trim(YamlParser::dump($var['header'], 20)) . "\n---\n\n" : '') . $var['markdown'];
// Normalize line endings to Unix style.
$o = (string)preg_replace("/(\r\n|\r)/", "\n", $o);
return $o;
}
/**
* Decode RAW string into contents.
*
* @param string $var
* @return array
*/
protected function decode($var)
{
$content = [
'header' => false,
'frontmatter' => ''
];
$frontmatter_regex = "/^---\n(.+?)\n---\n{0,}(.*)$/uis";
// Remove UTF-8 BOM if it exists.
$var = ltrim($var, "\xef\xbb\xbf");
// Normalize line endings to Unix style.
$var = (string)preg_replace("/(\r\n|\r)/", "\n", $var);
// Parse header.
preg_match($frontmatter_regex, ltrim($var), $m);
if(!empty($m)) {
// Normalize frontmatter.
$content['frontmatter'] = $frontmatter = preg_replace("/\n\t/", "\n ", $m[1]);
// Try native PECL YAML PHP extension first if available.
if (\function_exists('yaml_parse') && $this->setting('native')) {
// Safely decode YAML.
$saved = @ini_get('yaml.decode_php');
@ini_set('yaml.decode_php', '0');
$content['header'] = @yaml_parse("---\n" . $frontmatter . "\n...");
if ($saved !== false) {
@ini_set('yaml.decode_php', $saved);
}
}
if ($content['header'] === false) {
// YAML hasn't been parsed yet (error or extension isn't available). Fall back to Symfony parser.
try {
$content['header'] = (array) YamlParser::parse($frontmatter);
} catch (ParseException $e) {
if (!$this->setting('compat', true)) {
throw $e;
}
$content['header'] = (array) FallbackYamlParser::parse($frontmatter);
}
}
$content['markdown'] = $m[2];
} else {
$content['header'] = [];
$content['markdown'] = $var;
}
return $content;
}
}