1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11: class ElggAttributeLoader {
12:
13: 14: 15:
16: protected static $primary_attr_names = array(
17: 'guid',
18: 'type',
19: 'subtype',
20: 'owner_guid',
21: 'container_guid',
22: 'site_guid',
23: 'access_id',
24: 'time_created',
25: 'time_updated',
26: 'last_action',
27: 'enabled',
28: );
29:
30: 31: 32:
33: protected $secondary_attr_names = array();
34:
35: 36: 37:
38: protected $required_type;
39:
40: 41: 42:
43: protected $initialized_attributes;
44:
45: 46: 47:
48: protected $class;
49:
50: 51: 52:
53: public $requires_access_control = true;
54:
55: 56: 57:
58: public $primary_loader = 'get_entity_as_row';
59:
60: 61: 62:
63: public $secondary_loader = '';
64:
65: 66: 67:
68: public $full_loader = '';
69:
70: 71: 72: 73: 74: 75: 76: 77:
78: public function __construct($class, $required_type, array $initialized_attrs) {
79: if (!is_string($class)) {
80: throw new InvalidArgumentException('$class must be a class name.');
81: }
82: $this->class = $class;
83:
84: if (!is_string($required_type)) {
85: throw new InvalidArgumentException('$requiredType must be a system entity type.');
86: }
87: $this->required_type = $required_type;
88:
89: $this->initialized_attributes = $initialized_attrs;
90: unset($initialized_attrs['tables_split'], $initialized_attrs['tables_loaded']);
91: $all_attr_names = array_keys($initialized_attrs);
92: $this->secondary_attr_names = array_diff($all_attr_names, self::$primary_attr_names);
93: }
94:
95: 96: 97: 98: 99: 100:
101: protected function isMissingPrimaries($row) {
102: return array_diff(self::$primary_attr_names, array_keys($row)) !== array();
103: }
104:
105: 106: 107: 108: 109: 110:
111: protected function isMissingSecondaries($row) {
112: return array_diff($this->secondary_attr_names, array_keys($row)) !== array();
113: }
114:
115: 116: 117: 118: 119: 120: 121:
122: protected function checkType($row) {
123: if ($row['type'] !== $this->required_type) {
124: $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($row['guid'], $this->class));
125: throw new InvalidClassException($msg);
126: }
127: }
128:
129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141:
142: public function getRequiredAttributes($row) {
143: if (!is_array($row) && !($row instanceof stdClass)) {
144:
145: $row = array('guid' => $row);
146: }
147: $row = (array) $row;
148: if (empty($row['guid'])) {
149: throw new InvalidArgumentException('$row must be or contain a GUID');
150: }
151:
152:
153: foreach (array('tables_split', 'tables_loaded') as $key) {
154: if (isset($this->initialized_attributes[$key])) {
155: $row[$key] = $this->initialized_attributes[$key];
156: }
157: }
158:
159: $was_missing_primaries = $this->isMissingPrimaries($row);
160: $was_missing_secondaries = $this->isMissingSecondaries($row);
161:
162:
163: if (($was_missing_primaries || $was_missing_secondaries) && is_callable($this->full_loader)) {
164: $fetched = (array) call_user_func($this->full_loader, $row['guid']);
165: if (!$fetched) {
166: return array();
167: }
168: $row = array_merge($row, $fetched);
169: $this->checkType($row);
170: } else {
171: if ($was_missing_primaries) {
172: if (!is_callable($this->primary_loader)) {
173: throw new LogicException('Primary attribute loader must be callable');
174: }
175: if ($this->requires_access_control) {
176: $fetched = (array) call_user_func($this->primary_loader, $row['guid']);
177: } else {
178: $ignoring_access = elgg_set_ignore_access();
179: $fetched = (array) call_user_func($this->primary_loader, $row['guid']);
180: elgg_set_ignore_access($ignoring_access);
181: }
182: if (!$fetched) {
183: return array();
184: }
185: $row = array_merge($row, $fetched);
186: }
187:
188:
189:
190: $this->checkType($row);
191:
192: if ($was_missing_secondaries) {
193: if (!is_callable($this->secondary_loader)) {
194: throw new LogicException('Secondary attribute loader must be callable');
195: }
196: $fetched = (array) call_user_func($this->secondary_loader, $row['guid']);
197: if (!$fetched) {
198: if ($row['type'] === 'site') {
199:
200:
201:
202:
203:
204: $row = $this->filterAddedColumns($row);
205: $row['guid'] = (int) $row['guid'];
206: return $row;
207: }
208: throw new IncompleteEntityException("Secondary loader failed to return row for {$row['guid']}");
209: }
210: $row = array_merge($row, $fetched);
211: }
212: }
213:
214: $row = $this->filterAddedColumns($row);
215:
216:
217:
218:
219:
220: $row['guid'] = (int) $row['guid'];
221:
222: return $row;
223: }
224:
225: 226: 227: 228: 229: 230:
231: protected function filterAddedColumns($row) {
232:
233: $acceptable_attrs = self::$primary_attr_names;
234: array_splice($acceptable_attrs, count($acceptable_attrs), 0, $this->secondary_attr_names);
235: $acceptable_attrs = array_combine($acceptable_attrs, $acceptable_attrs);
236:
237:
238: $acceptable_attrs['tables_split'] = true;
239: $acceptable_attrs['tables_loaded'] = true;
240:
241: foreach ($row as $key => $val) {
242: if (!isset($acceptable_attrs[$key])) {
243: unset($row[$key]);
244: }
245: }
246: return $row;
247: }
248: }
249: