mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-12-13 14:33:37 +08:00
0a182a45ba
Added test to cover.
141 lines
4.2 KiB
PHP
141 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace BookStack\Exports\ZipExports;
|
|
|
|
use BookStack\App\Model;
|
|
use BookStack\Entities\Queries\EntityQueries;
|
|
use BookStack\References\ModelResolvers\AttachmentModelResolver;
|
|
use BookStack\References\ModelResolvers\BookLinkModelResolver;
|
|
use BookStack\References\ModelResolvers\ChapterLinkModelResolver;
|
|
use BookStack\References\ModelResolvers\CrossLinkModelResolver;
|
|
use BookStack\References\ModelResolvers\ImageModelResolver;
|
|
use BookStack\References\ModelResolvers\PageLinkModelResolver;
|
|
use BookStack\References\ModelResolvers\PagePermalinkModelResolver;
|
|
use BookStack\Uploads\ImageStorage;
|
|
|
|
class ZipReferenceParser
|
|
{
|
|
/**
|
|
* @var CrossLinkModelResolver[]|null
|
|
*/
|
|
protected ?array $modelResolvers = null;
|
|
|
|
public function __construct(
|
|
protected EntityQueries $queries
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Parse and replace references in the given content.
|
|
* Calls the handler for each model link detected and replaces the link
|
|
* with the handler return value if provided.
|
|
* Returns the resulting content with links replaced.
|
|
* @param callable(Model):(string|null) $handler
|
|
*/
|
|
public function parseLinks(string $content, callable $handler): string
|
|
{
|
|
$linkRegex = $this->getLinkRegex();
|
|
$matches = [];
|
|
preg_match_all($linkRegex, $content, $matches);
|
|
|
|
if (count($matches) < 2) {
|
|
return $content;
|
|
}
|
|
|
|
foreach ($matches[1] as $link) {
|
|
$model = $this->linkToModel($link);
|
|
if ($model) {
|
|
$result = $handler($model);
|
|
if ($result !== null) {
|
|
$content = str_replace($link, $result, $content);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Parse and replace references in the given content.
|
|
* Calls the handler for each reference detected and replaces the link
|
|
* with the handler return value if provided.
|
|
* Returns the resulting content string with references replaced.
|
|
* @param callable(string $type, int $id):(string|null) $handler
|
|
*/
|
|
public function parseReferences(string $content, callable $handler): string
|
|
{
|
|
$referenceRegex = '/\[\[bsexport:([a-z]+):(\d+)]]/';
|
|
$matches = [];
|
|
preg_match_all($referenceRegex, $content, $matches);
|
|
|
|
if (count($matches) < 3) {
|
|
return $content;
|
|
}
|
|
|
|
for ($i = 0; $i < count($matches[0]); $i++) {
|
|
$referenceText = $matches[0][$i];
|
|
$type = strtolower($matches[1][$i]);
|
|
$id = intval($matches[2][$i]);
|
|
$result = $handler($type, $id);
|
|
if ($result !== null) {
|
|
$content = str_replace($referenceText, $result, $content);
|
|
}
|
|
}
|
|
|
|
return $content;
|
|
}
|
|
|
|
|
|
/**
|
|
* Attempt to resolve the given link to a model using the instance model resolvers.
|
|
*/
|
|
protected function linkToModel(string $link): ?Model
|
|
{
|
|
foreach ($this->getModelResolvers() as $resolver) {
|
|
$model = $resolver->resolve($link);
|
|
if (!is_null($model)) {
|
|
return $model;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected function getModelResolvers(): array
|
|
{
|
|
if (isset($this->modelResolvers)) {
|
|
return $this->modelResolvers;
|
|
}
|
|
|
|
$this->modelResolvers = [
|
|
new PagePermalinkModelResolver($this->queries->pages),
|
|
new PageLinkModelResolver($this->queries->pages),
|
|
new ChapterLinkModelResolver($this->queries->chapters),
|
|
new BookLinkModelResolver($this->queries->books),
|
|
new ImageModelResolver(),
|
|
new AttachmentModelResolver(),
|
|
];
|
|
|
|
return $this->modelResolvers;
|
|
}
|
|
|
|
/**
|
|
* Build the regex to identify links we should handle in content.
|
|
*/
|
|
protected function getLinkRegex(): string
|
|
{
|
|
$urls = [rtrim(url('/'), '/')];
|
|
$imageUrl = rtrim(ImageStorage::getPublicUrl('/'), '/');
|
|
if ($urls[0] !== $imageUrl) {
|
|
$urls[] = $imageUrl;
|
|
}
|
|
|
|
|
|
$urlBaseRegex = implode('|', array_map(function ($url) {
|
|
return preg_quote($url, '/');
|
|
}, $urls));
|
|
|
|
return "/(({$urlBaseRegex}).*?)[\\t\\n\\f>\"'=?#()]/";
|
|
}
|
|
}
|