Passed
Branch master (056094)
by Andreas
04:47
created

mgdobject::get_by_guid()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0067

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 14
ccs 10
cts 11
cp 0.9091
crap 3.0067
rs 9.4285
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 31
    {
34 135
        if ($id !== null) {
35 50
            if (is_int($id)) {
36 41
                $this->get_by_id($id);
37 49
            } elseif (is_string($id)) {
38 14
                $this->get_by_guid($id);
39 13
            }
40 48
        }
41 133
    }
42
43
    /**
44
     *
45
     * @param string $classname
46
     * @return collection
47
     */
48 16
    private function get_collection($classname)
49
    {
50 16
        if (!array_key_exists($classname, $this->collections)) {
51 16
            $this->collections[$classname] = new collection($classname);
52 16
        }
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 1
                }
66 1
            }
67 1
            $ret['metadata'] = $metadata;
68 1
        }
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 125
    public function __get($field)
82
    {
83
        if (   $field === 'metadata'
84 125
            && $this->metadata === null
85 125
            && $this instanceof metadata_interface) {
86 102
            $this->metadata = new metadata($this);
87 102
        }
88
89 125
        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 27
    protected function load_parent(array $candidates)
101 27
    {
102 4
        foreach ($candidates as $candidate) {
103 10
            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 1
                    } catch (exception $e) {
110
                        connection::log()->error('Failed to refresh parent from proxy: ' . $e->getMessage());
111
                        return null;
112 27
                    }
113 1
                }
114 4
                return $this->$candidate;
115
            }
116 3
        }
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
        if (   $entity instanceof Proxy
134 42
            && !$entity->__isInitialized()) {
135
            try {
136 7
                $entity->__load();
137 7
            } catch (\Doctrine\ORM\EntityNotFoundException $e) {
138 1
                throw exception::object_purged();
139
            }
140 6
        }
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 2
            throw exception::object_purged();
148 2
        }
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 17
    public function get_by_guid($guid)
162 1
    {
163 17
        if (!mgd_is_guid($guid)) {
164 2
            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 2
    }
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 3
            return false;
189 1
        }
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 107
        } 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 13
        } 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
        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 27
        } 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 8
        }
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 6
            } else {
304 3
                $conditions->add($qb->expr()->eq('c.' . $this->cm->midgard['upfield'], ':' . $this->cm->midgard['upfield']));
305 3
                $parameters[$this->cm->midgard['upfield']] = $this->{$this->cm->midgard['upfield']};
306
            }
307 7
        } 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 4
        }
316 7
        $qb->where($conditions)
317 7
            ->setParameters($parameters);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parameters does not seem to be defined for all execution paths leading up to this point.
Loading history...
318
319 7
        $qb->select("count(c)");
320 7
        $count = intval($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 108
        }
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'])
0 ignored issues
show
Bug introduced by
Accessing midgard on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
364 107
            && $this->__get($this->cm->midgard['upfield']) === $this->id) {
365 1
            exception::tree_is_circular();
366 1
            return false;
367
        }
368
        // @todo this should be recursive
369 107
        return true;
370
    }
371
372
    public function is_in_parent_tree($root_id, $id)
373
    {
374
        return false;
375
    }
376
377
    public function is_in_tree($root_id, $id)
378
    {
379
        return false;
380
    }
381
382 35
    public function has_dependents()
383
    {
384 35
        $this->initialize();
385
386 35
        $stat = false;
387
388 35
        if (!empty($this->cm->midgard['upfield'])) {
389 30
            $qb = connection::get_em()->createQueryBuilder();
390 30
            $qb->from(get_class($this), 'c')
391 30
                ->where('c.' . $this->cm->midgard['upfield'] . ' = ?0')
392 30
                ->setParameter(0, $this->id)
393 30
                ->select("COUNT(c)");
394 30
            $results = intval($qb->getQuery()->getSingleScalarResult());
395 30
            $stat = ($results > 0);
396 30
        }
397
398
        if (   !$stat
399 35
            && !empty($this->cm->midgard['childtypes'])) {
400 28
            foreach ($this->cm->midgard['childtypes'] as $typename => $parentfield) {
401 28
                $qb = connection::get_em()->createQueryBuilder();
402 28
                $qb->from('midgard:' . $typename, 'c')
403 28
                    ->where('c.' . $parentfield . ' = ?0')
404 28
                    ->setParameter(0, $this->id)
405 28
                    ->select("COUNT(c)");
406
407 28
                $results = intval($qb->getQuery()->getSingleScalarResult());
408 28
                $stat = ($results > 0);
409 28
                if ($stat) {
410 3
                    break;
411
                }
412 28
            }
413 28
        }
414
415 35
        return $stat;
416
    }
