Subversion Repositories oidplus

Rev

Rev 1126 | Rev 1130 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1126 Rev 1127
1
<?php
1
<?php
2
 
2
 
3
/*
3
/*
4
 * OIDplus 2.0
4
 * OIDplus 2.0
5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
6
 *
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
9
 * You may obtain a copy of the License at
10
 *
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
17
 * limitations under the License.
18
 */
18
 */
19
 
19
 
20
namespace ViaThinkSoft\OIDplus;
20
namespace ViaThinkSoft\OIDplus;
21
 
21
 
22
// phpcs:disable PSR1.Files.SideEffects
22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
24
// phpcs:enable PSR1.Files.SideEffects
25
 
25
 
26
abstract class OIDplusObject extends OIDplusBaseClass {
26
abstract class OIDplusObject extends OIDplusBaseClass {
27
        const UUID_NAMEBASED_NS_OidPlusMisc = 'ad1654e6-7e15-11e4-9ef6-78e3b5fc7f22';
27
        const UUID_NAMEBASED_NS_OidPlusMisc = 'ad1654e6-7e15-11e4-9ef6-78e3b5fc7f22';
28
 
28
 
29
        /**
29
        /**
30
         * Please overwrite this function!
30
         * Please overwrite this function!
31
         * @param string $node_id
31
         * @param string $node_id
32
         * @return OIDplusObject|null
32
         * @return OIDplusObject|null
33
         */
33
         */
34
        public static function parse(string $node_id)/*: ?OIDplusObject*/ {
34
        public static function parse(string $node_id)/*: ?OIDplusObject*/ {
35
                foreach (OIDplus::getEnabledObjectTypes() as $ot) {
35
                foreach (OIDplus::getEnabledObjectTypes() as $ot) {
36
                        try {
36
                        try {
37
                                $good = false;
37
                                $good = false;
38
                                if (get_parent_class($ot) == OIDplusObject::class) {
38
                                if (get_parent_class($ot) == OIDplusObject::class) {
39
                                        $reflector = new \ReflectionMethod($ot, 'parse');
39
                                        $reflector = new \ReflectionMethod($ot, 'parse');
40
                                        $isImplemented = ($reflector->getDeclaringClass()->getName() === $ot);
40
                                        $isImplemented = ($reflector->getDeclaringClass()->getName() === $ot);
41
                                        if ($isImplemented) { // avoid endless loop if parse is not overriden
41
                                        if ($isImplemented) { // avoid endless loop if parse is not overriden
42
                                                $good = true;
42
                                                $good = true;
43
                                        }
43
                                        }
44
                                }
44
                                }
45
                                // We need to do the workaround with "$good", otherwise PHPstan shows
45
                                // We need to do the workaround with "$good", otherwise PHPstan shows
46
                                // "Call to an undefined static method object::parse()"
46
                                // "Call to an undefined static method object::parse()"
47
                                if ($good && $obj = $ot::parse($node_id)) return $obj;
47
                                if ($good && $obj = $ot::parse($node_id)) return $obj;
48
                        } catch (\Exception $e) {}
48
                        } catch (\Exception $e) {}
49
                }
49
                }
50
                return null;
50
                return null;
51
        }
51
        }
52
 
52
 
53
        /**
53
        /**
54
         * @return OIDplusAltId[]
54
         * @return OIDplusAltId[]
55
         * @throws OIDplusException
55
         * @throws OIDplusException
56
         */
56
         */
57
        public function getAltIds(): array {
57
        public function getAltIds(): array {
58
                if ($this->isRoot()) return array();
58
                if ($this->isRoot()) return array();
59
 
59
 
60
                $ids = array();
60
                $ids = array();
61
 
61
 
62
                // Creates an OIDplus-Hash-OID
62
                // Creates an OIDplus-Hash-OID
63
                if ($this->ns() != 'oid') {
63
                if ($this->ns() != 'oid') {
64
                        $sid = OIDplus::getSystemId(true);
64
                        $sid = OIDplus::getSystemId(true);
65
                        if (!empty($sid)) {
65
                        if (!empty($sid)) {
66
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
66
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
67
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
67
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
68
                                        // Official ViaThinkSoft object type plugins
68
                                        // Official ViaThinkSoft object type plugins
69
                                        // For backwards compatibility with existing IDs,
69
                                        // For backwards compatibility with existing IDs,
70
                                        // set the hash_payload as '<namespace>:<id>'
70
                                        // set the hash_payload as '<namespace>:<id>'
71
                                        $hash_payload = $this->nodeId(true);
71
                                        $hash_payload = $this->nodeId(true);
72
                                } else {
72
                                } else {
73
                                        // Third-party object type plugins
73
                                        // Third-party object type plugins
74
                                        // Set the hash_payload as '<plugin oid>:<id>'
74
                                        // Set the hash_payload as '<plugin oid>:<id>'
75
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
75
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
76
                                }
76
                                }
77
                                $oid = $sid . '.' . smallhash($hash_payload);
77
                                $oid = $sid . '.' . smallhash($hash_payload);
78
                                $ids[] = new OIDplusAltId('oid', $oid, _L('OIDplus Information Object OID'));
78
                                $ids[] = new OIDplusAltId('oid', $oid, _L('OIDplus Information Object OID'));
79
                        }
79
                        }
80
                }
80
                }
81
 
81
 
82
                // Make a namebased UUID, but...
82
                // Make a namebased UUID, but...
83
                // ... exclude GUID, because a GUID is already a GUID
83
                // ... exclude GUID, because a GUID is already a GUID
84
                // ... exclude OID, because an OID already has a record UUID_NAMEBASED_NS_OID (defined by IETF) set by class OIDplusOid
84
                // ... exclude OID, because an OID already has a record UUID_NAMEBASED_NS_OID (defined by IETF) set by class OIDplusOid
85
                if (($this->ns() != 'guid') && ($this->ns() != 'oid')) {
85
                if (($this->ns() != 'guid') && ($this->ns() != 'oid')) {
86
                        $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
86
                        $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
87
                        $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
87
                        $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
88
                }
88
                }
89
 
89
 
90
                // Make a AID based on ViaThinkSoft schema
90
                // Make a AID based on ViaThinkSoft schema
91
                // ... but not for OIDs below oid:1.3.6.1.4.1.37476.30.9, because these are the definition of these Information Object AIDs (which will be decoded in the OID object type plugin)
91
                // ... but not for OIDs below oid:1.3.6.1.4.1.37476.30.9, because these are the definition of these Information Object AIDs (which will be decoded in the OID object type plugin)
92
                if (($this->ns() != 'aid') && !str_starts_with($this->nodeId(true), 'oid:1.3.6.1.4.1.37476.30.9.')) {
92
                if (($this->ns() != 'aid') && !str_starts_with($this->nodeId(true), 'oid:1.3.6.1.4.1.37476.30.9.')) {
93
                        $sid = OIDplus::getSystemId(false);
93
                        $sid = OIDplus::getSystemId(false);
94
                        if ($sid !== false) {
94
                        if ($sid !== false) {
95
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
95
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
96
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
96
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
97
                                        // Official ViaThinkSoft object type plugins
97
                                        // Official ViaThinkSoft object type plugins
98
                                        // For backwards compatibility with existing IDs,
98
                                        // For backwards compatibility with existing IDs,
99
                                        // set the hash_payload as '<namespace>:<id>'
99
                                        // set the hash_payload as '<namespace>:<id>'
100
                                        $hash_payload = $this->nodeId(true);
100
                                        $hash_payload = $this->nodeId(true);
101
                                } else {
101
                                } else {
102
                                        // Third-party object type plugins
102
                                        // Third-party object type plugins
103
                                        // Set the hash_payload as '<plugin oid>:<id>'
103
                                        // Set the hash_payload as '<plugin oid>:<id>'
104
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
104
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
105
                                }
105
                                }
106
 
106
 
107
                                $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
107
                                $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
108
                                $obj_hex = strtoupper(str_pad(dechex(smallhash($hash_payload)),8,'0',STR_PAD_LEFT));
108
                                $obj_hex = strtoupper(str_pad(dechex(smallhash($hash_payload)),8,'0',STR_PAD_LEFT));
109
                                $aid = 'D276000186B20005'.$sid_hex.$obj_hex;
109
                                $aid = 'D276000186B20005'.$sid_hex.$obj_hex;
110
                                $ids[] = new OIDplusAltId('aid', $aid, _L('OIDplus Information Object Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
110
                                $ids[] = new OIDplusAltId('aid', $aid, _L('OIDplus Information Object Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
111
                        }
111
                        }
112
                }
112
                }
113
 
113
 
114
                return $ids;
114
                return $ids;
115
        }
115
        }
116
 
116
 
117
        /**
117
        /**
118
         * @return string
118
         * @return string
119
         */
119
         */
120
        public abstract static function objectTypeTitle(): string;
120
        public abstract static function objectTypeTitle(): string;
121
 
121
 
122
        /**
122
        /**
123
         * @return string
123
         * @return string
124
         */
124
         */
125
        public abstract static function objectTypeTitleShort(): string;
125
        public abstract static function objectTypeTitleShort(): string;
126
 
126
 
127
        /**
127
        /**
128
         * @return OIDplusObjectTypePlugin|null
128
         * @return OIDplusObjectTypePlugin|null
129
         */
129
         */
130
        public function getPlugin()/*: ?OIDplusObjectTypePlugin */ {
130
        public function getPlugin()/*: ?OIDplusObjectTypePlugin */ {
131
                $plugins = OIDplus::getObjectTypePlugins();
131
                $plugins = OIDplus::getObjectTypePlugins();
132
                foreach ($plugins as $plugin) {
132
                foreach ($plugins as $plugin) {
133
                        if (get_class($this) == $plugin::getObjectTypeClassName()) {
133
                        if (get_class($this) == $plugin::getObjectTypeClassName()) {
134
                                return $plugin;
134
                                return $plugin;
135
                        }
135
                        }
136
                }
136
                }
137
                return null;
137
                return null;
138
        }
138
        }
139
 
139
 
140
        /**
140
        /**
141
         * @return string
141
         * @return string
142
         */
142
         */
143
        public abstract static function ns(): string;
143
        public abstract static function ns(): string;
144
 
144
 
145
        /**
145
        /**
146
         * @return string
146
         * @return string
147
         */
147
         */
148
        public abstract static function root(): string;
148
        public abstract static function root(): string;
149
 
149
 
150
        /**
150
        /**
151
         * @return bool
151
         * @return bool
152
         */
152
         */
153
        public abstract function isRoot(): bool;
153
        public abstract function isRoot(): bool;
154
 
154
 
155
        /**
155
        /**
156
         * @param bool $with_ns
156
         * @param bool $with_ns
157
         * @return string
157
         * @return string
158
         */
158
         */
159
        public abstract function nodeId(bool $with_ns=true): string;
159
        public abstract function nodeId(bool $with_ns=true): string;
160
 
160
 
161
        /**
161
        /**
162
         * @param string $str
162
         * @param string $str
163
         * @return string mixed
163
         * @return string mixed
164
         * @throws OIDplusException
164
         * @throws OIDplusException
165
         */
165
         */
166
        public abstract function addString(string $str): string;
166
        public abstract function addString(string $str): string;
167
 
167
 
168
        /**
168
        /**
169
         * @param OIDplusObject $parent
169
         * @param OIDplusObject $parent
170
         * @return string
170
         * @return string
171
         */
171
         */
172
        public abstract function crudShowId(OIDplusObject $parent): string;
172
        public abstract function crudShowId(OIDplusObject $parent): string;
173
 
173
 
174
        /**
174
        /**
175
         * @return string
175
         * @return string
176
         */
176
         */
177
        public function crudInsertPrefix(): string {
177
        public function crudInsertPrefix(): string {
178
                return '';
178
                return '';
179
        }
179
        }
180
 
180
 
181
        /**
181
        /**
182
         * @return string
182
         * @return string
183
         */
183
         */
184
        public function crudInsertSuffix(): string {
184
        public function crudInsertSuffix(): string {
185
                return '';
185
                return '';
186
        }
186
        }
187
 
187
 
188
        /**
188
        /**
189
         * @param OIDplusObject|null $parent
189
         * @param OIDplusObject|null $parent
190
         * @return string
190
         * @return string
191
         */
191
         */
192
        public abstract function jsTreeNodeName(OIDplusObject $parent = null): string;
192
        public abstract function jsTreeNodeName(OIDplusObject $parent = null): string;
193
 
193
 
194
        /**
194
        /**
195
         * @return string
195
         * @return string
196
         */
196
         */
197
        public abstract function defaultTitle(): string;
197
        public abstract function defaultTitle(): string;
198
 
198
 
199
        /**
199
        /**
200
         * @return bool
200
         * @return bool
201
         */
201
         */
202
        public abstract function isLeafNode(): bool;
202
        public abstract function isLeafNode(): bool;
203
 
203
 
204
        /**
204
        /**
205
         * @param string $title
205
         * @param string $title
206
         * @param string $content
206
         * @param string $content
207
         * @param string $icon
207
         * @param string $icon
208
         * @return void
208
         * @return void
209
         */
209
         */
210
        public abstract function getContentPage(string &$title, string &$content, string &$icon);
210
        public abstract function getContentPage(string &$title, string &$content, string &$icon);
211
 
211
 
212
        /**
212
        /**
213
         * @param OIDplusRA|string|null $ra
213
         * @param OIDplusRA|string|null $ra
214
         * @return array
214
         * @return array
215
         * @throws OIDplusConfigInitializationException
215
         * @throws OIDplusConfigInitializationException
216
         * @throws OIDplusException
216
         * @throws OIDplusException
217
         */
217
         */
218
        public static function getRaRoots($ra=null) : array{
218
        public static function getRaRoots($ra=null) : array{
219
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
219
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
220
 
220
 
221
                $out = array();
221
                $out = array();
222
 
222
 
223
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
223
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
224
                        if (!$ra) {
224
                        if (!$ra) {
225
                                $res = OIDplus::db()->query("select oChild.id as id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ###objects as oChild ".
225
                                $res = OIDplus::db()->query("select oChild.id as id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ###objects as oChild ".
226
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
226
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
227
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'));
227
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'));
228
                                while ($row = $res->fetch_array()) {
228
                                while ($row = $res->fetch_array()) {
229
                                        if (!OIDplus::authUtils()->isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()->isRaLoggedIn($row['child_mail'])) {
229
                                        if (!OIDplus::authUtils()->isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()->isRaLoggedIn($row['child_mail'])) {
230
                                                $x = self::parse($row['id']); // can be NULL if namespace was disabled
230
                                                $x = self::parse($row['id']); // can be NULL if namespace was disabled
231
                                                if ($x) $out[] = $x;
231
                                                if ($x) $out[] = $x;
232
                                        }
232
                                        }
233
                                }
233
                                }
234
                        } else {
234
                        } else {
235
                                $res = OIDplus::db()->query("select oChild.id as id from ###objects as oChild ".
235
                                $res = OIDplus::db()->query("select oChild.id as id from ###objects as oChild ".
236
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
236
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
237
                                                            "where (".OIDplus::db()->getSlang()->isNullFunction('oParent.ra_email',"''")." <> ? and ".
237
                                                            "where (".OIDplus::db()->getSlang()->isNullFunction('oParent.ra_email',"''")." <> ? and ".
238
                                                            OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) or ".
238
                                                            OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) or ".
239
                                                            "      (oParent.ra_email is null and ".OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) ".
239
                                                            "      (oParent.ra_email is null and ".OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) ".
240
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'), array($ra, $ra, $ra));
240
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'), array($ra, $ra, $ra));
241
                                while ($row = $res->fetch_array()) {
241
                                while ($row = $res->fetch_array()) {
242
                                        $x = self::parse($row['id']); // can be NULL if namespace was disabled
242
                                        $x = self::parse($row['id']); // can be NULL if namespace was disabled
243
                                        if ($x) $out[] = $x;
243
                                        if ($x) $out[] = $x;
244
                                }
244
                                }
245
                        }
245
                        }
246
                } else {
246
                } else {
247
                        if (!$ra) {
247
                        if (!$ra) {
248
                                $ra_mails_to_check = OIDplus::authUtils()->loggedInRaList();
248
                                $ra_mails_to_check = OIDplus::authUtils()->loggedInRaList();
249
                                if (count($ra_mails_to_check) == 0) return $out;
249
                                if (count($ra_mails_to_check) == 0) return $out;
250
                        } else {
250
                        } else {
251
                                $ra_mails_to_check = array($ra);
251
                                $ra_mails_to_check = array($ra);
252
                        }
252
                        }
253
 
253
 
254
                        self::buildObjectInformationCache();
254
                        self::buildObjectInformationCache();
255
 
255
 
256
                        foreach ($ra_mails_to_check as $check_ra_mail) {
256
                        foreach ($ra_mails_to_check as $check_ra_mail) {
257
                                $out_part = array();
257
                                $out_part = array();
258
 
258
 
259
                                foreach (self::$object_info_cache as $id => $cacheitem) {
259
                                foreach (self::$object_info_cache as $id => $cacheitem) {
260
                                        if ($cacheitem[self::CACHE_RA_EMAIL] == $check_ra_mail) {
260
                                        if ($cacheitem[self::CACHE_RA_EMAIL] == $check_ra_mail) {
261
                                                $parent = $cacheitem[self::CACHE_PARENT];
261
                                                $parent = $cacheitem[self::CACHE_PARENT];
262
                                                if (!isset(self::$object_info_cache[$parent]) || (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] != $check_ra_mail)) {
262
                                                if (!isset(self::$object_info_cache[$parent]) || (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] != $check_ra_mail)) {
263
                                                        $out_part[] = $id;
263
                                                        $out_part[] = $id;
264
                                                }
264
                                                }
265
                                        }
265
                                        }
266
                                }
266
                                }
267
 
267
 
268
                                natsort($out_part);
268
                                natsort($out_part);
269
 
269
 
270
                                foreach ($out_part as $id) {
270
                                foreach ($out_part as $id) {
271
                                        $obj = self::parse($id);
271
                                        $obj = self::parse($id);
272
                                        if ($obj) $out[] = $obj;
272
                                        if ($obj) $out[] = $obj;
273
                                }
273
                                }
274
                        }
274
                        }
275
                }
275
                }
