Completed
Push — master ( 01c28b...0d4f0a )
by Andreas
17:26
created

midgard_admin_asgard_handler_object_manage   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 501
Duplicated Lines 0 %

Test Coverage

Coverage 76.21%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 223
dl 0
loc 501
ccs 173
cts 227
cp 0.7621
rs 4.08
c 5
b 0
f 0
wmc 59

16 Methods

Rating   Name   Duplication   Size   Complexity  
A _handler_open() 0 4 1
A _load_schemadb() 0 5 1
A _load_object() 0 11 3
A _prepare_request_data() 0 7 1
A _handler_view() 0 19 1
B _handler_create() 0 52 9
A _show_create() 0 16 4
B get_defaults() 0 31 10
A _show_copy() 0 11 2
A _add_jscripts() 0 9 1
A _handler_edit() 0 26 3
A _handler_delete() 0 39 4
A _handler_copy() 0 47 5
B _process_copy() 0 40 6
A _object_to_jsdata() 0 15 2
A _prepare_relocate() 0 26 6

How to fix   Complexity   

Complex Class

Complex classes like midgard_admin_asgard_handler_object_manage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use midgard_admin_asgard_handler_object_manage, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package midgard.admin.asgard
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 midcom\datamanager\datamanager;
10
use midcom\datamanager\controller;
11
use midcom\datamanager\schemadb;
12
use Symfony\Component\HttpFoundation\Request;
13
14
/**
15
 * Object management interface
16
 *
17
 * @package midgard.admin.asgard
18
 */
19
class midgard_admin_asgard_handler_object_manage extends midcom_baseclasses_components_handler
20
{
21
    use midgard_admin_asgard_handler;
22
23
    /**
24
     * Some object
25
     *
26
     * @var midcom_core_dbaobject
27
     */
28
    private $_object;
29
30
    /**
31
     * Some newly created object
32
     *
33
     * @var midcom_core_dbaobject
34
     */
35
    private $_new_object;
36
37
    /**
38
     * The Datamanager of the object to display.
39
     *
40
     * @var datamanager
41
     */
42
    private $datamanager;
43
44
    /**
45
     * The Controller of the object used for editing
46
     *
47
     * @var controller
48
     */
49
    private $controller;
50
51
    /**
52
     * The schema database in use, available only while a datamanager is loaded.
53
     *
54
     * @var schemadb
55
     */
56
    private $schemadb;
57
58
    /**
59
     * Retrieve the object from the db
60
     *
61
     * @param string $guid GUID
62
     */
63 5
    private function _load_object($guid)
64
    {
65
        try {
66 5
            $this->_object = midcom::get()->dbfactory->get_object_by_guid($guid);
67
        } catch (midcom_error $e) {
68
            if (midcom_connection::get_error() == MGD_ERR_OBJECT_DELETED) {
69
                $relocate = $this->router->generate('object_deleted', ['guid' => $guid]);
70
                midcom::get()->relocate($relocate);
71
            }
72
73
            throw $e;
74
        }
75 5
    }
76
77
    /**
78
     * Simple helper which references all important members to the request data listing
79
     * for usage within the style listing.
80
     */
81 8
    private function _prepare_request_data()
82
    {
83 8
        $this->_request_data['object'] = $this->_object;
84 8
        $this->_request_data['controller'] = $this->controller;
85 8
        $this->_request_data['datamanager'] = $this->datamanager;
86 8
        $this->_request_data['asgard_prefix'] = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . '__mfa/asgard/';
0 ignored issues
show
Bug introduced by
Are you sure midcom_core_context::get...M_CONTEXT_ANCHORPREFIX) of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

86
        $this->_request_data['asgard_prefix'] = /** @scrutinizer ignore-type */ midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . '__mfa/asgard/';
Loading history...
87 8
        $this->_request_data['style_helper'] = new midgard_admin_asgard_stylehelper($this->_request_data);
88 8
    }
89
90
    /**
91
     * Loads the schemadb from the helper class
92
     */
93 8
    private function _load_schemadb($type = null, $include_fields = null, $add_copy_fields = false)
94
    {
95 8
        $schema_helper = new midgard_admin_asgard_schemadb($this->_object, $this->_config, $type);
96 8
        $schema_helper->add_copy_fields = $add_copy_fields;
97 8
        $this->schemadb = $schema_helper->create($include_fields);
98 8
    }