417
418
    public function get_parent()
419
    {
420
        return null;
421
    }
422
423
    /**
424
     * This function is called list() in Midgard, but that doesn't work in plain PHP
425
     *
426
     * @return array
427
     */
428 1
    private function _list()
429
    {
430 1
        $this->initialize();
431
432 1
        if (!empty($this->cm->midgard['upfield'])) {
433 1
            $qb = connection::get_em()->createQueryBuilder();
434 1
            $qb->from(get_class($this), 'c')
435 1
                ->where('c.' . $this->cm->midgard['upfield'] . ' = ?0')
436 1
                ->setParameter(0, $this->id)
437 1
                ->select("c");
438 1
            return $qb->getQuery()->getResult();
439
        }
440
441
        return [];
442
    }
443
444
    /**
445
     * This should return child objects, but only if they are of a different type
446
     * For all other input, an empty array is returned
447
     * (not implemented yet)
448
     *
449
     * @param string $classname
450
     * @return array
451
     */
452
    public function list_children($classname)
453
    {
454
        return [];
455
    }
456
457
    /**
458
     * @param string $path
459
     * @return boolean
460
     */
461 1
    public function get_by_path($path)
462
    {
463 1
        $parts = explode('/', trim($path, '/'));
464 1
        if (empty($parts)) {
465
            return false;
466
        }
467 1
        $this->initialize();
468
469 1
        if (count($this->cm->midgard['unique_fields']) != 1) {
470
            return false;
471
        }
472
473 1
        $field = $this->cm->midgard['unique_fields'][0];
474
475 1
        if (!empty($this->cm->midgard['parent'])) {
476 1
            $parent_cm = connection::get_em()->getClassMetadata('midgard:' . $this->cm->midgard['parent']);
477 1
            $parentclass = $this->cm->fullyQualifiedClassName($this->cm->midgard['parent']);
478 1
            $parentfield = $parent_cm->midgard['upfield'];
479 1
            $upfield = $this->cm->midgard['parentfield'];
480 1
        } elseif (!empty($this->cm->midgard['upfield'])) {
481 1
            $parentclass = get_class($this);
482 1
            $upfield = $this->cm->midgard['upfield'];
483 1
            $parentfield = $upfield;
484 1
        } else {
485
            return false;
486
        }
487
488 1
        $name = array_pop($parts);
489 1
        $up = 0;
490 1
        foreach ($parts as $part) {
491 1
            $qb = $this->get_uniquefield_query($parentclass, $field, $part, $parentfield, $up);
492 1
            $qb->select("c.id");
493 1
            $up = intval($qb->getQuery()->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR));
494 1
            if ($up === 0) {
495 1
                exception::not_exists();
496 1
                $this->id = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
497 1
                $this->set_guid('');
498 1
                return false;
499
            }
500 1
        }
501
502 1
        $qb = $this->get_uniquefield_query(get_class($this), $field, $name, $upfield, $up);
503 1
        $qb->select("c");
504
505 1
        $entity = $qb->getQuery()->getOneOrNullResult();
506
507 1
        if ($entity === null) {
508 1
            exception::not_exists();
509 1
            $this->id = 0;
510 1
            $this->set_guid('');
511 1
            return false;
512
        }
513 1
        $this->populate_from_entity($entity);
514
515 1
        return true;
516
    }
517
518
    /**
519
     * @return QueryBuilder
520
     */
521 1
    protected function get_uniquefield_query($classname, $field, $part, $upfield, $up)
522
    {
523 1
        $qb = connection::get_em()->createQueryBuilder();
524 1
        $qb->from($classname, 'c');
525 1
        $conditions = $qb->expr()->andX();
526 1
        $conditions->add($qb->expr()->eq('c.' . $field, ':' . $field));
527
        $parameters = [
528
            $field => $part
529 1
        ];
530
531 1
        if (empty($up)) {
532
            // If the database was created by Midgard, it might contain 0 instead of NULL, so...
533 1
            $empty_conditions = $qb->expr()->orX()
534 1
                ->add($qb->expr()->isNull('c.' . $upfield))
535 1
                ->add($qb->expr()->eq('c.' . $upfield, '0'));
536 1
            $conditions->add($empty_conditions);
537 1
        } else {
538 1
            $conditions->add($qb->expr()->eq('c.' . $upfield, ':' . $upfield));
539 1
            $parameters[$upfield] = $up;
540
        }
541
542 1
        $qb->where($conditions)
543 1
            ->setParameters($parameters);
544
545 1
        return $qb;
546
    }