276
 
276
 
277
                return $out;
277
                return $out;
278
        }
278
        }
279
 
279
 
280
        /**
280
        /**
281
         * @return array
281
         * @return array
282
         * @throws OIDplusException
282
         * @throws OIDplusException
283
         */
283
         */
284
        public static function getAllNonConfidential(): array {
284
        public static function getAllNonConfidential(): array {
285
                $out = array();
285
                $out = array();
286
 
286
 
287
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
287
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
288
                        $res = OIDplus::db()->query("select id from ###objects where confidential = ? order by ".OIDplus::db()->natOrder('id'), array(false));
288
                        $res = OIDplus::db()->query("select id from ###objects where confidential = ? order by ".OIDplus::db()->natOrder('id'), array(false));
289
 
289
 
290
                        while ($row = $res->fetch_array()) {
290
                        while ($row = $res->fetch_array()) {
291
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
291
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
292
                                if ($obj && (!$obj->isConfidential())) {
292
                                if ($obj && (!$obj->isConfidential())) {
293
                                        $out[] = $row['id'];
293
                                        $out[] = $row['id'];
294
                                }
294
                                }
295
                        }
295
                        }
296
                } else {
296
                } else {
297
                        self::buildObjectInformationCache();
297
                        self::buildObjectInformationCache();
298
 
298
 
299
                        foreach (self::$object_info_cache as $id => $cacheitem) {
299
                        foreach (self::$object_info_cache as $id => $cacheitem) {
300
                                $confidential = $cacheitem[self::CACHE_CONFIDENTIAL];
300
                                $confidential = $cacheitem[self::CACHE_CONFIDENTIAL];
301
                                if (!$confidential) {
301
                                if (!$confidential) {
302
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
302
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
303
                                        if ($obj && (!$obj->isConfidential())) {
303
                                        if ($obj && (!$obj->isConfidential())) {
304
                                                $out[] = $id;
304
                                                $out[] = $id;
305
                                        }
305
                                        }
306
                                }
306
                                }
307
                        }
307
                        }
308
                }
308
                }
