1<?php 2 3namespace ComboStrap; 4 5use action_plugin_combo_router; 6use ComboStrap\Meta\Field\Aliases; 7use ComboStrap\Meta\Field\AliasType; 8use ComboStrap\Meta\Store\MetadataDbStore; 9 10 11/** 12 * Class UrlManagerBestEndPage 13 * 14 * A class that implements the BestEndPage Algorithm for the {@link action_plugin_combo_router urlManager} 15 */ 16class RouterBestEndPage 17{ 18 19 /** 20 * If the number of names part that match is greater or equal to 21 * this configuration, an Id Redirect is performed 22 * A value of 0 disable and send only HTTP redirect 23 */ 24 const CONF_MINIMAL_SCORE_FOR_REDIRECT = 'BestEndPageMinimalScoreForAliasCreation'; 25 const CONF_MINIMAL_SCORE_FOR_REDIRECT_DEFAULT = '2'; 26 27 28 /** 29 * @param MarkupPath $requestedPage 30 * @return array - the best page id and its score 31 * The score is the number of name that matches 32 */ 33 public static function getBestEndPageId(MarkupPath $requestedPage): array 34 { 35 36 $pagesWithSameName = Index::getOrCreate() 37 ->getPagesWithSameLastName($requestedPage); 38 if (sizeof($pagesWithSameName) == 0) { 39 return [null, null]; 40 } 41 return self::getBestEndPageIdFromPages($pagesWithSameName, $requestedPage); 42 43 44 } 45 46 47 /** 48 * @param MarkupPath $missingPage 49 * @return array with the best page and the type of redirect 50 */ 51 public static function process(MarkupPath $missingPage): array 52 { 53 54 $return = [null, null]; 55 56 $minimalScoreForARedirect = SiteConfig::getConfValue(self::CONF_MINIMAL_SCORE_FOR_REDIRECT, self::CONF_MINIMAL_SCORE_FOR_REDIRECT_DEFAULT); 57 58 list($bestPage, $bestScore) = self::getBestEndPageId($missingPage); 59 if ($bestPage != null) { 60 $redirectType = RouterRedirection::REDIRECT_NOTFOUND_METHOD; 61 if ($minimalScoreForARedirect != 0 && $bestScore >= $minimalScoreForARedirect) { 62 try { 63 Aliases::createForPage($bestPage) 64 ->addAlias($missingPage, AliasType::REDIRECT) 65 ->sendToWriteStore() 66 ->setReadStore(MetadataDbStore::getOrCreateFromResource($bestPage)) 67 ->sendToWriteStore(); 68 } catch (ExceptionBadArgument|ExceptionCompile $e) { 69 LogUtility::error("Error while creating an alias",LogUtility::SUPPORT_CANONICAL,$e); 70 return $return; 71 } 72 $redirectType = RouterRedirection::REDIRECT_PERMANENT_METHOD; 73 } 74 $return = array( 75 $bestPage, 76 $redirectType 77 ); 78 } 79 return $return; 80 81 } 82 83 /** 84 * @param MarkupPath[] $candidatePagesWithSameLastName 85 * @param MarkupPath $requestedPage 86 * @return array 87 */ 88 public static function getBestEndPageIdFromPages(array $candidatePagesWithSameLastName, MarkupPath $requestedPage): array 89 { 90 // Default value 91 $bestScore = 0; 92 $bestPage = $candidatePagesWithSameLastName[0]; 93 94 // The name of the dokuwiki id 95 $requestedPageNames = $requestedPage->getPathObject()->getNames(); 96 97 // Loop 98 foreach ($candidatePagesWithSameLastName as $candidatePage) { 99 100 try { 101 if ($candidatePage->getWikiId() === $requestedPage->getWikiId()) { 102 // when the index is not up to date 103 continue; 104 } 105 } catch (ExceptionBadArgument $e) { 106 // should not happen but yeah 107 } 108 109 $candidatePageNames = $candidatePage->getPathObject()->getNames(); 110 $score = 0; 111 foreach ($candidatePageNames as $candidatePageName) { 112 if (in_array($candidatePageName, $requestedPageNames)) { 113 $score++; 114 } 115 } 116 if ($score > $bestScore) { 117 $bestScore = $score; 118 $bestPage = $candidatePage; 119 } else if ($score === $bestScore) { 120 /** 121 * Best backlink count 122 */ 123 $candidateBacklinksCount = sizeof($candidatePage->getBacklinks()); 124 $bestPageBacklinksCount = sizeof($bestPage->getBacklinks()); 125 if ($candidateBacklinksCount > $bestPageBacklinksCount) { 126 $bestPage = $candidatePage; 127 } 128 } 129 130 } 131 132 return array( 133 $bestPage, 134 $bestScore 135 ); 136 } 137} 138