1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @package org.openpsa.relatedto |
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
|
|
|
use Symfony\Component\HttpFoundation\JsonResponse; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* relatedto ajax/ahah handler |
13
|
|
|
* |
14
|
|
|
* @package org.openpsa.relatedto |
15
|
|
|
*/ |
16
|
|
|
class org_openpsa_relatedto_handler_relatedto extends midcom_baseclasses_components_handler |
17
|
|
|
{ |
18
|
|
|
private midcom_core_dbaobject $_object; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* The mode we're in |
22
|
|
|
*/ |
23
|
|
|
private string $_mode; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* The sort order |
27
|
|
|
*/ |
28
|
|
|
private string $_sort = 'default'; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* The link array |
32
|
|
|
*/ |
33
|
|
|
private array $_links = []; |
34
|
|
|
|
35
|
2 |
|
public function _on_initialize() |
36
|
|
|
{ |
37
|
2 |
|
midcom::get()->style->prepend_component_styledir('org.openpsa.relatedto'); |
38
|
|
|
} |
39
|
|
|
|
40
|
2 |
|
public function _handler_render(string $guid, string $mode, string $sort = 'default') |
41
|
|
|
{ |
42
|
2 |
|
$this->_object = midcom::get()->dbfactory->get_object_by_guid($guid); |
43
|
2 |
|
$this->_mode = $mode; |
44
|
2 |
|
$this->_sort = $sort; |
45
|
|
|
|
46
|
2 |
|
if ($this->_mode !== 'in') { |
47
|
2 |
|
$this->_links['outgoing'] = $this->_get_object_links(true); |
48
|
|
|
} |
49
|
2 |
|
if ($this->_mode !== 'out') { |
50
|
2 |
|
$this->_links['incoming'] = $this->_get_object_links(false); |
51
|
|
|
} |
52
|
|
|
|
53
|
2 |
|
$this->_prepare_request_data(); |
54
|
2 |
|
midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . "/org.openpsa.relatedto/related_to.js"); |
55
|
2 |
|
midcom::get()->head->add_stylesheet(MIDCOM_STATIC_URL . "/org.openpsa.relatedto/related_to.css"); |
56
|
|
|
} |
57
|
|
|
|
58
|
2 |
|
private function _prepare_request_data() |
59
|
|
|
{ |
60
|
2 |
|
$ref = midcom_helper_reflector::get($this->_object); |
61
|
2 |
|
$object_label = $ref->get_object_label($this->_object); |
62
|
|
|
|
63
|
2 |
|
$object_url = midcom::get()->permalinks->create_permalink($this->_object->guid); |
64
|
2 |
|
$this->_view_toolbar->add_item([ |
65
|
2 |
|
MIDCOM_TOOLBAR_URL => $object_url, |
66
|
2 |
|
MIDCOM_TOOLBAR_LABEL => $this->_l10n_midcom->get('back'), |
67
|
2 |
|
MIDCOM_TOOLBAR_GLYPHICON => 'eject', |
68
|
2 |
|
]); |
69
|
2 |
|
$this->add_breadcrumb($object_url, $object_label); |
|
|
|
|
70
|
|
|
|
71
|
2 |
|
$this->add_breadcrumb("", $this->_l10n->get('view related information')); |
72
|
|
|
|
73
|
|
|
// Load "Create X" buttons for all the related info |
74
|
2 |
|
$relatedto_button_settings = org_openpsa_relatedto_plugin::common_toolbar_buttons_defaults(); |
75
|
|
|
|
76
|
2 |
|
$class_label = $ref->get_class_label(); |
77
|
2 |
|
$date_label = $this->_l10n->get_formatter()->datetime(); |
78
|
2 |
|
$relatedto_button_settings['wikinote']['wikiword'] = str_replace('/', '-', sprintf($this->_l10n->get('notes for %s %s on %s'), $class_label, $object_label, $date_label)); |
79
|
|
|
|
80
|
2 |
|
org_openpsa_relatedto_plugin::common_node_toolbar_buttons($this->_view_toolbar, $this->_object, $this->_topic->component, $relatedto_button_settings); |
81
|
2 |
|
org_openpsa_relatedto_plugin::add_journal_entry_button($this->_view_toolbar, $this->_object->guid); |
82
|
|
|
|
83
|
2 |
|
$this->_request_data['object'] = $this->_object; |
84
|
2 |
|
$this->_request_data['show_title'] = ($this->_mode == 'both'); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Get object's relatedtos |
89
|
|
|
* |
90
|
|
|
* @param boolean $inbound True means toGuid == $obj->guid, false fromGuid == $obj->guid |
91
|
|
|
*/ |
92
|
2 |
|
private function _get_object_links(bool $inbound) : array |
93
|
|
|
{ |
94
|
2 |
|
$arr = []; |
95
|
2 |
|
if ($inbound) { |
96
|
2 |
|
$other = 'from'; |
97
|
2 |
|
$mc = org_openpsa_relatedto_dba::new_collector('toGuid', $this->_object->guid); |
98
|
|
|
} else { |
99
|
2 |
|
$other = 'to'; |
100
|
2 |
|
$mc = org_openpsa_relatedto_dba::new_collector('fromGuid', $this->_object->guid); |
101
|
|
|
} |
102
|
|
|
|
103
|
2 |
|
$mc->add_constraint('status', '<>', org_openpsa_relatedto_dba::NOTRELATED); |
104
|
2 |
|
$links = $mc->get_rows([$other . 'Component', $other . 'Class', 'status', $other . 'Guid']); |
105
|
|
|
|
106
|
2 |
|
foreach ($links as $guid => $link) { |
107
|
|
|
//TODO: check for duplicates ? |
108
|
|
|
try { |
109
|
2 |
|
$result = ['other_obj' => midcom::get()->dbfactory->get_object_by_guid($link[$other . 'Guid'])]; |
110
|
|
|
} catch (midcom_error $e) { |
111
|
|
|
continue; |
112
|
|
|
} |
113
|
2 |
|
$result['link'] = [ |
114
|
2 |
|
'guid' => $guid, |
115
|
2 |
|
'component' => $link[$other . 'Component'], |
116
|
2 |
|
'class' => $link[$other . 'Class'], |
117
|
2 |
|
'status' => $link['status'] |
118
|
2 |
|
]; |
119
|
|
|
|
120
|
2 |
|
$result['sort_time'] = $this->_get_object_links_sort_time($result['other_obj']); |
121
|
2 |
|
$arr[] = $result; |
122
|
|
|
} |
123
|
2 |
|
return $arr; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* returns a unix timestamp for sorting relatedto arrays |
128
|
|
|
*/ |
129
|
2 |
|
private function _get_object_links_sort_time(midcom_core_dbaobject $obj) |
130
|
|
|
{ |
131
|
|
|
switch (true) { |
132
|
2 |
|
case $obj instanceof org_openpsa_calendar_event_dba: |
133
|
2 |
|
case $obj instanceof org_openpsa_projects_task_dba: |
134
|
|
|
return $obj->start; |
|
|
|
|
135
|
|
|
default: |
136
|
2 |
|
return $obj->metadata->created; |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Renders the selected view |
142
|
|
|
*/ |
143
|
2 |
|
public function _show_render(string $handler_id, array &$data) |
144
|
|
|
{ |
145
|
2 |
|
midcom_show_style('relatedto_start'); |
146
|
|
|
|
147
|
2 |
|
$this->_show_list('incoming'); |
148
|
2 |
|
$this->_show_list('outgoing'); |
149
|
|
|
|
150
|
2 |
|
midcom_show_style('relatedto_end'); |
151
|
|
|
} |
152
|
|
|
|
153
|
2 |
|
private function _show_list(string $direction) |
154
|
|
|
{ |
155
|
2 |
|
if (empty($this->_links[$direction])) { |
156
|
2 |
|
return; |
157
|
|
|
} |
158
|
2 |
|
$this->_request_data['direction'] = $direction; |
159
|
|
|
|
160
|
|
|
//Sort the array of links |
161
|
2 |
|
uasort($this->_links[$direction], [$this, '_sort_by_time']); |
162
|
|
|
|
163
|
2 |
|
midcom_show_style('relatedto_list_top'); |
164
|
|
|
|
165
|
2 |
|
foreach ($this->_links[$direction] as $linkdata) { |
166
|
2 |
|
$this->_render_line($linkdata['link'], $linkdata['other_obj']); |
167
|
|
|
} |
168
|
|
|
|
169
|
2 |
|
midcom_show_style('relatedto_list_bottom'); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Code to sort array by key 'sort_time', from smallest to greatest |
174
|
|
|
*/ |
175
|
|
|
private function _sort_by_time($a, $b) |
176
|
|
|
{ |
177
|
|
|
$ap = $a['sort_time']; |
178
|
|
|
$bp = $b['sort_time']; |
179
|
|
|
if ($this->_sort == 'reverse') { |
180
|
|
|
return $bp <=> $ap; |
181
|
|
|
} |
182
|
|
|
return $ap <=> $bp; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Renders single link line |
187
|
|
|
* |
188
|
|
|
* @param array $link The necessary link information |
189
|
|
|
*/ |
190
|
2 |
|
private function _render_line(array $link, midcom_core_dbaobject &$other_obj) |
191
|
|
|
{ |
192
|
2 |
|
$this->_request_data['link'] = $link; |
193
|
2 |
|
$this->_request_data['other_obj'] =& $other_obj; |
194
|
2 |
|
$this->_request_data['icon'] = midcom_helper_reflector::get_object_icon($other_obj); |
195
|
|
|
|
196
|
2 |
|
if (get_class($other_obj) != $link['class']) { |
197
|
2 |
|
$other_obj = new $link['class']($other_obj); |
198
|
|
|
} |
199
|
|
|
|
200
|
2 |
|
switch ($link['class']) { |
201
|
|
|
case net_nemein_wiki_wikipage::class: |
202
|
|
|
$this->_render_line_wikipage($other_obj); |
203
|
|
|
break; |
204
|
|
|
case org_openpsa_calendar_event_dba::class: |
205
|
|
|
$this->_render_line_event($other_obj); |
206
|
|
|
break; |
207
|
|
|
case org_openpsa_projects_task_dba::class: |
208
|
|
|
case org_openpsa_projects_project::class: |
209
|
|
|
$this->_render_line_task($other_obj); |
210
|
|
|
break; |
211
|
|
|
case org_openpsa_documents_document_dba::class: |
212
|
|
|
$this->_render_line_document($other_obj); |
213
|
|
|
break; |
214
|
|
|
case org_openpsa_sales_salesproject_dba::class: |
215
|
2 |
|
$this->_render_line_salesproject($other_obj); |
216
|
2 |
|
break; |
217
|
|
|
case org_openpsa_invoices_invoice_dba::class: |
218
|
|
|
$this->_render_line_invoice($other_obj); |
219
|
|
|
break; |
220
|
|
|
default: |
221
|
|
|
$this->_render_line_default($link, $other_obj); |
222
|
|
|
break; |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
|
226
|
2 |
|
private function get_node_url(string $component) |
227
|
|
|
{ |
228
|
2 |
|
return org_openpsa_core_siteconfig::get_instance()->get_node_full_url($component); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Renders a document line |
233
|
|
|
*/ |
234
|
|
|
private function _render_line_document(org_openpsa_documents_document_dba $other_obj) |
235
|
|
|
{ |
236
|
|
|
$this->_request_data['document_url'] = midcom::get()->permalinks->create_permalink($other_obj->guid); |
237
|
|
|
|
238
|
|
|
midcom_show_style('relatedto_list_item_document'); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Renders a wikipage line |
243
|
|
|
*/ |
244
|
|
|
private function _render_line_wikipage(net_nemein_wiki_wikipage $other_obj) |
245
|
|
|
{ |
246
|
|
|
$nap = new midcom_helper_nav(); |
247
|
|
|
$node = $nap->get_node($other_obj->topic); |
248
|
|
|
if (!$node) { |
249
|
|
|
// The page isn't from this site |
250
|
|
|
return; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
$this->_request_data['page_url'] = $node[MIDCOM_NAV_FULLURL]; |
254
|
|
|
|
255
|
|
|
midcom_show_style('relatedto_list_item_wikipage'); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Renders an event line |
260
|
|
|
*/ |
261
|
|
|
private function _render_line_event(org_openpsa_calendar_event_dba $other_obj) |
262
|
|
|
{ |
263
|
|
|
$this->_request_data['raw_url'] = ''; |
264
|
|
|
|
265
|
|
|
$title = $other_obj->title; |
266
|
|
|
|
267
|
|
|
if ($url = $this->get_node_url('org.openpsa.calendar')) { |
268
|
|
|
//Calendar node found, render a better view |
269
|
|
|
$this->_request_data['raw_url'] = $url . 'event/raw/' . $other_obj->guid . '/'; |
270
|
|
|
$workflow = $this->get_workflow('viewer'); |
271
|
|
|
$title = '<a href="' . $url . 'event/' . $other_obj->guid . '/" ' . $workflow->render_attributes() . '>' . $title . "</a>\n"; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
$this->_request_data['title'] = $title; |
275
|
|
|
|
276
|
|
|
midcom_show_style('relatedto_list_item_event'); |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* Renders a task line |
281
|
|
|
* |
282
|
|
|
* @param object $other_obj The link target |
283
|
|
|
*/ |
284
|
|
|
private function _render_line_task($other_obj) |
285
|
|
|
{ |
286
|
|
|
if ($other_obj instanceof org_openpsa_projects_task_dba) { |
287
|
|
|
$type = 'task'; |
288
|
|
|
} else { |
289
|
|
|
$type = 'project'; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
$title = $other_obj->title; |
293
|
|
|
|
294
|
|
|
if ($url = $this->get_node_url('org.openpsa.projects')) { |
295
|
|
|
$title = '<a href="' . $url . $type . '/' . $other_obj->guid . '/" target="task_' . $other_obj->guid . '">' . $title . "</a>\n"; |
296
|
|
|
} |
297
|
|
|
$this->_request_data['title'] = $title; |
298
|
|
|
$this->_request_data['type'] = $type; |
299
|
|
|
|
300
|
|
|
midcom_show_style('relatedto_list_item_task'); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Renders a sales project line |
305
|
|
|
*/ |
306
|
2 |
|
private function _render_line_salesproject(org_openpsa_sales_salesproject_dba $other_obj) |
307
|
|
|
{ |
308
|
2 |
|
$title = $other_obj->title; |
309
|
|
|
|
310
|
2 |
|
if ($url = $this->get_node_url('org.openpsa.sales')) { |
311
|
2 |
|
$title = '<a href="' . $url . 'salesproject/' . $other_obj->guid . '/" target="salesproject_' . $other_obj->guid . '">' . $title . "</a>\n"; |
312
|
|
|
} |
313
|
|
|
|
314
|
2 |
|
$this->_request_data['title'] = $title; |
315
|
|
|
|
316
|
2 |
|
midcom_show_style('relatedto_list_item_salesproject'); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Renders an invoice line |
321
|
|
|
*/ |
322
|
|
|
private function _render_line_invoice(org_openpsa_invoices_invoice_dba $other_obj) |
323
|
|
|
{ |
324
|
|
|
$title = $this->_i18n->get_string('invoice', 'org.openpsa.invoices') . ' ' . $other_obj->get_label(); |
325
|
|
|
|
326
|
|
|
if ($url = $this->get_node_url('org.openpsa.invoices')) { |
327
|
|
|
$title = '<a href="' . $url . 'invoice/' . $other_obj->guid . '/" target="invoice_' . $other_obj->guid . '">' . $title . "</a>\n"; |
328
|
|
|
} |
329
|
|
|
$this->_request_data['title'] = $title; |
330
|
|
|
|
331
|
|
|
midcom_show_style('relatedto_list_item_invoice'); |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
/** |
335
|
|
|
* Default line rendering, used if a specific renderer cannot be found |
336
|
|
|
* |
337
|
|
|
* Tries to find certain properties likely to hold semi-useful information about |
338
|
|
|
* the object, failing that outputs class and guid. |
339
|
|
|
* |
340
|
|
|
* @param array $link The necessary link information |
341
|
|
|
* @param object $other_obj The link target |
342
|
|
|
*/ |
343
|
|
|
private function _render_line_default(array $link, $other_obj) |
344
|
|
|
{ |
345
|
|
|
$class = get_class($other_obj); |
346
|
|
|
|
347
|
|
|
$ref = midcom_helper_reflector::get($other_obj); |
348
|
|
|
$object_label = $ref->get_object_label($other_obj); |
349
|
|
|
if ($url = midcom::get()->permalinks->create_permalink($other_obj->guid)) { |
350
|
|
|
$object_label = '<a href="' . $url . '" target="' . $class . $this->_object->guid . '">' . $object_label . '</a>'; |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
echo " <li class=\"unknown {$class}\" id=\"org_openpsa_relatedto_line_{$link['guid']}\">\n"; |
354
|
|
|
echo ' <span class="icon">' . $this->_request_data['icon'] . "</span>\n"; |
355
|
|
|
echo ' <span class="title">' . $object_label . "</span>\n"; |
356
|
|
|
echo ' <ul class="metadata">'; |
357
|
|
|
echo ' <li>' . $ref->get_class_label() . "</li>\n"; |
358
|
|
|
echo " </ul>\n"; |
359
|
|
|
self::render_line_controls($link, $other_obj); |
360
|
|
|
echo "</li>\n"; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
/** |
364
|
|
|
* Renders (if necessary) controls for confirming/deleting link object |
365
|
|
|
* |
366
|
|
|
* @param array $link The necessary link information |
367
|
|
|
* @param object $other_obj The link target |
368
|
|
|
*/ |
369
|
2 |
|
public static function render_line_controls(array $link, $other_obj) |
370
|
|
|
{ |
371
|
2 |
|
echo "<ul class=\"relatedto_toolbar\" data-link-guid=\"{$link['guid']}\" data-other-guid=\"{$other_obj->guid}\">\n"; |
372
|
|
|
|
373
|
2 |
|
if (in_array($link['component'], ['net.nemein.wiki', 'org.openpsa.calendar'])) { |
374
|
|
|
echo "<li><input type=\"button\" class=\"button info\" value=\"" . midcom::get()->i18n->get_string('details', 'org.openpsa.relatedto') . "\" /></li>\n"; |
375
|
|
|
} |
376
|
|
|
|
377
|
2 |
|
if ($link['status'] == org_openpsa_relatedto_dba::SUSPECTED) { |
378
|
|
|
echo "<li><input type=\"button\" class=\"button confirm\" value=\"" . midcom::get()->i18n->get_string('confirm relation', 'org.openpsa.relatedto') . "\" /></li>\n"; |
379
|
|
|
echo "<li><input type=\"button\" class=\"button deny\" value=\"" . midcom::get()->i18n->get_string('deny relation', 'org.openpsa.relatedto') . "\" /></li>\n"; |
380
|
|
|
} |
381
|
|
|
|
382
|
2 |
|
echo '<li><input type="button" class="button delete" id="org_openpsa_relatedto_delete-' . $link['guid'] . '" value="' . midcom::get()->i18n->get_string('delete relation', 'org.openpsa.relatedto') . '" /></li>'; |
383
|
2 |
|
echo "</ul>\n"; |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
public function _handler_ajax(string $guid, string $mode) |
387
|
|
|
{ |
388
|
|
|
midcom::get()->auth->require_valid_user(); |
389
|
|
|
|
390
|
|
|
$response = ['result' => false]; |
391
|
|
|
|
392
|
|
|
try { |
393
|
|
|
$this->_object = midcom::get()->dbfactory->get_object_by_guid($guid); |
394
|
|
|
if (!($this->_object instanceof org_openpsa_relatedto_dba)) { |
395
|
|
|
$response['status'] = "method requires guid of a link object as an argument"; |
396
|
|
|
} |
397
|
|
|
} catch (midcom_error $e) { |
398
|
|
|
$response['status'] = "error: " . $e->getMessage(); |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
if (empty($response['status'])) { |
402
|
|
|
$this->_object->status = $mode == 'deny' ? org_openpsa_relatedto_dba::NOTRELATED : org_openpsa_relatedto_dba::CONFIRMED; |
|
|
|
|
403
|
|
|
$response['result'] = $this->_object->update(); |
404
|
|
|
$response['status'] = 'error:' . midcom_connection::get_error_string(); |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
return new JsonResponse($response); |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
public function _handler_delete(string $guid) |
411
|
|
|
{ |
412
|
|
|
midcom::get()->auth->require_valid_user(); |
413
|
|
|
|
414
|
|
|
try { |
415
|
|
|
$relation = new org_openpsa_relatedto_dba($guid); |
416
|
|
|
$result = $relation->delete(); |
417
|
|
|
$status = 'Last message: ' . midcom_connection::get_error_string(); |
418
|
|
|
} catch (midcom_error $e) { |
419
|
|
|
$result = false; |
420
|
|
|
$status = "Object '{$guid}' could not be loaded, error:" . $e->getMessage(); |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
return new JsonResponse(['result' => $result, 'status' => $status]); |
424
|
|
|
} |
425
|
|
|
} |
426
|
|
|
|