Completed
Push — master ( 2c0a26...1ebb0e )
by Joe
02:03
created

Win32Model::getWmiClassNameAttribute()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 12
ccs 5
cts 7
cp 0.7143
rs 10
cc 3
nc 3
nop 0
crap 3.2098
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
    /* TODO: Remove ObjectPath dependency. Should be passed into attributes */
51 14
    public function __construct(array $attributes = [], ObjectPath $objectPath = null)
52
    {
53 14
        $this->setCasts($this->attribute_casting, $this->merge_parent_casting);
54 14
        $this->mergeHiddenAttributes($this->hidden_attributes, $this->merge_parent_hidden_attributes);
55 14
        $this->fill($attributes);
56
57 14
        $this->objectPath = $objectPath;
58 14
    }
59
60
    /**
61
     * @param Connection|string|null $connection
62
     *
63
     * @return ModelCollection|Win32Model[]
64
     */
65
    public static function all($connection = null)
66
    {
67
        return static::query(static::newInstance()->getConnection($connection))->all();
68
    }
69
70
    /**
71
     * @param array           $attributes
72
     * @param ObjectPath|null $objectPath
73
     *
74
     * @return Win32Model
75
     */
76 3
    public static function newInstance(array $attributes = [], ObjectPath $objectPath = null)
77
    {
78 3
        return new static($attributes, $objectPath);
79
    }
80
81
    /**
82
     * @param Connection|string|null $connection
83
     *
84
     * @return Builder
85
     */
86
    public static function query($connection = null)
87
    {
88
        return new Builder($self = static::newInstance(), $self->getConnection($connection));
89
    }
90
91
    /**
92
     * @return string
93
     */
94
    public function getConnectionName()
95
    {
96
        return $this->connection;
97
    }
98
99
    /**
100
     * @param Connection|string|null $connection
101
     *
102
     * @throws InvalidConnectionException
103
     *
104
     * @return Connection
105
     */
106 2
    public function getConnection($connection = null)
107
    {
108 2
        return connection($connection, $this->connection);
109
    }
110
111
    /**
112
     * @return string
113
     */
114 3
    public function getModelNameAttribute()
115
    {
116 3
        return $this->getClassName();
117
    }
118
119
    /**
120
     * @return string
121
     */
122 5
    public function getWmiClassNameAttribute()
123
    {
124 5
        if (!is_null($this->wmi_class_name)) {
125 3
            return $this->wmi_class_name;
126
        }
127
128 2
        if ($this->wmi_class_name = $this->wmiClassNameSearch()) {
129 2
            return $this->wmi_class_name;
130
        }
131
132
        throw new WmiClassNotFoundException(
133
            'Cannot find a suitable WMI Class to query. Please set $wmi_class_name manually.'
134
        );
135
    }
136
137
    /**
138
     * Uses the Classes constant class to map models to WMI models for querying. If the current instance
139
     * does not yield results then we search the class' parents until a suitable match is found.
140
     *
141
     * @return string|null
142
     */
143 2
    protected function wmiClassNameSearch()
144
    {
145 2
        if ($result = array_search(static::class, Classes::CLASS_MAP, true)) {
146 1
            return $result;
147
        }
148
149 1
        foreach (class_parents($this) as $parent) {
150 1
            if ($result = array_search($parent, Classes::CLASS_MAP, true)) {
151 1
                return $result;
152
            }
153
        }
154
155
        return null;
156
    }
157
158
    /**
159
     * @return string
160
     */
161 3
    public function getClassName()
162
    {
163 3
        $classname = get_called_class();
164
165 3
        if (preg_match('@\\\\([\w]+)$@', $classname, $matches)) {
166
            $classname = $matches[1];
167
        }
168
169 3
        return $classname;
170
    }
171
172
    /**
173
     * @return string
174
     */
175
    public function toJson(): string
176
    {
177
        return json_encode($this->toArray());
178
    }
179
180
    /**
181
     * @return string
182
     */
183
    public function toString(): string
184
    {
185
        return $this->toJson();
186
    }
187
188
    /**
189
     * @return string
190
     */
191
    public function __toString()
192
    {
193
        return $this->toString();
194
    }
195
196
    /**
197
     * @param array $attributes
198
     */
199 14
    protected function fill(array $attributes)
200
    {
201 14
        foreach ($attributes as $key => $value) {
202 3
            $key = lcfirst($key);
203 3
            $value = $this->reduceValueArray($value);
204 3
            if ($this->hasProperty($key)) {
205 3
                $this->{$key} = $this->cast($key, $value);
206 3
                continue;
207
            }
208
209
            $this->unmapped_attributes[$key] =
210
                $this->cast($key, $value);
211
        }
212 14
    }
213
214
    /**
215
     * @param $value
216
     *
217
     * @return mixed
218
     */
219 3
    protected function reduceValueArray($value)
220
    {
221 3
        if (is_array($value) && array_key_exists('value', $value)) {
222 2
            $value = $value['value'];
223
        }
224
225 3
        return $value;
226
    }
227
228
    /**
229
     * @TODO: This should just be a helper method instead of returning a callback.
230
     *
231
     * @param $constant_class
232
     *
233
     * @return Closure
234
     */
235
    protected function constantToStringCallback($constant_class)
236
    {
237
        return function ($constant) use ($constant_class) {
238
            if (trim($type = call_user_func_array($constant_class . '::string', [$constant])) === '') {
239
                return "[{$constant}] - UNKNOWN";
240
            }
241
242
            return "[{$constant}] - {$type}";
243
        };
244
    }
245
}
246