1<?php
2/**
3 * DokuWiki Plugin snippets (Helper Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Myron Turner <turnermm02@shaw.ca>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12class helper_plugin_snippets extends DokuWiki_Plugin {
13
14    private $metafn;
15
16    function __construct() {
17        $this->metafn = metaFN('snippets_upd','.ser');
18        if(!file_exists($this->metafn)) {
19            $ar = array('snip'=>array(), 'doc'=>array());
20            io_saveFile($this->metafn,serialize($ar));
21        }
22    }
23
24    /**
25     * Return info about supported methods in this Helper Plugin
26     *
27     * @return array of public methods
28     */
29    public function getMethods() {
30        return array(
31            array(
32                'name'   => 'mostRecentVersion',
33                'desc'   => 'checks metadata for most recent version of  $id',
34                'params' => array(
35                    'id'         => 'string'
36                ),
37                'return' => array('timestamp' => 'integer')
38            ),
39            array(
40                'name' => 'snippetWasUpdated',
41                'desc' => 'check if snippet inserted in a page was updated to most recent version',
42                'params' => array( 'id'=>'string', 'snippet'=>'string'),
43                'return' =>array('timstamp'=>'boolean')
44            ),
45           array(
46                'name' => 'updateMetaTime',
47                'desc' => 'sets and updates timestamp of snippet in metafile of page where snippet is inserted',
48                'params' => array(
49                    'id' => 'string',
50                    'snippet' => 'string',
51                    'set_time' => 'int'
52                ),
53                'return' =>array()
54            ),
55           array(
56                'name' => 'insertSnippet',
57                'desc' => 'inserts updated snippet into page',
58                'params' => array(
59                  'result (reference)' => 'string',
60                  'page_id' => 'string'
61                ),
62                'return' =>array()
63            ),
64        );
65    }
66
67    /**
68     *  If the metadata shows that the (snippet) file has been restored from an earlier version, that is the most recent
69     *  version; otherwise the last modified date is the most recent version
70     *  @param string  $id  id of page to be checked for most recent version
71     *  @modified int  timestamp
72     *  @return int timestamp
73    */
74    function mostRecentVersion($id, &$modified) {
75        $modified = p_get_metadata($id, 'date modified');
76        $sum = p_get_metadata($id, 'last_change sum');
77        if($sum && preg_match('#restored\s+(\(.*?\))#',$sum,$matches)){
78            return  strtotime(trim($matches[1],'()'));
79        }
80        return $modified;
81  }
82    /**
83      *  Checks the most recent version of  snippet against the timestamp for snippet
84      *  stored in the meta file for page into which the snippet has been inserted
85      *  If the timestamps are the same then the snippet has been updated
86      *  @param $id string  id of page where snippet was inserted
87      *  @param snippet string  page id of snippet
88    */
89   function snippetWasUpdated($id, $snippet) {
90       $isref = p_get_metadata($id, 'relation isreferencedby' );
91       $snip_time = $isref['snippets'][$snippet] ;
92       if(empty($snip_time)) {
93          $this->updateMetaTime($id,$snippet);
94       }
95       $time_stamp = $this->mostRecentVersion($snippet, $modified);
96
97        return $snip_time  ==  $time_stamp;
98   }
99
100    /**
101      *  Updates time stamp of snippet in metafile of page where snippet is inserted
102    */
103    function updateMetaTime($id,$snippet) {
104    global $ID;
105    if(empty($ID)) $ID = $id;
106        if(!$snippet) return;
107    $isref = p_get_metadata($id, 'relation isreferencedby');
108        $time =  $this->mostRecentVersion($snippet, $modified) ;
109
110    $data = array();
111
112    if(!is_array($isref)) {
113       $is_array= array();
114    }
115    $isref['snippets'][$snippet] = $time;
116
117    $data['relation']['isreferencedby']=$isref;
118     p_set_metadata($id, $data);
119}
120
121    /**
122      * Inserts updated snippets in page after checking to see if snippets have been updated
123      * @param result:   reference to string that holds the page contents
124      * @param page_id  string
125      * @ param $force boolean: if true, latest snippet will be inserted into Old Revisions
126    */
127    function insertSnippet(&$result, $page_id,$force) {
128         if(!file_exists(wikiFN($page_id))) return;
129         $snip_data=unserialize(io_readFile($this->metafn,false));
130         if(!array_key_exists($page_id,$snip_data['doc'])) return; //Check if page contains snippet
131
132         global $replacement;  // will hold new version of snippet
133
134         $snippets = $snip_data['doc'][$page_id];
135         $page_t = filemtime(wikiFN($page_id));
136
137         foreach ($snippets as $snip) {
138             $snip_file = wikiFN($snip);
139             if(!file_exists($snip_file)) continue;
140             $snip_t = filemtime($snip_file);
141
142             if($snip_t < $page_t && $this->snippetWasUpdated($page_id,$snip) && !$force) {
143                   continue;
144             }
145
146             $replacement =  trim(preg_replace('/<snippet>.*?<\/snippet>/s', '', io_readFile($snip_file)));
147             $snip_id = preg_quote($snip);
148             $result = preg_replace_callback(
149                "|(?<=~~SNIPPET_O)\d*(~~$snip_id~~).*?(?=~~SNIPPET_C~~$snip_id~~)|ms",
150                     function($matches){
151                         global $replacement;
152                         return  time()  . $matches[1]. "\n" .$replacement  . "\n";  // time() makes each update unique for renderer
153                  },
154                  $result
155                );
156          }
157
158    }
159
160    /*
161      *    create new page array for a snippet entry in the database
162      *
163      *    @ $pages  array   page ids currently held for snippet
164      *    @ $id  string        id of current page
165    */
166    function getPageArray($pages, $id) {
167        $id_array = array();
168        foreach($pages as $page_id) {
169            if($id != $page_id) {  // remove current page from array of pages held by the snippet
170                $id_array[] = $page_id;
171            }
172        }
173        return $id_array;
174    }
175
176   function getMetaFileName() {
177       return $this->metafn;
178   }
179
180}
181// vim:ts=4:sw=4:et:
182