309
 
309
 
310
                return $out;
310
                return $out;
311
        }
311
        }
312
 
312
 
313
        /**
313
        /**
314
         * @return bool
314
         * @return bool
315
         * @throws OIDplusException
315
         * @throws OIDplusException
316
         */
316
         */
317
        public function isConfidential(): bool {
317
        public function isConfidential(): bool {
318
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
318
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
319
                        //static $confidential_cache = array();
319
                        //static $confidential_cache = array();
320
                        $curid = $this->nodeId();
320
                        $curid = $this->nodeId();
321
                        //$orig_curid = $curid;
321
                        //$orig_curid = $curid;
322
                        //if (isset($confidential_cache[$curid])) return $confidential_cache[$curid];
322
                        //if (isset($confidential_cache[$curid])) return $confidential_cache[$curid];
323
                        // Recursively search for the confidential flag in the parents
323
                        // Recursively search for the confidential flag in the parents
324
                        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
324
                        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
325
                                $row = $res->fetch_array();
325
                                $row = $res->fetch_array();
326
                                if ($row['confidential']) {
326
                                if ($row['confidential']) {
327
                                        //$confidential_cache[$curid] = true;
327
                                        //$confidential_cache[$curid] = true;
328
                                        //$confidential_cache[$orig_curid] = true;
328
                                        //$confidential_cache[$orig_curid] = true;
329
                                        return true;
329
                                        return true;
330
                                } else {
330
                                } else {
331
                                        //$confidential_cache[$curid] = false;
331
                                        //$confidential_cache[$curid] = false;
332
                                }
332
                                }
333
                                $curid = $row['parent'];
333
                                $curid = $row['parent'];
334
                                //if (isset($confidential_cache[$curid])) {
334
                                //if (isset($confidential_cache[$curid])) {
335
                                        //$confidential_cache[$orig_curid] = $confidential_cache[$curid];
335
                                        //$confidential_cache[$orig_curid] = $confidential_cache[$curid];
336
                                        //return $confidential_cache[$curid];
336
                                        //return $confidential_cache[$curid];
337
                                //}
337
                                //}
338
                        }
338
                        }
