Completed
Push — master ( 7668ba...b7b643 )
by Andreas
08:40
created

net_nemein_wiki_wikipage::update_link_cache()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 33
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 18
nc 6
nop 0
dl 0
loc 33
rs 8.5806
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package net.nemein.wiki
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * Wiki note helper class to be used by other components
11
 *
12
 * @package net.nemein.wiki
13
 */
14
class net_nemein_wiki_wikipage extends midcom_db_article
1 ignored issue
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
15
{
16
    public $autodelete_dependents = array
17
    (
18
        'net_nemein_wiki_link_dba' => 'frompage'
19
    );
20
21
    public function _on_loaded()
22
    {
23
        // Backwards compatibility
24
        if ($this->name == '')
25
        {
26
            $generator = midcom::get()->serviceloader->load('midcom_core_service_urlgenerator');
27
            $this->name = $generator->from_string($this->title);
28
            $this->update();
29
        }
30
    }
31
32
    public function _on_creating()
33
    {
34
        if (   $this->title == ''
35
            || !$this->topic)
36
        {
37
            // We must have wikiword and topic at this stage
38
            return false;
39
        }
40
41
        // Check for duplicates
42
        $qb = net_nemein_wiki_wikipage::new_query_builder();
43
        $qb->add_constraint('topic', '=', $this->topic);
44
        $qb->add_constraint('title', '=', $this->title);
45
        if ($qb->count() > 0)
46
        {
47
            midcom_connection::set_error(MGD_ERR_OBJECT_NAME_EXISTS);
48
            return false;
49
        }
50
51
        // Generate URL-clean name
52
        if ($this->name != 'index')
53
        {
54
            $generator = midcom::get()->serviceloader->load('midcom_core_service_urlgenerator');
55
            $this->name = $generator->from_string($this->title);
56
        }
57
        return true;
58
    }
59
60
    public function _on_updating()
61
    {
62
        if (midcom::get()->auth->user)
63
        {
64
            // Place current user in the page authors list
65
            $authors = explode('|', substr($this->metadata->authors, 1, -1));
66
            if (!in_array(midcom::get()->auth->user->guid, $authors))
67
            {
68
                $authors[] = midcom::get()->auth->user->guid;
69
                $this->metadata->authors = '|' . implode('|', $authors) . '|';
70
            }
71
        }
72
        return parent::_on_updating();
73
    }
74
75
    public function _on_updated()
76
    {
77
        parent::_on_updated();
78
        $this->update_watchers();
79
        $this->update_link_cache();
80
    }
81
82
    /**
83
     * Caches links in the wiki page into database for faster "what links here" queries
84
     */
85
    private function update_link_cache()
86
    {
87
        $parser = new net_nemein_wiki_parser($this);
88
        $links_in_content = $parser->find_links_in_content();
89
90
        $qb = net_nemein_wiki_link_dba::new_query_builder();
91
        $qb->add_constraint('frompage', '=', $this->id);
92
        $links_in_db = $qb->execute();
93
94
        // Check links in DB versus links in content to see what needs to be removed
95
        foreach ($links_in_db as $link)
0 ignored issues
show
Bug introduced by
The expression $links_in_db of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
96
        {
97
            if (!array_key_exists($link->topage, $links_in_content))
98
            {
99
                // This link is not any more in content, remove
100
                $link->delete();
101
                continue;
102
            }
103
            //no change for this link
104
            unset($links_in_content[$link->topage]);
105
        }
106
107
        // What is still left needs to be added
108
        $links_in_content = array_keys($links_in_content);
109
        foreach ($links_in_content as $wikilink)
110
        {
111
            $link = new net_nemein_wiki_link_dba();
112
            $link->frompage = $this->id;
113
            $link->topage = $wikilink;
114
            debug_add("Creating net_nemein_wiki_link_dba: from page #{$link->frompage}, to page: '$link->topage'");
115
            $link->create();
116
        }
117
    }
118
119
    private function list_watchers()
120
    {
121
        $topic = new midcom_db_topic($this->topic);
122
        // Get list of people watching this page
123
        $watchers = array();
124
        $qb = new midgard_query_builder('midgard_parameter');
125
        $qb->add_constraint('domain', '=', 'net.nemein.wiki:watch');
126
        $qb->begin_group('OR');
127
            // List people watching the whole wiki
128
            $qb->add_constraint('parentguid', '=', $topic->guid);
129
            // List people watching this particular page
130
            $qb->add_constraint('parentguid', '=', $this->guid);
131
        $qb->end_group();
132
        $watcher_params = $qb->execute();
133
134
        foreach ($watcher_params as $parameter)
135
        {
136
            if (in_array($parameter->name, $watchers))
137
            {
138
                // We found this one already, skip
139
                continue;
140
            }
141
142
            $watchers[] = $parameter->name;
143
        }
144
        return $watchers;
145
    }
146
147
    private function update_watchers()
148
    {
149
        $watchers = $this->list_watchers();
150
        if (empty($watchers))
151
        {
152
            return;
153
        }
154
155
        $diff = $this->get_diff();
156
        if (empty($diff))
157
        {
158
            // No sense to email empty diffs
159
            return;
160
        }
161
162
        // Construct the message
163
        $message = array();
164
        $user_string = midcom::get()->i18n->get_string('anonymous', 'net.nemein.wiki');
165
        if (midcom::get()->auth->user)
166
        {
167
            $user = midcom::get()->auth->user->get_storage();
168
            $user_string = $user->name;
169
        }
170
        // Title for long notifications
171
        $message['title'] = sprintf(midcom::get()->i18n->get_string('page %s has been updated by %s', 'net.nemein.wiki'), $this->title, $user_string);
172
        // Content for long notifications
173
        $message['content']  = "{$message['title']}\n\n";
174
175
        // TODO: Get RCS diff here
176
        $message['content'] .= midcom::get()->i18n->get_string('page modifications', 'net.nemein.wiki') . ":\n";
177
        $message['content'] .= "\n{$diff}\n\n";
178
179
        $message['content'] .= midcom::get()->i18n->get_string('link to page', 'net.nemein.wiki') . ":\n";
180
        $message['content'] .= midcom::get()->permalinks->create_permalink($this->guid);
181
182
        // Content for short notifications
183
        $topic = new midcom_db_topic($this->topic);
184
        $message['abstract'] = sprintf(midcom::get()->i18n->get_string('page %s has been updated by %s in wiki %s', 'net.nemein.wiki'), $this->title, $user_string, $topic->extra);
185
186
        debug_add("Processing list of Wiki subscribers");
187
188
        // Send the message out
189
        foreach ($watchers as $recipient)
190
        {
191
            debug_add("Notifying {$recipient}...");
192
            org_openpsa_notifications::notify('net.nemein.wiki:page_updated', $recipient, $message);
193
        }
194
    }
195
196
    private function get_diff($field = 'content')
197
    {
198
        // Load the RCS handler
199
        $rcs = midcom::get()->rcs;
200
        $rcs_handler = $rcs->load_handler($this);
201
        if (!$rcs_handler)
202
        {
203
            return null;
204
        }
205
206
        // Find out what versions to diff
207
        $history = $rcs_handler->list_history_numeric();
208
        if (count($history) < 2)
209
        {
210
            return '';
211
        }
212
        $this_version = $history[0];
213
        $prev_version = $history[1];
214
215
        try
216
        {
217
            $diff_fields = $rcs_handler->get_diff($prev_version, $this_version, 'unified');
218
        }
219
        catch (midcom_error $e)
220
        {
221
            $e->log();
222
            return '';
223
        }
224
225
        if (!array_key_exists('diff', $diff_fields[$field]))
226
        {
227
            // No differences
228
            return '';
229
        }
230
231
        return $diff_fields[$field]['diff'];
232
    }
233
}
234