Completed
Push — master ( a3b87b...c9d36f )
by Andreas
14:59
created

midgard_admin_asgard_handler_object_manage   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 460
Duplicated Lines 0 %

Test Coverage

Coverage 80.58%

Importance

Changes 0
Metric Value
eloc 203
dl 0
loc 460
ccs 166
cts 206
cp 0.8058
rs 7.92
c 0
b 0
f 0
wmc 51

14 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 get_defaults() 0 31 10
A _handler_edit() 0 26 3
B _handler_create() 0 53 7
A _show_copy() 0 11 2
A _add_jscripts() 0 9 1
A _handler_delete() 0 39 4
A _handler_copy() 0 47 5
B _process_copy() 0 40 6
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 7
    private function _prepare_request_data()
82
    {
83 7
        $this->_request_data['object'] = $this->_object;
84 7
        $this->_request_data['controller'] = $this->controller;
85 7
        $this->_request_data['datamanager'] = $this->datamanager;
86 7
        $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 7
        $this->_request_data['style_helper'] = new midgard_admin_asgard_stylehelper($this->_request_data);
88 7
    }
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
        if ($handler_id === 'object_create_chooser') {
214 1
            midcom::get()->head->set_pagetitle($data['view_title']);
215 1
            $workflow = $this->get_workflow('chooser', [
216 1
                'controller' => $this->controller
217
            ]);
218 1
            return $workflow->run($request);
219
        }
220
221 2
        switch ($this->controller->handle($request)) {
222 2
            case 'save':
223
                // Reindex the object
224
                //$indexer = midcom::get()->indexer;
225
                //net_nemein_wiki_viewer::index($this->_request_data['controller']->datamanager, $indexer, $this->_topic);
226
                return $this->_prepare_relocate($this->_new_object);
227
228 2
            case 'cancel':
229
                if ($this->_object) {
230
                    return $this->_prepare_relocate($this->_object);
231
                }
232
                return new midcom_response_relocate($this->router->generate('type', ['type' => $args[0]]));
233
        }
234
235 2
        $this->_prepare_request_data();
236 2
        return $this->get_response('midgard_admin_asgard_object_create');
237
    }
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 1
    private function _prepare_relocate(midcom_core_dbaobject $object, $mode = 'default') : midcom_response_relocate
273
    {
274
        // Redirect parameters to overview
275 1
        if ($object instanceof midcom_db_parameter) {
276
            return new midcom_response_relocate($this->router->generate('object_parameters', ['guid' => $object->parentguid]));
277
        }
278
279 1
        if ($mode == 'delete') {
280
            // Redirect person deletion to user management
281
            if ($object instanceof midcom_db_person) {
282
                return new midcom_response_relocate("__mfa/asgard_midgard.admin.user/");
283
            }
284
            if ($parent = $object->get_parent()) {
285
                return $this->_prepare_relocate($parent);
286
            }
287
288
            $url = $this->router->generate('type', ['type' => $object->__mgdschema_class_name__]);
289
        } else {
290
            // Redirect persons to user management
291 1
            if ($object instanceof midcom_db_person) {
292
                return new midcom_response_relocate("__mfa/asgard_midgard.admin.user/edit/{$object->guid}/");
293
            }
294
            // Redirect to default object mode page.
295 1
            $url = $this->router->generate('object_' . $this->_request_data['default_mode'], ['guid' => $object->guid]);
296
        }
297 1
        return new midcom_response_relocate($url);
298
    }
299
300
    /**
301
     * Object display
302
     *
303
     * @param Request $request The request object
304
     * @param mixed $handler_id The ID of the handler.
305
     * @param string $guid The object's GUID
306
     * @param array $data The local request data.
307
     */
308 1
    public function _handler_delete(Request $request, $handler_id, $guid, array &$data)
309
    {
310 1
        $this->_load_object($guid);
311 1
        $this->_object->require_do('midgard:delete');
312 1
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', null, 'midgard_admin_asgard_plugin');
313
314 1
        $this->_load_schemadb();
315 1
        $this->datamanager = new datamanager($this->schemadb);
316 1
        $this->datamanager
317 1
            ->set_storage($this->_object, 'default')
318 1
            ->get_form();
319
320 1
        if ($request->request->has('midgard_admin_asgard_deleteok')) {
321
            // Deletion confirmed.
322
            $this->_object->_use_rcs = !$request->request->getBoolean('midgard_admin_asgard_disablercs');
323
324
            if (!$this->_object->delete_tree()) {
325
                throw new midcom_error("Failed to delete object {$guid}, last Midgard error was: " . midcom_connection::get_error_string());
326
            }
327
328
            return $this->_prepare_relocate($this->_object, 'delete');
329
        }
330
331 1
        if ($request->request->has('midgard_admin_asgard_deletecancel')) {
332
            return $this->_prepare_relocate($this->_object);
333
        }
334
335 1
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
336 1
        $this->_prepare_request_data();
337 1
        $this->_add_jscripts();
338
339 1
        $data['view_object'] = $this->datamanager->get_content_html();
340
341
        // Initialize the tree
342 1
        $data['tree'] = new midgard_admin_asgard_copytree($this->_object, $data);
343 1
        $data['tree']->copy_tree = false;
344 1
        $data['tree']->inputs = false;
345
346 1
        return $this->get_response('midgard_admin_asgard_object_delete');
347
    }
348
349
    /**
350
     * Copy handler
351
     *
352
     * @param Request $request The request object
353
     * @param mixed $handler_id The ID of the handler.
354
     * @param string $guid The object's GUID
355
     * @param array $data The local request data.
356
     */
