Completed
Push — master ( fd9a8e...06aafd )
by Andreas
06:23
created

mgdobject::is_unique()   B

Complexity

Conditions 11
Paths 67

Size

Total Lines 60
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 11.3284

Importance

Changes 0
Metric Value
cc 11
eloc 39
c 0
b 0
f 0
nc 67
nop 0
dl 0
loc 60
ccs 37
cts 43
cp 0.8605
crap 11.3284
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 107
            && $this->cm->getAssociationMapping($this->cm->midgard['upfield'])['targetEntity'] === $this->cm->getName()) {
0 ignored issues
show
Bug introduced by
The method getAssociationMapping() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. Did you maybe mean getAssociationNames()? ( Ignorable by Annotation )

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

365
            && $this->cm->/** @scrutinizer ignore-call */ getAssociationMapping($this->cm->midgard['upfield'])['targetEntity'] === $this->cm->getName()) {

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

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

Loading history...
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 = intval($qb->getQuery()->getSingleScalarResult());
396 30
            $stat = ($results > 0);
397 30
        }
398
399
        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 = intval($qb->getQuery()->getSingleScalarResult());
409 28
                $stat = ($results > 0);
410 28
                if ($stat) {
411 3
                    break;
412
                }
413 28
            }
414 28
        }
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 1
        } 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 = intval($qb->getQuery()->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR));
495 1
            if ($up === 0) {
496 1
                exception::not_exists();
497 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...
498 1
                $this->set_guid('');
499 1
                return false;
500
            }
501 1
        }
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
            $field => $part
530 1
        ];
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 1
        } 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 1
        }
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 11
        ];
625 11
        $params = $this->get_collection('midgard_parameter')->find($this->guid, $constraints);
626
627
        // check value
628 11
        if ($value === false || $value === null || $value === "") {
629 2
            if (count($params) == 0) {
630 1
                exception::not_exists();
631 1
                return false;
632
            }
633 2
            foreach ($params as $param) {
634 2
                $stat = $param->delete();
635 2
            }
636 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 633. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
637
        }
638
639 11
        $om = new objectmanager(connection::get_em());