339
 
339
 
340
                        //$confidential_cache[$orig_curid] = false;
340
                        //$confidential_cache[$orig_curid] = false;
341
                        return false;
341
                        return false;
342
                } else {
342
                } else {
343
                        self::buildObjectInformationCache();
343
                        self::buildObjectInformationCache();
344
 
344
 
345
                        $curid = $this->nodeId();
345
                        $curid = $this->nodeId();
346
                        // Recursively search for the confidential flag in the parents
346
                        // Recursively search for the confidential flag in the parents
347
                        while (isset(self::$object_info_cache[$curid])) {
347
                        while (isset(self::$object_info_cache[$curid])) {
348
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
348
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
349
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
349
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
350
                        }
350
                        }
351
                        return false;
351
                        return false;
352
                }
352
                }
353
        }
353
        }
354
 
354
 
355
        /**
355
        /**
356
         * @param OIDplusObject $obj
356
         * @param OIDplusObject $obj
357
         * @return bool
357
         * @return bool
358
         * @throws OIDplusException
358
         * @throws OIDplusException
359
         */
359
         */
360
        public function isChildOf(OIDplusObject $obj): bool {
360
        public function isChildOf(OIDplusObject $obj): bool {
361
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
361
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
362
                        $curid = $this->nodeId();
362
                        $curid = $this->nodeId();
363
                        while (($res = OIDplus::db()->query("select parent from ###objects where id = ?", array($curid)))->any()) {
363
                        while (($res = OIDplus::db()->query("select parent from ###objects where id = ?", array($curid)))->any()) {
364
                                $row = $res->fetch_array();
364
                                $row = $res->fetch_array();
365
                                if ($curid == $obj->nodeId()) return true;
365
                                if ($curid == $obj->nodeId()) return true;
366
                                $curid = $row['parent'];
366
                                $curid = $row['parent'];
367
                        }
367
                        }
368
                        return false;
368
                        return false;
369
                } else {
369
                } else {
370
                        self::buildObjectInformationCache();
370
                        self::buildObjectInformationCache();
371
 
371
 
372
                        $curid = $this->nodeId();
372
                        $curid = $this->nodeId();
373
                        while (isset(self::$object_info_cache[$curid])) {
373
                        while (isset(self::$object_info_cache[$curid])) {
374
                                if ($curid == $obj->nodeId()) return true;
374
                                if ($curid == $obj->nodeId()) return true;
375
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
375
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
376
                        }
376
                        }
377
                        return false;
377
                        return false;
378
                }
378
                }
379
        }
379
        }
380
 
380
 
381
        /**
381
        /**
382
         * @return array
382
         * @return array
383
         * @throws OIDplusException
383
         * @throws OIDplusException
384
         */
384
         */
385
        public function getChildren(): array {
385
        public function getChildren(): array {
386
                $out = array();
386
                $out = array();
387
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
387
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
388
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array($this->nodeId()));
388
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array($this->nodeId()));
389
                        while ($row = $res->fetch_array()) {
389
                        while ($row = $res->fetch_array()) {
390
                                $obj = self::parse($row['id']);
390
                                $obj = self::parse($row['id']);
391
                                if (!$obj) continue;
391
                                if (!$obj) continue;
392
                                $out[] = $obj;
392
                                $out[] = $obj;
393
                        }
393
                        }
394
                } else {
394
                } else {
395
                        self::buildObjectInformationCache();
395
                        self::buildObjectInformationCache();
396
 
396
 
397
                        foreach (self::$object_info_cache as $id => $cacheitem) {
397
                        foreach (self::$object_info_cache as $id => $cacheitem) {
398
                                $parent = $cacheitem[self::CACHE_PARENT];
398
                                $parent = $cacheitem[self::CACHE_PARENT];
399
                                if ($parent == $this->nodeId()) {
399
                                if ($parent == $this->nodeId()) {
400
                                        $obj = self::parse($id);
400
                                        $obj = self::parse($id);
401
                                        if (!$obj) continue;
401
                                        if (!$obj) continue;
402
                                        $out[] = $obj;
402
                                        $out[] = $obj;
403
                                }
403
                                }
404
                        }
404
                        }
405
                }
405
                }
406
                return $out;
406
                return $out;
407
        }
407
        }
408
 
408
 
409
        /**
409
        /**
410
         * @return OIDplusRA
410
         * @return OIDplusRA
411
         * @throws OIDplusException
411
         * @throws OIDplusException
412
         */
412
         */
413
        public function getRa(): OIDplusRA {
413
        public function getRa(): OIDplusRA {
414
                return new OIDplusRA($this->getRaMail());
414
                return new OIDplusRA($this->getRaMail());
415
        }
415
        }
416
 
416
 
