| 
									
										
										
										
											2024-10-21 02:56:56 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 17:48:26 +08:00
										 |  |  | namespace BookStack\Exports\ZipExports; | 
					
						
							| 
									
										
										
										
											2024-10-21 02:56:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | use BookStack\App\Model; | 
					
						
							|  |  |  | use BookStack\Entities\Queries\EntityQueries; | 
					
						
							| 
									
										
										
										
											2024-10-21 19:13:41 +08:00
										 |  |  | use BookStack\References\ModelResolvers\AttachmentModelResolver; | 
					
						
							| 
									
										
										
										
											2024-10-21 02:56:56 +08:00
										 |  |  | use BookStack\References\ModelResolvers\BookLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\ChapterLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\CrossLinkModelResolver; | 
					
						
							| 
									
										
										
										
											2024-10-21 19:13:41 +08:00
										 |  |  | use BookStack\References\ModelResolvers\ImageModelResolver; | 
					
						
							| 
									
										
										
										
											2024-10-21 02:56:56 +08:00
										 |  |  | use BookStack\References\ModelResolvers\PageLinkModelResolver; | 
					
						
							|  |  |  | use BookStack\References\ModelResolvers\PagePermalinkModelResolver; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ZipReferenceParser | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @var CrossLinkModelResolver[] | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected array $modelResolvers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function __construct(EntityQueries $queries) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->modelResolvers = [ | 
					
						
							|  |  |  |             new PagePermalinkModelResolver($queries->pages), | 
					
						
							|  |  |  |             new PageLinkModelResolver($queries->pages), | 
					
						
							|  |  |  |             new ChapterLinkModelResolver($queries->chapters), | 
					
						
							|  |  |  |             new BookLinkModelResolver($queries->books), | 
					
						
							| 
									
										
										
										
											2024-10-21 19:13:41 +08:00
										 |  |  |             new ImageModelResolver(), | 
					
						
							|  |  |  |             new AttachmentModelResolver(), | 
					
						
							| 
									
										
										
										
											2024-10-21 02:56:56 +08:00
										 |  |  |         ]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Parse and replace references in the given content. | 
					
						
							|  |  |  |      * @param callable(Model):(string|null) $handler | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function parse(string $content, callable $handler): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $escapedBase = preg_quote(url('/'), '/'); | 
					
						
							|  |  |  |         $linkRegex = "/({$escapedBase}.*?)[\\t\\n\\f>\"'=?#]/"; | 
					
						
							|  |  |  |         $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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |