Elgg  Version 1.9
AttributeLoader.php
Go to the documentation of this file.
1 <?php
2 
12 
18  protected static $primary_attr_names = array(
19  'guid',
20  'type',
21  'subtype',
22  'owner_guid',
23  'container_guid',
24  'site_guid',
25  'access_id',
26  'time_created',
27  'time_updated',
28  'last_action',
29  'enabled',
30  );
31 
35  protected static $integer_attr_names = array(
36  'guid',
37  'owner_guid',
38  'container_guid',
39  'site_guid',
40  'access_id',
41  'time_created',
42  'time_updated',
43  'last_action',
44  // ElggUser
45  'prev_last_action',
46  'last_login',
47  'prev_last_login'
48  );
49 
53  protected static $null_attr_names = array(
54  'name',
55  'title',
56  'description',
57  'url',
58  );
59 
63  protected $secondary_attr_names = array();
64 
68  protected $required_type;
69 
74 
78  protected $class;
79 
83  public $requires_access_control = true;
84 
88  public $primary_loader = 'get_entity_as_row';
89 
93  public $secondary_loader = '';
94 
98  public $full_loader = '';
99 
103  protected $additional_select_values = array();
104 
113  public function __construct($class, $required_type, array $initialized_attrs) {
114  if (!is_string($class)) {
115  throw new InvalidArgumentException('$class must be a class name.');
116  }
117  $this->class = $class;
118 
119  if (!is_string($required_type)) {
120  throw new InvalidArgumentException('$requiredType must be a system entity type.');
121  }
122  $this->required_type = $required_type;
123 
124  $this->initialized_attributes = $initialized_attrs;
125  $all_attr_names = array_keys($initialized_attrs);
126  $this->secondary_attr_names = array_diff($all_attr_names, self::$primary_attr_names);
127  }
128 
135  protected function isMissingPrimaries($row) {
136  return array_diff(self::$primary_attr_names, array_keys($row)) !== array();
137  }
138 
145  protected function isMissingSecondaries($row) {
146  return array_diff($this->secondary_attr_names, array_keys($row)) !== array();
147  }
148 
156  protected function checkType($row) {
157  if ($row['type'] !== $this->required_type) {
158  $msg = "GUID:" . $row['guid'] . " is not a valid " . $this->class;
159  throw new InvalidClassException($msg);
160  }
161  }
162 
168  public function getAdditionalSelectValues() {
170  }
171 
185  public function getRequiredAttributes($row) {
186  if (!is_array($row) && !($row instanceof stdClass)) {
187  // assume row is the GUID
188  $row = array('guid' => $row);
189  }
190  $row = (array) $row;
191  if (empty($row['guid'])) {
192  throw new InvalidArgumentException('$row must be or contain a GUID');
193  }
194 
195  $was_missing_primaries = $this->isMissingPrimaries($row);
196  $was_missing_secondaries = $this->isMissingSecondaries($row);
197 
198  // some types have a function to load all attributes at once, it should be faster
199  if (($was_missing_primaries || $was_missing_secondaries) && is_callable($this->full_loader)) {
200  $fetched = (array) call_user_func($this->full_loader, $row['guid']);
201  if (!$fetched) {
202  return array();
203  }
204  $row = array_merge($row, $fetched);
205  $this->checkType($row);
206  } else {
207  if ($was_missing_primaries) {
208  if (!is_callable($this->primary_loader)) {
209  throw new LogicException('Primary attribute loader must be callable');
210  }
211  if ($this->requires_access_control) {
212  $fetched = (array) call_user_func($this->primary_loader, $row['guid']);
213  } else {
214  $ignoring_access = elgg_set_ignore_access();
215  $fetched = (array) call_user_func($this->primary_loader, $row['guid']);
216  elgg_set_ignore_access($ignoring_access);
217  }
218  if (!$fetched) {
219  return array();
220  }
221  $row = array_merge($row, $fetched);
222  }
223 
224  // We must test type before trying to load the secondaries so that InvalidClassException
225  // gets thrown. Otherwise the secondary loader will fail and return false.
226  $this->checkType($row);
227 
228  if ($was_missing_secondaries) {
229  if (!is_callable($this->secondary_loader)) {
230  throw new LogicException('Secondary attribute loader must be callable');
231  }
232  $fetched = (array) call_user_func($this->secondary_loader, $row['guid']);
233  if (!$fetched) {
234  throw new IncompleteEntityException("Secondary loader failed to return row for {$row['guid']}");
235  }
236  $row = array_merge($row, $fetched);
237  }
238  }
239 
240  $row = $this->filterAddedColumns($row);
241 
242  $row['subtype'] = (int)$row['subtype'];
243 
244  // set to null when reading empty value, to match default empty value; See #5456
245  foreach (self::$null_attr_names as $key) {
246  if (isset($row[$key]) && !$row[$key]) {
247  $row[$key] = null;
248  }
249  }
250 
251  // Note: If there are still missing attributes, we're running on a 1.7 or earlier schema. We let
252  // this pass so the upgrades can run.
253 
254  // guid needs to be an int https://github.com/elgg/elgg/issues/4111
255  foreach (self::$integer_attr_names as $key) {
256  if (isset($row[$key])) {
257  $row[$key] = (int) $row[$key];
258  }
259  }
260  return $row;
261  }
262 
269  protected function filterAddedColumns($row) {
270  // make an array with keys as acceptable attribute names
271  $acceptable_attrs = self::$primary_attr_names;
272  array_splice($acceptable_attrs, count($acceptable_attrs), 0, $this->secondary_attr_names);
273  $acceptable_attrs = array_combine($acceptable_attrs, $acceptable_attrs);
274 
275  foreach ($row as $key => $val) {
276  if (!isset($acceptable_attrs[$key])) {
277  $this->additional_select_values[$key] = $val;
278  unset($row[$key]);
279  }
280  }
281  return $row;
282  }
283 }
checkType($row)
Check that the type is correct.
isMissingSecondaries($row)
Get secondary attributes that are missing.
getRequiredAttributes($row)
Get all required attributes for the entity, validating any that are passed in.
$key
Definition: summary.php:34
elgg_set_ignore_access($ignore=true)
Set if Elgg&#39;s access system should be ignored.
Definition: access.php:43
isMissingPrimaries($row)
Get primary attributes missing that are missing.
__construct($class, $required_type, array $initialized_attrs)
Constructor.
getAdditionalSelectValues()
Get values selected from the database that are not attributes.
filterAddedColumns($row)
Filter non-attribute keys into $this->additional_select_values.
$row