xref: /plugin/combo/ComboStrap/MarkupPath.php (revision 65e00826e4eceefc13be6f404ba5dcc7c44f243c)
104fd306cSNickeau<?php
204fd306cSNickeau
304fd306cSNickeaunamespace ComboStrap;
404fd306cSNickeau
504fd306cSNickeau
604fd306cSNickeauuse ComboStrap\Api\QualityMessageHandler;
704fd306cSNickeauuse ComboStrap\Meta\Api\Metadata;
804fd306cSNickeauuse ComboStrap\Meta\Api\MetadataBoolean;
904fd306cSNickeauuse ComboStrap\Meta\Api\MetadataStore;
1004fd306cSNickeauuse ComboStrap\Meta\Api\MetadataStoreAbs;
1104fd306cSNickeauuse ComboStrap\Meta\Field\Alias;
1204fd306cSNickeauuse ComboStrap\Meta\Field\Aliases;
1304fd306cSNickeauuse ComboStrap\Meta\Field\AliasType;
1404fd306cSNickeauuse ComboStrap\Meta\Field\PageH1;
1504fd306cSNickeauuse ComboStrap\Meta\Field\PageImage;
1604fd306cSNickeauuse ComboStrap\Meta\Field\PageImages;
1704fd306cSNickeauuse ComboStrap\Meta\Field\PageTemplateName;
1804fd306cSNickeauuse ComboStrap\Meta\Field\Region;
1904fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore;
2004fd306cSNickeauuse ComboStrap\Web\Url;
2104fd306cSNickeauuse ComboStrap\Web\UrlEndpoint;
2204fd306cSNickeauuse DateTime;
2304fd306cSNickeauuse dokuwiki\ChangeLog\ChangeLog;
2404fd306cSNickeauuse Exception;
2504fd306cSNickeauuse renderer_plugin_combo_analytics;
2604fd306cSNickeau
2704fd306cSNickeau
2804fd306cSNickeau/**
2904fd306cSNickeau *
3004fd306cSNickeau * A markup is a logical unit that represents a markup file.
3104fd306cSNickeau *
3204fd306cSNickeau * It has its own file system {@link MarkupFileSystem} explained in the
3304fd306cSNickeau * https://combostrap.com/page/system (or system.txt file).
3404fd306cSNickeau * ie the {@link Path::getParent()} is not the same than on an normal file system.
3504fd306cSNickeau *
3604fd306cSNickeau * This should be an extension of {@link WikiPath} but for now, we are not extending {@link WikiPath}
3704fd306cSNickeau * for the following old reasons:
3804fd306cSNickeau *   * we want to be able to return a {@link MarkupPath} in the {@link MarkupPath::getParent()} function
3904fd306cSNickeau * otherwise if we do, we get a hierarchical error.
4004fd306cSNickeau *   * we can then accepts also {@link LocalPath}
4104fd306cSNickeau *
4204fd306cSNickeau * But because this is a {@link ResourceCombo}, we see tht this is part of the {@link WikiPath}
4304fd306cSNickeau * system with an {@link ResourceCombo::getUid()} unique uid.
4404fd306cSNickeau *
4504fd306cSNickeau * We should find a way to be able to create a wiki path with a {@link LocalPath}
4604fd306cSNickeau * via the {@link WikiPath::getDrive()} ?
4704fd306cSNickeau *
4804fd306cSNickeau */
4904fd306cSNickeauclass MarkupPath extends PathAbs implements ResourceCombo, Path
5004fd306cSNickeau{
5104fd306cSNickeau
5204fd306cSNickeau    const CANONICAL_PAGE = "markup";
5304fd306cSNickeau
5404fd306cSNickeau
5504fd306cSNickeau    const TYPE = "page";
5604fd306cSNickeau
5704fd306cSNickeau    /**
5804fd306cSNickeau     * @var Canonical
5904fd306cSNickeau     */
6004fd306cSNickeau    private $canonical;
6104fd306cSNickeau    /**
6204fd306cSNickeau     * @var PageH1
6304fd306cSNickeau     */
6404fd306cSNickeau    private $h1;
6504fd306cSNickeau    /**
6604fd306cSNickeau     * @var ResourceName
6704fd306cSNickeau     */
6804fd306cSNickeau    private $pageName;
6904fd306cSNickeau    /**
7004fd306cSNickeau     * @var PageType
7104fd306cSNickeau     */
7204fd306cSNickeau    private $type;
7304fd306cSNickeau    /**
7404fd306cSNickeau     * @var PageTitle $title
7504fd306cSNickeau     */
7604fd306cSNickeau    private $title;
7704fd306cSNickeau
7804fd306cSNickeau    private $uidObject;
7904fd306cSNickeau
8004fd306cSNickeau    private LowQualityPageOverwrite $canBeOfLowQuality;
8104fd306cSNickeau    /**
8204fd306cSNickeau     * @var Region
8304fd306cSNickeau     */
8404fd306cSNickeau    private $region;
8504fd306cSNickeau    /**
8604fd306cSNickeau     * @var Lang
8704fd306cSNickeau     */
8804fd306cSNickeau    private $lang;
8904fd306cSNickeau    /**
9004fd306cSNickeau     * @var PageId
9104fd306cSNickeau     */
9204fd306cSNickeau    private $pageId;
9304fd306cSNickeau
9404fd306cSNickeau    /**
9504fd306cSNickeau     * @var LowQualityCalculatedIndicator
9604fd306cSNickeau     */
9704fd306cSNickeau    private $lowQualityIndicatorCalculated;
9804fd306cSNickeau
9904fd306cSNickeau    /**
10004fd306cSNickeau     * @var PageTemplateName
10104fd306cSNickeau     */
10204fd306cSNickeau    private $layout;
10304fd306cSNickeau    /**
10404fd306cSNickeau     * @var Aliases
10504fd306cSNickeau     */
10604fd306cSNickeau    private $aliases;
10704fd306cSNickeau    /**
10804fd306cSNickeau     * @var Slug a slug path
10904fd306cSNickeau     */
11004fd306cSNickeau    private $slug;
11104fd306cSNickeau
11204fd306cSNickeau
11304fd306cSNickeau    /**
11404fd306cSNickeau     * @var QualityDynamicMonitoringOverwrite
11504fd306cSNickeau     */
11604fd306cSNickeau    private $qualityMonitoringIndicator;
11704fd306cSNickeau
11804fd306cSNickeau    /**
11904fd306cSNickeau     * @var string the alias used to build this page
12004fd306cSNickeau     */
12104fd306cSNickeau    private $buildAliasPath;
12204fd306cSNickeau    /**
12304fd306cSNickeau     * @var PagePublicationDate
12404fd306cSNickeau     */
12504fd306cSNickeau    private $publishedDate;
12604fd306cSNickeau    /**
12704fd306cSNickeau     * @var StartDate
12804fd306cSNickeau     */
12904fd306cSNickeau    private $startDate;
13004fd306cSNickeau    /**
13104fd306cSNickeau     * @var EndDate
13204fd306cSNickeau     */
13304fd306cSNickeau    private $endDate;
13404fd306cSNickeau    /**
13504fd306cSNickeau     * @var PageImages
13604fd306cSNickeau     */
13704fd306cSNickeau    private $pageImages;
13804fd306cSNickeau
13904fd306cSNickeau    private PageKeywords $keywords;
14004fd306cSNickeau    /**
14104fd306cSNickeau     * @var CacheExpirationFrequency
14204fd306cSNickeau     */
14304fd306cSNickeau    private $cacheExpirationFrequency;
14404fd306cSNickeau    /**
14504fd306cSNickeau     * @var CacheExpirationDate
14604fd306cSNickeau     */
14704fd306cSNickeau    private $cacheExpirationDate;
14804fd306cSNickeau    /**
14904fd306cSNickeau     *
15004fd306cSNickeau     * @var LdJson
15104fd306cSNickeau     */
15204fd306cSNickeau    private $ldJson;
15304fd306cSNickeau
15404fd306cSNickeau
15504fd306cSNickeau    /**
15604fd306cSNickeau     * @var PageDescription $description
15704fd306cSNickeau     */
15804fd306cSNickeau    private $description;
15904fd306cSNickeau    /**
16004fd306cSNickeau     * @var CreationDate
16104fd306cSNickeau     */
16204fd306cSNickeau    private $creationTime;
16304fd306cSNickeau    /**
16404fd306cSNickeau     * @var Locale
16504fd306cSNickeau     */
16604fd306cSNickeau    private $locale;
16704fd306cSNickeau    /**
16804fd306cSNickeau     * @var ModificationDate
16904fd306cSNickeau     */
17004fd306cSNickeau    private $modifiedTime;
17104fd306cSNickeau    /**
17204fd306cSNickeau     * @var PageUrlPath
17304fd306cSNickeau     */
17404fd306cSNickeau    private $pageUrlPath;
17504fd306cSNickeau    /**
17604fd306cSNickeau     * @var MetadataStore|string
17704fd306cSNickeau     */
17804fd306cSNickeau    private $readStore;
17904fd306cSNickeau
18004fd306cSNickeau    /**
18104fd306cSNickeau     * @var Path -  {@link MarkupPath} has other hierachy system in regards with parent
18204fd306cSNickeau     * May be we just should extends {@link WikiPath} but it was a way to be able to locate
18304fd306cSNickeau     * default markup path file that were not in any drive
18404fd306cSNickeau     * TODO: Just extends WikiPath and add private drive when data should be accessed locally ?
18504fd306cSNickeau     */
18604fd306cSNickeau    private Path $path;
18704fd306cSNickeau
18804fd306cSNickeau    /**
18904fd306cSNickeau     * Page constructor.
19004fd306cSNickeau     *
19104fd306cSNickeau     */
19204fd306cSNickeau    public function __construct(Path $path)
19304fd306cSNickeau    {
19404fd306cSNickeau
19504fd306cSNickeau        $this->path = $path;
19604fd306cSNickeau        if (FileSystems::isDirectory($path)) {
19704fd306cSNickeau            $this->setCorrectPathForDirectoryToIndexPage();
19804fd306cSNickeau        }
19904fd306cSNickeau        $this->buildPropertiesFromFileSystem();
20004fd306cSNickeau
20104fd306cSNickeau    }
20204fd306cSNickeau
20304fd306cSNickeau    /**
20404fd306cSNickeau     * The current running rendering markup
20504fd306cSNickeau     * @throws ExceptionNotFound
20604fd306cSNickeau     */
20704fd306cSNickeau    public static function createPageFromExecutingId(): MarkupPath
20804fd306cSNickeau    {
20904fd306cSNickeau        $wikiPath = WikiPath::createExecutingMarkupWikiPath();
21004fd306cSNickeau        return self::createPageFromPathObject($wikiPath);
21104fd306cSNickeau    }
21204fd306cSNickeau
21304fd306cSNickeau
21404fd306cSNickeau    public static function createMarkupFromId($id): MarkupPath
21504fd306cSNickeau    {
21604fd306cSNickeau        return new MarkupPath(WikiPath::createMarkupPathFromId($id));
21704fd306cSNickeau    }
21804fd306cSNickeau
21904fd306cSNickeau    /**
22004fd306cSNickeau     * @param string $path -  relative or absolute
22104fd306cSNickeau     * @return MarkupPath
22204fd306cSNickeau     */
22304fd306cSNickeau    public static function createMarkupFromStringPath(string $path): MarkupPath
22404fd306cSNickeau    {
22504fd306cSNickeau        $wikiPath = WikiPath::createMarkupPathFromPath($path);
22604fd306cSNickeau        return new MarkupPath($wikiPath);
22704fd306cSNickeau
22804fd306cSNickeau    }
22904fd306cSNickeau
23004fd306cSNickeau    /**
23104fd306cSNickeau     * @return MarkupPath - the requested page
23204fd306cSNickeau     * @throws ExceptionNotFound
23304fd306cSNickeau     */
23404fd306cSNickeau    public static function createFromRequestedPage(): MarkupPath
23504fd306cSNickeau    {
23604fd306cSNickeau        $path = WikiPath::createRequestedPagePathFromRequest();
23704fd306cSNickeau        return MarkupPath::createPageFromPathObject($path);
23804fd306cSNickeau    }
23904fd306cSNickeau
24004fd306cSNickeau
24104fd306cSNickeau    public static function createPageFromPathObject(Path $path): MarkupPath
24204fd306cSNickeau    {
24304fd306cSNickeau        if ($path instanceof MarkupPath) {
24404fd306cSNickeau            return $path;
24504fd306cSNickeau        }
24604fd306cSNickeau        return new MarkupPath($path);
24704fd306cSNickeau    }
24804fd306cSNickeau
24904fd306cSNickeau
25004fd306cSNickeau    /**
25104fd306cSNickeau     *
25204fd306cSNickeau     * @throws ExceptionBadSyntax - if this is not a
25304fd306cSNickeau     * @deprecated just pass a namespace path to the page creation and you will get the index page in return
25404fd306cSNickeau     */
25504fd306cSNickeau    public static function getIndexPageFromNamespace(string $namespacePath): MarkupPath
25604fd306cSNickeau    {
25704fd306cSNickeau        WikiPath::checkNamespacePath($namespacePath);
25804fd306cSNickeau
25904fd306cSNickeau        return MarkupPath::createMarkupFromId($namespacePath);
26004fd306cSNickeau    }
26104fd306cSNickeau
26204fd306cSNickeau
26304fd306cSNickeau    static function createPageFromAbsoluteId($qualifiedPath): MarkupPath
26404fd306cSNickeau    {
26504fd306cSNickeau        $path = WikiPath::createMarkupPathFromId($qualifiedPath);
26604fd306cSNickeau        return new MarkupPath($path);
26704fd306cSNickeau    }
26804fd306cSNickeau
26904fd306cSNickeau
27004fd306cSNickeau    /**
27104fd306cSNickeau     *
27204fd306cSNickeau     * @throws ExceptionCompile
27304fd306cSNickeau     */
27404fd306cSNickeau    public
27504fd306cSNickeau    function setCanonical($canonical): MarkupPath
27604fd306cSNickeau    {
27704fd306cSNickeau        $this->canonical
27804fd306cSNickeau            ->setValue($canonical)
27904fd306cSNickeau            ->sendToWriteStore();
28004fd306cSNickeau        return $this;
28104fd306cSNickeau    }
28204fd306cSNickeau
28304fd306cSNickeau
28404fd306cSNickeau    /**
28504fd306cSNickeau     * @return bool true if this is a fragment markup
28604fd306cSNickeau     */
28704fd306cSNickeau    public function isSlot(): bool
28804fd306cSNickeau    {
28904fd306cSNickeau        $slotNames = SlotSystem::getSlotNames();
29004fd306cSNickeau        try {
29104fd306cSNickeau            $name = $this->getPathObject()->getLastNameWithoutExtension();
29204fd306cSNickeau        } catch (ExceptionNotFound $e) {
29304fd306cSNickeau            // root case
29404fd306cSNickeau            return false;
29504fd306cSNickeau        }
29604fd306cSNickeau        return in_array($name, $slotNames, true);
29704fd306cSNickeau    }
29804fd306cSNickeau
29904fd306cSNickeau    /**
30004fd306cSNickeau     * @return bool true if this is the side slot
30104fd306cSNickeau     */
30204fd306cSNickeau    public function isSideSlot(): bool
30304fd306cSNickeau    {
30404fd306cSNickeau        $slotNames = SlotSystem::getSidebarName();
30504fd306cSNickeau        try {
30604fd306cSNickeau            $name = $this->getPathObject()->getLastNameWithoutExtension();
30704fd306cSNickeau        } catch (ExceptionNotFound $e) {
30804fd306cSNickeau            // root case
30904fd306cSNickeau            return false;
31004fd306cSNickeau        }
31104fd306cSNickeau        return $name === $slotNames;
31204fd306cSNickeau    }
31304fd306cSNickeau
31404fd306cSNickeau    /**
31504fd306cSNickeau     * @return bool true if this is the main
31604fd306cSNickeau     */
31704fd306cSNickeau    public function isMainHeaderFooterSlot(): bool
31804fd306cSNickeau    {
31904fd306cSNickeau
32004fd306cSNickeau        $slotNames = [SlotSystem::getMainHeaderSlotName(), SlotSystem::getMainFooterSlotName()];
32104fd306cSNickeau        try {
32204fd306cSNickeau            $name = $this->getPathObject()->getLastNameWithoutExtension();
32304fd306cSNickeau        } catch (ExceptionNotFound $e) {
32404fd306cSNickeau            // root case
32504fd306cSNickeau            return false;
32604fd306cSNickeau        }
32704fd306cSNickeau
32804fd306cSNickeau        return in_array($name, $slotNames, true);
32904fd306cSNickeau    }
33004fd306cSNickeau
33104fd306cSNickeau
33204fd306cSNickeau    /**
33304fd306cSNickeau     * Return a canonical if set
33404fd306cSNickeau     * otherwise derive it from the id
33504fd306cSNickeau     * by taking the last two parts
33604fd306cSNickeau     *
33704fd306cSNickeau     * @return WikiPath
33804fd306cSNickeau     * @throws ExceptionNotFound
33904fd306cSNickeau     * @deprecated for {@link Canonical::getValueOrDefault()}
34004fd306cSNickeau     */
34104fd306cSNickeau    public
34204fd306cSNickeau    function getCanonicalOrDefault(): WikiPath
34304fd306cSNickeau    {
34404fd306cSNickeau        return $this->canonical->getValueFromStoreOrDefault();
34504fd306cSNickeau
34604fd306cSNickeau    }
34704fd306cSNickeau
34804fd306cSNickeau
34904fd306cSNickeau    /**
35004fd306cSNickeau     * Rebuild the page
35104fd306cSNickeau     * (refresh from disk, reset object to null)
35204fd306cSNickeau     * @return $this
35304fd306cSNickeau     */
35404fd306cSNickeau    public
35504fd306cSNickeau    function rebuild(): MarkupPath
35604fd306cSNickeau    {
35704fd306cSNickeau        $this->readStore = null;
35804fd306cSNickeau        $this->buildPropertiesFromFileSystem();
35904fd306cSNickeau        return $this;
36004fd306cSNickeau    }
36104fd306cSNickeau
36204fd306cSNickeau    /**
36304fd306cSNickeau     *
36404fd306cSNickeau     * @return MarkupPath[]|null the internal links or null
36504fd306cSNickeau     */
36604fd306cSNickeau    public
36704fd306cSNickeau    function getLinkReferences(): ?array
36804fd306cSNickeau    {
36904fd306cSNickeau        $store = $this->getReadStoreOrDefault();
37004fd306cSNickeau        if (!($store instanceof MetadataDokuWikiStore)) {
37104fd306cSNickeau            return null;
37204fd306cSNickeau        }
37304fd306cSNickeau        $metadata = $store->getCurrentFromName('relation');
37404fd306cSNickeau        if ($metadata === null) {
37504fd306cSNickeau            /**
37604fd306cSNickeau             * Happens when no rendering has been made
37704fd306cSNickeau             */
37804fd306cSNickeau            return null;
37904fd306cSNickeau        }
38004fd306cSNickeau        if (!key_exists('references', $metadata)) {
38104fd306cSNickeau            return null;
38204fd306cSNickeau        }
38304fd306cSNickeau
38404fd306cSNickeau        $pages = [];
38504fd306cSNickeau        foreach (array_keys($metadata['references']) as $referencePageId) {
38604fd306cSNickeau            $pages[$referencePageId] = MarkupPath::createMarkupFromId($referencePageId);
38704fd306cSNickeau        }
38804fd306cSNickeau        return $pages;
38904fd306cSNickeau
39004fd306cSNickeau    }
39104fd306cSNickeau
39204fd306cSNickeau
39304fd306cSNickeau    /**
39404fd306cSNickeau     *
39504fd306cSNickeau     * @throws ExceptionNotExists - if the path does not exists
39604fd306cSNickeau     * @throws ExceptionCast - if the path is not a wiki path which is mandatory for the context
39704fd306cSNickeau     */
39804fd306cSNickeau    public function createHtmlFetcherWithItselfAsContextPath(): FetcherMarkup
39904fd306cSNickeau    {
40004fd306cSNickeau        $path = $this->getPathObject();
40104fd306cSNickeau        return FetcherMarkup::createXhtmlMarkupFetcherFromPath($path, $path->toWikiPath());
40204fd306cSNickeau    }
40304fd306cSNickeau
40404fd306cSNickeau    /**
40504fd306cSNickeau     * @throws ExceptionCompile
40604fd306cSNickeau     */
40704fd306cSNickeau    public function getHtmlPath(): LocalPath
40804fd306cSNickeau    {
40904fd306cSNickeau
41004fd306cSNickeau        $fetcher = $this->createHtmlFetcherWithItselfAsContextPath();
41104fd306cSNickeau        return $fetcher->processIfNeededAndGetFetchPath();
41204fd306cSNickeau
41304fd306cSNickeau    }
41404fd306cSNickeau
41504fd306cSNickeau    /**
41604fd306cSNickeau     * Set the page quality
41704fd306cSNickeau     * @param boolean $value true if this is a low quality page rank false otherwise
41804fd306cSNickeau     * @throws ExceptionCompile
41904fd306cSNickeau     */
42004fd306cSNickeau    public
42104fd306cSNickeau    function setCanBeOfLowQuality(bool $value): MarkupPath
42204fd306cSNickeau    {
42304fd306cSNickeau        return $this->setQualityIndicatorAndDeleteCacheIfNeeded($this->canBeOfLowQuality, $value);
42404fd306cSNickeau    }
42504fd306cSNickeau
42604fd306cSNickeau    /**
42704fd306cSNickeau     * @return MarkupPath[] the backlinks
42804fd306cSNickeau     * Duplicate of related
42904fd306cSNickeau     *
43004fd306cSNickeau     * Same as {@link WikiPath::getReferencedBy()} ?
43104fd306cSNickeau     */
43204fd306cSNickeau    public
43304fd306cSNickeau    function getBacklinks(): array
43404fd306cSNickeau    {
43504fd306cSNickeau        $backlinks = array();
43604fd306cSNickeau        /**
43704fd306cSNickeau         * Same as
43804fd306cSNickeau         * idx_get_indexer()->lookupKey('relation_references', $ID);
43904fd306cSNickeau         */
44004fd306cSNickeau        $ft_backlinks = ft_backlinks($this->getWikiId());
44104fd306cSNickeau        foreach ($ft_backlinks as $backlinkId) {
44204fd306cSNickeau            $backlinks[$backlinkId] = MarkupPath::createMarkupFromId($backlinkId);
44304fd306cSNickeau        }
44404fd306cSNickeau        return $backlinks;
44504fd306cSNickeau    }
44604fd306cSNickeau
44704fd306cSNickeau
44804fd306cSNickeau    /**
44904fd306cSNickeau     * Low page quality
45004fd306cSNickeau     * @return bool true if this is a low quality page
45104fd306cSNickeau     */
45204fd306cSNickeau    function isLowQualityPage(): bool
45304fd306cSNickeau    {
45404fd306cSNickeau
45504fd306cSNickeau
45604fd306cSNickeau        if (!$this->getCanBeOfLowQuality()) {
45704fd306cSNickeau            return false;
45804fd306cSNickeau        }
45904fd306cSNickeau
46004fd306cSNickeau        if (!Site::isLowQualityProtectionEnable()) {
46104fd306cSNickeau            return false;
46204fd306cSNickeau        }
46304fd306cSNickeau        try {
46404fd306cSNickeau            return $this->getLowQualityIndicatorCalculated();
46504fd306cSNickeau        } catch (ExceptionNotFound $e) {
46604fd306cSNickeau            // We were returning null but null used in a condition is falsy
46704fd306cSNickeau            // we return false
46804fd306cSNickeau            return false;
46904fd306cSNickeau        }
47004fd306cSNickeau
47104fd306cSNickeau    }
47204fd306cSNickeau
47304fd306cSNickeau
47404fd306cSNickeau    /**
47504fd306cSNickeau     *
47604fd306cSNickeau     */
47704fd306cSNickeau    public function getCanBeOfLowQuality(): bool
47804fd306cSNickeau    {
47904fd306cSNickeau
48004fd306cSNickeau        return $this->canBeOfLowQuality->getValueOrDefault();
48104fd306cSNickeau
48204fd306cSNickeau    }
48304fd306cSNickeau
48404fd306cSNickeau
48504fd306cSNickeau    /**
48604fd306cSNickeau     * Return the Title
48704fd306cSNickeau     * @deprecated for {@link PageTitle::getValue()}
48804fd306cSNickeau     */
48904fd306cSNickeau    public
49004fd306cSNickeau    function getTitle(): ?string
49104fd306cSNickeau    {
49204fd306cSNickeau        return $this->title->getValueFromStore();
49304fd306cSNickeau    }
49404fd306cSNickeau
49504fd306cSNickeau    /**
49604fd306cSNickeau     * If true, the page is quality monitored (a note is shown to the writer)
49704fd306cSNickeau     * @return null|bool
49804fd306cSNickeau     */
49904fd306cSNickeau    public
50004fd306cSNickeau    function getQualityMonitoringIndicator(): ?bool
50104fd306cSNickeau    {
50204fd306cSNickeau        return $this->qualityMonitoringIndicator->getValueFromStore();
50304fd306cSNickeau    }
50404fd306cSNickeau
50504fd306cSNickeau    /**
50604fd306cSNickeau     * @return string the title, or h1 if empty or the id if empty
50704fd306cSNickeau     * Shortcut to {@link PageTitle::getValueOrDefault()}
50804fd306cSNickeau     *
50904fd306cSNickeau     */
51004fd306cSNickeau    public
51104fd306cSNickeau    function getTitleOrDefault(): string
51204fd306cSNickeau    {
51304fd306cSNickeau        try {
51404fd306cSNickeau            return $this->title->getValueOrDefault();
51504fd306cSNickeau        } catch (ExceptionNotFound $e) {
51604fd306cSNickeau            LogUtility::internalError("Internal Error: The page ($this) does not have any default title");
51704fd306cSNickeau            return $this->getPathObject()->getLastNameWithoutExtension();
51804fd306cSNickeau        }
51904fd306cSNickeau
52004fd306cSNickeau    }
52104fd306cSNickeau
52204fd306cSNickeau
52304fd306cSNickeau    public function getH1OrDefault(): string
52404fd306cSNickeau    {
52504fd306cSNickeau
52604fd306cSNickeau        return $this->h1->getValueOrDefault();
52704fd306cSNickeau
52804fd306cSNickeau    }
52904fd306cSNickeau
53004fd306cSNickeau    /**
53104fd306cSNickeau     * @return string
53204fd306cSNickeau     * @throws ExceptionNotFound
53304fd306cSNickeau     */
53404fd306cSNickeau    public
53504fd306cSNickeau    function getDescription(): string
53604fd306cSNickeau    {
53704fd306cSNickeau        return $this->description->getValue();
53804fd306cSNickeau    }
53904fd306cSNickeau
54004fd306cSNickeau
54104fd306cSNickeau    /**
54204fd306cSNickeau     * @return string - the description or the dokuwiki generated description
54304fd306cSNickeau     */
54404fd306cSNickeau    public
54504fd306cSNickeau    function getDescriptionOrElseDokuWiki(): string
54604fd306cSNickeau    {
54704fd306cSNickeau        return $this->description->getValueOrDefault();
54804fd306cSNickeau    }
54904fd306cSNickeau
55004fd306cSNickeau
55104fd306cSNickeau    /**
55204fd306cSNickeau     * @return string
55304fd306cSNickeau     * The content / markup that should be parsed by the parser
55404fd306cSNickeau     */
55504fd306cSNickeau    public
55604fd306cSNickeau    function getMarkup(): string
55704fd306cSNickeau    {
55804fd306cSNickeau
55904fd306cSNickeau        try {
56004fd306cSNickeau            return FileSystems::getContent($this->getPathObject());
56104fd306cSNickeau        } catch (ExceptionNotFound $e) {
56204fd306cSNickeau            LogUtility::msg("The page ($this) was not found");
56304fd306cSNickeau            return "";
56404fd306cSNickeau        }
56504fd306cSNickeau
56604fd306cSNickeau    }
56704fd306cSNickeau
56804fd306cSNickeau
56904fd306cSNickeau    public
57004fd306cSNickeau    function isInIndex(): bool
57104fd306cSNickeau    {
57204fd306cSNickeau        $Indexer = idx_get_indexer();
57304fd306cSNickeau        $pages = $Indexer->getPages();
57404fd306cSNickeau        $return = array_search($this->getPathObject()->getWikiId(), $pages, true);
57504fd306cSNickeau        return $return !== false;
57604fd306cSNickeau    }
57704fd306cSNickeau
57804fd306cSNickeau
57904fd306cSNickeau    /**
58004fd306cSNickeau     * Save the content with the {@link ChangeLog}
58104fd306cSNickeau     * @param string $content
58204fd306cSNickeau     * @param string $summary
58304fd306cSNickeau     * @return $this
58404fd306cSNickeau     * Use {@link FileSystems::setContent()} if you don't want any log
58504fd306cSNickeau     * This function wraps {@link saveWikiText()} it implements the events system and may have side-effects
58604fd306cSNickeau     */
58704fd306cSNickeau    public
58804fd306cSNickeau    function setContentWithLog(string $content, string $summary = "Default"): MarkupPath
58904fd306cSNickeau    {
59004fd306cSNickeau        $path = $this->getPathObject();
59104fd306cSNickeau        if (!($path instanceof WikiPath)) {
59204fd306cSNickeau            throw new ExceptionRuntime("The path of this markup is not a wiki path");
59304fd306cSNickeau        }
59404fd306cSNickeau        saveWikiText($path->getWikiId(), $content, $summary);
59504fd306cSNickeau        return $this;
59604fd306cSNickeau    }
59704fd306cSNickeau
59804fd306cSNickeau    public
59904fd306cSNickeau    function addToIndex()
60004fd306cSNickeau    {
60104fd306cSNickeau        /**
60204fd306cSNickeau         * Add to index check the metadata cache
60304fd306cSNickeau         * Because we log the cache at the requested page level, we need to
60404fd306cSNickeau         * set the global ID
60504fd306cSNickeau         */
60604fd306cSNickeau        global $ID;
60704fd306cSNickeau        $keep = $ID;
60804fd306cSNickeau        global $ACT;
60904fd306cSNickeau        $keepACT = $ACT;
61004fd306cSNickeau        try {
61104fd306cSNickeau            $ACT = "show";
61204fd306cSNickeau            $ID = $this->getPathObject()->toWikiPath()->getWikiId();
61304fd306cSNickeau            idx_addPage($ID);
61404fd306cSNickeau        } finally {
61504fd306cSNickeau            $ID = $keep;
61604fd306cSNickeau            $ACT = $keepACT;
61704fd306cSNickeau        }
61804fd306cSNickeau        return $this;
61904fd306cSNickeau
62004fd306cSNickeau    }
62104fd306cSNickeau
62204fd306cSNickeau    /**
62304fd306cSNickeau     * @return mixed
62404fd306cSNickeau     */
62504fd306cSNickeau    public
62604fd306cSNickeau    function getTypeOrDefault()
62704fd306cSNickeau    {
62804fd306cSNickeau        return $this->type->getValueFromStoreOrDefault();
62904fd306cSNickeau    }
63004fd306cSNickeau
63104fd306cSNickeau
63204fd306cSNickeau    /**
63304fd306cSNickeau     * @throws ExceptionNotFound
63404fd306cSNickeau     */
63504fd306cSNickeau    public
63604fd306cSNickeau    function getFirstImage(): IFetcherLocalImage
63704fd306cSNickeau    {
63804fd306cSNickeau        try {
63904fd306cSNickeau            return IFetcherLocalImage::createImageFetchFromPath(FirstRasterImage::createForPage($this)->getValue());
64004fd306cSNickeau        } catch (ExceptionBadSyntax|ExceptionBadArgument $e) {
64104fd306cSNickeau            LogUtility::error("First Raster Image error. Error: " . $e->getMessage(), self::CANONICAL_PAGE, $e);
64204fd306cSNickeau            throw new ExceptionNotFound();
64304fd306cSNickeau        } catch (ExceptionNotExists $e) {
64404fd306cSNickeau            throw new ExceptionNotFound();
64504fd306cSNickeau        }
64604fd306cSNickeau
64704fd306cSNickeau    }
64804fd306cSNickeau
64904fd306cSNickeau    /**
65004fd306cSNickeau     * Return the media stored during parsing
65104fd306cSNickeau     *
65204fd306cSNickeau     * They are saved via the function {@link \Doku_Renderer_metadata::_recordMediaUsage()}
65304fd306cSNickeau     * called by the {@link \Doku_Renderer_metadata::internalmedia()}
65404fd306cSNickeau     *
65504fd306cSNickeau     *
65604fd306cSNickeau     * {@link \Doku_Renderer_metadata::externalmedia()} does not save them
65704fd306cSNickeau     */
65804fd306cSNickeau    public
65904fd306cSNickeau    function getMediasMetadata(): ?array
66004fd306cSNickeau    {
66104fd306cSNickeau
66204fd306cSNickeau        $store = $this->getReadStoreOrDefault();
66304fd306cSNickeau        if (!($store instanceof MetadataDokuWikiStore)) {
66404fd306cSNickeau            return null;
66504fd306cSNickeau        }
66604fd306cSNickeau        $medias = [];
66704fd306cSNickeau
66804fd306cSNickeau        $relation = $store->getCurrentFromName('relation');
66904fd306cSNickeau        if (isset($relation['media'])) {
67004fd306cSNickeau            /**
67104fd306cSNickeau             * The relation is
67204fd306cSNickeau             * $this->meta['relation']['media'][$src] = $exists;
67304fd306cSNickeau             *
67404fd306cSNickeau             */
67504fd306cSNickeau            foreach ($relation['media'] as $src => $exists) {
67604fd306cSNickeau                if ($exists) {
67704fd306cSNickeau                    $medias[] = $src;
67804fd306cSNickeau                }
67904fd306cSNickeau            }
68004fd306cSNickeau        }
68104fd306cSNickeau        return $medias;
68204fd306cSNickeau    }
68304fd306cSNickeau
68404fd306cSNickeau
68504fd306cSNickeau    /**
68604fd306cSNickeau     * Get author name
68704fd306cSNickeau     *
68804fd306cSNickeau     * @return string
68904fd306cSNickeau     */
69004fd306cSNickeau    public
69104fd306cSNickeau    function getAuthor(): ?string
69204fd306cSNickeau    {
69304fd306cSNickeau        $store = $this->getReadStoreOrDefault();
69404fd306cSNickeau        if (!($store instanceof MetadataDokuWikiStore)) {
69504fd306cSNickeau            return null;
69604fd306cSNickeau        }
69704fd306cSNickeau
69804fd306cSNickeau        return $store->getFromName('creator');
69904fd306cSNickeau    }
70004fd306cSNickeau
70104fd306cSNickeau    /**
70204fd306cSNickeau     * Get author ID
70304fd306cSNickeau     *
70404fd306cSNickeau     * @return string
70504fd306cSNickeau     */
70604fd306cSNickeau    public
70704fd306cSNickeau    function getAuthorID(): ?string
70804fd306cSNickeau    {
70904fd306cSNickeau
71004fd306cSNickeau        $store = $this->getReadStoreOrDefault();
71104fd306cSNickeau        if (!($store instanceof MetadataDokuWikiStore)) {
71204fd306cSNickeau            return null;
71304fd306cSNickeau        }
71404fd306cSNickeau
71504fd306cSNickeau        return $store->getFromName('user');
71604fd306cSNickeau
71704fd306cSNickeau    }
71804fd306cSNickeau
71904fd306cSNickeau
72004fd306cSNickeau    /**
72104fd306cSNickeau     * Get the create date of page
72204fd306cSNickeau     *
72304fd306cSNickeau     * @return DateTime
72404fd306cSNickeau     * @throws ExceptionNotFound
72504fd306cSNickeau     */
72604fd306cSNickeau    public
72704fd306cSNickeau    function getCreatedTime(): ?DateTime
72804fd306cSNickeau    {
72904fd306cSNickeau        return $this->creationTime->getValue();
73004fd306cSNickeau    }
73104fd306cSNickeau
73204fd306cSNickeau
73304fd306cSNickeau    /**
73404fd306cSNickeau     *
73504fd306cSNickeau     * @return DateTime
73604fd306cSNickeau     */
73704fd306cSNickeau    public
73804fd306cSNickeau    function getModifiedTime(): DateTime
73904fd306cSNickeau    {
74004fd306cSNickeau        return $this->modifiedTime->getValueFromStore();
74104fd306cSNickeau    }
74204fd306cSNickeau
74304fd306cSNickeau    /**
74404fd306cSNickeau     * @throws ExceptionNotFound
74504fd306cSNickeau     */
74604fd306cSNickeau    public
74704fd306cSNickeau    function getModifiedTimeOrDefault(): DateTime
74804fd306cSNickeau    {
74904fd306cSNickeau        return $this->modifiedTime->getValueFromStoreOrDefault();
75004fd306cSNickeau    }
75104fd306cSNickeau
75204fd306cSNickeau
75304fd306cSNickeau    /**
75404fd306cSNickeau     * Utility class, refresh the metadata (used only in test)
75504fd306cSNickeau     * @deprecated if possible used {@link FetcherMarkup} instead
75604fd306cSNickeau     */
75704fd306cSNickeau    public function renderMetadataAndFlush(): MarkupPath
75804fd306cSNickeau    {
75904fd306cSNickeau
76004fd306cSNickeau        if (!FileSystems::exists($this)) {
76104fd306cSNickeau            if (PluginUtility::isDevOrTest()) {
76204fd306cSNickeau                LogUtility::msg("You can't render the metadata of a markup path that does not exist ($this)");
76304fd306cSNickeau            }
76404fd306cSNickeau            return $this;
76504fd306cSNickeau        }
76604fd306cSNickeau
76704fd306cSNickeau        try {
76804fd306cSNickeau            $wikiPath = $this->getPathObject()->toWikiPath();
76904fd306cSNickeau            FetcherMarkup::confRoot()
77004fd306cSNickeau                ->setRequestedContextPath($wikiPath)
77104fd306cSNickeau                ->setRequestedExecutingPath($wikiPath)
77204fd306cSNickeau                ->setRequestedMimeToMetadata()
77304fd306cSNickeau                ->build()
77404fd306cSNickeau                ->processMetadataIfNotYetDone();
77504fd306cSNickeau        } catch (ExceptionCast|ExceptionNotExists $e) {
77604fd306cSNickeau            // not a wiki path, no meta
77704fd306cSNickeau        }
77804fd306cSNickeau
77904fd306cSNickeau
78004fd306cSNickeau        return $this;
78104fd306cSNickeau
78204fd306cSNickeau    }
78304fd306cSNickeau
78404fd306cSNickeau    /**
78504fd306cSNickeau     * @return string|null
78604fd306cSNickeau     * @deprecated for {@link Region}
78704fd306cSNickeau     */
78804fd306cSNickeau    public
78904fd306cSNickeau    function getLocaleRegion(): ?string
79004fd306cSNickeau    {
79104fd306cSNickeau        return $this->region->getValueFromStore();
79204fd306cSNickeau    }
79304fd306cSNickeau
79404fd306cSNickeau    public
79504fd306cSNickeau    function getRegionOrDefault()
79604fd306cSNickeau    {
79704fd306cSNickeau
79804fd306cSNickeau        return $this->region->getValueFromStoreOrDefault();
79904fd306cSNickeau
80004fd306cSNickeau    }
80104fd306cSNickeau
80204fd306cSNickeau    public
80304fd306cSNickeau    function getLang(): ?string
80404fd306cSNickeau    {
80504fd306cSNickeau        return $this->lang->getValueFromStore();
80604fd306cSNickeau    }
80704fd306cSNickeau
80804fd306cSNickeau    public function getLangOrDefault(): string
80904fd306cSNickeau    {
81004fd306cSNickeau        return $this->lang->getValueOrDefault();
81104fd306cSNickeau    }
81204fd306cSNickeau
81304fd306cSNickeau    /**
81404fd306cSNickeau     * The home page is an index page
81504fd306cSNickeau     * Adapted from {@link FsWikiUtility::getHomePagePath()}
81604fd306cSNickeau     * @return bool
81704fd306cSNickeau     */
81804fd306cSNickeau    public function isIndexPage(): bool
81904fd306cSNickeau    {
82004fd306cSNickeau
82104fd306cSNickeau        $startPageName = Site::getIndexPageName();
82204fd306cSNickeau        try {
82304fd306cSNickeau            if ($this->getPathObject()->getLastNameWithoutExtension() === $startPageName) {
82404fd306cSNickeau                return true;
82504fd306cSNickeau            }
82604fd306cSNickeau        } catch (ExceptionNotFound $e) {
82704fd306cSNickeau            // ok
82804fd306cSNickeau        }
82904fd306cSNickeau
83004fd306cSNickeau        try {
83104fd306cSNickeau            /**
83204fd306cSNickeau             * page named like the NS inside the NS
83304fd306cSNickeau             * ie ns:ns
83404fd306cSNickeau             */
83504fd306cSNickeau            $objectPath = $this->path;
83604fd306cSNickeau            $parentPath = $this->path->getParent();
83704fd306cSNickeau            if (!($parentPath instanceof WikiPath)) {
83804fd306cSNickeau                return false;
83904fd306cSNickeau            }
84004fd306cSNickeau            if ($parentPath->getLastNameWithoutExtension() === $objectPath->getLastNameWithoutExtension()) {
84104fd306cSNickeau                /**
84204fd306cSNickeau                 * If the start page does not exists, this is the index page
84304fd306cSNickeau                 */
84404fd306cSNickeau                $startPage = $parentPath->resolveId($startPageName);
84504fd306cSNickeau                if (!FileSystems::exists($startPage)) {
84604fd306cSNickeau                    return true;
84704fd306cSNickeau                }
84804fd306cSNickeau            }
84904fd306cSNickeau        } catch (ExceptionNotFound $e) {
85004fd306cSNickeau            // no parent, no last name, etc
85104fd306cSNickeau        }
85204fd306cSNickeau
85304fd306cSNickeau        return false;
85404fd306cSNickeau    }
85504fd306cSNickeau
85604fd306cSNickeau
85704fd306cSNickeau    /**
85804fd306cSNickeau     * @throws ExceptionNotFound
85904fd306cSNickeau     */
86004fd306cSNickeau    public
86104fd306cSNickeau    function getPublishedTime(): DateTime
86204fd306cSNickeau    {
86304fd306cSNickeau        return $this->publishedDate->getValueFromStore();
86404fd306cSNickeau    }
86504fd306cSNickeau
86604fd306cSNickeau    /**
86704fd306cSNickeau     * @return bool
86804fd306cSNickeau     * @deprecated for {@link FileSystems::exists()}
86904fd306cSNickeau     */
87004fd306cSNickeau    public function exists(): bool
87104fd306cSNickeau    {
87204fd306cSNickeau        return FileSystems::exists($this);
87304fd306cSNickeau    }
87404fd306cSNickeau
87504fd306cSNickeau    /**
87604fd306cSNickeau     * @return DateTime
87704fd306cSNickeau     * @throws ExceptionNotFound
87804fd306cSNickeau     */
87904fd306cSNickeau    public
88004fd306cSNickeau    function getPublishedElseCreationTime(): DateTime
88104fd306cSNickeau    {
88204fd306cSNickeau        return $this->publishedDate->getValueFromStoreOrDefault();
88304fd306cSNickeau    }
88404fd306cSNickeau
88504fd306cSNickeau
88604fd306cSNickeau    public
88704fd306cSNickeau    function isLatePublication(): bool
88804fd306cSNickeau    {
88904fd306cSNickeau        try {
89004fd306cSNickeau            $dateTime = $this->getPublishedElseCreationTime();
89104fd306cSNickeau        } catch (ExceptionNotFound $e) {
89204fd306cSNickeau            return false;
89304fd306cSNickeau        }
89404fd306cSNickeau        return $dateTime > new DateTime('now');
89504fd306cSNickeau    }
89604fd306cSNickeau
89704fd306cSNickeau    /**
89804fd306cSNickeau     * The unique page Url (also known as Canonical URL) used:
89904fd306cSNickeau     *   * in the link
90004fd306cSNickeau     *   * in the canonical ref
90104fd306cSNickeau     *   * in the site map
90204fd306cSNickeau     * @return Url
90304fd306cSNickeau     */
90404fd306cSNickeau    public
90504fd306cSNickeau    function getCanonicalUrl(): Url
90604fd306cSNickeau    {
90704fd306cSNickeau
90804fd306cSNickeau        /**
90904fd306cSNickeau         * Dokuwiki Methodology Taken from {@link tpl_metaheaders()}
91004fd306cSNickeau         */
91104fd306cSNickeau        if ($this->isRootHomePage()) {
912*65e00826Sgerardnico            return UrlEndpoint::createBaseUrl()->toAbsoluteUrl();
91304fd306cSNickeau        }
91404fd306cSNickeau
91504fd306cSNickeau        try {
91604fd306cSNickeau            return UrlEndpoint::createDokuUrl()
917*65e00826Sgerardnico                ->setQueryParameter(DokuwikiId::DOKUWIKI_ID_ATTRIBUTE, $this->getWikiId())
918*65e00826Sgerardnico                ->toAbsoluteUrl();
91904fd306cSNickeau        } catch (ExceptionBadArgument $e) {
92004fd306cSNickeau            LogUtility::error("This markup path ($this) can not be accessed externaly");
92104fd306cSNickeau            return UrlEndpoint::createBaseUrl();
92204fd306cSNickeau        }
92304fd306cSNickeau
92404fd306cSNickeau
92504fd306cSNickeau    }
92604fd306cSNickeau
92704fd306cSNickeau
92804fd306cSNickeau
92904fd306cSNickeau    /**
93004fd306cSNickeau     *
93104fd306cSNickeau     * @return string|null - the locale facebook way
93204fd306cSNickeau     * @throws ExceptionNotFound
93304fd306cSNickeau     * @deprecated for {@link Locale}
93404fd306cSNickeau     */
93504fd306cSNickeau    public
93604fd306cSNickeau    function getLocale($default = null): ?string
93704fd306cSNickeau    {
93804fd306cSNickeau        $value = $this->locale->getValueFromStore();
93904fd306cSNickeau        if ($value === null) {
94004fd306cSNickeau            return $default;
94104fd306cSNickeau        }
94204fd306cSNickeau        return $value;
94304fd306cSNickeau    }
94404fd306cSNickeau
94504fd306cSNickeau
94604fd306cSNickeau    /**
94704fd306cSNickeau     *
94804fd306cSNickeau     * @deprecated use a {@link FetcherMarkup::getFetchString()} instead
94904fd306cSNickeau     */
95004fd306cSNickeau    public function toXhtml(): string
95104fd306cSNickeau    {
95204fd306cSNickeau
95304fd306cSNickeau        $fetcherMarkup = $this->createHtmlFetcherWithItselfAsContextPath();
95404fd306cSNickeau        return $fetcherMarkup->getFetchString();
95504fd306cSNickeau
95604fd306cSNickeau
95704fd306cSNickeau    }
95804fd306cSNickeau
95904fd306cSNickeau
96004fd306cSNickeau    public
96104fd306cSNickeau    function getHtmlAnchorLink($logicalTag = null): string
96204fd306cSNickeau    {
96304fd306cSNickeau        $id = $this->getPathObject()->getWikiId();
96404fd306cSNickeau        try {
96504fd306cSNickeau            return LinkMarkup::createFromPageIdOrPath($id)
96604fd306cSNickeau                    ->toAttributes($logicalTag)
96704fd306cSNickeau                    ->toHtmlEnterTag("a")
96804fd306cSNickeau                . $this->getNameOrDefault()
96904fd306cSNickeau                . "</a>";
97004fd306cSNickeau        } catch (ExceptionCompile $e) {
97104fd306cSNickeau            LogUtility::msg("The markup ref returns an error for the creation of the page anchor html link ($this). Error: {$e->getMessage()}");
97204fd306cSNickeau            return "<a href=\"{$this->getCanonicalUrl()}\" data-wiki-id=\"$id\">{$this->getNameOrDefault()}</a>";
97304fd306cSNickeau        }
97404fd306cSNickeau    }
97504fd306cSNickeau
97604fd306cSNickeau
97704fd306cSNickeau    /**
97804fd306cSNickeau     * Without the `:` at the end
97904fd306cSNickeau     * @return string
98004fd306cSNickeau     * @throws ExceptionNotFound
98104fd306cSNickeau     * @deprecated / shortcut for {@link WikiPath::getParent()}
98204fd306cSNickeau     * Because a page has always a parent, the string is never null.
98304fd306cSNickeau     */
98404fd306cSNickeau    public function getNamespacePath(): string
98504fd306cSNickeau    {
98604fd306cSNickeau
98704fd306cSNickeau        return $this->getParent()->toAbsoluteId();
98804fd306cSNickeau
98904fd306cSNickeau    }
99004fd306cSNickeau
99104fd306cSNickeau
99204fd306cSNickeau    /**
99304fd306cSNickeau     * @return $this
99404fd306cSNickeau     * @deprecated use {@link MetadataDokuWikiStore::deleteAndFlush()}
99504fd306cSNickeau     */
99604fd306cSNickeau    public
99704fd306cSNickeau    function deleteMetadatasAndFlush(): MarkupPath
99804fd306cSNickeau    {
99904fd306cSNickeau        MetadataDokuWikiStore::getOrCreateFromResource($this)
100004fd306cSNickeau            ->deleteAndFlush();
100104fd306cSNickeau        return $this;
100204fd306cSNickeau    }
100304fd306cSNickeau
100404fd306cSNickeau    /**
100504fd306cSNickeau     * @throws ExceptionNotFound
100604fd306cSNickeau     */
100704fd306cSNickeau    public
100804fd306cSNickeau    function getName(): string
100904fd306cSNickeau    {
101004fd306cSNickeau
101104fd306cSNickeau        return $this->pageName->getValue();
101204fd306cSNickeau
101304fd306cSNickeau    }
101404fd306cSNickeau
101504fd306cSNickeau    public
101604fd306cSNickeau    function getNameOrDefault(): string
101704fd306cSNickeau    {
101804fd306cSNickeau
101904fd306cSNickeau        return ResourceName::createForResource($this)->getValueOrDefault();
102004fd306cSNickeau
102104fd306cSNickeau
102204fd306cSNickeau    }
102304fd306cSNickeau
102404fd306cSNickeau    /**
102504fd306cSNickeau     * @param $property
102604fd306cSNickeau     */
102704fd306cSNickeau    public
102804fd306cSNickeau    function unsetMetadata($property)
102904fd306cSNickeau    {
103004fd306cSNickeau        $meta = p_read_metadata($this->getPathObject()->getWikiId());
103104fd306cSNickeau        if (isset($meta['persistent'][$property])) {
103204fd306cSNickeau            unset($meta['persistent'][$property]);
103304fd306cSNickeau        }
103404fd306cSNickeau        p_save_metadata($this->getPathObject()->getWikiId(), $meta);
103504fd306cSNickeau
103604fd306cSNickeau    }
103704fd306cSNickeau
103804fd306cSNickeau    /**
103904fd306cSNickeau     * @return array - return the standard / generated metadata
104004fd306cSNickeau     * used to create a variable environment (context) in rendering
104104fd306cSNickeau     */
104204fd306cSNickeau    public
104304fd306cSNickeau    function getMetadataForRendering(): array
104404fd306cSNickeau    {
104504fd306cSNickeau
104604fd306cSNickeau        $metadataNames = [
104704fd306cSNickeau            PageH1::PROPERTY_NAME,
104804fd306cSNickeau            PageTitle::PROPERTY_NAME,
104904fd306cSNickeau            Lead::PROPERTY_NAME,
105004fd306cSNickeau            Canonical::PROPERTY_NAME,
105104fd306cSNickeau            PagePath::PROPERTY_NAME,
105204fd306cSNickeau            Label::PROPERTY_NAME,
105304fd306cSNickeau            PageDescription::PROPERTY_NAME,
105404fd306cSNickeau            ResourceName::PROPERTY_NAME,
105504fd306cSNickeau            PageType::PROPERTY_NAME,
105604fd306cSNickeau            Slug::PROPERTY_NAME,
105704fd306cSNickeau            PageTemplateName::PROPERTY_NAME,
105804fd306cSNickeau            DokuwikiId::DOKUWIKI_ID_ATTRIBUTE, // Dokuwiki id is deprecated for path
105904fd306cSNickeau            PageLevel::PROPERTY_NAME,
106004fd306cSNickeau            PageKeywords::PROPERTY_NAME
106104fd306cSNickeau        ];
106204fd306cSNickeau
106304fd306cSNickeau        /**
106404fd306cSNickeau         * The metadata that works only
106504fd306cSNickeau         * if the file exists
106604fd306cSNickeau         */
106704fd306cSNickeau        if (FileSystems::exists($this)) {
106804fd306cSNickeau            $metadataThatNeedsExistingFile = [
106904fd306cSNickeau                PageId::PROPERTY_NAME,
107004fd306cSNickeau                CreationDate::PROPERTY_NAME,
107104fd306cSNickeau                ModificationDate::PROPERTY_NAME,
107204fd306cSNickeau                PagePublicationDate::PROPERTY_NAME,
107304fd306cSNickeau                StartDate::PROPERTY_NAME,
107404fd306cSNickeau                EndDate::PROPERTY_NAME,
107504fd306cSNickeau            ];
107604fd306cSNickeau            $metadataNames = array_merge($metadataNames, $metadataThatNeedsExistingFile);
107704fd306cSNickeau        }
107804fd306cSNickeau
107904fd306cSNickeau
108004fd306cSNickeau        foreach ($metadataNames as $metadataName) {
108104fd306cSNickeau            try {
108204fd306cSNickeau                $metadata = Meta\Api\MetadataSystem::getForName($metadataName);
108304fd306cSNickeau            } catch (ExceptionNotFound $e) {
108404fd306cSNickeau                LogUtility::msg("The metadata ($metadataName) should be defined");
108504fd306cSNickeau                continue;
108604fd306cSNickeau            }
108704fd306cSNickeau            /**
108804fd306cSNickeau             * The Value or Default is returned
108904fd306cSNickeau             *
109004fd306cSNickeau             * Because the title/h1 should never be null
109104fd306cSNickeau             * otherwise a template link such as [[$path|$title]] will return a link without an description
109204fd306cSNickeau             * and therefore will be not visible
109304fd306cSNickeau             *
109404fd306cSNickeau             * ToStoreValue to get the string format of date/boolean in the {@link PipelineUtility}
109504fd306cSNickeau             * If we want the native value, we need to change the pipeline
109604fd306cSNickeau             */
109704fd306cSNickeau            $value = $metadata
109804fd306cSNickeau                ->setResource($this)
109904fd306cSNickeau                ->setReadStore(MetadataDokuWikiStore::class)
110004fd306cSNickeau                ->setWriteStore(TemplateStore::class)
110104fd306cSNickeau                ->buildFromReadStore()
110204fd306cSNickeau                ->toStoreValueOrDefault();
110304fd306cSNickeau            $array[$metadataName] = $value;
110404fd306cSNickeau        }
110504fd306cSNickeau
110604fd306cSNickeau        $array["url"] = $this->getCanonicalUrl()->toAbsoluteUrl()->toString();
110704fd306cSNickeau        $array["now"] = Iso8601Date::createFromNow()->toString();
110804fd306cSNickeau        return $array;
110904fd306cSNickeau
111004fd306cSNickeau    }
111104fd306cSNickeau
111204fd306cSNickeau
111304fd306cSNickeau    public
111404fd306cSNickeau    function getPublishedTimeAsString(): ?string
111504fd306cSNickeau    {
111604fd306cSNickeau        return $this->getPublishedTime() !== null ? $this->getPublishedTime()->format(Iso8601Date::getFormat()) : null;
111704fd306cSNickeau    }
111804fd306cSNickeau
111904fd306cSNickeau
112004fd306cSNickeau    /**
112104fd306cSNickeau     * @throws ExceptionNotFound
112204fd306cSNickeau     */
112304fd306cSNickeau    public
112404fd306cSNickeau    function getEndDate(): DateTime
112504fd306cSNickeau    {
112604fd306cSNickeau        return $this->endDate->getValue();
112704fd306cSNickeau    }
112804fd306cSNickeau
112904fd306cSNickeau
113004fd306cSNickeau
113104fd306cSNickeau    /**
113204fd306cSNickeau     * @throws ExceptionNotFound
113304fd306cSNickeau     */
113404fd306cSNickeau    public
113504fd306cSNickeau    function getStartDate(): DateTime
113604fd306cSNickeau    {
113704fd306cSNickeau        return $this->startDate->getValue();
113804fd306cSNickeau    }
113904fd306cSNickeau
114004fd306cSNickeau    /**
114104fd306cSNickeau     * A page id
114204fd306cSNickeau     * @return string
114304fd306cSNickeau     * @throws ExceptionNotFound - when the page does not exist
114404fd306cSNickeau     */
114504fd306cSNickeau    public
114604fd306cSNickeau    function getPageId(): string
114704fd306cSNickeau    {
114804fd306cSNickeau        return PageId::createForPage($this)->getValue();
114904fd306cSNickeau    }
115004fd306cSNickeau
115104fd306cSNickeau
115204fd306cSNickeau    /**
115304fd306cSNickeau     * @throws ExceptionNotExists
115404fd306cSNickeau     */
115504fd306cSNickeau    public
115604fd306cSNickeau    function fetchAnalyticsDocument(): FetcherMarkup
115704fd306cSNickeau    {
115804fd306cSNickeau        return renderer_plugin_combo_analytics::createAnalyticsFetcherForPageFragment($this);
115904fd306cSNickeau    }
116004fd306cSNickeau
116104fd306cSNickeau    /**
116204fd306cSNickeau     * @throws ExceptionCompile
116304fd306cSNickeau     * @throws ExceptionNotExists
116404fd306cSNickeau     */
116504fd306cSNickeau    public
116604fd306cSNickeau    function fetchAnalyticsPath(): Path
116704fd306cSNickeau    {
116804fd306cSNickeau        $fetcher = renderer_plugin_combo_analytics::createAnalyticsFetcherForPageFragment($this);
116904fd306cSNickeau        return $fetcher->processIfNeededAndGetFetchPath();
117004fd306cSNickeau
117104fd306cSNickeau    }
117204fd306cSNickeau
117304fd306cSNickeau    /**
117404fd306cSNickeau     */
117504fd306cSNickeau    public
117604fd306cSNickeau    function getDatabasePage(): DatabasePageRow
117704fd306cSNickeau    {
117804fd306cSNickeau
117904fd306cSNickeau        return DatabasePageRow::getFromPageObject($this);
118004fd306cSNickeau
118104fd306cSNickeau    }
118204fd306cSNickeau
118304fd306cSNickeau    /**
118404fd306cSNickeau     * @throws ExceptionSqliteNotAvailable
118504fd306cSNickeau     */
118604fd306cSNickeau    public
118704fd306cSNickeau    function getOrCreateDatabasePage(): DatabasePageRow
118804fd306cSNickeau    {
118904fd306cSNickeau
119004fd306cSNickeau        return DatabasePageRow::getOrCreateFromPageObject($this);
119104fd306cSNickeau
119204fd306cSNickeau    }
119304fd306cSNickeau
119404fd306cSNickeau    public
119504fd306cSNickeau    function canBeUpdatedByCurrentUser(): bool
119604fd306cSNickeau    {
119704fd306cSNickeau        return Identity::isWriter($this->getWikiId());
119804fd306cSNickeau    }
119904fd306cSNickeau
120004fd306cSNickeau
120104fd306cSNickeau    public
120204fd306cSNickeau    function isRootHomePage(): bool
120304fd306cSNickeau    {
120404fd306cSNickeau        global $conf;
120504fd306cSNickeau        $startPageName = $conf['start'];
120604fd306cSNickeau        return $this->getPathObject()->toAbsoluteId() === ":$startPageName";
120704fd306cSNickeau
120804fd306cSNickeau    }
120904fd306cSNickeau
121004fd306cSNickeau
121104fd306cSNickeau    /**
121204fd306cSNickeau     * @throws ExceptionNotFound
121304fd306cSNickeau     */
121404fd306cSNickeau    public
121504fd306cSNickeau    function getPageType(): string
121604fd306cSNickeau    {
121704fd306cSNickeau        return $this->type->getValueFromStore();
121804fd306cSNickeau    }
121904fd306cSNickeau
122004fd306cSNickeau    /**
122104fd306cSNickeau     * @throws ExceptionNotFound
122204fd306cSNickeau     * @deprecated
122304fd306cSNickeau     */
122404fd306cSNickeau    public
122504fd306cSNickeau    function getCanonical(): WikiPath
122604fd306cSNickeau    {
122704fd306cSNickeau        return $this->canonical->getValue();
122804fd306cSNickeau    }
122904fd306cSNickeau
123004fd306cSNickeau    /**
123104fd306cSNickeau     * Create a canonical from the last page path part.
123204fd306cSNickeau     *
123304fd306cSNickeau     * @return string|null
123404fd306cSNickeau     * @throws ExceptionNotFound
123504fd306cSNickeau     */
123604fd306cSNickeau    public
123704fd306cSNickeau    function getDefaultCanonical(): ?string
123804fd306cSNickeau    {
123904fd306cSNickeau        return $this->canonical->getDefaultValue();
124004fd306cSNickeau    }
124104fd306cSNickeau
124204fd306cSNickeau    /**
124304fd306cSNickeau     * @throws ExceptionNotFound
124404fd306cSNickeau     */
124504fd306cSNickeau    public
124604fd306cSNickeau    function getLayout()
124704fd306cSNickeau    {
124804fd306cSNickeau        return $this->layout->getValueFromStore();
124904fd306cSNickeau    }
125004fd306cSNickeau
125104fd306cSNickeau    /**
125204fd306cSNickeau     * @throws ExceptionNotFound
125304fd306cSNickeau     */
125404fd306cSNickeau    public
125504fd306cSNickeau    function getDefaultPageName(): string
125604fd306cSNickeau    {
125704fd306cSNickeau        return $this->pageName->getDefaultValue();
125804fd306cSNickeau    }
125904fd306cSNickeau
126004fd306cSNickeau    public
126104fd306cSNickeau    function getDefaultTitle(): string
126204fd306cSNickeau    {
126304fd306cSNickeau        return $this->title->getDefaultValue();
126404fd306cSNickeau    }
126504fd306cSNickeau
126604fd306cSNickeau    /**
126704fd306cSNickeau     * @throws ExceptionNotFound
126804fd306cSNickeau     */
126904fd306cSNickeau    public
127004fd306cSNickeau    function getDefaultH1()
127104fd306cSNickeau    {
127204fd306cSNickeau        return $this->h1->getValueOrDefault();
127304fd306cSNickeau    }
127404fd306cSNickeau
127504fd306cSNickeau    public
127604fd306cSNickeau    function getDefaultType(): string
127704fd306cSNickeau    {
127804fd306cSNickeau        return $this->type->getDefaultValue();
127904fd306cSNickeau    }
128004fd306cSNickeau
128104fd306cSNickeau    public
128204fd306cSNickeau    function getDefaultLayout(): string
128304fd306cSNickeau    {
128404fd306cSNickeau        return $this->layout->getDefaultValue();
128504fd306cSNickeau    }
128604fd306cSNickeau
128704fd306cSNickeau
128804fd306cSNickeau    /**
128904fd306cSNickeau     *
129004fd306cSNickeau     * @throws ExceptionCompile
129104fd306cSNickeau     */
129204fd306cSNickeau    public
129304fd306cSNickeau    function setLowQualityIndicatorCalculation($bool): MarkupPath
129404fd306cSNickeau    {
129504fd306cSNickeau        return $this->setQualityIndicatorAndDeleteCacheIfNeeded($this->lowQualityIndicatorCalculated, $bool);
129604fd306cSNickeau    }
129704fd306cSNickeau
129804fd306cSNickeau
129904fd306cSNickeau    /**
130004fd306cSNickeau     * Change the quality indicator
130104fd306cSNickeau     * and if the quality level has become low
130204fd306cSNickeau     * and that the protection is on, delete the cache
130304fd306cSNickeau     * @param MetadataBoolean $lowQualityAttributeName
130404fd306cSNickeau     * @param bool $value
130504fd306cSNickeau     * @return MarkupPath
130604fd306cSNickeau     * @throws ExceptionBadArgument - if the value cannot be persisted
130704fd306cSNickeau     */
130804fd306cSNickeau    private
130904fd306cSNickeau    function setQualityIndicatorAndDeleteCacheIfNeeded(MetadataBoolean $lowQualityAttributeName, bool $value): MarkupPath
131004fd306cSNickeau    {
131104fd306cSNickeau        try {
131204fd306cSNickeau            $actualValue = $lowQualityAttributeName->getValue();
131304fd306cSNickeau        } catch (ExceptionNotFound $e) {
131404fd306cSNickeau            $actualValue = null;
131504fd306cSNickeau        }
131604fd306cSNickeau        if ($value !== $actualValue) {
131704fd306cSNickeau            $lowQualityAttributeName
131804fd306cSNickeau                ->setValue($value)
131904fd306cSNickeau                ->persist();
132004fd306cSNickeau        }
132104fd306cSNickeau        return $this;
132204fd306cSNickeau    }
132304fd306cSNickeau
132404fd306cSNickeau
132504fd306cSNickeau    /**
132604fd306cSNickeau     * @throws ExceptionNotFound
132704fd306cSNickeau     */
132804fd306cSNickeau    public
132904fd306cSNickeau    function getLowQualityIndicatorCalculated()
133004fd306cSNickeau    {
133104fd306cSNickeau
133204fd306cSNickeau        return $this->lowQualityIndicatorCalculated->getValueOrDefault();
133304fd306cSNickeau
133404fd306cSNickeau    }
133504fd306cSNickeau
133604fd306cSNickeau    /**
133704fd306cSNickeau     * @return PageImage[]
133804fd306cSNickeau     * @deprecated
133904fd306cSNickeau     */
134004fd306cSNickeau    public
134104fd306cSNickeau    function getPageMetadataImages(): array
134204fd306cSNickeau    {
134304fd306cSNickeau        return $this->pageImages->getValueAsPageImages();
134404fd306cSNickeau    }
134504fd306cSNickeau
134604fd306cSNickeau
134704fd306cSNickeau    /**
134804fd306cSNickeau     * @param array|string $jsonLd
134904fd306cSNickeau     * @return $this
135004fd306cSNickeau     * @throws ExceptionCompile
135104fd306cSNickeau     * @deprecated for {@link LdJson}
135204fd306cSNickeau     */
135304fd306cSNickeau    public
135404fd306cSNickeau    function setJsonLd($jsonLd): MarkupPath
135504fd306cSNickeau    {
135604fd306cSNickeau        $this->ldJson
135704fd306cSNickeau            ->setValue($jsonLd)
135804fd306cSNickeau            ->sendToWriteStore();
135904fd306cSNickeau        return $this;
136004fd306cSNickeau    }
136104fd306cSNickeau
136204fd306cSNickeau    /**
136304fd306cSNickeau     * @throws ExceptionCompile
136404fd306cSNickeau     */
136504fd306cSNickeau    public
136604fd306cSNickeau    function setPageType(string $value): MarkupPath
136704fd306cSNickeau    {
136804fd306cSNickeau        $this->type
136904fd306cSNickeau            ->setValue($value)
137004fd306cSNickeau            ->sendToWriteStore();
137104fd306cSNickeau        return $this;
137204fd306cSNickeau    }
137304fd306cSNickeau
137404fd306cSNickeau
137504fd306cSNickeau    /**
137604fd306cSNickeau     * @param $aliasPath
137704fd306cSNickeau     * @param string $aliasType
137804fd306cSNickeau     * @return Alias
137904fd306cSNickeau     * @deprecated for {@link Aliases}
138004fd306cSNickeau     */
138104fd306cSNickeau    public
138204fd306cSNickeau    function addAndGetAlias($aliasPath, string $aliasType = AliasType::REDIRECT): Alias
138304fd306cSNickeau    {
138404fd306cSNickeau
138504fd306cSNickeau        return $this->aliases->addAndGetAlias($aliasPath, $aliasType);
138604fd306cSNickeau
138704fd306cSNickeau    }
138804fd306cSNickeau
138904fd306cSNickeau
139004fd306cSNickeau    /**
139104fd306cSNickeau     * @return Alias[]
139204fd306cSNickeau     * @throws ExceptionNotFound
139304fd306cSNickeau     */
139404fd306cSNickeau    public
139504fd306cSNickeau    function getAliases(): array
139604fd306cSNickeau    {
139704fd306cSNickeau        return $this->aliases->getValueAsAlias();
139804fd306cSNickeau    }
139904fd306cSNickeau
140004fd306cSNickeau    /**
140104fd306cSNickeau     * @return string
140204fd306cSNickeau     */
140304fd306cSNickeau    public
140404fd306cSNickeau    function getSlugOrDefault(): string
140504fd306cSNickeau    {
140604fd306cSNickeau        try {
140704fd306cSNickeau            return $this->getSlug();
140804fd306cSNickeau        } catch (ExceptionNotFound $e) {
140904fd306cSNickeau            return $this->getDefaultSlug();
141004fd306cSNickeau        }
141104fd306cSNickeau
141204fd306cSNickeau    }
141304fd306cSNickeau
141404fd306cSNickeau    /**
141504fd306cSNickeau     *
141604fd306cSNickeau     * @return string
141704fd306cSNickeau     *
141804fd306cSNickeau     */
141904fd306cSNickeau    public
142004fd306cSNickeau    function getDefaultSlug(): string
142104fd306cSNickeau    {
142204fd306cSNickeau        return $this->slug->getDefaultValue();
142304fd306cSNickeau    }
142404fd306cSNickeau
142504fd306cSNickeau    /**
142604fd306cSNickeau     * The parent page is the parent in the page tree directory
142704fd306cSNickeau     *
142804fd306cSNickeau     * If the page is at the root, the parent page is the root home
142904fd306cSNickeau     * Only the root home does not have any parent page and return null.
143004fd306cSNickeau     *
143104fd306cSNickeau     * @return MarkupPath
143204fd306cSNickeau     * @throws ExceptionNotFound
143304fd306cSNickeau     */
143404fd306cSNickeau    public function getParent(): MarkupPath
143504fd306cSNickeau    {
143604fd306cSNickeau
143704fd306cSNickeau        $names = $this->getNames();
143804fd306cSNickeau        if (sizeof($names) == 0) {
143904fd306cSNickeau            throw new ExceptionNotFound("No parent page");
144004fd306cSNickeau        }
144104fd306cSNickeau        $slice = 1;
144204fd306cSNickeau        if ($this->isIndexPage()) {
144304fd306cSNickeau            /**
144404fd306cSNickeau             * The parent of a home page
144504fd306cSNickeau             * is in the parent directory
144604fd306cSNickeau             */
144704fd306cSNickeau            $slice = 2;
144804fd306cSNickeau        }
144904fd306cSNickeau        /**
145004fd306cSNickeau         * Delete the last or the two last parts
145104fd306cSNickeau         */
145204fd306cSNickeau        if (sizeof($names) < $slice) {
145304fd306cSNickeau            throw new ExceptionNotFound("No parent page");
145404fd306cSNickeau        }
145504fd306cSNickeau        /**
145604fd306cSNickeau         * Get the actual directory for a page
145704fd306cSNickeau         * or the parent directory for a home page
145804fd306cSNickeau         */
145904fd306cSNickeau        $parentNames = array_slice($names, 0, sizeof($names) - $slice);
146004fd306cSNickeau        /**
146104fd306cSNickeau         * Create the parent namespace id
146204fd306cSNickeau         */
146304fd306cSNickeau        $parentNamespaceId = implode(WikiPath::NAMESPACE_SEPARATOR_DOUBLE_POINT, $parentNames) . WikiPath::NAMESPACE_SEPARATOR_DOUBLE_POINT;
146404fd306cSNickeau        try {
146504fd306cSNickeau            return self::getIndexPageFromNamespace($parentNamespaceId);
146604fd306cSNickeau        } catch (ExceptionBadSyntax $e) {
146704fd306cSNickeau            $message = "Error on getParentPage, null returned - Error: {$e->getMessage()}";
146804fd306cSNickeau            LogUtility::internalError($message);
146904fd306cSNickeau            throw new ExceptionNotFound($message);
147004fd306cSNickeau        }
147104fd306cSNickeau
147204fd306cSNickeau    }
147304fd306cSNickeau
147404fd306cSNickeau    /**
147504fd306cSNickeau     * @throws ExceptionCompile
147604fd306cSNickeau     */
147704fd306cSNickeau    public
147804fd306cSNickeau    function setDescription($description): MarkupPath
147904fd306cSNickeau    {
148004fd306cSNickeau
148104fd306cSNickeau        $this->description
148204fd306cSNickeau            ->setValue($description)
148304fd306cSNickeau            ->sendToWriteStore();
148404fd306cSNickeau        return $this;
148504fd306cSNickeau    }
148604fd306cSNickeau
148704fd306cSNickeau    /**
148804fd306cSNickeau     * @throws ExceptionCompile
148904fd306cSNickeau     * @deprecated uses {@link EndDate} instead
149004fd306cSNickeau     */
149104fd306cSNickeau    public
149204fd306cSNickeau    function setEndDate($value): MarkupPath
149304fd306cSNickeau    {
149404fd306cSNickeau        $this->endDate
149504fd306cSNickeau            ->setFromStoreValue($value)
149604fd306cSNickeau            ->sendToWriteStore();
149704fd306cSNickeau        return $this;
149804fd306cSNickeau    }
149904fd306cSNickeau
150004fd306cSNickeau    /**
150104fd306cSNickeau     * @throws ExceptionCompile
150204fd306cSNickeau     * @deprecated uses {@link StartDate} instead
150304fd306cSNickeau     */
150404fd306cSNickeau    public
150504fd306cSNickeau    function setStartDate($value): MarkupPath
150604fd306cSNickeau    {
150704fd306cSNickeau        $this->startDate
150804fd306cSNickeau            ->setFromStoreValue($value)
150904fd306cSNickeau            ->sendToWriteStore();
151004fd306cSNickeau        return $this;
151104fd306cSNickeau    }
151204fd306cSNickeau
151304fd306cSNickeau    /**
151404fd306cSNickeau     * @throws ExceptionCompile
151504fd306cSNickeau     */
151604fd306cSNickeau    public
151704fd306cSNickeau    function setPublishedDate($value): MarkupPath
151804fd306cSNickeau    {
151904fd306cSNickeau        $this->publishedDate
152004fd306cSNickeau            ->setFromStoreValue($value)
152104fd306cSNickeau            ->sendToWriteStore();
152204fd306cSNickeau        return $this;
152304fd306cSNickeau    }
152404fd306cSNickeau
152504fd306cSNickeau    /**
152604fd306cSNickeau     * Utility to {@link ResourceName::setValue()}
152704fd306cSNickeau     * Used mostly to create page in test
152804fd306cSNickeau     * @throws ExceptionCompile
152904fd306cSNickeau     * @deprecated use not persist
153004fd306cSNickeau     */
153104fd306cSNickeau    public
153204fd306cSNickeau    function setPageName($value): MarkupPath
153304fd306cSNickeau    {
153404fd306cSNickeau        $this->pageName
153504fd306cSNickeau            ->setValue($value)
153604fd306cSNickeau            ->sendToWriteStore();
153704fd306cSNickeau        return $this;
153804fd306cSNickeau    }
153904fd306cSNickeau
154004fd306cSNickeau
154104fd306cSNickeau    /**
154204fd306cSNickeau     * @throws ExceptionCompile
154304fd306cSNickeau     */
154404fd306cSNickeau    public
154504fd306cSNickeau    function setTitle($value): MarkupPath
154604fd306cSNickeau    {
154704fd306cSNickeau        $this->title
154804fd306cSNickeau            ->setValue($value)
154904fd306cSNickeau            ->sendToWriteStore();
155004fd306cSNickeau        return $this;
155104fd306cSNickeau    }
155204fd306cSNickeau
155304fd306cSNickeau    /**
155404fd306cSNickeau     * @throws ExceptionCompile
155504fd306cSNickeau     */
155604fd306cSNickeau    public
155704fd306cSNickeau    function setH1($value): MarkupPath
155804fd306cSNickeau    {
155904fd306cSNickeau        $this->h1
156004fd306cSNickeau            ->setValue($value)
156104fd306cSNickeau            ->sendToWriteStore();
156204fd306cSNickeau        return $this;
156304fd306cSNickeau    }
156404fd306cSNickeau
156504fd306cSNickeau    /**
156604fd306cSNickeau     * @throws Exception
156704fd306cSNickeau     */
156804fd306cSNickeau    public
156904fd306cSNickeau    function setRegion($value): MarkupPath
157004fd306cSNickeau    {
157104fd306cSNickeau        $this->region
157204fd306cSNickeau            ->setFromStoreValue($value)
157304fd306cSNickeau            ->sendToWriteStore();
157404fd306cSNickeau        return $this;
157504fd306cSNickeau    }
157604fd306cSNickeau
157704fd306cSNickeau    /**
157804fd306cSNickeau     * @throws ExceptionCompile
157904fd306cSNickeau     */
158004fd306cSNickeau    public
158104fd306cSNickeau    function setLang($value): MarkupPath
158204fd306cSNickeau    {
158304fd306cSNickeau
158404fd306cSNickeau        $this->lang
158504fd306cSNickeau            ->setFromStoreValue($value)
158604fd306cSNickeau            ->sendToWriteStore();
158704fd306cSNickeau        return $this;
158804fd306cSNickeau    }
158904fd306cSNickeau
159004fd306cSNickeau    /**
159104fd306cSNickeau     * @throws ExceptionCompile
159204fd306cSNickeau     */
159304fd306cSNickeau    public
159404fd306cSNickeau    function setLayout($value): MarkupPath
159504fd306cSNickeau    {
159604fd306cSNickeau        $this->layout
159704fd306cSNickeau            ->setValue($value)
159804fd306cSNickeau            ->sendToWriteStore();
159904fd306cSNickeau        return $this;
160004fd306cSNickeau    }
160104fd306cSNickeau
160204fd306cSNickeau
160304fd306cSNickeau    /**
160404fd306cSNickeau     *
160504fd306cSNickeau     * We manage the properties by setter and getter
160604fd306cSNickeau     *
160704fd306cSNickeau     * Why ?
160804fd306cSNickeau     *   * Because we can capture the updates
160904fd306cSNickeau     *   * Because setter are the entry point to good quality data
161004fd306cSNickeau     *   * Because dokuwiki may cache the metadata (see below)
161104fd306cSNickeau     *
161204fd306cSNickeau     * Note all properties have been migrated
161304fd306cSNickeau     * but they should be initialized below
161404fd306cSNickeau     *
161504fd306cSNickeau     * Dokuwiki cache: the data may be cached without our consent
161604fd306cSNickeau     * The method {@link p_get_metadata()} does it with this logic
161704fd306cSNickeau     * ```
161804fd306cSNickeau     * $cache = ($ID == $id);
161904fd306cSNickeau     * $meta = p_read_metadata($id, $cache);
162004fd306cSNickeau     * ```
162104fd306cSNickeau     */
162204fd306cSNickeau    private
162304fd306cSNickeau    function buildPropertiesFromFileSystem()
162404fd306cSNickeau    {
162504fd306cSNickeau
162604fd306cSNickeau        /**
162704fd306cSNickeau         * New meta system
162804fd306cSNickeau         * Even if it does not exist, the metadata object should be instantiated
162904fd306cSNickeau         * otherwise, there is a null exception
163004fd306cSNickeau         */
163104fd306cSNickeau        $this->cacheExpirationDate = CacheExpirationDate::createForPage($this);
163204fd306cSNickeau        $this->aliases = Aliases::createForPage($this);
163304fd306cSNickeau        $this->pageImages = PageImages::createForPage($this);
163404fd306cSNickeau        $this->pageName = ResourceName::createForResource($this);
163504fd306cSNickeau        $this->cacheExpirationFrequency = CacheExpirationFrequency::createForPage($this);
163604fd306cSNickeau        $this->ldJson = LdJson::createForPage($this);
163704fd306cSNickeau        $this->canonical = Canonical::createForPage($this);
163804fd306cSNickeau        $this->description = PageDescription::createForPage($this);
163904fd306cSNickeau        $this->h1 = PageH1::createForPage($this);
164004fd306cSNickeau        $this->type = PageType::createForPage($this);
164104fd306cSNickeau        $this->creationTime = CreationDate::createForPage($this);
164204fd306cSNickeau        $this->title = PageTitle::createForMarkup($this);
164304fd306cSNickeau        $this->keywords = PageKeywords::createForPage($this);
164404fd306cSNickeau        $this->publishedDate = PagePublicationDate::createFromPage($this);
164504fd306cSNickeau        $this->startDate = StartDate::createFromPage($this);
164604fd306cSNickeau        $this->endDate = EndDate::createFromPage($this);
164704fd306cSNickeau        $this->locale = Locale::createForPage($this);
164804fd306cSNickeau        $this->lang = Lang::createForMarkup($this);
164904fd306cSNickeau        $this->region = Region::createForPage($this);
165004fd306cSNickeau        $this->slug = \ComboStrap\Slug::createForPage($this);
165104fd306cSNickeau        $this->canBeOfLowQuality = LowQualityPageOverwrite::createForPage($this);
165204fd306cSNickeau        $this->lowQualityIndicatorCalculated = LowQualityCalculatedIndicator::createFromPage($this);
165304fd306cSNickeau        $this->qualityMonitoringIndicator = QualityDynamicMonitoringOverwrite::createFromPage($this);
165404fd306cSNickeau        $this->modifiedTime = ModificationDate::createForPage($this);
165504fd306cSNickeau        $this->pageUrlPath = PageUrlPath::createForPage($this);
165604fd306cSNickeau        $this->layout = PageTemplateName::createFromPage($this);
165704fd306cSNickeau
165804fd306cSNickeau    }
165904fd306cSNickeau
166004fd306cSNickeau
166104fd306cSNickeau    function getPageIdAbbr()
166204fd306cSNickeau    {
166304fd306cSNickeau
166404fd306cSNickeau        if ($this->getPageId() === null) return null;
166504fd306cSNickeau        return PageId::getAbbreviated($this->getPageId());
166604fd306cSNickeau
166704fd306cSNickeau    }
166804fd306cSNickeau
166904fd306cSNickeau    public
167004fd306cSNickeau    function setDatabasePage(DatabasePageRow $databasePage): MarkupPath
167104fd306cSNickeau    {
167204fd306cSNickeau        $this->databasePage = $databasePage;
167304fd306cSNickeau        return $this;
167404fd306cSNickeau    }
167504fd306cSNickeau
167604fd306cSNickeau
167704fd306cSNickeau    /**
167804fd306cSNickeau     * @return string|null
167904fd306cSNickeau     *
168004fd306cSNickeau     * @throws ExceptionNotFound
168104fd306cSNickeau     */
168204fd306cSNickeau    public
168304fd306cSNickeau    function getSlug(): string
168404fd306cSNickeau    {
168504fd306cSNickeau        return $this->slug->getValue();
168604fd306cSNickeau    }
168704fd306cSNickeau
168804fd306cSNickeau
168904fd306cSNickeau    /**
169004fd306cSNickeau     * @throws ExceptionCompile
169104fd306cSNickeau     */
169204fd306cSNickeau    public
169304fd306cSNickeau    function setSlug($slug): MarkupPath
169404fd306cSNickeau    {
169504fd306cSNickeau        $this->slug
169604fd306cSNickeau            ->setFromStoreValue($slug)
169704fd306cSNickeau            ->sendToWriteStore();
169804fd306cSNickeau        return $this;
169904fd306cSNickeau    }
170004fd306cSNickeau
170104fd306cSNickeau
170204fd306cSNickeau    /**
170304fd306cSNickeau     * @return string - the id in the Url
170404fd306cSNickeau     */
170504fd306cSNickeau    public function getUrlId(): string
170604fd306cSNickeau    {
170704fd306cSNickeau        return $this->pageUrlPath->getValueOrDefaultAsWikiId();
170804fd306cSNickeau    }
170904fd306cSNickeau
171004fd306cSNickeau
171104fd306cSNickeau    /**
171204fd306cSNickeau     * @throws ExceptionCompile
171304fd306cSNickeau     */
171404fd306cSNickeau    public
171504fd306cSNickeau    function setQualityMonitoringIndicator($boolean): MarkupPath
171604fd306cSNickeau    {
171704fd306cSNickeau        $this->qualityMonitoringIndicator
171804fd306cSNickeau            ->setFromStoreValue($boolean)
171904fd306cSNickeau            ->sendToWriteStore();
172004fd306cSNickeau        return $this;
172104fd306cSNickeau    }
172204fd306cSNickeau
172304fd306cSNickeau    /**
172404fd306cSNickeau     *
172504fd306cSNickeau     * @param $aliasPath - third information - the alias used to build this page
172604fd306cSNickeau     */
172704fd306cSNickeau    public
172804fd306cSNickeau    function setBuildAliasPath($aliasPath)
172904fd306cSNickeau    {
173004fd306cSNickeau        $this->buildAliasPath = $aliasPath;
173104fd306cSNickeau    }
173204fd306cSNickeau
173304fd306cSNickeau    public
173404fd306cSNickeau    function getBuildAlias(): ?Alias
173504fd306cSNickeau    {
173604fd306cSNickeau        if ($this->buildAliasPath === null) return null;
173704fd306cSNickeau        try {
173804fd306cSNickeau            $aliases = $this->getAliases();
173904fd306cSNickeau        } catch (ExceptionNotFound $e) {
174004fd306cSNickeau            // should not
174104fd306cSNickeau            return null;
174204fd306cSNickeau        }
174304fd306cSNickeau        foreach ($aliases as $alias) {
174404fd306cSNickeau            if ($alias->getPath() === $this->buildAliasPath) {
174504fd306cSNickeau                return $alias;
174604fd306cSNickeau            }
174704fd306cSNickeau        }
174804fd306cSNickeau        return null;
174904fd306cSNickeau    }
175004fd306cSNickeau
175104fd306cSNickeau    public
175204fd306cSNickeau    function isDynamicQualityMonitored(): bool
175304fd306cSNickeau    {
175404fd306cSNickeau        if ($this->getQualityMonitoringIndicator() !== null) {
175504fd306cSNickeau            return $this->getQualityMonitoringIndicator();
175604fd306cSNickeau        }
175704fd306cSNickeau        return $this->getDefaultQualityMonitoring();
175804fd306cSNickeau    }
175904fd306cSNickeau
176004fd306cSNickeau    public
176104fd306cSNickeau    function getDefaultQualityMonitoring(): bool
176204fd306cSNickeau    {
176304fd306cSNickeau        if (SiteConfig::getConfValue(QualityMessageHandler::CONF_DISABLE_QUALITY_MONITORING) === 1) {
176404fd306cSNickeau            return false;
176504fd306cSNickeau        } else {
176604fd306cSNickeau            return true;
176704fd306cSNickeau        }
176804fd306cSNickeau    }
176904fd306cSNickeau
177004fd306cSNickeau    /**
177104fd306cSNickeau     * @param MetadataStore|string $store
177204fd306cSNickeau     * @return $this
177304fd306cSNickeau     */
177404fd306cSNickeau    public
177504fd306cSNickeau    function setReadStore($store): MarkupPath
177604fd306cSNickeau    {
177704fd306cSNickeau        $this->readStore = $store;
177804fd306cSNickeau        return $this;
177904fd306cSNickeau    }
178004fd306cSNickeau
178104fd306cSNickeau
178204fd306cSNickeau    /**
178304fd306cSNickeau     * @param array $usages
178404fd306cSNickeau     * @return IFetcherLocalImage[]
178504fd306cSNickeau     */
178604fd306cSNickeau    public
178704fd306cSNickeau    function getImagesForTheFollowingUsages(array $usages): array
178804fd306cSNickeau    {
178904fd306cSNickeau        $usages = array_merge($usages, [PageImageUsage::ALL]);
179004fd306cSNickeau        $images = [];
179104fd306cSNickeau        foreach ($this->getPageMetadataImages() as $pageImage) {
179204fd306cSNickeau            foreach ($usages as $usage) {
179304fd306cSNickeau                if (in_array($usage, $pageImage->getUsages())) {
179404fd306cSNickeau                    $path = $pageImage->getImagePath();
179504fd306cSNickeau                    try {
179604fd306cSNickeau                        $images[] = IFetcherLocalImage::createImageFetchFromPath($path);
179704fd306cSNickeau                    } catch (ExceptionBadArgument $e) {
179804fd306cSNickeau                        LogUtility::error(`The page image $path of the page $this is not an image`);
179904fd306cSNickeau                    } catch (ExceptionBadSyntax $e) {
180004fd306cSNickeau                        LogUtility::error(`The page image $path has a bad syntax`);
180104fd306cSNickeau                    } catch (ExceptionNotExists $e) {
180204fd306cSNickeau                        LogUtility::error(`The page image $path does not exists`);
180304fd306cSNickeau                    }
180404fd306cSNickeau                    continue 2;
180504fd306cSNickeau                }
180604fd306cSNickeau            }
180704fd306cSNickeau        }
180804fd306cSNickeau        return $images;
180904fd306cSNickeau
181004fd306cSNickeau    }
181104fd306cSNickeau
181204fd306cSNickeau
181304fd306cSNickeau    /**
181404fd306cSNickeau     * @throws ExceptionNotFound
181504fd306cSNickeau     */
181604fd306cSNickeau    public
181704fd306cSNickeau    function getKeywords(): array
181804fd306cSNickeau    {
181904fd306cSNickeau        return $this->keywords->getValue();
182004fd306cSNickeau    }
182104fd306cSNickeau
182204fd306cSNickeau    /**
182304fd306cSNickeau     * @throws ExceptionNotFound
182404fd306cSNickeau     */
182504fd306cSNickeau    public function getKeywordsOrDefault(): array
182604fd306cSNickeau    {
182704fd306cSNickeau        return $this->keywords->getValueOrDefaults();
182804fd306cSNickeau    }
182904fd306cSNickeau
183004fd306cSNickeau
183104fd306cSNickeau    /**
183204fd306cSNickeau     * @throws ExceptionCompile
183304fd306cSNickeau     */
183404fd306cSNickeau    public
183504fd306cSNickeau    function setKeywords($value): MarkupPath
183604fd306cSNickeau    {
183704fd306cSNickeau        $this->keywords
183804fd306cSNickeau            ->setFromStoreValue($value)
183904fd306cSNickeau            ->sendToWriteStore();
184004fd306cSNickeau        return $this;
184104fd306cSNickeau    }
184204fd306cSNickeau
184304fd306cSNickeau    /**
184404fd306cSNickeau     * @return DateTime|null
184504fd306cSNickeau     * @throws ExceptionNotFound
184604fd306cSNickeau     * @deprecated for {@link CacheExpirationDate}
184704fd306cSNickeau     */
184804fd306cSNickeau    public
184904fd306cSNickeau    function getCacheExpirationDate(): ?DateTime
185004fd306cSNickeau    {
185104fd306cSNickeau        return $this->cacheExpirationDate->getValue();
185204fd306cSNickeau    }
185304fd306cSNickeau
185404fd306cSNickeau    /**
185504fd306cSNickeau     * @return DateTime|null
185604fd306cSNickeau     * @throws ExceptionNotFound
185704fd306cSNickeau     * @deprecated for {@link CacheExpirationDate}
185804fd306cSNickeau     */
185904fd306cSNickeau    public
186004fd306cSNickeau    function getDefaultCacheExpirationDate(): ?DateTime
186104fd306cSNickeau    {
186204fd306cSNickeau        return $this->cacheExpirationDate->getDefaultValue();
186304fd306cSNickeau    }
186404fd306cSNickeau
186504fd306cSNickeau    /**
186604fd306cSNickeau     * @return string|null
186704fd306cSNickeau     * @throws ExceptionNotFound
186804fd306cSNickeau     * @deprecated for {@link CacheExpirationFrequency}
186904fd306cSNickeau     */
187004fd306cSNickeau    public
187104fd306cSNickeau    function getCacheExpirationFrequency(): string
187204fd306cSNickeau    {
187304fd306cSNickeau        return $this->cacheExpirationFrequency->getValue();
187404fd306cSNickeau    }
187504fd306cSNickeau
187604fd306cSNickeau
187704fd306cSNickeau    /**
187804fd306cSNickeau     * @param DateTime $cacheExpirationDate
187904fd306cSNickeau     * @return $this
188004fd306cSNickeau     * @deprecated for {@link CacheExpirationDate}
188104fd306cSNickeau     */
188204fd306cSNickeau    public
188304fd306cSNickeau    function setCacheExpirationDate(DateTime $cacheExpirationDate): MarkupPath
188404fd306cSNickeau    {
188504fd306cSNickeau        $this->cacheExpirationDate->setValue($cacheExpirationDate);
188604fd306cSNickeau        return $this;
188704fd306cSNickeau    }
188804fd306cSNickeau
188904fd306cSNickeau
189004fd306cSNickeau    /**
189104fd306cSNickeau     * Utility class
189204fd306cSNickeau     * Get the instructions document as if it was the main page.
189304fd306cSNickeau     * Ie the context path is:
189404fd306cSNickeau     *  * the markup path itself)
189504fd306cSNickeau     *  * or the default context path if the path cannot be transformed as wiki path.
189604fd306cSNickeau     */
189704fd306cSNickeau    public function getInstructionsDocument(): FetcherMarkup
189804fd306cSNickeau    {
189904fd306cSNickeau
190004fd306cSNickeau        $path = $this->getPathObject();
190104fd306cSNickeau        try {
190204fd306cSNickeau            $contextPath = $path->toWikiPath();
190304fd306cSNickeau        } catch (ExceptionCast $e) {
190404fd306cSNickeau            $contextPath = ExecutionContext::getActualOrCreateFromEnv()
190504fd306cSNickeau                ->getDefaultContextPath();
190604fd306cSNickeau        }
190704fd306cSNickeau        return FetcherMarkup::confRoot()
190804fd306cSNickeau            ->setRequestedExecutingPath($path)
190904fd306cSNickeau            ->setRequestedContextPath($contextPath)
191004fd306cSNickeau            ->setRequestedMimeToInstructions()
191104fd306cSNickeau            ->build();
191204fd306cSNickeau
191304fd306cSNickeau    }
191404fd306cSNickeau
191504fd306cSNickeau    public
191604fd306cSNickeau    function delete()
191704fd306cSNickeau    {
191804fd306cSNickeau
191904fd306cSNickeau        Index::getOrCreate()->deletePage($this);
192004fd306cSNickeau        saveWikiText($this->getWikiId(), "", "Delete");
192104fd306cSNickeau
192204fd306cSNickeau    }
192304fd306cSNickeau
192404fd306cSNickeau    /**
192504fd306cSNickeau     * @return Url -the absolute canonical url
192604fd306cSNickeau     */
192704fd306cSNickeau    public
192804fd306cSNickeau    function getAbsoluteCanonicalUrl(): Url
192904fd306cSNickeau    {
193004fd306cSNickeau        return $this->getCanonicalUrl()->toAbsoluteUrl();
193104fd306cSNickeau    }
193204fd306cSNickeau
193304fd306cSNickeau
193404fd306cSNickeau    public
193504fd306cSNickeau    function getReadStoreOrDefault(): MetadataStore
193604fd306cSNickeau    {
193704fd306cSNickeau        if ($this->readStore === null) {
193804fd306cSNickeau            /**
193904fd306cSNickeau             * No cache please if not set
194004fd306cSNickeau             * Cache should be in the MetadataDokuWikiStore
194104fd306cSNickeau             * that is page requested scoped and not by slot
194204fd306cSNickeau             */
194304fd306cSNickeau            return MetadataDokuWikiStore::getOrCreateFromResource($this);
194404fd306cSNickeau        }
194504fd306cSNickeau        if (!($this->readStore instanceof MetadataStore)) {
194604fd306cSNickeau            $this->readStore = MetadataStoreAbs::toMetadataStore($this->readStore, $this);
194704fd306cSNickeau        }
194804fd306cSNickeau        return $this->readStore;
194904fd306cSNickeau    }
195004fd306cSNickeau
195104fd306cSNickeau    /**
195204fd306cSNickeau     * @return Path
195304fd306cSNickeau     * A markup path wraps a path
195404fd306cSNickeau     */
195504fd306cSNickeau    public function getPathObject(): Path
195604fd306cSNickeau    {
195704fd306cSNickeau        return $this->path;
195804fd306cSNickeau    }
195904fd306cSNickeau
196004fd306cSNickeau
196104fd306cSNickeau    /**
196204fd306cSNickeau     * A shortcut for {@link MarkupPath::getPathObject()::getDokuwikiId()}
196304fd306cSNickeau     *
196404fd306cSNickeau     * @throws ExceptionBadArgument - if the markup path is not a {@link WikiPath}
196504fd306cSNickeau     */
196604fd306cSNickeau    public
196704fd306cSNickeau    function getWikiId(): string
196804fd306cSNickeau    {
196904fd306cSNickeau        $path = $this->getPathObject();
197004fd306cSNickeau        return WikiPath::createFromPathObject($path)->getWikiId();
197104fd306cSNickeau    }
197204fd306cSNickeau
197304fd306cSNickeau    public
197404fd306cSNickeau    function getUid(): Metadata
197504fd306cSNickeau    {
197604fd306cSNickeau        return PageId::createForPage($this);
197704fd306cSNickeau    }
197804fd306cSNickeau
197904fd306cSNickeau
198004fd306cSNickeau    public
198104fd306cSNickeau    function getAbsolutePath(): string
198204fd306cSNickeau    {
198304fd306cSNickeau        return WikiPath::NAMESPACE_SEPARATOR_DOUBLE_POINT . $this->getWikiId();
198404fd306cSNickeau    }
198504fd306cSNickeau
198604fd306cSNickeau    /**
198704fd306cSNickeau     * Todo, it should be a property of the markup not every markup file are main page markup.
198804fd306cSNickeau     * @return string
198904fd306cSNickeau     */
199004fd306cSNickeau    function getType(): string
199104fd306cSNickeau    {
199204fd306cSNickeau        return self::TYPE;
199304fd306cSNickeau    }
199404fd306cSNickeau
199504fd306cSNickeau    /**
199604fd306cSNickeau     * @return PageUrlPath
199704fd306cSNickeau     * @deprecated use {@link PageUrlPath} instead
199804fd306cSNickeau     */
199904fd306cSNickeau    public
200004fd306cSNickeau    function getUrlPathObject(): PageUrlPath
200104fd306cSNickeau    {
200204fd306cSNickeau        return $this->pageUrlPath;
200304fd306cSNickeau    }
200404fd306cSNickeau
200504fd306cSNickeau
200604fd306cSNickeau    public function getSideSlot(): ?MarkupPath
200704fd306cSNickeau    {
200804fd306cSNickeau
200904fd306cSNickeau        /**
201004fd306cSNickeau         * Only primary slot have a side slot
201104fd306cSNickeau         * Root Home page does not have one either
201204fd306cSNickeau         */
201304fd306cSNickeau        if ($this->isSlot()) {
201404fd306cSNickeau            return null;
201504fd306cSNickeau        }
201604fd306cSNickeau
201704fd306cSNickeau        $nearestMainFooter = $this->findNearest(SlotSystem::getSidebarName());
201804fd306cSNickeau        if ($nearestMainFooter === false) {
201904fd306cSNickeau            return null;
202004fd306cSNickeau        }
202104fd306cSNickeau        return MarkupPath::createMarkupFromId($nearestMainFooter);
202204fd306cSNickeau
202304fd306cSNickeau
202404fd306cSNickeau    }
202504fd306cSNickeau
202604fd306cSNickeau    /**
202704fd306cSNickeau     * @param $pageName
202804fd306cSNickeau     * @return false|string
202904fd306cSNickeau     */
203004fd306cSNickeau    private function findNearest($pageName)
203104fd306cSNickeau    {
203204fd306cSNickeau        global $ID;
203304fd306cSNickeau        $keep = $ID;
203404fd306cSNickeau        try {
203504fd306cSNickeau            $ID = $this->getWikiId();
203604fd306cSNickeau            return page_findnearest($pageName);
203704fd306cSNickeau        } finally {
203804fd306cSNickeau            $ID = $keep;
203904fd306cSNickeau        }
204004fd306cSNickeau
204104fd306cSNickeau    }
204204fd306cSNickeau
204304fd306cSNickeau    /**
204404fd306cSNickeau     * The slots that are independent from the primary slot
204504fd306cSNickeau     *
204604fd306cSNickeau     * @return MarkupPath[]
204704fd306cSNickeau     * @deprecated should be {@link TemplateForWebPage} based
204804fd306cSNickeau     */
204904fd306cSNickeau    public function getPrimaryIndependentSlots(): array
205004fd306cSNickeau    {
205104fd306cSNickeau        $secondarySlots = [];
205204fd306cSNickeau        $sideSlot = $this->getSideSlot();
205304fd306cSNickeau        if ($sideSlot !== null) {
205404fd306cSNickeau            $secondarySlots[] = $sideSlot;
205504fd306cSNickeau        }
205604fd306cSNickeau        return $secondarySlots;
205704fd306cSNickeau    }
205804fd306cSNickeau
205904fd306cSNickeau
206004fd306cSNickeau    public function isHidden(): bool
206104fd306cSNickeau    {
206204fd306cSNickeau        return isHiddenPage($this->getWikiId());
206304fd306cSNickeau    }
206404fd306cSNickeau
206504fd306cSNickeau
206604fd306cSNickeau    public function getPrimaryHeaderPage(): ?MarkupPath
206704fd306cSNickeau    {
206804fd306cSNickeau        $nearest = page_findnearest(SlotSystem::getMainHeaderSlotName());
206904fd306cSNickeau        if ($nearest === false) {
207004fd306cSNickeau            return null;
207104fd306cSNickeau        }
207204fd306cSNickeau        return MarkupPath::createMarkupFromId($nearest);
207304fd306cSNickeau    }
207404fd306cSNickeau
207504fd306cSNickeau    public function createPageFetcherHtml(): FetcherPage
207604fd306cSNickeau    {
207704fd306cSNickeau        return FetcherPage::createPageFetcherFromMarkupPath($this);
207804fd306cSNickeau    }
207904fd306cSNickeau
208004fd306cSNickeau    public function getHttpResponse(): HttpResponse
208104fd306cSNickeau    {
208204fd306cSNickeau        return HttpRequest::fetchXhtmlPageResponse($this->getWikiId());
208304fd306cSNickeau    }
208404fd306cSNickeau
208504fd306cSNickeau    /**
208604fd306cSNickeau     * @return Outline
208704fd306cSNickeau     * @deprecated uses {@link FetcherMarkup::getOutline()} instead
208804fd306cSNickeau     */
208904fd306cSNickeau    public function getOutline(): Outline
209004fd306cSNickeau    {
209104fd306cSNickeau
209204fd306cSNickeau        return $this->getInstructionsDocument()->getOutline();
209304fd306cSNickeau
209404fd306cSNickeau    }
209504fd306cSNickeau
209604fd306cSNickeau
209704fd306cSNickeau    public function persistToDefaultMetaStore(): MarkupPath
209804fd306cSNickeau    {
209904fd306cSNickeau        $this->getReadStoreOrDefault()->persist();
210004fd306cSNickeau        return $this;
210104fd306cSNickeau    }
210204fd306cSNickeau
210304fd306cSNickeau    public function getInstructionsPath(): LocalPath
210404fd306cSNickeau    {
210504fd306cSNickeau
210604fd306cSNickeau        $instructionsDocument = $this->getInstructionsDocument();
210704fd306cSNickeau        return $instructionsDocument->getInstructionsPath();
210804fd306cSNickeau
210904fd306cSNickeau    }
211004fd306cSNickeau
211104fd306cSNickeau    public function setContent(string $textContent): MarkupPath
211204fd306cSNickeau    {
211304fd306cSNickeau        FileSystems::setContent($this, $textContent);
211404fd306cSNickeau        return $this;
211504fd306cSNickeau    }
211604fd306cSNickeau
211704fd306cSNickeau    /**
211804fd306cSNickeau     * @throws ExceptionNotExists - if the path does not exist
211904fd306cSNickeau     */
212004fd306cSNickeau    public function createHtmlFetcherWithRequestedPathAsContextPath(): FetcherMarkup
212104fd306cSNickeau    {
212204fd306cSNickeau        $executionContext = ExecutionContext::getActualOrCreateFromEnv();
212304fd306cSNickeau        $executingPath = $this->getPathObject();
212404fd306cSNickeau        $requestedPath = $executionContext->getRequestedPath();
212504fd306cSNickeau        $requestedMarkupPath = MarkupPath::createPageFromPathObject($requestedPath);
212604fd306cSNickeau
212704fd306cSNickeau        if ($requestedMarkupPath->isSlot()) {
212804fd306cSNickeau            try {
212904fd306cSNickeau                $markupContextPath = SlotSystem::getContextPath();
213004fd306cSNickeau                SlotSystem::sendContextPathMessage($markupContextPath);
213104fd306cSNickeau                $requestedPath = $markupContextPath->toWikiPath();
213204fd306cSNickeau            } catch (\Exception $e) {
213304fd306cSNickeau                // should not
213404fd306cSNickeau            }
213504fd306cSNickeau        }
213604fd306cSNickeau        return FetcherMarkup::confRoot()
213704fd306cSNickeau            ->setRequestedMimeToXhtml()
213804fd306cSNickeau            ->setRequestedContextPath($requestedPath)
213904fd306cSNickeau            ->setRequestedExecutingPath($executingPath)
214004fd306cSNickeau            ->build();
214104fd306cSNickeau    }
214204fd306cSNickeau
214304fd306cSNickeau    public
214404fd306cSNickeau    function isRootItemPage(): bool
214504fd306cSNickeau    {
214604fd306cSNickeau        try {
214704fd306cSNickeau            if ($this->isIndexPage()) {
214804fd306cSNickeau                return false;
214904fd306cSNickeau            }
215004fd306cSNickeau            $parent = $this->getParent();
215104fd306cSNickeau            if ($parent->isRootHomePage()) {
215204fd306cSNickeau                return true;
215304fd306cSNickeau            }
215404fd306cSNickeau            return false;
215504fd306cSNickeau        } catch (ExceptionNotFound $e) {
215604fd306cSNickeau            return false;
215704fd306cSNickeau        }
215804fd306cSNickeau    }
215904fd306cSNickeau
216004fd306cSNickeau    private
216104fd306cSNickeau    function getPrimaryFooterPage(): ?MarkupPath
216204fd306cSNickeau    {
216304fd306cSNickeau        $nearest = page_findnearest(SlotSystem::getMainFooterSlotName());
216404fd306cSNickeau        if ($nearest === false) {
216504fd306cSNickeau            return null;
216604fd306cSNickeau        }
216704fd306cSNickeau        return MarkupPath::createMarkupFromId($nearest);
216804fd306cSNickeau    }
216904fd306cSNickeau
217004fd306cSNickeau    /**
217104fd306cSNickeau     * Set the page path to an index page for a directory path
217204fd306cSNickeau     * @return void
217304fd306cSNickeau     */
217404fd306cSNickeau    private
217504fd306cSNickeau    function setCorrectPathForDirectoryToIndexPage(): void
217604fd306cSNickeau    {
217704fd306cSNickeau
217804fd306cSNickeau
217904fd306cSNickeau        if (!($this->path instanceof WikiPath)) {
218004fd306cSNickeau            return;
218104fd306cSNickeau        }
218204fd306cSNickeau        /**
218304fd306cSNickeau         * @var $path WikiPath
218404fd306cSNickeau         */
218504fd306cSNickeau        $path = $this->path;
218604fd306cSNickeau
218704fd306cSNickeau        /**
218804fd306cSNickeau         * We correct the path
218904fd306cSNickeau         * We don't return a page because it does not work in a constructor
219004fd306cSNickeau         */
219104fd306cSNickeau        $startPageName = Site::getIndexPageName();
219204fd306cSNickeau        $indexPath = $path->resolveId($startPageName);
219304fd306cSNickeau        if (FileSystems::exists($indexPath)) {
219404fd306cSNickeau            // start page inside namespace
219504fd306cSNickeau            $this->path = $indexPath;
219604fd306cSNickeau            return;
219704fd306cSNickeau        }
219804fd306cSNickeau
219904fd306cSNickeau        // page named like the NS inside the NS
220004fd306cSNickeau        try {
220104fd306cSNickeau            $parentName = $this->getLastNameWithoutExtension();
220204fd306cSNickeau            $nsInsideNsIndex = $this->path->resolveId($parentName);
220304fd306cSNickeau            if (FileSystems::exists($nsInsideNsIndex)) {
220404fd306cSNickeau                $this->path = $nsInsideNsIndex;
220504fd306cSNickeau                return;
220604fd306cSNickeau            }
220704fd306cSNickeau        } catch (ExceptionNotFound $e) {
220804fd306cSNickeau            // no last name
220904fd306cSNickeau        }
221004fd306cSNickeau
221104fd306cSNickeau        // We don't support the child page
221204fd306cSNickeau        // Does not exist but can be used by hierarchical function
221304fd306cSNickeau        $this->path = $indexPath;
221404fd306cSNickeau    }
221504fd306cSNickeau
221604fd306cSNickeau
221704fd306cSNickeau    public
221804fd306cSNickeau    function getUidObject(): Metadata
221904fd306cSNickeau    {
222004fd306cSNickeau        if ($this->uidObject === null) {
222104fd306cSNickeau            try {
222204fd306cSNickeau                $this->uidObject = Meta\Api\MetadataSystem::toMetadataObject($this->getUid())
222304fd306cSNickeau                    ->setResource($this);
222404fd306cSNickeau            } catch (ExceptionBadArgument $e) {
222504fd306cSNickeau                throw new ExceptionRuntimeInternal("Uid object is a metadata object. It should not happen.", self::CANONICAL_PAGE, 1, $e);
222604fd306cSNickeau            }
222704fd306cSNickeau        }
222804fd306cSNickeau
222904fd306cSNickeau        return $this->uidObject;
223004fd306cSNickeau    }
223104fd306cSNickeau
223204fd306cSNickeau    function getExtension(): string
223304fd306cSNickeau    {
223404fd306cSNickeau        return $this->path->getExtension();
223504fd306cSNickeau    }
223604fd306cSNickeau
223704fd306cSNickeau    function getLastNameWithoutExtension(): string
223804fd306cSNickeau    {
223904fd306cSNickeau        return $this->path->getLastNameWithoutExtension();
224004fd306cSNickeau    }
224104fd306cSNickeau
224204fd306cSNickeau    function getScheme(): string
224304fd306cSNickeau    {
224404fd306cSNickeau        return MarkupFileSystem::SCHEME;
224504fd306cSNickeau    }
224604fd306cSNickeau
224704fd306cSNickeau    function getLastName(): string
224804fd306cSNickeau    {
224904fd306cSNickeau        return $this->path->getLastName();
225004fd306cSNickeau    }
225104fd306cSNickeau
225204fd306cSNickeau    function getNames()
225304fd306cSNickeau    {
225404fd306cSNickeau        return $this->path->getNames();
225504fd306cSNickeau    }
225604fd306cSNickeau
225704fd306cSNickeau    function toAbsoluteId(): string
225804fd306cSNickeau    {
225904fd306cSNickeau        return $this->path->toAbsoluteId();
226004fd306cSNickeau    }
226104fd306cSNickeau
226204fd306cSNickeau    function toUriString(): string
226304fd306cSNickeau    {
226404fd306cSNickeau        return $this->path->toUriString();
226504fd306cSNickeau    }
226604fd306cSNickeau
226704fd306cSNickeau    function toAbsolutePath(): Path
226804fd306cSNickeau    {
226904fd306cSNickeau        return $this->path->toAbsolutePath();
227004fd306cSNickeau    }
227104fd306cSNickeau
227204fd306cSNickeau
227304fd306cSNickeau    function resolve(string $name): Path
227404fd306cSNickeau    {
227504fd306cSNickeau        return $this->path->resolve($name);
227604fd306cSNickeau    }
227704fd306cSNickeau
227804fd306cSNickeau
227904fd306cSNickeau    function getUrl(): Url
228004fd306cSNickeau    {
228104fd306cSNickeau        return FetcherPage::createPageFetcherFromMarkupPath($this)
228204fd306cSNickeau            ->getFetchUrl();
228304fd306cSNickeau    }
228404fd306cSNickeau
228504fd306cSNickeau    function getHost(): string
228604fd306cSNickeau    {
228704fd306cSNickeau        return $this->path->getHost();
228804fd306cSNickeau    }
228904fd306cSNickeau
229004fd306cSNickeau    public
229104fd306cSNickeau    function __toString(): string
229204fd306cSNickeau    {
229304fd306cSNickeau        return $this->path->__toString();
229404fd306cSNickeau    }
229504fd306cSNickeau
229604fd306cSNickeau    /**
229704fd306cSNickeau     * @throws ExceptionBadSyntax
229804fd306cSNickeau     * @throws ExceptionBadArgument
229904fd306cSNickeau     */
230004fd306cSNickeau    public
230104fd306cSNickeau    static function createFromUri(string $uri): MarkupPath
230204fd306cSNickeau    {
230304fd306cSNickeau        $path = FileSystems::createPathFromUri($uri);
230404fd306cSNickeau        return new MarkupPath($path);
230504fd306cSNickeau    }
230604fd306cSNickeau
230704fd306cSNickeau
230804fd306cSNickeau}
2309