99
100
    /**
101
     * Looks up the user's default mode and redirects there. This is mainly useful for links from outside Asgard
102
     *
103
     * @param string $guid The object's GUID
104
     * @param array $data The local request data.
105
     */
106
    public function _handler_open($guid, array &$data)
107
    {
108
        $relocate = $this->router->generate('object_' . $data['default_mode'], ['guid' => $guid]);
109
        return new midcom_response_relocate($relocate);
110
    }
111
112
    /**
113
     * Object display
114
     *
115
     * @param mixed $handler_id The ID of the handler.
116
     * @param string $guid The object's GUID
117
     * @param array $data The local request data.
118
     */
119 1
    public function _handler_view($handler_id, $guid, array &$data)
120
    {
121 1
        $this->_load_object($guid);
122
123 1
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', null, 'midgard_admin_asgard_plugin');
124
125 1
        $this->_load_schemadb();
126
127
        // Hide the revision message
128 1
        $this->schemadb->get_first()->get_field('_rcs_message')['hidden'] = true;
129
130 1
        $this->datamanager = new datamanager($this->schemadb);
131 1
        $this->datamanager
132 1
            ->set_storage($this->_object)
133 1
            ->get_form(); // currently needed to add head elements
134
135 1
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
136 1
        $this->_prepare_request_data();
137 1
        return $this->get_response('midgard_admin_asgard_object_view');
138
    }
139
140
    /**
141
     * Object editing view
142
     *
143
     * @param Request $request The request object
144
     * @param mixed $handler_id The ID of the handler.
145
     * @param string $guid The object's GUID
146
     * @param array $data The local request data.
147
     */
148 1
    public function _handler_edit(Request $request, $handler_id, $guid, array &$data)
149
    {
150 1
        $this->_load_object($guid);
151
152 1
        $this->_object->require_do('midgard:update');
153 1
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', null, 'midgard_admin_asgard_plugin');
154
155 1
        $this->_load_schemadb();
156 1
        $dm = new datamanager($this->schemadb);
157 1
        $this->controller = $dm
158 1
            ->set_storage($this->_object, 'default')
159 1
            ->get_controller();
160 1
        switch ($this->controller->handle($request)) {
161 1
            case 'save':
162
                // Reindex the object
163
                //$indexer = midcom::get()->indexer;
164
                //net_nemein_wiki_viewer::index($this->_request_data['controller']->datamanager, $indexer, $this->_topic);
165
                //Fall-through
166
167 1
            case 'cancel':
168
                return $this->_prepare_relocate($this->_object);
169
        }
170
171 1
        $this->_prepare_request_data();
172 1
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
173 1
        return $this->get_response('midgard_admin_asgard_object_edit');
174
    }
175
176
    /**
177
     * Object creating view
178
     *
179
     * @param Request $request The request object
180
     * @param mixed $handler_id The ID of the handler.
181
     * @param array $args The argument list.
182
     * @param array $data The local request data.
183
     */
184 3
    public function _handler_create(Request $request, $handler_id, array $args, array &$data)
185
    {
186 3
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', null, 'midgard_admin_asgard_plugin');
187
188 3
        $data['current_type'] = $args[0];
189 3
        $create_type = midcom::get()->dbclassloader->get_midcom_class_name_for_mgdschema_object($data['current_type']);
190 3
        if (!$create_type) {
191
            throw new midcom_error_notfound('Failed to find type for the new object');
192
        }
193 3
        $this->_new_object = new $create_type();
194
195 3
        if (in_array($handler_id, ['object_create_toplevel', 'object_create_chooser'])) {
196 2
            midcom::get()->auth->require_user_do('midgard:create', null, $create_type);
197
198 2
            $data['view_title'] = sprintf($this->_l10n_midcom->get('create %s'), midgard_admin_asgard_plugin::get_type_label($data['current_type']));
199
        } else {
200 1
            $this->_object = midcom::get()->dbfactory->get_object_by_guid($args[1]);
201 1
            $this->_object->require_do('midgard:create');
202 1
            midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
203
        }
204
205 3
        $this->_load_schemadb($create_type);
206
207 3
        $dm = new datamanager($this->schemadb);
208 3
        $this->controller = $dm
209 3
            ->set_defaults($this->get_defaults($request, $create_type))
210 3
            ->set_storage($this->_new_object, 'default')
211 3
            ->get_controller();
212
213 3
        switch ($this->controller->handle($request)) {
214 3
            case 'save':
215
                // Reindex the object
216
                //$indexer = midcom::get()->indexer;
217
                //net_nemein_wiki_viewer::index($this->_request_data['controller']->datamanager, $indexer, $this->_topic);
218
219
                if ($handler_id !== 'object_create_chooser') {
220
                    return $this->_prepare_relocate($this->_new_object);
221
                }
222
                break;
223 3
            case 'cancel':
224
                $data['cancelled'] = true;
225
                if ($handler_id !== 'object_create_chooser') {
226
                    if ($this->_object) {
227
                        return $this->_prepare_relocate($this->_object);
228
                    }
229
                    return new midcom_response_relocate($this->router->generate('type', ['type' => $args[0]]));
230
                }
231
        }
232
233 3
        $this->_prepare_request_data();
234 3
        if ($handler_id !== 'object_create_chooser') {
235 2
            return $this->get_response();
236
        }
237 1
    }