417
        /**
417
        /**
418
         * @param OIDplusRA|string|null $ra
418
         * @param OIDplusRA|string|null $ra
419
         * @return bool
419
         * @return bool
420
         * @throws OIDplusConfigInitializationException
420
         * @throws OIDplusConfigInitializationException
421
         * @throws OIDplusException
421
         * @throws OIDplusException
422
         */
422
         */
423
        public function userHasReadRights($ra=null): bool {
423
        public function userHasReadRights($ra=null): bool {
424
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
424
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
425
 
425
 
426
                // If it is not confidential, everybody can read/see it.
426
                // If it is not confidential, everybody can read/see it.
427
                // Note: This also checks if superior OIDs are confidential.
427
                // Note: This also checks if superior OIDs are confidential.
428
                if (!$this->isConfidential()) return true;
428
                if (!$this->isConfidential()) return true;
429
 
429
 
430
                if (!$ra) {
430
                if (!$ra) {
431
                        // Admin may do everything
431
                        // Admin may do everything
432
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
432
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
433
 
433
 
434
                        // If the RA is logged in, then they can see the OID.
434
                        // If the RA is logged in, then they can see the OID.
435
                        if (OIDplus::authUtils()->isRaLoggedIn($this->getRaMail())) return true;
435
                        if (OIDplus::authUtils()->isRaLoggedIn($this->getRaMail())) return true;
436
                } else {
436
                } else {
437
                        // If this OID belongs to the requested RA, then they may see it.
437
                        // If this OID belongs to the requested RA, then they may see it.
438
                        if ($this->getRaMail() == $ra) return true;
438
                        if ($this->getRaMail() == $ra) return true;
439
                }
439
                }
440
 
440
 
441
                // If someone has rights to an object below our confidential node,
441
                // If someone has rights to an object below our confidential node,
442
                // we let him see the confidential node,
442
                // we let him see the confidential node,
443
                // Otherwise he could not browse through to his own node.
443
                // Otherwise he could not browse through to his own node.
444
                $roots = $this->getRaRoots($ra);
444
                $roots = $this->getRaRoots($ra);
445
                foreach ($roots as $root) {
445
                foreach ($roots as $root) {
446
                        if ($root->isChildOf($this)) return true;
446
                        if ($root->isChildOf($this)) return true;
447
                }
447
                }
448
 
448
 
449
                return false;
449
                return false;
450
        }
450
        }
451
 
451
 
452
        /**
452
        /**
453
         * @param array|null $row
453
         * @param array|null $row
454
         * @return string|null
454
         * @return string|null
455
         * @throws OIDplusException
455
         * @throws OIDplusException
456
         */
456
         */
457
        public function getIcon(array $row=null) {
457
        public function getIcon(array $row=null) {
458
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
458
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
459
 
459
 
460
                if (is_null($row)) {
460
                if (is_null($row)) {
461
                        $ra_email = $this->getRaMail();
461
                        $ra_email = $this->getRaMail();
462
                } else {
462
                } else {
463
                        $ra_email = $row['ra_email'];
463
                        $ra_email = $row['ra_email'];
464
                }
464
                }
465
 
465
 
466
                $dirs = glob(OIDplus::localpath().'plugins/'.'*'.'/objectTypes/'.$namespace.'/');
466
                // $dirs = glob(OIDplus::localpath().'plugins/'.'*'.'/objectTypes/'.$namespace.'/');
467
 
-
 
468
                if (count($dirs) == 0) return null; // default icon (folder)
467
                // if (count($dirs) == 0) return null; // default icon (folder)
469
 
-
 
470
                $dir = substr($dirs[0], strlen(OIDplus::localpath()));
468
                // $dir = substr($dirs[0], strlen(OIDplus::localpath()));
-
 
469
                $reflection = new \ReflectionClass($this);
-
 
470
                $dir = dirname($reflection->getFilename());
-
 
471
                $dir = substr($dir, strlen(OIDplus::localpath()));
471
 
472
 
472
                if ($this->isRoot()) {
473
                if ($this->isRoot()) {
473
                        $icon = $dir . '/' . $this::treeIconFilename('root'); // see also OIDplusPagePublicObjects::get_treeicon_root()
474
                        $icon = $dir . '/' . $this::treeIconFilename('root');
474
                } else {
475
                } else {
475
                        // We use $this:: instead of self:: , because we want to call the overridden methods
476
                        // We use $this:: instead of self:: , because we want to call the overridden methods
476
                        if ($ra_email && OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
477
                        if ($ra_email && OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
477
                                if ($this->isLeafNode()) {
478
                                if ($this->isLeafNode()) {
478
                                        $icon = $dir . '/' . $this::treeIconFilename('own_leaf');
479
                                        $icon = $dir . '/' . $this::treeIconFilename('own_leaf');
479
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('own');
480
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('own');
480
                                } else {
481
                                } else {
481
                                        $icon = $dir . '/' . $this::treeIconFilename('own');
482
                                        $icon = $dir . '/' . $this::treeIconFilename('own');
482
                                }
483
                                }
483
                        } else {
484
                        } else {
484
                                if ($this->isLeafNode()) {
485
                                if ($this->isLeafNode()) {
485
                                        $icon = $dir . '/' . $this::treeIconFilename('general_leaf');
486
                                        $icon = $dir . '/' . $this::treeIconFilename('general_leaf');
486
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('general');
487
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('general');
487
                                } else {
488
                                } else {
488
                                        $icon = $dir . '/' . $this::treeIconFilename('general');
489
                                        $icon = $dir . '/' . $this::treeIconFilename('general');
489
                                }
490
                                }
490
                        }
491
                        }
491
                }
492
                }
492
 
493
 
493
                if (!file_exists($icon)) return null; // default icon (folder)
494
                if (!file_exists($icon)) return null; // default icon (folder)
494
 
495
 
495
                return $icon;
496
                return $icon;
496
        }
497
        }
497
 
498
 
498
        /**
499
        /**
499
         * @param string $id
500
         * @param string $id
500
         * @return bool
501
         * @return bool
501
         * @throws OIDplusException
502
         * @throws OIDplusException
502
         */
503
         */
503
        public static function exists(string $id): bool {
504
        public static function exists(string $id): bool {
504
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
505
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
505
                        $res = OIDplus::db()->query("select id from ###objects where id = ?", array($id));
506
                        $res = OIDplus::db()->query("select id from ###objects where id = ?", array($id));
506
                        return $res->any();
507
                        return $res->any();
507
                } else {
508
                } else {
508
                        self::buildObjectInformationCache();
509
                        self::buildObjectInformationCache();
509
                        return isset(self::$object_info_cache[$id]);
510
                        return isset(self::$object_info_cache[$id]);
510
                }
511
                }
511
        }
512
        }
512
 
513
 
