1<?php
2
3
4namespace ComboStrap;
5
6
7use ComboStrap\Meta\Api\Metadata;
8use ComboStrap\Meta\Api\MetadataStore;
9use ComboStrap\Meta\Api\MetadataText;
10use ComboStrap\Meta\Store\MetadataDokuWikiStore;
11use syntax_plugin_combo_frontmatter;
12
13class PageDescription extends MetadataText
14{
15
16    /**
17     * The description sub key in the dokuwiki meta
18     * that has the description text
19     */
20    const ABSTRACT_KEY = "abstract";
21    public const PROPERTY_NAME = "description";
22    const DESCRIPTION_ORIGIN = "origin";
23    const PLUGIN_DESCRIPTION_META = "plugin_description";
24
25
26    /**
27     * @var string - the origin of the description
28     */
29    private $descriptionOrigin;
30
31
32    public const DESCRIPTION_PROPERTY = "description";
33    /**
34     * To indicate from where the description comes
35     * This is when it's the original dokuwiki description
36     */
37    public const DESCRIPTION_DOKUWIKI_ORIGIN = "dokuwiki";
38    /**
39     * The origin of the description was set to frontmatter
40     * due to historic reason to say to it comes from combo
41     * (You may set it via the metadata manager and get this origin)
42     */
43    public const DESCRIPTION_COMBO_ORIGIN = syntax_plugin_combo_frontmatter::CANONICAL;
44    private ?string $defaultValue = null;
45
46    public static function createForPage($page): PageDescription
47    {
48        return (new PageDescription())
49            ->setResource($page);
50    }
51
52    public static function getTab(): string
53    {
54        return MetaManagerForm::TAB_PAGE_VALUE;
55    }
56
57    public static function getDescription(): string
58    {
59        return "The description is a paragraph that describe your page. It's advertised to external application and used in templating.";
60    }
61
62    public static function getLabel(): string
63    {
64        return "Description";
65    }
66
67    static public function getName(): string
68    {
69        return self::DESCRIPTION_PROPERTY;
70    }
71
72    public static function getPersistenceType(): string
73    {
74        return MetadataDokuWikiStore::PERSISTENT_DOKUWIKI_KEY;
75    }
76
77    public static function getDataType(): string
78    {
79        return DataType::PARAGRAPH_TYPE_VALUE;
80    }
81
82
83    public static function isMutable(): bool
84    {
85        return true;
86    }
87
88
89    /**
90     * @return string
91     */
92    public function getValueOrDefault(): string
93    {
94
95        try {
96            $value = $this->getValue();
97            if (empty($value)) {
98                return $this->getDefaultValue();
99            }
100            return $value;
101        } catch (ExceptionNotFound $e) {
102            return $this->getDefaultValue();
103        }
104
105
106    }
107
108
109    /**
110     * @return string - the dokuwiki calculated description
111     * or the resource name if none (case when there is no text at all for instance with only a icon)
112     */
113    public function getDefaultValue(): string
114    {
115
116        $this->buildCheck();
117        if ($this->defaultValue === "" || $this->defaultValue === null) {
118            return PageTitle::createForMarkup($this->getResource())
119                ->getValueOrDefault();
120        }
121        return $this->defaultValue;
122
123    }
124
125
126    public function setFromStoreValueWithoutException($value): Metadata
127    {
128
129        $metaDataStore = $this->getReadStore();
130        if (!$metaDataStore->isDokuWikiStore()) {
131            parent::setFromStoreValueWithoutException($value);
132            return $this;
133        }
134
135        if (is_array($value)) {
136            $description = $value[self::ABSTRACT_KEY];
137            if ($description !== null) {
138                $descriptionOrigin = $value[self::DESCRIPTION_ORIGIN] ?? null;
139                if ($descriptionOrigin !== null) {
140                    $this->descriptionOrigin = $descriptionOrigin;
141                    parent::setFromStoreValueWithoutException($description);
142                    return $this;
143                }
144            }
145        }
146        /**
147         * Plugin Plugin Description Integration
148         */
149        $value = $metaDataStore->getFromName(self::PLUGIN_DESCRIPTION_META);
150        if ($value !== null) {
151            $keywords = $value["keywords"];
152            if ($keywords !== null) {
153                parent::setFromStoreValueWithoutException($keywords);
154                $this->descriptionOrigin = self::PLUGIN_DESCRIPTION_META;
155                return $this;
156            }
157        }
158
159        /**
160         * No description set, null
161         */
162        parent::setFromStoreValueWithoutException(null);
163
164        /**
165         * Default value is derived from the meta store
166         * We need to set it at build time because the store may change
167         * after the build
168         */
169        $this->defaultValue = $this->getGeneratedValueFromDokuWikiStore($metaDataStore);
170
171        return $this;
172    }
173
174
175    public function setValue($value): Metadata
176    {
177
178        if ($value === "" || $value === null) {
179
180            if ($this->getReadStore() instanceof MetadataDokuWikiStore) {
181                // we need to know the origin of the actual description
182                if ($this->descriptionOrigin === null) {
183                    /**
184                     * we don't do {@link Metadata::buildCheck() build check} otherwise we get a loop
185                     * because it will use back this method {@link Metadata::setValue()}
186                     */
187                    $this->buildFromReadStore();
188                }
189                if ($this->descriptionOrigin === PageDescription::DESCRIPTION_COMBO_ORIGIN) {
190                    throw new ExceptionCompile("The description cannot be empty", PageDescription::DESCRIPTION_PROPERTY);
191                } else {
192                    // The original description is from Dokuwiki, we don't send an error
193                    // otherwise all page without a first description would get an error
194                    // (What fucked up is fucked up)
195                    return $this;
196                }
197            }
198
199        }
200
201        parent::setValue($value);
202        return $this;
203    }
204
205    /**
206     * @return ?string|array
207     */
208    public function toStoreValue()
209    {
210        $metaDataStore = $this->getWriteStore();
211        if (!($metaDataStore instanceof MetadataDokuWikiStore)) {
212            // A string
213            return parent::toStoreValue();
214        }
215        /**
216         * For dokuwiki, this is an array
217         */
218        try {
219            return array(
220                self::ABSTRACT_KEY => $this->getValue(),
221                self::DESCRIPTION_ORIGIN => PageDescription::DESCRIPTION_COMBO_ORIGIN
222            );
223        } catch (ExceptionNotFound $e) {
224            return null;
225        }
226    }
227
228
229    public function getDescriptionOrigin(): string
230    {
231        return $this->descriptionOrigin;
232    }
233
234    private function getGeneratedValueFromDokuWikiStore(MetadataStore $metaDataStore): ?string
235    {
236
237        /**
238         * The generated is in the current metadata
239         */
240        $descriptionArray = $metaDataStore->getFromName(self::PROPERTY_NAME);
241        if (empty($descriptionArray)) {
242            return null;
243        }
244        if (!array_key_exists(self::ABSTRACT_KEY, $descriptionArray)) {
245            return null;
246        }
247        $value = $descriptionArray[self::ABSTRACT_KEY];
248
249
250        /**
251         * Dokuwiki description
252         * With some trick
253         * TODO: Generate our own description ?
254         */
255        // suppress the carriage return
256        $description = str_replace("\n", " ", $value);
257        // suppress the h1
258        $resourceCombo = $this->getResource();
259        if ($resourceCombo instanceof MarkupPath) {
260            $description = str_replace($resourceCombo->getH1OrDefault(), "", $description);
261        }
262        // Suppress the star, the tab, About
263        $description = preg_replace('/(\*|\t|About)/im', "", $description);
264        // Suppress all double space and trim
265        return trim(preg_replace('/ /m', " ", $description));
266    }
267
268
269    public static function isOnForm(): bool
270    {
271        return true;
272    }
273}
274