Completed
Push — master ( 1c61d9...2c0a26 )
by Joe
02:01
created

Win32Model::query()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace PhpWinTools\WmiScripting;
4
5
use Closure;
6
use PhpWinTools\WmiScripting\Query\Builder;
7
use PhpWinTools\WmiScripting\Models\Classes;
8
use PhpWinTools\WmiScripting\Contracts\Jsonable;
9
use PhpWinTools\WmiScripting\Contracts\Arrayable;
10
use PhpWinTools\WmiScripting\Contracts\HasAttributes;
11
use PhpWinTools\WmiScripting\Concerns\ComHasAttributes;
12
use function PhpWinTools\WmiScripting\Support\connection;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, PhpWinTools\WmiScripting\connection. 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...
13
use PhpWinTools\WmiScripting\Collections\ModelCollection;
14
use PhpWinTools\WmiScripting\Exceptions\WmiClassNotFoundException;
15
use PhpWinTools\WmiScripting\Exceptions\InvalidConnectionException;
16
use PhpWinTools\WmiScripting\Support\ApiObjects\Contracts\ObjectPath;
17
18
/**
19
 * @link https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-provider
20
 */
21
class Win32Model implements Arrayable, Jsonable, HasAttributes
22
{
23
    use ComHasAttributes;
24
25
    /** @var string */
26
    protected $uuid;
27
28
    /** @var ObjectPath|null */
29
    protected $objectPath;
30
31
    /** @var Builder|null */
32
    protected $queryBuilder;
33
34
    /** @var array */
35
    protected $hidden_attributes = ['queryBuilder', 'connection', 'wmi_class_name'];
36
37
    /** @var bool */
38
    protected $merge_parent_casting = true;
39
40
    /** @var bool */
41
    protected $merge_parent_hidden_attributes = true;
42
43
    /** @var array */
44
    protected $attribute_casting = [];
45
46
    protected $connection = 'default';
47
48
    protected $wmi_class_name;
49
50 2
    public function __construct(array $attributes = [], ObjectPath $objectPath = null)
51
    {
52 2
        $this->setCasts($this->attribute_casting, $this->merge_parent_casting);
53 2
        $this->mergeHiddenAttributes($this->hidden_attributes, $this->merge_parent_hidden_attributes);
54 2
        $this->fill($attributes);
55
56 2
        $this->objectPath = $objectPath;
57 2
    }
58
59
    /**
60
     * @param Connection|string|null $connection
61
     *
62
     * @return ModelCollection|Win32Model[]
63
     */
64
    public static function all($connection = null)
65
    {
66
        return static::query(static::newInstance()->getConnection($connection))->all();
67
    }
68
69
    /**
70
     * @param array           $attributes
71
     * @param ObjectPath|null $objectPath
72
     *
73
     * @return Win32Model
74
     */
75 2
    public static function newInstance(array $attributes = [], ObjectPath $objectPath = null)
76
    {
77 2
        return new static($attributes, $objectPath);
78
    }
79
80
    /**
81
     * @param Connection|string|null $connection
82
     *
83
     * @return Builder
84
     */
85
    public static function query($connection = null)
86
    {
87
        return new Builder($self = static::newInstance(), $self->getConnection($connection));
88
    }
89
90
    /**
91
     * @return string
92
     */
93
    public function getConnectionName()
94
    {
95
        return $this->connection;
96
    }
97
98
    /**
99
     * @param Connection|string|null $connection
100
     *
101
     * @throws InvalidConnectionException
102
     *
103
     * @return Connection
104
     */
105 2
    public function getConnection($connection = null)
106
    {
107 2
        return connection($connection, $this->connection);
108
    }
109
110
    /**
111
     * @return string
112
     */
113
    public function getModelNameAttribute()
114
    {
115
        return $this->getClassName();
116
    }
117
118
    /**
119
     * @return string
120
     */
121 2
    public function getWmiClassNameAttribute()
122
    {
123 2
        if (!is_null($this->wmi_class_name)) {
124
            return $this->wmi_class_name;
125
        }
126
127 2
        if ($this->wmi_class_name = $this->wmiClassNameSearch()) {
128 2
            return $this->wmi_class_name;
129
        }
130
131
        throw new WmiClassNotFoundException(
132
            'Cannot find a suitable WMI Class to query. Please set $wmi_class_name manually.'
133
        );
134
    }
135
136
    /**
137
     * Uses the Classes constant class to map models to WMI models for querying. If the current instance
138
     * does not yield results then we search the class' parents until a suitable match is found.
139
     *
140
     * @return string|null
141
     */
142 2
    protected function wmiClassNameSearch()
143
    {
144 2
        if ($result = array_search(static::class, Classes::CLASS_MAP, true)) {
145 1
            return $result;
146
        }
147
148 1
        foreach (class_parents($this) as $parent) {
149 1
            if ($result = array_search($parent, Classes::CLASS_MAP, true)) {
150 1
                return $result;
151
            }
152
        }
153
154
        return null;
155
    }
156
157
    /**
158
     * @return string
159
     */
160
    public function getClassName()
161
    {
162
        $classname = get_called_class();
163
164
        if (preg_match('@\\\\([\w]+)$@', $classname, $matches)) {
165
            $classname = $matches[1];
166
        }
167
168
        return $classname;
169
    }
170
171
    /**
172
     * @return string
173
     */
174
    public function toJson(): string
175
    {
176
        return json_encode($this->toArray());
177
    }
178
179
    /**
180
     * @return string
181
     */
182
    public function toString(): string
183
    {
184
        return $this->toJson();
185
    }
186
187
    /**
188
     * @return string
189
     */
190
    public function __toString()
191
    {
192
        return $this->toString();
193
    }
194
195
    /**
196
     * @param array $attributes
197
     */
198 2
    protected function fill(array $attributes)
199
    {
200 2
        foreach ($attributes as $key => $value) {
201 2
            $key = lcfirst($key);
202 2
            $value = $this->reduceValueArray($value);
203 2
            if ($this->hasProperty($key)) {
204 2
                $this->{$key} = $this->cast($key, $value);
205 2
                continue;
206
            }
207
208
            $this->unmapped_attributes[$key] =
209
                $this->cast($key, $value);
210
        }
211 2
    }
212
213
    /**
214
     * @param $value
215
     *
216
     * @return mixed
217
     */
218 2
    protected function reduceValueArray($value)
219
    {
220 2
        if (is_array($value) && array_key_exists('value', $value)) {
221 2
            $value = $value['value'];
222
        }
223
224 2
        return $value;
225
    }
226
227
    /**
228
     * @param $constant_class
229
     *
230
     * @return Closure
231
     */
232
    protected function constantToStringCallback($constant_class)
233
    {
234
        return function ($constant) use ($constant_class) {
235
            if (trim($type = call_user_func_array($constant_class . '::string', [$constant])) === '') {
236
                return "[{$constant}] - UNKNOWN";
237
            }
238
239
            return "[{$constant}] - {$type}";
240
        };
241
    }
242
}
243