357 2
    public function _handler_copy(Request $request, $handler_id, $guid, array &$data)
358
    {
359
        // Get the object that will be copied
360 2
        $this->_load_object($guid);
361 2
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', null, 'midgard_admin_asgard_plugin');
362
363 2
        if ($handler_id === 'object_copy_tree') {
364 1
            $parent = midcom_helper_reflector_copy::get_parent_property($this->_object->__object);
365 1
            $this->_load_schemadb(get_class($this->_object), $parent, true);
366
            // Change the name for the parent field
367 1
            $this->schemadb->get_first()->get_field($parent)['title'] = $this->_l10n->get('choose the target');
368
        } else {
369 1
            $parent = null;
370 1
            $this->_load_schemadb(get_class($this->_object), [false], true);
371
        }
372
373 2
        $dm = new datamanager($this->schemadb);
374 2
        $this->controller = $dm->get_controller();
375
376 2
        $this->_prepare_request_data();
377 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

377
        $reflector = new midcom_helper_reflector(/** @scrutinizer ignore-type */ $this->_object);
Loading history...
378
379
        // Process the form
380 2
        switch ($this->controller->handle($request)) {
381 2
            case 'save':
382 1
                $new_object = $this->_process_copy($request, $parent, $reflector);
383
                // Relocate to the newly created object
384 1
                return $this->_prepare_relocate($new_object);
385
386 2
            case 'cancel':
387
                return $this->_prepare_relocate($this->_object);
388
        }
389
390 2
        $this->_add_jscripts();
391
392
        // Common hooks for Asgard
393 2
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
394
395
        // Set the page title
396 2
        $label = $reflector->get_object_label($this->_object);
397 2
        if ($handler_id === 'object_copy_tree') {
398 1
            $data['page_title'] = sprintf($this->_l10n->get('copy %s and its descendants'), $label);
399
        } else {
400 1
            $data['page_title'] = sprintf($this->_l10n->get('copy %s'), $label);
401
        }
402
403 2
        return $this->get_response();
404
    }
405
406
    /**
407
     * Add the necessary static files for copy/delete operations
408
     */
409 3
    private function _add_jscripts()
410
    {
411
        // Add Colorbox
412 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/jQuery/colorbox/jquery.colorbox-min.js');
413 3
        $this->add_stylesheet(MIDCOM_STATIC_URL . '/jQuery/colorbox/colorbox.css', 'screen');
414 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midgard.admin.asgard/object_browser.js');
415
416
        // Add jQuery file for the checkbox operations
417 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midgard.admin.asgard/jquery-copytree.js');
418 3
    }
419
420 1
    private function _process_copy(Request $request, $parent, midcom_helper_reflector $reflector) : midcom_core_dbaobject
421
    {
422 1
        $formdata = $this->controller->get_datamanager()->get_content_raw();
423 1
        $copy = new midcom_helper_reflector_copy();
424
425
        // Copying of parameters, metadata and such
426 1
        $copy->parameters = $formdata['parameters'];
427 1
        $copy->metadata = $formdata['metadata'];
428 1
        $copy->attachments = $formdata['attachments'];
429 1
        $copy->privileges = $formdata['privileges'];
430
431 1
        if ($this->_request_data['handler_id'] === 'object_copy_tree') {
432
            // Set the target - if available
433
            if (!empty($formdata[$parent])) {
434
                $link_properties = $reflector->get_link_properties();
435
436
                if (empty($link_properties[$parent])) {
437
                    throw new midcom_error('Failed to construct the target class object');
438
                }
439
440
                $class_name = $link_properties[$parent]['class'];
441
                $copy->target = new $class_name($formdata[$parent]);
442
            }
443
            $copy->exclude = array_diff($request->request->get('all_objects'), $request->request->get('selected'));
444
        } else {
445 1
            $copy->recursive = false;
446
        }
447 1
        $new_object = $copy->execute($this->_object);
448
449 1
        if ($new_object === false) {
0 ignored issues
show
introduced by
The condition $new_object === false is always true.
Loading history...
450
            debug_print_r('Copying failed with the following errors', $copy->errors, MIDCOM_LOG_ERROR);
451
            throw new midcom_error('Failed to successfully copy the object. Details in error level log');
452
        }
453
454 1
        if ($this->_request_data['handler_id'] === 'object_copy_tree') {
455
            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'));
456
        } else {
457 1
            midcom::get()->uimessages->add($this->_l10n->get('midgard.admin.asgard'), $this->_l10n->get('copy successful, you have been relocated to the new object'));
458
        }
459 1
        return midcom::get()->dbfactory->convert_midgard_to_midcom($new_object);
460
    }
461
462
    /**
463
     * Show copy style
464
     *
465
     * @param mixed $handler_id The ID of the handler.
466
     * @param array $data The local request data.
467
     */
468 2
    public function _show_copy($handler_id, array &$data)
469
    {
470
        // Show the tree hierarchy
471 2
        if ($handler_id === 'object_copy_tree') {
472 1
            $data['tree'] = new midgard_admin_asgard_copytree($this->_object, $data);
473 1
            $data['tree']->inputs = true;
474 1
            $data['tree']->copy_tree = true;
475 1
            midcom_show_style('midgard_admin_asgard_object_copytree');
476
        } else {
477
            // Show the copy page
478 1
            midcom_show_style('midgard_admin_asgard_object_copy');
479
        }
480 2
    }
481
}
482