238
239 3
    private function get_defaults(Request $request, $new_type) : array
240
    {
241 3
        $defaults = [];
242 3
        if ($this->_object) {
243
            // Figure out the linking property
244 1
            $parent_property = midgard_object_class::get_property_parent($this->_request_data['current_type']);
245 1
            $new_type_reflector = midcom_helper_reflector::get($new_type);
246 1
            $link_properties = $new_type_reflector->get_link_properties();
247 1
            $type_to_link_to = midcom_helper_reflector::class_rewrite($this->_object->__mgdschema_class_name__);
248 1
            foreach ($link_properties as $child_property => $link) {
249 1
                $linked_type = midcom_helper_reflector::class_rewrite($link['class']);
250 1
                if (   midcom_helper_reflector::is_same_class($linked_type, $type_to_link_to)
251 1
                    || (   $link['type'] == MGD_TYPE_GUID
252 1
                        && $link['class'] === null)) {
253 1
                    $defaults[$child_property] = $this->_object->{$link['target']};
254 1
                } elseif (   $child_property == $parent_property
255 1
                          && midcom_helper_reflector::is_same_class($new_type, $type_to_link_to)) {
256 1
                    $defaults[$child_property] = $this->_object->$parent_property;
257
                }
258
            }
259 1
            if (empty($defaults)) {
260
                throw new midcom_error("Could not establish link between {$new_type} and " . get_class($this->_object));
261
            }
262
        }
263
264
        // Allow setting defaults from query string, useful for things like "create event for today" and chooser
265 3
        if ($request->query->has('defaults')) {
266
            $get_defaults = array_intersect_key($request->query->get('defaults'), $this->schemadb->get_first()->get('fields'));
267
            $defaults = array_merge($defaults, array_map('trim', $get_defaults));
268
        }
269 3
        return $defaults;
270
    }
271
272
    /**
273
     * Shows the loaded object in editor.
274
     *
275
     * @param mixed $handler_id The ID of the handler.
276
     * @param array $data The local request data.
277
     */
278 3
    public function _show_create($handler_id, array &$data)
279
    {
280 3
        if ($handler_id == 'object_create_chooser') {
281 1
            midcom_show_style('midgard_admin_asgard_popup_header');
282 1
            if (   $this->_new_object->id
283 1
                || isset($data['cancelled'])) {
284
                $data['jsdata'] = $this->_object_to_jsdata($this->_new_object);
285
                midcom_show_style('midgard_admin_asgard_object_create_after');
286
            } else {
287 1
                midcom_show_style('midgard_admin_asgard_object_create');
288
            }
289 1
            midcom_show_style('midgard_admin_asgard_popup_footer');
290 1
            return;
291
        }
292
293 2
        midcom_show_style('midgard_admin_asgard_object_create');
294 2
    }
295
296
    private function _object_to_jsdata($object) : string
297
    {
298
        $jsdata = [
299
            'id' => (string) @$object->id,
300
            'guid' => @$object->guid,
301
            'pre_selected' => true
302
        ];
303
304
        foreach (array_keys($this->schemadb->get_first()->get('fields')) as $field) {
305
            $value = @$object->$field;
306
            $value = rawurlencode($value);
307
            $jsdata[$field] = $value;
308
        }
309
310
        return json_encode($jsdata);
311
    }
312
313 1
    private function _prepare_relocate(midcom_core_dbaobject $object, $mode = 'default') : midcom_response_relocate
