xref: /plugin/combo/syntax/frontmatter.php (revision 1fa8c418ed5809db58049141be41b7738471dd32)
1007225e5Sgerardnico<?php
2007225e5Sgerardnico/**
3007225e5Sgerardnico * Front Matter implementation to add metadata
4007225e5Sgerardnico *
5007225e5Sgerardnico *
6007225e5Sgerardnico * that enhance the metadata dokuwiki system
7007225e5Sgerardnico * https://www.dokuwiki.org/metadata
8007225e5Sgerardnico * that use the Dublin Core Standard
9007225e5Sgerardnico * http://dublincore.org/
10007225e5Sgerardnico * by adding the front matter markup specification
11007225e5Sgerardnico * https://gerardnico.com/markup/front-matter
12007225e5Sgerardnico *
13007225e5Sgerardnico * Inspiration
14007225e5Sgerardnico * https://github.com/dokufreaks/plugin-meta/blob/master/syntax.php
15007225e5Sgerardnico * https://www.dokuwiki.org/plugin:semantic
16007225e5Sgerardnico *
17007225e5Sgerardnico * See also structured plugin
18007225e5Sgerardnico * https://www.dokuwiki.org/plugin:data
19007225e5Sgerardnico * https://www.dokuwiki.org/plugin:struct
20007225e5Sgerardnico *
21007225e5Sgerardnico */
22007225e5Sgerardnico
2337748cd8SNickeauuse ComboStrap\Analytics;
2437748cd8SNickeauuse ComboStrap\CacheManager;
2537748cd8SNickeauuse ComboStrap\Iso8601Date;
26007225e5Sgerardnicouse ComboStrap\LogUtility;
2737748cd8SNickeauuse ComboStrap\MediaLink;
2871f916b9Sgerardnicouse ComboStrap\Page;
29a6bf47aaSNickeauuse ComboStrap\PluginUtility;
3037748cd8SNickeauuse ComboStrap\Publication;
31007225e5Sgerardnico
3237748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
33007225e5Sgerardnico
34007225e5Sgerardnico
35007225e5Sgerardnico/**
36007225e5Sgerardnico * All DokuWiki plugins to extend the parser/rendering mechanism
37007225e5Sgerardnico * need to inherit from this class
38d5303bc5Sgerardnico *
39d5303bc5Sgerardnico * For a list of meta, see also https://ghost.org/docs/publishing/#api-data
40007225e5Sgerardnico */
41007225e5Sgerardnicoclass syntax_plugin_combo_frontmatter extends DokuWiki_Syntax_Plugin
42007225e5Sgerardnico{
43007225e5Sgerardnico    const PARSING_STATE_EMPTY = "empty";
44007225e5Sgerardnico    const PARSING_STATE_ERROR = "error";
45007225e5Sgerardnico    const PARSING_STATE_SUCCESSFUL = "successful";
465f891b7eSNickeau    const STATUS = "status";
475f891b7eSNickeau    const CANONICAL = "frontmatter";
4821913ab3SNickeau    const CONF_ENABLE_SECTION_EDITING = 'enableFrontMatterSectionEditing';
49007225e5Sgerardnico
50007225e5Sgerardnico    /**
5137748cd8SNickeau     * Used in the move plugin
5237748cd8SNickeau     * !!! The two last word of the plugin class !!!
5337748cd8SNickeau     */
5437748cd8SNickeau    const COMPONENT = 'combo_' . self::CANONICAL;
5537748cd8SNickeau    const START_TAG = '---json';
5637748cd8SNickeau    const END_TAG = '---';
5737748cd8SNickeau    const METADATA_IMAGE_CANONICAL = "metadata:image";
5837748cd8SNickeau
5937748cd8SNickeau    /**
6037748cd8SNickeau     * @param $match
6137748cd8SNickeau     * @return array|mixed - null if decodage problem, empty array if no json or an associative array
6237748cd8SNickeau     */
6337748cd8SNickeau    public static function FrontMatterMatchToAssociativeArray($match)
6437748cd8SNickeau    {
6537748cd8SNickeau        // strip
6637748cd8SNickeau        //   from start `---json` + eol = 8
6737748cd8SNickeau        //   from end   `---` + eol = 4
6837748cd8SNickeau        $jsonString = substr($match, 7, -3);
6937748cd8SNickeau
7037748cd8SNickeau        // Empty front matter
7137748cd8SNickeau        if (trim($jsonString) == "") {
7237748cd8SNickeau            self::deleteKnownMetaThatAreNoMorePresent();
7337748cd8SNickeau            return [];
7437748cd8SNickeau        }
7537748cd8SNickeau
7637748cd8SNickeau        // Otherwise you get an object ie $arrayFormat-> syntax
7737748cd8SNickeau        $arrayFormat = true;
7837748cd8SNickeau        return json_decode($jsonString, $arrayFormat);
7937748cd8SNickeau    }
8037748cd8SNickeau
8137748cd8SNickeau    /**
82007225e5Sgerardnico     * Syntax Type.
83007225e5Sgerardnico     *
84007225e5Sgerardnico     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
85007225e5Sgerardnico     * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
86007225e5Sgerardnico     *
87007225e5Sgerardnico     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
88007225e5Sgerardnico     *
89007225e5Sgerardnico     * baseonly - run only in the base
90007225e5Sgerardnico     */
91007225e5Sgerardnico    function getType()
92007225e5Sgerardnico    {
93007225e5Sgerardnico        return 'baseonly';
94007225e5Sgerardnico    }
95007225e5Sgerardnico
96531e725cSNickeau    public function getPType()
97531e725cSNickeau    {
9885e82846SNickeau        /**
9985e82846SNickeau         * This element create a section
10085e82846SNickeau         * element that is a div
10185e82846SNickeau         * that should not be in paragraph
10285e82846SNickeau         *
10385e82846SNickeau         * We make it a block
10485e82846SNickeau         */
10585e82846SNickeau        return "block";
106531e725cSNickeau    }
107531e725cSNickeau
108531e725cSNickeau
109007225e5Sgerardnico    /**
110007225e5Sgerardnico     * @see Doku_Parser_Mode::getSort()
111007225e5Sgerardnico     * Higher number than the teaser-columns
112007225e5Sgerardnico     * because the mode with the lowest sort number will win out
113007225e5Sgerardnico     */
114007225e5Sgerardnico    function getSort()
115007225e5Sgerardnico    {
116007225e5Sgerardnico        return 99;
117007225e5Sgerardnico    }
118007225e5Sgerardnico
119007225e5Sgerardnico    /**
120007225e5Sgerardnico     * Create a pattern that will called this plugin
121007225e5Sgerardnico     *
122007225e5Sgerardnico     * @param string $mode
123007225e5Sgerardnico     * @see Doku_Parser_Mode::connectTo()
124007225e5Sgerardnico     */
125007225e5Sgerardnico    function connectTo($mode)
126007225e5Sgerardnico    {
127007225e5Sgerardnico        if ($mode == "base") {
128007225e5Sgerardnico            // only from the top
12937748cd8SNickeau            $this->Lexer->addSpecialPattern(self::START_TAG . '.*?' . self::END_TAG, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
130007225e5Sgerardnico        }
131007225e5Sgerardnico    }
132007225e5Sgerardnico
133007225e5Sgerardnico    /**
134007225e5Sgerardnico     *
135007225e5Sgerardnico     * The handle function goal is to parse the matched syntax through the pattern function
136007225e5Sgerardnico     * and to return the result for use in the renderer
137007225e5Sgerardnico     * This result is always cached until the page is modified.
138007225e5Sgerardnico     * @param string $match
139007225e5Sgerardnico     * @param int $state
140007225e5Sgerardnico     * @param int $pos
141007225e5Sgerardnico     * @param Doku_Handler $handler
142007225e5Sgerardnico     * @return array|bool
143007225e5Sgerardnico     * @see DokuWiki_Syntax_Plugin::handle()
144007225e5Sgerardnico     *
145007225e5Sgerardnico     */
146007225e5Sgerardnico    function handle($match, $state, $pos, Doku_Handler $handler)
147007225e5Sgerardnico    {
148007225e5Sgerardnico
149007225e5Sgerardnico        if ($state == DOKU_LEXER_SPECIAL) {
150007225e5Sgerardnico
151007225e5Sgerardnico
15237748cd8SNickeau            $jsonArray = self::FrontMatterMatchToAssociativeArray($match);
153007225e5Sgerardnico
154007225e5Sgerardnico
155a6bf47aaSNickeau            $result = [];
156007225e5Sgerardnico            // Decodage problem
157531e725cSNickeau            if ($jsonArray == null) {
15837748cd8SNickeau
159a6bf47aaSNickeau                $result[self::STATUS] = self::PARSING_STATE_ERROR;
160a6bf47aaSNickeau                $result[PluginUtility::PAYLOAD] = $match;
16137748cd8SNickeau
162a6bf47aaSNickeau            } else {
16337748cd8SNickeau
16437748cd8SNickeau                if (sizeof($jsonArray) === 0) {
16537748cd8SNickeau                    return array(self::STATUS => self::PARSING_STATE_EMPTY);
16637748cd8SNickeau                }
16737748cd8SNickeau
1685f891b7eSNickeau                $result[self::STATUS] = self::PARSING_STATE_SUCCESSFUL;
16937748cd8SNickeau                /**
17037748cd8SNickeau                 * Published is an alias for date published
17137748cd8SNickeau                 */
17237748cd8SNickeau                if (isset($jsonArray[Publication::OLD_META_KEY])) {
17337748cd8SNickeau                    $jsonArray[Publication::DATE_PUBLISHED] = $jsonArray[Publication::OLD_META_KEY];
17437748cd8SNickeau                    unset($jsonArray[Publication::OLD_META_KEY]);
17537748cd8SNickeau                }
17637748cd8SNickeau                /**
17737748cd8SNickeau                 * Add the time part if not present
17837748cd8SNickeau                 */
17937748cd8SNickeau                if (isset($jsonArray[Publication::DATE_PUBLISHED])) {
180*1fa8c418SNickeau                    $dateAsString = $jsonArray[Publication::DATE_PUBLISHED];
181*1fa8c418SNickeau                    $dateObject = Iso8601Date::create($dateAsString);
182*1fa8c418SNickeau                    if (!$dateObject->isValidDateEntry()) {
183*1fa8c418SNickeau                        LogUtility::msg("The published date ($dateAsString) is not a valid date supported.", LogUtility::LVL_MSG_ERROR, Iso8601Date::CANONICAL);
18437748cd8SNickeau                        unset($jsonArray[Publication::DATE_PUBLISHED]);
18537748cd8SNickeau                    } else {
186*1fa8c418SNickeau                        $jsonArray[Publication::DATE_PUBLISHED] = "$dateObject";
187*1fa8c418SNickeau                    }
18837748cd8SNickeau                }
18937748cd8SNickeau
190*1fa8c418SNickeau                if (isset($jsonArray[Analytics::DATE_START])) {
191*1fa8c418SNickeau                    $dateAsString = $jsonArray[Analytics::DATE_START];
192*1fa8c418SNickeau                    $dateObject = Iso8601Date::create($dateAsString);
193*1fa8c418SNickeau                    if (!$dateObject->isValidDateEntry()) {
194*1fa8c418SNickeau                        LogUtility::msg("The start date ($dateAsString) is not a valid date supported.", LogUtility::LVL_MSG_ERROR, Iso8601Date::CANONICAL);
195*1fa8c418SNickeau                        unset($jsonArray[Analytics::DATE_START]);
196*1fa8c418SNickeau                    } else {
197*1fa8c418SNickeau                        $jsonArray[Analytics::DATE_START] = "$dateObject";
19837748cd8SNickeau                    }
199*1fa8c418SNickeau                }
200*1fa8c418SNickeau
201*1fa8c418SNickeau                if (isset($jsonArray[Analytics::DATE_END])) {
202*1fa8c418SNickeau                    $dateAsString = $jsonArray[Analytics::DATE_END];
203*1fa8c418SNickeau                    $dateObject = Iso8601Date::create($dateAsString);
204*1fa8c418SNickeau                    if (!$dateObject->isValidDateEntry()) {
205*1fa8c418SNickeau                        LogUtility::msg("The end date ($dateAsString) is not a valid date supported.", LogUtility::LVL_MSG_ERROR, Iso8601Date::CANONICAL);
206*1fa8c418SNickeau                        unset($jsonArray[Analytics::DATE_END]);
207*1fa8c418SNickeau                    } else {
208*1fa8c418SNickeau                        $jsonArray[Analytics::DATE_END] = "$dateObject";
209*1fa8c418SNickeau                    }
210*1fa8c418SNickeau                }
211*1fa8c418SNickeau
212a6bf47aaSNickeau                $result[PluginUtility::ATTRIBUTES] = $jsonArray;
213a6bf47aaSNickeau            }
214531e725cSNickeau
215531e725cSNickeau            /**
216531e725cSNickeau             * End position is the length of the match + 1 for the newline
217531e725cSNickeau             */
218531e725cSNickeau            $newLine = 1;
219531e725cSNickeau            $endPosition = $pos + strlen($match) + $newLine;
220531e725cSNickeau            $result[PluginUtility::POSITION] = [$pos, $endPosition];
221007225e5Sgerardnico
222007225e5Sgerardnico            return $result;
223007225e5Sgerardnico        }
224007225e5Sgerardnico
225007225e5Sgerardnico        return array();
226007225e5Sgerardnico    }
227007225e5Sgerardnico
228007225e5Sgerardnico    /**
229007225e5Sgerardnico     * Render the output
230007225e5Sgerardnico     * @param string $format
231007225e5Sgerardnico     * @param Doku_Renderer $renderer
232007225e5Sgerardnico     * @param array $data - what the function handle() return'ed
233007225e5Sgerardnico     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
234007225e5Sgerardnico     * @see DokuWiki_Syntax_Plugin::render()
235007225e5Sgerardnico     *
236007225e5Sgerardnico     *
237007225e5Sgerardnico     */
238007225e5Sgerardnico    function render($format, Doku_Renderer $renderer, $data)
239007225e5Sgerardnico    {
240007225e5Sgerardnico
241007225e5Sgerardnico        switch ($format) {
242007225e5Sgerardnico            case 'xhtml':
243007225e5Sgerardnico                global $ID;
244007225e5Sgerardnico                /** @var Doku_Renderer_xhtml $renderer */
24521913ab3SNickeau
2465f891b7eSNickeau                $state = $data[self::STATUS];
247007225e5Sgerardnico                if ($state == self::PARSING_STATE_ERROR) {
2485f891b7eSNickeau                    $json = $data[PluginUtility::PAYLOAD];
2495f891b7eSNickeau                    LogUtility::msg("Front Matter: The json object for the page ($ID) is not valid. See the errors it by clicking on <a href=\"https://jsonformatter.curiousconcept.com/?data=" . urlencode($json) . "\">this link</a>.", LogUtility::LVL_MSG_ERROR);
250007225e5Sgerardnico                }
25121913ab3SNickeau
25221913ab3SNickeau                /**
25321913ab3SNickeau                 * Section
25421913ab3SNickeau                 */
25521913ab3SNickeau                list($startPosition, $endPosition) = $data[PluginUtility::POSITION];
25621913ab3SNickeau                if (PluginUtility::getConfValue(self::CONF_ENABLE_SECTION_EDITING, 1)) {
25721913ab3SNickeau                    $position = $startPosition;
25821913ab3SNickeau                    $name = self::CANONICAL;
25921913ab3SNickeau                    PluginUtility::startSection($renderer, $position, $name);
26021913ab3SNickeau                    $renderer->finishSectionEdit($endPosition);
26121913ab3SNickeau                }
262007225e5Sgerardnico                break;
263531e725cSNickeau            case renderer_plugin_combo_analytics::RENDERER_FORMAT:
264a6bf47aaSNickeau
265a6bf47aaSNickeau                if ($data[self::STATUS] != self::PARSING_STATE_SUCCESSFUL) {
266a6bf47aaSNickeau                    return false;
267a6bf47aaSNickeau                }
268a6bf47aaSNickeau
26937748cd8SNickeau                $notModifiableMeta = [
27037748cd8SNickeau                    Analytics::PATH,
27137748cd8SNickeau                    Analytics::DATE_CREATED,
27237748cd8SNickeau                    Analytics::DATE_MODIFIED
27337748cd8SNickeau                ];
27437748cd8SNickeau
275007225e5Sgerardnico                /** @var renderer_plugin_combo_analytics $renderer */
276a6bf47aaSNickeau                $jsonArray = $data[PluginUtility::ATTRIBUTES];
27737748cd8SNickeau                foreach ($jsonArray as $key => $value) {
27837748cd8SNickeau                    if (!in_array($key, $notModifiableMeta)) {
27937748cd8SNickeau
28037748cd8SNickeau                        $renderer->setMeta($key, $value);
28137748cd8SNickeau                        if ($key === Page::IMAGE_META_PROPERTY) {
28237748cd8SNickeau                            $this->updateImageStatistics($value, $renderer);
283007225e5Sgerardnico                        }
28437748cd8SNickeau
28537748cd8SNickeau                    } else {
28637748cd8SNickeau                        LogUtility::msg("The metadata ($key) cannot be set.", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
287007225e5Sgerardnico                    }
2889b9e6d1fSgerardnico                }
289007225e5Sgerardnico                break;
29037748cd8SNickeau
291a6bf47aaSNickeau            case "metadata":
292a6bf47aaSNickeau
29337748cd8SNickeau                /** @var Doku_Renderer_metadata $renderer */
294a6bf47aaSNickeau                if ($data[self::STATUS] != self::PARSING_STATE_SUCCESSFUL) {
295a6bf47aaSNickeau                    return false;
296a6bf47aaSNickeau                }
297a6bf47aaSNickeau
298a6bf47aaSNickeau                global $ID;
299a6bf47aaSNickeau                $jsonArray = $data[PluginUtility::ATTRIBUTES];
300a6bf47aaSNickeau
301a6bf47aaSNickeau
302a6bf47aaSNickeau                $notModifiableMeta = [
303a6bf47aaSNickeau                    "date",
304a6bf47aaSNickeau                    "user",
305a6bf47aaSNickeau                    "last_change",
306a6bf47aaSNickeau                    "creator",
307a6bf47aaSNickeau                    "contributor"
308a6bf47aaSNickeau                ];
309a6bf47aaSNickeau
310a6bf47aaSNickeau                foreach ($jsonArray as $key => $value) {
311a6bf47aaSNickeau
312a6bf47aaSNickeau                    $lowerCaseKey = trim(strtolower($key));
313a6bf47aaSNickeau
314a6bf47aaSNickeau                    // Not modifiable metadata
315a6bf47aaSNickeau                    if (in_array($lowerCaseKey, $notModifiableMeta)) {
316a6bf47aaSNickeau                        LogUtility::msg("Front Matter: The metadata ($lowerCaseKey) is a protected metadata and cannot be modified", LogUtility::LVL_MSG_WARNING);
317a6bf47aaSNickeau                        continue;
318a6bf47aaSNickeau                    }
319a6bf47aaSNickeau
320a6bf47aaSNickeau                    switch ($lowerCaseKey) {
321a6bf47aaSNickeau
322a6bf47aaSNickeau                        case Page::DESCRIPTION_PROPERTY:
323a6bf47aaSNickeau                            /**
324a6bf47aaSNickeau                             * Overwrite also the actual description
325a6bf47aaSNickeau                             */
326a6bf47aaSNickeau                            p_set_metadata($ID, array(Page::DESCRIPTION_PROPERTY => array(
327a6bf47aaSNickeau                                "abstract" => $value,
328a6bf47aaSNickeau                                "origin" => syntax_plugin_combo_frontmatter::CANONICAL
329a6bf47aaSNickeau                            )));
330a6bf47aaSNickeau                            /**
331a6bf47aaSNickeau                             * Continue because
332a6bf47aaSNickeau                             * the description value was already stored
333a6bf47aaSNickeau                             * We don't want to override it
334a6bf47aaSNickeau                             * And continue 2 because continue == break in a switch
335a6bf47aaSNickeau                             */
336a6bf47aaSNickeau                            continue 2;
337a6bf47aaSNickeau
338a6bf47aaSNickeau
339a6bf47aaSNickeau                        // Canonical should be lowercase
340a6bf47aaSNickeau                        case Page::CANONICAL_PROPERTY:
341a6bf47aaSNickeau                            $value = strtolower($value);
342a6bf47aaSNickeau                            break;
343a6bf47aaSNickeau
34437748cd8SNickeau                        case Page::IMAGE_META_PROPERTY:
34537748cd8SNickeau
34637748cd8SNickeau                            $imageValues = [];
34737748cd8SNickeau                            $this->aggregateImageValues($imageValues, $value);
34837748cd8SNickeau                            foreach ($imageValues as $imageValue) {
34937748cd8SNickeau                                $media = MediaLink::createFromRenderMatch($imageValue);
35037748cd8SNickeau                                $attributes = $media->toCallStackArray();
35137748cd8SNickeau                                syntax_plugin_combo_media::registerImageMeta($attributes, $renderer);
35237748cd8SNickeau                            }
35337748cd8SNickeau                            break;
35437748cd8SNickeau
355a6bf47aaSNickeau                    }
356a6bf47aaSNickeau                    // Set the value persistently
357a6bf47aaSNickeau                    p_set_metadata($ID, array($lowerCaseKey => $value));
358a6bf47aaSNickeau
359a6bf47aaSNickeau                }
360a6bf47aaSNickeau
361a6bf47aaSNickeau                $this->deleteKnownMetaThatAreNoMorePresent($jsonArray);
362a6bf47aaSNickeau
363a6bf47aaSNickeau                break;
364007225e5Sgerardnico
365007225e5Sgerardnico        }
366007225e5Sgerardnico        return true;
367007225e5Sgerardnico    }
368007225e5Sgerardnico
369007225e5Sgerardnico    /**
370007225e5Sgerardnico     *
371007225e5Sgerardnico     * @param array $json - The Json
372007225e5Sgerardnico     * Delete the controlled meta that are no more present if they exists
373007225e5Sgerardnico     * @return bool
374007225e5Sgerardnico     */
37537748cd8SNickeau    static public
376a6bf47aaSNickeau    function deleteKnownMetaThatAreNoMorePresent(array $json = array())
377007225e5Sgerardnico    {
378007225e5Sgerardnico        global $ID;
379007225e5Sgerardnico
380007225e5Sgerardnico        /**
381007225e5Sgerardnico         * The managed meta with the exception of
382007225e5Sgerardnico         * the {@link action_plugin_combo_metadescription::DESCRIPTION_META_KEY description}
383007225e5Sgerardnico         * because it's already managed by dokuwiki in description['abstract']
384007225e5Sgerardnico         */
385007225e5Sgerardnico        $managedMeta = [
38671f916b9Sgerardnico            Page::CANONICAL_PROPERTY,
38737748cd8SNickeau            Page::TYPE_META_PROPERTY,
38837748cd8SNickeau            Page::IMAGE_META_PROPERTY,
38937748cd8SNickeau            Page::COUNTRY_META_PROPERTY,
39037748cd8SNickeau            Page::LANG_META_PROPERTY,
39137748cd8SNickeau            Analytics::TITLE,
39237748cd8SNickeau            syntax_plugin_combo_disqus::META_DISQUS_IDENTIFIER,
39337748cd8SNickeau            Publication::OLD_META_KEY,
39437748cd8SNickeau            Publication::DATE_PUBLISHED,
39537748cd8SNickeau            Analytics::NAME,
39637748cd8SNickeau            CacheManager::DATE_CACHE_EXPIRATION_META_KEY,
39737748cd8SNickeau            action_plugin_combo_metagoogle::JSON_LD_META_PROPERTY,
39837748cd8SNickeau
399007225e5Sgerardnico        ];
400007225e5Sgerardnico        $meta = p_read_metadata($ID);
401007225e5Sgerardnico        foreach ($managedMeta as $metaKey) {
402007225e5Sgerardnico            if (!array_key_exists($metaKey, $json)) {
403007225e5Sgerardnico                if (isset($meta['persistent'][$metaKey])) {
404007225e5Sgerardnico                    unset($meta['persistent'][$metaKey]);
405007225e5Sgerardnico                }
406007225e5Sgerardnico            }
407007225e5Sgerardnico        }
408007225e5Sgerardnico        return p_save_metadata($ID, $meta);
409007225e5Sgerardnico    }
410007225e5Sgerardnico
41137748cd8SNickeau    private function updateImageStatistics($value, $renderer)
41237748cd8SNickeau    {
41337748cd8SNickeau        if(is_array($value)){
41437748cd8SNickeau            foreach($value as $subImage){
41537748cd8SNickeau                $this->updateImageStatistics($subImage, $renderer);
41637748cd8SNickeau            }
41737748cd8SNickeau        } else {
41837748cd8SNickeau            $media = MediaLink::createFromRenderMatch($value);
41937748cd8SNickeau            $attributes = $media->toCallStackArray();
42037748cd8SNickeau            syntax_plugin_combo_media::updateStatistics($attributes, $renderer);
42137748cd8SNickeau        }
42237748cd8SNickeau    }
42337748cd8SNickeau
42437748cd8SNickeau    private function aggregateImageValues(array &$imageValues, $value)
42537748cd8SNickeau    {
42637748cd8SNickeau        if (is_array($value)) {
42737748cd8SNickeau            foreach ($value as $subImageValue) {
42837748cd8SNickeau                $this->aggregateImageValues($imageValues,$subImageValue);
42937748cd8SNickeau            }
43037748cd8SNickeau        } else {
43137748cd8SNickeau            $imageValues[] = $value;
43237748cd8SNickeau        }
43337748cd8SNickeau    }
43437748cd8SNickeau
435007225e5Sgerardnico
436007225e5Sgerardnico}
437007225e5Sgerardnico
438