513
        /**
514
        /**
514
         * Get parent gives the next possible parent which is EXISTING in OIDplus
515
         * Get parent gives the next possible parent which is EXISTING in OIDplus
515
         * It does not give the immediate parent
516
         * It does not give the immediate parent
516
         * @return OIDplusObject|null
517
         * @return OIDplusObject|null
517
         * @throws OIDplusException
518
         * @throws OIDplusException
518
         */
519
         */
519
        public function getParent()/*: ?OIDplusObject*/ {
520
        public function getParent()/*: ?OIDplusObject*/ {
520
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
521
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
521
                        $res = OIDplus::db()->query("select parent from ###objects where id = ?", array($this->nodeId()));
522
                        $res = OIDplus::db()->query("select parent from ###objects where id = ?", array($this->nodeId()));
522
                        if (!$res->any()) return null;
523
                        if (!$res->any()) return null;
523
                        $row = $res->fetch_array();
524
                        $row = $res->fetch_array();
524
                        $parent = $row['parent'];
525
                        $parent = $row['parent'];
525
                        $obj = OIDplusObject::parse($parent);
526
                        $obj = OIDplusObject::parse($parent);
526
                        if ($obj) return $obj;
527
                        if ($obj) return $obj;
527
                        // TODO: Also implement one_up() like below
528
                        // TODO: Also implement one_up() like below
528
                } else {
529
                } else {
529
                        self::buildObjectInformationCache();
530
                        self::buildObjectInformationCache();
530
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
531
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
531
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
532
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
532
                                $obj = OIDplusObject::parse($parent);
533
                                $obj = OIDplusObject::parse($parent);
533
                                if ($obj) return $obj;
534
                                if ($obj) return $obj;
534
                        }
535
                        }
535
 
536
 
536
                        // If this OID does not exist, the SQL query "select parent from ..." does not work. So we try to find the next possible parent using one_up()
537
                        // If this OID does not exist, the SQL query "select parent from ..." does not work. So we try to find the next possible parent using one_up()
537
                        $cur = $this->one_up();
538
                        $cur = $this->one_up();
538
                        if (!$cur) return null;
539
                        if (!$cur) return null;
539
                        do {
540
                        do {
540
                                // findFitting() checks if that OID exists
541
                                // findFitting() checks if that OID exists
541
                                if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
542
                                if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
542
 
543
 
543
                                $prev = $cur;
544
                                $prev = $cur;
544
                                $cur = $cur->one_up();
545
                                $cur = $cur->one_up();
545
                                if (!$cur) return null;
546
                                if (!$cur) return null;
546
                        } while ($prev !== $cur);
547
                        } while ($prev !== $cur);
547
                }
548
                }
548
                return null;
549
                return null;
549
        }
550
        }
550
 
551
 
551
        /**
552
        /**
552
         * @return false|string|null
553
         * @return false|string|null
553
         * @throws OIDplusException
554
         * @throws OIDplusException
554
         */
555
         */
555
        public function getRaMail() {
556
        public function getRaMail() {
556
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
557
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
557
                        $res = OIDplus::db()->query("select ra_email from ###objects where id = ?", array($this->nodeId()));
558
                        $res = OIDplus::db()->query("select ra_email from ###objects where id = ?", array($this->nodeId()));
558
                        if (!$res->any()) return null;
559
                        if (!$res->any()) return null;
559
                        $row = $res->fetch_array();
560
                        $row = $res->fetch_array();
560
                        return $row['ra_email'];
561
                        return $row['ra_email'];
561
                } else {
562
                } else {
562
                        self::buildObjectInformationCache();
563
                        self::buildObjectInformationCache();
563
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
564
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
564
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
565
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
565
                        }
566
                        }
566
                        return false;
567
                        return false;
567
                }
568
                }
568
        }
569
        }
569
 
570
 
570
        /**
571
        /**
571
         * @return false|string|null
572
         * @return false|string|null
572
         * @throws OIDplusException
573
         * @throws OIDplusException
573
         */
574
         */
574
        public function getTitle() {
575
        public function getTitle() {
575
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
576
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
576
                        $res = OIDplus::db()->query("select title from ###objects where id = ?", array($this->nodeId()));
577
                        $res = OIDplus::db()->query("select title from ###objects where id = ?", array($this->nodeId()));
577
                        if (!$res->any()) return null;
578
                        if (!$res->any()) return null;
578
                        $row = $res->fetch_array();
579
                        $row = $res->fetch_array();
579
                        return $row['title'];
580
                        return $row['title'];
580
                } else {
581
                } else {
581
                        self::buildObjectInformationCache();
582
                        self::buildObjectInformationCache();
582
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
583
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
583
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
584
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
584
                        }
585
                        }
585
                        return false;
586
                        return false;
586
                }
587
                }
587
        }
588
        }
588
 
589
 
589
        /**
590
        /**
590
         * @return false|string|null
591
         * @return false|string|null
591
         * @throws OIDplusException
592
         * @throws OIDplusException
592
         */
593
         */
593
        public function getDescription() {
594
        public function getDescription() {
594
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
595
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
595
                        $res = OIDplus::db()->query("select description from ###objects where id = ?", array($this->nodeId()));
596
                        $res = OIDplus::db()->query("select description from ###objects where id = ?", array($this->nodeId()));
596
                        if (!$res->any()) return null;
597
                        if (!$res->any()) return null;
597
                        $row = $res->fetch_array();
598
                        $row = $res->fetch_array();
598
                        return $row['description'];
599
                        return $row['description'];
599
                } else {
600
                } else {
600
                        self::buildObjectInformationCache();
601
                        self::buildObjectInformationCache();
601
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
602
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
602
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_DESCRIPTION];
603
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_DESCRIPTION];
603
                        }
604
                        }
604
                        return false;
605
                        return false;
605
                }
606
                }
606
        }
607
        }
607
 
608
 
608
        /**
609
        /**
609
         * @return false|string|null
610
         * @return false|string|null
610
         * @throws OIDplusException
611
         * @throws OIDplusException
611
         */
612
         */
612
        public function getComment() {
613
        public function getComment() {
613
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
614
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
614
                        $res = OIDplus::db()->query("select comment from ###objects where id = ?", array($this->nodeId()));
615
                        $res = OIDplus::db()->query("select comment from ###objects where id = ?", array($this->nodeId()));
615
                        if (!$res->any()) return null;
616
                        if (!$res->any()) return null;
616
                        $row = $res->fetch_array();
617
                        $row = $res->fetch_array();
617
                        return $row['comment'];
618
                        return $row['comment'];
618
                } else {
619
                } else {
619
                        self::buildObjectInformationCache();
620
                        self::buildObjectInformationCache();
620
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
621
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
621
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_COMMENT];
622
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_COMMENT];
622
                        }
623
                        }
623
                        return false;
624
                        return false;
624
                }
625
                }
625
        }
626
        }
626
 
627
 
