|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @author CONTENT CONTROL http://www.contentcontrol-berlin.de/ |
|
4
|
|
|
* @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/ |
|
5
|
|
|
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License |
|
6
|
|
|
*/ |
|
7
|
|
|
namespace midgard\portable\api; |
|
8
|
|
|
|
|
9
|
|
|
use midgard\portable\storage\connection; |
|
10
|
|
|
use midgard\portable\storage\objectmanager; |
|
11
|
|
|
use midgard\portable\storage\collection; |
|
12
|
|
|
use midgard\portable\storage\interfaces\metadata as metadata_interface; |
|
13
|
|
|
use midgard\portable\mgdschema\translator; |
|
14
|
|
|
use midgard\portable\api\error\exception; |
|
15
|
|
|
use Doctrine\ORM\Query; |
|
16
|
|
|
use midgard_connection; |
|
17
|
|
|
use Doctrine\ORM\Proxy\Proxy; |
|
18
|
|
|
use Doctrine\ORM\QueryBuilder; |
|
19
|
|
|
|
|
20
|
|
|
abstract class mgdobject extends dbobject |
|
21
|
|
|
{ |
|
22
|
|
|
protected $metadata; // compat with mgd behavior: If the schema has no metadata, the property is present anyway |
|
23
|
|
|
|
|
24
|
|
|
public $action = ''; // <== does this need to do anything? |
|
25
|
|
|
|
|
26
|
|
|
private $collections = []; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* |
|
30
|
|
|
* @param mixed $id ID or GUID |
|
31
|
|
|
*/ |
|
32
|
135 |
|
public function __construct($id = null) |
|
33
|
|
|
{ |
|
34
|
135 |
|
if ($id !== null) { |
|
35
|
50 |
|
if (is_int($id)) { |
|
36
|
41 |
|
$this->get_by_id($id); |
|
37
|
14 |
|
} elseif (is_string($id)) { |
|
38
|
14 |
|
$this->get_by_guid($id); |
|
39
|
|
|
} |
|
40
|
|
|
} |
|
41
|
133 |
|
} |
|
42
|
|
|
|
|
43
|
|
|
/** |
|
44
|
|
|
* |
|
45
|
|
|
* @param string $classname |
|
46
|
|
|
* @return collection |
|
47
|
|
|
*/ |
|
48
|
16 |
|
private function get_collection($classname) |
|
49
|
|
|
{ |
|
50
|
16 |
|
if (!isset($this->collections[$classname])) { |
|
51
|
16 |
|
$this->collections[$classname] = new collection($classname); |
|
52
|
|
|
} |
|
53
|
16 |
|
return $this->collections[$classname]; |
|
54
|
|
|
} |
|
55
|
|
|
|
|
56
|
1 |
|
public function __debugInfo() |
|
57
|
|
|
{ |
|
58
|
1 |
|
$ret = parent::__debugInfo(); |
|
59
|
1 |
|
if (property_exists($this, 'metadata')) { |
|
60
|
1 |
|
$metadata = new \stdClass; |
|
61
|
1 |
|
foreach ($this->cm->getFieldNames() as $name) { |
|
62
|
1 |
|
if (strpos($name, 'metadata_') !== false) { |
|
63
|
1 |
|
$fieldname = str_replace('metadata_', '', $name); |
|
64
|
1 |
|
$metadata->$fieldname = $this->__get($name); |
|
65
|
|
|
} |
|
66
|
|
|
} |
|
67
|
1 |
|
$ret['metadata'] = $metadata; |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
1 |
|
return $ret; |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
110 |
|
public function __set($field, $value) |
|
74
|
|
|
{ |
|
75
|
110 |
|
if ($field == 'guid') { |
|
76
|
6 |
|
return; |
|
77
|
|
|
} |
|
78
|
110 |
|
parent::__set($field, $value); |
|
79
|
110 |
|
} |
|
80
|
|
|
|
|
81
|
126 |
|
public function __get($field) |
|
82
|
|
|
{ |
|
83
|
126 |
|
if ( $field === 'metadata' |
|
84
|
126 |
|
&& $this->metadata === null |
|
85
|
126 |
|
&& $this instanceof metadata_interface) { |
|
86
|
102 |
|
$this->metadata = new metadata($this); |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
126 |
|
return parent::__get($field); |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
1 |
|
public function __call($method, $args) |
|
93
|
|
|
{ |
|
94
|
1 |
|
if ($method === 'list') { |
|
95
|
1 |
|
return $this->_list(); |
|
96
|
|
|
} |
|
97
|
|
|
throw new \BadMethodCallException("Unknown method " . $method . " on " . get_class($this)); |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
4 |
|
protected function load_parent(array $candidates) |
|
101
|
|
|
{ |
|
102
|
4 |
|
foreach ($candidates as $candidate) { |
|
103
|
4 |
|
if ($this->$candidate !== null) { |
|
104
|
|
|
//Proxies become stale if the object itself is detached, so we have to re-fetch |
|
105
|
4 |
|
if ( $this->$candidate instanceof Proxy |
|
106
|
4 |
|
&& $this->$candidate->__isInitialized()) { |
|
107
|
|
|
try { |
|
108
|
1 |
|
$this->$candidate->get_by_id($this->$candidate->id); |
|
109
|
|
|
} catch (exception $e) { |
|
110
|
|
|
connection::log()->error('Failed to refresh parent from proxy: ' . $e->getMessage()); |
|
111
|
|
|
return null; |
|
112
|
|
|
} |
|
113
|
|
|
} |
|
114
|
4 |
|
return $this->$candidate; |
|
115
|
|
|
} |
|
116
|
|
|
} |
|
117
|
1 |
|
return null; |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
/** |
|
121
|
|
|
* @param integer $id |
|
122
|
|
|
* @return boolean |
|
123
|
|
|
*/ |
|
124
|
43 |
|
public function get_by_id($id) |
|
125
|
|
|
{ |
|
126
|
43 |
|
$entity = connection::get_em()->find(get_class($this), $id); |
|
127
|
|
|
|
|
128
|
43 |
|
if ($entity === null) { |
|
129
|
3 |
|
throw exception::not_exists(); |
|
130
|
|
|
} |
|
131
|
|
|
// According to Doctrine documentation, proxies should be transparent, but in practice, |
|
132
|
|
|
// there will be problems if we don't force-load |
|
133
|
42 |
|
if ( $entity instanceof Proxy |
|
134
|
42 |
|
&& !$entity->__isInitialized()) { |
|
135
|
|
|
try { |
|
136
|
7 |
|
$entity->__load(); |
|
137
|
1 |
|
} catch (\Doctrine\ORM\EntityNotFoundException $e) { |
|
138
|
1 |
|
throw exception::object_purged(); |
|
139
|
|
|
} |
|
140
|
|
|
} |
|
141
|
42 |
|
if ($entity instanceof metadata_interface && $entity->{metadata_interface::DELETED_FIELD}) { |
|
142
|
|
|
// This can happen when the "deleted" entity is still in EM's identity map |
|
143
|
|
|
throw exception::object_deleted(); |
|
144
|
|
|
} |
|
145
|
42 |
|
if (empty($entity->guid)) { |
|
146
|
|
|
// This can happen when a reference proxy to a purged entity is still in EM's identity map |
|
147
|
|
|
throw exception::object_purged(); |
|
148
|
|
|
} |
|
149
|
|
|
|
|
150
|
42 |
|
$this->populate_from_entity($entity); |
|
151
|
|
|
|
|
152
|
42 |
|
connection::get_em()->detach($entity); |
|
|
|
|
|
|
153
|
42 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
154
|
42 |
|
return true; |
|
155
|
|
|
} |
|
156
|
|
|
|
|
157
|
|
|
/** |
|
158
|
|
|
* @param string $guid |
|
159
|
|
|
* @return boolean |
|
160
|
|
|
*/ |
|
161
|
16 |
|
public function get_by_guid($guid) |
|
162
|
|
|
{ |
|
163
|
16 |
|
if (!mgd_is_guid($guid)) { |
|
164
|
1 |
|
throw new \InvalidArgumentException("'$guid' is not a valid guid"); |
|
165
|
|
|
} |
|
166
|
15 |
|
$entity = connection::get_em()->getRepository(get_class($this))->findOneBy(['guid' => $guid]); |
|
167
|
15 |
|
if ($entity === null) { |
|
168
|
|
|
throw exception::not_exists(); |
|
169
|
|
|
} |
|
170
|
15 |
|
$this->populate_from_entity($entity); |
|
171
|
|
|
|
|
172
|
15 |
|
connection::get_em()->detach($entity); |
|
|
|
|
|
|
173
|
15 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
174
|
15 |
|
return true; |
|
175
|
|
|
} |
|
176
|
|
|
|
|
177
|
|
|
/** |
|
178
|
|
|
* @return boolean |
|
179
|
|
|
*/ |
|
180
|
108 |
|
public function create() |
|
181
|
|
|
{ |
|
182
|
108 |
|
if (!empty($this->id)) { |
|
183
|
2 |
|
exception::duplicate(); |
|
184
|
2 |
|
return false; |
|
185
|
|
|
} |
|
186
|
108 |
|
if ( !$this->is_unique() |
|
187
|
108 |
|
|| !$this->check_parent()) { |
|
188
|
2 |
|
return false; |
|
189
|
|
|
} |
|
190
|
108 |
|
if (!$this->check_fields()) { |
|
191
|
1 |
|
return false; |
|
192
|
|
|
} |
|
193
|
|
|
try { |
|
194
|
107 |
|
$om = new objectmanager(connection::get_em()); |
|
195
|
107 |
|
$om->create($this); |
|
196
|
|
|
} catch (\Exception $e) { |
|
197
|
|
|
exception::internal($e); |
|
198
|
|
|
return false; |
|
199
|
|
|
} |
|
200
|
|
|
|
|
201
|
107 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
202
|
|
|
|
|
203
|
107 |
|
return $this->id != 0; |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
/** |
|
207
|
|
|
* @return boolean |
|
208
|
|
|
*/ |
|
209
|
16 |
|
public function update() |
|
210
|
|
|
{ |
|
211
|
16 |
|
if (empty($this->id)) { |
|
212
|
1 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_INTERNAL); |
|
213
|
1 |
|
return false; |
|
214
|
|
|
} |
|
215
|
15 |
|
if (!$this->check_fields()) { |
|
216
|
2 |
|
return false; |
|
217
|
|
|
} |
|
218
|
|
|
try { |
|
219
|
13 |
|
$om = new objectmanager(connection::get_em()); |
|
220
|
13 |
|
$om->update($this); |
|
221
|
|
|
} catch (\Exception $e) { |
|
222
|
|
|
exception::internal($e); |
|
223
|
|
|
return false; |
|
224
|
|
|
} |
|
225
|
13 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
226
|
|
|
|
|
227
|
13 |
|
return true; |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
|
|
/** |
|
231
|
|
|
* @todo: Tests indicate that $check_dependencies is ignored in the mgd2 extension, |
|
232
|
|
|
* so we might consider ignoring it, too |
|
233
|
|
|
* |
|
234
|
|
|
* @return boolean |
|
235
|
|
|
*/ |
|
236
|
29 |
|
public function delete($check_dependencies = true) |
|
237
|
|
|
{ |
|
238
|
29 |
|
if (empty($this->id)) { |
|
239
|
1 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_INVALID_PROPERTY_VALUE); |
|
240
|
1 |
|
return false; |
|
241
|
|
|
} |
|
242
|
28 |
|
if ( $check_dependencies |
|
243
|
28 |
|
&& $this->has_dependents()) { |
|
244
|
4 |
|
exception::has_dependants(); |
|
245
|
4 |
|
return false; |
|
246
|
|
|
} |
|
247
|
28 |
|
if (!($this instanceof metadata_interface)) { |
|
248
|
1 |
|
exception::invalid_property_value(); |
|
249
|
1 |
|
return false; |
|
250
|
|
|
} |
|
251
|
27 |
|
if ($this->{metadata_interface::DELETED_FIELD}) { |
|
252
|
1 |
|
return true; |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
try { |
|
256
|
27 |
|
$om = new objectmanager(connection::get_em()); |
|
257
|
27 |
|
$om->delete($this); |
|
258
|
|
|
} catch (\Exception $e) { |
|
259
|
|
|
exception::internal($e); |
|
260
|
|
|
return false; |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
27 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
264
|
27 |
|
return true; |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
108 |
|
private function is_unique() |
|
268
|
|
|
{ |
|
269
|
108 |
|
$this->initialize(); |
|
270
|
|
|
|
|
271
|
108 |
|
if (empty($this->cm->midgard['unique_fields'])) { |
|
272
|
102 |
|
return true; |
|
273
|
|
|
} |
|
274
|
|
|
|
|
275
|
8 |
|
$qb = connection::get_em()->createQueryBuilder(); |
|
276
|
8 |
|
$qb->from(get_class($this), 'c'); |
|
277
|
8 |
|
$conditions = $qb->expr()->andX(); |
|
278
|
8 |
|
if ($this->id) { |
|
279
|
|
|
$parameters = [ |
|
280
|
|
|
'id' => $this->id |
|
281
|
|
|
]; |
|
282
|
|
|
$conditions->add($qb->expr()->neq('c.id', ':id')); |
|
283
|
|
|
} |
|
284
|
8 |
|
$found = false; |
|
285
|
8 |
|
foreach ($this->cm->midgard['unique_fields'] as $field) { |
|
286
|
8 |
|
if (empty($this->$field)) { |
|
287
|
|
|
//empty names automatically pass according to Midgard logic |
|
288
|
2 |
|
continue; |
|
289
|
|
|
} |
|
290
|
7 |
|
$conditions->add($qb->expr()->eq('c.' . $field, ':' . $field)); |
|
291
|
7 |
|
$parameters[$field] = $this->$field; |
|
292
|
7 |
|
$found = true; |
|
293
|
|
|
} |
|
294
|
|
|
|
|
295
|
8 |
|
if (!$found) { |
|
296
|
2 |
|
return true; |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
7 |
|
if (!empty($this->cm->midgard['upfield'])) { |
|
300
|
|
|
// TODO: This needs to be changed so that value is always numeric, since this is how midgard does it |
|
301
|
6 |
|
if ($this->{$this->cm->midgard['upfield']} === null) { |
|
302
|
6 |
|
$conditions->add($qb->expr()->isNull('c.' . $this->cm->midgard['upfield'])); |
|
303
|
|
|
} else { |
|
304
|
3 |
|
$conditions->add($qb->expr()->eq('c.' . $this->cm->midgard['upfield'], ':' . $this->cm->midgard['upfield'])); |
|
305
|
6 |
|
$parameters[$this->cm->midgard['upfield']] = $this->{$this->cm->midgard['upfield']}; |
|
306
|
|
|
} |
|
307
|
5 |
|
} elseif (!empty($this->cm->midgard['parentfield'])) { |
|
308
|
|
|
// TODO: This needs to be changed so that value is always numeric, since this is how midgard does it |
|
309
|
4 |
|
if ($this->{$this->cm->midgard['parentfield']} === null) { |
|
310
|
|
|
$conditions->add($qb->expr()->isNull('c.' . $this->cm->midgard['parentfield'])); |
|
311
|
|
|
} else { |
|
312
|
4 |
|
$conditions->add($qb->expr()->eq('c.' . $this->cm->midgard['parentfield'], ':' . $this->cm->midgard['parentfield'])); |
|
313
|
4 |
|
$parameters[$this->cm->midgard['parentfield']] = $this->{$this->cm->midgard['parentfield']}; |
|
314
|
|
|
} |
|
315
|
|
|
} |
|
316
|
7 |
|
$qb->where($conditions) |
|
317
|
7 |
|
->setParameters($parameters); |
|
|
|
|
|
|
318
|
|
|
|
|
319
|
7 |
|
$qb->select("count(c)"); |
|
320
|
7 |
|
$count = (int) $qb->getQuery()->getSingleScalarResult(); |
|
321
|
|
|
|
|
322
|
7 |
|
if ($count !== 0) { |
|
323
|
1 |
|
exception::object_name_exists(); |
|
324
|
1 |
|
return false; |
|
325
|
|
|
} |
|
326
|
7 |
|
return true; |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
108 |
|
private function check_parent() |
|
330
|
|
|
{ |
|
331
|
108 |
|
$this->initialize(); |
|
332
|
|
|
|
|
333
|
108 |
|
if ( empty($this->cm->midgard['parentfield']) |
|
334
|
108 |
|
|| empty($this->cm->midgard['parent'])) { |
|
335
|
108 |
|
return true; |
|
336
|
|
|
} |
|
337
|
|
|
|
|
338
|
8 |
|
if (empty($this->{$this->cm->midgard['parentfield']})) { |
|
339
|
1 |
|
exception::object_no_parent(); |
|
340
|
1 |
|
return false; |
|
341
|
|
|
} |
|
342
|
8 |
|
return true; |
|
343
|
|
|
} |
|
344
|
|
|
|
|
345
|
108 |
|
private function check_fields() |
|
346
|
|
|
{ |
|
347
|
108 |
|
$this->initialize(); |
|
348
|
|
|
|
|
349
|
108 |
|
foreach ($this->cm->fieldMappings as $name => $field) { |
|
350
|
108 |
|
if ( $field['midgard:midgard_type'] == translator::TYPE_GUID |
|
351
|
108 |
|
&& !empty($this->$name) |
|
352
|
108 |
|
&& !mgd_is_guid($this->$name)) { |
|
353
|
2 |
|
exception::invalid_property_value("'" . $name . "' property's value is not a guid."); |
|
354
|
2 |
|
return false; |
|
355
|
|
|
} |
|
356
|
|
|
} |
|
357
|
107 |
|
return $this->check_upfield(); |
|
358
|
|
|
} |
|
359
|
|
|
|
|
360
|
107 |
|
private function check_upfield() |
|
361
|
|
|
{ |
|
362
|
107 |
|
if ( !empty($this->id) |
|
363
|
107 |
|
&& !empty($this->cm->midgard['upfield']) |
|
|
|
|
|
|
364
|
107 |
|
&& $this->__get($this->cm->midgard['upfield']) === $this->id |
|
365
|
107 |
|
&& $this->cm->getAssociationMapping($this->cm->midgard['upfield'])['targetEntity'] === $this->cm->getName()) { |
|
|
|
|
|
|
366
|
1 |
|
exception::tree_is_circular(); |
|
367
|
1 |
|
return false; |
|
368
|
|
|
} |
|
369
|
|
|
// @todo this should be recursive |
|
370
|
107 |
|
return true; |
|
371
|
|
|
} |
|
372
|
|
|
|
|
373
|
|
|
public function is_in_parent_tree($root_id, $id) |
|
374
|
|
|
{ |
|
375
|
|
|
return false; |
|
376
|
|
|
} |
|
377
|
|
|
|
|
378
|
|
|
public function is_in_tree($root_id, $id) |
|
379
|
|
|
{ |
|
380
|
|
|
return false; |
|
381
|
|
|
} |
|
382
|
|
|
|
|
383
|
35 |
|
public function has_dependents() |
|
384
|
|
|
{ |
|
385
|
35 |
|
$this->initialize(); |
|
386
|
|
|
|
|
387
|
35 |
|
$stat = false; |
|
388
|
|
|
|
|
389
|
35 |
|
if (!empty($this->cm->midgard['upfield'])) { |
|
390
|
30 |
|
$qb = connection::get_em()->createQueryBuilder(); |
|
391
|
30 |
|
$qb->from(get_class($this), 'c') |
|
392
|
30 |
|
->where('c.' . $this->cm->midgard['upfield'] . ' = ?0') |
|
393
|
30 |
|
->setParameter(0, $this->id) |
|
394
|
30 |
|
->select("COUNT(c)"); |
|
395
|
30 |
|
$results = (int) $qb->getQuery()->getSingleScalarResult(); |
|
396
|
30 |
|
$stat = $results > 0; |
|
397
|
|
|
} |
|
398
|
|
|
|
|
399
|
35 |
|
if ( !$stat |
|
400
|
35 |
|
&& !empty($this->cm->midgard['childtypes'])) { |
|
401
|
28 |
|
foreach ($this->cm->midgard['childtypes'] as $typename => $parentfield) { |
|
402
|
28 |
|
$qb = connection::get_em()->createQueryBuilder(); |
|
403
|
28 |
|
$qb->from('midgard:' . $typename, 'c') |
|
404
|
28 |
|
->where('c.' . $parentfield . ' = ?0') |
|
405
|
28 |
|
->setParameter(0, $this->id) |
|
406
|
28 |
|
->select("COUNT(c)"); |
|
407
|
|
|
|
|
408
|
28 |
|
$results = (int) $qb->getQuery()->getSingleScalarResult(); |
|
409
|
28 |
|
$stat = $results > 0; |
|
410
|
28 |
|
if ($stat) { |
|
411
|
3 |
|
break; |
|
412
|
|
|
} |
|
413
|
|
|
} |
|
414
|
|
|
} |
|
415
|
|
|
|
|
416
|
35 |
|
return $stat; |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
public function get_parent() |
|
420
|
|
|
{ |
|
421
|
|
|
return null; |
|
422
|
|
|
} |
|
423
|
|
|
|
|
424
|
|
|
/** |
|
425
|
|
|
* This function is called list() in Midgard, but that doesn't work in plain PHP |
|
426
|
|
|
* |
|
427
|
|
|
* @return array |
|
428
|
|
|
*/ |
|
429
|
1 |
|
private function _list() |
|
430
|
|
|
{ |
|
431
|
1 |
|
$this->initialize(); |
|
432
|
|
|
|
|
433
|
1 |
|
if (!empty($this->cm->midgard['upfield'])) { |
|
434
|
1 |
|
$qb = connection::get_em()->createQueryBuilder(); |
|
435
|
1 |
|
$qb->from(get_class($this), 'c') |
|
436
|
1 |
|
->where('c.' . $this->cm->midgard['upfield'] . ' = ?0') |
|
437
|
1 |
|
->setParameter(0, $this->id) |
|
438
|
1 |
|
->select("c"); |
|
439
|
1 |
|
return $qb->getQuery()->getResult(); |
|
440
|
|
|
} |
|
441
|
|
|
|
|
442
|
|
|
return []; |
|
443
|
|
|
} |
|
444
|
|
|
|
|
445
|
|
|
/** |
|
446
|
|
|
* This should return child objects, but only if they are of a different type |
|
447
|
|
|
* For all other input, an empty array is returned |
|
448
|
|
|
* (not implemented yet) |
|
449
|
|
|
* |
|
450
|
|
|
* @param string $classname |
|
451
|
|
|
* @return array |
|
452
|
|
|
*/ |
|
453
|
|
|
public function list_children($classname) |
|
454
|
|
|
{ |
|
455
|
|
|
return []; |
|
456
|
|
|
} |
|
457
|
|
|
|
|
458
|
|
|
/** |
|
459
|
|
|
* @param string $path |
|
460
|
|
|
* @return boolean |
|
461
|
|
|
*/ |
|
462
|
1 |
|
public function get_by_path($path) |
|
463
|
|
|
{ |
|
464
|
1 |
|
$parts = explode('/', trim($path, '/')); |
|
465
|
1 |
|
if (empty($parts)) { |
|
466
|
|
|
return false; |
|
467
|
|
|
} |
|
468
|
1 |
|
$this->initialize(); |
|
469
|
|
|
|
|
470
|
1 |
|
if (count($this->cm->midgard['unique_fields']) != 1) { |
|
471
|
|
|
return false; |
|
472
|
|
|
} |
|
473
|
|
|
|
|
474
|
1 |
|
$field = $this->cm->midgard['unique_fields'][0]; |
|
475
|
|
|
|
|
476
|
1 |
|
if (!empty($this->cm->midgard['parent'])) { |
|
477
|
1 |
|
$parent_cm = connection::get_em()->getClassMetadata('midgard:' . $this->cm->midgard['parent']); |
|
478
|
1 |
|
$parentclass = $this->cm->fullyQualifiedClassName($this->cm->midgard['parent']); |
|
479
|
1 |
|
$parentfield = $parent_cm->midgard['upfield']; |
|
480
|
1 |
|
$upfield = $this->cm->midgard['parentfield']; |
|
481
|
1 |
|
} elseif (!empty($this->cm->midgard['upfield'])) { |
|
482
|
1 |
|
$parentclass = get_class($this); |
|
483
|
1 |
|
$upfield = $this->cm->midgard['upfield']; |
|
484
|
1 |
|
$parentfield = $upfield; |
|
485
|
|
|
} else { |
|
486
|
|
|
return false; |
|
487
|
|
|
} |
|
488
|
|
|
|
|
489
|
1 |
|
$name = array_pop($parts); |
|
490
|
1 |
|
$up = 0; |
|
491
|
1 |
|
foreach ($parts as $part) { |
|
492
|
1 |
|
$qb = $this->get_uniquefield_query($parentclass, $field, $part, $parentfield, $up); |
|
493
|
1 |
|
$qb->select("c.id"); |
|
494
|
1 |
|
$up = (int) $qb->getQuery()->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR); |
|
495
|
1 |
|
if ($up === 0) { |
|
496
|
1 |
|
exception::not_exists(); |
|
497
|
1 |
|
$this->id = 0; |
|
|
|
|
|
|
498
|
1 |
|
$this->set_guid(''); |
|
499
|
1 |
|
return false; |
|
500
|
|
|
} |
|
501
|
|
|
} |
|
502
|
|
|
|
|
503
|
1 |
|
$qb = $this->get_uniquefield_query(get_class($this), $field, $name, $upfield, $up); |
|
504
|
1 |
|
$qb->select("c"); |
|
505
|
|
|
|
|
506
|
1 |
|
$entity = $qb->getQuery()->getOneOrNullResult(); |
|
507
|
|
|
|
|
508
|
1 |
|
if ($entity === null) { |
|
509
|
1 |
|
exception::not_exists(); |
|
510
|
1 |
|
$this->id = 0; |
|
511
|
1 |
|
$this->set_guid(''); |
|
512
|
1 |
|
return false; |
|
513
|
|
|
} |
|
514
|
1 |
|
$this->populate_from_entity($entity); |
|
515
|
|
|
|
|
516
|
1 |
|
return true; |
|
517
|
|
|
} |
|
518
|
|
|
|
|
519
|
|
|
/** |
|
520
|
|
|
* @return QueryBuilder |
|
521
|
|
|
*/ |
|
522
|
1 |
|
protected function get_uniquefield_query($classname, $field, $part, $upfield, $up) |
|
523
|
|
|
{ |
|
524
|
1 |
|
$qb = connection::get_em()->createQueryBuilder(); |
|
525
|
1 |
|
$qb->from($classname, 'c'); |
|
526
|
1 |
|
$conditions = $qb->expr()->andX(); |
|
527
|
1 |
|
$conditions->add($qb->expr()->eq('c.' . $field, ':' . $field)); |
|
528
|
|
|
$parameters = [ |
|
529
|
1 |
|
$field => $part |
|
530
|
|
|
]; |
|
531
|
|
|
|
|
532
|
1 |
|
if (empty($up)) { |
|
533
|
|
|
// If the database was created by Midgard, it might contain 0 instead of NULL, so... |
|
534
|
1 |
|
$empty_conditions = $qb->expr()->orX() |
|
535
|
1 |
|
->add($qb->expr()->isNull('c.' . $upfield)) |
|
536
|
1 |
|
->add($qb->expr()->eq('c.' . $upfield, '0')); |
|
537
|
1 |
|
$conditions->add($empty_conditions); |
|
538
|
|
|
} else { |
|
539
|
1 |
|
$conditions->add($qb->expr()->eq('c.' . $upfield, ':' . $upfield)); |
|
540
|
1 |
|
$parameters[$upfield] = $up; |
|
541
|
|
|
} |
|
542
|
|
|
|
|
543
|
1 |
|
$qb->where($conditions) |
|
544
|
1 |
|
->setParameters($parameters); |
|
545
|
|
|
|
|
546
|
1 |
|
return $qb; |
|
547
|
|
|
} |
|
548
|
|
|
|
|
549
|
|
|
/** |
|
550
|
|
|
* @return boolean |
|
551
|
|
|
*/ |
|
552
|
|
|
public function parent() |
|
553
|
|
|
{ |
|
554
|
|
|
return false; |
|
555
|
|
|
} |
|
556
|
|
|
|
|
557
|
|
|
/** |
|
558
|
|
|
* @return boolean |
|
559
|
|
|
*/ |
|
560
|
1 |
|
public function has_parameters() |
|
561
|
|
|
{ |
|
562
|
1 |
|
return !$this->get_collection('midgard_parameter')->is_empty($this->guid); |
|
563
|
|
|
} |
|
564
|
|
|
|
|
565
|
4 |
|
public function list_parameters($domain = false) |
|
566
|
|
|
{ |
|
567
|
4 |
|
$constraints = []; |
|
568
|
4 |
|
if ($domain) { |
|
569
|
1 |
|
$constraints = ["domain" => $domain]; |
|
570
|
|
|
} |
|
571
|
|
|
|
|
572
|
4 |
|
return $this->get_collection('midgard_parameter')->find($this->guid, $constraints); |
|
573
|
|
|
} |
|
574
|
|
|
|
|
575
|
3 |
|
public function find_parameters(array $constraints = []) |
|
576
|
|
|
{ |
|
577
|
3 |
|
return $this->get_collection('midgard_parameter')->find($this->guid, $constraints); |
|
578
|
|
|
} |
|
579
|
|
|
|
|
580
|
|
|
/** |
|
581
|
|
|
* @param array $constraints |
|
582
|
|
|
* @return number |
|
583
|
|
|
*/ |
|
584
|
1 |
|
public function delete_parameters(array $constraints = []) |
|
585
|
|
|
{ |
|
586
|
1 |
|
return $this->get_collection('midgard_parameter')->delete($this->guid, $constraints); |
|
587
|
|
|
} |
|
588
|
|
|
|
|
589
|
|
|
/** |
|
590
|
|
|
* @param array $constraints |
|
591
|
|
|
* @return number |
|
592
|
|
|
*/ |
|
593
|
1 |
|
public function purge_parameters(array $constraints = []) |
|
594
|
|
|
{ |
|
595
|
1 |
|
return $this->get_collection('midgard_parameter')->purge($this->guid, $constraints); |
|
596
|
|
|
} |
|
597
|
|
|
|
|
598
|
2 |
|
public function get_parameter($domain, $name) |
|
599
|
|
|
{ |
|
600
|
2 |
|
if (!$this->guid) { |
|
601
|
1 |
|
return false; |
|
602
|
|
|
} |
|
603
|
2 |
|
$qb = connection::get_em()->createQueryBuilder(); |
|
604
|
|
|
$qb |
|
605
|
2 |
|
->select('c.value') |
|
606
|
2 |
|
->from('midgard:midgard_parameter', 'c') |
|
607
|
2 |
|
->where('c.domain = :domain AND c.name = :name AND c.parentguid = :parentguid') |
|
608
|
2 |
|
->setParameters(['domain' => $domain, 'name' => $name, 'parentguid' => $this->guid]); |
|
609
|
|
|
|
|
610
|
2 |
|
return $qb->getQuery()->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR); |
|
611
|
|
|
} |
|
612
|
|
|
|
|
613
|
|
|
/** |
|
614
|
|
|
* @param string $domain |
|
615
|
|
|
* @param string $name |
|
616
|
|
|
* @param mixed $value |
|
617
|
|
|
* @return boolean |
|
618
|
|
|
*/ |
|
619
|
11 |
|
public function set_parameter($domain, $name, $value) |
|
620
|
|
|
{ |
|
621
|
|
|
$constraints = [ |
|
622
|
11 |
|
'domain' => $domain, |
|
623
|
11 |
|
'name' => $name, |
|
624
|
|
|
]; |
|
625
|
11 |
|
$params = $this->get_collection('midgard_parameter')->find($this->guid, $constraints); |
|
626
|
|
|
|
|
627
|
|
|
// check value |
|
628
|
11 |
|
if (in_array($value, [false, null, ''], true)) { |
|
629
|
2 |
|
if (empty($params)) { |
|
630
|
1 |
|
exception::not_exists(); |
|
631
|
1 |
|
return false; |
|
632
|
|
|
} |
|
633
|
2 |
|
foreach ($params as $param) { |
|
634
|
2 |
|
$stat = $param->delete(); |
|
635
|
|
|
} |
|
636
|
2 |
|
return $stat; |
|
|
|
|
|
|
637
|
|
|
} |
|
638
|
|
|
|
|
639
|
11 |
|
$om = new objectmanager(connection::get_em()); |
|
640
|
|
|
try { |
|
641
|
|
|
// create new |
|
642
|
11 |
|
if (empty($params)) { |
|
643
|
11 |
|
$parameter = $om->new_instance(connection::get_em()->getClassMetadata('midgard:midgard_parameter')->getName()); |
|
644
|
11 |
|
$parameter->parentguid = $this->guid; |
|
|
|
|
|
|
645
|
11 |
|
$parameter->domain = $domain; |
|
|
|
|
|
|
646
|
11 |
|
$parameter->name = $name; |
|
|
|
|
|
|
647
|
11 |
|
$parameter->value = $value; |
|
|
|
|
|
|
648
|
11 |
|
$om->create($parameter); |
|
649
|
|
|
} |
|
650
|
|
|
// use existing |
|
651
|
|
|
else { |
|
652
|
1 |
|
$parameter = $params[0]; |
|
653
|
1 |
|
$parameter->value = $value; |
|
|
|
|
|
|
654
|
1 |
|
$om->update($parameter); |
|
655
|
|
|
} |
|
656
|
11 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
657
|
11 |
|
return true; |
|
658
|
|
|
} catch (\Exception $e) { |
|
659
|
|
|
exception::internal($e); |
|
660
|
|
|
return false; |
|
661
|
|
|
} |
|
662
|
|
|
} |
|
663
|
|
|
|
|
664
|
|
|
/** |
|
665
|
|
|
* The signature is a little different from original, because Doctrine doesn't support func_get_args() in proxies |
|
666
|
|
|
*/ |
|
667
|
2 |
|
public function parameter($domain, $name, $value = '__UNINITIALIZED__') |
|
668
|
|
|
{ |
|
669
|
2 |
|
if ($value === '__UNINITIALIZED__') { |
|
670
|
1 |
|
return $this->get_parameter($domain, $name); |
|
671
|
|
|
} |
|
672
|
2 |
|
return $this->set_parameter($domain, $name, $value); |
|
673
|
|
|
} |
|
674
|
|
|
|
|
675
|
|
|
/** |
|
676
|
|
|
* @return boolean |
|
677
|
|
|
*/ |
|
678
|
1 |
|
public function has_attachments() |
|
679
|
|
|
{ |
|
680
|
1 |
|
return !$this->get_collection('midgard_attachment')->is_empty($this->guid); |
|
681
|
|
|
} |
|
682
|
|
|
|
|
683
|
2 |
|
public function list_attachments() |
|
684
|
|
|
{ |
|
685
|
2 |
|
return $this->get_collection('midgard_attachment')->find($this->guid, []); |
|
686
|
|
|
} |
|
687
|
|
|
|
|
688
|
|
|
public function find_attachments(array $constraints = []) |
|
689
|
|
|
{ |
|
690
|
|
|
return $this->get_collection('midgard_attachment')->find($this->guid, $constraints); |
|
691
|
|
|
} |
|
692
|
|
|
|
|
693
|
|
|
/** |
|
694
|
|
|
* @param array $constraints |
|
695
|
|
|
* @return number |
|
696
|
|
|
*/ |
|
697
|
|
|
public function delete_attachments(array $constraints = []) |
|
698
|
|
|
{ |
|
699
|
|
|
return $this->get_collection('midgard_attachment')->delete($this->guid, $constraints); |
|
700
|
|
|
} |
|
701
|
|
|
|
|
702
|
|
|
/** |
|
703
|
|
|
* |
|
704
|
|
|
* @param array $constraints |
|
705
|
|
|
* @param boolean $delete_blob |
|
706
|
|
|
* @return boolean False if one or more attachments couldn't be deleted |
|
707
|
|
|
* @todo Implement delete_blob & return value |
|
708
|
|
|
*/ |
|
709
|
|
|
public function purge_attachments(array $constraints = [], $delete_blob = true) |
|
710
|
|
|
{ |
|
711
|
|
|
return $this->get_collection('midgard_attachment')->purge($this->guid, $constraints); |
|
712
|
|
|
} |
|
713
|
|
|
|
|
714
|
3 |
|
public function create_attachment($name, $title = '', $mimetype = '') |
|
715
|
|
|
{ |
|
716
|
3 |
|
$existing = $this->get_collection('midgard_attachment')->find($this->guid, ['name' => $name]); |
|
717
|
3 |
|
if (!empty($existing)) { |
|
718
|
1 |
|
exception::object_name_exists(); |
|
719
|
1 |
|
return null; |
|
720
|
|
|
} |
|
721
|
3 |
|
$om = new objectmanager(connection::get_em()); |
|
722
|
3 |
|
$att = $om->new_instance(connection::get_em()->getClassMetadata('midgard:midgard_attachment')->getName()); |
|
723
|
|
|
|
|
724
|
3 |
|
$att->parentguid = $this->guid; |
|
|
|
|
|
|
725
|
3 |
|
$att->title = $title; |
|
|
|
|
|
|
726
|
3 |
|
$att->name = $name; |
|
|
|
|
|
|
727
|
3 |
|
$att->mimetype = $mimetype; |
|
|
|
|
|
|
728
|
|
|
try { |
|
729
|
3 |
|
$om->create($att); |
|
730
|
3 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
731
|
3 |
|
return $att; |
|
732
|
|
|
} catch (\Exception $e) { |
|
733
|
|
|
exception::internal($e); |
|
734
|
|
|
return null; |
|
735
|
|
|
} |
|
736
|
|
|
} |
|
737
|
|
|
|
|
738
|
|
|
/** |
|
739
|
|
|
* @todo: Tests indicate that $check_dependencies is ignored in the mgd2 extension, |
|
740
|
|
|
* so we might consider ignoring it, too |
|
741
|
|
|
* @return boolean |
|
742
|
|
|
*/ |
|
743
|
17 |
|
public function purge($check_dependencies = true) |
|
744
|
|
|
{ |
|
745
|
17 |
|
if (empty($this->id)) { |
|
746
|
|
|
// This usually means that the object has been purged already |
|
747
|
|
|
exception::not_exists(); |
|
748
|
|
|
return false; |
|
749
|
|
|
} |
|
750
|
17 |
|
if ( $check_dependencies |
|
751
|
17 |
|
&& $this->has_dependents()) { |
|
752
|
2 |
|
exception::has_dependants(); |
|
753
|
2 |
|
return false; |
|
754
|
|
|
} |
|
755
|
|
|
|
|
756
|
|
|
try { |
|
757
|
17 |
|
$om = new objectmanager(connection::get_em()); |
|
758
|
17 |
|
$om->purge($this); |
|
759
|
2 |
|
} catch (\Doctrine\ORM\EntityNotFoundException $e) { |
|
760
|
2 |
|
exception::not_exists(); |
|
761
|
2 |
|
return false; |
|
762
|
|
|
} catch (\Exception $e) { |
|
763
|
|
|
exception::internal($e); |
|
764
|
|
|
return false; |
|
765
|
|
|
} |
|
766
|
17 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
767
|
|
|
|
|
768
|
17 |
|
return true; |
|
769
|
|
|
} |
|
770
|
|
|
|
|
771
|
|
|
/** |
|
772
|
|
|
* @return boolean |
|
773
|
|
|
*/ |
|
774
|
2 |
|
public static function undelete($guid) |
|
775
|
|
|
{ |
|
776
|
2 |
|
return \midgard_object_class::undelete($guid); |
|
777
|
|
|
} |
|
778
|
|
|
|
|
779
|
|
|
/** |
|
780
|
|
|
* @return \midgard_query_builder |
|
781
|
|
|
*/ |
|
782
|
1 |
|
public static function new_query_builder() |
|
783
|
|
|
{ |
|
784
|
1 |
|
return new \midgard_query_builder(get_called_class()); |
|
785
|
|
|
} |
|
786
|
|
|
|
|
787
|
|
|
/** |
|
788
|
|
|
* |
|
789
|
|
|
* @param string $field |
|
790
|
|
|
* @param mixed $value |
|
791
|
|
|
* @return \midgard_collector |
|
792
|
|
|
*/ |
|
793
|
1 |
|
public static function new_collector($field, $value) |
|
794
|
|
|
{ |
|
795
|
1 |
|
return new \midgard_collector(get_called_class(), $field, $value); |
|
796
|
|
|
} |
|
797
|
|
|
|
|
798
|
|
|
/** |
|
799
|
|
|
* @return \midgard_reflection_property |
|
800
|
|
|
*/ |
|
801
|
|
|
public static function new_reflection_property() |
|
802
|
|
|
{ |
|
803
|
|
|
return new \midgard_reflection_property(get_called_class()); |
|
804
|
|
|
} |
|
805
|
|
|
|
|
806
|
108 |
|
public function set_guid($guid) |
|
807
|
|
|
{ |
|
808
|
108 |
|
parent::__set('guid', $guid); |
|
809
|
108 |
|
} |
|
810
|
|
|
|
|
811
|
|
|
/** |
|
812
|
|
|
* Helper for managing the isapproved and islocked metadata properties |
|
813
|
|
|
* |
|
814
|
|
|
* @param string $action the property to manage (either approve or lock) |
|
815
|
|
|
* @param bool $value |
|
816
|
|
|
* @return boolean |
|
817
|
|
|
*/ |
|
818
|
8 |
|
private function manage_meta_property($action, $value) |
|
819
|
|
|
{ |
|
820
|
8 |
|
if (!($this instanceof metadata_interface)) { |
|
821
|
4 |
|
exception::no_metadata(); |
|
822
|
4 |
|
return false; |
|
823
|
|
|
} |
|
824
|
4 |
|
$user = connection::get_user(); |
|
825
|
4 |
|
if ($user === null) { |
|
826
|
4 |
|
exception::access_denied(); |
|
827
|
4 |
|
return false; |
|
828
|
|
|
} |
|
829
|
4 |
|
if ($action == 'lock') { |
|
830
|
2 |
|
$flag = 'islocked'; |
|
831
|
2 |
|
} elseif ($action == 'approve') { |
|
832
|
2 |
|
$flag = 'isapproved'; |
|
833
|
|
|
} else { |
|
834
|
|
|
throw new exception('Unsupported action ' . $action); |
|
835
|
|
|
} |
|
836
|
|
|
// same val |
|
837
|
4 |
|
if ($this->__get('metadata')->$flag === $value) { |
|
838
|
3 |
|
return false; |
|
839
|
|
|
} |
|
840
|
4 |
|
if ($value === false) { |
|
841
|
2 |
|
$action = 'un' . $action; |
|
842
|
|
|
} |
|
843
|
|
|
|
|
844
|
4 |
|
if ($this->id) { |
|
845
|
|
|
try { |
|
846
|
4 |
|
$om = new objectmanager(connection::get_em()); |
|
847
|
4 |
|
$om->{$action}($this); |
|
848
|
|
|
} catch (\Exception $e) { |
|
849
|
|
|
exception::internal($e); |
|
850
|
|
|
return false; |
|
851
|
|
|
} |
|
852
|
|
|
} |
|
853
|
4 |
|
midgard_connection::get_instance()->set_error(MGD_ERR_OK); |
|
854
|
|
|
|
|
855
|
4 |
|
return true; |
|
856
|
|
|
} |
|
857
|
|
|
|
|
858
|
|
|
/** |
|
859
|
|
|
* @return boolean |
|
860
|
|
|
*/ |
|
861
|
3 |
|
public function approve() |
|
862
|
|
|
{ |
|
863
|
3 |
|
return $this->manage_meta_property("approve", true); |
|
864
|
|
|
} |
|
865
|
|
|
|
|
866
|
|
|
/** |
|
867
|
|
|
* @return boolean |
|
868
|
|
|
*/ |
|
869
|
2 |
|
public function is_approved() |
|
870
|
|
|
{ |
|
871
|
2 |
|
if (!($this instanceof metadata_interface)) { |
|
872
|
|
|
exception::no_metadata(); |
|
873
|
|
|
return false; |
|
874
|
|
|
} |
|
875
|
2 |
|
return $this->metadata_isapproved; |
|
|
|
|
|
|
876
|
|
|
} |
|
877
|
|
|
|
|
878
|
|
|
/** |
|
879
|
|
|
* @return boolean |
|
880
|
|
|
*/ |
|
881
|
2 |
|
public function unapprove() |
|
882
|
|
|
{ |
|
883
|
2 |
|
return $this->manage_meta_property("approve", false); |
|
884
|
|
|
} |
|
885
|
|
|
|
|
886
|
|
|
/** |
|
887
|
|
|
* @return boolean |
|
888
|
|
|
*/ |
|
889
|
3 |
|
public function lock() |
|
890
|
|
|
{ |
|
891
|
3 |
|
if ($this->is_locked()) { |
|
892
|
1 |
|
exception::object_is_locked(); |
|
893
|
1 |
|
return false; |
|
894
|
|
|
} |
|
895
|
3 |
|
return $this->manage_meta_property("lock", true); |
|
896
|
|
|
} |
|
897
|
|
|
|
|
898
|
|
|
/** |
|
899
|
|
|
* @return boolean |
|
900
|
|
|
*/ |
|
901
|
3 |
|
public function is_locked() |
|
902
|
|
|
{ |
|
903
|
3 |
|
if (!($this instanceof metadata_interface)) { |
|
904
|
1 |
|
exception::no_metadata(); |
|
905
|
1 |
|
return false; |
|
906
|
|
|
} |
|
907
|
2 |
|
return $this->metadata_islocked; |
|
|
|
|
|
|
908
|
|
|
} |
|
909
|
|
|
|
|
910
|
|
|
/** |
|
911
|
|
|
* @return boolean |
|
912
|
|
|
*/ |
|
913
|
2 |
|
public function unlock() |
|
914
|
|
|
{ |
|
915
|
2 |
|
return $this->manage_meta_property("lock", false); |
|
916
|
|
|
} |
|
917
|
|
|
} |
|
918
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.