Passed
Push — master ( c41cb1...84b849 )
by Andreas
10:10
created

midgard_admin_asgard_handler_object_manage   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 390
Duplicated Lines 0 %

Test Coverage

Coverage 78.31%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 187
c 1
b 0
f 0
dl 0
loc 390
ccs 148
cts 189
cp 0.7831
rs 6.96
wmc 53

15 Methods

Rating   Name   Duplication   Size   Complexity  
A _load_schemadb() 0 5 1
A _handler_open() 0 4 1
A _load_object() 0 11 3
A _prepare_request_data() 0 6 1
A _prepare_relocate() 0 26 6
B get_defaults() 0 28 10
B _handler_create() 0 50 7
A _handler_view() 0 14 1
A _on_initialize() 0 3 1
A _handler_edit() 0 23 3
A _handler_delete() 0 34 4
A _show_copy() 0 11 2
A _add_jscripts() 0 9 1
B _handler_copy() 0 46 6
B _process_copy() 0 39 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;
0 ignored issues
show
introduced by
The trait midgard_admin_asgard_handler requires some properties which are not provided by midgard_admin_asgard_handler_object_manage: $dbclassloader, $dbfactory
Loading history...
22
23
    private ?midcom_core_dbaobject $_object = null;
24
25
    /**
26
     * @var datamanager
27
     */
28
    private $datamanager;
29
30
    /**
31
     * @var controller
32
     */
33
    private $controller;
34
35
    private schemadb $schemadb;
36
37 8
    public function _on_initialize()
38
    {
39 8
        midcom::get()->auth->require_user_do('midgard.admin.asgard:manage_objects', class: 'midgard_admin_asgard_plugin');
40
    }
41
42
    /**
43
     * Retrieve the object from the db
44
     */
45 5
    private function _load_object(string $guid)
46
    {
47
        try {
48 5
            $this->_object = midcom::get()->dbfactory->get_object_by_guid($guid);
49
        } catch (midcom_error $e) {
50
            if (midcom_connection::get_error() == MGD_ERR_OBJECT_DELETED) {
51
                $relocate = $this->router->generate('object_deleted', ['guid' => $guid]);
52
                midcom::get()->relocate($relocate);
53
            }
54
55
            throw $e;
56
        }
57
    }
58
59
    /**
60
     * Simple helper which references all important members to the request data listing
61
     * for usage within the style listing.
62
     */
63 7
    private function _prepare_request_data()
64
    {
65 7
        $this->_request_data['object'] = $this->_object;
66 7
        $this->_request_data['controller'] = $this->controller;
67 7
        $this->_request_data['datamanager'] = $this->datamanager;
68 7
        $this->_request_data['style_helper'] = new midgard_admin_asgard_stylehelper($this->_request_data);
69
    }
70
71
    /**
72
     * Loads the schemadb from the helper class
73
     */
74 8
    private function _load_schemadb(?midcom_core_dbaobject $object = null, ?array $include_fields = null, bool $add_copy_fields = false)
75
    {
76 8
        $schema_helper = new midgard_admin_asgard_schemadb($object ?? $this->_object, $this->_config);
0 ignored issues
show
Bug introduced by
It seems like $object ?? $this->_object can also be of type null; however, parameter $object of midgard_admin_asgard_schemadb::__construct() does only seem to accept midcom_core_dbaobject, maybe add an additional type check? ( Ignorable by Annotation )

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

76
        $schema_helper = new midgard_admin_asgard_schemadb(/** @scrutinizer ignore-type */ $object ?? $this->_object, $this->_config);
Loading history...
77 8
        $schema_helper->add_copy_fields = $add_copy_fields;
78 8
        $this->schemadb = $schema_helper->create($include_fields);
79
    }
80
81
    /**
82
     * Looks up the user's default mode and redirects there. This is mainly useful for links from outside Asgard
83
     */
84
    public function _handler_open(string $guid, array &$data)
85
    {
86
        $relocate = $this->router->generate('object_' . $data['default_mode'], ['guid' => $guid]);
87
        return new midcom_response_relocate($relocate);
88
    }
89
90
    /**
91
     * Object display
92
     */
93 1
    public function _handler_view(string $handler_id, string $guid, array &$data)
94
    {
95 1
        $this->_load_object($guid);
96 1
        $this->_load_schemadb();
97
98
        // Hide the revision message
99 1
        $this->schemadb->get_first()->get_field('_rcs_message')['hidden'] = true;
100
101 1
        $this->datamanager = (new datamanager($this->schemadb))
102 1
            ->set_storage($this->_object);
103
104 1
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
105 1
        $this->_prepare_request_data();
106 1
        return $this->get_response('midgard_admin_asgard_object_view');
107
    }
108
109
    /**
110
     * Object editing view
111
     */