640
        try {
641
            // create new
642 11
            if (count($params) == 0) {
643 11
                $parameter = $om->new_instance(connection::get_em()->getClassMetadata('midgard:midgard_parameter')->getName());
644 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...
645 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...
646 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...
647 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...
648 11
                $om->create($parameter);
649 11
            }
650
            // use existing
651
            else {
652 1
                $parameter = array_shift($params);
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 (count($existing) > 0) {
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;
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...
725 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...
726 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...
727 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...
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
     * @return boolean
740
     */
741
    public static function serve_attachment($guid)
742
    {
743
        return false;
744
    }
745
746
    /**
747
     * @todo: Tests indicate that $check_dependencies is ignored in the mgd2 extension,
748
     * so we might consider ignoring it, too
749
     * @return boolean
750
     */
751 17
    public function purge($check_dependencies = true)
752
    {
753 17
        if (empty($this->id)) {
754
            // This usually means that the object has been purged already
755
            exception::not_exists();
756
            return false;
757
        }
758
        if (   $check_dependencies
759 17
            && $this->has_dependents()) {
760 2
            exception::has_dependants();
761 2
            return false;
762
        }
763
764
        try {
765 17
            $om = new objectmanager(connection::get_em());
766 17
            $om->purge($this);
767 17
        } catch (\Doctrine\ORM\EntityNotFoundException $e) {
768 2
            exception::not_exists();
769 2
            return false;
770
        } catch (\Exception $e) {
771
            exception::internal($e);
772
            return false;
773
        }
774 17
        midgard_connection::get_instance()->set_error(MGD_ERR_OK);
775
776 17
        return true;
777
    }
778
779
    /**
780
     * @return boolean
781
     */
782 2
    public static function undelete($guid)
783
    {
784 2
        return \midgard_object_class::undelete($guid);
785
    }
786
787
    /**
788
     * @return boolean
789
     */
790
    public function connect($signal, $callback, $user_data)
791
    {
792
        return false;
793
    }
794
795
    /**
796
     * @return \midgard_query_builder
797
     */
798 1
    public static function new_query_builder()
799
    {
800 1
        return new \midgard_query_builder(get_called_class());
801
    }
802
803
    /**
804
     *
805
     * @param string $field
806
     * @param mixed $value
807
     * @return \midgard_collector
808
     */
809 1
    public static function new_collector($field, $value)
810
    {
811 1
        return new \midgard_collector(get_called_class(), $field, $value);
812
    }
813
814
    /**
815
     * @return \midgard_reflection_property
816
     */
817
    public static function new_reflection_property()
818
    {
819
        return new \midgard_reflection_property(get_called_class());
820
    }
821
822 108
    public function set_guid($guid)
823
    {
824 108
        parent::__set('guid', $guid);
825 108
    }
826
827
    /**
828
     * @return boolean
829
     */
830
    public function emit($signal)
831
    {
832
        return false;
833
    }
834
835
    /**
836
     * Helper for managing the isapproved and islocked metadata properties
837
     *
838
     * @param string $action the property to manage (either approve or lock)
839
     * @param bool $value
840
     * @return boolean
841
     */
842 8
    private function manage_meta_property($action, $value)
843
    {
844 8
        if (!($this instanceof metadata_interface)) {
845 4
            exception::no_metadata();
846 4
            return false;
847
        }
848 4
        $user = connection::get_user();
849 4
        if ($user === null) {
850 4
            exception::access_denied();
851 4
            return false;
852
        }
853 4
        if ($action == 'lock') {
854 2
            $flag = 'islocked';
855 4
        } elseif ($action == 'approve') {
856 2
            $flag = 'isapproved';
857 2
        } else {
858
            throw new exception('Unsupported action ' . $action);
859
        }
860
        // same val
861 4
        if ($this->__get('metadata')->$flag === $value) {
862 3
            return false;
863
        }
864 4
        if ($value === false) {
865 2
            $action = 'un' . $action;
866 2
        }
867
868 4
        if ($this->id) {
869
            try {
870 4
                $om = new objectmanager(connection::get_em());
871 4
                $om->{$action}($this);
872 4
            } catch (\Exception $e) {
873
                exception::internal($e);
874
                return false;
875
            }
876 4
        }
877 4
        midgard_connection::get_instance()->set_error(MGD_ERR_OK);
878
879 4
        return true;
880
    }
881
882
    /**
883
     * @return boolean
884
     */
885 3
    public function approve()
886
    {
887 3
        return $this->manage_meta_property("approve", true);
888
    }
889
890
    /**
891
     * @return boolean
892
     */
893 2
    public function is_approved()
894
    {
895 2
        if (!($this instanceof metadata_interface)) {
896
            exception::no_metadata();
897
            return false;
898
        }
899 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...
900
    }
901
902
    /**
903
     * @return boolean
904
     */
905 2
    public function unapprove()
906
    {
907 2
        return $this->manage_meta_property("approve", false);
908
    }
909
910
    /**
911
     * @return boolean
912
     */
913 3
    public function lock()
914
    {
915 3
        if ($this->is_locked()) {
916 1
            exception::object_is_locked();
917 1
            return false;
918
        }
919 3
        return $this->manage_meta_property("lock", true);
920
    }
921
922
    /**
923
     * @return boolean
924
     */
925 3
    public function is_locked()
926
    {
927 3
        if (!($this instanceof metadata_interface)) {
928 1
            exception::no_metadata();
929 1
            return false;
930
        }
931 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...
932
    }
933
934
    /**
935
     * @return boolean
936
     */
937 2
    public function unlock()
938
    {
939 2
        return $this->manage_meta_property("lock", false);
940
    }
941
942
    /**
943
     * @return boolean
944
     */
945
    public function get_workspace()
946
    {
947
        return false;
948
    }
949
}
950