547
548
    /**
549
     * @return boolean
550
     */
551
    public function parent()
552
    {
553
        return false;
554
    }
555
556
    /**
557
     * @return boolean
558
     */
559 1
    public function has_parameters()
560
    {
561 1
        return !$this->get_collection('midgard_parameter')->is_empty($this->guid);
562
    }
563
564 4
    public function list_parameters($domain = false)
565
    {
566 4
        $constraints = [];
567 4
        if ($domain) {
568 1
            $constraints = ["domain" => $domain];
569 1
        }
570
571 4
        return $this->get_collection('midgard_parameter')->find($this->guid, $constraints);
572
    }
573
574 3
    public function find_parameters(array $constraints = [])
575
    {
576 3
        return $this->get_collection('midgard_parameter')->find($this->guid, $constraints);
577
    }
578
579
    /**
580
     * @param array $constraints
581
     * @return number
582
     */
583 1
    public function delete_parameters(array $constraints = [])
584
    {
585 1
        return $this->get_collection('midgard_parameter')->delete($this->guid, $constraints);
586
    }
587
588
    /**
589
     * @param array $constraints
590
     * @return number
591
     */
592 1
    public function purge_parameters(array $constraints = [])
593
    {
594 1
        return $this->get_collection('midgard_parameter')->purge($this->guid, $constraints);
595
    }
596
597 2
    public function get_parameter($domain, $name)
598
    {
599 2
        if (!$this->guid) {
600 1
            return false;
601
        }
602 2
        $qb = connection::get_em()->createQueryBuilder();
603
        $qb
604 2
            ->select('c.value')
605 2
            ->from('midgard:midgard_parameter', 'c')
606 2
            ->where('c.domain = :domain AND c.name = :name AND c.parentguid = :parentguid')
607 2
            ->setParameters(['domain' => $domain, 'name' => $name, 'parentguid' => $this->guid]);
608
609 2
        return $qb->getQuery()->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR);
610
    }
611
612
    /**
613
     * @param string $domain
614
     * @param string $name
615
     * @param mixed $value
616
     * @return boolean
617
     */
618 11
    public function set_parameter($domain, $name, $value)
619
    {
620
        $constraints = [
621 11
            'domain' => $domain,
622 11
            'name' => $name,
623 11
        ];
624 11
        $params = $this->get_collection('midgard_parameter')->find($this->guid, $constraints);
625
626
        // check value
627 11
        if ($value === false || $value === null || $value === "") {
628 2
            if (count($params) == 0) {
629 1
                exception::not_exists();
630 1
                return false;
631
            }
632 2
            foreach ($params as $param) {
633 2
                $stat = $param->delete();
634 2
            }
635 2
            return $stat;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $stat seems to be defined by a foreach iteration on line 632. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
636
        }
637
638 11
        $om = new objectmanager(connection::get_em());
639
        try {
640
            // create new
641 11
            if (count($params) == 0) {
642 11
                $parameter = $om->new_instance(connection::get_em()->getClassMetadata('midgard:midgard_parameter')->getName());
643 11
                $parameter->parentguid = $this->guid;
0 ignored issues
show
Bug Best Practice introduced by
The property parentguid does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
644 11
                $parameter->domain = $domain;
0 ignored issues
show
Bug Best Practice introduced by
The property domain does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
645 11
                $parameter->name = $name;
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
646 11
                $parameter->value = $value;
0 ignored issues
show
Bug Best Practice introduced by
The property value does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
647 11
                $om->create($parameter);
648 11
            }
649
            // use existing
650
            else {
651 1
                $parameter = array_shift($params);
652 1
                $parameter->value = $value;
653 1
                $om->update($parameter);
654
            }
655 11
            midgard_connection::get_instance()->set_error(MGD_ERR_OK);
656 11
            return true;
657
        } catch (\Exception $e) {
658
            exception::internal($e);
659
            return false;
660
        }
661
    }