112 1
    public function _handler_edit(Request $request, string $handler_id, string $guid, array &$data)
113
    {
114 1
        $this->_load_object($guid);
115 1
        $this->_object->require_do('midgard:update');
116 1
        $this->_load_schemadb();
117
118 1
        $this->controller = (new datamanager($this->schemadb))
119 1
            ->set_storage($this->_object, 'default')
120 1
            ->get_controller();
121 1
        switch ($this->controller->handle($request)) {
122 1
            case 'save':
123
                // Reindex the object
124
                //$indexer = midcom::get()->indexer;
125
                //net_nemein_wiki_viewer::index($this->_request_data['controller']->datamanager, $indexer, $this->_topic);
126
                //Fall-through
127
128 1
            case 'cancel':
129
                return $this->_prepare_relocate($this->_object);
130
        }
131
132 1
        $this->_prepare_request_data();
133 1
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
134 1
        return $this->get_response('midgard_admin_asgard_object_edit');
135
    }
136
137
    /**
138
     * Object creating view
139
     */
140 3
    public function _handler_create(Request $request, string $handler_id, array $args, array &$data)
141
    {
142 3
        $data['current_type'] = $args[0];
143 3
        $create_type = midcom::get()->dbclassloader->get_midcom_class_name_for_mgdschema_object($data['current_type']);
144 3
        if (!$create_type) {
145
            throw new midcom_error_notfound('Failed to find type for the new object');
146
        }
147 3
        $new_object = new $create_type();
148
149 3
        if (in_array($handler_id, ['object_create_toplevel', 'object_create_chooser'])) {
150 2
            midcom::get()->auth->require_user_do('midgard:create', class: $create_type);
151
152 2
            $data['view_title'] = sprintf($this->_l10n_midcom->get('create %s'), midgard_admin_asgard_plugin::get_type_label($data['current_type']));
153
        } else {
154 1
            $this->_object = midcom::get()->dbfactory->get_object_by_guid($args[1]);
155 1
            $this->_object->require_do('midgard:create');
156 1
            midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
157
        }
158
159 3
        $this->_load_schemadb($new_object);
160
161 3
        $this->controller = (new datamanager($this->schemadb))
162 3
            ->set_defaults($this->get_defaults($request, $create_type))
0 ignored issues
show
Bug introduced by
It seems like $create_type can also be of type null; however, parameter $new_type of midgard_admin_asgard_han..._manage::get_defaults() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

162
            ->set_defaults($this->get_defaults($request, /** @scrutinizer ignore-type */ $create_type))
Loading history...
163 3
            ->set_storage($new_object, 'default')
164 3
            ->get_controller();
165
166 3
        if ($handler_id === 'object_create_chooser') {
167 1
            midcom::get()->head->set_pagetitle($data['view_title']);
168 1
            $workflow = $this->get_workflow('chooser', [
169 1
                'controller' => $this->controller
170 1
            ]);
171 1
            return $workflow->run($request);
172
        }
173
174 2
        switch ($this->controller->handle($request)) {
175 2
            case 'save':
176
                // Reindex the object
177
                //$indexer = midcom::get()->indexer;
178
                //net_nemein_wiki_viewer::index($this->_request_data['controller']->datamanager, $indexer, $this->_topic);
179
                return $this->_prepare_relocate($new_object);
180
181 2
            case 'cancel':
182
                if ($this->_object) {
183
                    return $this->_prepare_relocate($this->_object);
184
                }
185
                return new midcom_response_relocate($this->router->generate('type', ['type' => $args[0]]));
186
        }
187
188 2
        $this->_prepare_request_data();
189 2
        return $this->get_response('midgard_admin_asgard_object_create');
190
    }
191
192 3
    private function get_defaults(Request $request, string $new_type) : array
193
    {
194 3
        $defaults = [];
195 3
        if ($this->_object) {
196
            // Figure out the linking property
197 1
            $parent_property = midgard_object_class::get_property_parent($this->_request_data['current_type']);
198 1
            $new_type_reflector = midcom_helper_reflector::get($new_type);
199 1
            $link_properties = $new_type_reflector->get_link_properties();
200 1
            foreach ($link_properties as $property => $link) {
201 1
                if (   ($link['class'] && midcom_helper_reflector::is_same_class($link['class'], $this->_object->__mgdschema_class_name__))
202 1
                    || $link['type'] == MGD_TYPE_GUID) {
203 1
                    $defaults[$property] = $this->_object->{$link['target']};
204 1
                } elseif (   $property == $parent_property
205 1
                          && midcom_helper_reflector::is_same_class($new_type, $this->_object->__mgdschema_class_name__)) {
206
                    $defaults[$property] = $this->_object->$parent_property;
207
                }
208
            }
209 1
            if (empty($defaults)) {
210
                throw new midcom_error("Could not establish link between {$new_type} and " . $this->_object::class);
211
            }
212
        }
213
214
        // Allow setting defaults from query string, useful for things like "create event for today" and chooser
215 3
        if ($request->query->has('defaults')) {
216
            $get_defaults = array_intersect_key($request->query->all('defaults'), $this->schemadb->get_first()->get('fields'));
217
            $defaults = array_merge($defaults, array_map(trim(...), $get_defaults));
0 ignored issues
show
Bug introduced by
The type trim was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
218
        }
219 3
        return $defaults;
220
    }
