Passed
Push — master ( 40aec1...d8787f )
by Andreas
11:30
created

blobs::load_map()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5.0729

Importance

Changes 0
Metric Value
cc 5
eloc 13
c 0
b 0
f 0
nc 5
nop 2
dl 0
loc 20
ccs 12
cts 14
cp 0.8571
crap 5.0729
rs 9.5222
1
<?php
2
/**
3
 * @copyright CONTENT CONTROL GmbH, http://www.contentcontrol-berlin.de
4
 */
5
6
namespace midcom\datamanager\storage;
7
8
use midcom_db_attachment;
9
use midcom_core_dbaobject;
10
use midcom_error;
11
use midcom_connection;
12
use midcom;
13
use midcom\datamanager\helper\attachment;
14
use Symfony\Component\Mime\FileBinaryMimeTypeGuesser;
15
16
/**
17
 * Experimental storage class
18
 */
19
class blobs extends delayed
20
{
21
    use attachment;
22
23
    /**
24
     * @var midcom_db_attachment[]
25
     */
26
    protected array $map = [];
27
28
    /**
29
     * @return midcom_db_attachment[]
30
     */
31 46
    public function load()
32
    {
33 46
        $results = [];
34 46
        if (!$this->object->id) {
35 11
            return $results;
36
        }
37
38 36
        $items = $this->load_attachment_list();
39 36
        foreach ($items as $identifier => $guid) {
40
            try {
41 4
                $results[$identifier] = new midcom_db_attachment($guid);
42
            } catch (midcom_error $e) {
43
                $e->log();
44
            }
45
        }
46
47 36
        return $results;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53 1
    public function save()
54
    {
55 1
        $this->map = [];
56 1
        $atts_in_db = $this->load();
57
58 1
        if (!empty($this->value)) {
59 1
            $guesser = new FileBinaryMimeTypeGuesser;
60 1
            foreach ($this->value as $identifier => $att) {
61 1
                if (!($att instanceof midcom_db_attachment)) {
62
                    continue;
63
                }
64
65 1
                $db_att = $atts_in_db[$identifier] ?? null;
66
67
                // new upload case
68 1
                if ($att->id === 0) {
69 1
                    $filename = midcom_db_attachment::safe_filename($att->name);
70 1
                    $title = $att->title ?: $att->name;
71 1
                    $source = $att->location;
72 1
                    $mimetype = $guesser->guessMimeType($source);
73
74 1
                    if (empty($db_att)) {
75 1
                        $db_att = $att;
76 1
                        $db_att->parentguid = $this->object->guid;
77 1
                        $this->create_attachment($db_att, $filename, $title, $mimetype);
0 ignored issues
show
Bug introduced by
It seems like $mimetype can also be of type null; however, parameter $mimetype of midcom\datamanager\stora...bs::create_attachment() 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

77
                        $this->create_attachment($db_att, $filename, $title, /** @scrutinizer ignore-type */ $mimetype);
Loading history...
78 1
                        $identifier = md5(time() . $db_att->name . $source);
79
                    } else {
80
                        $db_att->name = $filename;
81
                        $db_att->title = $title;
82
                        $db_att->mimetype = $mimetype;
83
                    }
84 1
                    if (!$db_att->copy_from_file($source)) {
85
                        throw new midcom_error('Failed to copy attachment: ' . midcom_connection::get_error_string());
86
                    }
87 1
                    unlink($source);
88
                }
89
                // No file upload, only title change
90 1
                elseif ($db_att->title != $att->title) {
91
                    $db_att->title = $att->title;
92
                    $db_att->update();
0 ignored issues
show
Bug introduced by
The method update() does not exist on null. ( Ignorable by Annotation )

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

92
                    $db_att->/** @scrutinizer ignore-call */ 
93
                             update();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
93
                }
94 1
                $this->map[$identifier] = $db_att;
95 1
                if (!empty($this->config['widget_config']['sortable'])) {
96
                    $db_att->metadata->score = $att->metadata->score;
97
                    $db_att->update();
98
                }
99 1
                if (!empty($this->config['widget_config']['show_description'])) {
100
                    $db_att->set_parameter('midcom.helper.datamanager2.type.blobs', 'description', $this->value['description']);
101
                }
102
            }
103
        }
104
        //delete attachments which are no longer in map
105 1
        foreach (array_diff_key($atts_in_db, $this->map) as $attachment) {
106
            $attachment->delete();
107
        }
108
109 1
        $this->save_attachment_list();
110
    }
111
112
    public function move_uploaded_files() : int
113
    {
114
        $total_moved = 0;
115
116
        foreach ($this->value as $att) {
117
            if (!($att instanceof midcom_db_attachment)) {
118
                continue;
119
            }
120
            if ($att->id !== 0) {
121
                continue;
122
            }
123
            $prefix = midcom::get()->config->get('midcom_tempdir') . '/tmpfile-';
124
            if (str_starts_with($att->location, $prefix)) {
125
                continue;
126
            }
127
            $total_moved++;
128
129
            $source = $att->location;
130
            $att->location = $prefix . md5(time() . $att->name . $source);
131
            $att->title = $att->name;
132
133
            move_uploaded_file($source, $att->location);
134
        }
135
136
        return $total_moved;
137
    }
138
139 2
    protected function save_attachment_list() : bool
140
    {
141 2
        if (!empty($this->config['widget_config']['sortable'])) {
142
            uasort($this->map, function (midcom_db_attachment $a, midcom_db_attachment $b) {
143
                if ($a->metadata->score == $b->metadata->score) {
144
                    return strnatcasecmp($a->name, $b->name);
145
                }
146
                return $b->metadata->score <=> $a->metadata->score;
147
            });
148
        }
149
150 2
        $list = [];
151
152 2
        foreach ($this->map as $identifier => $attachment) {
153 2
            $list[] = $identifier . ':' . $attachment->guid;
154
        }
155 2
        return $this->object->set_parameter('midcom.helper.datamanager2.type.blobs', "guids_{$this->config['name']}", implode(',', $list));
156
    }
157
158 36
    protected function load_attachment_list() : array
159
    {
160 36
        return self::load_map($this->object, $this->config['name']);
161
    }
162
163 44
    private static function load_map(midcom_core_dbaobject $object, string $field) : array
164
    {
165 44
        $map = [];
166 44
        $raw_list = $object->get_parameter('midcom.helper.datamanager2.type.blobs', "guids_{$field}");
167 44
        if (!$raw_list) {
168 40
            return $map;
169
        }
170
171 4
        foreach (explode(',', $raw_list) as $item) {
172 4
            $info = explode(':', $item);
173 4
            if (count($info) < 2) {
174
                debug_add("item '{$item}' is broken!", MIDCOM_LOG_ERROR);
175
                continue;
176
            }
177 4
            [$identifier, $guid] = $info;
178 4
            if (mgd_is_guid($guid)) {
179 4
                $map[$identifier] = $guid;
180
            }
181
        }
182 4
        return $map;
183
    }
184
185
    /**
186
     * @return midcom_db_attachment[] List of attachments, indexed by identifier
187
     */
188 9
    public static function get_attachments(midcom_core_dbaobject $object, string $field) : array
189
    {
190 9
        $attachments = [];
191 9
        foreach (self::load_map($object, $field) as $identifier => $guid) {
192
            try {
193
                $attachments[$identifier] = midcom_db_attachment::get_cached($guid);
194
            } catch (midcom_error $e) {
195
                $e->log();
196
            }
197
        }
198 9
        return $attachments;
199
    }
200
}
201