Completed
Pull Request — 2.3 (#11038)
by Ismayil
20:26 queued 07:31
created
engine/classes/Elgg/AttributeLoader.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -131,7 +131,7 @@  discard block
 block discarded – undo
131 131
 	 * Get primary attributes missing that are missing
132 132
 	 *
133 133
 	 * @param \stdClass $row Database row
134
-	 * @return array
134
+	 * @return boolean
135 135
 	 */
136 136
 	protected function isMissingPrimaries($row) {
137 137
 		return array_diff(self::$primary_attr_names, array_keys($row)) !== array();
@@ -141,7 +141,7 @@  discard block
 block discarded – undo
141 141
 	 * Get secondary attributes that are missing
142 142
 	 *
143 143
 	 * @param \stdClass $row Database row
144
-	 * @return array
144
+	 * @return boolean
145 145
 	 */
146 146
 	protected function isMissingSecondaries($row) {
147 147
 		return array_diff($this->secondary_attr_names, array_keys($row)) !== array();
Please login to merge, or discard this patch.
Indentation   +269 added lines, -269 removed lines patch added patch discarded remove patch
@@ -11,275 +11,275 @@
 block discarded – undo
11 11
  */
12 12
 class AttributeLoader {
13 13
 
14
-	/**
15
-	 * @var array names of attributes in all entities
16
-	 *
17
-	 * @todo require this to be injected and get it from \ElggEntity
18
-	 */
19
-	protected static $primary_attr_names = array(
20
-		'guid',
21
-		'type',
22
-		'subtype',
23
-		'owner_guid',
24
-		'container_guid',
25
-		'site_guid',
26
-		'access_id',
27
-		'time_created',
28
-		'time_updated',
29
-		'last_action',
30
-		'enabled',
31
-	);
32
-
33
-	/**
34
-	 * @var array names of attributes in all entities that should be stored as integer values
35
-	 */
36
-	protected static $integer_attr_names = array(
37
-		'guid',
38
-		'owner_guid',
39
-		'container_guid',
40
-		'site_guid',
41
-		'access_id',
42
-		'time_created',
43
-		'time_updated',
44
-		'last_action',
45
-		// \ElggUser
46
-		'prev_last_action',
47
-		'last_login',
48
-		'prev_last_login'
49
-	);
50
-
51
-	/**
52
-	 * @var array names of attributes in all entities that should be stored as null if empty
53
-	 */
54
-	protected static $null_attr_names = array(
55
-		'name',
56
-		'title',
57
-		'description',
58
-		'url',
59
-	);
60
-
61
-	/**
62
-	 * @var array names of secondary attributes required for the entity
63
-	 */
64
-	protected $secondary_attr_names = array();
65
-
66
-	/**
67
-	 * @var string entity type (not class) required for fetched primaries
68
-	 */
69
-	protected $required_type;
70
-
71
-	/**
72
-	 * @var array
73
-	 */
74
-	protected $initialized_attributes;
75
-
76
-	/**
77
-	 * @var string class of object being loaded
78
-	 */
79
-	protected $class;
80
-
81
-	/**
82
-	 * @var bool should access control be considered when fetching entity?
83
-	 */
84
-	public $requires_access_control = true;
85
-
86
-	/**
87
-	 * @var callable function used to load attributes from {prefix}entities table
88
-	 */
89
-	public $primary_loader = 'get_entity_as_row';
90
-
91
-	/**
92
-	 * @var callable function used to load attributes from secondary table
93
-	 */
94
-	public $secondary_loader = '';
95
-
96
-	/**
97
-	 * @var callable function used to load all necessary attributes
98
-	 */
99
-	public $full_loader = '';
100
-
101
-	/**
102
-	 * @var array retrieved values that are not attributes
103
-	 */
104
-	protected $additional_select_values = array();
105
-
106
-	/**
107
-	 * Constructor
108
-	 *
109
-	 * @param string $class             class of object being loaded
110
-	 * @param string $required_type     entity type this is being used to populate
111
-	 * @param array  $initialized_attrs attributes after initializeAttributes() has been run
112
-	 * @throws \InvalidArgumentException
113
-	 */
114
-	public function __construct($class, $required_type, array $initialized_attrs) {
115
-		if (!is_string($class)) {
116
-			throw new \InvalidArgumentException('$class must be a class name.');
117
-		}
118
-		$this->class = $class;
119
-
120
-		if (!is_string($required_type)) {
121
-			throw new \InvalidArgumentException('$requiredType must be a system entity type.');
122
-		}
123
-		$this->required_type = $required_type;
124
-
125
-		$this->initialized_attributes = $initialized_attrs;
126
-		$all_attr_names = array_keys($initialized_attrs);
127
-		$this->secondary_attr_names = array_diff($all_attr_names, self::$primary_attr_names);
128
-	}
129
-
130
-	/**
131
-	 * Get primary attributes missing that are missing
132
-	 *
133
-	 * @param \stdClass $row Database row
134
-	 * @return array
135
-	 */
136
-	protected function isMissingPrimaries($row) {
137
-		return array_diff(self::$primary_attr_names, array_keys($row)) !== array();
138
-	}
139
-
140
-	/**
141
-	 * Get secondary attributes that are missing
142
-	 *
143
-	 * @param \stdClass $row Database row
144
-	 * @return array
145
-	 */
146
-	protected function isMissingSecondaries($row) {
147
-		return array_diff($this->secondary_attr_names, array_keys($row)) !== array();
148
-	}
149
-
150
-	/**
151
-	 * Check that the type is correct
152
-	 *
153
-	 * @param \stdClass $row Database row
154
-	 * @return void
155
-	 * @throws \InvalidClassException
156
-	 */
157
-	protected function checkType($row) {
158
-		if ($row['type'] !== $this->required_type) {
159
-			$msg = "GUID:" . $row['guid'] . " is not a valid " . $this->class;
160
-			throw new \InvalidClassException($msg);
161
-		}
162
-	}
163
-
164
-	/**
165
-	 * Get values selected from the database that are not attributes
166
-	 *
167
-	 * @return array
168
-	 */
169
-	public function getAdditionalSelectValues() {
170
-		return $this->additional_select_values;
171
-	}
14
+    /**
15
+     * @var array names of attributes in all entities
16
+     *
17
+     * @todo require this to be injected and get it from \ElggEntity
18
+     */
19
+    protected static $primary_attr_names = array(
20
+        'guid',
21
+        'type',
22
+        'subtype',
23
+        'owner_guid',
24
+        'container_guid',
25
+        'site_guid',
26
+        'access_id',
27
+        'time_created',
28
+        'time_updated',
29
+        'last_action',
30
+        'enabled',
31
+    );
32
+
33
+    /**
34
+     * @var array names of attributes in all entities that should be stored as integer values
35
+     */
36
+    protected static $integer_attr_names = array(
37
+        'guid',
38
+        'owner_guid',
39
+        'container_guid',
40
+        'site_guid',
41
+        'access_id',
42
+        'time_created',
43
+        'time_updated',
44
+        'last_action',
45
+        // \ElggUser
46
+        'prev_last_action',
47
+        'last_login',
48
+        'prev_last_login'
49
+    );
50
+
51
+    /**
52
+     * @var array names of attributes in all entities that should be stored as null if empty
53
+     */
54
+    protected static $null_attr_names = array(
55
+        'name',
56
+        'title',
57
+        'description',
58
+        'url',
59
+    );
60
+
61
+    /**
62
+     * @var array names of secondary attributes required for the entity
63
+     */
64
+    protected $secondary_attr_names = array();
65
+
66
+    /**
67
+     * @var string entity type (not class) required for fetched primaries
68
+     */
69
+    protected $required_type;
70
+
71
+    /**
72
+     * @var array
73
+     */
74
+    protected $initialized_attributes;
75
+
76
+    /**
77
+     * @var string class of object being loaded
78
+     */
79
+    protected $class;
80
+
81
+    /**
82
+     * @var bool should access control be considered when fetching entity?
83
+     */
84
+    public $requires_access_control = true;
85
+
86
+    /**
87
+     * @var callable function used to load attributes from {prefix}entities table
88
+     */
89
+    public $primary_loader = 'get_entity_as_row';
90
+
91
+    /**
92
+     * @var callable function used to load attributes from secondary table
93
+     */
94
+    public $secondary_loader = '';
95
+
96
+    /**
97
+     * @var callable function used to load all necessary attributes
98
+     */
99
+    public $full_loader = '';
100
+
101
+    /**
102
+     * @var array retrieved values that are not attributes
103
+     */
104
+    protected $additional_select_values = array();
105
+
106
+    /**
107
+     * Constructor
108
+     *
109
+     * @param string $class             class of object being loaded
110
+     * @param string $required_type     entity type this is being used to populate
111
+     * @param array  $initialized_attrs attributes after initializeAttributes() has been run
112
+     * @throws \InvalidArgumentException
113
+     */
114
+    public function __construct($class, $required_type, array $initialized_attrs) {
115
+        if (!is_string($class)) {
116
+            throw new \InvalidArgumentException('$class must be a class name.');
117
+        }
118
+        $this->class = $class;
119
+
120
+        if (!is_string($required_type)) {
121
+            throw new \InvalidArgumentException('$requiredType must be a system entity type.');
122
+        }
123
+        $this->required_type = $required_type;
124
+
125
+        $this->initialized_attributes = $initialized_attrs;
126
+        $all_attr_names = array_keys($initialized_attrs);
127
+        $this->secondary_attr_names = array_diff($all_attr_names, self::$primary_attr_names);
128
+    }
129
+
130
+    /**
131
+     * Get primary attributes missing that are missing
132
+     *
133
+     * @param \stdClass $row Database row
134
+     * @return array
135
+     */
136
+    protected function isMissingPrimaries($row) {
137
+        return array_diff(self::$primary_attr_names, array_keys($row)) !== array();
138
+    }
139
+
140
+    /**
141
+     * Get secondary attributes that are missing
142
+     *
143
+     * @param \stdClass $row Database row
144
+     * @return array
145
+     */
146
+    protected function isMissingSecondaries($row) {
147
+        return array_diff($this->secondary_attr_names, array_keys($row)) !== array();
148
+    }
149
+
150
+    /**
151
+     * Check that the type is correct
152
+     *
153
+     * @param \stdClass $row Database row
154
+     * @return void
155
+     * @throws \InvalidClassException
156
+     */
157
+    protected function checkType($row) {
158
+        if ($row['type'] !== $this->required_type) {
159
+            $msg = "GUID:" . $row['guid'] . " is not a valid " . $this->class;
160
+            throw new \InvalidClassException($msg);
161
+        }
162
+    }
163
+
164
+    /**
165
+     * Get values selected from the database that are not attributes
166
+     *
167
+     * @return array
168
+     */
169
+    public function getAdditionalSelectValues() {
170
+        return $this->additional_select_values;
171
+    }
172 172
 	
173
-	/**
174
-	 * Get all required attributes for the entity, validating any that are passed in. Returns empty array
175
-	 * if can't be loaded (Check $failure_reason).
176
-	 *
177
-	 * This function splits loading between "primary" attributes (those in {prefix}entities table) and
178
-	 * "secondary" attributes (e.g. those in {prefix}objects_entity), but can load all at once if a
179
-	 * combined loader is available.
180
-	 *
181
-	 * @param mixed $row a row loaded from DB (array or \stdClass) or a GUID
182
-	 * @return array will be empty if failed to load all attributes (access control or entity doesn't exist)
183
-	 *
184
-	 * @throws \InvalidArgumentException|\LogicException|\IncompleteEntityException
185
-	 */
186
-	public function getRequiredAttributes($row) {
187
-		if (!is_array($row) && !($row instanceof \stdClass)) {
188
-			// assume row is the GUID
189
-			$row = array('guid' => $row);
190
-		}
191
-		$row = (array) $row;
192
-		if (empty($row['guid'])) {
193
-			throw new \InvalidArgumentException('$row must be or contain a GUID');
194
-		}
195
-
196
-		$was_missing_primaries = $this->isMissingPrimaries($row);
197
-		$was_missing_secondaries = $this->isMissingSecondaries($row);
198
-
199
-		// some types have a function to load all attributes at once, it should be faster
200
-		if (($was_missing_primaries || $was_missing_secondaries) && is_callable($this->full_loader)) {
201
-			$fetched = (array) call_user_func($this->full_loader, $row['guid']);
202
-			if (!$fetched) {
203
-				return array();
204
-			}
205
-			$row = array_merge($row, $fetched);
206
-			$this->checkType($row);
207
-		} else {
208
-			if ($was_missing_primaries) {
209
-				if (!is_callable($this->primary_loader)) {
210
-					throw new \LogicException('Primary attribute loader must be callable');
211
-				}
212
-				if ($this->requires_access_control) {
213
-					$fetched = (array) call_user_func($this->primary_loader, $row['guid']);
214
-				} else {
215
-					$ignoring_access = elgg_set_ignore_access();
216
-					$fetched = (array) call_user_func($this->primary_loader, $row['guid']);
217
-					elgg_set_ignore_access($ignoring_access);
218
-				}
219
-				if (!$fetched) {
220
-					return array();
221
-				}
222
-				$row = array_merge($row, $fetched);
223
-			}
224
-
225
-			// We must test type before trying to load the secondaries so that InvalidClassException
226
-			// gets thrown. Otherwise the secondary loader will fail and return false.
227
-			$this->checkType($row);
228
-
229
-			if ($was_missing_secondaries) {
230
-				if (!is_callable($this->secondary_loader)) {
231
-					throw new \LogicException('Secondary attribute loader must be callable');
232
-				}
233
-				$fetched = (array) call_user_func($this->secondary_loader, $row['guid']);
234
-				if (!$fetched) {
235
-					throw new \IncompleteEntityException("Secondary loader failed to return row for {$row['guid']}");
236
-				}
237
-				$row = array_merge($row, $fetched);
238
-			}
239
-		}
240
-
241
-		$row = $this->filterAddedColumns($row);
242
-
243
-		$row['subtype'] = (int)$row['subtype'];
244
-
245
-		// set to null when reading empty value, to match default empty value; See #5456
246
-		foreach (self::$null_attr_names as $key) {
247
-			if (isset($row[$key]) && !$row[$key]) {
248
-				$row[$key] = null;
249
-			}
250
-		}
251
-
252
-		// Note: If there are still missing attributes, we're running on a 1.7 or earlier schema. We let
253
-		// this pass so the upgrades can run.
254
-
255
-		// guid needs to be an int  https://github.com/elgg/elgg/issues/4111
256
-		foreach (self::$integer_attr_names as $key) {
257
-			if (isset($row[$key])) {
258
-				$row[$key] = (int) $row[$key];
259
-			}
260
-		}
261
-		return $row;
262
-	}
263
-
264
-	/**
265
-	 * Filter non-attribute keys into $this->additional_select_values
266
-	 *
267
-	 * @param array $row All columns from the query
268
-	 * @return array Columns acceptable for the entity's attributes
269
-	 */
270
-	protected function filterAddedColumns($row) {
271
-		// make an array with keys as acceptable attribute names
272
-		$acceptable_attrs = self::$primary_attr_names;
273
-		array_splice($acceptable_attrs, count($acceptable_attrs), 0, $this->secondary_attr_names);
274
-		$acceptable_attrs = array_combine($acceptable_attrs, $acceptable_attrs);
275
-
276
-		foreach ($row as $key => $val) {
277
-			if (!isset($acceptable_attrs[$key])) {
278
-				$this->additional_select_values[$key] = $val;
279
-				unset($row[$key]);
280
-			}
281
-		}
282
-		return $row;
283
-	}
173
+    /**
174
+     * Get all required attributes for the entity, validating any that are passed in. Returns empty array
175
+     * if can't be loaded (Check $failure_reason).
176
+     *
177
+     * This function splits loading between "primary" attributes (those in {prefix}entities table) and
178
+     * "secondary" attributes (e.g. those in {prefix}objects_entity), but can load all at once if a
179
+     * combined loader is available.
180
+     *
181
+     * @param mixed $row a row loaded from DB (array or \stdClass) or a GUID
182
+     * @return array will be empty if failed to load all attributes (access control or entity doesn't exist)
183
+     *
184
+     * @throws \InvalidArgumentException|\LogicException|\IncompleteEntityException
185
+     */
186
+    public function getRequiredAttributes($row) {
187
+        if (!is_array($row) && !($row instanceof \stdClass)) {
188
+            // assume row is the GUID
189
+            $row = array('guid' => $row);
190
+        }
191
+        $row = (array) $row;
192
+        if (empty($row['guid'])) {
193
+            throw new \InvalidArgumentException('$row must be or contain a GUID');
194
+        }
195
+
196
+        $was_missing_primaries = $this->isMissingPrimaries($row);
197
+        $was_missing_secondaries = $this->isMissingSecondaries($row);
198
+
199
+        // some types have a function to load all attributes at once, it should be faster
200
+        if (($was_missing_primaries || $was_missing_secondaries) && is_callable($this->full_loader)) {
201
+            $fetched = (array) call_user_func($this->full_loader, $row['guid']);
202
+            if (!$fetched) {
203
+                return array();
204
+            }
205
+            $row = array_merge($row, $fetched);
206
+            $this->checkType($row);
207
+        } else {
208
+            if ($was_missing_primaries) {
209
+                if (!is_callable($this->primary_loader)) {
210
+                    throw new \LogicException('Primary attribute loader must be callable');
211
+                }
212
+                if ($this->requires_access_control) {
213
+                    $fetched = (array) call_user_func($this->primary_loader, $row['guid']);
214
+                } else {
215
+                    $ignoring_access = elgg_set_ignore_access();
216
+                    $fetched = (array) call_user_func($this->primary_loader, $row['guid']);
217
+                    elgg_set_ignore_access($ignoring_access);
218
+                }
219
+                if (!$fetched) {
220
+                    return array();
221
+                }
222
+                $row = array_merge($row, $fetched);
223
+            }
224
+
225
+            // We must test type before trying to load the secondaries so that InvalidClassException
226
+            // gets thrown. Otherwise the secondary loader will fail and return false.
227
+            $this->checkType($row);
228
+
229
+            if ($was_missing_secondaries) {
230
+                if (!is_callable($this->secondary_loader)) {
231
+                    throw new \LogicException('Secondary attribute loader must be callable');
232
+                }
233
+                $fetched = (array) call_user_func($this->secondary_loader, $row['guid']);
234
+                if (!$fetched) {
235
+                    throw new \IncompleteEntityException("Secondary loader failed to return row for {$row['guid']}");
236
+                }
237
+                $row = array_merge($row, $fetched);
238
+            }
239
+        }
240
+
241
+        $row = $this->filterAddedColumns($row);
242
+
243
+        $row['subtype'] = (int)$row['subtype'];
244
+
245
+        // set to null when reading empty value, to match default empty value; See #5456
246
+        foreach (self::$null_attr_names as $key) {
247
+            if (isset($row[$key]) && !$row[$key]) {
248
+                $row[$key] = null;
249
+            }
250
+        }
251
+
252
+        // Note: If there are still missing attributes, we're running on a 1.7 or earlier schema. We let
253
+        // this pass so the upgrades can run.
254
+
255
+        // guid needs to be an int  https://github.com/elgg/elgg/issues/4111
256
+        foreach (self::$integer_attr_names as $key) {
257
+            if (isset($row[$key])) {
258
+                $row[$key] = (int) $row[$key];
259
+            }
260
+        }
261
+        return $row;
262
+    }
263
+
264
+    /**
265
+     * Filter non-attribute keys into $this->additional_select_values
266
+     *
267
+     * @param array $row All columns from the query
268
+     * @return array Columns acceptable for the entity's attributes
269
+     */
270
+    protected function filterAddedColumns($row) {
271
+        // make an array with keys as acceptable attribute names
272
+        $acceptable_attrs = self::$primary_attr_names;
273
+        array_splice($acceptable_attrs, count($acceptable_attrs), 0, $this->secondary_attr_names);
274
+        $acceptable_attrs = array_combine($acceptable_attrs, $acceptable_attrs);
275
+
276
+        foreach ($row as $key => $val) {
277
+            if (!isset($acceptable_attrs[$key])) {
278
+                $this->additional_select_values[$key] = $val;
279
+                unset($row[$key]);
280
+            }
281
+        }
282
+        return $row;
283
+    }
284 284
 }
285 285
 
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
 	 */
157 157
 	protected function checkType($row) {
158 158
 		if ($row['type'] !== $this->required_type) {
159
-			$msg = "GUID:" . $row['guid'] . " is not a valid " . $this->class;
159
+			$msg = "GUID:".$row['guid']." is not a valid ".$this->class;
160 160
 			throw new \InvalidClassException($msg);
161 161
 		}
162 162
 	}
@@ -240,7 +240,7 @@  discard block
 block discarded – undo
240 240
 
241 241
 		$row = $this->filterAddedColumns($row);
242 242
 
243
-		$row['subtype'] = (int)$row['subtype'];
243
+		$row['subtype'] = (int) $row['subtype'];
244 244
 
245 245
 		// set to null when reading empty value, to match default empty value; See #5456
246 246
 		foreach (self::$null_attr_names as $key) {
Please login to merge, or discard this patch.
engine/classes/Elgg/Database/Annotations.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -33,7 +33,7 @@
 block discarded – undo
33 33
 	 *
34 34
 	 * @param int $id The id of the annotation object being retrieved.
35 35
 	 *
36
-	 * @return \ElggAnnotation|false
36
+	 * @return \ElggExtender
37 37
 	 */
38 38
 	function get($id) {
39 39
 		return _elgg_get_metastring_based_object_from_id($id, 'annotation');
Please login to merge, or discard this patch.
Indentation   +424 added lines, -424 removed lines patch added patch discarded remove patch
@@ -12,481 +12,481 @@
 block discarded – undo
12 12
  */
13 13
 class Annotations {
14 14
 
15
-	use \Elgg\TimeUsing;
15
+    use \Elgg\TimeUsing;
16 16
 	
17
-	/**
18
-	 * @var \Elgg\Database
19
-	 */
20
-	protected $db;
17
+    /**
18
+     * @var \Elgg\Database
19
+     */
20
+    protected $db;
21 21
 
22
-	/**
23
-	 * @var \ElggSession
24
-	 */
25
-	protected $session;
22
+    /**
23
+     * @var \ElggSession
24
+     */
25
+    protected $session;
26 26
 
27
-	/**
28
-	 * @var \Elgg\EventsService
29
-	 */
30
-	protected $events;
27
+    /**
28
+     * @var \Elgg\EventsService
29
+     */
30
+    protected $events;
31 31
 
32
-	/**
33
-	 * Constructor
34
-	 *
35
-	 * @param \Elgg\Database      $db      Database
36
-	 * @param \ElggSession        $session Session
37
-	 * @param \Elgg\EventsService $events  Events
38
-	 */
39
-	public function __construct(\Elgg\Database $db, \ElggSession $session, \Elgg\EventsService $events) {
40
-		$this->db = $db;
41
-		$this->session = $session;
42
-		$this->events = $events;
43
-	}
32
+    /**
33
+     * Constructor
34
+     *
35
+     * @param \Elgg\Database      $db      Database
36
+     * @param \ElggSession        $session Session
37
+     * @param \Elgg\EventsService $events  Events
38
+     */
39
+    public function __construct(\Elgg\Database $db, \ElggSession $session, \Elgg\EventsService $events) {
40
+        $this->db = $db;
41
+        $this->session = $session;
42
+        $this->events = $events;
43
+    }
44 44
 
45
-	/**
46
-	 * Get a specific annotation by its id.
47
-	 * If you want multiple annotation objects, use
48
-	 * {@link elgg_get_annotations()}.
49
-	 *
50
-	 * @param int $id The id of the annotation object being retrieved.
51
-	 *
52
-	 * @return \ElggAnnotation|false
53
-	 */
54
-	function get($id) {
55
-		return _elgg_get_metastring_based_object_from_id($id, 'annotation');
56
-	}
57
-	
58
-	/**
59
-	 * Deletes an annotation using its ID.
60
-	 *
61
-	 * @param int $id The annotation ID to delete.
62
-	 * @return bool
63
-	 */
64
-	function delete($id) {
65
-		$annotation = $this->get($id);
66
-		if (!$annotation) {
67
-			return false;
68
-		}
69
-		return $annotation->delete();
70
-	}
71
-	
72
-	/**
73
-	 * Create a new annotation.
74
-	 *
75
-	 * @param int    $entity_guid GUID of entity to be annotated
76
-	 * @param string $name        Name of annotation
77
-	 * @param string $value       Value of annotation
78
-	 * @param string $value_type  Type of value (default is auto detection)
79
-	 * @param int    $owner_guid  Owner of annotation (default is logged in user)
80
-	 * @param int    $access_id   Access level of annotation
81
-	 *
82
-	 * @return int|bool id on success or false on failure
83
-	 */
84
-	function create($entity_guid, $name, $value, $value_type = '', $owner_guid = 0, $access_id = ACCESS_PRIVATE) {
45
+    /**
46
+     * Get a specific annotation by its id.
47
+     * If you want multiple annotation objects, use
48
+     * {@link elgg_get_annotations()}.
49
+     *
50
+     * @param int $id The id of the annotation object being retrieved.
51
+     *
52
+     * @return \ElggAnnotation|false
53
+     */
54
+    function get($id) {
55
+        return _elgg_get_metastring_based_object_from_id($id, 'annotation');
56
+    }
57
+	
58
+    /**
59
+     * Deletes an annotation using its ID.
60
+     *
61
+     * @param int $id The annotation ID to delete.
62
+     * @return bool
63
+     */
64
+    function delete($id) {
65
+        $annotation = $this->get($id);
66
+        if (!$annotation) {
67
+            return false;
68
+        }
69
+        return $annotation->delete();
70
+    }
71
+	
72
+    /**
73
+     * Create a new annotation.
74
+     *
75
+     * @param int    $entity_guid GUID of entity to be annotated
76
+     * @param string $name        Name of annotation
77
+     * @param string $value       Value of annotation
78
+     * @param string $value_type  Type of value (default is auto detection)
79
+     * @param int    $owner_guid  Owner of annotation (default is logged in user)
80
+     * @param int    $access_id   Access level of annotation
81
+     *
82
+     * @return int|bool id on success or false on failure
83
+     */
84
+    function create($entity_guid, $name, $value, $value_type = '', $owner_guid = 0, $access_id = ACCESS_PRIVATE) {
85 85
 		
86 86
 	
87
-		$result = false;
87
+        $result = false;
88 88
 	
89
-		$entity_guid = (int)$entity_guid;
90
-		$value_type = \ElggExtender::detectValueType($value, $value_type);
89
+        $entity_guid = (int)$entity_guid;
90
+        $value_type = \ElggExtender::detectValueType($value, $value_type);
91 91
 	
92
-		$owner_guid = (int)$owner_guid;
93
-		if ($owner_guid == 0) {
94
-			$owner_guid = $this->session->getLoggedInUserGuid();
95
-		}
92
+        $owner_guid = (int)$owner_guid;
93
+        if ($owner_guid == 0) {
94
+            $owner_guid = $this->session->getLoggedInUserGuid();
95
+        }
96 96
 	
97
-		$access_id = (int)$access_id;
98
-		$time = $this->getCurrentTime()->getTimestamp();
97
+        $access_id = (int)$access_id;
98
+        $time = $this->getCurrentTime()->getTimestamp();
99 99
 	
100
-		$value_id = elgg_get_metastring_id($value);
101
-		if (!$value_id) {
102
-			return false;
103
-		}
100
+        $value_id = elgg_get_metastring_id($value);
101
+        if (!$value_id) {
102
+            return false;
103
+        }
104 104
 	
105
-		$name_id = elgg_get_metastring_id($name);
106
-		if (!$name_id) {
107
-			return false;
108
-		}
105
+        $name_id = elgg_get_metastring_id($name);
106
+        if (!$name_id) {
107
+            return false;
108
+        }
109 109
 	
110
-		// @todo we don't check that the entity is loaded which means the user may
111
-		// not have access to the entity
112
-		$entity = get_entity($entity_guid);
110
+        // @todo we don't check that the entity is loaded which means the user may
111
+        // not have access to the entity
112
+        $entity = get_entity($entity_guid);
113 113
 	
114
-		if ($this->events->trigger('annotate', $entity->type, $entity)) {
115
-			$result = $this->db->insertData("INSERT INTO {$this->db->prefix}annotations
114
+        if ($this->events->trigger('annotate', $entity->type, $entity)) {
115
+            $result = $this->db->insertData("INSERT INTO {$this->db->prefix}annotations
116 116
 				(entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id) VALUES
117 117
 				($entity_guid, $name_id, $value_id, '$value_type', $owner_guid, $time, $access_id)");
118 118
 	
119
-			if ($result !== false) {
120
-				$obj = elgg_get_annotation_from_id($result);
121
-				if ($this->events->trigger('create', 'annotation', $obj)) {
122
-					return $result;
123
-				} else {
124
-					// plugin returned false to reject annotation
125
-					elgg_delete_annotation_by_id($result);
126
-					return false;
127
-				}
128
-			}
129
-		}
130
-	
131
-		return $result;
132
-	}
133
-	
134
-	/**
135
-	 * Update an annotation.
136
-	 *
137
-	 * @param int    $annotation_id Annotation ID
138
-	 * @param string $name          Name of annotation
139
-	 * @param string $value         Value of annotation
140
-	 * @param string $value_type    Type of value
141
-	 * @param int    $owner_guid    Owner of annotation
142
-	 * @param int    $access_id     Access level of annotation
143
-	 *
144
-	 * @return bool
145
-	 */
146
-	function update($annotation_id, $name, $value, $value_type, $owner_guid, $access_id) {
119
+            if ($result !== false) {
120
+                $obj = elgg_get_annotation_from_id($result);
121
+                if ($this->events->trigger('create', 'annotation', $obj)) {
122
+                    return $result;
123
+                } else {
124
+                    // plugin returned false to reject annotation
125
+                    elgg_delete_annotation_by_id($result);
126
+                    return false;
127
+                }
128
+            }
129
+        }
130
+	
131
+        return $result;
132
+    }
133
+	
134
+    /**
135
+     * Update an annotation.
136
+     *
137
+     * @param int    $annotation_id Annotation ID
138
+     * @param string $name          Name of annotation
139
+     * @param string $value         Value of annotation
140
+     * @param string $value_type    Type of value
141
+     * @param int    $owner_guid    Owner of annotation
142
+     * @param int    $access_id     Access level of annotation
143
+     *
144
+     * @return bool
145
+     */
146
+    function update($annotation_id, $name, $value, $value_type, $owner_guid, $access_id) {
147 147
 		
148 148
 	
149
-		$annotation_id = (int)$annotation_id;
149
+        $annotation_id = (int)$annotation_id;
150 150
 	
151
-		$annotation = $this->get($annotation_id);
152
-		if (!$annotation) {
153
-			return false;
154
-		}
155
-		if (!$annotation->canEdit()) {
156
-			return false;
157
-		}
151
+        $annotation = $this->get($annotation_id);
152
+        if (!$annotation) {
153
+            return false;
154
+        }
155
+        if (!$annotation->canEdit()) {
156
+            return false;
157
+        }
158 158
 	
159
-		$name = trim($name);
160
-		$value_type = \ElggExtender::detectValueType($value, $value_type);
159
+        $name = trim($name);
160
+        $value_type = \ElggExtender::detectValueType($value, $value_type);
161 161
 	
162
-		$owner_guid = (int)$owner_guid;
163
-		if ($owner_guid == 0) {
164
-			$owner_guid = $this->session->getLoggedInUserGuid();
165
-		}
162
+        $owner_guid = (int)$owner_guid;
163
+        if ($owner_guid == 0) {
164
+            $owner_guid = $this->session->getLoggedInUserGuid();
165
+        }
166 166
 	
167
-		$access_id = (int)$access_id;
167
+        $access_id = (int)$access_id;
168 168
 	
169
-		$value_id = elgg_get_metastring_id($value);
170
-		if (!$value_id) {
171
-			return false;
172
-		}
169
+        $value_id = elgg_get_metastring_id($value);
170
+        if (!$value_id) {
171
+            return false;
172
+        }
173 173
 	
174
-		$name_id = elgg_get_metastring_id($name);
175
-		if (!$name_id) {
176
-			return false;
177
-		}
174
+        $name_id = elgg_get_metastring_id($name);
175
+        if (!$name_id) {
176
+            return false;
177
+        }
178 178
 	
179
-		$result = $this->db->updateData("UPDATE {$this->db->prefix}annotations
179
+        $result = $this->db->updateData("UPDATE {$this->db->prefix}annotations
180 180
 			SET name_id = $name_id, value_id = $value_id, value_type = '$value_type',
181 181
 			access_id = $access_id, owner_guid = $owner_guid
182 182
 			WHERE id = $annotation_id");
183 183
 	
184
-		if ($result !== false) {
185
-			// @todo add plugin hook that sends old and new annotation information before db access
186
-			$obj = $this->get($annotation_id);
187
-			$this->events->trigger('update', 'annotation', $obj);
188
-		}
189
-	
190
-		return $result;
191
-	}
192
-	
193
-	/**
194
-	 * Returns annotations.  Accepts all elgg_get_entities() options for entity
195
-	 * restraints.
196
-	 *
197
-	 * @see elgg_get_entities
198
-	 *
199
-	 * @param array $options Array in format:
200
-	 *
201
-	 * annotation_names              => null|ARR Annotation names
202
-	 * annotation_values             => null|ARR Annotation values
203
-	 * annotation_ids                => null|ARR annotation ids
204
-	 * annotation_case_sensitive     => BOOL Overall Case sensitive
205
-	 * annotation_owner_guids        => null|ARR guids for annotation owners
206
-	 * annotation_created_time_lower => INT Lower limit for created time.
207
-	 * annotation_created_time_upper => INT Upper limit for created time.
208
-	 * annotation_calculation        => STR Perform the MySQL function on the annotation values returned.
209
-	 *                                   Do not confuse this "annotation_calculation" option with the
210
-	 *                                   "calculation" option to elgg_get_entities_from_annotation_calculation().
211
-	 *                                   The "annotation_calculation" option causes this function to
212
-	 *                                   return the result of performing a mathematical calculation on
213
-	 *                                   all annotations that match the query instead of \ElggAnnotation
214
-	 *                                   objects.
215
-	 *                                   See the docs for elgg_get_entities_from_annotation_calculation()
216
-	 *                                   for the proper use of the "calculation" option.
217
-	 *
218
-	 *
219
-	 * @return \ElggAnnotation[]|mixed
220
-	 */
221
-	function find(array $options = array()) {
184
+        if ($result !== false) {
185
+            // @todo add plugin hook that sends old and new annotation information before db access
186
+            $obj = $this->get($annotation_id);
187
+            $this->events->trigger('update', 'annotation', $obj);
188
+        }
189
+	
190
+        return $result;
191
+    }
192
+	
193
+    /**
194
+     * Returns annotations.  Accepts all elgg_get_entities() options for entity
195
+     * restraints.
196
+     *
197
+     * @see elgg_get_entities
198
+     *
199
+     * @param array $options Array in format:
200
+     *
201
+     * annotation_names              => null|ARR Annotation names
202
+     * annotation_values             => null|ARR Annotation values
203
+     * annotation_ids                => null|ARR annotation ids
204
+     * annotation_case_sensitive     => BOOL Overall Case sensitive
205
+     * annotation_owner_guids        => null|ARR guids for annotation owners
206
+     * annotation_created_time_lower => INT Lower limit for created time.
207
+     * annotation_created_time_upper => INT Upper limit for created time.
208
+     * annotation_calculation        => STR Perform the MySQL function on the annotation values returned.
209
+     *                                   Do not confuse this "annotation_calculation" option with the
210
+     *                                   "calculation" option to elgg_get_entities_from_annotation_calculation().
211
+     *                                   The "annotation_calculation" option causes this function to
212
+     *                                   return the result of performing a mathematical calculation on
213
+     *                                   all annotations that match the query instead of \ElggAnnotation
214
+     *                                   objects.
215
+     *                                   See the docs for elgg_get_entities_from_annotation_calculation()
216
+     *                                   for the proper use of the "calculation" option.
217
+     *
218
+     *
219
+     * @return \ElggAnnotation[]|mixed
220
+     */
221
+    function find(array $options = array()) {
222 222
 
223
-		// support shortcut of 'count' => true for 'annotation_calculation' => 'count'
224
-		if (isset($options['count']) && $options['count']) {
225
-			$options['annotation_calculation'] = 'count';
226
-			unset($options['count']);
227
-		}
223
+        // support shortcut of 'count' => true for 'annotation_calculation' => 'count'
224
+        if (isset($options['count']) && $options['count']) {
225
+            $options['annotation_calculation'] = 'count';
226
+            unset($options['count']);
227
+        }
228 228
 		
229
-		$options['metastring_type'] = 'annotations';
230
-		return _elgg_get_metastring_based_objects($options);
231
-	}
232
-	
233
-	/**
234
-	 * Deletes annotations based on $options.
235
-	 *
236
-	 * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
237
-	 *          This requires at least one constraint: annotation_owner_guid(s),
238
-	 *          annotation_name(s), annotation_value(s), or guid(s) must be set.
239
-	 *
240
-	 * @param array $options An options array. {@link elgg_get_annotations()}
241
-	 * @return bool|null true on success, false on failure, null if no annotations to delete.
242
-	 */
243
-	function deleteAll(array $options) {
244
-		if (!_elgg_is_valid_options_for_batch_operation($options, 'annotation')) {
245
-			return false;
246
-		}
247
-	
248
-		$options['metastring_type'] = 'annotations';
249
-		return _elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
250
-	}
251
-	
252
-	/**
253
-	 * Disables annotations based on $options.
254
-	 *
255
-	 * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
256
-	 *
257
-	 * @param array $options An options array. {@link elgg_get_annotations()}
258
-	 * @return bool|null true on success, false on failure, null if no annotations disabled.
259
-	 */
260
-	function disableAll(array $options) {
261
-		if (!_elgg_is_valid_options_for_batch_operation($options, 'annotation')) {
262
-			return false;
263
-		}
229
+        $options['metastring_type'] = 'annotations';
230
+        return _elgg_get_metastring_based_objects($options);
231
+    }
232
+	
233
+    /**
234
+     * Deletes annotations based on $options.
235
+     *
236
+     * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
237
+     *          This requires at least one constraint: annotation_owner_guid(s),
238
+     *          annotation_name(s), annotation_value(s), or guid(s) must be set.
239
+     *
240
+     * @param array $options An options array. {@link elgg_get_annotations()}
241
+     * @return bool|null true on success, false on failure, null if no annotations to delete.
242
+     */
243
+    function deleteAll(array $options) {
244
+        if (!_elgg_is_valid_options_for_batch_operation($options, 'annotation')) {
245
+            return false;
246
+        }
247
+	
248
+        $options['metastring_type'] = 'annotations';
249
+        return _elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
250
+    }
251
+	
252
+    /**
253
+     * Disables annotations based on $options.
254
+     *
255
+     * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
256
+     *
257
+     * @param array $options An options array. {@link elgg_get_annotations()}
258
+     * @return bool|null true on success, false on failure, null if no annotations disabled.
259
+     */
260
+    function disableAll(array $options) {
261
+        if (!_elgg_is_valid_options_for_batch_operation($options, 'annotation')) {
262
+            return false;
263
+        }
264 264
 		
265
-		// if we can see hidden (disabled) we need to use the offset
266
-		// otherwise we risk an infinite loop if there are more than 50
267
-		$inc_offset = access_get_show_hidden_status();
268
-	
269
-		$options['metastring_type'] = 'annotations';
270
-		return _elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
271
-	}
272
-	
273
-	/**
274
-	 * Enables annotations based on $options.
275
-	 *
276
-	 * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
277
-	 *
278
-	 * @warning In order to enable annotations, you must first use
279
-	 * {@link access_show_hidden_entities()}.
280
-	 *
281
-	 * @param array $options An options array. {@link elgg_get_annotations()}
282
-	 * @return bool|null true on success, false on failure, null if no metadata enabled.
283
-	 */
284
-	function enableAll(array $options) {
285
-		if (!$options || !is_array($options)) {
286
-			return false;
287
-		}
288
-	
289
-		$options['metastring_type'] = 'annotations';
290
-		return _elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
291
-	}
292
-	
293
-	/**
294
-	 * Returns entities based upon annotations.  Also accepts all options available
295
-	 * to elgg_get_entities() and elgg_get_entities_from_metadata().
296
-	 *
297
-	 * @see elgg_get_entities
298
-	 * @see elgg_get_entities_from_metadata
299
-	 *
300
-	 * @param array $options Array in format:
301
-	 *
302
-	 * 	annotation_names => null|ARR annotations names
303
-	 *
304
-	 * 	annotation_values => null|ARR annotations values
305
-	 *
306
-	 * 	annotation_name_value_pairs => null|ARR (name = 'name', value => 'value',
307
-	 * 	'operator' => '=', 'case_sensitive' => true) entries.
308
-	 * 	Currently if multiple values are sent via an array (value => array('value1', 'value2')
309
-	 * 	the pair's operator will be forced to "IN".
310
-	 *
311
-	 * 	annotation_name_value_pairs_operator => null|STR The operator to use for combining
312
-	 *  (name = value) OPERATOR (name = value); default AND
313
-	 *
314
-	 * 	annotation_case_sensitive => BOOL Overall Case sensitive
315
-	 *
316
-	 *  order_by_annotation => null|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC,
317
-	 *  'as' => text|integer),
318
-	 *
319
-	 *  Also supports array('name' => 'annotation_text1')
320
-	 *
321
-	 *  annotation_owner_guids => null|ARR guids for annotaiton owners
322
-	 *
323
-	 * @return mixed If count, int. If not count, array. false on errors.
324
-	 */
325
-	function getEntities(array $options = array()) {
326
-		$defaults = array(
327
-			'annotation_names'						=> ELGG_ENTITIES_ANY_VALUE,
328
-			'annotation_values'						=> ELGG_ENTITIES_ANY_VALUE,
329
-			'annotation_name_value_pairs'			=> ELGG_ENTITIES_ANY_VALUE,
330
-	
331
-			'annotation_name_value_pairs_operator'	=> 'AND',
332
-			'annotation_case_sensitive' 			=> true,
333
-			'order_by_annotation'					=> array(),
334
-	
335
-			'annotation_created_time_lower'			=> ELGG_ENTITIES_ANY_VALUE,
336
-			'annotation_created_time_upper'			=> ELGG_ENTITIES_ANY_VALUE,
337
-	
338
-			'annotation_owner_guids'				=> ELGG_ENTITIES_ANY_VALUE,
339
-		);
340
-	
341
-		$options = array_merge($defaults, $options);
342
-	
343
-		$singulars = array('annotation_name', 'annotation_value',
344
-		'annotation_name_value_pair', 'annotation_owner_guid');
345
-	
346
-		$options = _elgg_normalize_plural_options_array($options, $singulars);
347
-		$options = _elgg_entities_get_metastrings_options('annotation', $options);
348
-	
349
-		if (!$options) {
350
-			return false;
351
-		}
352
-	
353
-		// because of performance issues support for ordering by maxtime has been dropped
354
-		// @see https://github.com/Elgg/Elgg/issues/6638
355
-		if (isset($options['order_by']) && preg_match('~\bmaxtime\b~i', $options['order_by'])) {
356
-			// check if the user provided maxtime
357
-			$deprecated = true;
358
-			if (isset($options['selects'])) {
359
-				$selects = $options['selects'];
360
-				if (!is_array($selects)) {
361
-					$selects = array($selects);
362
-				}
265
+        // if we can see hidden (disabled) we need to use the offset
266
+        // otherwise we risk an infinite loop if there are more than 50
267
+        $inc_offset = access_get_show_hidden_status();
268
+	
269
+        $options['metastring_type'] = 'annotations';
270
+        return _elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
271
+    }
272
+	
273
+    /**
274
+     * Enables annotations based on $options.
275
+     *
276
+     * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
277
+     *
278
+     * @warning In order to enable annotations, you must first use
279
+     * {@link access_show_hidden_entities()}.
280
+     *
281
+     * @param array $options An options array. {@link elgg_get_annotations()}
282
+     * @return bool|null true on success, false on failure, null if no metadata enabled.
283
+     */
284
+    function enableAll(array $options) {
285
+        if (!$options || !is_array($options)) {
286
+            return false;
287
+        }
288
+	
289
+        $options['metastring_type'] = 'annotations';
290
+        return _elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
291
+    }
292
+	
293
+    /**
294
+     * Returns entities based upon annotations.  Also accepts all options available
295
+     * to elgg_get_entities() and elgg_get_entities_from_metadata().
296
+     *
297
+     * @see elgg_get_entities
298
+     * @see elgg_get_entities_from_metadata
299
+     *
300
+     * @param array $options Array in format:
301
+     *
302
+     * 	annotation_names => null|ARR annotations names
303
+     *
304
+     * 	annotation_values => null|ARR annotations values
305
+     *
306
+     * 	annotation_name_value_pairs => null|ARR (name = 'name', value => 'value',
307
+     * 	'operator' => '=', 'case_sensitive' => true) entries.
308
+     * 	Currently if multiple values are sent via an array (value => array('value1', 'value2')
309
+     * 	the pair's operator will be forced to "IN".
310
+     *
311
+     * 	annotation_name_value_pairs_operator => null|STR The operator to use for combining
312
+     *  (name = value) OPERATOR (name = value); default AND
313
+     *
314
+     * 	annotation_case_sensitive => BOOL Overall Case sensitive
315
+     *
316
+     *  order_by_annotation => null|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC,
317
+     *  'as' => text|integer),
318
+     *
319
+     *  Also supports array('name' => 'annotation_text1')
320
+     *
321
+     *  annotation_owner_guids => null|ARR guids for annotaiton owners
322
+     *
323
+     * @return mixed If count, int. If not count, array. false on errors.
324
+     */
325
+    function getEntities(array $options = array()) {
326
+        $defaults = array(
327
+            'annotation_names'						=> ELGG_ENTITIES_ANY_VALUE,
328
+            'annotation_values'						=> ELGG_ENTITIES_ANY_VALUE,
329
+            'annotation_name_value_pairs'			=> ELGG_ENTITIES_ANY_VALUE,
330
+	
331
+            'annotation_name_value_pairs_operator'	=> 'AND',
332
+            'annotation_case_sensitive' 			=> true,
333
+            'order_by_annotation'					=> array(),
334
+	
335
+            'annotation_created_time_lower'			=> ELGG_ENTITIES_ANY_VALUE,
336
+            'annotation_created_time_upper'			=> ELGG_ENTITIES_ANY_VALUE,
337
+	
338
+            'annotation_owner_guids'				=> ELGG_ENTITIES_ANY_VALUE,
339
+        );
340
+	
341
+        $options = array_merge($defaults, $options);
342
+	
343
+        $singulars = array('annotation_name', 'annotation_value',
344
+        'annotation_name_value_pair', 'annotation_owner_guid');
345
+	
346
+        $options = _elgg_normalize_plural_options_array($options, $singulars);
347
+        $options = _elgg_entities_get_metastrings_options('annotation', $options);
348
+	
349
+        if (!$options) {
350
+            return false;
351
+        }
352
+	
353
+        // because of performance issues support for ordering by maxtime has been dropped
354
+        // @see https://github.com/Elgg/Elgg/issues/6638
355
+        if (isset($options['order_by']) && preg_match('~\bmaxtime\b~i', $options['order_by'])) {
356
+            // check if the user provided maxtime
357
+            $deprecated = true;
358
+            if (isset($options['selects'])) {
359
+                $selects = $options['selects'];
360
+                if (!is_array($selects)) {
361
+                    $selects = array($selects);
362
+                }
363 363
 					
364
-				foreach ($selects as $select) {
365
-					if (preg_match('~\bmaxtime\b~i', $options['order_by'])) {
366
-						$deprecated = false;
367
-						break;
368
-					}
369
-				}
370
-			}
364
+                foreach ($selects as $select) {
365
+                    if (preg_match('~\bmaxtime\b~i', $options['order_by'])) {
366
+                        $deprecated = false;
367
+                        break;
368
+                    }
369
+                }
370
+            }
371 371
 		
372
-			// the user didn't provide maxtime
373
-			if ($deprecated) {
374
-				// special sorting for annotations
375
-				elgg_deprecated_notice(__FUNCTION__ . ": no longer orders by annotations by default. If you order"
376
-					. " by maxtime, you must provide that column via \$options['selects']. See"
377
-					. " https://github.com/Elgg/Elgg/issues/6638#issuecomment-41562034", "1.10");
372
+            // the user didn't provide maxtime
373
+            if ($deprecated) {
374
+                // special sorting for annotations
375
+                elgg_deprecated_notice(__FUNCTION__ . ": no longer orders by annotations by default. If you order"
376
+                    . " by maxtime, you must provide that column via \$options['selects']. See"
377
+                    . " https://github.com/Elgg/Elgg/issues/6638#issuecomment-41562034", "1.10");
378 378
 					
379
-				$options['selects'][] = "MAX(n_table.time_created) AS maxtime";
380
-				$options['group_by'] = 'n_table.entity_guid';
381
-			}
382
-		}
379
+                $options['selects'][] = "MAX(n_table.time_created) AS maxtime";
380
+                $options['group_by'] = 'n_table.entity_guid';
381
+            }
382
+        }
383 383
 		
384
-		$time_wheres = _elgg_get_entity_time_where_sql('n_table', $options['annotation_created_time_upper'],
385
-			$options['annotation_created_time_lower']);
384
+        $time_wheres = _elgg_get_entity_time_where_sql('n_table', $options['annotation_created_time_upper'],
385
+            $options['annotation_created_time_lower']);
386 386
 
387
-		if ($time_wheres) {
388
-			$options['wheres'][] = $time_wheres;
389
-		}
390
-	
391
-		return elgg_get_entities_from_metadata($options);
392
-	}
393
-	
394
-	/**
395
-	 * Get entities ordered by a mathematical calculation on annotation values
396
-	 *
397
-	 * @tip Note that this function uses { @link elgg_get_annotations() } to return a list of entities ordered by a mathematical
398
-	 * calculation on annotation values, and { @link elgg_get_entities_from_annotations() } to return a count of entities
399
-	 * if $options['count'] is set to a truthy value
400
-	 *
401
-	 * @param array $options An options array:
402
-	 * 	'calculation'            => The calculation to use. Must be a valid MySQL function.
403
-	 *                              Defaults to sum.  Result selected as 'annotation_calculation'.
404
-	 *                              Don't confuse this "calculation" option with the
405
-	 *                              "annotation_calculation" option to elgg_get_annotations().
406
-	 *                              This "calculation" option is applied to each entity's set of
407
-	 *                              annotations and is selected as annotation_calculation for that row.
408
-	 *                              See the docs for elgg_get_annotations() for proper use of the
409
-	 *                              "annotation_calculation" option.
410
-	 *	'order_by'               => The order for the sorting. Defaults to 'annotation_calculation desc'.
411
-	 *	'annotation_names'       => The names of annotations on the entity.
412
-	 *	'annotation_values'	     => The values of annotations on the entity.
413
-	 *
414
-	 * 	'metadata_names'         => The name of metadata on the entity.
415
-	 * 	'metadata_values'        => The value of metadata on the entitiy.
416
-	 * 	'callback'               => Callback function to pass each row through.
417
-	 *                              @tip This function is different from other ege* functions, 
418
-	 *                              as it uses a metastring-based getter function { @link elgg_get_annotations() },
419
-	 *                              therefore the callback function should be a derivative of { @link entity_row_to_elggstar() }
420
-	 *                              and not of { @link row_to_annotation() }
421
-	 *
422
-	 * @return \ElggEntity[]|int An array or a count of entities
423
-	 * @see elgg_get_annotations()
424
-	 * @see elgg_get_entities_from_annotations()
425
-	 */
426
-	function getEntitiesFromCalculation($options) {
387
+        if ($time_wheres) {
388
+            $options['wheres'][] = $time_wheres;
389
+        }
390
+	
391
+        return elgg_get_entities_from_metadata($options);
392
+    }
393
+	
394
+    /**
395
+     * Get entities ordered by a mathematical calculation on annotation values
396
+     *
397
+     * @tip Note that this function uses { @link elgg_get_annotations() } to return a list of entities ordered by a mathematical
398
+     * calculation on annotation values, and { @link elgg_get_entities_from_annotations() } to return a count of entities
399
+     * if $options['count'] is set to a truthy value
400
+     *
401
+     * @param array $options An options array:
402
+     * 	'calculation'            => The calculation to use. Must be a valid MySQL function.
403
+     *                              Defaults to sum.  Result selected as 'annotation_calculation'.
404
+     *                              Don't confuse this "calculation" option with the
405
+     *                              "annotation_calculation" option to elgg_get_annotations().
406
+     *                              This "calculation" option is applied to each entity's set of
407
+     *                              annotations and is selected as annotation_calculation for that row.
408
+     *                              See the docs for elgg_get_annotations() for proper use of the
409
+     *                              "annotation_calculation" option.
410
+     *	'order_by'               => The order for the sorting. Defaults to 'annotation_calculation desc'.
411
+     *	'annotation_names'       => The names of annotations on the entity.
412
+     *	'annotation_values'	     => The values of annotations on the entity.
413
+     *
414
+     * 	'metadata_names'         => The name of metadata on the entity.
415
+     * 	'metadata_values'        => The value of metadata on the entitiy.
416
+     * 	'callback'               => Callback function to pass each row through.
417
+     *                              @tip This function is different from other ege* functions, 
418
+     *                              as it uses a metastring-based getter function { @link elgg_get_annotations() },
419
+     *                              therefore the callback function should be a derivative of { @link entity_row_to_elggstar() }
420
+     *                              and not of { @link row_to_annotation() }
421
+     *
422
+     * @return \ElggEntity[]|int An array or a count of entities
423
+     * @see elgg_get_annotations()
424
+     * @see elgg_get_entities_from_annotations()
425
+     */
426
+    function getEntitiesFromCalculation($options) {
427 427
 		
428
-		if (isset($options['count']) && $options['count']) {
429
-			return elgg_get_entities_from_annotations($options);
430
-		}
428
+        if (isset($options['count']) && $options['count']) {
429
+            return elgg_get_entities_from_annotations($options);
430
+        }
431 431
 		
432
-		$db_prefix = $this->db->prefix;
433
-		$defaults = array(
434
-			'calculation' => 'sum',
435
-			'order_by' => 'annotation_calculation desc'
436
-		);
432
+        $db_prefix = $this->db->prefix;
433
+        $defaults = array(
434
+            'calculation' => 'sum',
435
+            'order_by' => 'annotation_calculation desc'
436
+        );
437 437
 	
438
-		$options = array_merge($defaults, $options);
438
+        $options = array_merge($defaults, $options);
439 439
 	
440
-		$function = sanitize_string(elgg_extract('calculation', $options, 'sum', false));
440
+        $function = sanitize_string(elgg_extract('calculation', $options, 'sum', false));
441 441
 	
442
-		// you must cast this as an int or it sorts wrong.
443
-		$options['selects'][] = 'e.*';
444
-		$options['selects'][] = "$function(CAST(a_msv.string AS signed)) AS annotation_calculation";
442
+        // you must cast this as an int or it sorts wrong.
443
+        $options['selects'][] = 'e.*';
444
+        $options['selects'][] = "$function(CAST(a_msv.string AS signed)) AS annotation_calculation";
445 445
 	
446
-		// need our own join to get the values because the lower level functions don't
447
-		// add all the joins if it's a different callback.
448
-		$options['joins'][] = "JOIN {$db_prefix}metastrings a_msv ON n_table.value_id = a_msv.id";
446
+        // need our own join to get the values because the lower level functions don't
447
+        // add all the joins if it's a different callback.
448
+        $options['joins'][] = "JOIN {$db_prefix}metastrings a_msv ON n_table.value_id = a_msv.id";
449 449
 	
450
-		// don't need access control because it's taken care of by elgg_get_annotations.
451
-		$options['group_by'] = 'n_table.entity_guid';
450
+        // don't need access control because it's taken care of by elgg_get_annotations.
451
+        $options['group_by'] = 'n_table.entity_guid';
452 452
 
453
-		// do not default to a callback function used in elgg_get_annotation()
454
-		if (!isset($options['callback'])) {
455
-			$options['callback'] = 'entity_row_to_elggstar';
456
-		}
453
+        // do not default to a callback function used in elgg_get_annotation()
454
+        if (!isset($options['callback'])) {
455
+            $options['callback'] = 'entity_row_to_elggstar';
456
+        }
457 457
 
458
-		return elgg_get_annotations($options);
459
-	}
460
-	
461
-	/**
462
-	 * Check to see if a user has already created an annotation on an object
463
-	 *
464
-	 * @param int    $entity_guid     Entity guid
465
-	 * @param string $annotation_type Type of annotation
466
-	 * @param int    $owner_guid      Defaults to logged in user.
467
-	 *
468
-	 * @return bool
469
-	 */
470
-	function exists($entity_guid, $annotation_type, $owner_guid = null) {
458
+        return elgg_get_annotations($options);
459
+    }
460
+	
461
+    /**
462
+     * Check to see if a user has already created an annotation on an object
463
+     *
464
+     * @param int    $entity_guid     Entity guid
465
+     * @param string $annotation_type Type of annotation
466
+     * @param int    $owner_guid      Defaults to logged in user.
467
+     *
468
+     * @return bool
469
+     */
470
+    function exists($entity_guid, $annotation_type, $owner_guid = null) {
471 471
 		
472 472
 	
473
-		if (!$owner_guid && !($owner_guid = $this->session->getLoggedInUserGuid())) {
474
-			return false;
475
-		}
473
+        if (!$owner_guid && !($owner_guid = $this->session->getLoggedInUserGuid())) {
474
+            return false;
475
+        }
476 476
 	
477
-		$entity_guid = sanitize_int($entity_guid);
478
-		$owner_guid = sanitize_int($owner_guid);
479
-		$annotation_type = sanitize_string($annotation_type);
477
+        $entity_guid = sanitize_int($entity_guid);
478
+        $owner_guid = sanitize_int($owner_guid);
479
+        $annotation_type = sanitize_string($annotation_type);
480 480
 	
481
-		$sql = "SELECT a.id FROM {$this->db->prefix}annotations a" .
482
-				" JOIN {$this->db->prefix}metastrings m ON a.name_id = m.id" .
483
-				" WHERE a.owner_guid = $owner_guid AND a.entity_guid = $entity_guid" .
484
-				" AND m.string = '$annotation_type'";
481
+        $sql = "SELECT a.id FROM {$this->db->prefix}annotations a" .
482
+                " JOIN {$this->db->prefix}metastrings m ON a.name_id = m.id" .
483
+                " WHERE a.owner_guid = $owner_guid AND a.entity_guid = $entity_guid" .
484
+                " AND m.string = '$annotation_type'";
485 485
 	
486
-		if ($this->db->getDataRow($sql)) {
487
-			return true;
488
-		}
486
+        if ($this->db->getDataRow($sql)) {
487
+            return true;
488
+        }
489 489
 	
490
-		return false;
491
-	}
490
+        return false;
491
+    }
492 492
 }
493 493
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -86,15 +86,15 @@  discard block
 block discarded – undo
86 86
 	
87 87
 		$result = false;
88 88
 	
89
-		$entity_guid = (int)$entity_guid;
89
+		$entity_guid = (int) $entity_guid;
90 90
 		$value_type = \ElggExtender::detectValueType($value, $value_type);
91 91
 	
92
-		$owner_guid = (int)$owner_guid;
92
+		$owner_guid = (int) $owner_guid;
93 93
 		if ($owner_guid == 0) {
94 94
 			$owner_guid = $this->session->getLoggedInUserGuid();
95 95
 		}
96 96
 	
97
-		$access_id = (int)$access_id;
97
+		$access_id = (int) $access_id;
98 98
 		$time = $this->getCurrentTime()->getTimestamp();
99 99
 	
100 100
 		$value_id = elgg_get_metastring_id($value);
@@ -146,7 +146,7 @@  discard block
 block discarded – undo
146 146
 	function update($annotation_id, $name, $value, $value_type, $owner_guid, $access_id) {
147 147
 		
148 148
 	
149
-		$annotation_id = (int)$annotation_id;
149
+		$annotation_id = (int) $annotation_id;
150 150
 	
151 151
 		$annotation = $this->get($annotation_id);
152 152
 		if (!$annotation) {
@@ -159,12 +159,12 @@  discard block
 block discarded – undo
159 159
 		$name = trim($name);
160 160
 		$value_type = \ElggExtender::detectValueType($value, $value_type);
161 161
 	
162
-		$owner_guid = (int)$owner_guid;
162
+		$owner_guid = (int) $owner_guid;
163 163
 		if ($owner_guid == 0) {
164 164
 			$owner_guid = $this->session->getLoggedInUserGuid();
165 165
 		}
166 166
 	
167
-		$access_id = (int)$access_id;
167
+		$access_id = (int) $access_id;
168 168
 	
169 169
 		$value_id = elgg_get_metastring_id($value);
170 170
 		if (!$value_id) {
@@ -372,7 +372,7 @@  discard block
 block discarded – undo
372 372
 			// the user didn't provide maxtime
373 373
 			if ($deprecated) {
374 374
 				// special sorting for annotations
375
-				elgg_deprecated_notice(__FUNCTION__ . ": no longer orders by annotations by default. If you order"
375
+				elgg_deprecated_notice(__FUNCTION__.": no longer orders by annotations by default. If you order"
376 376
 					. " by maxtime, you must provide that column via \$options['selects']. See"
377 377
 					. " https://github.com/Elgg/Elgg/issues/6638#issuecomment-41562034", "1.10");
378 378
 					
@@ -478,9 +478,9 @@  discard block
 block discarded – undo
478 478
 		$owner_guid = sanitize_int($owner_guid);
479 479
 		$annotation_type = sanitize_string($annotation_type);
480 480
 	
481
-		$sql = "SELECT a.id FROM {$this->db->prefix}annotations a" .
482
-				" JOIN {$this->db->prefix}metastrings m ON a.name_id = m.id" .
483
-				" WHERE a.owner_guid = $owner_guid AND a.entity_guid = $entity_guid" .
481
+		$sql = "SELECT a.id FROM {$this->db->prefix}annotations a".
482
+				" JOIN {$this->db->prefix}metastrings m ON a.name_id = m.id".
483
+				" WHERE a.owner_guid = $owner_guid AND a.entity_guid = $entity_guid".
484 484
 				" AND m.string = '$annotation_type'";
485 485
 	
486 486
 		if ($this->db->getDataRow($sql)) {
Please login to merge, or discard this patch.
engine/classes/Elgg/Database/MetadataTable.php 3 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
 	 *
77 77
 	 * @param int $id The id of the metadata object being retrieved.
78 78
 	 *
79
-	 * @return \ElggMetadata|false  false if not found
79
+	 * @return \ElggExtender  false if not found
80 80
 	 */
81 81
 	function get($id) {
82 82
 		return _elgg_get_metastring_based_object_from_id($id, 'metadata');
@@ -767,7 +767,7 @@  discard block
 block discarded – undo
767 767
 	 *
768 768
 	 * @param int $id Metadata ID
769 769
 	 *
770
-	 * @return mixed
770
+	 * @return string|false
771 771
 	 */
772 772
 	function getUrl($id) {
773 773
 		$extender = $this->get($id);
@@ -817,7 +817,7 @@  discard block
 block discarded – undo
817 817
 	 * @param string      $object_type The type of object
818 818
 	 * @param \ElggEntity $object      The entity itself
819 819
 	 *
820
-	 * @return true
820
+	 * @return boolean
821 821
 	 * @access private Set as private in 1.9.0
822 822
 	 */
823 823
 	function handleUpdate($event, $object_type, $object) {
Please login to merge, or discard this patch.
Indentation   +782 added lines, -782 removed lines patch added patch discarded remove patch
@@ -20,233 +20,233 @@  discard block
 block discarded – undo
20 20
  */
21 21
 class MetadataTable {
22 22
 
23
-	use \Elgg\TimeUsing;
23
+    use \Elgg\TimeUsing;
24 24
 
25
-	/** @var array */
26
-	protected $independents = array();
25
+    /** @var array */
26
+    protected $independents = array();
27 27
 	
28
-	/** @var Cache */
29
-	protected $cache;
28
+    /** @var Cache */
29
+    protected $cache;
30 30
 	
31
-	/** @var Database */
32
-	protected $db;
31
+    /** @var Database */
32
+    protected $db;
33 33
 	
34
-	/** @var EntityTable */
35
-	protected $entityTable;
34
+    /** @var EntityTable */
35
+    protected $entityTable;
36 36
 	
37
-	/** @var MetastringsTable */
38
-	protected $metastringsTable;
37
+    /** @var MetastringsTable */
38
+    protected $metastringsTable;
39 39
 	
40
-	/** @var Events */
41
-	protected $events;
40
+    /** @var Events */
41
+    protected $events;
42 42
 	
43
-	/** @var Session */
44
-	protected $session;
43
+    /** @var Session */
44
+    protected $session;
45 45
 	
46
-	/** @var string */
47
-	protected $table;
46
+    /** @var string */
47
+    protected $table;
48 48
 
49
-	/**
50
-	 * Constructor
51
-	 * 
52
-	 * @param Cache            $cache            A cache for this table
53
-	 * @param Database         $db               The Elgg database
54
-	 * @param EntityTable      $entityTable      The entities table
55
-	 * @param Events           $events           The events registry
56
-	 * @param MetastringsTable $metastringsTable The metastrings table
57
-	 * @param Session          $session          The session
58
-	 */
59
-	public function __construct(
60
-			Cache $cache,
61
-			Database $db,
62
-			EntityTable $entityTable,
63
-			Events $events,
64
-			MetastringsTable $metastringsTable,
65
-			Session $session) {
66
-		$this->cache = $cache;
67
-		$this->db = $db;
68
-		$this->entityTable = $entityTable;
69
-		$this->events = $events;
70
-		$this->metastringsTable = $metastringsTable;
71
-		$this->session = $session;
72
-		$this->table = $this->db->prefix . "metadata";
73
-	}
49
+    /**
50
+     * Constructor
51
+     * 
52
+     * @param Cache            $cache            A cache for this table
53
+     * @param Database         $db               The Elgg database
54
+     * @param EntityTable      $entityTable      The entities table
55
+     * @param Events           $events           The events registry
56
+     * @param MetastringsTable $metastringsTable The metastrings table
57
+     * @param Session          $session          The session
58
+     */
59
+    public function __construct(
60
+            Cache $cache,
61
+            Database $db,
62
+            EntityTable $entityTable,
63
+            Events $events,
64
+            MetastringsTable $metastringsTable,
65
+            Session $session) {
66
+        $this->cache = $cache;
67
+        $this->db = $db;
68
+        $this->entityTable = $entityTable;
69
+        $this->events = $events;
70
+        $this->metastringsTable = $metastringsTable;
71
+        $this->session = $session;
72
+        $this->table = $this->db->prefix . "metadata";
73
+    }
74 74
 
75
-	/**
76
-	 * Get a specific metadata object by its id.
77
-	 * If you want multiple metadata objects, use
78
-	 * {@link elgg_get_metadata()}.
79
-	 *
80
-	 * @param int $id The id of the metadata object being retrieved.
81
-	 *
82
-	 * @return \ElggMetadata|false  false if not found
83
-	 */
84
-	function get($id) {
85
-		return _elgg_get_metastring_based_object_from_id($id, 'metadata');
86
-	}
87
-	
88
-	/**
89
-	 * Deletes metadata using its ID.
90
-	 *
91
-	 * @param int $id The metadata ID to delete.
92
-	 * @return bool
93
-	 */
94
-	function delete($id) {
95
-		$metadata = $this->get($id);
75
+    /**
76
+     * Get a specific metadata object by its id.
77
+     * If you want multiple metadata objects, use
78
+     * {@link elgg_get_metadata()}.
79
+     *
80
+     * @param int $id The id of the metadata object being retrieved.
81
+     *
82
+     * @return \ElggMetadata|false  false if not found
83
+     */
84
+    function get($id) {
85
+        return _elgg_get_metastring_based_object_from_id($id, 'metadata');
86
+    }
87
+	
88
+    /**
89
+     * Deletes metadata using its ID.
90
+     *
91
+     * @param int $id The metadata ID to delete.
92
+     * @return bool
93
+     */
94
+    function delete($id) {
95
+        $metadata = $this->get($id);
96 96
 
97
-		return $metadata ? $metadata->delete() : false;
98
-	}
99
-	
100
-	/**
101
-	 * Create a new metadata object, or update an existing one.
102
-	 *
103
-	 * Metadata can be an array by setting allow_multiple to true, but it is an
104
-	 * indexed array with no control over the indexing.
105
-	 *
106
-	 * @param int    $entity_guid    The entity to attach the metadata to
107
-	 * @param string $name           Name of the metadata
108
-	 * @param string $value          Value of the metadata
109
-	 * @param string $value_type     'text', 'integer', or '' for automatic detection
110
-	 * @param int    $owner_guid     GUID of entity that owns the metadata. Default is logged in user.
111
-	 * @param int    $access_id      Default is ACCESS_PRIVATE
112
-	 * @param bool   $allow_multiple Allow multiple values for one key. Default is false
113
-	 *
114
-	 * @return int|false id of metadata or false if failure
115
-	 */
116
-	function create($entity_guid, $name, $value, $value_type = '', $owner_guid = 0,
117
-			$access_id = ACCESS_PRIVATE, $allow_multiple = false) {
97
+        return $metadata ? $metadata->delete() : false;
98
+    }
99
+	
100
+    /**
101
+     * Create a new metadata object, or update an existing one.
102
+     *
103
+     * Metadata can be an array by setting allow_multiple to true, but it is an
104
+     * indexed array with no control over the indexing.
105
+     *
106
+     * @param int    $entity_guid    The entity to attach the metadata to
107
+     * @param string $name           Name of the metadata
108
+     * @param string $value          Value of the metadata
109
+     * @param string $value_type     'text', 'integer', or '' for automatic detection
110
+     * @param int    $owner_guid     GUID of entity that owns the metadata. Default is logged in user.
111
+     * @param int    $access_id      Default is ACCESS_PRIVATE
112
+     * @param bool   $allow_multiple Allow multiple values for one key. Default is false
113
+     *
114
+     * @return int|false id of metadata or false if failure
115
+     */
116
+    function create($entity_guid, $name, $value, $value_type = '', $owner_guid = 0,
117
+            $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
118 118
 
119
-		$entity_guid = (int)$entity_guid;
120
-		// name and value are encoded in add_metastring()
121
-		$value_type = \ElggExtender::detectValueType($value, trim($value_type));
122
-		$time = $this->getCurrentTime()->getTimestamp();
123
-		$owner_guid = (int)$owner_guid;
124
-		$allow_multiple = (boolean)$allow_multiple;
119
+        $entity_guid = (int)$entity_guid;
120
+        // name and value are encoded in add_metastring()
121
+        $value_type = \ElggExtender::detectValueType($value, trim($value_type));
122
+        $time = $this->getCurrentTime()->getTimestamp();
123
+        $owner_guid = (int)$owner_guid;
124
+        $allow_multiple = (boolean)$allow_multiple;
125 125
 	
126
-		if (!isset($value)) {
127
-			return false;
128
-		}
126
+        if (!isset($value)) {
127
+            return false;
128
+        }
129 129
 	
130
-		if ($owner_guid == 0) {
131
-			$owner_guid = $this->session->getLoggedInUserGuid();
132
-		}
130
+        if ($owner_guid == 0) {
131
+            $owner_guid = $this->session->getLoggedInUserGuid();
132
+        }
133 133
 	
134
-		$access_id = (int) $access_id;
134
+        $access_id = (int) $access_id;
135 135
 	
136
-		$query = "SELECT * FROM {$this->table}
136
+        $query = "SELECT * FROM {$this->table}
137 137
 			WHERE entity_guid = :entity_guid and name_id = :name_id LIMIT 1";
138 138
 
139
-		$params = [
140
-			':entity_guid' => $entity_guid,
141
-			':name_id' => $this->metastringsTable->getId($name)
142
-		];
139
+        $params = [
140
+            ':entity_guid' => $entity_guid,
141
+            ':name_id' => $this->metastringsTable->getId($name)
142
+        ];
143 143
 
144
-		$existing = $this->db->getDataRow($query, null, $params);
145
-		if ($existing && !$allow_multiple) {
146
-			$id = (int)$existing->id;
147
-			$result = $this->update($id, $name, $value, $value_type, $owner_guid, $access_id);
148
-	
149
-			if (!$result) {
150
-				return false;
151
-			}
152
-		} else {
153
-			// Support boolean types
154
-			if (is_bool($value)) {
155
-				$value = (int)$value;
156
-			}
157
-	
158
-			// Add the metastrings
159
-			$value_id = $this->metastringsTable->getId($value);
160
-			if (!$value_id) {
161
-				return false;
162
-			}
163
-	
164
-			$name_id = $this->metastringsTable->getId($name);
165
-			if (!$name_id) {
166
-				return false;
167
-			}
168
-	
169
-			// If ok then add it
170
-			$query = "INSERT INTO {$this->table}
144
+        $existing = $this->db->getDataRow($query, null, $params);
145
+        if ($existing && !$allow_multiple) {
146
+            $id = (int)$existing->id;
147
+            $result = $this->update($id, $name, $value, $value_type, $owner_guid, $access_id);
148
+	
149
+            if (!$result) {
150
+                return false;
151
+            }
152
+        } else {
153
+            // Support boolean types
154
+            if (is_bool($value)) {
155
+                $value = (int)$value;
156
+            }
157
+	
158
+            // Add the metastrings
159
+            $value_id = $this->metastringsTable->getId($value);
160
+            if (!$value_id) {
161
+                return false;
162
+            }
163
+	
164
+            $name_id = $this->metastringsTable->getId($name);
165
+            if (!$name_id) {
166
+                return false;
167
+            }
168
+	
169
+            // If ok then add it
170
+            $query = "INSERT INTO {$this->table}
171 171
 				(entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id)
172 172
 				VALUES (:entity_guid, :name_id, :value_id, :value_type, :owner_guid, :time_created, :access_id)";
173 173
 
174
-			$params = [
175
-				':entity_guid' => $entity_guid,
176
-				':name_id' => $name_id,
177
-				':value_id' => $value_id,
178
-				':value_type' => $value_type,
179
-				':owner_guid' => $owner_guid,
180
-				':time_created' => $time,
181
-				':access_id' => $access_id,
182
-			];
174
+            $params = [
175
+                ':entity_guid' => $entity_guid,
176
+                ':name_id' => $name_id,
177
+                ':value_id' => $value_id,
178
+                ':value_type' => $value_type,
179
+                ':owner_guid' => $owner_guid,
180
+                ':time_created' => $time,
181
+                ':access_id' => $access_id,
182
+            ];
183 183
 			
184
-			$id = $this->db->insertData($query, $params);
184
+            $id = $this->db->insertData($query, $params);
185 185
 			
186
-			if ($id !== false) {
187
-				$obj = $this->get($id);
188
-				if ($this->events->trigger('create', 'metadata', $obj)) {
186
+            if ($id !== false) {
187
+                $obj = $this->get($id);
188
+                if ($this->events->trigger('create', 'metadata', $obj)) {
189 189
 
190
-					$this->cache->clear($entity_guid);
191
-	
192
-					return $id;
193
-				} else {
194
-					$this->delete($id);
195
-				}
196
-			}
197
-		}
198
-	
199
-		return $id;
200
-	}
201
-	
202
-	/**
203
-	 * Update a specific piece of metadata.
204
-	 *
205
-	 * @param int    $id         ID of the metadata to update
206
-	 * @param string $name       Metadata name
207
-	 * @param string $value      Metadata value
208
-	 * @param string $value_type Value type
209
-	 * @param int    $owner_guid Owner guid
210
-	 * @param int    $access_id  Access ID
211
-	 *
212
-	 * @return bool
213
-	 */
214
-	function update($id, $name, $value, $value_type, $owner_guid, $access_id) {
215
-		$id = (int)$id;
216
-	
217
-		if (!$md = $this->get($id)) {
218
-			return false;
219
-		}
220
-		if (!$md->canEdit()) {
221
-			return false;
222
-		}
223
-	
224
-		$value_type = \ElggExtender::detectValueType($value, trim($value_type));
225
-	
226
-		$owner_guid = (int)$owner_guid;
227
-		if ($owner_guid == 0) {
228
-			$owner_guid = $this->session->getLoggedInUserGuid();
229
-		}
230
-	
231
-		$access_id = (int)$access_id;
232
-	
233
-		// Support boolean types (as integers)
234
-		if (is_bool($value)) {
235
-			$value = (int)$value;
236
-		}
237
-	
238
-		$value_id = $this->metastringsTable->getId($value);
239
-		if (!$value_id) {
240
-			return false;
241
-		}
242
-	
243
-		$name_id = $this->metastringsTable->getId($name);
244
-		if (!$name_id) {
245
-			return false;
246
-		}
247
-	
248
-		// If ok then add it
249
-		$query = "UPDATE {$this->table}
190
+                    $this->cache->clear($entity_guid);
191
+	
192
+                    return $id;
193
+                } else {
194
+                    $this->delete($id);
195
+                }
196
+            }
197
+        }
198
+	
199
+        return $id;
200
+    }
201
+	
202
+    /**
203
+     * Update a specific piece of metadata.
204
+     *
205
+     * @param int    $id         ID of the metadata to update
206
+     * @param string $name       Metadata name
207
+     * @param string $value      Metadata value
208
+     * @param string $value_type Value type
209
+     * @param int    $owner_guid Owner guid
210
+     * @param int    $access_id  Access ID
211
+     *
212
+     * @return bool
213
+     */
214
+    function update($id, $name, $value, $value_type, $owner_guid, $access_id) {
215
+        $id = (int)$id;
216
+	
217
+        if (!$md = $this->get($id)) {
218
+            return false;
219
+        }
220
+        if (!$md->canEdit()) {
221
+            return false;
222
+        }
223
+	
224
+        $value_type = \ElggExtender::detectValueType($value, trim($value_type));
225
+	
226
+        $owner_guid = (int)$owner_guid;
227
+        if ($owner_guid == 0) {
228
+            $owner_guid = $this->session->getLoggedInUserGuid();
229
+        }
230
+	
231
+        $access_id = (int)$access_id;
232
+	
233
+        // Support boolean types (as integers)
234
+        if (is_bool($value)) {
235
+            $value = (int)$value;
236
+        }
237
+	
238
+        $value_id = $this->metastringsTable->getId($value);
239
+        if (!$value_id) {
240
+            return false;
241
+        }
242
+	
243
+        $name_id = $this->metastringsTable->getId($name);
244
+        if (!$name_id) {
245
+            return false;
246
+        }
247
+	
248
+        // If ok then add it
249
+        $query = "UPDATE {$this->table}
250 250
 			SET name_id = :name_id,
251 251
 			    value_id = :value_id,
252 252
 				value_type = :value_type,
@@ -254,603 +254,603 @@  discard block
 block discarded – undo
254 254
 			    owner_guid = :owner_guid
255 255
 			WHERE id = :id";
256 256
 
257
-		$params = [
258
-			':name_id' => $name_id,
259
-			':value_id' => $value_id,
260
-			':value_type' => $value_type,
261
-			':access_id' => $access_id,
262
-			':owner_guid' => $owner_guid,
263
-			':id' => $id,
264
-		];
257
+        $params = [
258
+            ':name_id' => $name_id,
259
+            ':value_id' => $value_id,
260
+            ':value_type' => $value_type,
261
+            ':access_id' => $access_id,
262
+            ':owner_guid' => $owner_guid,
263
+            ':id' => $id,
264
+        ];
265 265
 		
266
-		$result = $this->db->updateData($query, false, $params);
266
+        $result = $this->db->updateData($query, false, $params);
267 267
 		
268
-		if ($result !== false) {
269
-	
270
-			$this->cache->clear($md->entity_guid);
271
-	
272
-			// @todo this event tells you the metadata has been updated, but does not
273
-			// let you do anything about it. What is needed is a plugin hook before
274
-			// the update that passes old and new values.
275
-			$obj = $this->get($id);
276
-			$this->events->trigger('update', 'metadata', $obj);
277
-		}
278
-	
279
-		return $result;
280
-	}
281
-	
282
-	/**
283
-	 * This function creates metadata from an associative array of "key => value" pairs.
284
-	 *
285
-	 * To achieve an array for a single key, pass in the same key multiple times with
286
-	 * allow_multiple set to true. This creates an indexed array. It does not support
287
-	 * associative arrays and there is no guarantee on the ordering in the array.
288
-	 *
289
-	 * @param int    $entity_guid     The entity to attach the metadata to
290
-	 * @param array  $name_and_values Associative array - a value can be a string, number, bool
291
-	 * @param string $value_type      'text', 'integer', or '' for automatic detection
292
-	 * @param int    $owner_guid      GUID of entity that owns the metadata
293
-	 * @param int    $access_id       Default is ACCESS_PRIVATE
294
-	 * @param bool   $allow_multiple  Allow multiple values for one key. Default is false
295
-	 *
296
-	 * @return bool
297
-	 */
298
-	function createFromArray($entity_guid, array $name_and_values, $value_type, $owner_guid,
299
-			$access_id = ACCESS_PRIVATE, $allow_multiple = false) {
300
-	
301
-		foreach ($name_and_values as $k => $v) {
302
-			$result = $this->create($entity_guid, $k, $v, $value_type, $owner_guid,
303
-				$access_id, $allow_multiple);
304
-			if (!$result) {
305
-				return false;
306
-			}
307
-		}
308
-		return true;
309
-	}
310
-	
311
-	/**
312
-	 * Returns metadata.  Accepts all elgg_get_entities() options for entity
313
-	 * restraints.
314
-	 *
315
-	 * @see elgg_get_entities
316
-	 *
317
-	 * @warning 1.7's find_metadata() didn't support limits and returned all metadata.
318
-	 *          This function defaults to a limit of 25. There is probably not a reason
319
-	 *          for you to return all metadata unless you're exporting an entity,
320
-	 *          have other restraints in place, or are doing something horribly
321
-	 *          wrong in your code.
322
-	 *
323
-	 * @param array $options Array in format:
324
-	 *
325
-	 * metadata_names               => null|ARR metadata names
326
-	 * metadata_values              => null|ARR metadata values
327
-	 * metadata_ids                 => null|ARR metadata ids
328
-	 * metadata_case_sensitive      => BOOL Overall Case sensitive
329
-	 * metadata_owner_guids         => null|ARR guids for metadata owners
330
-	 * metadata_created_time_lower  => INT Lower limit for created time.
331
-	 * metadata_created_time_upper  => INT Upper limit for created time.
332
-	 * metadata_calculation         => STR Perform the MySQL function on the metadata values returned.
333
-	 *                                   The "metadata_calculation" option causes this function to
334
-	 *                                   return the result of performing a mathematical calculation on
335
-	 *                                   all metadata that match the query instead of returning
336
-	 *                                   \ElggMetadata objects.
337
-	 *
338
-	 * @return \ElggMetadata[]|mixed
339
-	 */
340
-	function getAll(array $options = array()) {
341
-	
342
-		// @todo remove support for count shortcut - see #4393
343
-		// support shortcut of 'count' => true for 'metadata_calculation' => 'count'
344
-		if (isset($options['count']) && $options['count']) {
345
-			$options['metadata_calculation'] = 'count';
346
-			unset($options['count']);
347
-		}
348
-	
349
-		$options['metastring_type'] = 'metadata';
350
-		return _elgg_get_metastring_based_objects($options);
351
-	}
352
-	
353
-	/**
354
-	 * Deletes metadata based on $options.
355
-	 *
356
-	 * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
357
-	 *          This requires at least one constraint: metadata_owner_guid(s),
358
-	 *          metadata_name(s), metadata_value(s), or guid(s) must be set.
359
-	 *
360
-	 * @param array $options An options array. {@link elgg_get_metadata()}
361
-	 * @return bool|null true on success, false on failure, null if no metadata to delete.
362
-	 */
363
-	function deleteAll(array $options) {
364
-		if (!_elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
365
-			return false;
366
-		}
367
-		$options['metastring_type'] = 'metadata';
368
-		$result = _elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
369
-	
370
-		// This moved last in case an object's constructor sets metadata. Currently the batch
371
-		// delete process has to create the entity to delete its metadata. See #5214
372
-		$this->cache->invalidateByOptions($options);
373
-	
374
-		return $result;
375
-	}
376
-	
377
-	/**
378
-	 * Disables metadata based on $options.
379
-	 *
380
-	 * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
381
-	 *
382
-	 * @param array $options An options array. {@link elgg_get_metadata()}
383
-	 * @return bool|null true on success, false on failure, null if no metadata disabled.
384
-	 */
385
-	function disableAll(array $options) {
386
-		if (!_elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
387
-			return false;
388
-		}
389
-	
390
-		$this->cache->invalidateByOptions($options);
391
-	
392
-		// if we can see hidden (disabled) we need to use the offset
393
-		// otherwise we risk an infinite loop if there are more than 50
394
-		$inc_offset = access_get_show_hidden_status();
395
-	
396
-		$options['metastring_type'] = 'metadata';
397
-		return _elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
398
-	}
399
-	
400
-	/**
401
-	 * Enables metadata based on $options.
402
-	 *
403
-	 * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
404
-	 *
405
-	 * @warning In order to enable metadata, you must first use
406
-	 * {@link access_show_hidden_entities()}.
407
-	 *
408
-	 * @param array $options An options array. {@link elgg_get_metadata()}
409
-	 * @return bool|null true on success, false on failure, null if no metadata enabled.
410
-	 */
411
-	function enableAll(array $options) {
412
-		if (!$options || !is_array($options)) {
413
-			return false;
414
-		}
415
-	
416
-		$this->cache->invalidateByOptions($options);
417
-	
418
-		$options['metastring_type'] = 'metadata';
419
-		return _elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
420
-	}
421
-	
422
-	/**
423
-	 * Returns entities based upon metadata.  Also accepts all
424
-	 * options available to elgg_get_entities().  Supports
425
-	 * the singular option shortcut.
426
-	 *
427
-	 * @note Using metadata_names and metadata_values results in a
428
-	 * "names IN (...) AND values IN (...)" clause.  This is subtly
429
-	 * differently than default multiple metadata_name_value_pairs, which use
430
-	 * "(name = value) AND (name = value)" clauses.
431
-	 *
432
-	 * When in doubt, use name_value_pairs.
433
-	 *
434
-	 * To ask for entities that do not have a metadata value, use a custom
435
-	 * where clause like this:
436
-	 *
437
-	 * 	$options['wheres'][] = "NOT EXISTS (
438
-	 *			SELECT 1 FROM {$dbprefix}metadata md
439
-	 *			WHERE md.entity_guid = e.guid
440
-	 *				AND md.name_id = $name_metastring_id
441
-	 *				AND md.value_id = $value_metastring_id)";
442
-	 *
443
-	 * Note the metadata name and value has been denormalized in the above example.
444
-	 *
445
-	 * @see elgg_get_entities
446
-	 *
447
-	 * @param array $options Array in format:
448
-	 *
449
-	 * 	metadata_names => null|ARR metadata names
450
-	 *
451
-	 * 	metadata_values => null|ARR metadata values
452
-	 *
453
-	 * 	metadata_name_value_pairs => null|ARR (
454
-	 *                                         name => 'name',
455
-	 *                                         value => 'value',
456
-	 *                                         'operand' => '=',
457
-	 *                                         'case_sensitive' => true
458
-	 *                                        )
459
-	 *                               Currently if multiple values are sent via
460
-	 *                               an array (value => array('value1', 'value2')
461
-	 *                               the pair's operand will be forced to "IN".
462
-	 *                               If passing "IN" as the operand and a string as the value, 
463
-	 *                               the value must be a properly quoted and escaped string.
464
-	 *
465
-	 * 	metadata_name_value_pairs_operator => null|STR The operator to use for combining
466
-	 *                                        (name = value) OPERATOR (name = value); default AND
467
-	 *
468
-	 * 	metadata_case_sensitive => BOOL Overall Case sensitive
469
-	 *
470
-	 *  order_by_metadata => null|ARR array(
471
-	 *                                      'name' => 'metadata_text1',
472
-	 *                                      'direction' => ASC|DESC,
473
-	 *                                      'as' => text|integer
474
-	 *                                     )
475
-	 *                                Also supports array('name' => 'metadata_text1')
476
-	 *
477
-	 *  metadata_owner_guids => null|ARR guids for metadata owners
478
-	 *
479
-	 * @return \ElggEntity[]|mixed If count, int. If not count, array. false on errors.
480
-	 */
481
-	function getEntities(array $options = array()) {
482
-		$defaults = array(
483
-			'metadata_names'                     => ELGG_ENTITIES_ANY_VALUE,
484
-			'metadata_values'                    => ELGG_ENTITIES_ANY_VALUE,
485
-			'metadata_name_value_pairs'          => ELGG_ENTITIES_ANY_VALUE,
486
-	
487
-			'metadata_name_value_pairs_operator' => 'AND',
488
-			'metadata_case_sensitive'            => true,
489
-			'order_by_metadata'                  => array(),
490
-	
491
-			'metadata_owner_guids'               => ELGG_ENTITIES_ANY_VALUE,
492
-		);
493
-	
494
-		$options = array_merge($defaults, $options);
495
-	
496
-		$singulars = array('metadata_name', 'metadata_value',
497
-			'metadata_name_value_pair', 'metadata_owner_guid');
498
-	
499
-		$options = _elgg_normalize_plural_options_array($options, $singulars);
500
-	
501
-		if (!$options = _elgg_entities_get_metastrings_options('metadata', $options)) {
502
-			return false;
503
-		}
504
-	
505
-		return $this->entityTable->getEntities($options);
506
-	}
507
-	
508
-	/**
509
-	 * Returns metadata name and value SQL where for entities.
510
-	 * NB: $names and $values are not paired. Use $pairs for this.
511
-	 * Pairs default to '=' operand.
512
-	 *
513
-	 * This function is reused for annotations because the tables are
514
-	 * exactly the same.
515
-	 *
516
-	 * @param string     $e_table           Entities table name
517
-	 * @param string     $n_table           Normalized metastrings table name (Where entities,
518
-	 *                                    values, and names are joined. annotations / metadata)
519
-	 * @param array|null $names             Array of names
520
-	 * @param array|null $values            Array of values
521
-	 * @param array|null $pairs             Array of names / values / operands
522
-	 * @param string     $pair_operator     ("AND" or "OR") Operator to use to join the where clauses for pairs
523
-	 * @param bool       $case_sensitive    Case sensitive metadata names?
524
-	 * @param array|null $order_by_metadata Array of names / direction
525
-	 * @param array|null $owner_guids       Array of owner GUIDs
526
-	 *
527
-	 * @return false|array False on fail, array('joins', 'wheres')
528
-	 * @access private
529
-	 */
530
-	function getEntityMetadataWhereSql($e_table, $n_table, $names = null, $values = null,
531
-			$pairs = null, $pair_operator = 'AND', $case_sensitive = true, $order_by_metadata = null,
532
-			$owner_guids = null) {
533
-		// short circuit if nothing requested
534
-		// 0 is a valid (if not ill-conceived) metadata name.
535
-		// 0 is also a valid metadata value for false, null, or 0
536
-		// 0 is also a valid(ish) owner_guid
537
-		if ((!$names && $names !== 0)
538
-			&& (!$values && $values !== 0)
539
-			&& (!$pairs && $pairs !== 0)
540
-			&& (!$owner_guids && $owner_guids !== 0)
541
-			&& !$order_by_metadata) {
542
-			return '';
543
-		}
544
-	
545
-		// join counter for incremental joins.
546
-		$i = 1;
547
-	
548
-		// binary forces byte-to-byte comparision of strings, making
549
-		// it case- and diacritical-mark- sensitive.
550
-		// only supported on values.
551
-		$binary = ($case_sensitive) ? ' BINARY ' : '';
552
-	
553
-		$access = _elgg_get_access_where_sql(array(
554
-			'table_alias' => 'n_table',
555
-			'guid_column' => 'entity_guid',
556
-		));
557
-	
558
-		$return = array (
559
-			'joins' => array (),
560
-			'wheres' => array(),
561
-			'orders' => array()
562
-		);
563
-	
564
-		// will always want to join these tables if pulling metastrings.
565
-		$return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table on
268
+        if ($result !== false) {
269
+	
270
+            $this->cache->clear($md->entity_guid);
271
+	
272
+            // @todo this event tells you the metadata has been updated, but does not
273
+            // let you do anything about it. What is needed is a plugin hook before
274
+            // the update that passes old and new values.
275
+            $obj = $this->get($id);
276
+            $this->events->trigger('update', 'metadata', $obj);
277
+        }
278
+	
279
+        return $result;
280
+    }
281
+	
282
+    /**
283
+     * This function creates metadata from an associative array of "key => value" pairs.
284
+     *
285
+     * To achieve an array for a single key, pass in the same key multiple times with
286
+     * allow_multiple set to true. This creates an indexed array. It does not support
287
+     * associative arrays and there is no guarantee on the ordering in the array.
288
+     *
289
+     * @param int    $entity_guid     The entity to attach the metadata to
290
+     * @param array  $name_and_values Associative array - a value can be a string, number, bool
291
+     * @param string $value_type      'text', 'integer', or '' for automatic detection
292
+     * @param int    $owner_guid      GUID of entity that owns the metadata
293
+     * @param int    $access_id       Default is ACCESS_PRIVATE
294
+     * @param bool   $allow_multiple  Allow multiple values for one key. Default is false
295
+     *
296
+     * @return bool
297
+     */
298
+    function createFromArray($entity_guid, array $name_and_values, $value_type, $owner_guid,
299
+            $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
300
+	
301
+        foreach ($name_and_values as $k => $v) {
302
+            $result = $this->create($entity_guid, $k, $v, $value_type, $owner_guid,
303
+                $access_id, $allow_multiple);
304
+            if (!$result) {
305
+                return false;
306
+            }
307
+        }
308
+        return true;
309
+    }
310
+	
311
+    /**
312
+     * Returns metadata.  Accepts all elgg_get_entities() options for entity
313
+     * restraints.
314
+     *
315
+     * @see elgg_get_entities
316
+     *
317
+     * @warning 1.7's find_metadata() didn't support limits and returned all metadata.
318
+     *          This function defaults to a limit of 25. There is probably not a reason
319
+     *          for you to return all metadata unless you're exporting an entity,
320
+     *          have other restraints in place, or are doing something horribly
321
+     *          wrong in your code.
322
+     *
323
+     * @param array $options Array in format:
324
+     *
325
+     * metadata_names               => null|ARR metadata names
326
+     * metadata_values              => null|ARR metadata values
327
+     * metadata_ids                 => null|ARR metadata ids
328
+     * metadata_case_sensitive      => BOOL Overall Case sensitive
329
+     * metadata_owner_guids         => null|ARR guids for metadata owners
330
+     * metadata_created_time_lower  => INT Lower limit for created time.
331
+     * metadata_created_time_upper  => INT Upper limit for created time.
332
+     * metadata_calculation         => STR Perform the MySQL function on the metadata values returned.
333
+     *                                   The "metadata_calculation" option causes this function to
334
+     *                                   return the result of performing a mathematical calculation on
335
+     *                                   all metadata that match the query instead of returning
336
+     *                                   \ElggMetadata objects.
337
+     *
338
+     * @return \ElggMetadata[]|mixed
339
+     */
340
+    function getAll(array $options = array()) {
341
+	
342
+        // @todo remove support for count shortcut - see #4393
343
+        // support shortcut of 'count' => true for 'metadata_calculation' => 'count'
344
+        if (isset($options['count']) && $options['count']) {
345
+            $options['metadata_calculation'] = 'count';
346
+            unset($options['count']);
347
+        }
348
+	
349
+        $options['metastring_type'] = 'metadata';
350
+        return _elgg_get_metastring_based_objects($options);
351
+    }
352
+	
353
+    /**
354
+     * Deletes metadata based on $options.
355
+     *
356
+     * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
357
+     *          This requires at least one constraint: metadata_owner_guid(s),
358
+     *          metadata_name(s), metadata_value(s), or guid(s) must be set.
359
+     *
360
+     * @param array $options An options array. {@link elgg_get_metadata()}
361
+     * @return bool|null true on success, false on failure, null if no metadata to delete.
362
+     */
363
+    function deleteAll(array $options) {
364
+        if (!_elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
365
+            return false;
366
+        }
367
+        $options['metastring_type'] = 'metadata';
368
+        $result = _elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
369
+	
370
+        // This moved last in case an object's constructor sets metadata. Currently the batch
371
+        // delete process has to create the entity to delete its metadata. See #5214
372
+        $this->cache->invalidateByOptions($options);
373
+	
374
+        return $result;
375
+    }
376
+	
377
+    /**
378
+     * Disables metadata based on $options.
379
+     *
380
+     * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
381
+     *
382
+     * @param array $options An options array. {@link elgg_get_metadata()}
383
+     * @return bool|null true on success, false on failure, null if no metadata disabled.
384
+     */
385
+    function disableAll(array $options) {
386
+        if (!_elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
387
+            return false;
388
+        }
389
+	
390
+        $this->cache->invalidateByOptions($options);
391
+	
392
+        // if we can see hidden (disabled) we need to use the offset
393
+        // otherwise we risk an infinite loop if there are more than 50
394
+        $inc_offset = access_get_show_hidden_status();
395
+	
396
+        $options['metastring_type'] = 'metadata';
397
+        return _elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
398
+    }
399
+	
400
+    /**
401
+     * Enables metadata based on $options.
402
+     *
403
+     * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
404
+     *
405
+     * @warning In order to enable metadata, you must first use
406
+     * {@link access_show_hidden_entities()}.
407
+     *
408
+     * @param array $options An options array. {@link elgg_get_metadata()}
409
+     * @return bool|null true on success, false on failure, null if no metadata enabled.
410
+     */
411
+    function enableAll(array $options) {
412
+        if (!$options || !is_array($options)) {
413
+            return false;
414
+        }
415
+	
416
+        $this->cache->invalidateByOptions($options);
417
+	
418
+        $options['metastring_type'] = 'metadata';
419
+        return _elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
420
+    }
421
+	
422
+    /**
423
+     * Returns entities based upon metadata.  Also accepts all
424
+     * options available to elgg_get_entities().  Supports
425
+     * the singular option shortcut.
426
+     *
427
+     * @note Using metadata_names and metadata_values results in a
428
+     * "names IN (...) AND values IN (...)" clause.  This is subtly
429
+     * differently than default multiple metadata_name_value_pairs, which use
430
+     * "(name = value) AND (name = value)" clauses.
431
+     *
432
+     * When in doubt, use name_value_pairs.
433
+     *
434
+     * To ask for entities that do not have a metadata value, use a custom
435
+     * where clause like this:
436
+     *
437
+     * 	$options['wheres'][] = "NOT EXISTS (
438
+     *			SELECT 1 FROM {$dbprefix}metadata md
439
+     *			WHERE md.entity_guid = e.guid
440
+     *				AND md.name_id = $name_metastring_id
441
+     *				AND md.value_id = $value_metastring_id)";
442
+     *
443
+     * Note the metadata name and value has been denormalized in the above example.
444
+     *
445
+     * @see elgg_get_entities
446
+     *
447
+     * @param array $options Array in format:
448
+     *
449
+     * 	metadata_names => null|ARR metadata names
450
+     *
451
+     * 	metadata_values => null|ARR metadata values
452
+     *
453
+     * 	metadata_name_value_pairs => null|ARR (
454
+     *                                         name => 'name',
455
+     *                                         value => 'value',
456
+     *                                         'operand' => '=',
457
+     *                                         'case_sensitive' => true
458
+     *                                        )
459
+     *                               Currently if multiple values are sent via
460
+     *                               an array (value => array('value1', 'value2')
461
+     *                               the pair's operand will be forced to "IN".
462
+     *                               If passing "IN" as the operand and a string as the value, 
463
+     *                               the value must be a properly quoted and escaped string.
464
+     *
465
+     * 	metadata_name_value_pairs_operator => null|STR The operator to use for combining
466
+     *                                        (name = value) OPERATOR (name = value); default AND
467
+     *
468
+     * 	metadata_case_sensitive => BOOL Overall Case sensitive
469
+     *
470
+     *  order_by_metadata => null|ARR array(
471
+     *                                      'name' => 'metadata_text1',
472
+     *                                      'direction' => ASC|DESC,
473
+     *                                      'as' => text|integer
474
+     *                                     )
475
+     *                                Also supports array('name' => 'metadata_text1')
476
+     *
477
+     *  metadata_owner_guids => null|ARR guids for metadata owners
478
+     *
479
+     * @return \ElggEntity[]|mixed If count, int. If not count, array. false on errors.
480
+     */
481
+    function getEntities(array $options = array()) {
482
+        $defaults = array(
483
+            'metadata_names'                     => ELGG_ENTITIES_ANY_VALUE,
484
+            'metadata_values'                    => ELGG_ENTITIES_ANY_VALUE,
485
+            'metadata_name_value_pairs'          => ELGG_ENTITIES_ANY_VALUE,
486
+	
487
+            'metadata_name_value_pairs_operator' => 'AND',
488
+            'metadata_case_sensitive'            => true,
489
+            'order_by_metadata'                  => array(),
490
+	
491
+            'metadata_owner_guids'               => ELGG_ENTITIES_ANY_VALUE,
492
+        );
493
+	
494
+        $options = array_merge($defaults, $options);
495
+	
496
+        $singulars = array('metadata_name', 'metadata_value',
497
+            'metadata_name_value_pair', 'metadata_owner_guid');
498
+	
499
+        $options = _elgg_normalize_plural_options_array($options, $singulars);
500
+	
501
+        if (!$options = _elgg_entities_get_metastrings_options('metadata', $options)) {
502
+            return false;
503
+        }
504
+	
505
+        return $this->entityTable->getEntities($options);
506
+    }
507
+	
508
+    /**
509
+     * Returns metadata name and value SQL where for entities.
510
+     * NB: $names and $values are not paired. Use $pairs for this.
511
+     * Pairs default to '=' operand.
512
+     *
513
+     * This function is reused for annotations because the tables are
514
+     * exactly the same.
515
+     *
516
+     * @param string     $e_table           Entities table name
517
+     * @param string     $n_table           Normalized metastrings table name (Where entities,
518
+     *                                    values, and names are joined. annotations / metadata)
519
+     * @param array|null $names             Array of names
520
+     * @param array|null $values            Array of values
521
+     * @param array|null $pairs             Array of names / values / operands
522
+     * @param string     $pair_operator     ("AND" or "OR") Operator to use to join the where clauses for pairs
523
+     * @param bool       $case_sensitive    Case sensitive metadata names?
524
+     * @param array|null $order_by_metadata Array of names / direction
525
+     * @param array|null $owner_guids       Array of owner GUIDs
526
+     *
527
+     * @return false|array False on fail, array('joins', 'wheres')
528
+     * @access private
529
+     */
530
+    function getEntityMetadataWhereSql($e_table, $n_table, $names = null, $values = null,
531
+            $pairs = null, $pair_operator = 'AND', $case_sensitive = true, $order_by_metadata = null,
532
+            $owner_guids = null) {
533
+        // short circuit if nothing requested
534
+        // 0 is a valid (if not ill-conceived) metadata name.
535
+        // 0 is also a valid metadata value for false, null, or 0
536
+        // 0 is also a valid(ish) owner_guid
537
+        if ((!$names && $names !== 0)
538
+            && (!$values && $values !== 0)
539
+            && (!$pairs && $pairs !== 0)
540
+            && (!$owner_guids && $owner_guids !== 0)
541
+            && !$order_by_metadata) {
542
+            return '';
543
+        }
544
+	
545
+        // join counter for incremental joins.
546
+        $i = 1;
547
+	
548
+        // binary forces byte-to-byte comparision of strings, making
549
+        // it case- and diacritical-mark- sensitive.
550
+        // only supported on values.
551
+        $binary = ($case_sensitive) ? ' BINARY ' : '';
552
+	
553
+        $access = _elgg_get_access_where_sql(array(
554
+            'table_alias' => 'n_table',
555
+            'guid_column' => 'entity_guid',
556
+        ));
557
+	
558
+        $return = array (
559
+            'joins' => array (),
560
+            'wheres' => array(),
561
+            'orders' => array()
562
+        );
563
+	
564
+        // will always want to join these tables if pulling metastrings.
565
+        $return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table on
566 566
 			{$e_table}.guid = n_table.entity_guid";
567 567
 	
568
-		$wheres = array();
569
-	
570
-		// get names wheres and joins
571
-		$names_where = '';
572
-		if ($names !== null) {
573
-			if (!is_array($names)) {
574
-				$names = array($names);
575
-			}
576
-	
577
-			$sanitised_names = array();
578
-			foreach ($names as $name) {
579
-				// normalise to 0.
580
-				if (!$name) {
581
-					$name = '0';
582
-				}
583
-				$sanitised_names[] = '\'' . $this->db->sanitizeString($name) . '\'';
584
-			}
585
-	
586
-			if ($names_str = implode(',', $sanitised_names)) {
587
-				$return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn on n_table.name_id = msn.id";
588
-				$names_where = "(msn.string IN ($names_str))";
589
-			}
590
-		}
591
-	
592
-		// get values wheres and joins
593
-		$values_where = '';
594
-		if ($values !== null) {
595
-			if (!is_array($values)) {
596
-				$values = array($values);
597
-			}
598
-	
599
-			$sanitised_values = array();
600
-			foreach ($values as $value) {
601
-				// normalize to 0
602
-				if (!$value) {
603
-					$value = 0;
604
-				}
605
-				$sanitised_values[] = '\'' . $this->db->sanitizeString($value) . '\'';
606
-			}
607
-	
608
-			if ($values_str = implode(',', $sanitised_values)) {
609
-				$return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv on n_table.value_id = msv.id";
610
-				$values_where = "({$binary}msv.string IN ($values_str))";
611
-			}
612
-		}
613
-	
614
-		if ($names_where && $values_where) {
615
-			$wheres[] = "($names_where AND $values_where AND $access)";
616
-		} elseif ($names_where) {
617
-			$wheres[] = "($names_where AND $access)";
618
-		} elseif ($values_where) {
619
-			$wheres[] = "($values_where AND $access)";
620
-		}
621
-	
622
-		// add pairs
623
-		// pairs must be in arrays.
624
-		if (is_array($pairs)) {
625
-			// check if this is an array of pairs or just a single pair.
626
-			if (isset($pairs['name']) || isset($pairs['value'])) {
627
-				$pairs = array($pairs);
628
-			}
629
-	
630
-			$pair_wheres = array();
631
-	
632
-			// @todo when the pairs are > 3 should probably split the query up to
633
-			// denormalize the strings table.
634
-	
635
-			foreach ($pairs as $index => $pair) {
636
-				// @todo move this elsewhere?
637
-				// support shortcut 'n' => 'v' method.
638
-				if (!is_array($pair)) {
639
-					$pair = array(
640
-						'name' => $index,
641
-						'value' => $pair
642
-					);
643
-				}
644
-	
645
-				// must have at least a name and value
646
-				if (!isset($pair['name']) || !isset($pair['value'])) {
647
-					// @todo should probably return false.
648
-					continue;
649
-				}
650
-	
651
-				// case sensitivity can be specified per pair.
652
-				// default to higher level setting.
653
-				if (isset($pair['case_sensitive'])) {
654
-					$pair_binary = ($pair['case_sensitive']) ? ' BINARY ' : '';
655
-				} else {
656
-					$pair_binary = $binary;
657
-				}
658
-	
659
-				if (isset($pair['operand'])) {
660
-					$operand = $this->db->sanitizeString($pair['operand']);
661
-				} else {
662
-					$operand = ' = ';
663
-				}
664
-	
665
-				// for comparing
666
-				$trimmed_operand = trim(strtolower($operand));
667
-	
668
-				$access = _elgg_get_access_where_sql(array(
669
-					'table_alias' => "n_table{$i}",
670
-					'guid_column' => 'entity_guid',
671
-				));
568
+        $wheres = array();
569
+	
570
+        // get names wheres and joins
571
+        $names_where = '';
572
+        if ($names !== null) {
573
+            if (!is_array($names)) {
574
+                $names = array($names);
575
+            }
576
+	
577
+            $sanitised_names = array();
578
+            foreach ($names as $name) {
579
+                // normalise to 0.
580
+                if (!$name) {
581
+                    $name = '0';
582
+                }
583
+                $sanitised_names[] = '\'' . $this->db->sanitizeString($name) . '\'';
584
+            }
585
+	
586
+            if ($names_str = implode(',', $sanitised_names)) {
587
+                $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn on n_table.name_id = msn.id";
588
+                $names_where = "(msn.string IN ($names_str))";
589
+            }
590
+        }
591
+	
592
+        // get values wheres and joins
593
+        $values_where = '';
594
+        if ($values !== null) {
595
+            if (!is_array($values)) {
596
+                $values = array($values);
597
+            }
598
+	
599
+            $sanitised_values = array();
600
+            foreach ($values as $value) {
601
+                // normalize to 0
602
+                if (!$value) {
603
+                    $value = 0;
604
+                }
605
+                $sanitised_values[] = '\'' . $this->db->sanitizeString($value) . '\'';
606
+            }
607
+	
608
+            if ($values_str = implode(',', $sanitised_values)) {
609
+                $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv on n_table.value_id = msv.id";
610
+                $values_where = "({$binary}msv.string IN ($values_str))";
611
+            }
612
+        }
613
+	
614
+        if ($names_where && $values_where) {
615
+            $wheres[] = "($names_where AND $values_where AND $access)";
616
+        } elseif ($names_where) {
617
+            $wheres[] = "($names_where AND $access)";
618
+        } elseif ($values_where) {
619
+            $wheres[] = "($values_where AND $access)";
620
+        }
621
+	
622
+        // add pairs
623
+        // pairs must be in arrays.
624
+        if (is_array($pairs)) {
625
+            // check if this is an array of pairs or just a single pair.
626
+            if (isset($pairs['name']) || isset($pairs['value'])) {
627
+                $pairs = array($pairs);
628
+            }
629
+	
630
+            $pair_wheres = array();
631
+	
632
+            // @todo when the pairs are > 3 should probably split the query up to
633
+            // denormalize the strings table.
634
+	
635
+            foreach ($pairs as $index => $pair) {
636
+                // @todo move this elsewhere?
637
+                // support shortcut 'n' => 'v' method.
638
+                if (!is_array($pair)) {
639
+                    $pair = array(
640
+                        'name' => $index,
641
+                        'value' => $pair
642
+                    );
643
+                }
644
+	
645
+                // must have at least a name and value
646
+                if (!isset($pair['name']) || !isset($pair['value'])) {
647
+                    // @todo should probably return false.
648
+                    continue;
649
+                }
650
+	
651
+                // case sensitivity can be specified per pair.
652
+                // default to higher level setting.
653
+                if (isset($pair['case_sensitive'])) {
654
+                    $pair_binary = ($pair['case_sensitive']) ? ' BINARY ' : '';
655
+                } else {
656
+                    $pair_binary = $binary;
657
+                }
658
+	
659
+                if (isset($pair['operand'])) {
660
+                    $operand = $this->db->sanitizeString($pair['operand']);
661
+                } else {
662
+                    $operand = ' = ';
663
+                }
664
+	
665
+                // for comparing
666
+                $trimmed_operand = trim(strtolower($operand));
667
+	
668
+                $access = _elgg_get_access_where_sql(array(
669
+                    'table_alias' => "n_table{$i}",
670
+                    'guid_column' => 'entity_guid',
671
+                ));
672 672
 
673
-				// certain operands can't work well with strings that can be interpreted as numbers
674
-				// for direct comparisons like IN, =, != we treat them as strings
675
-				// gt/lt comparisons need to stay unencapsulated because strings '5' > '15'
676
-				// see https://github.com/Elgg/Elgg/issues/7009
677
-				$num_safe_operands = array('>', '<', '>=', '<=');
678
-				$num_test_operand = trim(strtoupper($operand));
679
-	
680
-				if (is_numeric($pair['value']) && in_array($num_test_operand, $num_safe_operands)) {
681
-					$value = $this->db->sanitizeString($pair['value']);
682
-				} else if (is_bool($pair['value'])) {
683
-					$value = (int)$pair['value'];
684
-				} else if (is_array($pair['value'])) {
685
-					$values_array = array();
686
-	
687
-					foreach ($pair['value'] as $pair_value) {
688
-						if (is_numeric($pair_value) && !in_array($num_test_operand, $num_safe_operands)) {
689
-							$values_array[] = $this->db->sanitizeString($pair_value);
690
-						} else {
691
-							$values_array[] = "'" . $this->db->sanitizeString($pair_value) . "'";
692
-						}
693
-					}
694
-	
695
-					if ($values_array) {
696
-						$value = '(' . implode(', ', $values_array) . ')';
697
-					}
698
-	
699
-					// @todo allow support for non IN operands with array of values.
700
-					// will have to do more silly joins.
701
-					$operand = 'IN';
702
-				} else if ($trimmed_operand == 'in') {
703
-					$value = "({$pair['value']})";
704
-				} else {
705
-					$value = "'" . $this->db->sanitizeString($pair['value']) . "'";
706
-				}
707
-	
708
-				$name = $this->db->sanitizeString($pair['name']);
709
-	
710
-				// @todo The multiple joins are only needed when the operator is AND
711
-				$return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table{$i}
673
+                // certain operands can't work well with strings that can be interpreted as numbers
674
+                // for direct comparisons like IN, =, != we treat them as strings
675
+                // gt/lt comparisons need to stay unencapsulated because strings '5' > '15'
676
+                // see https://github.com/Elgg/Elgg/issues/7009
677
+                $num_safe_operands = array('>', '<', '>=', '<=');
678
+                $num_test_operand = trim(strtoupper($operand));
679
+	
680
+                if (is_numeric($pair['value']) && in_array($num_test_operand, $num_safe_operands)) {
681
+                    $value = $this->db->sanitizeString($pair['value']);
682
+                } else if (is_bool($pair['value'])) {
683
+                    $value = (int)$pair['value'];
684
+                } else if (is_array($pair['value'])) {
685
+                    $values_array = array();
686
+	
687
+                    foreach ($pair['value'] as $pair_value) {
688
+                        if (is_numeric($pair_value) && !in_array($num_test_operand, $num_safe_operands)) {
689
+                            $values_array[] = $this->db->sanitizeString($pair_value);
690
+                        } else {
691
+                            $values_array[] = "'" . $this->db->sanitizeString($pair_value) . "'";
692
+                        }
693
+                    }
694
+	
695
+                    if ($values_array) {
696
+                        $value = '(' . implode(', ', $values_array) . ')';
697
+                    }
698
+	
699
+                    // @todo allow support for non IN operands with array of values.
700
+                    // will have to do more silly joins.
701
+                    $operand = 'IN';
702
+                } else if ($trimmed_operand == 'in') {
703
+                    $value = "({$pair['value']})";
704
+                } else {
705
+                    $value = "'" . $this->db->sanitizeString($pair['value']) . "'";
706
+                }
707
+	
708
+                $name = $this->db->sanitizeString($pair['name']);
709
+	
710
+                // @todo The multiple joins are only needed when the operator is AND
711
+                $return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table{$i}
712 712
 					on {$e_table}.guid = n_table{$i}.entity_guid";
713
-				$return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn{$i}
713
+                $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn{$i}
714 714
 					on n_table{$i}.name_id = msn{$i}.id";
715
-				$return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv{$i}
715
+                $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv{$i}
716 716
 					on n_table{$i}.value_id = msv{$i}.id";
717 717
 	
718
-				$pair_wheres[] = "(msn{$i}.string = '$name' AND {$pair_binary}msv{$i}.string
718
+                $pair_wheres[] = "(msn{$i}.string = '$name' AND {$pair_binary}msv{$i}.string
719 719
 					$operand $value AND $access)";
720 720
 	
721
-				$i++;
722
-			}
723
-	
724
-			if ($where = implode(" $pair_operator ", $pair_wheres)) {
725
-				$wheres[] = "($where)";
726
-			}
727
-		}
728
-	
729
-		// add owner_guids
730
-		if ($owner_guids) {
731
-			if (is_array($owner_guids)) {
732
-				$sanitised = array_map('sanitise_int', $owner_guids);
733
-				$owner_str = implode(',', $sanitised);
734
-			} else {
735
-				$owner_str = (int)$owner_guids;
736
-			}
737
-	
738
-			$wheres[] = "(n_table.owner_guid IN ($owner_str))";
739
-		}
740
-	
741
-		if ($where = implode(' AND ', $wheres)) {
742
-			$return['wheres'][] = "($where)";
743
-		}
744
-	
745
-		if (is_array($order_by_metadata)) {
746
-			if ((count($order_by_metadata) > 0) && !isset($order_by_metadata[0])) {
747
-				// singleton, so fix
748
-				$order_by_metadata = array($order_by_metadata);
749
-			}
750
-			foreach ($order_by_metadata as $order_by) {
751
-				if (is_array($order_by) && isset($order_by['name'])) {
752
-					$name = $this->db->sanitizeString($order_by['name']);
753
-					if (isset($order_by['direction'])) {
754
-						$direction = $this->db->sanitizeString($order_by['direction']);
755
-					} else {
756
-						$direction = 'ASC';
757
-					}
758
-					$return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table{$i}
721
+                $i++;
722
+            }
723
+	
724
+            if ($where = implode(" $pair_operator ", $pair_wheres)) {
725
+                $wheres[] = "($where)";
726
+            }
727
+        }
728
+	
729
+        // add owner_guids
730
+        if ($owner_guids) {
731
+            if (is_array($owner_guids)) {
732
+                $sanitised = array_map('sanitise_int', $owner_guids);
733
+                $owner_str = implode(',', $sanitised);
734
+            } else {
735
+                $owner_str = (int)$owner_guids;
736
+            }
737
+	
738
+            $wheres[] = "(n_table.owner_guid IN ($owner_str))";
739
+        }
740
+	
741
+        if ($where = implode(' AND ', $wheres)) {
742
+            $return['wheres'][] = "($where)";
743
+        }
744
+	
745
+        if (is_array($order_by_metadata)) {
746
+            if ((count($order_by_metadata) > 0) && !isset($order_by_metadata[0])) {
747
+                // singleton, so fix
748
+                $order_by_metadata = array($order_by_metadata);
749
+            }
750
+            foreach ($order_by_metadata as $order_by) {
751
+                if (is_array($order_by) && isset($order_by['name'])) {
752
+                    $name = $this->db->sanitizeString($order_by['name']);
753
+                    if (isset($order_by['direction'])) {
754
+                        $direction = $this->db->sanitizeString($order_by['direction']);
755
+                    } else {
756
+                        $direction = 'ASC';
757
+                    }
758
+                    $return['joins'][] = "JOIN {$this->db->prefix}{$n_table} n_table{$i}
759 759
 						on {$e_table}.guid = n_table{$i}.entity_guid";
760
-					$return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn{$i}
760
+                    $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msn{$i}
761 761
 						on n_table{$i}.name_id = msn{$i}.id";
762
-					$return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv{$i}
762
+                    $return['joins'][] = "JOIN {$this->metastringsTable->getTableName()} msv{$i}
763 763
 						on n_table{$i}.value_id = msv{$i}.id";
764 764
 	
765
-					$access = _elgg_get_access_where_sql(array(
766
-						'table_alias' => "n_table{$i}",
767
-						'guid_column' => 'entity_guid',
768
-					));
769
-	
770
-					$return['wheres'][] = "(msn{$i}.string = '$name' AND $access)";
771
-					if (isset($order_by['as']) && $order_by['as'] == 'integer') {
772
-						$return['orders'][] = "CAST(msv{$i}.string AS SIGNED) $direction";
773
-					} else {
774
-						$return['orders'][] = "msv{$i}.string $direction";
775
-					}
776
-					$i++;
777
-				}
778
-			}
779
-		}
780
-	
781
-		return $return;
782
-	}
783
-	
784
-	/**
785
-	 * Get the URL for this metadata
786
-	 *
787
-	 * By default this links to the export handler in the current view.
788
-	 *
789
-	 * @param int $id Metadata ID
790
-	 *
791
-	 * @return mixed
792
-	 */
793
-	function getUrl($id) {
794
-		$extender = $this->get($id);
765
+                    $access = _elgg_get_access_where_sql(array(
766
+                        'table_alias' => "n_table{$i}",
767
+                        'guid_column' => 'entity_guid',
768
+                    ));
769
+	
770
+                    $return['wheres'][] = "(msn{$i}.string = '$name' AND $access)";
771
+                    if (isset($order_by['as']) && $order_by['as'] == 'integer') {
772
+                        $return['orders'][] = "CAST(msv{$i}.string AS SIGNED) $direction";
773
+                    } else {
774
+                        $return['orders'][] = "msv{$i}.string $direction";
775
+                    }
776
+                    $i++;
777
+                }
778
+            }
779
+        }
780
+	
781
+        return $return;
782
+    }
783
+	
784
+    /**
785
+     * Get the URL for this metadata
786
+     *
787
+     * By default this links to the export handler in the current view.
788
+     *
789
+     * @param int $id Metadata ID
790
+     *
791
+     * @return mixed
792
+     */
793
+    function getUrl($id) {
794
+        $extender = $this->get($id);
795 795
 
796
-		return $extender ? $extender->getURL() : false;
797
-	}
798
-	
799
-	/**
800
-	 * Mark entities with a particular type and subtype as having access permissions
801
-	 * that can be changed independently from their parent entity
802
-	 *
803
-	 * @param string $type    The type - object, user, etc
804
-	 * @param string $subtype The subtype; all subtypes by default
805
-	 *
806
-	 * @return void
807
-	 */
808
-	function registerMetadataAsIndependent($type, $subtype = '*') {
809
-		if (!isset($this->independents[$type])) {
810
-			$this->independents[$type] = array();
811
-		}
796
+        return $extender ? $extender->getURL() : false;
797
+    }
798
+	
799
+    /**
800
+     * Mark entities with a particular type and subtype as having access permissions
801
+     * that can be changed independently from their parent entity
802
+     *
803
+     * @param string $type    The type - object, user, etc
804
+     * @param string $subtype The subtype; all subtypes by default
805
+     *
806
+     * @return void
807
+     */
808
+    function registerMetadataAsIndependent($type, $subtype = '*') {
809
+        if (!isset($this->independents[$type])) {
810
+            $this->independents[$type] = array();
811
+        }
812 812
 		
813
-		$this->independents[$type][$subtype] = true;
814
-	}
815
-	
816
-	/**
817
-	 * Determines whether entities of a given type and subtype should not change
818
-	 * their metadata in line with their parent entity
819
-	 *
820
-	 * @param string $type    The type - object, user, etc
821
-	 * @param string $subtype The entity subtype
822
-	 *
823
-	 * @return bool
824
-	 */
825
-	function isMetadataIndependent($type, $subtype) {
826
-		if (empty($this->independents[$type])) {
827
-			return false;
828
-		}
813
+        $this->independents[$type][$subtype] = true;
814
+    }
815
+	
816
+    /**
817
+     * Determines whether entities of a given type and subtype should not change
818
+     * their metadata in line with their parent entity
819
+     *
820
+     * @param string $type    The type - object, user, etc
821
+     * @param string $subtype The entity subtype
822
+     *
823
+     * @return bool
824
+     */
825
+    function isMetadataIndependent($type, $subtype) {
826
+        if (empty($this->independents[$type])) {
827
+            return false;
828
+        }
829 829
 
830
-		return !empty($this->independents[$type][$subtype])
831
-			|| !empty($this->independents[$type]['*']);
832
-	}
833
-	
834
-	/**
835
-	 * When an entity is updated, resets the access ID on all of its child metadata
836
-	 *
837
-	 * @param string      $event       The name of the event
838
-	 * @param string      $object_type The type of object
839
-	 * @param \ElggEntity $object      The entity itself
840
-	 *
841
-	 * @return true
842
-	 * @access private Set as private in 1.9.0
843
-	 */
844
-	function handleUpdate($event, $object_type, $object) {
845
-		if ($object instanceof \ElggEntity) {
846
-			if (!$this->isMetadataIndependent($object->getType(), $object->getSubtype())) {
847
-				$access_id = (int)$object->access_id;
848
-				$guid = (int)$object->getGUID();
849
-				$query = "update {$this->table} set access_id = {$access_id} where entity_guid = {$guid}";
850
-				$this->db->updateData($query);
851
-			}
852
-		}
853
-		return true;
854
-	}
830
+        return !empty($this->independents[$type][$subtype])
831
+            || !empty($this->independents[$type]['*']);
832
+    }
833
+	
834
+    /**
835
+     * When an entity is updated, resets the access ID on all of its child metadata
836
+     *
837
+     * @param string      $event       The name of the event
838
+     * @param string      $object_type The type of object
839
+     * @param \ElggEntity $object      The entity itself
840
+     *
841
+     * @return true
842
+     * @access private Set as private in 1.9.0
843
+     */
844
+    function handleUpdate($event, $object_type, $object) {
845
+        if ($object instanceof \ElggEntity) {
846
+            if (!$this->isMetadataIndependent($object->getType(), $object->getSubtype())) {
847
+                $access_id = (int)$object->access_id;
848
+                $guid = (int)$object->getGUID();
849
+                $query = "update {$this->table} set access_id = {$access_id} where entity_guid = {$guid}";
850
+                $this->db->updateData($query);
851
+            }
852
+        }
853
+        return true;
854
+    }
855 855
 	
856 856
 }
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -69,7 +69,7 @@  discard block
 block discarded – undo
69 69
 		$this->events = $events;
70 70
 		$this->metastringsTable = $metastringsTable;
71 71
 		$this->session = $session;
72
-		$this->table = $this->db->prefix . "metadata";
72
+		$this->table = $this->db->prefix."metadata";
73 73
 	}
74 74
 
75 75
 	/**
@@ -116,12 +116,12 @@  discard block
 block discarded – undo
116 116
 	function create($entity_guid, $name, $value, $value_type = '', $owner_guid = 0,
117 117
 			$access_id = ACCESS_PRIVATE, $allow_multiple = false) {
118 118
 
119
-		$entity_guid = (int)$entity_guid;
119
+		$entity_guid = (int) $entity_guid;
120 120
 		// name and value are encoded in add_metastring()
121 121
 		$value_type = \ElggExtender::detectValueType($value, trim($value_type));
122 122
 		$time = $this->getCurrentTime()->getTimestamp();
123
-		$owner_guid = (int)$owner_guid;
124
-		$allow_multiple = (boolean)$allow_multiple;
123
+		$owner_guid = (int) $owner_guid;
124
+		$allow_multiple = (boolean) $allow_multiple;
125 125
 	
126 126
 		if (!isset($value)) {
127 127
 			return false;
@@ -143,7 +143,7 @@  discard block
 block discarded – undo
143 143
 
144 144
 		$existing = $this->db->getDataRow($query, null, $params);
145 145
 		if ($existing && !$allow_multiple) {
146
-			$id = (int)$existing->id;
146
+			$id = (int) $existing->id;
147 147
 			$result = $this->update($id, $name, $value, $value_type, $owner_guid, $access_id);
148 148
 	
149 149
 			if (!$result) {
@@ -152,7 +152,7 @@  discard block
 block discarded – undo
152 152
 		} else {
153 153
 			// Support boolean types
154 154
 			if (is_bool($value)) {
155
-				$value = (int)$value;
155
+				$value = (int) $value;
156 156
 			}
157 157
 	
158 158
 			// Add the metastrings
@@ -212,7 +212,7 @@  discard block
 block discarded – undo
212 212
 	 * @return bool
213 213
 	 */
214 214
 	function update($id, $name, $value, $value_type, $owner_guid, $access_id) {
215
-		$id = (int)$id;
215
+		$id = (int) $id;
216 216
 	
217 217
 		if (!$md = $this->get($id)) {
218 218
 			return false;
@@ -223,16 +223,16 @@  discard block
 block discarded – undo
223 223
 	
224 224
 		$value_type = \ElggExtender::detectValueType($value, trim($value_type));
225 225
 	
226
-		$owner_guid = (int)$owner_guid;
226
+		$owner_guid = (int) $owner_guid;
227 227
 		if ($owner_guid == 0) {
228 228
 			$owner_guid = $this->session->getLoggedInUserGuid();
229 229
 		}
230 230
 	
231
-		$access_id = (int)$access_id;
231
+		$access_id = (int) $access_id;
232 232
 	
233 233
 		// Support boolean types (as integers)
234 234
 		if (is_bool($value)) {
235
-			$value = (int)$value;
235
+			$value = (int) $value;
236 236
 		}
237 237
 	
238 238
 		$value_id = $this->metastringsTable->getId($value);
@@ -555,8 +555,8 @@  discard block
 block discarded – undo
555 555
 			'guid_column' => 'entity_guid',
556 556
 		));
557 557
 	
558
-		$return = array (
559
-			'joins' => array (),
558
+		$return = array(
559
+			'joins' => array(),
560 560
 			'wheres' => array(),
561 561
 			'orders' => array()
562 562
 		);
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
 				if (!$name) {
581 581
 					$name = '0';
582 582
 				}
583
-				$sanitised_names[] = '\'' . $this->db->sanitizeString($name) . '\'';
583
+				$sanitised_names[] = '\''.$this->db->sanitizeString($name).'\'';
584 584
 			}
585 585
 	
586 586
 			if ($names_str = implode(',', $sanitised_names)) {
@@ -602,7 +602,7 @@  discard block
 block discarded – undo
602 602
 				if (!$value) {
603 603
 					$value = 0;
604 604
 				}
605
-				$sanitised_values[] = '\'' . $this->db->sanitizeString($value) . '\'';
605
+				$sanitised_values[] = '\''.$this->db->sanitizeString($value).'\'';
606 606
 			}
607 607
 	
608 608
 			if ($values_str = implode(',', $sanitised_values)) {
@@ -680,7 +680,7 @@  discard block
 block discarded – undo
680 680
 				if (is_numeric($pair['value']) && in_array($num_test_operand, $num_safe_operands)) {
681 681
 					$value = $this->db->sanitizeString($pair['value']);
682 682
 				} else if (is_bool($pair['value'])) {
683
-					$value = (int)$pair['value'];
683
+					$value = (int) $pair['value'];
684 684
 				} else if (is_array($pair['value'])) {
685 685
 					$values_array = array();
686 686
 	
@@ -688,12 +688,12 @@  discard block
 block discarded – undo
688 688
 						if (is_numeric($pair_value) && !in_array($num_test_operand, $num_safe_operands)) {
689 689
 							$values_array[] = $this->db->sanitizeString($pair_value);
690 690
 						} else {
691
-							$values_array[] = "'" . $this->db->sanitizeString($pair_value) . "'";
691
+							$values_array[] = "'".$this->db->sanitizeString($pair_value)."'";
692 692
 						}
693 693
 					}
694 694
 	
695 695
 					if ($values_array) {
696
-						$value = '(' . implode(', ', $values_array) . ')';
696
+						$value = '('.implode(', ', $values_array).')';
697 697
 					}
698 698
 	
699 699
 					// @todo allow support for non IN operands with array of values.
@@ -702,7 +702,7 @@  discard block
 block discarded – undo
702 702
 				} else if ($trimmed_operand == 'in') {
703 703
 					$value = "({$pair['value']})";
704 704
 				} else {
705
-					$value = "'" . $this->db->sanitizeString($pair['value']) . "'";
705
+					$value = "'".$this->db->sanitizeString($pair['value'])."'";
706 706
 				}
707 707
 	
708 708
 				$name = $this->db->sanitizeString($pair['name']);
@@ -732,7 +732,7 @@  discard block
 block discarded – undo
732 732
 				$sanitised = array_map('sanitise_int', $owner_guids);
733 733
 				$owner_str = implode(',', $sanitised);
734 734
 			} else {
735
-				$owner_str = (int)$owner_guids;
735
+				$owner_str = (int) $owner_guids;
736 736
 			}
737 737
 	
738 738
 			$wheres[] = "(n_table.owner_guid IN ($owner_str))";
@@ -844,8 +844,8 @@  discard block
 block discarded – undo
844 844
 	function handleUpdate($event, $object_type, $object) {
845 845
 		if ($object instanceof \ElggEntity) {
846 846
 			if (!$this->isMetadataIndependent($object->getType(), $object->getSubtype())) {
847
-				$access_id = (int)$object->access_id;
848
-				$guid = (int)$object->getGUID();
847
+				$access_id = (int) $object->access_id;
848
+				$guid = (int) $object->getGUID();
849 849
 				$query = "update {$this->table} set access_id = {$access_id} where entity_guid = {$guid}";
850 850
 				$this->db->updateData($query);
851 851
 			}
Please login to merge, or discard this patch.
engine/classes/Elgg/Database/SiteSecret.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -28,7 +28,7 @@
 block discarded – undo
28 28
 	 *
29 29
 	 * Note: Old secrets were hex encoded.
30 30
 	 *
31
-	 * @return mixed The site secret hash or false
31
+	 * @return string|false The site secret hash or false
32 32
 	 * @access private
33 33
 	 */
34 34
 	function init() {
Please login to merge, or discard this patch.
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -21,114 +21,114 @@
 block discarded – undo
21 21
  */
22 22
 class SiteSecret {
23 23
 
24
-	/**
25
-	 * @var Datalist
26
-	 */
27
-	private $datalist;
24
+    /**
25
+     * @var Datalist
26
+     */
27
+    private $datalist;
28 28
 
29
-	/**
30
-	 * Constructor
31
-	 *
32
-	 * @param Datalist $datalist Datalist table
33
-	 */
34
-	public function __construct(Datalist $datalist) {
35
-		$this->datalist = $datalist;
36
-	}
29
+    /**
30
+     * Constructor
31
+     *
32
+     * @param Datalist $datalist Datalist table
33
+     */
34
+    public function __construct(Datalist $datalist) {
35
+        $this->datalist = $datalist;
36
+    }
37 37
 
38
-	/**
39
-	 * @var string
40
-	 */
41
-	private $test_secret = '';
38
+    /**
39
+     * @var string
40
+     */
41
+    private $test_secret = '';
42 42
 
43
-	/**
44
-	 * Set a secret to be used in testing
45
-	 *
46
-	 * @param string $secret Testing site secret. 32 alphanums starting with "z"
47
-	 * @return void
48
-	 */
49
-	public function setTestingSecret($secret) {
50
-		$this->test_secret = $secret;
51
-	}
43
+    /**
44
+     * Set a secret to be used in testing
45
+     *
46
+     * @param string $secret Testing site secret. 32 alphanums starting with "z"
47
+     * @return void
48
+     */
49
+    public function setTestingSecret($secret) {
50
+        $this->test_secret = $secret;
51
+    }
52 52
 
53
-	/**
54
-	 * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL).
55
-	 *
56
-	 * Used during installation and saves as a datalist.
57
-	 *
58
-	 * Note: Old secrets were hex encoded.
59
-	 *
60
-	 * @return mixed The site secret hash or false
61
-	 * @access private
62
-	 */
63
-	function init() {
64
-		$secret = 'z' . _elgg_services()->crypto->getRandomString(31);
53
+    /**
54
+     * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL).
55
+     *
56
+     * Used during installation and saves as a datalist.
57
+     *
58
+     * Note: Old secrets were hex encoded.
59
+     *
60
+     * @return mixed The site secret hash or false
61
+     * @access private
62
+     */
63
+    function init() {
64
+        $secret = 'z' . _elgg_services()->crypto->getRandomString(31);
65 65
 
66
-		if ($this->datalist->set('__site_secret__', $secret)) {
67
-			return $secret;
68
-		}
66
+        if ($this->datalist->set('__site_secret__', $secret)) {
67
+            return $secret;
68
+        }
69 69
 
70
-		return false;
71
-	}
70
+        return false;
71
+    }
72 72
 
73
-	/**
74
-	 * Returns the site secret.
75
-	 *
76
-	 * Used to generate difficult to guess hashes for sessions and action tokens.
77
-	 *
78
-	 * @param bool $raw If true, a binary key will be returned
79
-	 *
80
-	 * @return string Site secret.
81
-	 * @access private
82
-	 */
83
-	function get($raw = false) {
84
-		if ($this->test_secret) {
85
-			$secret = $this->test_secret;
86
-		} else {
87
-			$secret = $this->datalist->get('__site_secret__');
88
-		}
89
-		if (!$secret) {
90
-			$secret = $this->init();
91
-		}
73
+    /**
74
+     * Returns the site secret.
75
+     *
76
+     * Used to generate difficult to guess hashes for sessions and action tokens.
77
+     *
78
+     * @param bool $raw If true, a binary key will be returned
79
+     *
80
+     * @return string Site secret.
81
+     * @access private
82
+     */
83
+    function get($raw = false) {
84
+        if ($this->test_secret) {
85
+            $secret = $this->test_secret;
86
+        } else {
87
+            $secret = $this->datalist->get('__site_secret__');
88
+        }
89
+        if (!$secret) {
90
+            $secret = $this->init();
91
+        }
92 92
 
93
-		if ($raw) {
94
-			// try to return binary key
95
-			if ($secret[0] === 'z') {
96
-				// new keys are "z" + base64URL
97
-				$base64 = strtr(substr($secret, 1), '-_', '+/');
98
-				$key = base64_decode($base64);
99
-				if ($key !== false) {
100
-					// on failure, at least return string key :/
101
-					return $key;
102
-				}
103
-			} else {
104
-				// old keys are hex
105
-				return hex2bin($secret);
106
-			}
107
-		}
93
+        if ($raw) {
94
+            // try to return binary key
95
+            if ($secret[0] === 'z') {
96
+                // new keys are "z" + base64URL
97
+                $base64 = strtr(substr($secret, 1), '-_', '+/');
98
+                $key = base64_decode($base64);
99
+                if ($key !== false) {
100
+                    // on failure, at least return string key :/
101
+                    return $key;
102
+                }
103
+            } else {
104
+                // old keys are hex
105
+                return hex2bin($secret);
106
+            }
107
+        }
108 108
 
109
-		return $secret;
110
-	}
109
+        return $secret;
110
+    }
111 111
 
112
-	/**
113
-	 * Get the strength of the site secret
114
-	 *
115
-	 * If "weak" or "moderate" is returned, this assumes we're running on the same system that created
116
-	 * the key.
117
-	 *
118
-	 * @return string "strong", "moderate", or "weak"
119
-	 * @access private
120
-	 */
121
-	function getStrength() {
122
-		$secret = $this->get();
123
-		if ($secret[0] !== 'z') {
124
-			$rand_max = getrandmax();
125
-			if ($rand_max < pow(2, 16)) {
126
-				return 'weak';
127
-			}
128
-			if ($rand_max < pow(2, 32)) {
129
-				return 'moderate';
130
-			}
131
-		}
132
-		return 'strong';
133
-	}
112
+    /**
113
+     * Get the strength of the site secret
114
+     *
115
+     * If "weak" or "moderate" is returned, this assumes we're running on the same system that created
116
+     * the key.
117
+     *
118
+     * @return string "strong", "moderate", or "weak"
119
+     * @access private
120
+     */
121
+    function getStrength() {
122
+        $secret = $this->get();
123
+        if ($secret[0] !== 'z') {
124
+            $rand_max = getrandmax();
125
+            if ($rand_max < pow(2, 16)) {
126
+                return 'weak';
127
+            }
128
+            if ($rand_max < pow(2, 32)) {
129
+                return 'moderate';
130
+            }
131
+        }
132
+        return 'strong';
133
+    }
134 134
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -61,7 +61,7 @@
 block discarded – undo
61 61
 	 * @access private
62 62
 	 */
63 63
 	function init() {
64
-		$secret = 'z' . _elgg_services()->crypto->getRandomString(31);
64
+		$secret = 'z'._elgg_services()->crypto->getRandomString(31);
65 65
 
66 66
 		if ($this->datalist->set('__site_secret__', $secret)) {
67 67
 			return $secret;
Please login to merge, or discard this patch.
engine/classes/Elgg/Http/Request.php 3 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -105,6 +105,7 @@
 block discarded – undo
105 105
 
106 106
 	/**
107 107
 	 * {@inheritdoc}
108
+	 * @return string
108 109
 	 */
109 110
 	public function getClientIp() {
110 111
 		$ip = parent::getClientIp();
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -39,7 +39,7 @@
 block discarded – undo
39 39
 	 */
40 40
 	public function setUrlSegments(array $segments) {
41 41
 		$query = $this->query->all();
42
-		$query[Application::GET_PATH_KEY] = '/' . implode('/', $segments);
42
+		$query[Application::GET_PATH_KEY] = '/'.implode('/', $segments);
43 43
 		return $this->duplicate($query);
44 44
 	}
45 45
 
Please login to merge, or discard this patch.
Indentation   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -11,79 +11,79 @@
 block discarded – undo
11 11
  */
12 12
 class Request extends SymfonyRequest {
13 13
 
14
-	/**
15
-	 * Get the Elgg URL segments
16
-	 *
17
-	 * @param bool $raw If true, the segments will not be HTML escaped
18
-	 *
19
-	 * @return string[]
20
-	 */
21
-	public function getUrlSegments($raw = false) {
22
-		$path = trim($this->query->get(Application::GET_PATH_KEY), '/');
23
-		if (!$raw) {
24
-			$path = htmlspecialchars($path, ENT_QUOTES, 'UTF-8');
25
-		}
26
-		if (!$path) {
27
-			return array();
28
-		}
14
+    /**
15
+     * Get the Elgg URL segments
16
+     *
17
+     * @param bool $raw If true, the segments will not be HTML escaped
18
+     *
19
+     * @return string[]
20
+     */
21
+    public function getUrlSegments($raw = false) {
22
+        $path = trim($this->query->get(Application::GET_PATH_KEY), '/');
23
+        if (!$raw) {
24
+            $path = htmlspecialchars($path, ENT_QUOTES, 'UTF-8');
25
+        }
26
+        if (!$path) {
27
+            return array();
28
+        }
29 29
 
30
-		return explode('/', $path);
31
-	}
30
+        return explode('/', $path);
31
+    }
32 32
 
33
-	/**
34
-	 * Get a cloned request with new Elgg URL segments
35
-	 *
36
-	 * @param string[] $segments URL segments
37
-	 *
38
-	 * @return Request
39
-	 */
40
-	public function setUrlSegments(array $segments) {
41
-		$query = $this->query->all();
42
-		$query[Application::GET_PATH_KEY] = '/' . implode('/', $segments);
43
-		return $this->duplicate($query);
44
-	}
33
+    /**
34
+     * Get a cloned request with new Elgg URL segments
35
+     *
36
+     * @param string[] $segments URL segments
37
+     *
38
+     * @return Request
39
+     */
40
+    public function setUrlSegments(array $segments) {
41
+        $query = $this->query->all();
42
+        $query[Application::GET_PATH_KEY] = '/' . implode('/', $segments);
43
+        return $this->duplicate($query);
44
+    }
45 45
 
46
-	/**
47
-	 * Get first Elgg URL segment
48
-	 *
49
-	 * @see \Elgg\Http\Request::getUrlSegments()
50
-	 *
51
-	 * @return string
52
-	 */
53
-	public function getFirstUrlSegment() {
54
-		$segments = $this->getUrlSegments();
55
-		if ($segments) {
56
-			return array_shift($segments);
57
-		} else {
58
-			return '';
59
-		}
60
-	}
46
+    /**
47
+     * Get first Elgg URL segment
48
+     *
49
+     * @see \Elgg\Http\Request::getUrlSegments()
50
+     *
51
+     * @return string
52
+     */
53
+    public function getFirstUrlSegment() {
54
+        $segments = $this->getUrlSegments();
55
+        if ($segments) {
56
+            return array_shift($segments);
57
+        } else {
58
+            return '';
59
+        }
60
+    }
61 61
 
62
-	/**
63
-	 * {@inheritdoc}
64
-	 */
65
-	public function getClientIp() {
66
-		$ip = parent::getClientIp();
62
+    /**
63
+     * {@inheritdoc}
64
+     */
65
+    public function getClientIp() {
66
+        $ip = parent::getClientIp();
67 67
 
68
-		if ($ip == $this->server->get('REMOTE_ADDR')) {
69
-			// try one more
70
-			$ip_addresses = $this->server->get('HTTP_X_REAL_IP');
71
-			if ($ip_addresses) {
72
-				$ip_addresses = explode(',', $ip_addresses);
73
-				return array_pop($ip_addresses);
74
-			}
75
-		}
68
+        if ($ip == $this->server->get('REMOTE_ADDR')) {
69
+            // try one more
70
+            $ip_addresses = $this->server->get('HTTP_X_REAL_IP');
71
+            if ($ip_addresses) {
72
+                $ip_addresses = explode(',', $ip_addresses);
73
+                return array_pop($ip_addresses);
74
+            }
75
+        }
76 76
 
77
-		return $ip;
78
-	}
77
+        return $ip;
78
+    }
79 79
 
80
-	/**
81
-	 * {@inheritdoc}
82
-	 */
83
-	public function isXmlHttpRequest() {
84
-		return (strtolower($this->headers->get('X-Requested-With')) === 'xmlhttprequest'
85
-			|| $this->query->get('X-Requested-With') === 'XMLHttpRequest'
86
-			|| $this->request->get('X-Requested-With') === 'XMLHttpRequest');
87
-		// GET/POST check is necessary for jQuery.form and other iframe-based "ajax". #8735
88
-	}
80
+    /**
81
+     * {@inheritdoc}
82
+     */
83
+    public function isXmlHttpRequest() {
84
+        return (strtolower($this->headers->get('X-Requested-With')) === 'xmlhttprequest'
85
+            || $this->query->get('X-Requested-With') === 'XMLHttpRequest'
86
+            || $this->request->get('X-Requested-With') === 'XMLHttpRequest');
87
+        // GET/POST check is necessary for jQuery.form and other iframe-based "ajax". #8735
88
+    }
89 89
 }
Please login to merge, or discard this patch.
engine/classes/Elgg/Notifications/NotificationsService.php 3 patches
Doc Comments   +6 added lines patch added patch discarded remove patch
@@ -59,6 +59,8 @@  discard block
 block discarded – undo
59 59
 	/**
60 60
 	 * @see elgg_register_notification_event()
61 61
 	 * @access private
62
+	 * @param string $type
63
+	 * @param string $subtype
62 64
 	 */
63 65
 	public function registerEvent($type, $subtype, array $actions = array()) {
64 66
 
@@ -80,6 +82,8 @@  discard block
 block discarded – undo
80 82
 	/**
81 83
 	 * @see elgg_unregister_notification_event()
82 84
 	 * @access private
85
+	 * @param string $type
86
+	 * @param string $subtype
83 87
 	 */
84 88
 	public function unregisterEvent($type, $subtype) {
85 89
 
@@ -102,6 +106,7 @@  discard block
 block discarded – undo
102 106
 	/**
103 107
 	 * @see elgg_register_notification_method()
104 108
 	 * @access private
109
+	 * @param string $name
105 110
 	 */
106 111
 	public function registerMethod($name) {
107 112
 		$this->methods[$name] = $name;
@@ -110,6 +115,7 @@  discard block
 block discarded – undo
110 115
 	/**
111 116
 	 * @see elgg_unregister_notification_method()
112 117
 	 * @access private
118
+	 * @param string $name
113 119
 	 */
114 120
 	public function unregisterMethod($name) {
115 121
 		if (isset($this->methods[$name])) {
Please login to merge, or discard this patch.
Indentation   +720 added lines, -720 removed lines patch added patch discarded remove patch
@@ -25,746 +25,746 @@
 block discarded – undo
25 25
  */
26 26
 class NotificationsService {
27 27
 
28
-	const QUEUE_NAME = 'notifications';
28
+    const QUEUE_NAME = 'notifications';
29 29
 
30
-	/** @var SubscriptionsService */
31
-	protected $subscriptions;
30
+    /** @var SubscriptionsService */
31
+    protected $subscriptions;
32 32
 
33
-	/** @var Queue */
34
-	protected $queue;
33
+    /** @var Queue */
34
+    protected $queue;
35 35
 
36
-	/** @var PluginHooksService */
37
-	protected $hooks;
36
+    /** @var PluginHooksService */
37
+    protected $hooks;
38 38
 
39
-	/** @var ElggSession */
40
-	protected $session;
39
+    /** @var ElggSession */
40
+    protected $session;
41 41
 
42
-	/** @var Translator */
43
-	protected $translator;
42
+    /** @var Translator */
43
+    protected $translator;
44 44
 
45
-	/** @var EntityTable */
46
-	protected $entities;
45
+    /** @var EntityTable */
46
+    protected $entities;
47 47
 
48
-	/** @var Logger */
49
-	protected $logger;
48
+    /** @var Logger */
49
+    protected $logger;
50 50
 	
51
-	/** @var array Registered notification events */
52
-	protected $events = array();
53
-
54
-	/** @var array Registered notification methods */
55
-	protected $methods = array();
56
-
57
-	/** @var array Deprecated notification handlers */
58
-	protected $deprHandlers = array();
59
-
60
-	/** @var array Deprecated message subjects */
61
-	protected $deprSubjects = array();
62
-
63
-	/**
64
-	 * Constructor
65
-	 *
66
-	 * @param SubscriptionsService $subscriptions Subscription service
67
-	 * @param Queue                $queue         Queue
68
-	 * @param PluginHooksService   $hooks         Plugin hook service
69
-	 * @param ElggSession          $session       Session service
70
-	 * @param Translator           $translator    Translator
71
-	 * @param EntityTable          $entities      Entity table
72
-	 * @param Logger               $logger        Logger
73
-	 */
74
-	public function __construct(
75
-			SubscriptionsService $subscriptions,
76
-			Queue $queue, PluginHooksService $hooks,
77
-			ElggSession $session,
78
-			Translator $translator,
79
-			EntityTable $entities,
80
-			Logger $logger) {
81
-
82
-		$this->subscriptions = $subscriptions;
83
-		$this->queue = $queue;
84
-		$this->hooks = $hooks;
85
-		$this->session = $session;
86
-		$this->translator = $translator;
87
-		$this->entities = $entities;
88
-		$this->logger = $logger;
89
-	}
90
-
91
-	/**
92
-	 * @see elgg_register_notification_event()
93
-	 * @access private
94
-	 */
95
-	public function registerEvent($type, $subtype, array $actions = array()) {
96
-
97
-		if (!isset($this->events[$type])) {
98
-			$this->events[$type] = array();
99
-		}
100
-		if (!isset($this->events[$type][$subtype])) {
101
-			$this->events[$type][$subtype] = array();
102
-		}
103
-
104
-		$action_list =& $this->events[$type][$subtype];
105
-		if ($actions) {
106
-			$action_list = array_unique(array_merge($action_list, $actions));
107
-		} elseif (!in_array('create', $action_list)) {
108
-			$action_list[] = 'create';
109
-		}
110
-	}
111
-
112
-	/**
113
-	 * @see elgg_unregister_notification_event()
114
-	 * @access private
115
-	 */
116
-	public function unregisterEvent($type, $subtype) {
117
-
118
-		if (!isset($this->events[$type]) || !isset($this->events[$type][$subtype])) {
119
-			return false;
120
-		}
121
-
122
-		unset($this->events[$type][$subtype]);
123
-
124
-		return true;
125
-	}
126
-
127
-	/**
128
-	 * @access private
129
-	 */
130
-	public function getEvents() {
131
-		return $this->events;
132
-	}
133
-
134
-	/**
135
-	 * @see elgg_register_notification_method()
136
-	 * @access private
137
-	 */
138
-	public function registerMethod($name) {
139
-		$this->methods[$name] = $name;
140
-	}
141
-
142
-	/**
143
-	 * @see elgg_unregister_notification_method()
144
-	 * @access private
145
-	 */
146
-	public function unregisterMethod($name) {
147
-		if (isset($this->methods[$name])) {
148
-			unset($this->methods[$name]);
149
-			return true;
150
-		}
151
-		return false;
152
-	}
153
-
154
-	/**
155
-	 * @access private
156
-	 */
157
-	public function getMethods() {
158
-		return $this->methods;
159
-	}
160
-
161
-	/**
162
-	 * Add a notification event to the queue
163
-	 *
164
-	 * @param string   $action Action name
165
-	 * @param string   $type   Type of the object of the action
166
-	 * @param ElggData $object The object of the action
167
-	 * @return void
168
-	 * @access private
169
-	 */
170
-	public function enqueueEvent($action, $type, $object) {
51
+    /** @var array Registered notification events */
52
+    protected $events = array();
53
+
54
+    /** @var array Registered notification methods */
55
+    protected $methods = array();
56
+
57
+    /** @var array Deprecated notification handlers */
58
+    protected $deprHandlers = array();
59
+
60
+    /** @var array Deprecated message subjects */
61
+    protected $deprSubjects = array();
62
+
63
+    /**
64
+     * Constructor
65
+     *
66
+     * @param SubscriptionsService $subscriptions Subscription service
67
+     * @param Queue                $queue         Queue
68
+     * @param PluginHooksService   $hooks         Plugin hook service
69
+     * @param ElggSession          $session       Session service
70
+     * @param Translator           $translator    Translator
71
+     * @param EntityTable          $entities      Entity table
72
+     * @param Logger               $logger        Logger
73
+     */
74
+    public function __construct(
75
+            SubscriptionsService $subscriptions,
76
+            Queue $queue, PluginHooksService $hooks,
77
+            ElggSession $session,
78
+            Translator $translator,
79
+            EntityTable $entities,
80
+            Logger $logger) {
81
+
82
+        $this->subscriptions = $subscriptions;
83
+        $this->queue = $queue;
84
+        $this->hooks = $hooks;
85
+        $this->session = $session;
86
+        $this->translator = $translator;
87
+        $this->entities = $entities;
88
+        $this->logger = $logger;
89
+    }
90
+
91
+    /**
92
+     * @see elgg_register_notification_event()
93
+     * @access private
94
+     */
95
+    public function registerEvent($type, $subtype, array $actions = array()) {
96
+
97
+        if (!isset($this->events[$type])) {
98
+            $this->events[$type] = array();
99
+        }
100
+        if (!isset($this->events[$type][$subtype])) {
101
+            $this->events[$type][$subtype] = array();
102
+        }
103
+
104
+        $action_list =& $this->events[$type][$subtype];
105
+        if ($actions) {
106
+            $action_list = array_unique(array_merge($action_list, $actions));
107
+        } elseif (!in_array('create', $action_list)) {
108
+            $action_list[] = 'create';
109
+        }
110
+    }
111
+
112
+    /**
113
+     * @see elgg_unregister_notification_event()
114
+     * @access private
115
+     */
116
+    public function unregisterEvent($type, $subtype) {
117
+
118
+        if (!isset($this->events[$type]) || !isset($this->events[$type][$subtype])) {
119
+            return false;
120
+        }
121
+
122
+        unset($this->events[$type][$subtype]);
123
+
124
+        return true;
125
+    }
126
+
127
+    /**
128
+     * @access private
129
+     */
130
+    public function getEvents() {
131
+        return $this->events;
132
+    }
133
+
134
+    /**
135
+     * @see elgg_register_notification_method()
136
+     * @access private
137
+     */
138
+    public function registerMethod($name) {
139
+        $this->methods[$name] = $name;
140
+    }
141
+
142
+    /**
143
+     * @see elgg_unregister_notification_method()
144
+     * @access private
145
+     */
146
+    public function unregisterMethod($name) {
147
+        if (isset($this->methods[$name])) {
148
+            unset($this->methods[$name]);
149
+            return true;
150
+        }
151
+        return false;
152
+    }
153
+
154
+    /**
155
+     * @access private
156
+     */
157
+    public function getMethods() {
158
+        return $this->methods;
159
+    }
160
+
161
+    /**
162
+     * Add a notification event to the queue
163
+     *
164
+     * @param string   $action Action name
165
+     * @param string   $type   Type of the object of the action
166
+     * @param ElggData $object The object of the action
167
+     * @return void
168
+     * @access private
169
+     */
170
+    public function enqueueEvent($action, $type, $object) {
171 171
 		
172
-		if ($object instanceof ElggData) {
173
-			$object_type = $object->getType();
174
-			$object_subtype = $object->getSubtype();
175
-
176
-			$registered = false;
177
-			if (!empty($this->events[$object_type][$object_subtype]) && in_array($action, $this->events[$object_type][$object_subtype])) {
178
-				$registered = true;
179
-			}
180
-
181
-			if ($registered) {
182
-				$params = array(
183
-					'action' => $action,
184
-					'object' => $object,
185
-				);
186
-				$registered = $this->hooks->trigger('enqueue', 'notification', $params, $registered);
187
-			}
188
-
189
-			if ($registered) {
190
-				$this->queue->enqueue(new SubscriptionNotificationEvent($object, $action));
191
-			}
192
-		}
193
-	}
194
-
195
-	/**
196
-	 * Pull notification events from queue until stop time is reached
197
-	 *
198
-	 * @param int  $stopTime The Unix time to stop sending notifications
199
-	 * @param bool $matrix   If true, will return delivery matrix instead of a notifications event count
200
-	 * @return int|array The number of notification events handled, or a delivery matrix
201
-	 * @access private
202
-	 */
203
-	public function processQueue($stopTime, $matrix = false) {
204
-
205
-		$this->subscriptions->methods = $this->methods;
206
-
207
-		$delivery_matrix = [];
208
-
209
-		$count = 0;
210
-
211
-		// @todo grab mutex
212
-
213
-		$ia = $this->session->setIgnoreAccess(true);
214
-
215
-		while (time() < $stopTime) {
216
-			// dequeue notification event
217
-			$event = $this->queue->dequeue();
218
-			/* @var $event NotificationEvent */
219
-
220
-			if (!$event) {
221
-				// queue is empty
222
-				break;
223
-			}
224
-
225
-			if (!$event instanceof NotificationEvent || !$event->getObject() || !$event->getActor()) {
226
-				// event object or actor have been deleted since the event was enqueued
227
-				continue;
228
-			}
172
+        if ($object instanceof ElggData) {
173
+            $object_type = $object->getType();
174
+            $object_subtype = $object->getSubtype();
175
+
176
+            $registered = false;
177
+            if (!empty($this->events[$object_type][$object_subtype]) && in_array($action, $this->events[$object_type][$object_subtype])) {
178
+                $registered = true;
179
+            }
180
+
181
+            if ($registered) {
182
+                $params = array(
183
+                    'action' => $action,
184
+                    'object' => $object,
185
+                );
186
+                $registered = $this->hooks->trigger('enqueue', 'notification', $params, $registered);
187
+            }
188
+
189
+            if ($registered) {
190
+                $this->queue->enqueue(new SubscriptionNotificationEvent($object, $action));
191
+            }
192
+        }
193
+    }
194
+
195
+    /**
196
+     * Pull notification events from queue until stop time is reached
197
+     *
198
+     * @param int  $stopTime The Unix time to stop sending notifications
199
+     * @param bool $matrix   If true, will return delivery matrix instead of a notifications event count
200
+     * @return int|array The number of notification events handled, or a delivery matrix
201
+     * @access private
202
+     */
203
+    public function processQueue($stopTime, $matrix = false) {
204
+
205
+        $this->subscriptions->methods = $this->methods;
206
+
207
+        $delivery_matrix = [];
208
+
209
+        $count = 0;
210
+
211
+        // @todo grab mutex
212
+
213
+        $ia = $this->session->setIgnoreAccess(true);
214
+
215
+        while (time() < $stopTime) {
216
+            // dequeue notification event
217
+            $event = $this->queue->dequeue();
218
+            /* @var $event NotificationEvent */
219
+
220
+            if (!$event) {
221
+                // queue is empty
222
+                break;
223
+            }
224
+
225
+            if (!$event instanceof NotificationEvent || !$event->getObject() || !$event->getActor()) {
226
+                // event object or actor have been deleted since the event was enqueued
227
+                continue;
228
+            }
229 229
 		
230
-			// test for usage of the deprecated override hook
231
-			if ($this->existsDeprecatedNotificationOverride($event)) {
232
-				continue;
233
-			}
230
+            // test for usage of the deprecated override hook
231
+            if ($this->existsDeprecatedNotificationOverride($event)) {
232
+                continue;
233
+            }
234 234
 
235
-			$subscriptions = $this->subscriptions->getSubscriptions($event);
235
+            $subscriptions = $this->subscriptions->getSubscriptions($event);
236 236
 			
237
-			// return false to stop the default notification sender
238
-			$params = [
239
-				'event' => $event,
240
-				'subscriptions' => $subscriptions
241
-			];
237
+            // return false to stop the default notification sender
238
+            $params = [
239
+                'event' => $event,
240
+                'subscriptions' => $subscriptions
241
+            ];
242 242
 			
243
-			$deliveries = [];
244
-			if ($this->hooks->trigger('send:before', 'notifications', $params, true)) {
245
-				$deliveries = $this->sendNotifications($event, $subscriptions);
246
-			}
247
-			$params['deliveries'] = $deliveries;
248
-			$this->hooks->trigger('send:after', 'notifications', $params);
249
-			$count++;
250
-
251
-			$delivery_matrix[$event->getDescription()] = $deliveries;
252
-		}
253
-
254
-		// release mutex
255
-
256
-		$this->session->setIgnoreAccess($ia);
257
-
258
-		return $matrix ? $delivery_matrix : $count;
259
-	}
260
-
261
-	/**
262
-	 * Sends the notifications based on subscriptions
263
-	 *
264
-	 * Returns an array in the form:
265
-	 * <code>
266
-	 * [
267
-	 *    25 => [
268
-	 *      'email' => true,
269
-	 *      'sms' => false,
270
-	 *    ],
271
-	 *    55 => [],
272
-	 * ]
273
-	 * </code>
274
-	 *
275
-	 * @param NotificationEvent $event         Notification event
276
-	 * @param array             $subscriptions Subscriptions for this event
277
-	 * @param array             $params        Default notification parameters
278
-	 * @return array
279
-	 * @access private
280
-	 */
281
-	protected function sendNotifications($event, $subscriptions, array $params = []) {
282
-
283
-		if (!$this->methods) {
284
-			return 0;
285
-		}
286
-
287
-		$result = [];
288
-		foreach ($subscriptions as $guid => $methods) {
289
-			foreach ($methods as $method) {
290
-				$result[$guid][$method] = false;
291
-				if (in_array($method, $this->methods)) {
292
-					$result[$guid][$method] = $this->sendNotification($event, $guid, $method, $params);
293
-				}
294
-			}
295
-		}
296
-
297
-		$this->logger->notice("Results for the notification event {$event->getDescription()}: " . print_r($result, true));
298
-		return $result;
299
-	}
300
-
301
-	/**
302
-	 * Notify a user via their preferences.
303
-	 *
304
-	 * Returns an array in the form:
305
-	 * <code>
306
-	 * [
307
-	 *    25 => [
308
-	 *      'email' => true,
309
-	 *      'sms' => false,
310
-	 *    ],
311
-	 *    55 => [],
312
-	 * ]
313
-	 * </code>
314
-	 *
315
-	 * @param ElggEntity  $sender     Sender of the notification
316
-	 * @param ElggUser[]  $recipients An array of entities to notify
317
-	 * @param array       $params     Notification parameters
318
-	 * 
319
-	 * @uses $params['subject']          string
320
-	 *                                   Default message subject
321
-	 * @uses $params['body']             string
322
-	 *                                   Default message body
323
-	 * @uses $params['object']           null|\ElggEntity|\ElggAnnotation
324
-	 *                                   The object that is triggering the notification.
325
-	 * @uses $params['action']           null|string
326
-	 *                                   Word that describes the action that is triggering the notification
327
-	 *                                  (e.g. "create" or "update"). Defaults to "notify_user"
328
-	 * @uses $params['summary']          null|string
329
-	 *                                   Summary that notification plugins can use alongside the notification title and body.
330
-	 * @uses $params['methods_override'] string|array
331
-	 *                                   A string, or an array of strings specifying the delivery
332
-	 *                                   methods to use - or leave blank for delivery using the
333
-	 *                                   user's chosen delivery methods.
334
-	 *
335
-	 * @return array
336
-	 * @access private
337
-	 */
338
-	public function sendInstantNotifications(\ElggEntity $sender, array $recipients = [], array $params = []) {
339
-
340
-		if (!$sender instanceof \ElggEntity) {
341
-			throw new InvalidArgumentException("Notification sender must be a valid entity");
342
-		}
243
+            $deliveries = [];
244
+            if ($this->hooks->trigger('send:before', 'notifications', $params, true)) {
245
+                $deliveries = $this->sendNotifications($event, $subscriptions);
246
+            }
247
+            $params['deliveries'] = $deliveries;
248
+            $this->hooks->trigger('send:after', 'notifications', $params);
249
+            $count++;
250
+
251
+            $delivery_matrix[$event->getDescription()] = $deliveries;
252
+        }
253
+
254
+        // release mutex
255
+
256
+        $this->session->setIgnoreAccess($ia);
257
+
258
+        return $matrix ? $delivery_matrix : $count;
259
+    }
260
+
261
+    /**
262
+     * Sends the notifications based on subscriptions
263
+     *
264
+     * Returns an array in the form:
265
+     * <code>
266
+     * [
267
+     *    25 => [
268
+     *      'email' => true,
269
+     *      'sms' => false,
270
+     *    ],
271
+     *    55 => [],
272
+     * ]
273
+     * </code>
274
+     *
275
+     * @param NotificationEvent $event         Notification event
276
+     * @param array             $subscriptions Subscriptions for this event
277
+     * @param array             $params        Default notification parameters
278
+     * @return array
279
+     * @access private
280
+     */
281
+    protected function sendNotifications($event, $subscriptions, array $params = []) {
282
+
283
+        if (!$this->methods) {
284
+            return 0;
285
+        }
286
+
287
+        $result = [];
288
+        foreach ($subscriptions as $guid => $methods) {
289
+            foreach ($methods as $method) {
290
+                $result[$guid][$method] = false;
291
+                if (in_array($method, $this->methods)) {
292
+                    $result[$guid][$method] = $this->sendNotification($event, $guid, $method, $params);
293
+                }
294
+            }
295
+        }
296
+
297
+        $this->logger->notice("Results for the notification event {$event->getDescription()}: " . print_r($result, true));
298
+        return $result;
299
+    }
300
+
301
+    /**
302
+     * Notify a user via their preferences.
303
+     *
304
+     * Returns an array in the form:
305
+     * <code>
306
+     * [
307
+     *    25 => [
308
+     *      'email' => true,
309
+     *      'sms' => false,
310
+     *    ],
311
+     *    55 => [],
312
+     * ]
313
+     * </code>
314
+     *
315
+     * @param ElggEntity  $sender     Sender of the notification
316
+     * @param ElggUser[]  $recipients An array of entities to notify
317
+     * @param array       $params     Notification parameters
318
+     * 
319
+     * @uses $params['subject']          string
320
+     *                                   Default message subject
321
+     * @uses $params['body']             string
322
+     *                                   Default message body
323
+     * @uses $params['object']           null|\ElggEntity|\ElggAnnotation
324
+     *                                   The object that is triggering the notification.
325
+     * @uses $params['action']           null|string
326
+     *                                   Word that describes the action that is triggering the notification
327
+     *                                  (e.g. "create" or "update"). Defaults to "notify_user"
328
+     * @uses $params['summary']          null|string
329
+     *                                   Summary that notification plugins can use alongside the notification title and body.
330
+     * @uses $params['methods_override'] string|array
331
+     *                                   A string, or an array of strings specifying the delivery
332
+     *                                   methods to use - or leave blank for delivery using the
333
+     *                                   user's chosen delivery methods.
334
+     *
335
+     * @return array
336
+     * @access private
337
+     */
338
+    public function sendInstantNotifications(\ElggEntity $sender, array $recipients = [], array $params = []) {
339
+
340
+        if (!$sender instanceof \ElggEntity) {
341
+            throw new InvalidArgumentException("Notification sender must be a valid entity");
342
+        }
343 343
 		
344
-		$deliveries = [];
344
+        $deliveries = [];
345 345
 
346
-		if (!$this->methods) {
347
-			return $deliveries;
348
-		}
346
+        if (!$this->methods) {
347
+            return $deliveries;
348
+        }
349 349
 		
350
-		$recipients = array_filter($recipients, function($e) {
351
-			return ($e instanceof \ElggUser);
352
-		});
350
+        $recipients = array_filter($recipients, function($e) {
351
+            return ($e instanceof \ElggUser);
352
+        });
353 353
 		
354
-		$object = elgg_extract('object', $params);
355
-		$action = elgg_extract('action', $params);
356
-
357
-		$methods_override = elgg_extract('methods_override', $params);
358
-		unset($params['methods_override']);
359
-		if ($methods_override && !is_array($methods_override)) {
360
-			$methods_override = [$methods_override];
361
-		}
362
-
363
-		$event = new InstantNotificationEvent($object, $action, $sender);
364
-
365
-		$params['event'] = $event;
366
-		$params['origin'] = Notification::ORIGIN_INSTANT;
367
-
368
-		$subscriptions = [];
369
-
370
-		foreach ($recipients as $recipient) {
371
-
372
-			// Are we overriding delivery?
373
-			$methods = $methods_override;
374
-			if (empty($methods)) {
375
-				$methods = [];
376
-				$user_settings = $recipient->getNotificationSettings();
377
-				foreach ($user_settings as $method => $enabled) {
378
-					if ($enabled) {
379
-						$methods[] = $method;
380
-					}
381
-				}
382
-			}
383
-
384
-			$subscriptions[$recipient->guid] = $methods;
385
-		}
386
-
387
-		$hook_params = [
388
-			'event' => $params['event'],
389
-			'origin' => $params['origin'],
390
-			'methods_override' => $methods_override,
391
-		];
392
-		$subscriptions = $this->hooks->trigger('get', 'subscriptions', $hook_params, $subscriptions);
354
+        $object = elgg_extract('object', $params);
355
+        $action = elgg_extract('action', $params);
356
+
357
+        $methods_override = elgg_extract('methods_override', $params);
358
+        unset($params['methods_override']);
359
+        if ($methods_override && !is_array($methods_override)) {
360
+            $methods_override = [$methods_override];
361
+        }
362
+
363
+        $event = new InstantNotificationEvent($object, $action, $sender);
364
+
365
+        $params['event'] = $event;
366
+        $params['origin'] = Notification::ORIGIN_INSTANT;
367
+
368
+        $subscriptions = [];
369
+
370
+        foreach ($recipients as $recipient) {
371
+
372
+            // Are we overriding delivery?
373
+            $methods = $methods_override;
374
+            if (empty($methods)) {
375
+                $methods = [];
376
+                $user_settings = $recipient->getNotificationSettings();
377
+                foreach ($user_settings as $method => $enabled) {
378
+                    if ($enabled) {
379
+                        $methods[] = $method;
380
+                    }
381
+                }
382
+            }
383
+
384
+            $subscriptions[$recipient->guid] = $methods;
385
+        }
386
+
387
+        $hook_params = [
388
+            'event' => $params['event'],
389
+            'origin' => $params['origin'],
390
+            'methods_override' => $methods_override,
391
+        ];
392
+        $subscriptions = $this->hooks->trigger('get', 'subscriptions', $hook_params, $subscriptions);
393 393
 		
394
-		$params['subscriptions'] = $subscriptions;
395
-
396
-		// return false to stop the default notification sender
397
-		if ($this->hooks->trigger('send:before', 'notifications', $params, true)) {
398
-			$deliveries = $this->sendNotifications($event, $subscriptions, $params);
399
-		}
400
-		$params['deliveries'] = $deliveries;
401
-		$this->hooks->trigger('send:after', 'notifications', $params);
402
-
403
-		return $deliveries;
404
-	}
405
-
406
-	/**
407
-	 * Send a notification to a subscriber
408
-	 *
409
-	 * @param NotificationEvent $event  The notification event
410
-	 * @param int               $guid   The guid of the subscriber
411
-	 * @param string            $method The notification method
412
-	 * @param array             $params Default notification params
413
-	 * @return bool
414
-	 * @access private
415
-	 */
416
-	protected function sendNotification(NotificationEvent $event, $guid, $method, array $params = []) {
417
-
418
-		$actor = $event->getActor();
419
-		$object = $event->getObject();
420
-
421
-		if ($event instanceof InstantNotificationEvent) {
422
-			$recipient = $this->entities->get($guid);
423
-			/* @var \ElggEntity $recipient */
424
-			$subject = elgg_extract('subject', $params, '');
425
-			$body = elgg_extract('body', $params, '');
426
-			$summary = elgg_extract('summary', $params, '');
427
-		} else {
428
-			$recipient = $this->entities->get($guid, 'user');
429
-			/* @var \ElggUser $recipient */
430
-			if (!$recipient || $recipient->isBanned()) {
431
-				return false;
432
-			}
394
+        $params['subscriptions'] = $subscriptions;
395
+
396
+        // return false to stop the default notification sender
397
+        if ($this->hooks->trigger('send:before', 'notifications', $params, true)) {
398
+            $deliveries = $this->sendNotifications($event, $subscriptions, $params);
399
+        }
400
+        $params['deliveries'] = $deliveries;
401
+        $this->hooks->trigger('send:after', 'notifications', $params);
402
+
403
+        return $deliveries;
404
+    }
405
+
406
+    /**
407
+     * Send a notification to a subscriber
408
+     *
409
+     * @param NotificationEvent $event  The notification event
410
+     * @param int               $guid   The guid of the subscriber
411
+     * @param string            $method The notification method
412
+     * @param array             $params Default notification params
413
+     * @return bool
414
+     * @access private
415
+     */
416
+    protected function sendNotification(NotificationEvent $event, $guid, $method, array $params = []) {
417
+
418
+        $actor = $event->getActor();
419
+        $object = $event->getObject();
420
+
421
+        if ($event instanceof InstantNotificationEvent) {
422
+            $recipient = $this->entities->get($guid);
423
+            /* @var \ElggEntity $recipient */
424
+            $subject = elgg_extract('subject', $params, '');
425
+            $body = elgg_extract('body', $params, '');
426
+            $summary = elgg_extract('summary', $params, '');
427
+        } else {
428
+            $recipient = $this->entities->get($guid, 'user');
429
+            /* @var \ElggUser $recipient */
430
+            if (!$recipient || $recipient->isBanned()) {
431
+                return false;
432
+            }
433 433
 		
434
-			if ($recipient->getGUID() == $event->getActorGUID()) {
435
-				// Content creators should not be receiving subscription
436
-				// notifications about their own content
437
-				return false;
438
-			}
434
+            if ($recipient->getGUID() == $event->getActorGUID()) {
435
+                // Content creators should not be receiving subscription
436
+                // notifications about their own content
437
+                return false;
438
+            }
439 439
 			
440
-			if (!$actor || !$object) {
441
-				return false;
442
-			}
443
-
444
-			if ($object instanceof ElggEntity && !has_access_to_entity($object, $recipient)) {
445
-				// Recipient does not have access to the notification object
446
-				// The access level may have changed since the event was enqueued
447
-				return false;
448
-			}
449
-
450
-			$subject = $this->getNotificationSubject($event, $recipient);
451
-			$body = $this->getNotificationBody($event, $recipient);
452
-			$summary = '';
440
+            if (!$actor || !$object) {
441
+                return false;
442
+            }
443
+
444
+            if ($object instanceof ElggEntity && !has_access_to_entity($object, $recipient)) {
445
+                // Recipient does not have access to the notification object
446
+                // The access level may have changed since the event was enqueued
447
+                return false;
448
+            }
449
+
450
+            $subject = $this->getNotificationSubject($event, $recipient);
451
+            $body = $this->getNotificationBody($event, $recipient);
452
+            $summary = '';
453 453
 			
454
-			$params['origin'] = Notification::ORIGIN_SUBSCRIPTIONS;
455
-		}
456
-
457
-		$language = $recipient->language;
458
-		$params['event'] = $event;
459
-		$params['method'] = $method;
460
-		$params['sender'] = $actor;
461
-		$params['recipient'] = $recipient;
462
-		$params['language'] = $language;
463
-		$params['object'] = $object;
464
-		$params['action'] = $event->getAction();
465
-
466
-		$notification = new Notification($actor, $recipient, $language, $subject, $body, $summary, $params);
467
-
468
-		$notification = $this->hooks->trigger('prepare', 'notification', $params, $notification);
469
-		if (!$notification instanceof Notification) {
470
-			throw new RuntimeException("'prepare','notification' hook must return an instance of " . Notification::class);
471
-		}
472
-
473
-		$type = 'notification:' . $event->getDescription();
474
-		if ($this->hooks->hasHandler('prepare', $type)) {
475
-			$notification = $this->hooks->trigger('prepare', $type, $params, $notification);
476
-			if (!$notification instanceof Notification) {
477
-				throw new RuntimeException("'prepare','$type' hook must return an instance of " . Notification::class);
478
-			}
479
-		} else {
480
-			// pre Elgg 1.9 notification message generation
481
-			$notification = $this->getDeprecatedNotificationBody($notification, $event, $method);
482
-		}
483
-
484
-		$notification = $this->hooks->trigger('format', "notification:$method", [], $notification);
485
-		if (!$notification instanceof Notification) {
486
-			throw new RuntimeException("'format','notification:$method' hook must return an instance of " . Notification::class);
487
-		}
488
-
489
-		if ($this->hooks->hasHandler('send', "notification:$method")) {
490
-			// return true to indicate the notification has been sent
491
-			$params = array(
492
-				'notification' => $notification,
493
-				'event' => $event,
494
-			);
495
-
496
-			$result = $this->hooks->trigger('send', "notification:$method", $params, false);
497
-			if ($this->logger->getLevel() == Logger::INFO) {
498
-				$logger_data = print_r((array) $notification->toObject(), true);
499
-				if ($result) {
500
-					$this->logger->info("Notification sent: " . $logger_data);
501
-				} else {
502
-					$this->logger->info("Notification was not sent: " . $logger_data);
503
-				}
504
-			}
505
-			return $result;
506
-		} else {
507
-			// pre Elgg 1.9 notification handler
508
-			$userGuid = $notification->getRecipientGUID();
509
-			$senderGuid = $notification->getSenderGUID();
510
-			$subject = $notification->subject;
511
-			$body = $notification->body;
512
-			$params = $notification->params;
513
-			return (bool) _elgg_notify_user($userGuid, $senderGuid, $subject, $body, $params, array($method));
514
-		}
515
-	}
516
-
517
-	/**
518
-	 * Get subject for the notification
519
-	 *
520
-	 * Plugins can define a subtype specific subject simply by providing a
521
-	 * translation for the string "notification:subject:<action>:<type>:<subtype".
522
-	 *
523
-	 * For example in mod/blog/languages/en.php:
524
-	 *
525
-	 *     'notification:subject:publish:object:blog' => '%s published a blog called %s'
526
-	 *
527
-	 * @param NotificationEvent $event     Notification event
528
-	 * @param ElggUser          $recipient Notification recipient
529
-	 * @return string Notification subject in the recipient's language
530
-	 */
531
-	private function getNotificationSubject(NotificationEvent $event, ElggUser $recipient) {
532
-		$actor = $event->getActor();
533
-		$object = $event->getObject();
534
-		/* @var \ElggObject $object */
535
-		$language = $recipient->language;
536
-
537
-		// Check custom notification subject for the action/type/subtype combination
538
-		$subject_key = "notification:{$event->getDescription()}:subject";
539
-		if ($this->translator->languageKeyExists($subject_key, $language)) {
540
-			if ($object instanceof \ElggEntity) {
541
-				$display_name = $object->getDisplayName();
542
-			} else {
543
-				$display_name = '';
544
-			}
545
-			return $this->translator->translate($subject_key, array(
546
-						$actor->name,
547
-						$display_name,
548
-							), $language);
549
-		}
550
-
551
-		// Fall back to default subject
552
-		return $this->translator->translate('notification:subject', array($actor->name), $language);
553
-	}
554
-
555
-	/**
556
-	 * Get body for the notification
557
-	 *
558
-	 * Plugin can define a subtype specific body simply by providing a
559
-	 * translation for the string "notification:body:<action>:<type>:<subtype".
560
-	 *
561
-	 * For example in mod/blog/languages/en.php:
562
-	 *
563
-	 *    'notification:body:publish:object:blog' => '
564
-	 *         Hi %s!
565
-	 *
566
-	 *         %s has created a new post called "%s" in the group %s.
567
-	 *
568
-	 *         It says:
569
-	 *
570
-	 *         "%s"
571
-	 *
572
-	 *         You can comment the post here:
573
-	 *         %s
574
-	 *     ',
575
-	 *
576
-	 * The arguments passed into the translation are:
577
-	 *     1. Recipient's name
578
-	 *     2. Name of the user who triggered the notification
579
-	 *     3. Title of the content
580
-	 *     4. Name of the content's container
581
-	 *     5. The actual content (entity's 'description' field)
582
-	 *     6. URL to the content
583
-	 *
584
-	 * Argument swapping can be used to change the order of the parameters.
585
-	 * See http://php.net/manual/en/function.sprintf.php#example-5427
586
-	 *
587
-	 * @param NotificationEvent $event     Notification event
588
-	 * @param ElggUser          $recipient Notification recipient
589
-	 * @return string Notification body in the recipient's language
590
-	 */
591
-	private function getNotificationBody(NotificationEvent $event, ElggUser $recipient) {
592
-		$actor = $event->getActor();
593
-		$object = $event->getObject();
594
-		/* @var \ElggObject $object */
595
-		$language = $recipient->language;
596
-
597
-		// Check custom notification body for the action/type/subtype combination
598
-		$body_key = "notification:{$event->getDescription()}:body";
599
-		if ($this->translator->languageKeyExists($body_key, $language)) {
600
-			if ($object instanceof \ElggEntity) {
601
-				$display_name = $object->getDisplayName();
602
-				$container_name = '';
603
-				$container = $object->getContainerEntity();
604
-				if ($container) {
605
-					$container_name = $container->getDisplayName();
606
-				}
607
-			} else {
608
-				$display_name = '';
609
-				$container_name = '';
610
-			}
611
-
612
-			return $this->translator->translate($body_key, array(
613
-						$recipient->name,
614
-						$actor->name,
615
-						$display_name,
616
-						$container_name,
617
-						$object->description,
618
-						$object->getURL(),
619
-							), $language);
620
-		}
621
-
622
-		// Fall back to default body
623
-		return $this->translator->translate('notification:body', array($object->getURL()), $language);
624
-	}
625
-
626
-	/**
627
-	 * Register a deprecated notification handler
628
-	 *
629
-	 * @param string $method  Method name
630
-	 * @param string $handler Handler callback
631
-	 * @return void
632
-	 */
633
-	public function registerDeprecatedHandler($method, $handler) {
634
-		$this->deprHandlers[$method] = $handler;
635
-	}
636
-
637
-	/**
638
-	 * Get a deprecated notification handler callback
639
-	 *
640
-	 * @param string $method Method name
641
-	 * @return callback|null
642
-	 */
643
-	public function getDeprecatedHandler($method) {
644
-		if (isset($this->deprHandlers[$method])) {
645
-			return $this->deprHandlers[$method];
646
-		} else {
647
-			return null;
648
-		}
649
-	}
650
-
651
-	/**
652
-	 * Provides a way to incrementally wean Elgg's notifications code from the
653
-	 * global $NOTIFICATION_HANDLERS
654
-	 *
655
-	 * @return array
656
-	 */
657
-	public function getMethodsAsDeprecatedGlobal() {
658
-		$data = array();
659
-		foreach ($this->methods as $method) {
660
-			$data[$method] = 'empty';
661
-		}
662
-		return $data;
663
-	}
664
-
665
-	/**
666
-	 * Get the notification body using a pre-Elgg 1.9 plugin hook
667
-	 *
668
-	 * @param Notification      $notification Notification
669
-	 * @param NotificationEvent $event        Event
670
-	 * @param string            $method       Method
671
-	 * @return Notification
672
-	 */
673
-	protected function getDeprecatedNotificationBody(Notification $notification, NotificationEvent $event, $method) {
674
-		$entity = $event->getObject();
675
-		if (!$entity) {
676
-			return $notification;
677
-		}
678
-		$params = array(
679
-			'entity' => $entity,
680
-			'to_entity' => $notification->getRecipient(),
681
-			'method' => $method,
682
-		);
683
-		$subject = $this->getDeprecatedNotificationSubject($entity->getType(), $entity->getSubtype());
684
-		$string = $subject . ": " . $entity->getURL();
685
-		$body = $this->hooks->trigger('notify:entity:message', $entity->getType(), $params, $string);
686
-
687
-		if ($subject) {
688
-			$notification->subject = $subject;
689
-			$notification->body = $body;
690
-		}
691
-
692
-		return $notification;
693
-	}
694
-
695
-	/**
696
-	 * Set message subject for deprecated notification code
697
-	 *
698
-	 * @param string $type    Entity type
699
-	 * @param string $subtype Entity subtype
700
-	 * @param string $subject Subject line
701
-	 * @return void
702
-	 */
703
-	public function setDeprecatedNotificationSubject($type, $subtype, $subject) {
704
-		if ($type == '') {
705
-			$type = '__BLANK__';
706
-		}
707
-		if ($subtype == '') {
708
-			$subtype = '__BLANK__';
709
-		}
710
-
711
-		if (!isset($this->deprSubjects[$type])) {
712
-			$this->deprSubjects[$type] = array();
713
-		}
714
-
715
-		$this->deprSubjects[$type][$subtype] = $subject;
716
-	}
717
-
718
-	/**
719
-	 * Get the deprecated subject
720
-	 *
721
-	 * @param string $type    Entity type
722
-	 * @param string $subtype Entity subtype
723
-	 * @return string
724
-	 */
725
-	protected function getDeprecatedNotificationSubject($type, $subtype) {
726
-		if ($type == '') {
727
-			$type = '__BLANK__';
728
-		}
729
-		if ($subtype == '') {
730
-			$subtype = '__BLANK__';
731
-		}
732
-
733
-		if (!isset($this->deprSubjects[$type])) {
734
-			return '';
735
-		}
736
-
737
-		if (!isset($this->deprSubjects[$type][$subtype])) {
738
-			return '';
739
-		}
740
-
741
-		return $this->deprSubjects[$type][$subtype];
742
-	}
743
-
744
-	/**
745
-	 * Is someone using the deprecated override
746
-	 *
747
-	 * @param NotificationEvent $event Event
748
-	 * @return boolean
749
-	 */
750
-	protected function existsDeprecatedNotificationOverride(NotificationEvent $event) {
751
-		$entity = $event->getObject();
752
-		if (!elgg_instanceof($entity)) {
753
-			return false;
754
-		}
755
-		$params = array(
756
-			'event' => $event->getAction(),
757
-			'object_type' => $entity->getType(),
758
-			'object' => $entity,
759
-		);
760
-		$hookresult = $this->hooks->trigger('object:notifications', $entity->getType(), $params, false);
761
-		if ($hookresult === true) {
762
-			elgg_deprecated_notice("Using the plugin hook 'object:notifications' has been deprecated "
763
-				. "by the hook 'send:before', 'notifications'", 1.9);
764
-			return true;
765
-		} else {
766
-			return false;
767
-		}
768
-	}
454
+            $params['origin'] = Notification::ORIGIN_SUBSCRIPTIONS;
455
+        }
456
+
457
+        $language = $recipient->language;
458
+        $params['event'] = $event;
459
+        $params['method'] = $method;
460
+        $params['sender'] = $actor;
461
+        $params['recipient'] = $recipient;
462
+        $params['language'] = $language;
463
+        $params['object'] = $object;
464
+        $params['action'] = $event->getAction();
465
+
466
+        $notification = new Notification($actor, $recipient, $language, $subject, $body, $summary, $params);
467
+
468
+        $notification = $this->hooks->trigger('prepare', 'notification', $params, $notification);
469
+        if (!$notification instanceof Notification) {
470
+            throw new RuntimeException("'prepare','notification' hook must return an instance of " . Notification::class);
471
+        }
472
+
473
+        $type = 'notification:' . $event->getDescription();
474
+        if ($this->hooks->hasHandler('prepare', $type)) {
475
+            $notification = $this->hooks->trigger('prepare', $type, $params, $notification);
476
+            if (!$notification instanceof Notification) {
477
+                throw new RuntimeException("'prepare','$type' hook must return an instance of " . Notification::class);
478
+            }
479
+        } else {
480
+            // pre Elgg 1.9 notification message generation
481
+            $notification = $this->getDeprecatedNotificationBody($notification, $event, $method);
482
+        }
483
+
484
+        $notification = $this->hooks->trigger('format', "notification:$method", [], $notification);
485
+        if (!$notification instanceof Notification) {
486
+            throw new RuntimeException("'format','notification:$method' hook must return an instance of " . Notification::class);
487
+        }
488
+
489
+        if ($this->hooks->hasHandler('send', "notification:$method")) {
490
+            // return true to indicate the notification has been sent
491
+            $params = array(
492
+                'notification' => $notification,
493
+                'event' => $event,
494
+            );
495
+
496
+            $result = $this->hooks->trigger('send', "notification:$method", $params, false);
497
+            if ($this->logger->getLevel() == Logger::INFO) {
498
+                $logger_data = print_r((array) $notification->toObject(), true);
499
+                if ($result) {
500
+                    $this->logger->info("Notification sent: " . $logger_data);
501
+                } else {
502
+                    $this->logger->info("Notification was not sent: " . $logger_data);
503
+                }
504
+            }
505
+            return $result;
506
+        } else {
507
+            // pre Elgg 1.9 notification handler
508
+            $userGuid = $notification->getRecipientGUID();
509
+            $senderGuid = $notification->getSenderGUID();
510
+            $subject = $notification->subject;
511
+            $body = $notification->body;
512
+            $params = $notification->params;
513
+            return (bool) _elgg_notify_user($userGuid, $senderGuid, $subject, $body, $params, array($method));
514
+        }
515
+    }
516
+
517
+    /**
518
+     * Get subject for the notification
519
+     *
520
+     * Plugins can define a subtype specific subject simply by providing a
521
+     * translation for the string "notification:subject:<action>:<type>:<subtype".
522
+     *
523
+     * For example in mod/blog/languages/en.php:
524
+     *
525
+     *     'notification:subject:publish:object:blog' => '%s published a blog called %s'
526
+     *
527
+     * @param NotificationEvent $event     Notification event
528
+     * @param ElggUser          $recipient Notification recipient
529
+     * @return string Notification subject in the recipient's language
530
+     */
531
+    private function getNotificationSubject(NotificationEvent $event, ElggUser $recipient) {
532
+        $actor = $event->getActor();
533
+        $object = $event->getObject();
534
+        /* @var \ElggObject $object */
535
+        $language = $recipient->language;
536
+
537
+        // Check custom notification subject for the action/type/subtype combination
538
+        $subject_key = "notification:{$event->getDescription()}:subject";
539
+        if ($this->translator->languageKeyExists($subject_key, $language)) {
540
+            if ($object instanceof \ElggEntity) {
541
+                $display_name = $object->getDisplayName();
542
+            } else {
543
+                $display_name = '';
544
+            }
545
+            return $this->translator->translate($subject_key, array(
546
+                        $actor->name,
547
+                        $display_name,
548
+                            ), $language);
549
+        }
550
+
551
+        // Fall back to default subject
552
+        return $this->translator->translate('notification:subject', array($actor->name), $language);
553
+    }
554
+
555
+    /**
556
+     * Get body for the notification
557
+     *
558
+     * Plugin can define a subtype specific body simply by providing a
559
+     * translation for the string "notification:body:<action>:<type>:<subtype".
560
+     *
561
+     * For example in mod/blog/languages/en.php:
562
+     *
563
+     *    'notification:body:publish:object:blog' => '
564
+     *         Hi %s!
565
+     *
566
+     *         %s has created a new post called "%s" in the group %s.
567
+     *
568
+     *         It says:
569
+     *
570
+     *         "%s"
571
+     *
572
+     *         You can comment the post here:
573
+     *         %s
574
+     *     ',
575
+     *
576
+     * The arguments passed into the translation are:
577
+     *     1. Recipient's name
578
+     *     2. Name of the user who triggered the notification
579
+     *     3. Title of the content
580
+     *     4. Name of the content's container
581
+     *     5. The actual content (entity's 'description' field)
582
+     *     6. URL to the content
583
+     *
584
+     * Argument swapping can be used to change the order of the parameters.
585
+     * See http://php.net/manual/en/function.sprintf.php#example-5427
586
+     *
587
+     * @param NotificationEvent $event     Notification event
588
+     * @param ElggUser          $recipient Notification recipient
589
+     * @return string Notification body in the recipient's language
590
+     */
591
+    private function getNotificationBody(NotificationEvent $event, ElggUser $recipient) {
592
+        $actor = $event->getActor();
593
+        $object = $event->getObject();
594
+        /* @var \ElggObject $object */
595
+        $language = $recipient->language;
596
+
597
+        // Check custom notification body for the action/type/subtype combination
598
+        $body_key = "notification:{$event->getDescription()}:body";
599
+        if ($this->translator->languageKeyExists($body_key, $language)) {
600
+            if ($object instanceof \ElggEntity) {
601
+                $display_name = $object->getDisplayName();
602
+                $container_name = '';
603
+                $container = $object->getContainerEntity();
604
+                if ($container) {
605
+                    $container_name = $container->getDisplayName();
606
+                }
607
+            } else {
608
+                $display_name = '';
609
+                $container_name = '';
610
+            }
611
+
612
+            return $this->translator->translate($body_key, array(
613
+                        $recipient->name,
614
+                        $actor->name,
615
+                        $display_name,
616
+                        $container_name,
617
+                        $object->description,
618
+                        $object->getURL(),
619
+                            ), $language);
620
+        }
621
+
622
+        // Fall back to default body
623
+        return $this->translator->translate('notification:body', array($object->getURL()), $language);
624
+    }
625
+
626
+    /**
627
+     * Register a deprecated notification handler
628
+     *
629
+     * @param string $method  Method name
630
+     * @param string $handler Handler callback
631
+     * @return void
632
+     */
633
+    public function registerDeprecatedHandler($method, $handler) {
634
+        $this->deprHandlers[$method] = $handler;
635
+    }
636
+
637
+    /**
638
+     * Get a deprecated notification handler callback
639
+     *
640
+     * @param string $method Method name
641
+     * @return callback|null
642
+     */
643
+    public function getDeprecatedHandler($method) {
644
+        if (isset($this->deprHandlers[$method])) {
645
+            return $this->deprHandlers[$method];
646
+        } else {
647
+            return null;
648
+        }
649
+    }
650
+
651
+    /**
652
+     * Provides a way to incrementally wean Elgg's notifications code from the
653
+     * global $NOTIFICATION_HANDLERS
654
+     *
655
+     * @return array
656
+     */
657
+    public function getMethodsAsDeprecatedGlobal() {
658
+        $data = array();
659
+        foreach ($this->methods as $method) {
660
+            $data[$method] = 'empty';
661
+        }
662
+        return $data;
663
+    }
664
+
665
+    /**
666
+     * Get the notification body using a pre-Elgg 1.9 plugin hook
667
+     *
668
+     * @param Notification      $notification Notification
669
+     * @param NotificationEvent $event        Event
670
+     * @param string            $method       Method
671
+     * @return Notification
672
+     */
673
+    protected function getDeprecatedNotificationBody(Notification $notification, NotificationEvent $event, $method) {
674
+        $entity = $event->getObject();
675
+        if (!$entity) {
676
+            return $notification;
677
+        }
678
+        $params = array(
679
+            'entity' => $entity,
680
+            'to_entity' => $notification->getRecipient(),
681
+            'method' => $method,
682
+        );
683
+        $subject = $this->getDeprecatedNotificationSubject($entity->getType(), $entity->getSubtype());
684
+        $string = $subject . ": " . $entity->getURL();
685
+        $body = $this->hooks->trigger('notify:entity:message', $entity->getType(), $params, $string);
686
+
687
+        if ($subject) {
688
+            $notification->subject = $subject;
689
+            $notification->body = $body;
690
+        }
691
+
692
+        return $notification;
693
+    }
694
+
695
+    /**
696
+     * Set message subject for deprecated notification code
697
+     *
698
+     * @param string $type    Entity type
699
+     * @param string $subtype Entity subtype
700
+     * @param string $subject Subject line
701
+     * @return void
702
+     */
703
+    public function setDeprecatedNotificationSubject($type, $subtype, $subject) {
704
+        if ($type == '') {
705
+            $type = '__BLANK__';
706
+        }
707
+        if ($subtype == '') {
708
+            $subtype = '__BLANK__';
709
+        }
710
+
711
+        if (!isset($this->deprSubjects[$type])) {
712
+            $this->deprSubjects[$type] = array();
713
+        }
714
+
715
+        $this->deprSubjects[$type][$subtype] = $subject;
716
+    }
717
+
718
+    /**
719
+     * Get the deprecated subject
720
+     *
721
+     * @param string $type    Entity type
722
+     * @param string $subtype Entity subtype
723
+     * @return string
724
+     */
725
+    protected function getDeprecatedNotificationSubject($type, $subtype) {
726
+        if ($type == '') {
727
+            $type = '__BLANK__';
728
+        }
729
+        if ($subtype == '') {
730
+            $subtype = '__BLANK__';
731
+        }
732
+
733
+        if (!isset($this->deprSubjects[$type])) {
734
+            return '';
735
+        }
736
+
737
+        if (!isset($this->deprSubjects[$type][$subtype])) {
738
+            return '';
739
+        }
740
+
741
+        return $this->deprSubjects[$type][$subtype];
742
+    }
743
+
744
+    /**
745
+     * Is someone using the deprecated override
746
+     *
747
+     * @param NotificationEvent $event Event
748
+     * @return boolean
749
+     */
750
+    protected function existsDeprecatedNotificationOverride(NotificationEvent $event) {
751
+        $entity = $event->getObject();
752
+        if (!elgg_instanceof($entity)) {
753
+            return false;
754
+        }
755
+        $params = array(
756
+            'event' => $event->getAction(),
757
+            'object_type' => $entity->getType(),
758
+            'object' => $entity,
759
+        );
760
+        $hookresult = $this->hooks->trigger('object:notifications', $entity->getType(), $params, false);
761
+        if ($hookresult === true) {
762
+            elgg_deprecated_notice("Using the plugin hook 'object:notifications' has been deprecated "
763
+                . "by the hook 'send:before', 'notifications'", 1.9);
764
+            return true;
765
+        } else {
766
+            return false;
767
+        }
768
+    }
769 769
 
770 770
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 			$this->events[$type][$subtype] = array();
102 102
 		}
103 103
 
104
-		$action_list =& $this->events[$type][$subtype];
104
+		$action_list = & $this->events[$type][$subtype];
105 105
 		if ($actions) {
106 106
 			$action_list = array_unique(array_merge($action_list, $actions));
107 107
 		} elseif (!in_array('create', $action_list)) {
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
 			}
295 295
 		}
296 296
 
297
-		$this->logger->notice("Results for the notification event {$event->getDescription()}: " . print_r($result, true));
297
+		$this->logger->notice("Results for the notification event {$event->getDescription()}: ".print_r($result, true));
298 298
 		return $result;
299 299
 	}
300 300
 
@@ -467,14 +467,14 @@  discard block
 block discarded – undo
467 467
 
468 468
 		$notification = $this->hooks->trigger('prepare', 'notification', $params, $notification);
469 469
 		if (!$notification instanceof Notification) {
470
-			throw new RuntimeException("'prepare','notification' hook must return an instance of " . Notification::class);
470
+			throw new RuntimeException("'prepare','notification' hook must return an instance of ".Notification::class);
471 471
 		}
472 472
 
473
-		$type = 'notification:' . $event->getDescription();
473
+		$type = 'notification:'.$event->getDescription();
474 474
 		if ($this->hooks->hasHandler('prepare', $type)) {
475 475
 			$notification = $this->hooks->trigger('prepare', $type, $params, $notification);
476 476
 			if (!$notification instanceof Notification) {
477
-				throw new RuntimeException("'prepare','$type' hook must return an instance of " . Notification::class);
477
+				throw new RuntimeException("'prepare','$type' hook must return an instance of ".Notification::class);
478 478
 			}
479 479
 		} else {
480 480
 			// pre Elgg 1.9 notification message generation
@@ -483,7 +483,7 @@  discard block
 block discarded – undo
483 483
 
484 484
 		$notification = $this->hooks->trigger('format', "notification:$method", [], $notification);
485 485
 		if (!$notification instanceof Notification) {
486
-			throw new RuntimeException("'format','notification:$method' hook must return an instance of " . Notification::class);
486
+			throw new RuntimeException("'format','notification:$method' hook must return an instance of ".Notification::class);
487 487
 		}
488 488
 
489 489
 		if ($this->hooks->hasHandler('send', "notification:$method")) {
@@ -497,9 +497,9 @@  discard block
 block discarded – undo
497 497
 			if ($this->logger->getLevel() == Logger::INFO) {
498 498
 				$logger_data = print_r((array) $notification->toObject(), true);
499 499
 				if ($result) {
500
-					$this->logger->info("Notification sent: " . $logger_data);
500
+					$this->logger->info("Notification sent: ".$logger_data);
501 501
 				} else {
502
-					$this->logger->info("Notification was not sent: " . $logger_data);
502
+					$this->logger->info("Notification was not sent: ".$logger_data);
503 503
 				}
504 504
 			}
505 505
 			return $result;
@@ -681,7 +681,7 @@  discard block
 block discarded – undo
681 681
 			'method' => $method,
682 682
 		);
683 683
 		$subject = $this->getDeprecatedNotificationSubject($entity->getType(), $entity->getSubtype());
684
-		$string = $subject . ": " . $entity->getURL();
684
+		$string = $subject.": ".$entity->getURL();
685 685
 		$body = $this->hooks->trigger('notify:entity:message', $entity->getType(), $params, $string);
686 686
 
687 687
 		if ($subject) {
Please login to merge, or discard this patch.
engine/classes/Elgg/PersistentLoginService.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -223,7 +223,7 @@
 block discarded – undo
223 223
 	 * @param \DatabaseException $exception The exception to handle
224 224
 	 * @param string             $default   The value to return if the table doesn't exist yet
225 225
 	 * 
226
-	 * @return mixed
226
+	 * @return string|null
227 227
 	 *
228 228
 	 * @throws \DatabaseException
229 229
 	 */
Please login to merge, or discard this patch.
Indentation   +346 added lines, -346 removed lines patch added patch discarded remove patch
@@ -25,354 +25,354 @@
 block discarded – undo
25 25
  */
26 26
 class PersistentLoginService {
27 27
 
28
-	/**
29
-	 * Constructor
30
-	 *
31
-	 * @param Database     $db            The DB service
32
-	 * @param \ElggSession $session       The Elgg session
33
-	 * @param \ElggCrypto  $crypto        The cryptography service
34
-	 * @param array        $cookie_config The persistent login cookie settings
35
-	 * @param string       $cookie_token  The token from the request cookie
36
-	 * @param int          $time          The current time
37
-	 */
38
-	public function __construct(
39
-			Database $db,
40
-			\ElggSession $session,
41
-			\ElggCrypto $crypto,
42
-			array $cookie_config,
43
-			$cookie_token,
44
-			$time = null) {
45
-		$this->db = $db;
46
-		$this->session = $session;
47
-		$this->crypto = $crypto;
48
-		$this->cookie_config = $cookie_config;
49
-		$this->cookie_token = $cookie_token;
50
-
51
-		$prefix = $this->db->prefix;
52
-		$this->table = "{$prefix}users_remember_me_cookies";
53
-		$this->time = is_numeric($time) ? (int)$time : time();
54
-	}
55
-
56
-	/**
57
-	 * Make the user's login persistent
58
-	 *
59
-	 * @param \ElggUser $user The user who logged in
60
-	 * 
61
-	 * @return void
62
-	 */
63
-	public function makeLoginPersistent(\ElggUser $user) {
64
-		$token = $this->generateToken();
65
-		$hash = $this->hashToken($token);
66
-
67
-		$this->storeHash($user, $hash);
68
-		$this->setCookie($token);
69
-		$this->setSession($token);
70
-	}
71
-
72
-	/**
73
-	 * Remove the persisted login token from client and server
74
-	 * 
75
-	 * @return void
76
-	 */
77
-	public function removePersistentLogin() {
78
-		if ($this->cookie_token) {
79
-			$client_hash = $this->hashToken($this->cookie_token);
80
-			$this->removeHash($client_hash);
81
-		}
82
-
83
-		$this->setCookie("");
84
-		$this->setSession("");
85
-	}
86
-
87
-	/**
88
-	 * Handle a password change
89
-	 *
90
-	 * @param \ElggUser $subject  The user whose password changed
91
-	 * @param \ElggUser $modifier The user who changed the password
92
-	 * 
93
-	 * @return void
94
-	 */
95
-	public function handlePasswordChange(\ElggUser $subject, \ElggUser $modifier = null) {
96
-		$this->removeAllHashes($subject);
97
-		if (!$modifier || ($modifier->guid !== $subject->guid) || !$this->cookie_token) {
98
-			return;
99
-		}
100
-
101
-		$this->makeLoginPersistent($modifier);
102
-	}
103
-
104
-	/**
105
-	 * Boot the persistent login session, possibly returning the user who should be
106
-	 * silently logged in.
107
-	 *
108
-	 * @return \ElggUser|null
109
-	 */
110
-	public function bootSession() {
111
-		if (!$this->cookie_token) {
112
-			return null;
113
-		}
114
-
115
-		// is this token good?
116
-		$cookie_hash = $this->hashToken($this->cookie_token);
117
-		$user = $this->getUserFromHash($cookie_hash);
118
-		if ($user) {
119
-			$this->setSession($this->cookie_token);
120
-			// note: if the token is legacy, we don't both replacing it here because
121
-			// it will be replaced during the next request boot
122
-			return $user;
123
-		} else {
124
-			if ($this->isLegacyToken($this->cookie_token)) {
125
-				// may be attempt to brute force legacy low-entropy tokens
126
-				call_user_func($this->_callable_sleep, 1);
127
-			}
128
-			$this->setCookie('');
129
-		}
130
-	}
131
-
132
-	/**
133
-	 * Replace the user's token if it's a legacy hexadecimal token
134
-	 *
135
-	 * @param \ElggUser $logged_in_user The logged in user
136
-	 * 
137
-	 * @return void
138
-	 */
139
-	public function replaceLegacyToken(\ElggUser $logged_in_user) {
140
-		if (!$this->cookie_token || !$this->isLegacyToken($this->cookie_token)) {
141
-			return;
142
-		}
143
-
144
-		// replace user's old weaker-entropy code with new one
145
-		$this->removeHash($this->hashToken($this->cookie_token));
146
-		$this->makeLoginPersistent($logged_in_user);
147
-	}
148
-
149
-	/**
150
-	 * Find a user with the given hash
151
-	 *
152
-	 * @param string $hash The hashed token
153
-	 * 
154
-	 * @return \ElggUser|null
155
-	 */
156
-	public function getUserFromHash($hash) {
157
-		if (!$hash) {
158
-			return null;
159
-		}
160
-
161
-		$hash = $this->db->sanitizeString($hash);
162
-		$query = "SELECT guid FROM {$this->table} WHERE code = '$hash'";
163
-		try {
164
-			$user_row = $this->db->getDataRow($query);
165
-		} catch (\DatabaseException $e) {
166
-			return $this->handleDbException($e);
167
-		}
168
-		if (!$user_row) {
169
-			return null;
170
-		}
171
-
172
-		$user = call_user_func($this->_callable_get_user, $user_row->guid);
173
-		return $user ? $user : null;
174
-	}
175
-
176
-	/**
177
-	 * Store a hash in the DB
178
-	 *
179
-	 * @param \ElggUser $user The user for whom we're storing the hash
180
-	 * @param string    $hash The hashed token
181
-	 * 
182
-	 * @return void
183
-	 */
184
-	protected function storeHash(\ElggUser $user, $hash) {
185
-		// This prevents inserting the same hash twice, which seems to be happening in some rare cases
186
-		// and for unknown reasons. See https://github.com/Elgg/Elgg/issues/8104
187
-		$this->removeHash($hash);
188
-
189
-		$time = time();
190
-		$hash = $this->db->sanitizeString($hash);
191
-
192
-		$query = "
28
+    /**
29
+     * Constructor
30
+     *
31
+     * @param Database     $db            The DB service
32
+     * @param \ElggSession $session       The Elgg session
33
+     * @param \ElggCrypto  $crypto        The cryptography service
34
+     * @param array        $cookie_config The persistent login cookie settings
35
+     * @param string       $cookie_token  The token from the request cookie
36
+     * @param int          $time          The current time
37
+     */
38
+    public function __construct(
39
+            Database $db,
40
+            \ElggSession $session,
41
+            \ElggCrypto $crypto,
42
+            array $cookie_config,
43
+            $cookie_token,
44
+            $time = null) {
45
+        $this->db = $db;
46
+        $this->session = $session;
47
+        $this->crypto = $crypto;
48
+        $this->cookie_config = $cookie_config;
49
+        $this->cookie_token = $cookie_token;
50
+
51
+        $prefix = $this->db->prefix;
52
+        $this->table = "{$prefix}users_remember_me_cookies";
53
+        $this->time = is_numeric($time) ? (int)$time : time();
54
+    }
55
+
56
+    /**
57
+     * Make the user's login persistent
58
+     *
59
+     * @param \ElggUser $user The user who logged in
60
+     * 
61
+     * @return void
62
+     */
63
+    public function makeLoginPersistent(\ElggUser $user) {
64
+        $token = $this->generateToken();
65
+        $hash = $this->hashToken($token);
66
+
67
+        $this->storeHash($user, $hash);
68
+        $this->setCookie($token);
69
+        $this->setSession($token);
70
+    }
71
+
72
+    /**
73
+     * Remove the persisted login token from client and server
74
+     * 
75
+     * @return void
76
+     */
77
+    public function removePersistentLogin() {
78
+        if ($this->cookie_token) {
79
+            $client_hash = $this->hashToken($this->cookie_token);
80
+            $this->removeHash($client_hash);
81
+        }
82
+
83
+        $this->setCookie("");
84
+        $this->setSession("");
85
+    }
86
+
87
+    /**
88
+     * Handle a password change
89
+     *
90
+     * @param \ElggUser $subject  The user whose password changed
91
+     * @param \ElggUser $modifier The user who changed the password
92
+     * 
93
+     * @return void
94
+     */
95
+    public function handlePasswordChange(\ElggUser $subject, \ElggUser $modifier = null) {
96
+        $this->removeAllHashes($subject);
97
+        if (!$modifier || ($modifier->guid !== $subject->guid) || !$this->cookie_token) {
98
+            return;
99
+        }
100
+
101
+        $this->makeLoginPersistent($modifier);
102
+    }
103
+
104
+    /**
105
+     * Boot the persistent login session, possibly returning the user who should be
106
+     * silently logged in.
107
+     *
108
+     * @return \ElggUser|null
109
+     */
110
+    public function bootSession() {
111
+        if (!$this->cookie_token) {
112
+            return null;
113
+        }
114
+
115
+        // is this token good?
116
+        $cookie_hash = $this->hashToken($this->cookie_token);
117
+        $user = $this->getUserFromHash($cookie_hash);
118
+        if ($user) {
119
+            $this->setSession($this->cookie_token);
120
+            // note: if the token is legacy, we don't both replacing it here because
121
+            // it will be replaced during the next request boot
122
+            return $user;
123
+        } else {
124
+            if ($this->isLegacyToken($this->cookie_token)) {
125
+                // may be attempt to brute force legacy low-entropy tokens
126
+                call_user_func($this->_callable_sleep, 1);
127
+            }
128
+            $this->setCookie('');
129
+        }
130
+    }
131
+
132
+    /**
133
+     * Replace the user's token if it's a legacy hexadecimal token
134
+     *
135
+     * @param \ElggUser $logged_in_user The logged in user
136
+     * 
137
+     * @return void
138
+     */
139
+    public function replaceLegacyToken(\ElggUser $logged_in_user) {
140
+        if (!$this->cookie_token || !$this->isLegacyToken($this->cookie_token)) {
141
+            return;
142
+        }
143
+
144
+        // replace user's old weaker-entropy code with new one
145
+        $this->removeHash($this->hashToken($this->cookie_token));
146
+        $this->makeLoginPersistent($logged_in_user);
147
+    }
148
+
149
+    /**
150
+     * Find a user with the given hash
151
+     *
152
+     * @param string $hash The hashed token
153
+     * 
154
+     * @return \ElggUser|null
155
+     */
156
+    public function getUserFromHash($hash) {
157
+        if (!$hash) {
158
+            return null;
159
+        }
160
+
161
+        $hash = $this->db->sanitizeString($hash);
162
+        $query = "SELECT guid FROM {$this->table} WHERE code = '$hash'";
163
+        try {
164
+            $user_row = $this->db->getDataRow($query);
165
+        } catch (\DatabaseException $e) {
166
+            return $this->handleDbException($e);
167
+        }
168
+        if (!$user_row) {
169
+            return null;
170
+        }
171
+
172
+        $user = call_user_func($this->_callable_get_user, $user_row->guid);
173
+        return $user ? $user : null;
174
+    }
175
+
176
+    /**
177
+     * Store a hash in the DB
178
+     *
179
+     * @param \ElggUser $user The user for whom we're storing the hash
180
+     * @param string    $hash The hashed token
181
+     * 
182
+     * @return void
183
+     */
184
+    protected function storeHash(\ElggUser $user, $hash) {
185
+        // This prevents inserting the same hash twice, which seems to be happening in some rare cases
186
+        // and for unknown reasons. See https://github.com/Elgg/Elgg/issues/8104
187
+        $this->removeHash($hash);
188
+
189
+        $time = time();
190
+        $hash = $this->db->sanitizeString($hash);
191
+
192
+        $query = "
193 193
 			INSERT INTO {$this->table} (code, guid, timestamp)
194 194
 		    VALUES ('$hash', {$user->guid}, $time)
195 195
 		";
196
-		try {
197
-			$this->db->insertData($query);
198
-		} catch (\DatabaseException $e) {
199
-			$this->handleDbException($e);
200
-		}
201
-	}
202
-
203
-	/**
204
-	 * Remove a hash from the DB
205
-	 *
206
-	 * @param string $hash The hashed token to remove (unused before 1.9)
207
-	 * @return void
208
-	 */
209
-	protected function removeHash($hash) {
210
-		$hash = $this->db->sanitizeString($hash);
211
-
212
-		$query = "DELETE FROM {$this->table} WHERE code = '$hash'";
213
-		try {
214
-			$this->db->deleteData($query);
215
-		} catch (\DatabaseException $e) {
216
-			$this->handleDbException($e);
217
-		}
218
-	}
219
-
220
-	/**
221
-	 * Swallow a schema not upgraded exception, otherwise rethrow it
222
-	 *
223
-	 * @param \DatabaseException $exception The exception to handle
224
-	 * @param string             $default   The value to return if the table doesn't exist yet
225
-	 * 
226
-	 * @return mixed
227
-	 *
228
-	 * @throws \DatabaseException
229
-	 */
230
-	protected function handleDbException(\DatabaseException $exception, $default = null) {
231
-		if (false !== strpos($exception->getMessage(), "users_remember_me_cookies' doesn't exist")) {
232
-			// schema has not been updated so we swallow this exception
233
-			return $default;
234
-		} else {
235
-			throw $exception;
236
-		}
237
-	}
238
-
239
-	/**
240
-	 * Remove all the hashes associated with a user
241
-	 *
242
-	 * @param \ElggUser $user The user for whom we're removing hashes
243
-	 * 
244
-	 * @return void
245
-	 */
246
-	protected function removeAllHashes(\ElggUser $user) {
247
-		$query = "DELETE FROM {$this->table} WHERE guid = '{$user->guid}'";
248
-		try {
249
-			$this->db->deleteData($query);
250
-		} catch (\DatabaseException $e) {
251
-			$this->handleDbException($e);
252
-		}
253
-	}
254
-
255
-	/**
256
-	 * Create a hash from the token
257
-	 *
258
-	 * @param string $token The token to hash
259
-	 * 
260
-	 * @return string
261
-	 */
262
-	protected function hashToken($token) {
263
-		// note: with user passwords, you'd want legit password hashing, but since these are randomly
264
-		// generated and long tokens, rainbow tables aren't any help.
265
-		return md5($token);
266
-	}
267
-
268
-	/**
269
-	 * Store the token in the client cookie (or remove the cookie)
270
-	 *
271
-	 * @param string $token Empty string to remove cookie
272
-	 * 
273
-	 * @return void
274
-	 */
275
-	protected function setCookie($token) {
276
-		$cookie = new \ElggCookie($this->cookie_config['name']);
277
-		foreach (array('expire', 'path', 'domain', 'secure', 'httponly') as $key) {
278
-			$cookie->$key = $this->cookie_config[$key];
279
-		}
280
-		$cookie->value = $token;
281
-		if (!$token) {
282
-			$cookie->expire = $this->time - (86400 * 30);
283
-		}
284
-		call_user_func($this->_callable_elgg_set_cookie, $cookie);
285
-	}
286
-
287
-	/**
288
-	 * Store the token in the session (or remove it from the session)
289
-	 *
290
-	 * @param string $token The token to store in session. Empty string to remove.
291
-	 * 
292
-	 * @return void
293
-	 */
294
-	protected function setSession($token) {
295
-		if ($token) {
296
-			$this->session->set('code', $token);
297
-		} else {
298
-			$this->session->remove('code');
299
-		}
300
-	}
301
-
302
-	/**
303
-	 * Generate a random token (base 64 URL)
304
-	 *
305
-	 * The first char is always "z" to indicate the value has more entropy than the
306
-	 * previously generated ones.
307
-	 *
308
-	 * @return string
309
-	 */
310
-	protected function generateToken() {
311
-		return 'z' . $this->crypto->getRandomString(31);
312
-	}
313
-
314
-	/**
315
-	 * Is the given token a legacy MD5 hash?
316
-	 *
317
-	 * @param string $token The token to analyze
318
-	 * 
319
-	 * @return bool
320
-	 */
321
-	protected function isLegacyToken($token) {
322
-		return (isset($token[0]) && $token[0] !== 'z');
323
-	}
324
-
325
-	/**
326
-	 * @var Database
327
-	 */
328
-	protected $db;
329
-
330
-	/**
331
-	 * @var string
332
-	 */
333
-	protected $table;
334
-
335
-	/**
336
-	 * @var array
337
-	 */
338
-	protected $cookie_config;
339
-
340
-	/**
341
-	 * @var string
342
-	 */
343
-	protected $cookie_token;
344
-
345
-	/**
346
-	 * @var \ElggSession
347
-	 */
348
-	protected $session;
349
-
350
-	/**
351
-	 * @var \ElggCrypto
352
-	 */
353
-	protected $crypto;
354
-
355
-	/**
356
-	 * @var int
357
-	 */
358
-	protected $time;
359
-
360
-	/**
361
-	 * DO NOT USE. For unit test mocking
362
-	 * @access private
363
-	 */
364
-	public $_callable_get_user = 'get_user';
365
-
366
-	/**
367
-	 * DO NOT USE. For unit test mocking
368
-	 * @access private
369
-	 */
370
-	public $_callable_elgg_set_cookie = 'elgg_set_cookie';
371
-
372
-	/**
373
-	 * DO NOT USE. For unit test mocking
374
-	 * @access private
375
-	 */
376
-	public $_callable_sleep = 'sleep';
196
+        try {
197
+            $this->db->insertData($query);
198
+        } catch (\DatabaseException $e) {
199
+            $this->handleDbException($e);
200
+        }
201
+    }
202
+
203
+    /**
204
+     * Remove a hash from the DB
205
+     *
206
+     * @param string $hash The hashed token to remove (unused before 1.9)
207
+     * @return void
208
+     */
209
+    protected function removeHash($hash) {
210
+        $hash = $this->db->sanitizeString($hash);
211
+
212
+        $query = "DELETE FROM {$this->table} WHERE code = '$hash'";
213
+        try {
214
+            $this->db->deleteData($query);
215
+        } catch (\DatabaseException $e) {
216
+            $this->handleDbException($e);
217
+        }
218
+    }
219
+
220
+    /**
221
+     * Swallow a schema not upgraded exception, otherwise rethrow it
222
+     *
223
+     * @param \DatabaseException $exception The exception to handle
224
+     * @param string             $default   The value to return if the table doesn't exist yet
225
+     * 
226
+     * @return mixed
227
+     *
228
+     * @throws \DatabaseException
229
+     */
230
+    protected function handleDbException(\DatabaseException $exception, $default = null) {
231
+        if (false !== strpos($exception->getMessage(), "users_remember_me_cookies' doesn't exist")) {
232
+            // schema has not been updated so we swallow this exception
233
+            return $default;
234
+        } else {
235
+            throw $exception;
236
+        }
237
+    }
238
+
239
+    /**
240
+     * Remove all the hashes associated with a user
241
+     *
242
+     * @param \ElggUser $user The user for whom we're removing hashes
243
+     * 
244
+     * @return void
245
+     */
246
+    protected function removeAllHashes(\ElggUser $user) {
247
+        $query = "DELETE FROM {$this->table} WHERE guid = '{$user->guid}'";
248
+        try {
249
+            $this->db->deleteData($query);
250
+        } catch (\DatabaseException $e) {
251
+            $this->handleDbException($e);
252
+        }
253
+    }
254
+
255
+    /**
256
+     * Create a hash from the token
257
+     *
258
+     * @param string $token The token to hash
259
+     * 
260
+     * @return string
261
+     */
262
+    protected function hashToken($token) {
263
+        // note: with user passwords, you'd want legit password hashing, but since these are randomly
264
+        // generated and long tokens, rainbow tables aren't any help.
265
+        return md5($token);
266
+    }
267
+
268
+    /**
269
+     * Store the token in the client cookie (or remove the cookie)
270
+     *
271
+     * @param string $token Empty string to remove cookie
272
+     * 
273
+     * @return void
274
+     */
275
+    protected function setCookie($token) {
276
+        $cookie = new \ElggCookie($this->cookie_config['name']);
277
+        foreach (array('expire', 'path', 'domain', 'secure', 'httponly') as $key) {
278
+            $cookie->$key = $this->cookie_config[$key];
279
+        }
280
+        $cookie->value = $token;
281
+        if (!$token) {
282
+            $cookie->expire = $this->time - (86400 * 30);
283
+        }
284
+        call_user_func($this->_callable_elgg_set_cookie, $cookie);
285
+    }
286
+
287
+    /**
288
+     * Store the token in the session (or remove it from the session)
289
+     *
290
+     * @param string $token The token to store in session. Empty string to remove.
291
+     * 
292
+     * @return void
293
+     */
294
+    protected function setSession($token) {
295
+        if ($token) {
296
+            $this->session->set('code', $token);
297
+        } else {
298
+            $this->session->remove('code');
299
+        }
300
+    }
301
+
302
+    /**
303
+     * Generate a random token (base 64 URL)
304
+     *
305
+     * The first char is always "z" to indicate the value has more entropy than the
306
+     * previously generated ones.
307
+     *
308
+     * @return string
309
+     */
310
+    protected function generateToken() {
311
+        return 'z' . $this->crypto->getRandomString(31);
312
+    }
313
+
314
+    /**
315
+     * Is the given token a legacy MD5 hash?
316
+     *
317
+     * @param string $token The token to analyze
318
+     * 
319
+     * @return bool
320
+     */
321
+    protected function isLegacyToken($token) {
322
+        return (isset($token[0]) && $token[0] !== 'z');
323
+    }
324
+
325
+    /**
326
+     * @var Database
327
+     */
328
+    protected $db;
329
+
330
+    /**
331
+     * @var string
332
+     */
333
+    protected $table;
334
+
335
+    /**
336
+     * @var array
337
+     */
338
+    protected $cookie_config;
339
+
340
+    /**
341
+     * @var string
342
+     */
343
+    protected $cookie_token;
344
+
345
+    /**
346
+     * @var \ElggSession
347
+     */
348
+    protected $session;
349
+
350
+    /**
351
+     * @var \ElggCrypto
352
+     */
353
+    protected $crypto;
354
+
355
+    /**
356
+     * @var int
357
+     */
358
+    protected $time;
359
+
360
+    /**
361
+     * DO NOT USE. For unit test mocking
362
+     * @access private
363
+     */
364
+    public $_callable_get_user = 'get_user';
365
+
366
+    /**
367
+     * DO NOT USE. For unit test mocking
368
+     * @access private
369
+     */
370
+    public $_callable_elgg_set_cookie = 'elgg_set_cookie';
371
+
372
+    /**
373
+     * DO NOT USE. For unit test mocking
374
+     * @access private
375
+     */
376
+    public $_callable_sleep = 'sleep';
377 377
 }
378 378
 
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
 
51 51
 		$prefix = $this->db->prefix;
52 52
 		$this->table = "{$prefix}users_remember_me_cookies";
53
-		$this->time = is_numeric($time) ? (int)$time : time();
53
+		$this->time = is_numeric($time) ? (int) $time : time();
54 54
 	}
55 55
 
56 56
 	/**
@@ -308,7 +308,7 @@  discard block
 block discarded – undo
308 308
 	 * @return string
309 309
 	 */
310 310
 	protected function generateToken() {
311
-		return 'z' . $this->crypto->getRandomString(31);
311
+		return 'z'.$this->crypto->getRandomString(31);
312 312
 	}
313 313
 
314 314
 	/**
Please login to merge, or discard this patch.
engine/classes/Elgg/Translit.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -120,7 +120,7 @@  discard block
 block discarded – undo
120 120
 	/**
121 121
 	 * Get array of UTF-8 (NFC) character replacements.
122 122
 	 *
123
-	 * @return array
123
+	 * @return string
124 124
 	 */
125 125
 	static public function getAsciiTranslitMap() {
126 126
 		return array(
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
 	/**
254 254
 	 * Tests that "normalizer_normalize" exists and works
255 255
 	 *
256
-	 * @return bool
256
+	 * @return boolean|null
257 257
 	 */
258 258
 	static public function hasNormalizerSupport() {
259 259
 		static $ret = null;
Please login to merge, or discard this patch.
Indentation   +223 added lines, -223 removed lines patch added patch discarded remove patch
@@ -30,240 +30,240 @@
 block discarded – undo
30 30
  */
31 31
 class Translit {
32 32
 
33
-	/**
34
-	 * Create a version of a string for embedding in a URL
35
-	 *
36
-	 * @param string $string    A UTF-8 string
37
-	 * @param string $separator The character to separate words with
38
-	 * @return string
39
-	 */
40
-	static public function urlize($string, $separator = '-') {
41
-		// Iñtërnâtiônàlizætiøn, AND 日本語!
33
+    /**
34
+     * Create a version of a string for embedding in a URL
35
+     *
36
+     * @param string $string    A UTF-8 string
37
+     * @param string $separator The character to separate words with
38
+     * @return string
39
+     */
40
+    static public function urlize($string, $separator = '-') {
41
+        // Iñtërnâtiônàlizætiøn, AND 日本語!
42 42
 
43
-		// try to force combined chars because the translit map and others expect it
44
-		if (self::hasNormalizerSupport()) {
45
-			$nfc = normalizer_normalize($string);
46
-			if (is_string($nfc)) {
47
-				$string = $nfc;
48
-			}
49
-		}
50
-		// Internationalization, AND 日本語!
51
-		$string = self::transliterateAscii($string);
43
+        // try to force combined chars because the translit map and others expect it
44
+        if (self::hasNormalizerSupport()) {
45
+            $nfc = normalizer_normalize($string);
46
+            if (is_string($nfc)) {
47
+                $string = $nfc;
48
+            }
49
+        }
50
+        // Internationalization, AND 日本語!
51
+        $string = self::transliterateAscii($string);
52 52
 
53
-		// allow HTML tags in titles
54
-		$string = preg_replace('~<([a-zA-Z][^>]*)>~', ' $1 ', $string);
53
+        // allow HTML tags in titles
54
+        $string = preg_replace('~<([a-zA-Z][^>]*)>~', ' $1 ', $string);
55 55
 
56
-		// more substitutions
57
-		// @todo put these somewhere else
58
-		$string = strtr($string, array(
59
-			// currency
60
-			"\xE2\x82\xAC" /* € */ => ' E ',
61
-			"\xC2\xA3" /* £ */ => ' GBP ',
62
-		));
56
+        // more substitutions
57
+        // @todo put these somewhere else
58
+        $string = strtr($string, array(
59
+            // currency
60
+            "\xE2\x82\xAC" /* € */ => ' E ',
61
+            "\xC2\xA3" /* £ */ => ' GBP ',
62
+        ));
63 63
 
64
-		// remove all ASCII except 0-9a-zA-Z, hyphen, underscore, and whitespace
65
-		// note: "x" modifier did not work with this pattern.
66
-		$string = preg_replace('~['
67
-			. '\x00-\x08'  // control chars
68
-			. '\x0b\x0c'   // vert tab, form feed
69
-			. '\x0e-\x1f'  // control chars
70
-			. '\x21-\x2c'  // ! ... ,
71
-			. '\x2e\x2f'   // . slash
72
-			. '\x3a-\x40'  // : ... @
73
-			. '\x5b-\x5e'  // [ ... ^
74
-			. '\x60'       // `
75
-			. '\x7b-\x7f'  // { ... DEL
76
-			. ']~', '', $string);
77
-		$string = strtr($string, '', '');
64
+        // remove all ASCII except 0-9a-zA-Z, hyphen, underscore, and whitespace
65
+        // note: "x" modifier did not work with this pattern.
66
+        $string = preg_replace('~['
67
+            . '\x00-\x08'  // control chars
68
+            . '\x0b\x0c'   // vert tab, form feed
69
+            . '\x0e-\x1f'  // control chars
70
+            . '\x21-\x2c'  // ! ... ,
71
+            . '\x2e\x2f'   // . slash
72
+            . '\x3a-\x40'  // : ... @
73
+            . '\x5b-\x5e'  // [ ... ^
74
+            . '\x60'       // `
75
+            . '\x7b-\x7f'  // { ... DEL
76
+            . ']~', '', $string);
77
+        $string = strtr($string, '', '');
78 78
 
79
-		// internationalization, and 日本語!
80
-		// note: not using elgg_strtolower to keep this class portable
81
-		$string = is_callable('mb_strtolower') ? mb_strtolower($string, 'UTF-8') : strtolower($string);
79
+        // internationalization, and 日本語!
80
+        // note: not using elgg_strtolower to keep this class portable
81
+        $string = is_callable('mb_strtolower') ? mb_strtolower($string, 'UTF-8') : strtolower($string);
82 82
 
83
-		// split by ASCII chars not in 0-9a-zA-Z
84
-		// note: we cannot use [^0-9a-zA-Z] because that matches multibyte chars.
85
-		// note: "x" modifier did not work with this pattern.
86
-		$pattern = '~['
87
-			. '\x00-\x2f'  // controls ... slash
88
-			. '\x3a-\x40'  // : ... @
89
-			. '\x5b-\x60'  // [ ... `
90
-			. '\x7b-\x7f'  // { ... DEL
91
-			. ']+~x';
83
+        // split by ASCII chars not in 0-9a-zA-Z
84
+        // note: we cannot use [^0-9a-zA-Z] because that matches multibyte chars.
85
+        // note: "x" modifier did not work with this pattern.
86
+        $pattern = '~['
87
+            . '\x00-\x2f'  // controls ... slash
88
+            . '\x3a-\x40'  // : ... @
89
+            . '\x5b-\x60'  // [ ... `
90
+            . '\x7b-\x7f'  // { ... DEL
91
+            . ']+~x';
92 92
 
93
-		// ['internationalization', 'and', '日本語']
94
-		$words = preg_split($pattern, $string, -1, PREG_SPLIT_NO_EMPTY);
93
+        // ['internationalization', 'and', '日本語']
94
+        $words = preg_split($pattern, $string, -1, PREG_SPLIT_NO_EMPTY);
95 95
 
96
-		// ['internationalization', 'and', '%E6%97%A5%E6%9C%AC%E8%AA%9E']
97
-		$words = array_map('urlencode', $words);
96
+        // ['internationalization', 'and', '%E6%97%A5%E6%9C%AC%E8%AA%9E']
97
+        $words = array_map('urlencode', $words);
98 98
 
99
-		// internationalization-and-%E6%97%A5%E6%9C%AC%E8%AA%9E
100
-		return implode($separator, $words);
101
-	}
99
+        // internationalization-and-%E6%97%A5%E6%9C%AC%E8%AA%9E
100
+        return implode($separator, $words);
101
+    }
102 102
 
103
-	/**
104
-	 * Transliterate Western multibyte chars to ASCII
105
-	 *
106
-	 * @param string $utf8 a UTF-8 string
107
-	 * @return string
108
-	 */
109
-	static public function transliterateAscii($utf8) {
110
-		static $map = null;
111
-		if (!preg_match('/[\x80-\xff]/', $utf8)) {
112
-			return $utf8;
113
-		}
114
-		if (null === $map) {
115
-			$map = self::getAsciiTranslitMap();
116
-		}
117
-		return strtr($utf8, $map);
118
-	}
103
+    /**
104
+     * Transliterate Western multibyte chars to ASCII
105
+     *
106
+     * @param string $utf8 a UTF-8 string
107
+     * @return string
108
+     */
109
+    static public function transliterateAscii($utf8) {
110
+        static $map = null;
111
+        if (!preg_match('/[\x80-\xff]/', $utf8)) {
112
+            return $utf8;
113
+        }
114
+        if (null === $map) {
115
+            $map = self::getAsciiTranslitMap();
116
+        }
117
+        return strtr($utf8, $map);
118
+    }
119 119
 
120
-	/**
121
-	 * Get array of UTF-8 (NFC) character replacements.
122
-	 *
123
-	 * @return array
124
-	 */
125
-	static public function getAsciiTranslitMap() {
126
-		return array(
127
-			// Decompositions for Latin-1 Supplement
128
-			"\xC2\xAA" /* ª */ => 'a', "\xC2\xBA" /* º */ => 'o', "\xC3\x80" /* À */ => 'A',
129
-			"\xC3\x81" /* Á */ => 'A', "\xC3\x82" /* Â */ => 'A', "\xC3\x83" /* Ã */ => 'A',
130
-			"\xC3\x84" /* Ä */ => 'A', "\xC3\x85" /* Å */ => 'A', "\xC3\x86" /* Æ */ => 'AE',
131
-			"\xC3\x87" /* Ç */ => 'C', "\xC3\x88" /* È */ => 'E', "\xC3\x89" /* É */ => 'E',
132
-			"\xC3\x8A" /* Ê */ => 'E', "\xC3\x8B" /* Ë */ => 'E', "\xC3\x8C" /* Ì */ => 'I',
133
-			"\xC3\x8D" /* Í */ => 'I', "\xC3\x8E" /* Î */ => 'I', "\xC3\x8F" /* Ï */ => 'I',
134
-			"\xC3\x90" /* Ð */ => 'D', "\xC3\x91" /* Ñ */ => 'N', "\xC3\x92" /* Ò */ => 'O',
135
-			"\xC3\x93" /* Ó */ => 'O', "\xC3\x94" /* Ô */ => 'O', "\xC3\x95" /* Õ */ => 'O',
136
-			"\xC3\x96" /* Ö */ => 'O', "\xC3\x99" /* Ù */ => 'U', "\xC3\x9A" /* Ú */ => 'U',
137
-			"\xC3\x9B" /* Û */ => 'U', "\xC3\x9C" /* Ü */ => 'U', "\xC3\x9D" /* Ý */ => 'Y',
138
-			"\xC3\x9E" /* Þ */ => 'TH', "\xC3\x9F" /* ß */ => 'ss', "\xC3\xA0" /* à */ => 'a',
139
-			"\xC3\xA1" /* á */ => 'a', "\xC3\xA2" /* â */ => 'a', "\xC3\xA3" /* ã */ => 'a',
140
-			"\xC3\xA4" /* ä */ => 'a', "\xC3\xA5" /* å */ => 'a', "\xC3\xA6" /* æ */ => 'ae',
141
-			"\xC3\xA7" /* ç */ => 'c', "\xC3\xA8" /* è */ => 'e', "\xC3\xA9" /* é */ => 'e',
142
-			"\xC3\xAA" /* ê */ => 'e', "\xC3\xAB" /* ë */ => 'e', "\xC3\xAC" /* ì */ => 'i',
143
-			"\xC3\xAD" /* í */ => 'i', "\xC3\xAE" /* î */ => 'i', "\xC3\xAF" /* ï */ => 'i',
144
-			"\xC3\xB0" /* ð */ => 'd', "\xC3\xB1" /* ñ */ => 'n', "\xC3\xB2" /* ò */ => 'o',
145
-			"\xC3\xB3" /* ó */ => 'o', "\xC3\xB4" /* ô */ => 'o', "\xC3\xB5" /* õ */ => 'o',
146
-			"\xC3\xB6" /* ö */ => 'o', "\xC3\xB8" /* ø */ => 'o', "\xC3\xB9" /* ù */ => 'u',
147
-			"\xC3\xBA" /* ú */ => 'u', "\xC3\xBB" /* û */ => 'u', "\xC3\xBC" /* ü */ => 'u',
148
-			"\xC3\xBD" /* ý */ => 'y', "\xC3\xBE" /* þ */ => 'th', "\xC3\xBF" /* ÿ */ => 'y',
149
-			"\xC3\x98" /* Ø */ => 'O',
150
-			// Decompositions for Latin Extended-A
151
-			"\xC4\x80" /* Ā */ => 'A', "\xC4\x81" /* ā */ => 'a', "\xC4\x82" /* Ă */ => 'A',
152
-			"\xC4\x83" /* ă */ => 'a', "\xC4\x84" /* Ą */ => 'A', "\xC4\x85" /* ą */ => 'a',
153
-			"\xC4\x86" /* Ć */ => 'C', "\xC4\x87" /* ć */ => 'c', "\xC4\x88" /* Ĉ */ => 'C',
154
-			"\xC4\x89" /* ĉ */ => 'c', "\xC4\x8A" /* Ċ */ => 'C', "\xC4\x8B" /* ċ */ => 'c',
155
-			"\xC4\x8C" /* Č */ => 'C', "\xC4\x8D" /* č */ => 'c', "\xC4\x8E" /* Ď */ => 'D',
156
-			"\xC4\x8F" /* ď */ => 'd', "\xC4\x90" /* Đ */ => 'D', "\xC4\x91" /* đ */ => 'd',
157
-			"\xC4\x92" /* Ē */ => 'E', "\xC4\x93" /* ē */ => 'e', "\xC4\x94" /* Ĕ */ => 'E',
158
-			"\xC4\x95" /* ĕ */ => 'e', "\xC4\x96" /* Ė */ => 'E', "\xC4\x97" /* ė */ => 'e',
159
-			"\xC4\x98" /* Ę */ => 'E', "\xC4\x99" /* ę */ => 'e', "\xC4\x9A" /* Ě */ => 'E',
160
-			"\xC4\x9B" /* ě */ => 'e', "\xC4\x9C" /* Ĝ */ => 'G', "\xC4\x9D" /* ĝ */ => 'g',
161
-			"\xC4\x9E" /* Ğ */ => 'G', "\xC4\x9F" /* ğ */ => 'g', "\xC4\xA0" /* Ġ */ => 'G',
162
-			"\xC4\xA1" /* ġ */ => 'g', "\xC4\xA2" /* Ģ */ => 'G', "\xC4\xA3" /* ģ */ => 'g',
163
-			"\xC4\xA4" /* Ĥ */ => 'H', "\xC4\xA5" /* ĥ */ => 'h', "\xC4\xA6" /* Ħ */ => 'H',
164
-			"\xC4\xA7" /* ħ */ => 'h', "\xC4\xA8" /* Ĩ */ => 'I', "\xC4\xA9" /* ĩ */ => 'i',
165
-			"\xC4\xAA" /* Ī */ => 'I', "\xC4\xAB" /* ī */ => 'i', "\xC4\xAC" /* Ĭ */ => 'I',
166
-			"\xC4\xAD" /* ĭ */ => 'i', "\xC4\xAE" /* Į */ => 'I', "\xC4\xAF" /* į */ => 'i',
167
-			"\xC4\xB0" /* İ */ => 'I', "\xC4\xB1" /* ı */ => 'i', "\xC4\xB2" /* IJ */ => 'IJ',
168
-			"\xC4\xB3" /* ij */ => 'ij', "\xC4\xB4" /* Ĵ */ => 'J', "\xC4\xB5" /* ĵ */ => 'j',
169
-			"\xC4\xB6" /* Ķ */ => 'K', "\xC4\xB7" /* ķ */ => 'k', "\xC4\xB8" /* ĸ */ => 'k',
170
-			"\xC4\xB9" /* Ĺ */ => 'L', "\xC4\xBA" /* ĺ */ => 'l', "\xC4\xBB" /* Ļ */ => 'L',
171
-			"\xC4\xBC" /* ļ */ => 'l', "\xC4\xBD" /* Ľ */ => 'L', "\xC4\xBE" /* ľ */ => 'l',
172
-			"\xC4\xBF" /* Ŀ */ => 'L', "\xC5\x80" /* ŀ */ => 'l', "\xC5\x81" /* Ł */ => 'L',
173
-			"\xC5\x82" /* ł */ => 'l', "\xC5\x83" /* Ń */ => 'N', "\xC5\x84" /* ń */ => 'n',
174
-			"\xC5\x85" /* Ņ */ => 'N', "\xC5\x86" /* ņ */ => 'n', "\xC5\x87" /* Ň */ => 'N',
175
-			"\xC5\x88" /* ň */ => 'n', "\xC5\x89" /* ʼn */ => 'N', "\xC5\x8A" /* Ŋ */ => 'n',
176
-			"\xC5\x8B" /* ŋ */ => 'N', "\xC5\x8C" /* Ō */ => 'O', "\xC5\x8D" /* ō */ => 'o',
177
-			"\xC5\x8E" /* Ŏ */ => 'O', "\xC5\x8F" /* ŏ */ => 'o', "\xC5\x90" /* Ő */ => 'O',
178
-			"\xC5\x91" /* ő */ => 'o', "\xC5\x92" /* Œ */ => 'OE', "\xC5\x93" /* œ */ => 'oe',
179
-			"\xC5\x94" /* Ŕ */ => 'R', "\xC5\x95" /* ŕ */ => 'r', "\xC5\x96" /* Ŗ */ => 'R',
180
-			"\xC5\x97" /* ŗ */ => 'r', "\xC5\x98" /* Ř */ => 'R', "\xC5\x99" /* ř */ => 'r',
181
-			"\xC5\x9A" /* Ś */ => 'S', "\xC5\x9B" /* ś */ => 's', "\xC5\x9C" /* Ŝ */ => 'S',
182
-			"\xC5\x9D" /* ŝ */ => 's', "\xC5\x9E" /* Ş */ => 'S', "\xC5\x9F" /* ş */ => 's',
183
-			"\xC5\xA0" /* Š */ => 'S', "\xC5\xA1" /* š */ => 's', "\xC5\xA2" /* Ţ */ => 'T',
184
-			"\xC5\xA3" /* ţ */ => 't', "\xC5\xA4" /* Ť */ => 'T', "\xC5\xA5" /* ť */ => 't',
185
-			"\xC5\xA6" /* Ŧ */ => 'T', "\xC5\xA7" /* ŧ */ => 't', "\xC5\xA8" /* Ũ */ => 'U',
186
-			"\xC5\xA9" /* ũ */ => 'u', "\xC5\xAA" /* Ū */ => 'U', "\xC5\xAB" /* ū */ => 'u',
187
-			"\xC5\xAC" /* Ŭ */ => 'U', "\xC5\xAD" /* ŭ */ => 'u', "\xC5\xAE" /* Ů */ => 'U',
188
-			"\xC5\xAF" /* ů */ => 'u', "\xC5\xB0" /* Ű */ => 'U', "\xC5\xB1" /* ű */ => 'u',
189
-			"\xC5\xB2" /* Ų */ => 'U', "\xC5\xB3" /* ų */ => 'u', "\xC5\xB4" /* Ŵ */ => 'W',
190
-			"\xC5\xB5" /* ŵ */ => 'w', "\xC5\xB6" /* Ŷ */ => 'Y', "\xC5\xB7" /* ŷ */ => 'y',
191
-			"\xC5\xB8" /* Ÿ */ => 'Y', "\xC5\xB9" /* Ź */ => 'Z', "\xC5\xBA" /* ź */ => 'z',
192
-			"\xC5\xBB" /* Ż */ => 'Z', "\xC5\xBC" /* ż */ => 'z', "\xC5\xBD" /* Ž */ => 'Z',
193
-			"\xC5\xBE" /* ž */ => 'z', "\xC5\xBF" /* ſ */ => 's',
194
-			// Decompositions for Latin Extended-B
195
-			"\xC8\x98" /* Ș */ => 'S', "\xC8\x99" /* ș */ => 's',
196
-			"\xC8\x9A" /* Ț */ => 'T', "\xC8\x9B" /* ț */ => 't',
197
-			// unmarked
198
-			"\xC6\xA0" /* Ơ */ => 'O', "\xC6\xA1" /* ơ */ => 'o',
199
-			"\xC6\xAF" /* Ư */ => 'U', "\xC6\xB0" /* ư */ => 'u',
200
-			// grave accent
201
-			"\xE1\xBA\xA6" /* Ầ */ => 'A', "\xE1\xBA\xA7" /* ầ */ => 'a',
202
-			"\xE1\xBA\xB0" /* Ằ */ => 'A', "\xE1\xBA\xB1" /* ằ */ => 'a',
203
-			"\xE1\xBB\x80" /* Ề */ => 'E', "\xE1\xBB\x81" /* ề */ => 'e',
204
-			"\xE1\xBB\x92" /* Ồ */ => 'O', "\xE1\xBB\x93" /* ồ */ => 'o',
205
-			"\xE1\xBB\x9C" /* Ờ */ => 'O', "\xE1\xBB\x9D" /* ờ */ => 'o',
206
-			"\xE1\xBB\xAA" /* Ừ */ => 'U', "\xE1\xBB\xAB" /* ừ */ => 'u',
207
-			"\xE1\xBB\xB2" /* Ỳ */ => 'Y', "\xE1\xBB\xB3" /* ỳ */ => 'y',
208
-			// hook
209
-			"\xE1\xBA\xA2" /* Ả */ => 'A', "\xE1\xBA\xA3" /* ả */ => 'a',
210
-			"\xE1\xBA\xA8" /* Ẩ */ => 'A', "\xE1\xBA\xA9" /* ẩ */ => 'a',
211
-			"\xE1\xBA\xB2" /* Ẳ */ => 'A', "\xE1\xBA\xB3" /* ẳ */ => 'a',
212
-			"\xE1\xBA\xBA" /* Ẻ */ => 'E', "\xE1\xBA\xBB" /* ẻ */ => 'e',
213
-			"\xE1\xBB\x82" /* Ể */ => 'E', "\xE1\xBB\x83" /* ể */ => 'e',
214
-			"\xE1\xBB\x88" /* Ỉ */ => 'I', "\xE1\xBB\x89" /* ỉ */ => 'i',
215
-			"\xE1\xBB\x8E" /* Ỏ */ => 'O', "\xE1\xBB\x8F" /* ỏ */ => 'o',
216
-			"\xE1\xBB\x94" /* Ổ */ => 'O', "\xE1\xBB\x95" /* ổ */ => 'o',
217
-			"\xE1\xBB\x9E" /* Ở */ => 'O', "\xE1\xBB\x9F" /* ở */ => 'o',
218
-			"\xE1\xBB\xA6" /* Ủ */ => 'U', "\xE1\xBB\xA7" /* ủ */ => 'u',
219
-			"\xE1\xBB\xAC" /* Ử */ => 'U', "\xE1\xBB\xAD" /* ử */ => 'u',
220
-			"\xE1\xBB\xB6" /* Ỷ */ => 'Y', "\xE1\xBB\xB7" /* ỷ */ => 'y',
221
-			// tilde
222
-			"\xE1\xBA\xAA" /* Ẫ */ => 'A', "\xE1\xBA\xAB" /* ẫ */ => 'a',
223
-			"\xE1\xBA\xB4" /* Ẵ */ => 'A', "\xE1\xBA\xB5" /* ẵ */ => 'a',
224
-			"\xE1\xBA\xBC" /* Ẽ */ => 'E', "\xE1\xBA\xBD" /* ẽ */ => 'e',
225
-			"\xE1\xBB\x84" /* Ễ */ => 'E', "\xE1\xBB\x85" /* ễ */ => 'e',
226
-			"\xE1\xBB\x96" /* Ỗ */ => 'O', "\xE1\xBB\x97" /* ỗ */ => 'o',
227
-			"\xE1\xBB\xA0" /* Ỡ */ => 'O', "\xE1\xBB\xA1" /* ỡ */ => 'o',
228
-			"\xE1\xBB\xAE" /* Ữ */ => 'U', "\xE1\xBB\xAF" /* ữ */ => 'u',
229
-			"\xE1\xBB\xB8" /* Ỹ */ => 'Y', "\xE1\xBB\xB9" /* ỹ */ => 'y',
230
-			// acute accent
231
-			"\xE1\xBA\xA4" /* Ấ */ => 'A', "\xE1\xBA\xA5" /* ấ */ => 'a',
232
-			"\xE1\xBA\xAE" /* Ắ */ => 'A', "\xE1\xBA\xAF" /* ắ */ => 'a',
233
-			"\xE1\xBA\xBE" /* Ế */ => 'E', "\xE1\xBA\xBF" /* ế */ => 'e',
234
-			"\xE1\xBB\x90" /* Ố */ => 'O', "\xE1\xBB\x91" /* ố */ => 'o',
235
-			"\xE1\xBB\x9A" /* Ớ */ => 'O', "\xE1\xBB\x9B" /* ớ */ => 'o',
236
-			"\xE1\xBB\xA8" /* Ứ */ => 'U', "\xE1\xBB\xA9" /* ứ */ => 'u',
237
-			// dot below
238
-			"\xE1\xBA\xA0" /* Ạ */ => 'A', "\xE1\xBA\xA1" /* ạ */ => 'a',
239
-			"\xE1\xBA\xAC" /* Ậ */ => 'A', "\xE1\xBA\xAD" /* ậ */ => 'a',
240
-			"\xE1\xBA\xB6" /* Ặ */ => 'A', "\xE1\xBA\xB7" /* ặ */ => 'a',
241
-			"\xE1\xBA\xB8" /* Ẹ */ => 'E', "\xE1\xBA\xB9" /* ẹ */ => 'e',
242
-			"\xE1\xBB\x86" /* Ệ */ => 'E', "\xE1\xBB\x87" /* ệ */ => 'e',
243
-			"\xE1\xBB\x8A" /* Ị */ => 'I', "\xE1\xBB\x8B" /* ị */ => 'i',
244
-			"\xE1\xBB\x8C" /* Ọ */ => 'O', "\xE1\xBB\x8D" /* ọ */ => 'o',
245
-			"\xE1\xBB\x98" /* Ộ */ => 'O', "\xE1\xBB\x99" /* ộ */ => 'o',
246
-			"\xE1\xBB\xA2" /* Ợ */ => 'O', "\xE1\xBB\xA3" /* ợ */ => 'o',
247
-			"\xE1\xBB\xA4" /* Ụ */ => 'U', "\xE1\xBB\xA5" /* ụ */ => 'u',
248
-			"\xE1\xBB\xB0" /* Ự */ => 'U', "\xE1\xBB\xB1" /* ự */ => 'u',
249
-			"\xE1\xBB\xB4" /* Ỵ */ => 'Y', "\xE1\xBB\xB5" /* ỵ */ => 'y',
250
-		);
251
-	}
120
+    /**
121
+     * Get array of UTF-8 (NFC) character replacements.
122
+     *
123
+     * @return array
124
+     */
125
+    static public function getAsciiTranslitMap() {
126
+        return array(
127
+            // Decompositions for Latin-1 Supplement
128
+            "\xC2\xAA" /* ª */ => 'a', "\xC2\xBA" /* º */ => 'o', "\xC3\x80" /* À */ => 'A',
129
+            "\xC3\x81" /* Á */ => 'A', "\xC3\x82" /* Â */ => 'A', "\xC3\x83" /* Ã */ => 'A',
130
+            "\xC3\x84" /* Ä */ => 'A', "\xC3\x85" /* Å */ => 'A', "\xC3\x86" /* Æ */ => 'AE',
131
+            "\xC3\x87" /* Ç */ => 'C', "\xC3\x88" /* È */ => 'E', "\xC3\x89" /* É */ => 'E',
132
+            "\xC3\x8A" /* Ê */ => 'E', "\xC3\x8B" /* Ë */ => 'E', "\xC3\x8C" /* Ì */ => 'I',
133
+            "\xC3\x8D" /* Í */ => 'I', "\xC3\x8E" /* Î */ => 'I', "\xC3\x8F" /* Ï */ => 'I',
134
+            "\xC3\x90" /* Ð */ => 'D', "\xC3\x91" /* Ñ */ => 'N', "\xC3\x92" /* Ò */ => 'O',
135
+            "\xC3\x93" /* Ó */ => 'O', "\xC3\x94" /* Ô */ => 'O', "\xC3\x95" /* Õ */ => 'O',
136
+            "\xC3\x96" /* Ö */ => 'O', "\xC3\x99" /* Ù */ => 'U', "\xC3\x9A" /* Ú */ => 'U',
137
+            "\xC3\x9B" /* Û */ => 'U', "\xC3\x9C" /* Ü */ => 'U', "\xC3\x9D" /* Ý */ => 'Y',
138
+            "\xC3\x9E" /* Þ */ => 'TH', "\xC3\x9F" /* ß */ => 'ss', "\xC3\xA0" /* à */ => 'a',
139
+            "\xC3\xA1" /* á */ => 'a', "\xC3\xA2" /* â */ => 'a', "\xC3\xA3" /* ã */ => 'a',
140
+            "\xC3\xA4" /* ä */ => 'a', "\xC3\xA5" /* å */ => 'a', "\xC3\xA6" /* æ */ => 'ae',
141
+            "\xC3\xA7" /* ç */ => 'c', "\xC3\xA8" /* è */ => 'e', "\xC3\xA9" /* é */ => 'e',
142
+            "\xC3\xAA" /* ê */ => 'e', "\xC3\xAB" /* ë */ => 'e', "\xC3\xAC" /* ì */ => 'i',
143
+            "\xC3\xAD" /* í */ => 'i', "\xC3\xAE" /* î */ => 'i', "\xC3\xAF" /* ï */ => 'i',
144
+            "\xC3\xB0" /* ð */ => 'd', "\xC3\xB1" /* ñ */ => 'n', "\xC3\xB2" /* ò */ => 'o',
145
+            "\xC3\xB3" /* ó */ => 'o', "\xC3\xB4" /* ô */ => 'o', "\xC3\xB5" /* õ */ => 'o',
146
+            "\xC3\xB6" /* ö */ => 'o', "\xC3\xB8" /* ø */ => 'o', "\xC3\xB9" /* ù */ => 'u',
147
+            "\xC3\xBA" /* ú */ => 'u', "\xC3\xBB" /* û */ => 'u', "\xC3\xBC" /* ü */ => 'u',
148
+            "\xC3\xBD" /* ý */ => 'y', "\xC3\xBE" /* þ */ => 'th', "\xC3\xBF" /* ÿ */ => 'y',
149
+            "\xC3\x98" /* Ø */ => 'O',
150
+            // Decompositions for Latin Extended-A
151
+            "\xC4\x80" /* Ā */ => 'A', "\xC4\x81" /* ā */ => 'a', "\xC4\x82" /* Ă */ => 'A',
152
+            "\xC4\x83" /* ă */ => 'a', "\xC4\x84" /* Ą */ => 'A', "\xC4\x85" /* ą */ => 'a',
153
+            "\xC4\x86" /* Ć */ => 'C', "\xC4\x87" /* ć */ => 'c', "\xC4\x88" /* Ĉ */ => 'C',
154
+            "\xC4\x89" /* ĉ */ => 'c', "\xC4\x8A" /* Ċ */ => 'C', "\xC4\x8B" /* ċ */ => 'c',
155
+            "\xC4\x8C" /* Č */ => 'C', "\xC4\x8D" /* č */ => 'c', "\xC4\x8E" /* Ď */ => 'D',
156
+            "\xC4\x8F" /* ď */ => 'd', "\xC4\x90" /* Đ */ => 'D', "\xC4\x91" /* đ */ => 'd',
157
+            "\xC4\x92" /* Ē */ => 'E', "\xC4\x93" /* ē */ => 'e', "\xC4\x94" /* Ĕ */ => 'E',
158
+            "\xC4\x95" /* ĕ */ => 'e', "\xC4\x96" /* Ė */ => 'E', "\xC4\x97" /* ė */ => 'e',
159
+            "\xC4\x98" /* Ę */ => 'E', "\xC4\x99" /* ę */ => 'e', "\xC4\x9A" /* Ě */ => 'E',
160
+            "\xC4\x9B" /* ě */ => 'e', "\xC4\x9C" /* Ĝ */ => 'G', "\xC4\x9D" /* ĝ */ => 'g',
161
+            "\xC4\x9E" /* Ğ */ => 'G', "\xC4\x9F" /* ğ */ => 'g', "\xC4\xA0" /* Ġ */ => 'G',
162
+            "\xC4\xA1" /* ġ */ => 'g', "\xC4\xA2" /* Ģ */ => 'G', "\xC4\xA3" /* ģ */ => 'g',
163
+            "\xC4\xA4" /* Ĥ */ => 'H', "\xC4\xA5" /* ĥ */ => 'h', "\xC4\xA6" /* Ħ */ => 'H',
164
+            "\xC4\xA7" /* ħ */ => 'h', "\xC4\xA8" /* Ĩ */ => 'I', "\xC4\xA9" /* ĩ */ => 'i',
165
+            "\xC4\xAA" /* Ī */ => 'I', "\xC4\xAB" /* ī */ => 'i', "\xC4\xAC" /* Ĭ */ => 'I',
166
+            "\xC4\xAD" /* ĭ */ => 'i', "\xC4\xAE" /* Į */ => 'I', "\xC4\xAF" /* į */ => 'i',
167
+            "\xC4\xB0" /* İ */ => 'I', "\xC4\xB1" /* ı */ => 'i', "\xC4\xB2" /* IJ */ => 'IJ',
168
+            "\xC4\xB3" /* ij */ => 'ij', "\xC4\xB4" /* Ĵ */ => 'J', "\xC4\xB5" /* ĵ */ => 'j',
169
+            "\xC4\xB6" /* Ķ */ => 'K', "\xC4\xB7" /* ķ */ => 'k', "\xC4\xB8" /* ĸ */ => 'k',
170
+            "\xC4\xB9" /* Ĺ */ => 'L', "\xC4\xBA" /* ĺ */ => 'l', "\xC4\xBB" /* Ļ */ => 'L',
171
+            "\xC4\xBC" /* ļ */ => 'l', "\xC4\xBD" /* Ľ */ => 'L', "\xC4\xBE" /* ľ */ => 'l',
172
+            "\xC4\xBF" /* Ŀ */ => 'L', "\xC5\x80" /* ŀ */ => 'l', "\xC5\x81" /* Ł */ => 'L',
173
+            "\xC5\x82" /* ł */ => 'l', "\xC5\x83" /* Ń */ => 'N', "\xC5\x84" /* ń */ => 'n',
174
+            "\xC5\x85" /* Ņ */ => 'N', "\xC5\x86" /* ņ */ => 'n', "\xC5\x87" /* Ň */ => 'N',
175
+            "\xC5\x88" /* ň */ => 'n', "\xC5\x89" /* ʼn */ => 'N', "\xC5\x8A" /* Ŋ */ => 'n',
176
+            "\xC5\x8B" /* ŋ */ => 'N', "\xC5\x8C" /* Ō */ => 'O', "\xC5\x8D" /* ō */ => 'o',
177
+            "\xC5\x8E" /* Ŏ */ => 'O', "\xC5\x8F" /* ŏ */ => 'o', "\xC5\x90" /* Ő */ => 'O',
178
+            "\xC5\x91" /* ő */ => 'o', "\xC5\x92" /* Œ */ => 'OE', "\xC5\x93" /* œ */ => 'oe',
179
+            "\xC5\x94" /* Ŕ */ => 'R', "\xC5\x95" /* ŕ */ => 'r', "\xC5\x96" /* Ŗ */ => 'R',
180
+            "\xC5\x97" /* ŗ */ => 'r', "\xC5\x98" /* Ř */ => 'R', "\xC5\x99" /* ř */ => 'r',
181
+            "\xC5\x9A" /* Ś */ => 'S', "\xC5\x9B" /* ś */ => 's', "\xC5\x9C" /* Ŝ */ => 'S',
182
+            "\xC5\x9D" /* ŝ */ => 's', "\xC5\x9E" /* Ş */ => 'S', "\xC5\x9F" /* ş */ => 's',
183
+            "\xC5\xA0" /* Š */ => 'S', "\xC5\xA1" /* š */ => 's', "\xC5\xA2" /* Ţ */ => 'T',
184
+            "\xC5\xA3" /* ţ */ => 't', "\xC5\xA4" /* Ť */ => 'T', "\xC5\xA5" /* ť */ => 't',
185
+            "\xC5\xA6" /* Ŧ */ => 'T', "\xC5\xA7" /* ŧ */ => 't', "\xC5\xA8" /* Ũ */ => 'U',
186
+            "\xC5\xA9" /* ũ */ => 'u', "\xC5\xAA" /* Ū */ => 'U', "\xC5\xAB" /* ū */ => 'u',
187
+            "\xC5\xAC" /* Ŭ */ => 'U', "\xC5\xAD" /* ŭ */ => 'u', "\xC5\xAE" /* Ů */ => 'U',
188
+            "\xC5\xAF" /* ů */ => 'u', "\xC5\xB0" /* Ű */ => 'U', "\xC5\xB1" /* ű */ => 'u',
189
+            "\xC5\xB2" /* Ų */ => 'U', "\xC5\xB3" /* ų */ => 'u', "\xC5\xB4" /* Ŵ */ => 'W',
190
+            "\xC5\xB5" /* ŵ */ => 'w', "\xC5\xB6" /* Ŷ */ => 'Y', "\xC5\xB7" /* ŷ */ => 'y',
191
+            "\xC5\xB8" /* Ÿ */ => 'Y', "\xC5\xB9" /* Ź */ => 'Z', "\xC5\xBA" /* ź */ => 'z',
192
+            "\xC5\xBB" /* Ż */ => 'Z', "\xC5\xBC" /* ż */ => 'z', "\xC5\xBD" /* Ž */ => 'Z',
193
+            "\xC5\xBE" /* ž */ => 'z', "\xC5\xBF" /* ſ */ => 's',
194
+            // Decompositions for Latin Extended-B
195
+            "\xC8\x98" /* Ș */ => 'S', "\xC8\x99" /* ș */ => 's',
196
+            "\xC8\x9A" /* Ț */ => 'T', "\xC8\x9B" /* ț */ => 't',
197
+            // unmarked
198
+            "\xC6\xA0" /* Ơ */ => 'O', "\xC6\xA1" /* ơ */ => 'o',
199
+            "\xC6\xAF" /* Ư */ => 'U', "\xC6\xB0" /* ư */ => 'u',
200
+            // grave accent
201
+            "\xE1\xBA\xA6" /* Ầ */ => 'A', "\xE1\xBA\xA7" /* ầ */ => 'a',
202
+            "\xE1\xBA\xB0" /* Ằ */ => 'A', "\xE1\xBA\xB1" /* ằ */ => 'a',
203
+            "\xE1\xBB\x80" /* Ề */ => 'E', "\xE1\xBB\x81" /* ề */ => 'e',
204
+            "\xE1\xBB\x92" /* Ồ */ => 'O', "\xE1\xBB\x93" /* ồ */ => 'o',
205
+            "\xE1\xBB\x9C" /* Ờ */ => 'O', "\xE1\xBB\x9D" /* ờ */ => 'o',
206
+            "\xE1\xBB\xAA" /* Ừ */ => 'U', "\xE1\xBB\xAB" /* ừ */ => 'u',
207
+            "\xE1\xBB\xB2" /* Ỳ */ => 'Y', "\xE1\xBB\xB3" /* ỳ */ => 'y',
208
+            // hook
209
+            "\xE1\xBA\xA2" /* Ả */ => 'A', "\xE1\xBA\xA3" /* ả */ => 'a',
210
+            "\xE1\xBA\xA8" /* Ẩ */ => 'A', "\xE1\xBA\xA9" /* ẩ */ => 'a',
211
+            "\xE1\xBA\xB2" /* Ẳ */ => 'A', "\xE1\xBA\xB3" /* ẳ */ => 'a',
212
+            "\xE1\xBA\xBA" /* Ẻ */ => 'E', "\xE1\xBA\xBB" /* ẻ */ => 'e',
213
+            "\xE1\xBB\x82" /* Ể */ => 'E', "\xE1\xBB\x83" /* ể */ => 'e',
214
+            "\xE1\xBB\x88" /* Ỉ */ => 'I', "\xE1\xBB\x89" /* ỉ */ => 'i',
215
+            "\xE1\xBB\x8E" /* Ỏ */ => 'O', "\xE1\xBB\x8F" /* ỏ */ => 'o',
216
+            "\xE1\xBB\x94" /* Ổ */ => 'O', "\xE1\xBB\x95" /* ổ */ => 'o',
217
+            "\xE1\xBB\x9E" /* Ở */ => 'O', "\xE1\xBB\x9F" /* ở */ => 'o',
218
+            "\xE1\xBB\xA6" /* Ủ */ => 'U', "\xE1\xBB\xA7" /* ủ */ => 'u',
219
+            "\xE1\xBB\xAC" /* Ử */ => 'U', "\xE1\xBB\xAD" /* ử */ => 'u',
220
+            "\xE1\xBB\xB6" /* Ỷ */ => 'Y', "\xE1\xBB\xB7" /* ỷ */ => 'y',
221
+            // tilde
222
+            "\xE1\xBA\xAA" /* Ẫ */ => 'A', "\xE1\xBA\xAB" /* ẫ */ => 'a',
223
+            "\xE1\xBA\xB4" /* Ẵ */ => 'A', "\xE1\xBA\xB5" /* ẵ */ => 'a',
224
+            "\xE1\xBA\xBC" /* Ẽ */ => 'E', "\xE1\xBA\xBD" /* ẽ */ => 'e',
225
+            "\xE1\xBB\x84" /* Ễ */ => 'E', "\xE1\xBB\x85" /* ễ */ => 'e',
226
+            "\xE1\xBB\x96" /* Ỗ */ => 'O', "\xE1\xBB\x97" /* ỗ */ => 'o',
227
+            "\xE1\xBB\xA0" /* Ỡ */ => 'O', "\xE1\xBB\xA1" /* ỡ */ => 'o',
228
+            "\xE1\xBB\xAE" /* Ữ */ => 'U', "\xE1\xBB\xAF" /* ữ */ => 'u',
229
+            "\xE1\xBB\xB8" /* Ỹ */ => 'Y', "\xE1\xBB\xB9" /* ỹ */ => 'y',
230
+            // acute accent
231
+            "\xE1\xBA\xA4" /* Ấ */ => 'A', "\xE1\xBA\xA5" /* ấ */ => 'a',
232
+            "\xE1\xBA\xAE" /* Ắ */ => 'A', "\xE1\xBA\xAF" /* ắ */ => 'a',
233
+            "\xE1\xBA\xBE" /* Ế */ => 'E', "\xE1\xBA\xBF" /* ế */ => 'e',
234
+            "\xE1\xBB\x90" /* Ố */ => 'O', "\xE1\xBB\x91" /* ố */ => 'o',
235
+            "\xE1\xBB\x9A" /* Ớ */ => 'O', "\xE1\xBB\x9B" /* ớ */ => 'o',
236
+            "\xE1\xBB\xA8" /* Ứ */ => 'U', "\xE1\xBB\xA9" /* ứ */ => 'u',
237
+            // dot below
238
+            "\xE1\xBA\xA0" /* Ạ */ => 'A', "\xE1\xBA\xA1" /* ạ */ => 'a',
239
+            "\xE1\xBA\xAC" /* Ậ */ => 'A', "\xE1\xBA\xAD" /* ậ */ => 'a',
240
+            "\xE1\xBA\xB6" /* Ặ */ => 'A', "\xE1\xBA\xB7" /* ặ */ => 'a',
241
+            "\xE1\xBA\xB8" /* Ẹ */ => 'E', "\xE1\xBA\xB9" /* ẹ */ => 'e',
242
+            "\xE1\xBB\x86" /* Ệ */ => 'E', "\xE1\xBB\x87" /* ệ */ => 'e',
243
+            "\xE1\xBB\x8A" /* Ị */ => 'I', "\xE1\xBB\x8B" /* ị */ => 'i',
244
+            "\xE1\xBB\x8C" /* Ọ */ => 'O', "\xE1\xBB\x8D" /* ọ */ => 'o',
245
+            "\xE1\xBB\x98" /* Ộ */ => 'O', "\xE1\xBB\x99" /* ộ */ => 'o',
246
+            "\xE1\xBB\xA2" /* Ợ */ => 'O', "\xE1\xBB\xA3" /* ợ */ => 'o',
247
+            "\xE1\xBB\xA4" /* Ụ */ => 'U', "\xE1\xBB\xA5" /* ụ */ => 'u',
248
+            "\xE1\xBB\xB0" /* Ự */ => 'U', "\xE1\xBB\xB1" /* ự */ => 'u',
249
+            "\xE1\xBB\xB4" /* Ỵ */ => 'Y', "\xE1\xBB\xB5" /* ỵ */ => 'y',
250
+        );
251
+    }
252 252
 
253
-	/**
254
-	 * Tests that "normalizer_normalize" exists and works
255
-	 *
256
-	 * @return bool
257
-	 */
258
-	static public function hasNormalizerSupport() {
259
-		static $ret = null;
260
-		if (null === $ret) {
261
-			$form_c = "\xC3\x85"; // 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5)
262
-			$form_d = "A\xCC\x8A"; // A followed by 'COMBINING RING ABOVE' (U+030A)
263
-			$ret = (function_exists('normalizer_normalize')
264
-				&& $form_c === normalizer_normalize($form_d));
265
-		}
266
-		return $ret;
267
-	}
253
+    /**
254
+     * Tests that "normalizer_normalize" exists and works
255
+     *
256
+     * @return bool
257
+     */
258
+    static public function hasNormalizerSupport() {
259
+        static $ret = null;
260
+        if (null === $ret) {
261
+            $form_c = "\xC3\x85"; // 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5)
262
+            $form_d = "A\xCC\x8A"; // A followed by 'COMBINING RING ABOVE' (U+030A)
263
+            $ret = (function_exists('normalizer_normalize')
264
+                && $form_c === normalizer_normalize($form_d));
265
+        }
266
+        return $ret;
267
+    }
268 268
 }
269 269
 
Please login to merge, or discard this patch.
engine/classes/ElggBatch.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -174,7 +174,7 @@
 block discarded – undo
174 174
 	 * @param array  $options    The options array to pass to the getter function. If limit is
175 175
 	 *                           not set, 10 is used as the default. In most cases that is not
176 176
 	 *                           what you want.
177
-	 * @param mixed  $callback   An optional callback function that all results will be passed
177
+	 * @param null|string  $callback   An optional callback function that all results will be passed
178 178
 	 *                           to upon load.  The callback needs to accept $result, $getter,
179 179
 	 *                           $options.
180 180
 	 * @param int    $chunk_size The number of entities to pull in before requesting more.
Please login to merge, or discard this patch.
Indentation   +417 added lines, -417 removed lines patch added patch discarded remove patch
@@ -72,422 +72,422 @@
 block discarded – undo
72 72
  */
73 73
 class ElggBatch implements BatchResult {
74 74
 
75
-	/**
76
-	 * The objects to iterate over.
77
-	 *
78
-	 * @var array
79
-	 */
80
-	private $results = array();
81
-
82
-	/**
83
-	 * The function used to get results.
84
-	 *
85
-	 * @var callable
86
-	 */
87
-	private $getter = null;
88
-
89
-	/**
90
-	 * The given $options to alter and pass to the getter.
91
-	 *
92
-	 * @var array
93
-	 */
94
-	private $options = array();
95
-
96
-	/**
97
-	 * The number of results to grab at a time.
98
-	 *
99
-	 * @var int
100
-	 */
101
-	private $chunkSize = 25;
102
-
103
-	/**
104
-	 * A callback function to pass results through.
105
-	 *
106
-	 * @var callable
107
-	 */
108
-	private $callback = null;
109
-
110
-	/**
111
-	 * Start after this many results.
112
-	 *
113
-	 * @var int
114
-	 */
115
-	private $offset = 0;
116
-
117
-	/**
118
-	 * Stop after this many results.
119
-	 *
120
-	 * @var int
121
-	 */
122
-	private $limit = 0;
123
-
124
-	/**
125
-	 * Number of processed results.
126
-	 *
127
-	 * @var int
128
-	 */
129
-	private $retrievedResults = 0;
130
-
131
-	/**
132
-	 * The index of the current result within the current chunk
133
-	 *
134
-	 * @var int
135
-	 */
136
-	private $resultIndex = 0;
137
-
138
-	/**
139
-	 * The index of the current chunk
140
-	 *
141
-	 * @var int
142
-	 */
143
-	private $chunkIndex = 0;
144
-
145
-	/**
146
-	 * The number of results iterated through
147
-	 *
148
-	 * @var int
149
-	 */
150
-	private $processedResults = 0;
151
-
152
-	/**
153
-	 * Is the getter a valid callback
154
-	 *
155
-	 * @var bool
156
-	 */
157
-	private $validGetter = null;
158
-
159
-	/**
160
-	 * The result of running all entities through the callback function.
161
-	 *
162
-	 * @var mixed
163
-	 */
164
-	public $callbackResult = null;
165
-
166
-	/**
167
-	 * If false, offset will not be incremented. This is used for callbacks/loops that delete.
168
-	 *
169
-	 * @var bool
170
-	 */
171
-	private $incrementOffset = true;
172
-
173
-	/**
174
-	 * Entities that could not be instantiated during a fetch
175
-	 *
176
-	 * @var \stdClass[]
177
-	 */
178
-	private $incompleteEntities = array();
179
-
180
-	/**
181
-	 * Total number of incomplete entities fetched
182
-	 *
183
-	 * @var int
184
-	 */
185
-	private $totalIncompletes = 0;
186
-
187
-	/**
188
-	 * Batches operations on any elgg_get_*() or compatible function that supports
189
-	 * an options array.
190
-	 *
191
-	 * Instead of returning all objects in memory, it goes through $chunk_size
192
-	 * objects, then requests more from the server.  This avoids OOM errors.
193
-	 *
194
-	 * @param string $getter     The function used to get objects.  Usually
195
-	 *                           an elgg_get_*() function, but can be any valid PHP callback.
196
-	 * @param array  $options    The options array to pass to the getter function. If limit is
197
-	 *                           not set, 10 is used as the default. In most cases that is not
198
-	 *                           what you want.
199
-	 * @param mixed  $callback   An optional callback function that all results will be passed
200
-	 *                           to upon load.  The callback needs to accept $result, $getter,
201
-	 *                           $options.
202
-	 * @param int    $chunk_size The number of entities to pull in before requesting more.
203
-	 *                           You have to balance this between running out of memory in PHP
204
-	 *                           and hitting the db server too often.
205
-	 * @param bool   $inc_offset Increment the offset on each fetch. This must be false for
206
-	 *                           callbacks that delete rows. You can set this after the
207
-	 *                           object is created with {@link \ElggBatch::setIncrementOffset()}.
208
-	 */
209
-	public function __construct($getter, $options, $callback = null, $chunk_size = 25,
210
-			$inc_offset = true) {
75
+    /**
76
+     * The objects to iterate over.
77
+     *
78
+     * @var array
79
+     */
80
+    private $results = array();
81
+
82
+    /**
83
+     * The function used to get results.
84
+     *
85
+     * @var callable
86
+     */
87
+    private $getter = null;
88
+
89
+    /**
90
+     * The given $options to alter and pass to the getter.
91
+     *
92
+     * @var array
93
+     */
94
+    private $options = array();
95
+
96
+    /**
97
+     * The number of results to grab at a time.
98
+     *
99
+     * @var int
100
+     */
101
+    private $chunkSize = 25;
102
+
103
+    /**
104
+     * A callback function to pass results through.
105
+     *
106
+     * @var callable
107
+     */
108
+    private $callback = null;
109
+
110
+    /**
111
+     * Start after this many results.
112
+     *
113
+     * @var int
114
+     */
115
+    private $offset = 0;
116
+
117
+    /**
118
+     * Stop after this many results.
119
+     *
120
+     * @var int
121
+     */
122
+    private $limit = 0;
123
+
124
+    /**
125
+     * Number of processed results.
126
+     *
127
+     * @var int
128
+     */
129
+    private $retrievedResults = 0;
130
+
131
+    /**
132
+     * The index of the current result within the current chunk
133
+     *
134
+     * @var int
135
+     */
136
+    private $resultIndex = 0;
137
+
138
+    /**
139
+     * The index of the current chunk
140
+     *
141
+     * @var int
142
+     */
143
+    private $chunkIndex = 0;
144
+
145
+    /**
146
+     * The number of results iterated through
147
+     *
148
+     * @var int
149
+     */
150
+    private $processedResults = 0;
151
+
152
+    /**
153
+     * Is the getter a valid callback
154
+     *
155
+     * @var bool
156
+     */
157
+    private $validGetter = null;
158
+
159
+    /**
160
+     * The result of running all entities through the callback function.
161
+     *
162
+     * @var mixed
163
+     */
164
+    public $callbackResult = null;
165
+
166
+    /**
167
+     * If false, offset will not be incremented. This is used for callbacks/loops that delete.
168
+     *
169
+     * @var bool
170
+     */
171
+    private $incrementOffset = true;
172
+
173
+    /**
174
+     * Entities that could not be instantiated during a fetch
175
+     *
176
+     * @var \stdClass[]
177
+     */
178
+    private $incompleteEntities = array();
179
+
180
+    /**
181
+     * Total number of incomplete entities fetched
182
+     *
183
+     * @var int
184
+     */
185
+    private $totalIncompletes = 0;
186
+
187
+    /**
188
+     * Batches operations on any elgg_get_*() or compatible function that supports
189
+     * an options array.
190
+     *
191
+     * Instead of returning all objects in memory, it goes through $chunk_size
192
+     * objects, then requests more from the server.  This avoids OOM errors.
193
+     *
194
+     * @param string $getter     The function used to get objects.  Usually
195
+     *                           an elgg_get_*() function, but can be any valid PHP callback.
196
+     * @param array  $options    The options array to pass to the getter function. If limit is
197
+     *                           not set, 10 is used as the default. In most cases that is not
198
+     *                           what you want.
199
+     * @param mixed  $callback   An optional callback function that all results will be passed
200
+     *                           to upon load.  The callback needs to accept $result, $getter,
201
+     *                           $options.
202
+     * @param int    $chunk_size The number of entities to pull in before requesting more.
203
+     *                           You have to balance this between running out of memory in PHP
204
+     *                           and hitting the db server too often.
205
+     * @param bool   $inc_offset Increment the offset on each fetch. This must be false for
206
+     *                           callbacks that delete rows. You can set this after the
207
+     *                           object is created with {@link \ElggBatch::setIncrementOffset()}.
208
+     */
209
+    public function __construct($getter, $options, $callback = null, $chunk_size = 25,
210
+            $inc_offset = true) {
211 211
 		
212
-		$this->getter = $getter;
213
-		$this->options = $options;
214
-		$this->callback = $callback;
215
-		$this->chunkSize = $chunk_size;
216
-		$this->setIncrementOffset($inc_offset);
217
-
218
-		if ($this->chunkSize <= 0) {
219
-			$this->chunkSize = 25;
220
-		}
221
-
222
-		// store these so we can compare later
223
-		$this->offset = elgg_extract('offset', $options, 0);
224
-		$this->limit = elgg_extract('limit', $options, elgg_get_config('default_limit'));
225
-
226
-		// if passed a callback, create a new \ElggBatch with the same options
227
-		// and pass each to the callback.
228
-		if ($callback && is_callable($callback)) {
229
-			$batch = new \ElggBatch($getter, $options, null, $chunk_size, $inc_offset);
230
-
231
-			$all_results = null;
232
-
233
-			foreach ($batch as $result) {
234
-				$result = call_user_func($callback, $result, $getter, $options);
235
-
236
-				if (!isset($all_results)) {
237
-					if ($result === true || $result === false || $result === null) {
238
-						$all_results = $result;
239
-					} else {
240
-						$all_results = array();
241
-					}
242
-				}
243
-
244
-				if (($result === true || $result === false || $result === null) && !is_array($all_results)) {
245
-					$all_results = $result && $all_results;
246
-				} else {
247
-					$all_results[] = $result;
248
-				}
249
-			}
250
-
251
-			$this->callbackResult = $all_results;
252
-		}
253
-	}
254
-
255
-	/**
256
-	 * Tell the process that an entity was incomplete during a fetch
257
-	 *
258
-	 * @param \stdClass $row
259
-	 *
260
-	 * @access private
261
-	 */
262
-	public function reportIncompleteEntity(\stdClass $row) {
263
-		$this->incompleteEntities[] = $row;
264
-	}
265
-
266
-	/**
267
-	 * Fetches the next chunk of results
268
-	 *
269
-	 * @return bool
270
-	 */
271
-	private function getNextResultsChunk() {
272
-
273
-		// always reset results.
274
-		$this->results = array();
275
-
276
-		if (!isset($this->validGetter)) {
277
-			$this->validGetter = is_callable($this->getter);
278
-		}
279
-
280
-		if (!$this->validGetter) {
281
-			return false;
282
-		}
283
-
284
-		$limit = $this->chunkSize;
285
-
286
-		// if someone passed limit = 0 they want everything.
287
-		if ($this->limit != 0) {
288
-			if ($this->retrievedResults >= $this->limit) {
289
-				return false;
290
-			}
291
-
292
-			// if original limit < chunk size, set limit to original limit
293
-			// else if the number of results we'll fetch if greater than the original limit
294
-			if ($this->limit < $this->chunkSize) {
295
-				$limit = $this->limit;
296
-			} elseif ($this->retrievedResults + $this->chunkSize > $this->limit) {
297
-				// set the limit to the number of results remaining in the original limit
298
-				$limit = $this->limit - $this->retrievedResults;
299
-			}
300
-		}
301
-
302
-		if ($this->incrementOffset) {
303
-			$offset = $this->offset + $this->retrievedResults;
304
-		} else {
305
-			$offset = $this->offset + $this->totalIncompletes;
306
-		}
307
-
308
-		$current_options = array(
309
-			'limit' => $limit,
310
-			'offset' => $offset,
311
-			'__ElggBatch' => $this,
312
-		);
313
-
314
-		$options = array_merge($this->options, $current_options);
315
-
316
-		$this->incompleteEntities = array();
317
-		$this->results = call_user_func($this->getter, $options);
318
-
319
-		// batch result sets tend to be large; we don't want to cache these.
320
-		_elgg_services()->db->disableQueryCache();
321
-
322
-		$num_results = count($this->results);
323
-		$num_incomplete = count($this->incompleteEntities);
324
-
325
-		$this->totalIncompletes += $num_incomplete;
326
-
327
-		if ($this->incompleteEntities) {
328
-			// pad the front of the results with nulls representing the incompletes
329
-			array_splice($this->results, 0, 0, array_pad(array(), $num_incomplete, null));
330
-			// ...and skip past them
331
-			reset($this->results);
332
-			for ($i = 0; $i < $num_incomplete; $i++) {
333
-				next($this->results);
334
-			}
335
-		}
336
-
337
-		if ($this->results) {
338
-			$this->chunkIndex++;
339
-
340
-			// let the system know we've jumped past the nulls
341
-			$this->resultIndex = $num_incomplete;
342
-
343
-			$this->retrievedResults += ($num_results + $num_incomplete);
344
-			if ($num_results == 0) {
345
-				// This fetch was *all* incompletes! We need to fetch until we can either
346
-				// offer at least one row to iterate over, or give up.
347
-				return $this->getNextResultsChunk();
348
-			}
349
-			_elgg_services()->db->enableQueryCache();
350
-			return true;
351
-		} else {
352
-			_elgg_services()->db->enableQueryCache();
353
-			return false;
354
-		}
355
-	}
356
-
357
-	/**
358
-	 * Increment the offset from the original options array? Setting to
359
-	 * false is required for callbacks that delete rows.
360
-	 *
361
-	 * @param bool $increment Set to false when deleting data
362
-	 * @return void
363
-	 */
364
-	public function setIncrementOffset($increment = true) {
365
-		$this->incrementOffset = (bool) $increment;
366
-	}
367
-
368
-	/**
369
-	 * Implements Iterator
370
-	 */
371
-
372
-	/**
373
-	 * {@inheritdoc}
374
-	 */
375
-	public function rewind() {
376
-		$this->resultIndex = 0;
377
-		$this->retrievedResults = 0;
378
-		$this->processedResults = 0;
379
-
380
-		// only grab results if we haven't yet or we're crossing chunks
381
-		if ($this->chunkIndex == 0 || $this->limit > $this->chunkSize) {
382
-			$this->chunkIndex = 0;
383
-			$this->getNextResultsChunk();
384
-		}
385
-	}
386
-
387
-	/**
388
-	 * {@inheritdoc}
389
-	 */
390
-	public function current() {
391
-		return current($this->results);
392
-	}
393
-
394
-	/**
395
-	 * {@inheritdoc}
396
-	 */
397
-	public function key() {
398
-		return $this->processedResults;
399
-	}
400
-
401
-	/**
402
-	 * {@inheritdoc}
403
-	 */
404
-	public function next() {
405
-		// if we'll be at the end.
406
-		if (($this->processedResults + 1) >= $this->limit && $this->limit > 0) {
407
-			$this->results = array();
408
-			return false;
409
-		}
410
-
411
-		// if we'll need new results.
412
-		if (($this->resultIndex + 1) >= $this->chunkSize) {
413
-			if (!$this->getNextResultsChunk()) {
414
-				$this->results = array();
415
-				return false;
416
-			}
417
-
418
-			$result = current($this->results);
419
-		} else {
420
-			// the function above resets the indexes, so only inc if not
421
-			// getting new set
422
-			$this->resultIndex++;
423
-			$result = next($this->results);
424
-		}
425
-
426
-		$this->processedResults++;
427
-		return $result;
428
-	}
429
-
430
-	/**
431
-	 * {@inheritdoc}
432
-	 */
433
-	public function valid() {
434
-		if (!is_array($this->results)) {
435
-			return false;
436
-		}
437
-		$key = key($this->results);
438
-		return ($key !== null && $key !== false);
439
-	}
440
-
441
-	/**
442
-	 * Count the total results available at this moment.
443
-	 *
444
-	 * As this performs a separate query, the count returned may not match the number of results you can
445
-	 * fetch via iteration on a very active DB.
446
-	 *
447
-	 * @see Countable::count()
448
-	 * @return int
449
-	 */
450
-	public function count() {
451
-		if (!is_callable($this->getter)) {
452
-			$inspector = new \Elgg\Debug\Inspector();
453
-			throw new RuntimeException("Getter is not callable: " . $inspector->describeCallable($this->getter));
454
-		}
455
-
456
-		$options = array_merge($this->options, ['count' => true]);
457
-
458
-		return call_user_func($this->getter, $options);
459
-	}
460
-
461
-	/**
462
-	 * Read a property
463
-	 *
464
-	 * @param string $name
465
-	 * @return mixed
466
-	 * @access private
467
-	 */
468
-	public function __get($name) {
469
-		if ($name === 'options') {
470
-			elgg_deprecated_notice("The ElggBatch 'options' property is private and should not be used", "2.3");
471
-			return $this->options;
472
-		}
473
-
474
-		_elgg_services()->logger->warn("Read of non-existent property '$name'");
475
-		return null;
476
-	}
477
-
478
-	/**
479
-	 * Write a property
480
-	 *
481
-	 * @param string $name
482
-	 * @param mixed  $value
483
-	 * @return void
484
-	 * @access private
485
-	 */
486
-	public function __set($name, $value) {
487
-		if ($name === 'options') {
488
-			elgg_deprecated_notice("The ElggBatch 'options' property is private and should not be used", "2.3");
489
-		}
490
-
491
-		$this->{$name} = $value;
492
-	}
212
+        $this->getter = $getter;
213
+        $this->options = $options;
214
+        $this->callback = $callback;
215
+        $this->chunkSize = $chunk_size;
216
+        $this->setIncrementOffset($inc_offset);
217
+
218
+        if ($this->chunkSize <= 0) {
219
+            $this->chunkSize = 25;
220
+        }
221
+
222
+        // store these so we can compare later
223
+        $this->offset = elgg_extract('offset', $options, 0);
224
+        $this->limit = elgg_extract('limit', $options, elgg_get_config('default_limit'));
225
+
226
+        // if passed a callback, create a new \ElggBatch with the same options
227
+        // and pass each to the callback.
228
+        if ($callback && is_callable($callback)) {
229
+            $batch = new \ElggBatch($getter, $options, null, $chunk_size, $inc_offset);
230
+
231
+            $all_results = null;
232
+
233
+            foreach ($batch as $result) {
234
+                $result = call_user_func($callback, $result, $getter, $options);
235
+
236
+                if (!isset($all_results)) {
237
+                    if ($result === true || $result === false || $result === null) {
238
+                        $all_results = $result;
239
+                    } else {
240
+                        $all_results = array();
241
+                    }
242
+                }
243
+
244
+                if (($result === true || $result === false || $result === null) && !is_array($all_results)) {
245
+                    $all_results = $result && $all_results;
246
+                } else {
247
+                    $all_results[] = $result;
248
+                }
249
+            }
250
+
251
+            $this->callbackResult = $all_results;
252
+        }
253
+    }
254
+
255
+    /**
256
+     * Tell the process that an entity was incomplete during a fetch
257
+     *
258
+     * @param \stdClass $row
259
+     *
260
+     * @access private
261
+     */
262
+    public function reportIncompleteEntity(\stdClass $row) {
263
+        $this->incompleteEntities[] = $row;
264
+    }
265
+
266
+    /**
267
+     * Fetches the next chunk of results
268
+     *
269
+     * @return bool
270
+     */
271
+    private function getNextResultsChunk() {
272
+
273
+        // always reset results.
274
+        $this->results = array();
275
+
276
+        if (!isset($this->validGetter)) {
277
+            $this->validGetter = is_callable($this->getter);
278
+        }
279
+
280
+        if (!$this->validGetter) {
281
+            return false;
282
+        }
283
+
284
+        $limit = $this->chunkSize;
285
+
286
+        // if someone passed limit = 0 they want everything.
287
+        if ($this->limit != 0) {
288
+            if ($this->retrievedResults >= $this->limit) {
289
+                return false;
290
+            }
291
+
292
+            // if original limit < chunk size, set limit to original limit
293
+            // else if the number of results we'll fetch if greater than the original limit
294
+            if ($this->limit < $this->chunkSize) {
295
+                $limit = $this->limit;
296
+            } elseif ($this->retrievedResults + $this->chunkSize > $this->limit) {
297
+                // set the limit to the number of results remaining in the original limit
298
+                $limit = $this->limit - $this->retrievedResults;
299
+            }
300
+        }
301
+
302
+        if ($this->incrementOffset) {
303
+            $offset = $this->offset + $this->retrievedResults;
304
+        } else {
305
+            $offset = $this->offset + $this->totalIncompletes;
306
+        }
307
+
308
+        $current_options = array(
309
+            'limit' => $limit,
310
+            'offset' => $offset,
311
+            '__ElggBatch' => $this,
312
+        );
313
+
314
+        $options = array_merge($this->options, $current_options);
315
+
316
+        $this->incompleteEntities = array();
317
+        $this->results = call_user_func($this->getter, $options);
318
+
319
+        // batch result sets tend to be large; we don't want to cache these.
320
+        _elgg_services()->db->disableQueryCache();
321
+
322
+        $num_results = count($this->results);
323
+        $num_incomplete = count($this->incompleteEntities);
324
+
325
+        $this->totalIncompletes += $num_incomplete;
326
+
327
+        if ($this->incompleteEntities) {
328
+            // pad the front of the results with nulls representing the incompletes
329
+            array_splice($this->results, 0, 0, array_pad(array(), $num_incomplete, null));
330
+            // ...and skip past them
331
+            reset($this->results);
332
+            for ($i = 0; $i < $num_incomplete; $i++) {
333
+                next($this->results);
334
+            }
335
+        }
336
+
337
+        if ($this->results) {
338
+            $this->chunkIndex++;
339
+
340
+            // let the system know we've jumped past the nulls
341
+            $this->resultIndex = $num_incomplete;
342
+
343
+            $this->retrievedResults += ($num_results + $num_incomplete);
344
+            if ($num_results == 0) {
345
+                // This fetch was *all* incompletes! We need to fetch until we can either
346
+                // offer at least one row to iterate over, or give up.
347
+                return $this->getNextResultsChunk();
348
+            }
349
+            _elgg_services()->db->enableQueryCache();
350
+            return true;
351
+        } else {
352
+            _elgg_services()->db->enableQueryCache();
353
+            return false;
354
+        }
355
+    }
356
+
357
+    /**
358
+     * Increment the offset from the original options array? Setting to
359
+     * false is required for callbacks that delete rows.
360
+     *
361
+     * @param bool $increment Set to false when deleting data
362
+     * @return void
363
+     */
364
+    public function setIncrementOffset($increment = true) {
365
+        $this->incrementOffset = (bool) $increment;
366
+    }
367
+
368
+    /**
369
+     * Implements Iterator
370
+     */
371
+
372
+    /**
373
+     * {@inheritdoc}
374
+     */
375
+    public function rewind() {
376
+        $this->resultIndex = 0;
377
+        $this->retrievedResults = 0;
378
+        $this->processedResults = 0;
379
+
380
+        // only grab results if we haven't yet or we're crossing chunks
381
+        if ($this->chunkIndex == 0 || $this->limit > $this->chunkSize) {
382
+            $this->chunkIndex = 0;
383
+            $this->getNextResultsChunk();
384
+        }
385
+    }
386
+
387
+    /**
388
+     * {@inheritdoc}
389
+     */
390
+    public function current() {
391
+        return current($this->results);
392
+    }
393
+
394
+    /**
395
+     * {@inheritdoc}
396
+     */
397
+    public function key() {
398
+        return $this->processedResults;
399
+    }
400
+
401
+    /**
402
+     * {@inheritdoc}
403
+     */
404
+    public function next() {
405
+        // if we'll be at the end.
406
+        if (($this->processedResults + 1) >= $this->limit && $this->limit > 0) {
407
+            $this->results = array();
408
+            return false;
409
+        }
410
+
411
+        // if we'll need new results.
412
+        if (($this->resultIndex + 1) >= $this->chunkSize) {
413
+            if (!$this->getNextResultsChunk()) {
414
+                $this->results = array();
415
+                return false;
416
+            }
417
+
418
+            $result = current($this->results);
419
+        } else {
420
+            // the function above resets the indexes, so only inc if not
421
+            // getting new set
422
+            $this->resultIndex++;
423
+            $result = next($this->results);
424
+        }
425
+
426
+        $this->processedResults++;
427
+        return $result;
428
+    }
429
+
430
+    /**
431
+     * {@inheritdoc}
432
+     */
433
+    public function valid() {
434
+        if (!is_array($this->results)) {
435
+            return false;
436
+        }
437
+        $key = key($this->results);
438
+        return ($key !== null && $key !== false);
439
+    }
440
+
441
+    /**
442
+     * Count the total results available at this moment.
443
+     *
444
+     * As this performs a separate query, the count returned may not match the number of results you can
445
+     * fetch via iteration on a very active DB.
446
+     *
447
+     * @see Countable::count()
448
+     * @return int
449
+     */
450
+    public function count() {
451
+        if (!is_callable($this->getter)) {
452
+            $inspector = new \Elgg\Debug\Inspector();
453
+            throw new RuntimeException("Getter is not callable: " . $inspector->describeCallable($this->getter));
454
+        }
455
+
456
+        $options = array_merge($this->options, ['count' => true]);
457
+
458
+        return call_user_func($this->getter, $options);
459
+    }
460
+
461
+    /**
462
+     * Read a property
463
+     *
464
+     * @param string $name
465
+     * @return mixed
466
+     * @access private
467
+     */
468
+    public function __get($name) {
469
+        if ($name === 'options') {
470
+            elgg_deprecated_notice("The ElggBatch 'options' property is private and should not be used", "2.3");
471
+            return $this->options;
472
+        }
473
+
474
+        _elgg_services()->logger->warn("Read of non-existent property '$name'");
475
+        return null;
476
+    }
477
+
478
+    /**
479
+     * Write a property
480
+     *
481
+     * @param string $name
482
+     * @param mixed  $value
483
+     * @return void
484
+     * @access private
485
+     */
486
+    public function __set($name, $value) {
487
+        if ($name === 'options') {
488
+            elgg_deprecated_notice("The ElggBatch 'options' property is private and should not be used", "2.3");
489
+        }
490
+
491
+        $this->{$name} = $value;
492
+    }
493 493
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -450,7 +450,7 @@
 block discarded – undo
450 450
 	public function count() {
451 451
 		if (!is_callable($this->getter)) {
452 452
 			$inspector = new \Elgg\Debug\Inspector();
453
-			throw new RuntimeException("Getter is not callable: " . $inspector->describeCallable($this->getter));
453
+			throw new RuntimeException("Getter is not callable: ".$inspector->describeCallable($this->getter));
454 454
 		}
455 455
 
456 456
 		$options = array_merge($this->options, ['count' => true]);
Please login to merge, or discard this patch.