314
    {
315
        // Redirect parameters to overview
316 1
        if ($object instanceof midcom_db_parameter) {
317
            return new midcom_response_relocate($this->router->generate('object_parameters', ['guid' => $object->parentguid]));
318
        }
319
320 1
        if ($mode == 'delete') {
321
            // Redirect person deletion to user management
322
            if ($object instanceof midcom_db_person) {
323
                return new midcom_response_relocate("__mfa/asgard_midgard.admin.user/");
324
            }
325
            if ($parent = $object->get_parent()) {
326
                return $this->_prepare_relocate($parent);
327
            }
328
329
            $url = $this->router->generate('type', ['type' => $object->__mgdschema_class_name__]);
330
        } else {
331
            // Redirect persons to user management
332 1
            if ($object instanceof midcom_db_person) {
333
                return new midcom_response_relocate("__mfa/asgard_midgard.admin.user/edit/{$object->guid}/");
334
            }
335
            // Redirect to default object mode page.
336 1
            $url = $this->router->generate('object_' . $this->_request_data['default_mode'], ['guid' => $object->guid]);
337
        }
338 1
        return new midcom_response_relocate($url);
339
    }
340
341
    /**
342
     * Object display
343
     *
344
     * @param Request $request The request object
345
     * @param mixed $handler_id The ID of the handler.
346
     * @param string $guid The object's GUID
347
     * @param array $data The local request data.
348
     */
349 1
    public function _handler_delete(Request $request, $handler_id, $guid, array &$data)
350
    {
351 1
        $this->_load_object($guid);
352 1
        $this->_object->require_do('midgard:delete');
353 1
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', null, 'midgard_admin_asgard_plugin');
354
355 1
        $this->_load_schemadb();
356 1
        $this->datamanager = new datamanager($this->schemadb);
357 1
        $this->datamanager
358 1
            ->set_storage($this->_object, 'default')
359 1
            ->get_form();
360
361 1
        if ($request->request->has('midgard_admin_asgard_deleteok')) {
362
            // Deletion confirmed.
363
            $this->_object->_use_rcs = !$request->request->getBoolean('midgard_admin_asgard_disablercs');
364
365
            if (!$this->_object->delete_tree()) {
366
                throw new midcom_error("Failed to delete object {$guid}, last Midgard error was: " . midcom_connection::get_error_string());
367
            }
368
369
            return $this->_prepare_relocate($this->_object, 'delete');
370
        }
371
372 1
        if ($request->request->has('midgard_admin_asgard_deletecancel')) {
373
            return $this->_prepare_relocate($this->_object);
374
        }
375
376 1
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
377 1
        $this->_prepare_request_data();
378 1
        $this->_add_jscripts();
379
380 1
        $data['view_object'] = $this->datamanager->get_content_html();
381
382
        // Initialize the tree
383 1
        $data['tree'] = new midgard_admin_asgard_copytree($this->_object, $data);
384 1
        $data['tree']->copy_tree = false;
385 1
        $data['tree']->inputs = false;
386
387 1
        return $this->get_response('midgard_admin_asgard_object_delete');
388
    }
389
390
    /**
391
     * Copy handler
392
     *
393
     * @param Request $request The request object
394
     * @param mixed $handler_id The ID of the handler.
395
     * @param string $guid The object's GUID
396
     * @param array $data The local request data.
397
     */
398 2
    public function _handler_copy(Request $request, $handler_id, $guid, array &$data)
399
    {
400
        // Get the object that will be copied
401 2
        $this->_load_object($guid);
402 2
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', null, 'midgard_admin_asgard_plugin');
403
404 2
        if ($handler_id === 'object_copy_tree') {
405 1
            $parent = midcom_helper_reflector_copy::get_parent_property($this->_object->__object);
406 1
            $this->_load_schemadb(get_class($this->_object), $parent, true);
407
            // Change the name for the parent field
408 1
            $this->schemadb->get_first()->get_field($parent)['title'] = $this->_l10n->get('choose the target');
409
        } else {
410 1
            $parent = null;
411 1
            $this->_load_schemadb(get_class($this->_object), [false], true);
412
        }
413
414 2
        $dm = new datamanager($this->schemadb);
415 2
        $this->controller = $dm->get_controller();
416
417 2
        $this->_prepare_request_data();
418 2
        $reflector = new midcom_helper_reflector($this->_object);
0 ignored issues
show
Bug introduced by
$this->_object of type midcom_core_dbaobject is incompatible with the type midgard\portable\api\mgdobject|string expected by parameter $src of midcom_helper_reflector::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

418
        $reflector = new midcom_helper_reflector(/** @scrutinizer ignore-type */ $this->_object);
Loading history...
419
420
        // Process the form
421 2
        switch ($this->controller->handle($request)) {
422 2
            case 'save':
423 1
                $new_object = $this->_process_copy($request, $parent, $reflector);
424
                // Relocate to the newly created object
425 1
                return $this->_prepare_relocate($new_object);
426
427 2
            case 'cancel':
428
                return $this->_prepare_relocate($this->_object);
429
        }
430
431 2
        $this->_add_jscripts();
432
433
        // Common hooks for Asgard
434 2
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
435
436
        // Set the page title
437 2
        $label = $reflector->get_object_label($this->_object);
438 2
        if ($handler_id === 'object_copy_tree') {
439 1
            $data['page_title'] = sprintf($this->_l10n->get('copy %s and its descendants'), $label);
440
        } else {
441 1
            $data['page_title'] = sprintf($this->_l10n->get('copy %s'), $label);
442
        }
443
444 2
        return $this->get_response();
445
    }
