midgard_collector   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Test Coverage

Coverage 92.42%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 27
eloc 63
c 3
b 0
f 0
dl 0
loc 143
ccs 61
cts 66
cp 0.9242
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
B execute() 0 45 9
A set_key_property() 0 9 2
A __construct() 0 5 2
A add_value_property() 0 14 4
A get() 0 3 1
A list_keys() 0 6 2
A _has_results() 0 4 1
A get_subkey() 0 3 1
A build_property_select() 0 20 5
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
8
use midgard\portable\api\error\exception;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, exception. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
use midgard\portable\storage\connection;
10
11
class midgard_collector extends midgard_query_builder
12
{
13
    /**
14
     * the results determined by execute
15
     */
16
    private ?array $_results = null;
17
18
    private string $key_property = "guid";
19
20
    private array $value_properties = [];
21
22 11
    public function __construct(string $class, ?string $field = null, $value = null)
23
    {
24 11
        parent::__construct($class);
25 11
        if ($field) {
26 11
            $this->add_constraint($field, '=', $value);
27
        }
28
    }
29
30 5
    public function set_key_property(string $property) : bool
31
    {
32
        // after execute there is no sense in changing the key property
33 5
        if ($this->_results !== null) {
34
            return false;
35
        }
36 5
        $this->key_property = $property;
37
38 5
        return true;
39
    }
40
41 6
    public function add_value_property(string $property) : bool
42
    {
43 6
        if ($this->_results !== null) {
44
            return false;
45
        }
46
47 6
        if (!isset($this->value_properties[$property])) {
48
            try {
49 6
                $this->value_properties[$property] = $this->build_property_select($property);
50 1
            } catch (exception) {
51 1
                return false;
52
            }
53
        }
54 5
        return true;
55
    }
56
57 10
    protected function build_property_select(string $property) : string
58
    {
59 10
        $parsed = $this->parse_constraint_name($property);
60
61
        // for properties like up.name
62 9
        if (   str_contains($property, ".")
63 9
            && !(str_starts_with($property, "metadata"))) {
64 1
            return $parsed['name'] . " as " . str_replace(".", "_", $property);
65
        }
66
67 9
        $cm = connection::get_em()->getClassMetadata($this->classname);
68 9
        if (array_key_exists($property, $cm->midgard['field_aliases'])) {
0 ignored issues
show
Bug introduced by
Accessing midgard on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
69 1
            return $parsed['name'] . " as " . str_replace(".", "_", $property);
70
        }
71
72 9
        if ($cm->hasAssociation($property)) {
73 1
            return 'IDENTITY(' . $parsed['name'] . ") as " . $property;
74
        }
75
76 9
        return $parsed['name'];
77
    }
78
79 8
    public function execute() : bool
80
    {
81 8
        if ($this->_results !== null) {
82
            return false;
83
        }
84 8
        $this->check_groups();
85 8
        $properties = $this->value_properties;
86 8
        if (!isset($this->value_properties[$this->key_property])) {
87
            try {
88 7
                $properties[] = $this->build_property_select($this->key_property);
89
            } catch (exception $e) {
90
                throw new exception('Property "' . $this->key_property . '" not found in "' . $this->classname . '"', exception::INVALID_PROPERTY, $e);
91
            }
92
        }
93
94 8
        $this->qb->addSelect(implode(", ", $properties));
95 8
        $this->pre_execution();
96 8
        $results = $this->qb->getQuery()->getArrayResult();
97 8
        $this->post_execution();
98
99 8
        $cm = connection::get_em()->getClassMetadata($this->classname);
100
        // map results by current key property
101 8
        $results_map = [];
102 8
        foreach ($results as $result) {
103 8
            foreach ($result as $key => &$value) {
104
                // for metadata fields remove the "metadata_" prefix
105 8
                if (str_contains($key, "metadata_")) {
106 1
                    $result[str_replace("metadata_", "", $key)] = $value;
107 1
                    unset($result[$key]);
108
                }
109
                // TODO: find out why Doctrine doesn't do this on its own
110 8
                if ($cm->hasAssociation($key)) {
111 1
                    $value = (int) $value;
112
                }
113
            }
114 8
            $key = $result[$this->key_property];
115 8
            if (!isset($this->value_properties[$this->key_property])) {
116 7
                unset($result[$this->key_property]);
117
            }
118
119 8
            $results_map[$key] = $result;
120
        }
121
122 8
        $this->_results = $results_map;
123 8
        return true;
124
    }
125
126
    /**
127
     * @return array
128
     */
129 2
    public function get(string $key)
130
    {
131 2
        return $this->_results[$key] ?? false;
132
    }
133
134 2
    public function get_subkey(string $key, string $property)
135
    {
136 2
        return $this->_results[$key][$property] ?? false;
137
    }
138
139
    /**
140
     * check whether we got any results to work on
141
     */
142 8
    private function _has_results() : bool
143
    {
144
        // execute was not called or we got an empty resultset
145 8
        return !empty($this->_results);
146
    }
147
148 8
    public function list_keys() : array
149
    {
150 8
        if (!$this->_has_results()) {
151 1
            return [];
152
        }
153 8
        return array_fill_keys(array_keys($this->_results), '');
154
    }
155
}
156