662
663
    /**
664
     * The signature is a little different from original, because Doctrine doesn't support func_get_args() in proxies
665
     */
666 2
    public function parameter($domain, $name, $value = '__UNINITIALIZED__')
667
    {
668 2
        if ($value === '__UNINITIALIZED__') {
669 1
            return $this->get_parameter($domain, $name);
670
        }
671 2
        return $this->set_parameter($domain, $name, $value);
672
    }
673
674
    /**
675
     * @return boolean
676
     */
677 1
    public function has_attachments()
678
    {
679 1
        return !$this->get_collection('midgard_attachment')->is_empty($this->guid);
680
    }
681
682 2
    public function list_attachments()
683
    {
684 2
        return $this->get_collection('midgard_attachment')->find($this->guid, []);
685
    }
686
687
    public function find_attachments(array $constraints = [])
688
    {
689
        return $this->get_collection('midgard_attachment')->find($this->guid, $constraints);
690
    }
691
692
    /**
693
     * @param array $constraints
694
     * @return number
695
     */
696
    public function delete_attachments(array $constraints = [])
697
    {
698
        return $this->get_collection('midgard_attachment')->delete($this->guid, $constraints);
699
    }
700
701
    /**
702
     *
703
     * @param array $constraints
704
     * @param boolean $delete_blob
705
     * @return boolean False if one or more attachments couldn't be deleted
706
     * @todo Implement delete_blob & return value
707
     */
708
    public function purge_attachments(array $constraints = [], $delete_blob = true)
709
    {
710
        return $this->get_collection('midgard_attachment')->purge($this->guid, $constraints);
711
    }
712
713 3
    public function create_attachment($name, $title = '', $mimetype = '')
714
    {
715 3
        $existing = $this->get_collection('midgard_attachment')->find($this->guid, ['name' => $name]);
716 3
        if (count($existing) > 0) {
717 1
            exception::object_name_exists();
718 1
            return null;
719
        }
720 3
        $om = new objectmanager(connection::get_em());
721 3
        $att = $om->new_instance(connection::get_em()->getClassMetadata('midgard:midgard_attachment')->getName());
722
723 3
        $att->parentguid = $this->guid;
0 ignored issues
show
Bug Best Practice introduced by
The property parentguid does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
724 3
        $att->title = $title;
0 ignored issues
show
Bug Best Practice introduced by
The property title does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
725 3
        $att->name = $name;
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
726 3
        $att->mimetype = $mimetype;
0 ignored issues
show
Bug Best Practice introduced by
The property mimetype does not exist on midgard\portable\api\dbobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
727
        try {
728 3
            $om->create($att);
729 3
            midgard_connection::get_instance()->set_error(MGD_ERR_OK);
730 3
            return $att;
731
        } catch (\Exception $e) {
732
            exception::internal($e);
733
            return null;
734
        }
735
    }
736
737
    /**
738
     * @return boolean
739
     */
740
    public static function serve_attachment($guid)
741
    {
742
        return false;
743
    }
744
745
    /**
746
     * @todo: Tests indicate that $check_dependencies is ignored in the mgd2 extension,
747
     * so we might consider ignoring it, too
748
     * @return boolean
749
     */
750 17
    public function purge($check_dependencies = true)
751
    {
752 17
        if (empty($this->id)) {
753
            // This usually means that the object has been purged already
754
            exception::not_exists();
755
            return false;
756
        }
757
        if (   $check_dependencies
758 17
            && $this->has_dependents()) {
759 2
            exception::has_dependants();
760 2
            return false;
761
        }
762
763
        try {
764 17
            $om = new objectmanager(connection::get_em());
765 17
            $om->purge($this);
766 17
        } catch (\Doctrine\ORM\EntityNotFoundException $e) {
767 2
            exception::not_exists();
768 2
            return false;
769
        } catch (\Exception $e) {
770
            exception::internal($e);
771
            return false;
772
        }
773 17
        midgard_connection::get_instance()->set_error(MGD_ERR_OK);
774
775 17
        return true;
776
    }
777
778
    /**
779
     * @return boolean
780
     */
781 2
    public static function undelete($guid)
782
    {
783 2
        return \midgard_object_class::undelete($guid);
784
    }
785
786
    /**
787
     * @return boolean
788
     */
789
    public function connect($signal, $callback, $user_data)