221
222 1
    private function _prepare_relocate(midcom_core_dbaobject $object, string $mode = 'default') : midcom_response_relocate
223
    {
224
        // Redirect parameters to overview
225 1
        if ($object instanceof midcom_db_parameter) {
226
            return new midcom_response_relocate($this->router->generate('object_parameters', ['guid' => $object->parentguid]));
227
        }
228
229 1
        if ($mode == 'delete') {
230
            // Redirect person deletion to user management
231
            if ($object instanceof midcom_db_person) {
232
                return new midcom_response_relocate("__mfa/asgard_midgard.admin.user/");
233
            }
234
            if ($parent = $object->get_parent()) {
235
                return $this->_prepare_relocate($parent);
236
            }
237
238
            $url = $this->router->generate('type', ['type' => $object->__mgdschema_class_name__]);
239
        } else {
240
            // Redirect persons to user management
241 1
            if ($object instanceof midcom_db_person) {
242
                return new midcom_response_relocate("__mfa/asgard_midgard.admin.user/edit/{$object->guid}/");
243
            }
244
            // Redirect to default object mode page.
245 1
            $url = $this->router->generate('object_' . $this->_request_data['default_mode'], ['guid' => $object->guid]);
246
        }
247 1
        return new midcom_response_relocate($url);
248
    }
249
250
    /**
251
     * Object deletion
252
     */
253 1
    public function _handler_delete(Request $request, string $handler_id, string $guid, array &$data)
254
    {
255 1
        $this->_load_object($guid);
256 1
        $this->_object->require_do('midgard:delete');
257 1
        $this->_load_schemadb();
258
259 1
        $this->datamanager = (new datamanager($this->schemadb))
260 1
            ->set_storage($this->_object, 'default');
261
262 1
        if ($request->request->has('midgard_admin_asgard_deleteok')) {
263
            // Deletion confirmed.
264
            $this->_object->_use_rcs = !$request->request->getBoolean('midgard_admin_asgard_disablercs');
265
266
            if (!$this->_object->delete_tree()) {
267
                throw new midcom_error("Failed to delete object {$guid}, last Midgard error was: " . midcom_connection::get_error_string());
268
            }
269
270
            return $this->_prepare_relocate($this->_object, 'delete');
271
        }
272
273 1
        if ($request->request->has('midgard_admin_asgard_deletecancel')) {
274
            return $this->_prepare_relocate($this->_object);
275
        }
276
277 1
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
278 1
        $this->_prepare_request_data();
279 1
        $this->_add_jscripts();
280
281
        // Initialize the tree
282 1
        $data['tree'] = new midgard_admin_asgard_copytree($this->_object, $data);
283 1
        $data['tree']->copy_tree = false;
284 1
        $data['tree']->inputs = false;
285
286 1
        return $this->get_response('midgard_admin_asgard_object_delete');
287
    }
288
289
    /**
290
     * Copy handler
291
     */
292 2
    public function _handler_copy(Request $request, string $handler_id, string $guid, array &$data)
293
    {
294 2
        $this->_load_object($guid);
295
296 2
        if ($handler_id === 'object_copy_tree') {
297 1
            $parent = midcom_helper_reflector_copy::get_parent_property($this->_object);
298 1
            $this->_load_schemadb($this->_object, [$parent], true);
299 1
            if ($parent) {
300
                // Change the name for the parent field
301 1
                $this->schemadb->get_first()->get_field($parent)['title'] = $this->_l10n->get('choose the target');
302
            }
303
        } else {
304 1
            $parent = null;
305 1
            $this->_load_schemadb($this->_object, [false], true);
306
        }
307
308 2
        $this->controller = (new datamanager($this->schemadb))->get_controller();
309
310 2
        $this->_prepare_request_data();
311 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

311
        $reflector = new midcom_helper_reflector(/** @scrutinizer ignore-type */ $this->_object);
Loading history...
312
313
        // Process the form
314 2
        switch ($this->controller->handle($request)) {
315 2
            case 'save':
316 1
                $new_object = $this->_process_copy($request, $parent, $reflector);
317
                // Relocate to the newly created object
318 1
                return $this->_prepare_relocate($new_object);
319
320 2
            case 'cancel':
321
                return $this->_prepare_relocate($this->_object);
322
        }
323
324 2
        $this->_add_jscripts();
325
326
        // Common hooks for Asgard
327 2
        midgard_admin_asgard_plugin::bind_to_object($this->_object, $handler_id, $data);
328
329
        // Set the page title
330 2
        $label = $reflector->get_object_label($this->_object);
331 2
        if ($handler_id === 'object_copy_tree') {
332 1
            $data['page_title'] = sprintf($this->_l10n->get('copy %s and its descendants'), $label);
333
        } else {
334 1
            $data['page_title'] = sprintf($this->_l10n->get('copy %s'), $label);
335
        }
336
337 2
        return $this->get_response();
338
    }
