]> BookStack Code Mirror - bookstack/blob - app/References/CrossLinkParser.php
Opensearch: Fixed XML declaration when php short tags enabled
[bookstack] / app / References / CrossLinkParser.php
1 <?php
2
3 namespace BookStack\References;
4
5 use BookStack\App\Model;
6 use BookStack\Entities\Queries\EntityQueries;
7 use BookStack\References\ModelResolvers\BookLinkModelResolver;
8 use BookStack\References\ModelResolvers\BookshelfLinkModelResolver;
9 use BookStack\References\ModelResolvers\ChapterLinkModelResolver;
10 use BookStack\References\ModelResolvers\CrossLinkModelResolver;
11 use BookStack\References\ModelResolvers\PageLinkModelResolver;
12 use BookStack\References\ModelResolvers\PagePermalinkModelResolver;
13 use BookStack\Util\HtmlDocument;
14
15 class CrossLinkParser
16 {
17     /**
18      * @var CrossLinkModelResolver[]
19      */
20     protected array $modelResolvers;
21
22     public function __construct(array $modelResolvers)
23     {
24         $this->modelResolvers = $modelResolvers;
25     }
26
27     /**
28      * Extract any found models within the given HTML content.
29      *
30      * @return Model[]
31      */
32     public function extractLinkedModels(string $html): array
33     {
34         $models = [];
35
36         $links = $this->getLinksFromContent($html);
37
38         foreach ($links as $link) {
39             $model = $this->linkToModel($link);
40             if (!is_null($model)) {
41                 $models[get_class($model) . ':' . $model->id] = $model;
42             }
43         }
44
45         return array_values($models);
46     }
47
48     /**
49      * Get a list of href values from the given document.
50      *
51      * @returns string[]
52      */
53     protected function getLinksFromContent(string $html): array
54     {
55         $links = [];
56
57         $doc = new HtmlDocument($html);
58         $anchors = $doc->queryXPath('//a[@href]');
59
60         /** @var \DOMElement $anchor */
61         foreach ($anchors as $anchor) {
62             $links[] = $anchor->getAttribute('href');
63         }
64
65         return $links;
66     }
67
68     /**
69      * Attempt to resolve the given link to a model using the instance model resolvers.
70      */
71     protected function linkToModel(string $link): ?Model
72     {
73         foreach ($this->modelResolvers as $resolver) {
74             $model = $resolver->resolve($link);
75             if (!is_null($model)) {
76                 return $model;
77             }
78         }
79
80         return null;
81     }
82
83     /**
84      * Create a new instance with a pre-defined set of model resolvers, specifically for the
85      * default set of entities within BookStack.
86      */
87     public static function createWithEntityResolvers(): self
88     {
89         $queries = app()->make(EntityQueries::class);
90
91         return new self([
92             new PagePermalinkModelResolver($queries->pages),
93             new PageLinkModelResolver($queries->pages),
94             new ChapterLinkModelResolver($queries->chapters),
95             new BookLinkModelResolver($queries->books),
96             new BookshelfLinkModelResolver($queries->shelves),
97         ]);
98     }
99 }