Object.php
5.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
<?php
/**
* @package AllediaFramework
* @contact www.alledia.com, hello@alledia.com
* @copyright 2016 Alledia.com, All rights reserved
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
*/
namespace Alledia\Framework;
use Alledia\Framework\Exception;
defined('_JEXEC') or die();
class Object
{
const MAP_UNDEFINED = 'undefined';
/**
* Retrieve all public properties and their values
* Although this duplicates get_object_vars(), it
* is mostly useful for internal calls when we need
* to filter out the non-public properties.
*
* @param bool $publicOnly
*
* @return array
*/
public function getProperties($publicOnly = true)
{
$reflection = new \ReflectionObject($this);
$properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);
if (!$publicOnly) {
$properties = array_merge(
$properties,
$reflection->getProperties(\ReflectionProperty::IS_PROTECTED)
);
}
$data = array();
foreach ($properties as $property) {
$name = $property->name;
$data[$name] = $this->$name;
}
return $data;
}
/**
* Set the public properties from the passed array/object
*
* @param array|object $data Values to copy to $this
* @param array $map Use properties from $data translated using a field map
*
* @return $this
* @throws Exception
*/
public function setProperties($data, array $map = null)
{
$properties = $this->getProperties();
if ($map !== null) {
$data = $this->map($data, array_keys($properties), $map);
} elseif (is_object($data)) {
$data = get_object_vars($data);
}
if (!is_array($data)) {
throw new Exception('Invalid argument given - ' . gettype($data));
}
foreach ($data as $k => $v) {
if (array_key_exists($k, $properties)) {
$this->$k = $data[$k];
}
}
return $this;
}
/**
* Set all properties to null
*
* @param bool $publicOnly Pass false to include protected properties as well
*
* @return $this
*/
public function clearProperties($publicOnly = true)
{
$properties = array_keys($this->getProperties($publicOnly));
foreach ($properties as $property) {
$this->$property = null;
}
return $this;
}
/**
* Map values in a source object/array to Joomlashack Framework keys using a map
* of key equivalences. Any fields in $keys not present in $map will be
* mapped name to name. Map fields mapped to null will be ignored.
*
* Special mappings for field values are recognized with another array. e.g.:
*
* $map['status'] = array(
* 'state' => array(
* 'active' => 1,
* 'closed' => 0,
* Object::MAP_UNDEFINED => -1
* )
* )
* Will map the extension field 'status' to the source field 'state' and
* set status based on the value in the state field. If no match, Object::MAP_UNDEFINED
* will be used for the unknown value.
*
*
* @param array|object $source Source data to be mapped
* @param array $keys Extension keys for which values are being requested
* @param array $map Associative array where key=Extension Key, value=Source Key
*
* @return array An array of all specified keys with values filled in based on map
* @throws Exception
*/
public function map($source, array $keys, array $map = array())
{
if (!is_object($source) && !is_array($source)) {
throw new Exception('Expected array or object for source argument');
}
$result = array_fill_keys($keys, null);
foreach ($keys as $srKey) {
$value = null;
if (!array_key_exists($srKey, $map)) {
$field = $srKey;
$value = $this->getKeyValue($source, $field);
} else {
// This is a mapped key
$field = $map[$srKey];
if (!is_array($field)) {
$value = $this->getKeyValue($source, $field);
} else {
// Mapped to field value
$values = reset($map[$srKey]);
$field = key($map[$srKey]);
$srcValue = $this->getKeyValue($source, $field);
if (isset($values[$srcValue])) {
$value = $values[$srcValue];
} elseif (isset($values[self::MAP_UNDEFINED])) {
$value = $values[self::MAP_UNDEFINED];
}
}
}
$result[$srKey] = $value;
}
return $result;
}
/**
* Safely get a value from an object|array
*
* @param object|array $data
* @param string $var
* @param mixed $default
*
* @return mixed
*/
public function getKeyValue($data, $var, $default = null)
{
if (is_object($data)) {
return isset($data->$var) ? $data->$var : $default;
}
return isset($data[$var]) ? $data[$var] : $default;
}
/**
*
* Default string rendering for the object. Subclasses should feel
* free to override as desired.
*
* @return string
*/
public function asString()
{
return get_class($this);
}
/**
* Expose properties with defined getters for direct use
*
* @param $name
*
* @return mixed
*/
public function __get($name)
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->$method();
}
return null;
}
public function __toString()
{
return $this->asString();
}
}