339
340
    /**
341
     * Add the necessary static files for copy/delete operations
342
     */
343 3
    private function _add_jscripts()
344
    {
345
        // Add Colorbox
346 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/jQuery/colorbox/jquery.colorbox-min.js');
347 3
        $this->add_stylesheet(MIDCOM_STATIC_URL . '/jQuery/colorbox/colorbox.css', 'screen');
348 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midgard.admin.asgard/object_browser.js');
349
350
        // Add jQuery file for the checkbox operations
351 3
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midgard.admin.asgard/jquery-copytree.js');
352
    }
353
354 1
    private function _process_copy(Request $request, ?string $parent, midcom_helper_reflector $reflector) : midcom_core_dbaobject
355
    {
356 1
        $formdata = $this->controller->get_datamanager()->get_content_raw();
357 1
        $copy = new midcom_helper_reflector_copy();
358
359
        // Copying of parameters, metadata and such
360 1
        $copy->parameters = $formdata['parameters'];
361 1
        $copy->metadata = $formdata['metadata'];
362 1
        $copy->attachments = $formdata['attachments'];
363 1
        $copy->privileges = $formdata['privileges'];
364
365 1
        if ($this->_request_data['handler_id'] === 'object_copy_tree') {
366
            // Set the target - if available
367
            if (!empty($formdata[$parent])) {
368
                $link_properties = $reflector->get_link_properties();
369
370
                if (empty($link_properties[$parent])) {
371
                    throw new midcom_error('Failed to construct the target class object');
372
                }
373
                $class_name = midcom::get()->dbclassloader->get_midcom_class_name_for_mgdschema_object($link_properties[$parent]['class']);
374
                $copy->target = new $class_name($formdata[$parent]);
375
            }
376
            $copy->exclude = array_diff($request->request->all('all_objects'), $request->request->all('selected'));
377
        } else {
378 1
            $copy->recursive = false;
379
        }
380 1
        $new_object = $copy->execute($this->_object);
0 ignored issues
show
Bug introduced by
It seems like $this->_object can also be of type null; however, parameter $source of midcom_helper_reflector_copy::execute() does only seem to accept midcom_core_dbaobject, maybe add an additional type check? ( Ignorable by Annotation )

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

380
        $new_object = $copy->execute(/** @scrutinizer ignore-type */ $this->_object);
Loading history...
381
382 1
        if ($new_object === null) {
383
            debug_print_r('Copying failed with the following errors', $copy->errors, MIDCOM_LOG_ERROR);
384
            throw new midcom_error('Failed to successfully copy the object. Details in error level log');
385
        }
386
387 1
        if ($this->_request_data['handler_id'] === 'object_copy_tree') {
388
            midcom::get()->uimessages->add($this->_l10n->get($this->_component), $this->_l10n->get('copy successful, you have been relocated to the root of the new object tree'));
389
        } else {
390 1
            midcom::get()->uimessages->add($this->_l10n->get($this->_component), $this->_l10n->get('copy successful, you have been relocated to the new object'));
391
        }
392 1
        return $new_object;
393
    }
394
395
    /**
396
     * Show copy style
397
     */
398 2
    public function _show_copy(string $handler_id, array &$data)
399
    {
400
        // Show the tree hierarchy
401 2
        if ($handler_id === 'object_copy_tree') {
402 1
            $data['tree'] = new midgard_admin_asgard_copytree($this->_object, $data);
0 ignored issues
show
Bug introduced by
It seems like $this->_object can also be of type null; however, parameter $object of midgard_admin_asgard_copytree::__construct() does only seem to accept midcom_core_dbaobject, maybe add an additional type check? ( Ignorable by Annotation )

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

402
            $data['tree'] = new midgard_admin_asgard_copytree(/** @scrutinizer ignore-type */ $this->_object, $data);
Loading history...
403 1
            $data['tree']->inputs = true;
404 1
            $data['tree']->copy_tree = true;
405 1
            midcom_show_style('midgard_admin_asgard_object_copytree');
406
        } else {
407
            // Show the copy page
408 1
            midcom_show_style('midgard_admin_asgard_object_copy');
409
        }
410
    }
411
}
412