xref: /template/strap/ComboStrap/TemplateSlot.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
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