| 
									
										
										
										
											2022-08-16 20:23:53 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:39:53 +08:00
										 |  |  | namespace BookStack\References; | 
					
						
							| 
									
										
										
										
											2022-08-16 20:23:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\App\Model; | 
					
						
							| 
									
										
										
										
											2024-02-08 00:37:36 +08:00
										 |  |  | use BookStack\Entities\Queries\EntityQueries; | 
					
						
							| 
									
										
										
										
											2022-08-17 21:39:53 +08:00
										 |  |  | use BookStack\References\ModelResolvers\BookLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\BookshelfLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\ChapterLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\CrossLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\PageLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\PagePermalinkModelResolver; | 
					
						
							| 
									
										
										
										
											2023-11-14 23:46:32 +08:00
										 |  |  | use BookStack\Util\HtmlDocument; | 
					
						
							| 
									
										
										
										
											2022-08-16 20:23:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class CrossLinkParser | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @var CrossLinkModelResolver[] | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected array $modelResolvers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function __construct(array $modelResolvers) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->modelResolvers = $modelResolvers; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Extract any found models within the given HTML content. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2022-08-17 21:39:53 +08:00
										 |  |  |      * @return Model[] | 
					
						
							| 
									
										
										
										
											2022-08-16 20:23:53 +08:00
										 |  |  |      */ | 
					
						
							|  |  |  |     public function extractLinkedModels(string $html): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $models = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $links = $this->getLinksFromContent($html); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($links as $link) { | 
					
						
							|  |  |  |             $model = $this->linkToModel($link); | 
					
						
							|  |  |  |             if (!is_null($model)) { | 
					
						
							|  |  |  |                 $models[get_class($model) . ':' . $model->id] = $model; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return array_values($models); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get a list of href values from the given document. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @returns string[] | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function getLinksFromContent(string $html): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $links = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-14 23:46:32 +08:00
										 |  |  |         $doc = new HtmlDocument($html); | 
					
						
							|  |  |  |         $anchors = $doc->queryXPath('//a[@href]'); | 
					
						
							| 
									
										
										
										
											2022-08-16 20:23:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** @var \DOMElement $anchor */ | 
					
						
							|  |  |  |         foreach ($anchors as $anchor) { | 
					
						
							|  |  |  |             $links[] = $anchor->getAttribute('href'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $links; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Attempt to resolve the given link to a model using the instance model resolvers. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function linkToModel(string $link): ?Model | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         foreach ($this->modelResolvers as $resolver) { | 
					
						
							|  |  |  |             $model = $resolver->resolve($link); | 
					
						
							|  |  |  |             if (!is_null($model)) { | 
					
						
							|  |  |  |                 return $model; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Create a new instance with a pre-defined set of model resolvers, specifically for the | 
					
						
							|  |  |  |      * default set of entities within BookStack. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function createWithEntityResolvers(): self | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-02-08 00:37:36 +08:00
										 |  |  |         $queries = app()->make(EntityQueries::class); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-30 00:39:50 +08:00
										 |  |  |         return new self([ | 
					
						
							| 
									
										
										
										
											2024-02-08 00:37:36 +08:00
										 |  |  |             new PagePermalinkModelResolver($queries->pages), | 
					
						
							|  |  |  |             new PageLinkModelResolver($queries->pages), | 
					
						
							|  |  |  |             new ChapterLinkModelResolver($queries->chapters), | 
					
						
							|  |  |  |             new BookLinkModelResolver($queries->books), | 
					
						
							|  |  |  |             new BookshelfLinkModelResolver($queries->shelves), | 
					
						
							| 
									
										
										
										
											2022-08-16 20:23:53 +08:00
										 |  |  |         ]); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-30 00:46:41 +08:00
										 |  |  | } |