446
447
    /**
448
     * Add the necessary static files for copy/delete operations
449
     */
450 3
    private function _add_jscripts()
451
    {
452
        // Add Colorbox
453 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/jQuery/colorbox/jquery.colorbox-min.js');
454 3
        $this->add_stylesheet(MIDCOM_STATIC_URL . '/jQuery/colorbox/colorbox.css', 'screen');
455 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midgard.admin.asgard/object_browser.js');
456
457
        // Add jQuery file for the checkbox operations
458 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midgard.admin.asgard/jquery-copytree.js');
459 3
    }
460
461 1
    private function _process_copy(Request $request, $parent, midcom_helper_reflector $reflector) : midcom_core_dbaobject
462
    {
463 1
        $formdata = $this->controller->get_datamanager()->get_content_raw();
464 1
        $copy = new midcom_helper_reflector_copy();
465
466
        // Copying of parameters, metadata and such
467 1
        $copy->parameters = $formdata['parameters'];
468 1
        $copy->metadata = $formdata['metadata'];
469 1
        $copy->attachments = $formdata['attachments'];
470 1
        $copy->privileges = $formdata['privileges'];
471
472 1
        if ($this->_request_data['handler_id'] === 'object_copy_tree') {
473
            // Set the target - if available
474
            if (!empty($formdata[$parent])) {
475
                $link_properties = $reflector->get_link_properties();
476
477
                if (empty($link_properties[$parent])) {
478
                    throw new midcom_error('Failed to construct the target class object');
479
                }
480
481
                $class_name = $link_properties[$parent]['class'];
482
                $copy->target = new $class_name($formdata[$parent]);
483
            }
484
            $copy->exclude = array_diff($request->request->get('all_objects'), $request->request->get('selected'));
485
        } else {
486 1
            $copy->recursive = false;
487
        }
488 1
        $new_object = $copy->execute($this->_object);
489
490 1
        if ($new_object === false) {
0 ignored issues
show
introduced by
The condition $new_object === false is always true.
Loading history...
491
            debug_print_r('Copying failed with the following errors', $copy->errors, MIDCOM_LOG_ERROR);
492
            throw new midcom_error('Failed to successfully copy the object. Details in error level log');
493
        }
494
495 1
        if ($this->_request_data['handler_id'] === 'object_copy_tree') {
496
            midcom::get()->uimessages->add($this->_l10n->get('midgard.admin.asgard'), $this->_l10n->get('copy successful, you have been relocated to the root of the new object tree'));
497
        } else {
498 1
            midcom::get()->uimessages->add($this->_l10n->get('midgard.admin.asgard'), $this->_l10n->get('copy successful, you have been relocated to the new object'));
499
        }
500 1
        return midcom::get()->dbfactory->convert_midgard_to_midcom($new_object);
501
    }
502
503
    /**
504
     * Show copy style
505
     *
506
     * @param mixed $handler_id The ID of the handler.
507
     * @param array $data The local request data.
508
     */
509 2
    public function _show_copy($handler_id, array &$data)
510
    {
511
        // Show the tree hierarchy
512 2
        if ($handler_id === 'object_copy_tree') {
513 1
            $data['tree'] = new midgard_admin_asgard_copytree($this->_object, $data);
514 1
            $data['tree']->inputs = true;
515 1
            $data['tree']->copy_tree = true;
516 1
            midcom_show_style('midgard_admin_asgard_object_copytree');
517
        } else {
518
            // Show the copy page
519 1
            midcom_show_style('midgard_admin_asgard_object_copy');
520
        }
521 2
    }
522
}
523