100 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
| <?php
 | |
| 
 | |
| namespace BookStack\References;
 | |
| 
 | |
| use BookStack\App\Model;
 | |
| use BookStack\Entities\Queries\EntityQueries;
 | |
| 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;
 | |
| use BookStack\Util\HtmlDocument;
 | |
| 
 | |
| class CrossLinkParser
 | |
| {
 | |
|     /**
 | |
|      * @var CrossLinkModelResolver[]
 | |
|      */
 | |
|     protected array $modelResolvers;
 | |
| 
 | |
|     public function __construct(array $modelResolvers)
 | |
|     {
 | |
|         $this->modelResolvers = $modelResolvers;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Extract any found models within the given HTML content.
 | |
|      *
 | |
|      * @return Model[]
 | |
|      */
 | |
|     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 = [];
 | |
| 
 | |
|         $doc = new HtmlDocument($html);
 | |
|         $anchors = $doc->queryXPath('//a[@href]');
 | |
| 
 | |
|         /** @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
 | |
|     {
 | |
|         $queries = app()->make(EntityQueries::class);
 | |
| 
 | |
|         return new self([
 | |
|             new PagePermalinkModelResolver($queries->pages),
 | |
|             new PageLinkModelResolver($queries->pages),
 | |
|             new ChapterLinkModelResolver($queries->chapters),
 | |
|             new BookLinkModelResolver($queries->books),
 | |
|             new BookshelfLinkModelResolver($queries->shelves),
 | |
|         ]);
 | |
|     }
 | |
| }
 |