627
        /**
628
        /**
628
         * @return false|string|null
629
         * @return false|string|null
629
         * @throws OIDplusException
630
         * @throws OIDplusException
630
         */
631
         */
631
        public function getCreatedTime() {
632
        public function getCreatedTime() {
632
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
633
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
633
                        $res = OIDplus::db()->query("select created from ###objects where id = ?", array($this->nodeId()));
634
                        $res = OIDplus::db()->query("select created from ###objects where id = ?", array($this->nodeId()));
634
                        if (!$res->any()) return null;
635
                        if (!$res->any()) return null;
635
                        $row = $res->fetch_array();
636
                        $row = $res->fetch_array();
636
                        return $row['created'];
637
                        return $row['created'];
637
                } else {
638
                } else {
638
                        self::buildObjectInformationCache();
639
                        self::buildObjectInformationCache();
639
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
640
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
640
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_CREATED];
641
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_CREATED];
641
                        }
642
                        }
642
                        return false;
643
                        return false;
643
                }
644
                }
644
        }
645
        }
645
 
646
 
646
        /**
647
        /**
647
         * @return false|string|null
648
         * @return false|string|null
648
         * @throws OIDplusException
649
         * @throws OIDplusException
649
         */
650
         */
650
        public function getUpdatedTime() {
651
        public function getUpdatedTime() {
651
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
652
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
652
                        $res = OIDplus::db()->query("select updated from ###objects where id = ?", array($this->nodeId()));
653
                        $res = OIDplus::db()->query("select updated from ###objects where id = ?", array($this->nodeId()));
653
                        if (!$res->any()) return null;
654
                        if (!$res->any()) return null;
654
                        $row = $res->fetch_array();
655
                        $row = $res->fetch_array();
655
                        return $row['updated'];
656
                        return $row['updated'];
656
                } else {
657
                } else {
657
                        self::buildObjectInformationCache();
658
                        self::buildObjectInformationCache();
658
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
659
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
659
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_UPDATED];
660
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_UPDATED];
660
                        }
661
                        }
661
                        return false;
662
                        return false;
662
                }
663
                }
663
        }
664
        }
664
 
665
 
665
        /**
666
        /**
666
         * @param OIDplusRA|string|null $ra
667
         * @param OIDplusRA|string|null $ra
667
         * @return bool
668
         * @return bool
668
         * @throws OIDplusException
669
         * @throws OIDplusException
669
         */
670
         */
670
        public function userHasParentalWriteRights($ra=null) {
671
        public function userHasParentalWriteRights($ra=null) {
671
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
672
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
672
 
673
 
673
                if (!$ra) {
674
                if (!$ra) {
674
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
675
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
675
                }
676
                }
676
 
677
 
677
                $objParent = $this->getParent();
678
                $objParent = $this->getParent();
678
                if (!$objParent) return false;
679
                if (!$objParent) return false;
679
                return $objParent->userHasWriteRights($ra);
680
                return $objParent->userHasWriteRights($ra);
680
        }
681
        }
681
 
682
 
682
        /**
683
        /**
683
         * @param OIDplusRA|string|null $ra
684
         * @param OIDplusRA|string|null $ra
684
         * @return bool
685
         * @return bool
685
         * @throws OIDplusException
686
         * @throws OIDplusException
686
         */
687
         */
687
        public function userHasWriteRights($ra=null): bool {
688
        public function userHasWriteRights($ra=null): bool {
688
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
689
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
689
 
690
 
690
                if (!$ra) {
691
                if (!$ra) {
691
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
692
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
692
                        return OIDplus::authUtils()->isRaLoggedIn($this->getRaMail());
693
                        return OIDplus::authUtils()->isRaLoggedIn($this->getRaMail());
693
                } else {
694
                } else {
694
                        return $this->getRaMail() == $ra;
695
                        return $this->getRaMail() == $ra;
695
                }
696
                }
696
        }
697
        }
697
 
698
 
698
        /**
699
        /**
699
         * @param string|OIDplusObject $to
700
         * @param string|OIDplusObject $to
700
         * @return int|null
701
         * @return int|null
701
         */
702
         */
702
        public function distance($to)/*: ?int*/ {
703
        public function distance($to)/*: ?int*/ {
703
                return null; // not implemented
704
                return null; // not implemented
704
        }
705
        }
705
 
706
 
706
        /**
707
        /**
707
         * @param OIDplusObject $obj
708
         * @param OIDplusObject $obj
708
         * @return bool
709
         * @return bool
709
         */
710
         */
710
        public function equals(OIDplusObject $obj): bool {
711
        public function equals(OIDplusObject $obj): bool {
711
                if (!$obj) return false;
712
                if (!$obj) return false;
712
                if (!is_object($obj)) $obj = OIDplusObject::parse($obj);
713
                if (!is_object($obj)) $obj = OIDplusObject::parse($obj);
713
                if (!$obj) return false;
714
                if (!$obj) return false;
714
                if (!($obj instanceof $this)) return false;
715
                if (!($obj instanceof $this)) return false;
715
 
716
 
716
                $distance = $this->distance($obj);
717
                $distance = $this->distance($obj);
717
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
718
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
718
 
719
 
719
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
720
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
720
        }
721
        }
721
 
722
 
722
        /**
723
        /**
723
         * @param string $id
724
         * @param string $id
724
         * @return OIDplusObject|false
725
         * @return OIDplusObject|false
725
         * @throws OIDplusException
726
         * @throws OIDplusException
726
         */
727
         */
727
        public static function findFitting(string $id) {
728
        public static function findFitting(string $id) {
728
                $obj = OIDplusObject::parse($id);
729
                $obj = OIDplusObject::parse($id);
729
                if (!$obj) return false; // e.g. if ObjectType plugin is disabled
730
                if (!$obj) return false; // e.g. if ObjectType plugin is disabled
730
 
731
 
731
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
732
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
732
                        $res = OIDplus::db()->query("select id from ###objects where id like ?", array($obj->ns().':%'));
733
                        $res = OIDplus::db()->query("select id from ###objects where id like ?", array($obj->ns().':%'));
733
                        while ($row = $res->fetch_object()) {
734
                        while ($row = $res->fetch_object()) {
734
                                $test = OIDplusObject::parse($row->id);
735
                                $test = OIDplusObject::parse($row->id);
735
                                if ($obj->equals($test)) return $test;
736
                                if ($obj->equals($test)) return $test;
736
                        }
737
                        }
737
                        return false;
738
                        return false;
738
                } else {
739
                } else {
739
                        self::buildObjectInformationCache();
740
                        self::buildObjectInformationCache();
740
                        foreach (self::$object_info_cache as $id => $cacheitem) {
741
                        foreach (self::$object_info_cache as $id => $cacheitem) {
741
                                if (strpos($id, $obj->ns().':') === 0) {
742
                                if (strpos($id, $obj->ns().':') === 0) {
742
                                        $test = OIDplusObject::parse($id);
743
                                        $test = OIDplusObject::parse($id);
743
                                        if ($obj->equals($test)) return $test;
744
                                        if ($obj->equals($test)) return $test;
744
                                }
745
                                }
745
                        }
746
                        }
746
                        return false;
747
                        return false;
747
                }
748
                }
