1<?php
2
3
4namespace ComboStrap\Meta\Field;
5
6use ComboStrap\ExceptionCompile;
7use ComboStrap\LogUtility;
8use ComboStrap\MarkupPath;
9use ComboStrap\Meta\Api\Metadata;
10use ComboStrap\Meta\Api\MetadataInteger;
11use ComboStrap\Meta\Store\MetadataDbStore;
12use ComboStrap\Meta\Store\MetadataDokuWikiStore;
13use ComboStrap\Sqlite;
14
15/**
16 * Class BacklinkCount
17 * @package ComboStrap
18 * Internal backlink count
19 */
20class BacklinkCount extends MetadataInteger
21{
22    const PROPERTY_NAME = 'backlink_count';
23
24    public static function createFromResource(MarkupPath $page)
25    {
26        return (new BacklinkCount())
27            ->setResource($page);
28    }
29
30    static public function getDescription(): string
31    {
32        return "The number of backlinks";
33    }
34
35    static public function getLabel(): string
36    {
37        return "Backlink Count";
38    }
39
40    public static function getName(): string
41    {
42        return self::PROPERTY_NAME;
43    }
44
45    static public function getPersistenceType(): string
46    {
47        return Metadata::DERIVED_METADATA;
48    }
49
50    static public function isMutable(): bool
51    {
52        return false;
53    }
54
55    public function buildFromReadStore(): Metadata
56    {
57
58        $storeClass = get_class($this->getReadStore());
59        switch ($storeClass) {
60            case MetadataDokuWikiStore::class:
61                $resource = $this->getResource();
62                if (!($resource instanceof MarkupPath)) {
63                    LogUtility::msg("Backlink count is not yet supported on the resource type ({$resource->getType()}");
64                    return $this;
65                }
66                $backlinks = $resource->getBacklinks();
67                $this->value = sizeof($backlinks);
68                return $this;
69            case MetadataDbStore::class:
70                $this->value = $this->calculateBacklinkCount();
71                return $this;
72            default:
73                LogUtility::msg("The store ($storeClass) does not support backlink count");
74                return $this;
75        }
76
77
78    }
79
80    /**
81     * Sqlite is much quicker than the Dokuwiki Internal Index
82     * We use it every time that we can
83     *
84     * @return int|null
85     */
86    private function calculateBacklinkCount(): ?int
87    {
88
89        $sqlite = Sqlite::createOrGetSqlite();
90        /** @noinspection SqlResolve */
91        $request = $sqlite
92            ->createRequest()
93            ->setQueryParametrized("select count(1) from PAGE_REFERENCES where REFERENCE = ? ", [$this->getResource()->getPathObject()->toAbsoluteId()]);
94        $count = 0;
95        try {
96            $count = $request
97                ->execute()
98                ->getFirstCellValue();
99        } catch (ExceptionCompile $e) {
100            LogUtility::error($e->getMessage(), self::PROPERTY_NAME, $e);
101        } finally {
102            $request->close();
103        }
104        return intval($count);
105
106    }
107
108
109    public function setFromStoreValueWithoutException($value): Metadata
110    {
111        /**
112         * not used because
113         * the data is not stored in the database
114         * We overwrite and build the value {@link BacklinkCount::buildFromReadStore()}
115         */
116        return $this;
117    }
118
119
120}
121