1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeau 4*04fd306cSNickeaunamespace ComboStrap; 5*04fd306cSNickeau 6*04fd306cSNickeau 7*04fd306cSNickeau/** 8*04fd306cSNickeau * This class represents a page layout slots 9*04fd306cSNickeau */ 10*04fd306cSNickeauclass TemplateSlot 11*04fd306cSNickeau{ 12*04fd306cSNickeau public const SLOT_IDS = [ 13*04fd306cSNickeau self::PAGE_SIDE_ID, 14*04fd306cSNickeau self::PAGE_HEADER_ID, 15*04fd306cSNickeau self::PAGE_MAIN_ID, 16*04fd306cSNickeau self::PAGE_FOOTER_ID, 17*04fd306cSNickeau self::MAIN_HEADER_ID, 18*04fd306cSNickeau self::MAIN_CONTENT_ID, 19*04fd306cSNickeau self::MAIN_SIDE_ID, 20*04fd306cSNickeau self::MAIN_FOOTER_ID 21*04fd306cSNickeau ]; 22*04fd306cSNickeau public const PAGE_HEADER_ID = "page-header"; 23*04fd306cSNickeau public const PAGE_FOOTER_ID = "page-footer"; 24*04fd306cSNickeau public const MAIN_SIDE_ID = "main-side"; 25*04fd306cSNickeau public const PAGE_SIDE_ID = "page-side"; 26*04fd306cSNickeau public const MAIN_CONTENT_ID = "main-content"; 27*04fd306cSNickeau public const MAIN_FOOTER_ID = "main-footer"; 28*04fd306cSNickeau public const MAIN_HEADER_ID = "main-header"; 29*04fd306cSNickeau public const PAGE_MAIN_ID = "page-main"; 30*04fd306cSNickeau public const CONF_PAGE_MAIN_SIDEKICK_NAME_DEFAULT = Site::SLOT_MAIN_SIDE_NAME; 31*04fd306cSNickeau public const CONF_PAGE_HEADER_NAME = "headerSlotPageName"; 32*04fd306cSNickeau public const CONF_PAGE_FOOTER_NAME = "footerSlotPageName"; 33*04fd306cSNickeau public const CONF_PAGE_HEADER_NAME_DEFAULT = "slot_header"; 34*04fd306cSNickeau public const CONF_PAGE_FOOTER_NAME_DEFAULT = "slot_footer"; 35*04fd306cSNickeau public const CONF_PAGE_MAIN_SIDEKICK_NAME = "sidekickSlotPageName"; 36*04fd306cSNickeau const MAIN_TOC_ID = "main-toc"; 37*04fd306cSNickeau const SLOT_MAIN_HEADER_PATH_NAME = "slot_main_header"; 38*04fd306cSNickeau const SLOT_MAIN_FOOTER_PATH_NAME = "slot_main_footer"; 39*04fd306cSNickeau 40*04fd306cSNickeau 41*04fd306cSNickeau /** 42*04fd306cSNickeau * @var WikiPath - the context path of this slot 43*04fd306cSNickeau */ 44*04fd306cSNickeau private WikiPath $contextPath; 45*04fd306cSNickeau /** 46*04fd306cSNickeau * @var FetcherMarkup - the fetcher if this is a slot and has a page fragment source 47*04fd306cSNickeau */ 48*04fd306cSNickeau private FetcherMarkup $fetcherFragment; 49*04fd306cSNickeau private string $elementId; 50*04fd306cSNickeau 51*04fd306cSNickeau 52*04fd306cSNickeau public function __construct(string $elementId, WikiPath $contextPath) 53*04fd306cSNickeau { 54*04fd306cSNickeau 55*04fd306cSNickeau $this->elementId = $elementId; 56*04fd306cSNickeau if (!in_array($elementId, self::SLOT_IDS)) { 57*04fd306cSNickeau throw new ExceptionRuntimeInternal("$elementId is not a valid slot id. Valid ids are (" . ArrayUtility::formatAsString(self::SLOT_IDS) . ")."); 58*04fd306cSNickeau } 59*04fd306cSNickeau $this->contextPath = $contextPath; 60*04fd306cSNickeau 61*04fd306cSNickeau 62*04fd306cSNickeau } 63*04fd306cSNickeau 64*04fd306cSNickeau public static function createFromElementId(string $elementId, WikiPath $contextPath = null): TemplateSlot 65*04fd306cSNickeau { 66*04fd306cSNickeau 67*04fd306cSNickeau if ($contextPath === null) { 68*04fd306cSNickeau $contextPath = ExecutionContext::getActualOrCreateFromEnv() 69*04fd306cSNickeau ->getConfig() 70*04fd306cSNickeau ->getDefaultContextPath(); 71*04fd306cSNickeau } 72*04fd306cSNickeau return new TemplateSlot($elementId, $contextPath); 73*04fd306cSNickeau 74*04fd306cSNickeau } 75*04fd306cSNickeau 76*04fd306cSNickeau public static function createFromPathName($pathNameWithoutExtension): TemplateSlot 77*04fd306cSNickeau { 78*04fd306cSNickeau return self::createFromElementId(self::getElementIdFromPathName($pathNameWithoutExtension)); 79*04fd306cSNickeau } 80*04fd306cSNickeau 81*04fd306cSNickeau private static function getElementIdFromPathName($pathNameWithoutExtension): string 82*04fd306cSNickeau { 83*04fd306cSNickeau if ($pathNameWithoutExtension === SlotSystem::getPageHeaderSlotName()) { 84*04fd306cSNickeau return self::PAGE_HEADER_ID; 85*04fd306cSNickeau } 86*04fd306cSNickeau 87*04fd306cSNickeau if ($pathNameWithoutExtension === SlotSystem::getPageFooterSlotName()) { 88*04fd306cSNickeau return self::PAGE_FOOTER_ID; 89*04fd306cSNickeau } 90*04fd306cSNickeau if ($pathNameWithoutExtension === SlotSystem::getSidebarName()) { 91*04fd306cSNickeau return self::PAGE_SIDE_ID; 92*04fd306cSNickeau } 93*04fd306cSNickeau 94*04fd306cSNickeau if ($pathNameWithoutExtension === SlotSystem::getMainSideSlotName()) { 95*04fd306cSNickeau return self::MAIN_SIDE_ID; 96*04fd306cSNickeau } 97*04fd306cSNickeau if ($pathNameWithoutExtension === self::SLOT_MAIN_HEADER_PATH_NAME) { 98*04fd306cSNickeau return self::MAIN_HEADER_ID; 99*04fd306cSNickeau } 100*04fd306cSNickeau if ($pathNameWithoutExtension === self::SLOT_MAIN_FOOTER_PATH_NAME) { 101*04fd306cSNickeau return self::MAIN_FOOTER_ID; 102*04fd306cSNickeau } 103*04fd306cSNickeau throw new ExceptionRuntimeInternal("Internal: The markup name ($pathNameWithoutExtension) was unexpected, it's not a slot"); 104*04fd306cSNickeau 105*04fd306cSNickeau } 106*04fd306cSNickeau 107*04fd306cSNickeau 108*04fd306cSNickeau public 109*04fd306cSNickeau static function getPathNameFromElementId($elementId) 110*04fd306cSNickeau { 111*04fd306cSNickeau switch ($elementId) { 112*04fd306cSNickeau case self::PAGE_HEADER_ID: 113*04fd306cSNickeau return SlotSystem::getPageHeaderSlotName(); 114*04fd306cSNickeau case self::PAGE_FOOTER_ID: 115*04fd306cSNickeau return SlotSystem::getPageFooterSlotName(); 116*04fd306cSNickeau case self::MAIN_CONTENT_ID: 117*04fd306cSNickeau throw new ExceptionRuntimeInternal("Main content area is not a slot and does not have any last slot name"); 118*04fd306cSNickeau case self::PAGE_SIDE_ID: 119*04fd306cSNickeau return SlotSystem::getSidebarName(); 120*04fd306cSNickeau case self::MAIN_SIDE_ID: 121*04fd306cSNickeau return SlotSystem::getMainSideSlotName(); 122*04fd306cSNickeau case self::MAIN_HEADER_ID: 123*04fd306cSNickeau return self::SLOT_MAIN_HEADER_PATH_NAME; 124*04fd306cSNickeau case self::MAIN_FOOTER_ID: 125*04fd306cSNickeau return self::SLOT_MAIN_FOOTER_PATH_NAME; 126*04fd306cSNickeau default: 127*04fd306cSNickeau throw new ExceptionRuntimeInternal("Internal: The element ($elementId) was unexpected, it's not a slot"); 128*04fd306cSNickeau } 129*04fd306cSNickeau 130*04fd306cSNickeau } 131*04fd306cSNickeau 132*04fd306cSNickeau /** 133*04fd306cSNickeau * 134*04fd306cSNickeau * @return WikiPath 135*04fd306cSNickeau */ 136*04fd306cSNickeau public 137*04fd306cSNickeau function getDefaultSlotContentPath(): WikiPath 138*04fd306cSNickeau { 139*04fd306cSNickeau return WikiPath::createComboResource(":slot:{$this->getElementId()}.md"); 140*04fd306cSNickeau } 141*04fd306cSNickeau 142*04fd306cSNickeau 143*04fd306cSNickeau /** 144*04fd306cSNickeau */ 145*04fd306cSNickeau public 146*04fd306cSNickeau function getLastFileNameForFragment() 147*04fd306cSNickeau { 148*04fd306cSNickeau $elementId = $this->getElementId(); 149*04fd306cSNickeau return self::getPathNameFromElementId($elementId); 150*04fd306cSNickeau } 151*04fd306cSNickeau 152*04fd306cSNickeau 153*04fd306cSNickeau public 154*04fd306cSNickeau function __toString() 155*04fd306cSNickeau { 156*04fd306cSNickeau return "Slot {$this->getElementId()} for {$this->contextPath}"; 157*04fd306cSNickeau } 158*04fd306cSNickeau 159*04fd306cSNickeau 160*04fd306cSNickeau /** 161*04fd306cSNickeau * @throws ExceptionNotFound - if the area is not a slot or there is no path found 162*04fd306cSNickeau */ 163*04fd306cSNickeau private 164*04fd306cSNickeau function getFragmentPath() 165*04fd306cSNickeau { 166*04fd306cSNickeau 167*04fd306cSNickeau // Main content 168*04fd306cSNickeau $requestedPath = $this->contextPath; 169*04fd306cSNickeau if ($this->getElementId() === self::MAIN_CONTENT_ID) { 170*04fd306cSNickeau return $requestedPath; 171*04fd306cSNickeau } 172*04fd306cSNickeau // Slot 173*04fd306cSNickeau $contextExtension = $requestedPath->getExtension(); 174*04fd306cSNickeau try { 175*04fd306cSNickeau return FileSystems::closest($requestedPath, $this->getLastFileNameForFragment() . '.' . $contextExtension); 176*04fd306cSNickeau } catch (ExceptionNotFound $e) { 177*04fd306cSNickeau foreach (WikiPath::ALL_MARKUP_EXTENSIONS as $markupExtension) { 178*04fd306cSNickeau if ($markupExtension == $contextExtension) { 179*04fd306cSNickeau continue; 180*04fd306cSNickeau } 181*04fd306cSNickeau try { 182*04fd306cSNickeau return FileSystems::closest($requestedPath, $this->getLastFileNameForFragment() . '.' . $contextExtension); 183*04fd306cSNickeau } catch (ExceptionNotFound $e) { 184*04fd306cSNickeau // not found, we let it go to the default if needed 185*04fd306cSNickeau } 186*04fd306cSNickeau } 187*04fd306cSNickeau } 188*04fd306cSNickeau 189*04fd306cSNickeau 190*04fd306cSNickeau return $this->getDefaultSlotContentPath(); 191*04fd306cSNickeau 192*04fd306cSNickeau 193*04fd306cSNickeau 194*04fd306cSNickeau } 195*04fd306cSNickeau 196*04fd306cSNickeau 197*04fd306cSNickeau /** 198*04fd306cSNickeau * @throws ExceptionNotFound if the page/markup fragment was not found (a container element does not have any also) 199*04fd306cSNickeau */ 200*04fd306cSNickeau public 201*04fd306cSNickeau function getMarkupFetcher(): FetcherMarkup 202*04fd306cSNickeau { 203*04fd306cSNickeau if (isset($this->fetcherFragment)) { 204*04fd306cSNickeau return $this->fetcherFragment; 205*04fd306cSNickeau } 206*04fd306cSNickeau /** 207*04fd306cSNickeau * Rebuild the fragment if any 208*04fd306cSNickeau */ 209*04fd306cSNickeau $fragmentPath = $this->getFragmentPath(); 210*04fd306cSNickeau $contextPath = $this->contextPath; 211*04fd306cSNickeau try { 212*04fd306cSNickeau $this->fetcherFragment = FetcherMarkup::createXhtmlMarkupFetcherFromPath($fragmentPath, $contextPath); 213*04fd306cSNickeau } catch (ExceptionNotExists $e) { 214*04fd306cSNickeau throw new ExceptionNotFound("The fragment path ($fragmentPath) was no found"); 215*04fd306cSNickeau } 216*04fd306cSNickeau return $this->fetcherFragment; 217*04fd306cSNickeau } 218*04fd306cSNickeau 219*04fd306cSNickeau public 220*04fd306cSNickeau function getElementId(): string 221*04fd306cSNickeau { 222*04fd306cSNickeau return $this->elementId; 223*04fd306cSNickeau } 224*04fd306cSNickeau 225*04fd306cSNickeau public function getPathName() 226*04fd306cSNickeau { 227*04fd306cSNickeau return self::getPathNameFromElementId($this->getElementId()); 228*04fd306cSNickeau } 229*04fd306cSNickeau 230*04fd306cSNickeau 231*04fd306cSNickeau} 232