748
        }
749
        }
749
 
750
 
750
        /**
751
        /**
751
         * @return OIDplusObject|null
752
         * @return OIDplusObject|null
752
         */
753
         */
753
        public function one_up()/*: ?OIDplusObject*/ {
754
        public function one_up()/*: ?OIDplusObject*/ {
754
                return null; // not implemented
755
                return null; // not implemented
755
        }
756
        }
756
 
757
 
757
        // Caching stuff
758
        // Caching stuff
758
 
759
 
759
        protected static $object_info_cache = null;
760
        protected static $object_info_cache = null;
760
 
761
 
761
        /**
762
        /**
762
         * @return void
763
         * @return void
763
         */
764
         */
764
        public static function resetObjectInformationCache() {
765
        public static function resetObjectInformationCache() {
765
                self::$object_info_cache = null;
766
                self::$object_info_cache = null;
766
        }
767
        }
767
 
768
 
768
        const CACHE_ID = 'id';
769
        const CACHE_ID = 'id';
769
        const CACHE_PARENT = 'parent';
770
        const CACHE_PARENT = 'parent';
770
        const CACHE_TITLE = 'title';
771
        const CACHE_TITLE = 'title';
771
        const CACHE_DESCRIPTION = 'description';
772
        const CACHE_DESCRIPTION = 'description';
772
        const CACHE_RA_EMAIL = 'ra_email';
773
        const CACHE_RA_EMAIL = 'ra_email';
773
        const CACHE_CONFIDENTIAL = 'confidential';
774
        const CACHE_CONFIDENTIAL = 'confidential';
774
        const CACHE_CREATED = 'created';
775
        const CACHE_CREATED = 'created';
775
        const CACHE_UPDATED = 'updated';
776
        const CACHE_UPDATED = 'updated';
776
        const CACHE_COMMENT = 'comment';
777
        const CACHE_COMMENT = 'comment';
777
 
778
 
778
        /**
779
        /**
779
         * @return void
780
         * @return void
780
         * @throws OIDplusException
781
         * @throws OIDplusException
781
         */
782
         */
782
        private static function buildObjectInformationCache() {
783
        private static function buildObjectInformationCache() {
783
                if (is_null(self::$object_info_cache)) {
784
                if (is_null(self::$object_info_cache)) {
784
                        self::$object_info_cache = array();
785
                        self::$object_info_cache = array();
785
                        $res = OIDplus::db()->query("select * from ###objects");
786
                        $res = OIDplus::db()->query("select * from ###objects");
786
                        while ($row = $res->fetch_array()) {
787
                        while ($row = $res->fetch_array()) {
787
                                self::$object_info_cache[$row['id']] = $row;
788
                                self::$object_info_cache[$row['id']] = $row;
788
                        }
789
                        }
789
                }
790
                }
790
        }
791
        }
791
 
792
 
792
        /**
793
        /**
793
         * override this function if you want your object type to save
794
         * override this function if you want your object type to save
794
         * attachments in directories with easy names.
795
         * attachments in directories with easy names.
795
         * Take care that your custom directory name will not allow jailbreaks (../) !
796
         * Take care that your custom directory name will not allow jailbreaks (../) !
796
         * @return string
797
         * @return string
797
         * @throws OIDplusException
798
         * @throws OIDplusException
798
         */
799
         */
799
        public function getDirectoryName(): string {
800
        public function getDirectoryName(): string {
800
                if ($this->isRoot()) return $this->ns();
801
                if ($this->isRoot()) return $this->ns();
801
                return $this->getLegacyDirectoryName();
802
                return $this->getLegacyDirectoryName();
802
        }
803
        }
803
 
804
 
804
        /**
805
        /**
805
         * @return string
806
         * @return string
806
         * @throws OIDplusException
807
         * @throws OIDplusException
807
         */
808
         */
808
        public final function getLegacyDirectoryName(): string {
809
        public final function getLegacyDirectoryName(): string {
809
                if ($this::ns() == 'oid') {
810
                if ($this::ns() == 'oid') {
810
                        $oid = $this->nodeId(false);
811
                        $oid = $this->nodeId(false);
811
                } else {
812
                } else {
812
                        $oid = null;
813
                        $oid = null;
813
                        $alt_ids = $this->getAltIds();
814
                        $alt_ids = $this->getAltIds();
814
                        foreach ($alt_ids as $alt_id) {
815
                        foreach ($alt_ids as $alt_id) {
815
                                if ($alt_id->getNamespace() == 'oid') {
816
                                if ($alt_id->getNamespace() == 'oid') {
816
                                        $oid = $alt_id->getId();
817
                                        $oid = $alt_id->getId();
817
                                        break; // we prefer the first OID (for GUIDs, the first OID is the OIDplus-OID, and the second OID is the UUID OID)
818
                                        break; // we prefer the first OID (for GUIDs, the first OID is the OIDplus-OID, and the second OID is the UUID OID)
818
                                }
819
                                }
819
                        }
820
                        }
820
                }
821
                }
821
 
822
 
822
                if (!is_null($oid) && ($oid != '')) {
823
                if (!is_null($oid) && ($oid != '')) {
823
                        // For OIDs, it is the OID, for other identifiers
824
                        // For OIDs, it is the OID, for other identifiers
824
                        // it it the OID alt ID (generated using the SystemID)
825
                        // it it the OID alt ID (generated using the SystemID)
825
                        return str_replace('.', '_', $oid);
826
                        return str_replace('.', '_', $oid);
826
                } else {
827
                } else {
827
                        // Can happen if you don't have a system ID (due to missing OpenSSL plugin)
828
                        // Can happen if you don't have a system ID (due to missing OpenSSL plugin)
828
                        return md5($this->nodeId(true)); // we don't use $id, because $this->nodeId(true) is possibly more canonical than $id
829
                        return md5($this->nodeId(true)); // we don't use $id, because $this->nodeId(true) is possibly more canonical than $id
829
                }
830
                }
830
        }
831
        }
831
 
832
 
832
        /**
833
        /**
833
         * @param string $mode
834
         * @param string $mode
834
         * @return string
835
         * @return string
835
         */
836
         */
836
        public static function treeIconFilename(string $mode): string {
837
        public static function treeIconFilename(string $mode): string {
837
                // for backwards-compatibility with older plugins
838
                // for backwards-compatibility with older plugins
838
                return 'img/treeicon_'.$mode.'.png';
839
                return 'img/treeicon_'.$mode.'.png';
839
        }
840
        }
840
 
841
 
841
}
842
}
842
 
843