790
    {
791
        return false;
792
    }
793
794
    /**
795
     * @return \midgard_query_builder
796
     */
797 1
    public static function new_query_builder()
798
    {
799 1
        return new \midgard_query_builder(get_called_class());
800
    }
801
802
    /**
803
     *
804
     * @param string $field
805
     * @param mixed $value
806
     * @return \midgard_collector
807
     */
808 1
    public static function new_collector($field, $value)
809
    {
810 1
        return new \midgard_collector(get_called_class(), $field, $value);
811
    }
812
813
    /**
814
     * @return \midgard_reflection_property
815
     */
816
    public static function new_reflection_property()
817
    {
818
        return new \midgard_reflection_property(get_called_class());
819
    }
820
821 108
    public function set_guid($guid)
822
    {
823 108
        parent::__set('guid', $guid);
824 108
    }
825
826
    /**
827
     * @return boolean
828
     */
829
    public function emit($signal)
830
    {
831
        return false;
832
    }
833
834
    /**
835
     * Helper for managing the isapproved and islocked metadata properties
836
     *
837
     * @param string $action the property to manage (either approve or lock)
838
     * @param bool $value
839
     * @return boolean
840
     */
841 8
    private function manage_meta_property($action, $value)
842
    {
843 8
        if (!($this instanceof metadata_interface)) {
844 4
            exception::no_metadata();
845 4
            return false;
846
        }
847 4
        $user = connection::get_user();
848 4
        if ($user === null) {
849 4
            exception::access_denied();
850 4
            return false;
851
        }
852 4
        if ($action == 'lock') {
853 2
            $flag = 'islocked';
854 4
        } elseif ($action == 'approve') {
855 2
            $flag = 'isapproved';
856 2
        } else {
857
            throw new exception('Unsupported action ' . $action);
858
        }
859
        // same val
860 4
        if ($this->__get('metadata')->$flag === $value) {
861 3
            return false;
862
        }
863 4
        if ($value === false) {
864 2
            $action = 'un' . $action;
865 2
        }
866
867 4
        if ($this->id) {
868
            try {
869 4
                $om = new objectmanager(connection::get_em());
870 4
                $om->{$action}($this);
871 4
            } catch (\Exception $e) {
872
                exception::internal($e);
873
                return false;
874
            }
875 4
        }
876 4
        midgard_connection::get_instance()->set_error(MGD_ERR_OK);
877
878 4
        return true;
879
    }
880
881
    /**
882
     * @return boolean
883
     */
884 3
    public function approve()
885
    {
886 3
        return $this->manage_meta_property("approve", true);
887
    }
888
889
    /**
890
     * @return boolean
891
     */
892 2
    public function is_approved()
893
    {
894 2
        if (!($this instanceof metadata_interface)) {
895
            exception::no_metadata();
896
            return false;
897
        }
898 2
        return $this->metadata_isapproved;
0 ignored issues
show
Bug Best Practice introduced by
The property metadata_isapproved does not exist on midgard\portable\api\mgdobject. Since you implemented __get, consider adding a @property annotation.
Loading history...
899
    }
900
901
    /**
902
     * @return boolean
903
     */
904 2
    public function unapprove()
905
    {
906 2
        return $this->manage_meta_property("approve", false);
907
    }
908
909
    /**
910
     * @return boolean
911
     */
912 3
    public function lock()
913
    {
914 3
        if ($this->is_locked()) {
915 1
            exception::object_is_locked();
916 1
            return false;
917
        }
918 3
        return $this->manage_meta_property("lock", true);
919
    }
920
921
    /**
922
     * @return boolean
923
     */
924 3
    public function is_locked()
925
    {
926 3
        if (!($this instanceof metadata_interface)) {
927 1
            exception::no_metadata();
928 1
            return false;
929
        }
930 2
        return $this->metadata_islocked;
0 ignored issues
show
Bug Best Practice introduced by
The property metadata_islocked does not exist on midgard\portable\api\mgdobject. Since you implemented __get, consider adding a @property annotation.
Loading history...
931
    }
932
933
    /**
934
     * @return boolean
935
     */
936 2
    public function unlock()
937
    {
938 2
        return $this->manage_meta_property("lock", false);
939
    }
940
941
    /**
942
     * @return boolean
943
     */
944
    public function get_workspace()
945
    {
946
        return false;
947
    }
948
}
949