project_wiki-1.x-dev/modules/project_wiki_markdown_content/src/Plugin/ProjectWikiMarkdownContentPluginBase.php
modules/project_wiki_markdown_content/src/Plugin/ProjectWikiMarkdownContentPluginBase.php
<?php
namespace Drupal\project_wiki_markdown_content\Plugin;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\project_wiki\Plugin\ProjectWikiContentPluginBase;
use Drupal\project_wiki\ProjectWikiValueObject;
use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
use League\CommonMark\Output\RenderedContentInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* The PluginBase for the Markdown services.
*/
abstract class ProjectWikiMarkdownContentPluginBase extends ProjectWikiContentPluginBase implements ContainerFactoryPluginInterface {
use StringTranslationTrait;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The file system service.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* The module config.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $config;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, ModuleHandlerInterface $module_handler, FileSystemInterface $file_system, ConfigFactoryInterface $config_factory) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $module_handler);
$this->moduleHandler = $module_handler;
$this->fileSystem = $file_system;
$this->config = $config_factory->get('project_wiki_markdown_content.settings');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('module_handler'),
$container->get('file_system'),
$container->get('config.factory'),
);
}
/**
* Abstract definition for the function providing directory path.
*/
abstract public function getEntriesDirectoryPath();
/**
* {@inheritdoc}
*/
public function getValueObjects(): array {
$entries = [];
$searchDir = $this->getEntriesDirectoryPath();
$files = $this->readMarkdownDirectories($searchDir);
foreach ($files as $file) {
$langcode = explode(DIRECTORY_SEPARATOR, str_replace($searchDir . DIRECTORY_SEPARATOR, '', $file->uri), 2)[0];
$category = explode(DIRECTORY_SEPARATOR, explode(DIRECTORY_SEPARATOR, str_replace($searchDir . DIRECTORY_SEPARATOR, '', $file->uri) ?? '', 2)[1] ?? '', 2)[0];
if (str_ends_with($category, '.md')) {
$category = NULL;
}
// Turn markdown into HTML and read header data:
$entries[] = $this->prepareMarkdown($file, $langcode ?: NULL, $category ?: NULL);
}
return $entries;
}
/**
* Returns all markdown files in the given directory and its subdirectories.
*
* @param string $searchDir
* The directory to search in.
* @param string $mask
* The mask to search by (.md files are the default).
*
* @return array
* The list of files.
*/
public function readMarkdownDirectories(string $searchDir, $mask = "/\.md$/"): array {
$files = [];
$allFiles = [];
if (is_dir($searchDir)) {
$allFiles = $this->fileSystem->scanDirectory($searchDir, $mask);
}
else {
throw new \Exception('Directory not found: "' . $searchDir . '"');
}
foreach ($allFiles as $file) {
if (file_exists($file->uri)) {
$files[] = $file;
}
}
return $files;
}
/**
* Prepares a markdown file.
*
* Reads and prepares the given markdown file to turn it into an
* ProjectWikiEntityContentValueObject.
*/
public function prepareMarkdown($file, $langcode = NULL, $category = NULL) : ProjectWikiValueObject {
// Get the markdown file contents:
$fileContents = file_get_contents($file->uri);
// Parse the markdown to a RenderedContent instance:
$renderedContent = $this->parseMarkdown($fileContents);
// Get markdown metadata and declare required variables:
$metaData = $renderedContent->getFrontMatter();
$isDeveloperContent = !empty($metaData['isDeveloperContent']) ? $metaData['isDeveloperContent'] : FALSE;
$title = !empty($metaData['title']) ? $metaData['title'] : $file->name;
$provider = 'project_wiki_markdown_content';
$id = $file->uri;
// Note, that if filterFormat is NULL, "filter_fallback_format()" is used.
$filteredContent = check_markup($renderedContent->getContent(), $this->config->get('filterFormat'), $langcode);
return new ProjectWikiValueObject($provider, $id, $langcode, $category, $title, $filteredContent, $isDeveloperContent);
}
/**
* Helper function to convert markdown into a RenderedContent instance.
*
* @param string $markdown
* The markdown string to parse.
*/
public function parseMarkdown(string $markdown): RenderedContentInterface {
$converter = new CommonMarkConverter();
$converter->getEnvironment()->addExtension(new FrontMatterExtension());
return $converter->convert($markdown);
}
}
