Win32Model::fill()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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