Test Failed
Push — master ( c2873c...a077d1 )
by Jeroen
01:35
created
engine/lib/pam.php 1 patch
Indentation   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -37,22 +37,22 @@  discard block
 block discarded – undo
37 37
  * @return bool
38 38
  */
39 39
 function register_pam_handler($handler, $importance = "sufficient", $policy = "user") {
40
-	// setup array for this type of pam if not already set
41
-	if (!isset(\ElggPAM::$_handlers[$policy])) {
42
-		\ElggPAM::$_handlers[$policy] = [];
43
-	}
40
+    // setup array for this type of pam if not already set
41
+    if (!isset(\ElggPAM::$_handlers[$policy])) {
42
+        \ElggPAM::$_handlers[$policy] = [];
43
+    }
44 44
 
45
-	// @todo remove requirement that $handle be a global function
46
-	if (is_string($handler) && is_callable($handler, true)) {
47
-		\ElggPAM::$_handlers[$policy][$handler] = new \stdClass;
45
+    // @todo remove requirement that $handle be a global function
46
+    if (is_string($handler) && is_callable($handler, true)) {
47
+        \ElggPAM::$_handlers[$policy][$handler] = new \stdClass;
48 48
 
49
-		\ElggPAM::$_handlers[$policy][$handler]->handler = $handler;
50
-		\ElggPAM::$_handlers[$policy][$handler]->importance = strtolower($importance);
49
+        \ElggPAM::$_handlers[$policy][$handler]->handler = $handler;
50
+        \ElggPAM::$_handlers[$policy][$handler]->importance = strtolower($importance);
51 51
 
52
-		return true;
53
-	}
52
+        return true;
53
+    }
54 54
 
55
-	return false;
55
+    return false;
56 56
 }
57 57
 
58 58
 /**
@@ -65,5 +65,5 @@  discard block
 block discarded – undo
65 65
  * @since 1.7.0
66 66
  */
67 67
 function unregister_pam_handler($handler, $policy = "user") {
68
-	unset(\ElggPAM::$_handlers[$policy][$handler]);
68
+    unset(\ElggPAM::$_handlers[$policy][$handler]);
69 69
 }
Please login to merge, or discard this patch.
engine/classes/ElggPAM.php 1 patch
Indentation   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -5,105 +5,105 @@
 block discarded – undo
5 5
  */
6 6
 class ElggPAM {
7 7
 
8
-	/**
9
-	 * @var array
10
-	 * @access private
11
-	 * @todo move state into a PAM service
12
-	 */
13
-	public static $_handlers = [];
8
+    /**
9
+     * @var array
10
+     * @access private
11
+     * @todo move state into a PAM service
12
+     */
13
+    public static $_handlers = [];
14 14
 
15
-	/**
16
-	 * @var string PAM policy type: user, api or plugin-defined policies
17
-	 */
18
-	protected $policy;
15
+    /**
16
+     * @var string PAM policy type: user, api or plugin-defined policies
17
+     */
18
+    protected $policy;
19 19
 
20
-	/**
21
-	 * @var array Failure mesages
22
-	 */
23
-	protected $messages;
20
+    /**
21
+     * @var array Failure mesages
22
+     */
23
+    protected $messages;
24 24
 
25
-	/**
26
-	 * \ElggPAM constructor
27
-	 *
28
-	 * @param string $policy PAM policy type: user, api, or plugin-defined policies
29
-	 */
30
-	public function __construct($policy) {
31
-		$this->policy = $policy;
32
-		$this->messages = ['sufficient' => [], 'required' => []];
33
-	}
25
+    /**
26
+     * \ElggPAM constructor
27
+     *
28
+     * @param string $policy PAM policy type: user, api, or plugin-defined policies
29
+     */
30
+    public function __construct($policy) {
31
+        $this->policy = $policy;
32
+        $this->messages = ['sufficient' => [], 'required' => []];
33
+    }
34 34
 
35
-	/**
36
-	 * Authenticate a set of credentials against a policy
37
-	 * This function will process all registered PAM handlers or stop when the first
38
-	 * handler fails. A handler fails by either returning false or throwing an
39
-	 * exception. The advantage of throwing an exception is that it returns a message
40
-	 * that can be passed to the user. The processing order of the handlers is
41
-	 * determined by the order that they were registered.
42
-	 *
43
-	 * If $credentials are provided, the PAM handler should authenticate using the
44
-	 * provided credentials. If not, then credentials should be prompted for or
45
-	 * otherwise retrieved (eg from the HTTP header or $_SESSION).
46
-	 *
47
-	 * @param array $credentials Credentials array dependant on policy type
48
-	 * @return bool
49
-	 */
50
-	public function authenticate($credentials = []) {
51
-		if (!isset(self::$_handlers[$this->policy]) ||
52
-			!is_array(self::$_handlers[$this->policy])) {
53
-			return false;
54
-		}
35
+    /**
36
+     * Authenticate a set of credentials against a policy
37
+     * This function will process all registered PAM handlers or stop when the first
38
+     * handler fails. A handler fails by either returning false or throwing an
39
+     * exception. The advantage of throwing an exception is that it returns a message
40
+     * that can be passed to the user. The processing order of the handlers is
41
+     * determined by the order that they were registered.
42
+     *
43
+     * If $credentials are provided, the PAM handler should authenticate using the
44
+     * provided credentials. If not, then credentials should be prompted for or
45
+     * otherwise retrieved (eg from the HTTP header or $_SESSION).
46
+     *
47
+     * @param array $credentials Credentials array dependant on policy type
48
+     * @return bool
49
+     */
50
+    public function authenticate($credentials = []) {
51
+        if (!isset(self::$_handlers[$this->policy]) ||
52
+            !is_array(self::$_handlers[$this->policy])) {
53
+            return false;
54
+        }
55 55
 
56
-		$authenticated = false;
56
+        $authenticated = false;
57 57
 
58
-		foreach (self::$_handlers[$this->policy] as $v) {
59
-			$handler = $v->handler;
60
-			if (!is_callable($handler)) {
61
-				continue;
62
-			}
63
-			/* @var callable $handler */
58
+        foreach (self::$_handlers[$this->policy] as $v) {
59
+            $handler = $v->handler;
60
+            if (!is_callable($handler)) {
61
+                continue;
62
+            }
63
+            /* @var callable $handler */
64 64
 
65
-			$importance = $v->importance;
65
+            $importance = $v->importance;
66 66
 
67
-			try {
68
-				// Execute the handler
69
-				// @todo don't assume $handler is a global function
70
-				$result = call_user_func($handler, $credentials);
71
-				if ($result) {
72
-					$authenticated = true;
73
-				} elseif ($result === false) {
74
-					if ($importance == 'required') {
75
-						$this->messages['required'][] = "$handler:failed";
76
-						return false;
77
-					} else {
78
-						$this->messages['sufficient'][] = "$handler:failed";
79
-					}
80
-				}
81
-			} catch (Exception $e) {
82
-				if ($importance == 'required') {
83
-					$this->messages['required'][] = $e->getMessage();
84
-					return false;
85
-				} else {
86
-					$this->messages['sufficient'][] = $e->getMessage();
87
-				}
88
-			}
89
-		}
67
+            try {
68
+                // Execute the handler
69
+                // @todo don't assume $handler is a global function
70
+                $result = call_user_func($handler, $credentials);
71
+                if ($result) {
72
+                    $authenticated = true;
73
+                } elseif ($result === false) {
74
+                    if ($importance == 'required') {
75
+                        $this->messages['required'][] = "$handler:failed";
76
+                        return false;
77
+                    } else {
78
+                        $this->messages['sufficient'][] = "$handler:failed";
79
+                    }
80
+                }
81
+            } catch (Exception $e) {
82
+                if ($importance == 'required') {
83
+                    $this->messages['required'][] = $e->getMessage();
84
+                    return false;
85
+                } else {
86
+                    $this->messages['sufficient'][] = $e->getMessage();
87
+                }
88
+            }
89
+        }
90 90
 
91
-		return $authenticated;
92
-	}
91
+        return $authenticated;
92
+    }
93 93
 
94
-	/**
95
-	 * Get a failure message to display to user
96
-	 *
97
-	 * @return string
98
-	 */
99
-	public function getFailureMessage() {
100
-		$message = _elgg_services()->translator->translate('auth:nopams');
101
-		if (!empty($this->messages['required'])) {
102
-			$message = $this->messages['required'][0];
103
-		} elseif (!empty($this->messages['sufficient'])) {
104
-			$message = $this->messages['sufficient'][0];
105
-		}
94
+    /**
95
+     * Get a failure message to display to user
96
+     *
97
+     * @return string
98
+     */
99
+    public function getFailureMessage() {
100
+        $message = _elgg_services()->translator->translate('auth:nopams');
101
+        if (!empty($this->messages['required'])) {
102
+            $message = $this->messages['required'][0];
103
+        } elseif (!empty($this->messages['sufficient'])) {
104
+            $message = $this->messages['sufficient'][0];
105
+        }
106 106
 
107
-		return _elgg_services()->hooks->trigger('fail', 'auth', $this->messages, $message);
108
-	}
107
+        return _elgg_services()->hooks->trigger('fail', 'auth', $this->messages, $message);
108
+    }
109 109
 }
Please login to merge, or discard this patch.
engine/classes/Elgg/Assets/ExternalFiles.php 2 patches
Indentation   +227 added lines, -227 removed lines patch added patch discarded remove patch
@@ -11,231 +11,231 @@
 block discarded – undo
11 11
  */
12 12
 class ExternalFiles {
13 13
 
14
-	/**
15
-	 * @var ElggPriorityList[]
16
-	 */
17
-	protected $externals = [];
18
-
19
-	/**
20
-	 * @var array
21
-	 */
22
-	protected $externals_map = [];
23
-
24
-	/**
25
-	 * Core registration function for external files
26
-	 *
27
-	 * @param string $type     Type of external resource (js or css)
28
-	 * @param string $name     Identifier used as key
29
-	 * @param string $url      URL
30
-	 * @param string $location Location in the page to include the file
31
-	 * @param int    $priority Loading priority of the file
32
-	 *
33
-	 * @return bool
34
-	 */
35
-	public function register($type, $name, $url, $location, $priority = 500) {
36
-		if (empty($name) || empty($url)) {
37
-			return false;
38
-		}
39
-	
40
-		$url = elgg_normalize_url($url);
41
-
42
-		$this->setupType($type);
43
-	
44
-		$name = trim(strtolower($name));
45
-	
46
-		// normalize bogus priorities, but allow empty, null, and false to be defaults.
47
-		if (!is_numeric($priority)) {
48
-			$priority = 500;
49
-		}
50
-	
51
-		// no negative priorities right now.
52
-		$priority = max((int) $priority, 0);
53
-	
54
-		$item = elgg_extract($name, $this->externals_map[$type]);
55
-	
56
-		if ($item) {
57
-			// updating a registered item
58
-			// don't update loaded because it could already be set
59
-			$item->url = $url;
60
-			$item->location = $location;
61
-	
62
-			// if loaded before registered, that means it hasn't been added to the list yet
63
-			if ($this->externals[$type]->contains($item)) {
64
-				$priority = $this->externals[$type]->move($item, $priority);
65
-			} else {
66
-				$priority = $this->externals[$type]->add($item, $priority);
67
-			}
68
-		} else {
69
-			$item = (object) [
70
-				'loaded' => false,
71
-				'url' => $url,
72
-				'location' => $location,
73
-			];
74
-			$priority = $this->externals[$type]->add($item, $priority);
75
-		}
76
-
77
-		$this->externals_map[$type][$name] = $item;
78
-	
79
-		return $priority !== false;
80
-	}
81
-	
82
-	/**
83
-	 * Unregister an external file
84
-	 *
85
-	 * @param string $type Type of file: js or css
86
-	 * @param string $name The identifier of the file
87
-	 *
88
-	 * @return bool
89
-	 */
90
-	public function unregister($type, $name) {
91
-		$this->setupType($type);
92
-	
93
-		$name = trim(strtolower($name));
94
-		$item = elgg_extract($name, $this->externals_map[$type]);
95
-	
96
-		if ($item) {
97
-			unset($this->externals_map[$type][$name]);
98
-			return $this->externals[$type]->remove($item);
99
-		}
100
-	
101
-		return false;
102
-	}
103
-
104
-	/**
105
-	 * Get metadata for a registered file
106
-	 *
107
-	 * @param string $type
108
-	 * @param string $name
109
-	 *
110
-	 * @return \stdClass|null
111
-	 */
112
-	public function getFile($type, $name) {
113
-		$this->setupType($type);
114
-
115
-		$name = trim(strtolower($name));
116
-		if (!isset($this->externals_map[$type][$name])) {
117
-			return null;
118
-		}
119
-
120
-		$item = $this->externals_map[$type][$name];
121
-		$priority = $this->externals[$type]->getPriority($item);
122
-
123
-		// don't allow internal properties to be altered
124
-		$clone = clone $item;
125
-		$clone->priority = $priority;
126
-
127
-		return $clone;
128
-	}
129
-	
130
-	/**
131
-	 * Load an external resource for use on this page
132
-	 *
133
-	 * @param string $type Type of file: js or css
134
-	 * @param string $name The identifier for the file
135
-	 *
136
-	 * @return void
137
-	 */
138
-	public function load($type, $name) {
139
-		$this->setupType($type);
140
-	
141
-		$name = trim(strtolower($name));
142
-	
143
-		$item = elgg_extract($name, $this->externals_map[$type]);
144
-	
145
-		if ($item) {
146
-			// update a registered item
147
-			$item->loaded = true;
148
-		} else {
149
-			$item = (object) [
150
-				'loaded' => true,
151
-				'url' => '',
152
-				'location' => '',
153
-			];
154
-			if (elgg_view_exists($name)) {
155
-				$item->url = elgg_get_simplecache_url($name);
156
-				$item->location = ($type == 'js') ? 'foot' : 'head';
157
-			}
158
-
159
-			$this->externals[$type]->add($item);
160
-			$this->externals_map[$type][$name] = $item;
161
-		}
162
-	}
163
-	
164
-	/**
165
-	 * Get external resource descriptors
166
-	 *
167
-	 * @param string $type     Type of file: js or css
168
-	 * @param string $location Page location
169
-	 *
170
-	 * @return string[] URLs of files to load
171
-	 */
172
-	public function getLoadedFiles($type, $location) {
173
-		if (!isset($this->externals[$type])) {
174
-			return [];
175
-		}
176
-
177
-		$items = $this->externals[$type]->getElements();
178
-
179
-		$items = array_filter($items, function($v) use ($location) {
180
-			return $v->loaded == true && $v->location == $location;
181
-		});
182
-		if ($items) {
183
-			array_walk($items, function(&$v, $k){
184
-				$v = $v->url;
185
-			});
186
-		}
187
-		return $items;
188
-	}
189
-
190
-	/**
191
-	 * Get registered file objects
192
-	 *
193
-	 * @param string $type     Type of file: js or css
194
-	 * @param string $location Page location
195
-	 *
196
-	 * @return \stdClass[]
197
-	 */
198
-	public function getRegisteredFiles($type, $location) {
199
-		if (!isset($this->externals[$type])) {
200
-			return [];
201
-		}
202
-
203
-		$ret = [];
204
-		$items = $this->externals[$type]->getElements();
205
-		$items = array_filter($items, function($v) use ($location) {
206
-			return ($v->location == $location);
207
-		});
208
-
209
-		foreach ($items as $item) {
210
-			$ret[] = clone $item;
211
-		}
212
-
213
-		return $ret;
214
-	}
215
-
216
-	/**
217
-	 * Unregister all files
218
-	 *
219
-	 * @return void
220
-	 */
221
-	public function reset() {
222
-		$this->externals = [];
223
-		$this->externals_map = [];
224
-	}
225
-	
226
-	/**
227
-	 * Bootstraps the externals data structure
228
-	 *
229
-	 * @param string $type The type of external, js or css.
230
-	 * @return void
231
-	 */
232
-	protected function setupType($type) {
233
-		if (!isset($this->externals[$type])) {
234
-			$this->externals[$type] = new \ElggPriorityList();
235
-		}
236
-	
237
-		if (!isset($this->externals_map[$type])) {
238
-			$this->externals_map[$type] = [];
239
-		}
240
-	}
14
+    /**
15
+     * @var ElggPriorityList[]
16
+     */
17
+    protected $externals = [];
18
+
19
+    /**
20
+     * @var array
21
+     */
22
+    protected $externals_map = [];
23
+
24
+    /**
25
+     * Core registration function for external files
26
+     *
27
+     * @param string $type     Type of external resource (js or css)
28
+     * @param string $name     Identifier used as key
29
+     * @param string $url      URL
30
+     * @param string $location Location in the page to include the file
31
+     * @param int    $priority Loading priority of the file
32
+     *
33
+     * @return bool
34
+     */
35
+    public function register($type, $name, $url, $location, $priority = 500) {
36
+        if (empty($name) || empty($url)) {
37
+            return false;
38
+        }
39
+	
40
+        $url = elgg_normalize_url($url);
41
+
42
+        $this->setupType($type);
43
+	
44
+        $name = trim(strtolower($name));
45
+	
46
+        // normalize bogus priorities, but allow empty, null, and false to be defaults.
47
+        if (!is_numeric($priority)) {
48
+            $priority = 500;
49
+        }
50
+	
51
+        // no negative priorities right now.
52
+        $priority = max((int) $priority, 0);
53
+	
54
+        $item = elgg_extract($name, $this->externals_map[$type]);
55
+	
56
+        if ($item) {
57
+            // updating a registered item
58
+            // don't update loaded because it could already be set
59
+            $item->url = $url;
60
+            $item->location = $location;
61
+	
62
+            // if loaded before registered, that means it hasn't been added to the list yet
63
+            if ($this->externals[$type]->contains($item)) {
64
+                $priority = $this->externals[$type]->move($item, $priority);
65
+            } else {
66
+                $priority = $this->externals[$type]->add($item, $priority);
67
+            }
68
+        } else {
69
+            $item = (object) [
70
+                'loaded' => false,
71
+                'url' => $url,
72
+                'location' => $location,
73
+            ];
74
+            $priority = $this->externals[$type]->add($item, $priority);
75
+        }
76
+
77
+        $this->externals_map[$type][$name] = $item;
78
+	
79
+        return $priority !== false;
80
+    }
81
+	
82
+    /**
83
+     * Unregister an external file
84
+     *
85
+     * @param string $type Type of file: js or css
86
+     * @param string $name The identifier of the file
87
+     *
88
+     * @return bool
89
+     */
90
+    public function unregister($type, $name) {
91
+        $this->setupType($type);
92
+	
93
+        $name = trim(strtolower($name));
94
+        $item = elgg_extract($name, $this->externals_map[$type]);
95
+	
96
+        if ($item) {
97
+            unset($this->externals_map[$type][$name]);
98
+            return $this->externals[$type]->remove($item);
99
+        }
100
+	
101
+        return false;
102
+    }
103
+
104
+    /**
105
+     * Get metadata for a registered file
106
+     *
107
+     * @param string $type
108
+     * @param string $name
109
+     *
110
+     * @return \stdClass|null
111
+     */
112
+    public function getFile($type, $name) {
113
+        $this->setupType($type);
114
+
115
+        $name = trim(strtolower($name));
116
+        if (!isset($this->externals_map[$type][$name])) {
117
+            return null;
118
+        }
119
+
120
+        $item = $this->externals_map[$type][$name];
121
+        $priority = $this->externals[$type]->getPriority($item);
122
+
123
+        // don't allow internal properties to be altered
124
+        $clone = clone $item;
125
+        $clone->priority = $priority;
126
+
127
+        return $clone;
128
+    }
129
+	
130
+    /**
131
+     * Load an external resource for use on this page
132
+     *
133
+     * @param string $type Type of file: js or css
134
+     * @param string $name The identifier for the file
135
+     *
136
+     * @return void
137
+     */
138
+    public function load($type, $name) {
139
+        $this->setupType($type);
140
+	
141
+        $name = trim(strtolower($name));
142
+	
143
+        $item = elgg_extract($name, $this->externals_map[$type]);
144
+	
145
+        if ($item) {
146
+            // update a registered item
147
+            $item->loaded = true;
148
+        } else {
149
+            $item = (object) [
150
+                'loaded' => true,
151
+                'url' => '',
152
+                'location' => '',
153
+            ];
154
+            if (elgg_view_exists($name)) {
155
+                $item->url = elgg_get_simplecache_url($name);
156
+                $item->location = ($type == 'js') ? 'foot' : 'head';
157
+            }
158
+
159
+            $this->externals[$type]->add($item);
160
+            $this->externals_map[$type][$name] = $item;
161
+        }
162
+    }
163
+	
164
+    /**
165
+     * Get external resource descriptors
166
+     *
167
+     * @param string $type     Type of file: js or css
168
+     * @param string $location Page location
169
+     *
170
+     * @return string[] URLs of files to load
171
+     */
172
+    public function getLoadedFiles($type, $location) {
173
+        if (!isset($this->externals[$type])) {
174
+            return [];
175
+        }
176
+
177
+        $items = $this->externals[$type]->getElements();
178
+
179
+        $items = array_filter($items, function($v) use ($location) {
180
+            return $v->loaded == true && $v->location == $location;
181
+        });
182
+        if ($items) {
183
+            array_walk($items, function(&$v, $k){
184
+                $v = $v->url;
185
+            });
186
+        }
187
+        return $items;
188
+    }
189
+
190
+    /**
191
+     * Get registered file objects
192
+     *
193
+     * @param string $type     Type of file: js or css
194
+     * @param string $location Page location
195
+     *
196
+     * @return \stdClass[]
197
+     */
198
+    public function getRegisteredFiles($type, $location) {
199
+        if (!isset($this->externals[$type])) {
200
+            return [];
201
+        }
202
+
203
+        $ret = [];
204
+        $items = $this->externals[$type]->getElements();
205
+        $items = array_filter($items, function($v) use ($location) {
206
+            return ($v->location == $location);
207
+        });
208
+
209
+        foreach ($items as $item) {
210
+            $ret[] = clone $item;
211
+        }
212
+
213
+        return $ret;
214
+    }
215
+
216
+    /**
217
+     * Unregister all files
218
+     *
219
+     * @return void
220
+     */
221
+    public function reset() {
222
+        $this->externals = [];
223
+        $this->externals_map = [];
224
+    }
225
+	
226
+    /**
227
+     * Bootstraps the externals data structure
228
+     *
229
+     * @param string $type The type of external, js or css.
230
+     * @return void
231
+     */
232
+    protected function setupType($type) {
233
+        if (!isset($this->externals[$type])) {
234
+            $this->externals[$type] = new \ElggPriorityList();
235
+        }
236
+	
237
+        if (!isset($this->externals_map[$type])) {
238
+            $this->externals_map[$type] = [];
239
+        }
240
+    }
241 241
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -180,7 +180,7 @@
 block discarded – undo
180 180
 			return $v->loaded == true && $v->location == $location;
181 181
 		});
182 182
 		if ($items) {
183
-			array_walk($items, function(&$v, $k){
183
+			array_walk($items, function(&$v, $k) {
184 184
 				$v = $v->url;
185 185
 			});
186 186
 		}
Please login to merge, or discard this patch.
engine/classes/Elgg/I18n/Translator.php 2 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
 	 */
66 66
 	public function __construct(Config $config) {
67 67
 		$this->config = $config;
68
-		$this->defaultPath = dirname(dirname(dirname(dirname(__DIR__)))) . "/languages/";
68
+		$this->defaultPath = dirname(dirname(dirname(dirname(__DIR__))))."/languages/";
69 69
 	}
70 70
 
71 71
 	/**
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
 	public function translate($message_key, array $args = [], $language = "") {
99 99
 		if (!is_string($message_key) || strlen($message_key) < 1) {
100 100
 			_elgg_services()->logger->warn(
101
-				'$message_key needs to be a string in ' . __METHOD__ . '(), ' . gettype($message_key) . ' provided'
101
+				'$message_key needs to be a string in '.__METHOD__.'(), '.gettype($message_key).' provided'
102 102
 			);
103 103
 			return '';
104 104
 		}
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
 	 * @return bool Success
328 328
 	 */
329 329
 	public function registerPluginTranslations($path) {
330
-		$languages_path = rtrim($path, "\\/") . "/languages";
330
+		$languages_path = rtrim($path, "\\/")."/languages";
331 331
 
332 332
 		// don't need to have translations
333 333
 		if (!is_dir($languages_path)) {
@@ -385,7 +385,7 @@  discard block
 block discarded – undo
385 385
 			}
386 386
 
387 387
 			if (in_array($language_file, $load_language_files) || $load_all) {
388
-				$result = (include $path . $language_file);
388
+				$result = (include $path.$language_file);
389 389
 				if ($result === false) {
390 390
 					$return = false;
391 391
 					continue;
@@ -466,7 +466,7 @@  discard block
 block discarded – undo
466 466
 			
467 467
 			$completeness = $this->getLanguageCompleteness($k);
468 468
 			if ($completeness < 100) {
469
-				$installed[$k] .= " (" . $completeness . "% " . $this->translate('complete') . ")";
469
+				$installed[$k] .= " (".$completeness."% ".$this->translate('complete').")";
470 470
 			}
471 471
 		}
472 472
 
Please login to merge, or discard this patch.
Indentation   +729 added lines, -729 removed lines patch added patch discarded remove patch
@@ -12,737 +12,737 @@
 block discarded – undo
12 12
  */
13 13
 class Translator {
14 14
 
15
-	/**
16
-	 * @var Config
17
-	 */
18
-	private $config;
19
-
20
-	/**
21
-	 * @var array
22
-	 */
23
-	private $translations = [];
24
-
25
-	/**
26
-	 * @var bool
27
-	 */
28
-	private $is_initialized = false;
29
-
30
-	/**
31
-	 * @var string
32
-	 */
33
-	private $current_language = null;
34
-
35
-	/**
36
-	 * Paths to scan for autoloading languages.
37
-	 *
38
-	 * Languages are automatically loaded for the site or
39
-	 * user's default language.  Plugins can extend or override strings.
40
-	 * language_paths is an array of paths to scan for PHP files matching
41
-	 * the default language.  The order of paths is determined by the plugin load order,
42
-	 * with later entries overriding earlier.  Language files within these paths are
43
-	 * named as the two-letter ISO 639-1 country codes for the language they represent.
44
-	 *
45
-	 * @link http://en.wikipedia.org/wiki/ISO_639-1
46
-	 *
47
-	 * @var array (paths are keys)
48
-	 */
49
-	private $language_paths = [];
50
-
51
-	/**
52
-	 * @var bool
53
-	 */
54
-	private $was_reloaded = false;
55
-
56
-	/**
57
-	 * @var bool
58
-	 */
59
-	private $loaded_from_cache = false;
60
-
61
-	/**
62
-	 * Constructor
63
-	 *
64
-	 * @param Config $config Elgg config
65
-	 */
66
-	public function __construct(Config $config) {
67
-		$this->config = $config;
68
-		$this->defaultPath = dirname(dirname(dirname(dirname(__DIR__)))) . "/languages/";
69
-	}
70
-
71
-	/**
72
-	 * @return bool
73
-	 */
74
-	public function wasLoadedFromCache() {
75
-		return $this->loaded_from_cache;
76
-	}
77
-
78
-	/**
79
-	 * Get a map of all loaded translations
80
-	 *
81
-	 * @return array
82
-	 */
83
-	public function getLoadedTranslations() {
84
-		return $this->translations;
85
-	}
86
-
87
-	/**
88
-	 * Given a message key, returns an appropriately translated full-text string
89
-	 *
90
-	 * @param string $message_key The short message code
91
-	 * @param array  $args        An array of arguments to pass through vsprintf().
92
-	 * @param string $language    Optionally, the standard language code
93
-	 *                            (defaults to site/user default, then English)
94
-	 *
95
-	 * @return string Either the translated string, the English string,
96
-	 * or the original language string.
97
-	 */
98
-	public function translate($message_key, array $args = [], $language = "") {
99
-		if (!is_string($message_key) || strlen($message_key) < 1) {
100
-			_elgg_services()->logger->warn(
101
-				'$message_key needs to be a string in ' . __METHOD__ . '(), ' . gettype($message_key) . ' provided'
102
-			);
103
-			return '';
104
-		}
15
+    /**
16
+     * @var Config
17
+     */
18
+    private $config;
19
+
20
+    /**
21
+     * @var array
22
+     */
23
+    private $translations = [];
24
+
25
+    /**
26
+     * @var bool
27
+     */
28
+    private $is_initialized = false;
29
+
30
+    /**
31
+     * @var string
32
+     */
33
+    private $current_language = null;
34
+
35
+    /**
36
+     * Paths to scan for autoloading languages.
37
+     *
38
+     * Languages are automatically loaded for the site or
39
+     * user's default language.  Plugins can extend or override strings.
40
+     * language_paths is an array of paths to scan for PHP files matching
41
+     * the default language.  The order of paths is determined by the plugin load order,
42
+     * with later entries overriding earlier.  Language files within these paths are
43
+     * named as the two-letter ISO 639-1 country codes for the language they represent.
44
+     *
45
+     * @link http://en.wikipedia.org/wiki/ISO_639-1
46
+     *
47
+     * @var array (paths are keys)
48
+     */
49
+    private $language_paths = [];
50
+
51
+    /**
52
+     * @var bool
53
+     */
54
+    private $was_reloaded = false;
55
+
56
+    /**
57
+     * @var bool
58
+     */
59
+    private $loaded_from_cache = false;
60
+
61
+    /**
62
+     * Constructor
63
+     *
64
+     * @param Config $config Elgg config
65
+     */
66
+    public function __construct(Config $config) {
67
+        $this->config = $config;
68
+        $this->defaultPath = dirname(dirname(dirname(dirname(__DIR__)))) . "/languages/";
69
+    }
70
+
71
+    /**
72
+     * @return bool
73
+     */
74
+    public function wasLoadedFromCache() {
75
+        return $this->loaded_from_cache;
76
+    }
77
+
78
+    /**
79
+     * Get a map of all loaded translations
80
+     *
81
+     * @return array
82
+     */
83
+    public function getLoadedTranslations() {
84
+        return $this->translations;
85
+    }
86
+
87
+    /**
88
+     * Given a message key, returns an appropriately translated full-text string
89
+     *
90
+     * @param string $message_key The short message code
91
+     * @param array  $args        An array of arguments to pass through vsprintf().
92
+     * @param string $language    Optionally, the standard language code
93
+     *                            (defaults to site/user default, then English)
94
+     *
95
+     * @return string Either the translated string, the English string,
96
+     * or the original language string.
97
+     */
98
+    public function translate($message_key, array $args = [], $language = "") {
99
+        if (!is_string($message_key) || strlen($message_key) < 1) {
100
+            _elgg_services()->logger->warn(
101
+                '$message_key needs to be a string in ' . __METHOD__ . '(), ' . gettype($message_key) . ' provided'
102
+            );
103
+            return '';
104
+        }
105 105
 		
106
-		if ($this->current_language === null) {
107
-			$this->current_language = $this->getCurrentLanguage();
108
-		}
109
-		if (!$language) {
110
-			$language = $this->current_language;
111
-		}
112
-
113
-		$this->ensureTranslationsLoaded($language);
114
-
115
-		$notice = '';
116
-		$string = $message_key;
117
-
118
-		// avoid dupes without overhead of array_unique
119
-		$langs[$language] = true;
120
-		$langs['en'] = true;
121
-
122
-		foreach (array_keys($langs) as $try_lang) {
123
-			if (isset($this->translations[$try_lang][$message_key])) {
124
-				$string = $this->translations[$try_lang][$message_key];
125
-
126
-				// only pass through if we have arguments to allow backward compatibility
127
-				// with manual sprintf() calls.
128
-				if ($args) {
129
-					$string = vsprintf($string, $args);
130
-				}
131
-
132
-				break;
133
-			} else {
134
-				$notice = sprintf(
135
-					'Missing %s translation for "%s" language key',
136
-					($try_lang === 'en') ? 'English' : $try_lang,
137
-					$message_key
138
-				);
139
-			}
140
-		}
141
-
142
-		if ($notice) {
143
-			_elgg_services()->logger->notice($notice);
144
-		}
145
-
146
-		return $string;
147
-	}
148
-
149
-	/**
150
-	 * Add a translation.
151
-	 *
152
-	 * Translations are arrays in the Zend Translation array format, eg:
153
-	 *
154
-	 *	$english = array('message1' => 'message1', 'message2' => 'message2');
155
-	 *  $german = array('message1' => 'Nachricht1','message2' => 'Nachricht2');
156
-	 *
157
-	 * @param string $country_code   Standard country code (eg 'en', 'nl', 'es')
158
-	 * @param array  $language_array Formatted array of strings
159
-	 *
160
-	 * @return bool Depending on success
161
-	 */
162
-	public function addTranslation($country_code, $language_array) {
163
-		$country_code = strtolower($country_code);
164
-		$country_code = trim($country_code);
165
-
166
-		if (!is_array($language_array) || $country_code === "") {
167
-			return false;
168
-		}
169
-
170
-		if (count($language_array) > 0) {
171
-			if (!isset($this->translations[$country_code])) {
172
-				$this->translations[$country_code] = $language_array;
173
-			} else {
174
-				$this->translations[$country_code] = $language_array + $this->translations[$country_code];
175
-			}
176
-		}
177
-
178
-		return true;
179
-	}
180
-
181
-	/**
182
-	 * Get the current system/user language or "en".
183
-	 *
184
-	 * @return string The language code for the site/user or "en" if not set
185
-	 */
186
-	public function getCurrentLanguage() {
187
-		$language = $this->detectLanguage();
188
-
189
-		if (!$language) {
190
-			$language = 'en';
191
-		}
192
-
193
-		return $language;
194
-	}
195
-
196
-	/**
197
-	 * Detect the current system/user language or false.
198
-	 *
199
-	 * @return string The language code (eg "en") or false if not set
200
-	 */
201
-	public function detectLanguage() {
202
-		$url_lang = _elgg_services()->input->get('hl');
203
-		if ($url_lang) {
204
-			return $url_lang;
205
-		}
206
-
207
-		$user = _elgg_services()->session->getLoggedInUser();
208
-		$language = false;
209
-
210
-		if (($user) && ($user->language)) {
211
-			$language = $user->language;
212
-		}
213
-
214
-		if (!$language) {
215
-			$site_language = $this->config->language;
216
-			if ($site_language) {
217
-				$language = $site_language;
218
-			}
219
-		}
220
-
221
-		return $language ? $language : false;
222
-	}
223
-
224
-	/**
225
-	 * Load both core and plugin translations
226
-	 *
227
-	 * By default this loads only English and the language of the logged
228
-	 * in user.
229
-	 *
230
-	 * The optional $language argument can be used to load translations
231
-	 * on-demand in case we need to translate something to a language not
232
-	 * loaded by default for the current request.
233
-	 *
234
-	 * @param string $language Language code
235
-	 * @access private
236
-	 */
237
-	public function loadTranslations($language = null) {
238
-		if (elgg_is_system_cache_enabled()) {
239
-			$loaded = true;
240
-
241
-			if ($language) {
242
-				$languages = [$language];
243
-			} else {
244
-				$languages = array_unique(['en', $this->getCurrentLanguage()]);
245
-			}
246
-
247
-			foreach ($languages as $language) {
248
-				$data = elgg_load_system_cache("$language.lang");
249
-				if ($data) {
250
-					$this->addTranslation($language, unserialize($data));
251
-				} else {
252
-					$loaded = false;
253
-				}
254
-			}
255
-
256
-			if ($loaded) {
257
-				$this->loaded_from_cache = true;
258
-				$this->language_paths[$this->defaultPath] = true;
259
-				$this->is_initialized = true;
260
-				return;
261
-			}
262
-		}
263
-
264
-		// load core translations from languages directory
265
-		$this->registerTranslations($this->defaultPath, false, $language);
266
-
267
-		// Plugin translation have already been loaded for the default
268
-		// languages by ElggApplication::bootCore(), so there's no need
269
-		// to continue unless loading a specific language on-demand
270
-		if ($language) {
271
-			$this->loadPluginTranslations($language);
272
-		}
273
-	}
274
-
275
-	/**
276
-	 * Load plugin translations for a language
277
-	 *
278
-	 * This is needed only if the current request uses a language
279
-	 * that is neither English of the same as the language of the
280
-	 * logged in user.
281
-	 *
282
-	 * @param string $language Language code
283
-	 * @return void
284
-	 * @throws \PluginException
285
-	 */
286
-	private function loadPluginTranslations($language) {
287
-		// Get active plugins
288
-		$plugins = _elgg_services()->plugins->find('active');
289
-
290
-		if (!$plugins) {
291
-			// Active plugins were not found, so no need to register plugin translations
292
-			return;
293
-		}
294
-
295
-		foreach ($plugins as $plugin) {
296
-			$languages_path = "{$plugin->getPath()}languages/";
297
-
298
-			if (!is_dir($languages_path)) {
299
-				// This plugin doesn't have anything to translate
300
-				continue;
301
-			}
302
-
303
-			$language_file = "{$languages_path}{$language}.php";
304
-
305
-			if (!file_exists($language_file)) {
306
-				// This plugin doesn't have translations for the requested language
307
-
308
-				$name = $plugin->getDisplayName();
309
-				_elgg_services()->logger->notice("Plugin $name is missing translations for $language language");
310
-
311
-				continue;
312
-			}
313
-
314
-			// Register translations from the plugin languages directory
315
-			if (!$this->registerTranslations($languages_path, false, $language)) {
316
-				throw new \PluginException(sprintf('Cannot register languages for plugin %s (guid: %s) at %s.',
317
-					[$plugin->getID(), $plugin->guid, $languages_path]));
318
-			}
319
-		}
320
-	}
321
-
322
-	/**
323
-	 * Registers translations in a directory assuming the standard plugin layout.
324
-	 *
325
-	 * @param string $path Without the trailing slash.
326
-	 *
327
-	 * @return bool Success
328
-	 */
329
-	public function registerPluginTranslations($path) {
330
-		$languages_path = rtrim($path, "\\/") . "/languages";
331
-
332
-		// don't need to have translations
333
-		if (!is_dir($languages_path)) {
334
-			return true;
335
-		}
336
-
337
-		return $this->registerTranslations($languages_path);
338
-	}
339
-
340
-	/**
341
-	 * When given a full path, finds translation files and loads them
342
-	 *
343
-	 * @param string $path     Full path
344
-	 * @param bool   $load_all If true all languages are loaded, if
345
-	 *                         false only the current language + en are loaded
346
-	 * @param string $language Language code
347
-	 *
348
-	 * @return bool success
349
-	 */
350
-	public function registerTranslations($path, $load_all = false, $language = null) {
351
-		$path = sanitise_filepath($path);
352
-
353
-		// Make a note of this path just in case we need to register this language later
354
-		$this->language_paths[$path] = true;
355
-		$this->is_initialized = true;
356
-
357
-		_elgg_services()->logger->info("Translations loaded from: $path");
358
-
359
-		if ($language) {
360
-			$load_language_files = ["$language.php"];
361
-			$load_all = false;
362
-		} else {
363
-			// Get the current language based on site defaults and user preference
364
-			$current_language = $this->getCurrentLanguage();
365
-
366
-			$load_language_files = [
367
-				'en.php',
368
-				"$current_language.php"
369
-			];
370
-
371
-			$load_language_files = array_unique($load_language_files);
372
-		}
373
-
374
-		$handle = opendir($path);
375
-		if (!$handle) {
376
-			_elgg_services()->logger->error("Could not open language path: $path");
377
-			return false;
378
-		}
379
-
380
-		$return = true;
381
-		while (false !== ($language_file = readdir($handle))) {
382
-			// ignore bad files
383
-			if (substr($language_file, 0, 1) == '.' || substr($language_file, -4) !== '.php') {
384
-				continue;
385
-			}
386
-
387
-			if (in_array($language_file, $load_language_files) || $load_all) {
388
-				$result = (include $path . $language_file);
389
-				if ($result === false) {
390
-					$return = false;
391
-					continue;
392
-				} elseif (is_array($result)) {
393
-					$this->addTranslation(basename($language_file, '.php'), $result);
394
-				}
395
-			}
396
-		}
397
-
398
-		return $return;
399
-	}
400
-
401
-	/**
402
-	 * Reload all translations from all registered paths.
403
-	 *
404
-	 * This is only called by functions which need to know all possible translations.
405
-	 *
406
-	 * @todo Better on demand loading based on language_paths array
407
-	 *
408
-	 * @return void
409
-	 */
410
-	public function reloadAllTranslations() {
411
-		if ($this->was_reloaded) {
412
-			return;
413
-		}
414
-
415
-		if ($this->loaded_from_cache) {
416
-			$cache = elgg_get_system_cache();
417
-			$cache_dir = $cache->getVariable("cache_path");
418
-			$filenames = elgg_get_file_list($cache_dir, [], [], [".lang"]);
419
-			foreach ($filenames as $filename) {
420
-				// Look for files matching for example 'en.lang', 'cmn.lang' or 'pt_br.lang'.
421
-				// Note that this regex is just for the system cache. The original language
422
-				// files are allowed to have uppercase letters (e.g. pt_BR.php).
423
-				if (preg_match('/(([a-z]{2,3})(_[a-z]{2})?)\.lang$/', $filename, $matches)) {
424
-					$language = $matches[1];
425
-					$data = elgg_load_system_cache("$language.lang");
426
-					if ($data) {
427
-						$this->addTranslation($language, unserialize($data));
428
-					}
429
-				}
430
-			}
431
-		} else {
432
-			foreach (array_keys($this->language_paths) as $path) {
433
-				$this->registerTranslations($path, true);
434
-			}
435
-		}
436
-
437
-		$this->was_reloaded = true;
438
-	}
439
-
440
-	/**
441
-	 * Return an array of installed translations as an associative
442
-	 * array "two letter code" => "native language name".
443
-	 *
444
-	 * @return array
445
-	 */
446
-	public function getInstalledTranslations() {
447
-		// Ensure that all possible translations are loaded
448
-		$this->reloadAllTranslations();
449
-
450
-		$installed = [];
451
-
452
-		$admin_logged_in = _elgg_services()->session->isAdminLoggedIn();
453
-
454
-		foreach ($this->translations as $k => $v) {
455
-			if ($this->languageKeyExists($k, $k)) {
456
-				$lang = $this->translate($k, [], $k);
457
-			} else {
458
-				$lang = $this->translate($k);
459
-			}
106
+        if ($this->current_language === null) {
107
+            $this->current_language = $this->getCurrentLanguage();
108
+        }
109
+        if (!$language) {
110
+            $language = $this->current_language;
111
+        }
112
+
113
+        $this->ensureTranslationsLoaded($language);
114
+
115
+        $notice = '';
116
+        $string = $message_key;
117
+
118
+        // avoid dupes without overhead of array_unique
119
+        $langs[$language] = true;
120
+        $langs['en'] = true;
121
+
122
+        foreach (array_keys($langs) as $try_lang) {
123
+            if (isset($this->translations[$try_lang][$message_key])) {
124
+                $string = $this->translations[$try_lang][$message_key];
125
+
126
+                // only pass through if we have arguments to allow backward compatibility
127
+                // with manual sprintf() calls.
128
+                if ($args) {
129
+                    $string = vsprintf($string, $args);
130
+                }
131
+
132
+                break;
133
+            } else {
134
+                $notice = sprintf(
135
+                    'Missing %s translation for "%s" language key',
136
+                    ($try_lang === 'en') ? 'English' : $try_lang,
137
+                    $message_key
138
+                );
139
+            }
140
+        }
141
+
142
+        if ($notice) {
143
+            _elgg_services()->logger->notice($notice);
144
+        }
145
+
146
+        return $string;
147
+    }
148
+
149
+    /**
150
+     * Add a translation.
151
+     *
152
+     * Translations are arrays in the Zend Translation array format, eg:
153
+     *
154
+     *	$english = array('message1' => 'message1', 'message2' => 'message2');
155
+     *  $german = array('message1' => 'Nachricht1','message2' => 'Nachricht2');
156
+     *
157
+     * @param string $country_code   Standard country code (eg 'en', 'nl', 'es')
158
+     * @param array  $language_array Formatted array of strings
159
+     *
160
+     * @return bool Depending on success
161
+     */
162
+    public function addTranslation($country_code, $language_array) {
163
+        $country_code = strtolower($country_code);
164
+        $country_code = trim($country_code);
165
+
166
+        if (!is_array($language_array) || $country_code === "") {
167
+            return false;
168
+        }
169
+
170
+        if (count($language_array) > 0) {
171
+            if (!isset($this->translations[$country_code])) {
172
+                $this->translations[$country_code] = $language_array;
173
+            } else {
174
+                $this->translations[$country_code] = $language_array + $this->translations[$country_code];
175
+            }
176
+        }
177
+
178
+        return true;
179
+    }
180
+
181
+    /**
182
+     * Get the current system/user language or "en".
183
+     *
184
+     * @return string The language code for the site/user or "en" if not set
185
+     */
186
+    public function getCurrentLanguage() {
187
+        $language = $this->detectLanguage();
188
+
189
+        if (!$language) {
190
+            $language = 'en';
191
+        }
192
+
193
+        return $language;
194
+    }
195
+
196
+    /**
197
+     * Detect the current system/user language or false.
198
+     *
199
+     * @return string The language code (eg "en") or false if not set
200
+     */
201
+    public function detectLanguage() {
202
+        $url_lang = _elgg_services()->input->get('hl');
203
+        if ($url_lang) {
204
+            return $url_lang;
205
+        }
206
+
207
+        $user = _elgg_services()->session->getLoggedInUser();
208
+        $language = false;
209
+
210
+        if (($user) && ($user->language)) {
211
+            $language = $user->language;
212
+        }
213
+
214
+        if (!$language) {
215
+            $site_language = $this->config->language;
216
+            if ($site_language) {
217
+                $language = $site_language;
218
+            }
219
+        }
220
+
221
+        return $language ? $language : false;
222
+    }
223
+
224
+    /**
225
+     * Load both core and plugin translations
226
+     *
227
+     * By default this loads only English and the language of the logged
228
+     * in user.
229
+     *
230
+     * The optional $language argument can be used to load translations
231
+     * on-demand in case we need to translate something to a language not
232
+     * loaded by default for the current request.
233
+     *
234
+     * @param string $language Language code
235
+     * @access private
236
+     */
237
+    public function loadTranslations($language = null) {
238
+        if (elgg_is_system_cache_enabled()) {
239
+            $loaded = true;
240
+
241
+            if ($language) {
242
+                $languages = [$language];
243
+            } else {
244
+                $languages = array_unique(['en', $this->getCurrentLanguage()]);
245
+            }
246
+
247
+            foreach ($languages as $language) {
248
+                $data = elgg_load_system_cache("$language.lang");
249
+                if ($data) {
250
+                    $this->addTranslation($language, unserialize($data));
251
+                } else {
252
+                    $loaded = false;
253
+                }
254
+            }
255
+
256
+            if ($loaded) {
257
+                $this->loaded_from_cache = true;
258
+                $this->language_paths[$this->defaultPath] = true;
259
+                $this->is_initialized = true;
260
+                return;
261
+            }
262
+        }
263
+
264
+        // load core translations from languages directory
265
+        $this->registerTranslations($this->defaultPath, false, $language);
266
+
267
+        // Plugin translation have already been loaded for the default
268
+        // languages by ElggApplication::bootCore(), so there's no need
269
+        // to continue unless loading a specific language on-demand
270
+        if ($language) {
271
+            $this->loadPluginTranslations($language);
272
+        }
273
+    }
274
+
275
+    /**
276
+     * Load plugin translations for a language
277
+     *
278
+     * This is needed only if the current request uses a language
279
+     * that is neither English of the same as the language of the
280
+     * logged in user.
281
+     *
282
+     * @param string $language Language code
283
+     * @return void
284
+     * @throws \PluginException
285
+     */
286
+    private function loadPluginTranslations($language) {
287
+        // Get active plugins
288
+        $plugins = _elgg_services()->plugins->find('active');
289
+
290
+        if (!$plugins) {
291
+            // Active plugins were not found, so no need to register plugin translations
292
+            return;
293
+        }
294
+
295
+        foreach ($plugins as $plugin) {
296
+            $languages_path = "{$plugin->getPath()}languages/";
297
+
298
+            if (!is_dir($languages_path)) {
299
+                // This plugin doesn't have anything to translate
300
+                continue;
301
+            }
302
+
303
+            $language_file = "{$languages_path}{$language}.php";
304
+
305
+            if (!file_exists($language_file)) {
306
+                // This plugin doesn't have translations for the requested language
307
+
308
+                $name = $plugin->getDisplayName();
309
+                _elgg_services()->logger->notice("Plugin $name is missing translations for $language language");
310
+
311
+                continue;
312
+            }
313
+
314
+            // Register translations from the plugin languages directory
315
+            if (!$this->registerTranslations($languages_path, false, $language)) {
316
+                throw new \PluginException(sprintf('Cannot register languages for plugin %s (guid: %s) at %s.',
317
+                    [$plugin->getID(), $plugin->guid, $languages_path]));
318
+            }
319
+        }
320
+    }
321
+
322
+    /**
323
+     * Registers translations in a directory assuming the standard plugin layout.
324
+     *
325
+     * @param string $path Without the trailing slash.
326
+     *
327
+     * @return bool Success
328
+     */
329
+    public function registerPluginTranslations($path) {
330
+        $languages_path = rtrim($path, "\\/") . "/languages";
331
+
332
+        // don't need to have translations
333
+        if (!is_dir($languages_path)) {
334
+            return true;
335
+        }
336
+
337
+        return $this->registerTranslations($languages_path);
338
+    }
339
+
340
+    /**
341
+     * When given a full path, finds translation files and loads them
342
+     *
343
+     * @param string $path     Full path
344
+     * @param bool   $load_all If true all languages are loaded, if
345
+     *                         false only the current language + en are loaded
346
+     * @param string $language Language code
347
+     *
348
+     * @return bool success
349
+     */
350
+    public function registerTranslations($path, $load_all = false, $language = null) {
351
+        $path = sanitise_filepath($path);
352
+
353
+        // Make a note of this path just in case we need to register this language later
354
+        $this->language_paths[$path] = true;
355
+        $this->is_initialized = true;
356
+
357
+        _elgg_services()->logger->info("Translations loaded from: $path");
358
+
359
+        if ($language) {
360
+            $load_language_files = ["$language.php"];
361
+            $load_all = false;
362
+        } else {
363
+            // Get the current language based on site defaults and user preference
364
+            $current_language = $this->getCurrentLanguage();
365
+
366
+            $load_language_files = [
367
+                'en.php',
368
+                "$current_language.php"
369
+            ];
370
+
371
+            $load_language_files = array_unique($load_language_files);
372
+        }
373
+
374
+        $handle = opendir($path);
375
+        if (!$handle) {
376
+            _elgg_services()->logger->error("Could not open language path: $path");
377
+            return false;
378
+        }
379
+
380
+        $return = true;
381
+        while (false !== ($language_file = readdir($handle))) {
382
+            // ignore bad files
383
+            if (substr($language_file, 0, 1) == '.' || substr($language_file, -4) !== '.php') {
384
+                continue;
385
+            }
386
+
387
+            if (in_array($language_file, $load_language_files) || $load_all) {
388
+                $result = (include $path . $language_file);
389
+                if ($result === false) {
390
+                    $return = false;
391
+                    continue;
392
+                } elseif (is_array($result)) {
393
+                    $this->addTranslation(basename($language_file, '.php'), $result);
394
+                }
395
+            }
396
+        }
397
+
398
+        return $return;
399
+    }
400
+
401
+    /**
402
+     * Reload all translations from all registered paths.
403
+     *
404
+     * This is only called by functions which need to know all possible translations.
405
+     *
406
+     * @todo Better on demand loading based on language_paths array
407
+     *
408
+     * @return void
409
+     */
410
+    public function reloadAllTranslations() {
411
+        if ($this->was_reloaded) {
412
+            return;
413
+        }
414
+
415
+        if ($this->loaded_from_cache) {
416
+            $cache = elgg_get_system_cache();
417
+            $cache_dir = $cache->getVariable("cache_path");
418
+            $filenames = elgg_get_file_list($cache_dir, [], [], [".lang"]);
419
+            foreach ($filenames as $filename) {
420
+                // Look for files matching for example 'en.lang', 'cmn.lang' or 'pt_br.lang'.
421
+                // Note that this regex is just for the system cache. The original language
422
+                // files are allowed to have uppercase letters (e.g. pt_BR.php).
423
+                if (preg_match('/(([a-z]{2,3})(_[a-z]{2})?)\.lang$/', $filename, $matches)) {
424
+                    $language = $matches[1];
425
+                    $data = elgg_load_system_cache("$language.lang");
426
+                    if ($data) {
427
+                        $this->addTranslation($language, unserialize($data));
428
+                    }
429
+                }
430
+            }
431
+        } else {
432
+            foreach (array_keys($this->language_paths) as $path) {
433
+                $this->registerTranslations($path, true);
434
+            }
435
+        }
436
+
437
+        $this->was_reloaded = true;
438
+    }
439
+
440
+    /**
441
+     * Return an array of installed translations as an associative
442
+     * array "two letter code" => "native language name".
443
+     *
444
+     * @return array
445
+     */
446
+    public function getInstalledTranslations() {
447
+        // Ensure that all possible translations are loaded
448
+        $this->reloadAllTranslations();
449
+
450
+        $installed = [];
451
+
452
+        $admin_logged_in = _elgg_services()->session->isAdminLoggedIn();
453
+
454
+        foreach ($this->translations as $k => $v) {
455
+            if ($this->languageKeyExists($k, $k)) {
456
+                $lang = $this->translate($k, [], $k);
457
+            } else {
458
+                $lang = $this->translate($k);
459
+            }
460 460
 			
461
-			$installed[$k] = $lang;
461
+            $installed[$k] = $lang;
462 462
 			
463
-			if (!$admin_logged_in || ($k === 'en')) {
464
-				continue;
465
-			}
463
+            if (!$admin_logged_in || ($k === 'en')) {
464
+                continue;
465
+            }
466 466
 			
467
-			$completeness = $this->getLanguageCompleteness($k);
468
-			if ($completeness < 100) {
469
-				$installed[$k] .= " (" . $completeness . "% " . $this->translate('complete') . ")";
470
-			}
471
-		}
472
-
473
-		return $installed;
474
-	}
475
-
476
-	/**
477
-	 * Return the level of completeness for a given language code (compared to english)
478
-	 *
479
-	 * @param string $language Language
480
-	 *
481
-	 * @return int
482
-	 */
483
-	public function getLanguageCompleteness($language) {
484
-
485
-
486
-		// Ensure that all possible translations are loaded
487
-		$this->reloadAllTranslations();
488
-
489
-		$language = sanitise_string($language);
490
-
491
-		$en = count($this->translations['en']);
492
-
493
-		$missing = $this->getMissingLanguageKeys($language);
494
-		if ($missing) {
495
-			$missing = count($missing);
496
-		} else {
497
-			$missing = 0;
498
-		}
499
-
500
-		$lang = $en - $missing;
501
-
502
-		return round(($lang / $en) * 100, 2);
503
-	}
504
-
505
-	/**
506
-	 * Return the translation keys missing from a given language,
507
-	 * or those that are identical to the english version.
508
-	 *
509
-	 * @param string $language The language
510
-	 *
511
-	 * @return mixed
512
-	 */
513
-	public function getMissingLanguageKeys($language) {
514
-
515
-
516
-		// Ensure that all possible translations are loaded
517
-		$this->reloadAllTranslations();
518
-
519
-		$missing = [];
520
-
521
-		foreach ($this->translations['en'] as $k => $v) {
522
-			if ((!isset($this->translations[$language][$k]))
523
-			|| ($this->translations[$language][$k] == $this->translations['en'][$k])) {
524
-				$missing[] = $k;
525
-			}
526
-		}
527
-
528
-		if (count($missing)) {
529
-			return $missing;
530
-		}
531
-
532
-		return false;
533
-	}
534
-
535
-	/**
536
-	 * Check if a given language key exists
537
-	 *
538
-	 * @param string $key      The translation key
539
-	 * @param string $language The specific language to check
540
-	 *
541
-	 * @return bool
542
-	 * @since 1.11
543
-	 */
544
-	function languageKeyExists($key, $language = 'en') {
545
-		if (empty($key)) {
546
-			return false;
547
-		}
548
-
549
-		$this->ensureTranslationsLoaded($language);
550
-
551
-		if (!array_key_exists($language, $this->translations)) {
552
-			return false;
553
-		}
554
-
555
-		return array_key_exists($key, $this->translations[$language]);
556
-	}
557
-
558
-	/**
559
-	 * Make sure translations are loaded
560
-	 *
561
-	 * @param string $language Language
562
-	 * @return void
563
-	 */
564
-	private function ensureTranslationsLoaded($language) {
565
-		if (!$this->is_initialized) {
566
-			// this means we probably had an exception before translations were initialized
567
-			$this->registerTranslations($this->defaultPath);
568
-		}
569
-
570
-		if (!isset($this->translations[$language])) {
571
-			// The language being requested is not the same as the language of the
572
-			// logged in user, so we will have to load it separately. (Most likely
573
-			// we're sending a notification and the recipient is using a different
574
-			// language than the logged in user.)
575
-			$this->loadTranslations($language);
576
-		}
577
-	}
578
-
579
-	/**
580
-	 * Returns an array of language codes.
581
-	 *
582
-	 * @return array
583
-	 */
584
-	public static function getAllLanguageCodes() {
585
-		return [
586
-			"aa", // "Afar"
587
-			"ab", // "Abkhazian"
588
-			"af", // "Afrikaans"
589
-			"am", // "Amharic"
590
-			"ar", // "Arabic"
591
-			"as", // "Assamese"
592
-			"ay", // "Aymara"
593
-			"az", // "Azerbaijani"
594
-			"ba", // "Bashkir"
595
-			"be", // "Byelorussian"
596
-			"bg", // "Bulgarian"
597
-			"bh", // "Bihari"
598
-			"bi", // "Bislama"
599
-			"bn", // "Bengali; Bangla"
600
-			"bo", // "Tibetan"
601
-			"br", // "Breton"
602
-			"ca", // "Catalan"
603
-			"cmn", // "Mandarin Chinese" // ISO 639-3
604
-			"co", // "Corsican"
605
-			"cs", // "Czech"
606
-			"cy", // "Welsh"
607
-			"da", // "Danish"
608
-			"de", // "German"
609
-			"dz", // "Bhutani"
610
-			"el", // "Greek"
611
-			"en", // "English"
612
-			"eo", // "Esperanto"
613
-			"es", // "Spanish"
614
-			"et", // "Estonian"
615
-			"eu", // "Basque"
616
-			"eu_es", // "Basque (Spain)"
617
-			"fa", // "Persian"
618
-			"fi", // "Finnish"
619
-			"fj", // "Fiji"
620
-			"fo", // "Faeroese"
621
-			"fr", // "French"
622
-			"fy", // "Frisian"
623
-			"ga", // "Irish"
624
-			"gd", // "Scots / Gaelic"
625
-			"gl", // "Galician"
626
-			"gn", // "Guarani"
627
-			"gu", // "Gujarati"
628
-			"he", // "Hebrew"
629
-			"ha", // "Hausa"
630
-			"hi", // "Hindi"
631
-			"hr", // "Croatian"
632
-			"hu", // "Hungarian"
633
-			"hy", // "Armenian"
634
-			"ia", // "Interlingua"
635
-			"id", // "Indonesian"
636
-			"ie", // "Interlingue"
637
-			"ik", // "Inupiak"
638
-			"is", // "Icelandic"
639
-			"it", // "Italian"
640
-			"iu", // "Inuktitut"
641
-			"iw", // "Hebrew (obsolete)"
642
-			"ja", // "Japanese"
643
-			"ji", // "Yiddish (obsolete)"
644
-			"jw", // "Javanese"
645
-			"ka", // "Georgian"
646
-			"kk", // "Kazakh"
647
-			"kl", // "Greenlandic"
648
-			"km", // "Cambodian"
649
-			"kn", // "Kannada"
650
-			"ko", // "Korean"
651
-			"ks", // "Kashmiri"
652
-			"ku", // "Kurdish"
653
-			"ky", // "Kirghiz"
654
-			"la", // "Latin"
655
-			"ln", // "Lingala"
656
-			"lo", // "Laothian"
657
-			"lt", // "Lithuanian"
658
-			"lv", // "Latvian/Lettish"
659
-			"mg", // "Malagasy"
660
-			"mi", // "Maori"
661
-			"mk", // "Macedonian"
662
-			"ml", // "Malayalam"
663
-			"mn", // "Mongolian"
664
-			"mo", // "Moldavian"
665
-			"mr", // "Marathi"
666
-			"ms", // "Malay"
667
-			"mt", // "Maltese"
668
-			"my", // "Burmese"
669
-			"na", // "Nauru"
670
-			"ne", // "Nepali"
671
-			"nl", // "Dutch"
672
-			"no", // "Norwegian"
673
-			"oc", // "Occitan"
674
-			"om", // "(Afan) Oromo"
675
-			"or", // "Oriya"
676
-			"pa", // "Punjabi"
677
-			"pl", // "Polish"
678
-			"ps", // "Pashto / Pushto"
679
-			"pt", // "Portuguese"
680
-			"pt_br", // "Portuguese (Brazil)"
681
-			"qu", // "Quechua"
682
-			"rm", // "Rhaeto-Romance"
683
-			"rn", // "Kirundi"
684
-			"ro", // "Romanian"
685
-			"ro_ro", // "Romanian (Romania)"
686
-			"ru", // "Russian"
687
-			"rw", // "Kinyarwanda"
688
-			"sa", // "Sanskrit"
689
-			"sd", // "Sindhi"
690
-			"sg", // "Sangro"
691
-			"sh", // "Serbo-Croatian"
692
-			"si", // "Singhalese"
693
-			"sk", // "Slovak"
694
-			"sl", // "Slovenian"
695
-			"sm", // "Samoan"
696
-			"sn", // "Shona"
697
-			"so", // "Somali"
698
-			"sq", // "Albanian"
699
-			"sr", // "Serbian"
700
-			"sr_latin", // "Serbian (Latin)"
701
-			"ss", // "Siswati"
702
-			"st", // "Sesotho"
703
-			"su", // "Sundanese"
704
-			"sv", // "Swedish"
705
-			"sw", // "Swahili"
706
-			"ta", // "Tamil"
707
-			"te", // "Tegulu"
708
-			"tg", // "Tajik"
709
-			"th", // "Thai"
710
-			"ti", // "Tigrinya"
711
-			"tk", // "Turkmen"
712
-			"tl", // "Tagalog"
713
-			"tn", // "Setswana"
714
-			"to", // "Tonga"
715
-			"tr", // "Turkish"
716
-			"ts", // "Tsonga"
717
-			"tt", // "Tatar"
718
-			"tw", // "Twi"
719
-			"ug", // "Uigur"
720
-			"uk", // "Ukrainian"
721
-			"ur", // "Urdu"
722
-			"uz", // "Uzbek"
723
-			"vi", // "Vietnamese"
724
-			"vo", // "Volapuk"
725
-			"wo", // "Wolof"
726
-			"xh", // "Xhosa"
727
-			"yi", // "Yiddish"
728
-			"yo", // "Yoruba"
729
-			"za", // "Zuang"
730
-			"zh", // "Chinese"
731
-			"zh_hans", // "Chinese Simplified"
732
-			"zu", // "Zulu"
733
-		];
734
-	}
735
-
736
-	/**
737
-	 * Normalize a language code (e.g. from Transifex)
738
-	 *
739
-	 * @param string $code Language code
740
-	 *
741
-	 * @return string
742
-	 */
743
-	public static function normalizeLanguageCode($code) {
744
-		$code = strtolower($code);
745
-		$code = preg_replace('~[^a-z0-9]~', '_', $code);
746
-		return $code;
747
-	}
467
+            $completeness = $this->getLanguageCompleteness($k);
468
+            if ($completeness < 100) {
469
+                $installed[$k] .= " (" . $completeness . "% " . $this->translate('complete') . ")";
470
+            }
471
+        }
472
+
473
+        return $installed;
474
+    }
475
+
476
+    /**
477
+     * Return the level of completeness for a given language code (compared to english)
478
+     *
479
+     * @param string $language Language
480
+     *
481
+     * @return int
482
+     */
483
+    public function getLanguageCompleteness($language) {
484
+
485
+
486
+        // Ensure that all possible translations are loaded
487
+        $this->reloadAllTranslations();
488
+
489
+        $language = sanitise_string($language);
490
+
491
+        $en = count($this->translations['en']);
492
+
493
+        $missing = $this->getMissingLanguageKeys($language);
494
+        if ($missing) {
495
+            $missing = count($missing);
496
+        } else {
497
+            $missing = 0;
498
+        }
499
+
500
+        $lang = $en - $missing;
501
+
502
+        return round(($lang / $en) * 100, 2);
503
+    }
504
+
505
+    /**
506
+     * Return the translation keys missing from a given language,
507
+     * or those that are identical to the english version.
508
+     *
509
+     * @param string $language The language
510
+     *
511
+     * @return mixed
512
+     */
513
+    public function getMissingLanguageKeys($language) {
514
+
515
+
516
+        // Ensure that all possible translations are loaded
517
+        $this->reloadAllTranslations();
518
+
519
+        $missing = [];
520
+
521
+        foreach ($this->translations['en'] as $k => $v) {
522
+            if ((!isset($this->translations[$language][$k]))
523
+            || ($this->translations[$language][$k] == $this->translations['en'][$k])) {
524
+                $missing[] = $k;
525
+            }
526
+        }
527
+
528
+        if (count($missing)) {
529
+            return $missing;
530
+        }
531
+
532
+        return false;
533
+    }
534
+
535
+    /**
536
+     * Check if a given language key exists
537
+     *
538
+     * @param string $key      The translation key
539
+     * @param string $language The specific language to check
540
+     *
541
+     * @return bool
542
+     * @since 1.11
543
+     */
544
+    function languageKeyExists($key, $language = 'en') {
545
+        if (empty($key)) {
546
+            return false;
547
+        }
548
+
549
+        $this->ensureTranslationsLoaded($language);
550
+
551
+        if (!array_key_exists($language, $this->translations)) {
552
+            return false;
553
+        }
554
+
555
+        return array_key_exists($key, $this->translations[$language]);
556
+    }
557
+
558
+    /**
559
+     * Make sure translations are loaded
560
+     *
561
+     * @param string $language Language
562
+     * @return void
563
+     */
564
+    private function ensureTranslationsLoaded($language) {
565
+        if (!$this->is_initialized) {
566
+            // this means we probably had an exception before translations were initialized
567
+            $this->registerTranslations($this->defaultPath);
568
+        }
569
+
570
+        if (!isset($this->translations[$language])) {
571
+            // The language being requested is not the same as the language of the
572
+            // logged in user, so we will have to load it separately. (Most likely
573
+            // we're sending a notification and the recipient is using a different
574
+            // language than the logged in user.)
575
+            $this->loadTranslations($language);
576
+        }
577
+    }
578
+
579
+    /**
580
+     * Returns an array of language codes.
581
+     *
582
+     * @return array
583
+     */
584
+    public static function getAllLanguageCodes() {
585
+        return [
586
+            "aa", // "Afar"
587
+            "ab", // "Abkhazian"
588
+            "af", // "Afrikaans"
589
+            "am", // "Amharic"
590
+            "ar", // "Arabic"
591
+            "as", // "Assamese"
592
+            "ay", // "Aymara"
593
+            "az", // "Azerbaijani"
594
+            "ba", // "Bashkir"
595
+            "be", // "Byelorussian"
596
+            "bg", // "Bulgarian"
597
+            "bh", // "Bihari"
598
+            "bi", // "Bislama"
599
+            "bn", // "Bengali; Bangla"
600
+            "bo", // "Tibetan"
601
+            "br", // "Breton"
602
+            "ca", // "Catalan"
603
+            "cmn", // "Mandarin Chinese" // ISO 639-3
604
+            "co", // "Corsican"
605
+            "cs", // "Czech"
606
+            "cy", // "Welsh"
607
+            "da", // "Danish"
608
+            "de", // "German"
609
+            "dz", // "Bhutani"
610
+            "el", // "Greek"
611
+            "en", // "English"
612
+            "eo", // "Esperanto"
613
+            "es", // "Spanish"
614
+            "et", // "Estonian"
615
+            "eu", // "Basque"
616
+            "eu_es", // "Basque (Spain)"
617
+            "fa", // "Persian"
618
+            "fi", // "Finnish"
619
+            "fj", // "Fiji"
620
+            "fo", // "Faeroese"
621
+            "fr", // "French"
622
+            "fy", // "Frisian"
623
+            "ga", // "Irish"
624
+            "gd", // "Scots / Gaelic"
625
+            "gl", // "Galician"
626
+            "gn", // "Guarani"
627
+            "gu", // "Gujarati"
628
+            "he", // "Hebrew"
629
+            "ha", // "Hausa"
630
+            "hi", // "Hindi"
631
+            "hr", // "Croatian"
632
+            "hu", // "Hungarian"
633
+            "hy", // "Armenian"
634
+            "ia", // "Interlingua"
635
+            "id", // "Indonesian"
636
+            "ie", // "Interlingue"
637
+            "ik", // "Inupiak"
638
+            "is", // "Icelandic"
639
+            "it", // "Italian"
640
+            "iu", // "Inuktitut"
641
+            "iw", // "Hebrew (obsolete)"
642
+            "ja", // "Japanese"
643
+            "ji", // "Yiddish (obsolete)"
644
+            "jw", // "Javanese"
645
+            "ka", // "Georgian"
646
+            "kk", // "Kazakh"
647
+            "kl", // "Greenlandic"
648
+            "km", // "Cambodian"
649
+            "kn", // "Kannada"
650
+            "ko", // "Korean"
651
+            "ks", // "Kashmiri"
652
+            "ku", // "Kurdish"
653
+            "ky", // "Kirghiz"
654
+            "la", // "Latin"
655
+            "ln", // "Lingala"
656
+            "lo", // "Laothian"
657
+            "lt", // "Lithuanian"
658
+            "lv", // "Latvian/Lettish"
659
+            "mg", // "Malagasy"
660
+            "mi", // "Maori"
661
+            "mk", // "Macedonian"
662
+            "ml", // "Malayalam"
663
+            "mn", // "Mongolian"
664
+            "mo", // "Moldavian"
665
+            "mr", // "Marathi"
666
+            "ms", // "Malay"
667
+            "mt", // "Maltese"
668
+            "my", // "Burmese"
669
+            "na", // "Nauru"
670
+            "ne", // "Nepali"
671
+            "nl", // "Dutch"
672
+            "no", // "Norwegian"
673
+            "oc", // "Occitan"
674
+            "om", // "(Afan) Oromo"
675
+            "or", // "Oriya"
676
+            "pa", // "Punjabi"
677
+            "pl", // "Polish"
678
+            "ps", // "Pashto / Pushto"
679
+            "pt", // "Portuguese"
680
+            "pt_br", // "Portuguese (Brazil)"
681
+            "qu", // "Quechua"
682
+            "rm", // "Rhaeto-Romance"
683
+            "rn", // "Kirundi"
684
+            "ro", // "Romanian"
685
+            "ro_ro", // "Romanian (Romania)"
686
+            "ru", // "Russian"
687
+            "rw", // "Kinyarwanda"
688
+            "sa", // "Sanskrit"
689
+            "sd", // "Sindhi"
690
+            "sg", // "Sangro"
691
+            "sh", // "Serbo-Croatian"
692
+            "si", // "Singhalese"
693
+            "sk", // "Slovak"
694
+            "sl", // "Slovenian"
695
+            "sm", // "Samoan"
696
+            "sn", // "Shona"
697
+            "so", // "Somali"
698
+            "sq", // "Albanian"
699
+            "sr", // "Serbian"
700
+            "sr_latin", // "Serbian (Latin)"
701
+            "ss", // "Siswati"
702
+            "st", // "Sesotho"
703
+            "su", // "Sundanese"
704
+            "sv", // "Swedish"
705
+            "sw", // "Swahili"
706
+            "ta", // "Tamil"
707
+            "te", // "Tegulu"
708
+            "tg", // "Tajik"
709
+            "th", // "Thai"
710
+            "ti", // "Tigrinya"
711
+            "tk", // "Turkmen"
712
+            "tl", // "Tagalog"
713
+            "tn", // "Setswana"
714
+            "to", // "Tonga"
715
+            "tr", // "Turkish"
716
+            "ts", // "Tsonga"
717
+            "tt", // "Tatar"
718
+            "tw", // "Twi"
719
+            "ug", // "Uigur"
720
+            "uk", // "Ukrainian"
721
+            "ur", // "Urdu"
722
+            "uz", // "Uzbek"
723
+            "vi", // "Vietnamese"
724
+            "vo", // "Volapuk"
725
+            "wo", // "Wolof"
726
+            "xh", // "Xhosa"
727
+            "yi", // "Yiddish"
728
+            "yo", // "Yoruba"
729
+            "za", // "Zuang"
730
+            "zh", // "Chinese"
731
+            "zh_hans", // "Chinese Simplified"
732
+            "zu", // "Zulu"
733
+        ];
734
+    }
735
+
736
+    /**
737
+     * Normalize a language code (e.g. from Transifex)
738
+     *
739
+     * @param string $code Language code
740
+     *
741
+     * @return string
742
+     */
743
+    public static function normalizeLanguageCode($code) {
744
+        $code = strtolower($code);
745
+        $code = preg_replace('~[^a-z0-9]~', '_', $code);
746
+        return $code;
747
+    }
748 748
 }
Please login to merge, or discard this patch.
engine/classes/Elgg/Database/AccessCollections.php 1 patch
Indentation   +823 added lines, -823 removed lines patch added patch discarded remove patch
@@ -23,171 +23,171 @@  discard block
 block discarded – undo
23 23
  */
24 24
 class AccessCollections {
25 25
 
26
-	/**
27
-	 * @var Conf
28
-	 */
29
-	protected $config;
30
-
31
-	/**
32
-	 * @var Database
33
-	 */
34
-	protected $db;
35
-
36
-	/**
37
-	 * @vars \ElggStateVariableCache
38
-	 */
39
-	protected $access_cache;
40
-
41
-	/**
42
-	 * @var PluginHooksService
43
-	 */
44
-	protected $hooks;
45
-
46
-	/**
47
-	 * @var ElggSession
48
-	 */
49
-	protected $session;
50
-
51
-	/**
52
-	 * @var EntityTable
53
-	 */
54
-	protected $entities;
55
-
56
-	/**
57
-	 * @var Translator
58
-	 */
59
-	protected $translator;
60
-
61
-	/**
62
-	 * @var string
63
-	 */
64
-	protected $table;
65
-
66
-	/**
67
-	 * @var string
68
-	 */
69
-	protected $membership_table;
70
-
71
-	/**
72
-	 * @var bool
73
-	 */
74
-	protected $init_complete = false;
75
-
76
-	/**
77
-	 * Constructor
78
-	 *
79
-	 * @param Conf                    $config     Config
80
-	 * @param Database                $db         Database
81
-	 * @param EntityTable             $entities   Entity table
82
-	 * @param ElggStaticVariableCache $cache      Access cache
83
-	 * @param PluginHooksService      $hooks      Hooks
84
-	 * @param ElggSession             $session    Session
85
-	 * @param Translator              $translator Translator
86
-	 */
87
-	public function __construct(
88
-			Conf $config,
89
-			Database $db,
90
-			EntityTable $entities,
91
-			ElggStaticVariableCache $cache,
92
-			PluginHooksService $hooks,
93
-			ElggSession $session,
94
-			Translator $translator) {
95
-		$this->config = $config;
96
-		$this->db = $db;
97
-		$this->entities = $entities;
98
-		$this->access_cache = $cache;
99
-		$this->hooks = $hooks;
100
-		$this->session = $session;
101
-		$this->translator = $translator;
102
-
103
-		$this->table = "{$this->db->prefix}access_collections";
104
-		$this->membership_table = "{$this->db->prefix}access_collection_membership";
105
-	}
106
-
107
-	/**
108
-	 * Mark the access system as initialized
109
-	 *
110
-	 * @return void
111
-	 */
112
-	public function markInitComplete() {
113
-		$this->init_complete = true;
114
-	}
115
-
116
-	/**
117
-	 * Returns a string of access_ids for $user_guid appropriate for inserting into an SQL IN clause.
118
-	 *
119
-	 * @see get_access_array()
120
-	 *
121
-	 * @param int  $user_guid User ID; defaults to currently logged in user
122
-	 * @param bool $flush     If set to true, will refresh the access list from the
123
-	 *                        database rather than using this function's cache.
124
-	 *
125
-	 * @return string A concatenated string of access collections suitable for using in an SQL IN clause
126
-	 * @access private
127
-	 */
128
-	public function getAccessList($user_guid = 0, $flush = false) {
129
-		$access_array = $this->getAccessArray($user_guid, $flush);
130
-		$access_ids = implode(',', $access_array);
131
-		$list = "($access_ids)";
132
-
133
-		// for BC, populate the cache
134
-		$hash = $user_guid . 'get_access_list';
135
-		$this->access_cache->add($hash, $list);
136
-
137
-		return $list;
138
-	}
139
-
140
-	/**
141
-	 * Returns an array of access IDs a user is permitted to see.
142
-	 *
143
-	 * Can be overridden with the 'access:collections:read', 'user' plugin hook.
144
-	 * @warning A callback for that plugin hook needs to either not retrieve data
145
-	 * from the database that would use the access system (triggering the plugin again)
146
-	 * or ignore the second call. Otherwise, an infinite loop will be created.
147
-	 *
148
-	 * This returns a list of all the collection ids a user owns or belongs
149
-	 * to plus public and logged in access levels. If the user is an admin, it includes
150
-	 * the private access level.
151
-	 *
152
-	 * @internal this is only used in core for creating the SQL where clause when
153
-	 * retrieving content from the database. The friends access level is handled by
154
-	 * _elgg_get_access_where_sql().
155
-	 *
156
-	 * @see get_write_access_array() for the access levels that a user can write to.
157
-	 *
158
-	 * @param int  $user_guid User ID; defaults to currently logged in user
159
-	 * @param bool $flush     If set to true, will refresh the access ids from the
160
-	 *                        database rather than using this function's cache.
161
-	 *
162
-	 * @return array An array of access collections ids
163
-	 */
164
-	public function getAccessArray($user_guid = 0, $flush = false) {
165
-		$cache = $this->access_cache;
166
-
167
-		if ($flush) {
168
-			$cache->clear();
169
-		}
170
-
171
-		if ($user_guid == 0) {
172
-			$user_guid = $this->session->getLoggedInUserGuid();
173
-		}
174
-
175
-		$user_guid = (int) $user_guid;
176
-
177
-		$hash = $user_guid . 'get_access_array';
178
-
179
-		if ($cache[$hash]) {
180
-			$access_array = $cache[$hash];
181
-		} else {
182
-			// Public access is always visible
183
-			$access_array = [ACCESS_PUBLIC];
184
-
185
-			// The following can only return sensible data for a known user.
186
-			if ($user_guid) {
187
-				$access_array[] = ACCESS_LOGGED_IN;
188
-
189
-				// Get ACLs that user owns or is a member of
190
-				$query = "
26
+    /**
27
+     * @var Conf
28
+     */
29
+    protected $config;
30
+
31
+    /**
32
+     * @var Database
33
+     */
34
+    protected $db;
35
+
36
+    /**
37
+     * @vars \ElggStateVariableCache
38
+     */
39
+    protected $access_cache;
40
+
41
+    /**
42
+     * @var PluginHooksService
43
+     */
44
+    protected $hooks;
45
+
46
+    /**
47
+     * @var ElggSession
48
+     */
49
+    protected $session;
50
+
51
+    /**
52
+     * @var EntityTable
53
+     */
54
+    protected $entities;
55
+
56
+    /**
57
+     * @var Translator
58
+     */
59
+    protected $translator;
60
+
61
+    /**
62
+     * @var string
63
+     */
64
+    protected $table;
65
+
66
+    /**
67
+     * @var string
68
+     */
69
+    protected $membership_table;
70
+
71
+    /**
72
+     * @var bool
73
+     */
74
+    protected $init_complete = false;
75
+
76
+    /**
77
+     * Constructor
78
+     *
79
+     * @param Conf                    $config     Config
80
+     * @param Database                $db         Database
81
+     * @param EntityTable             $entities   Entity table
82
+     * @param ElggStaticVariableCache $cache      Access cache
83
+     * @param PluginHooksService      $hooks      Hooks
84
+     * @param ElggSession             $session    Session
85
+     * @param Translator              $translator Translator
86
+     */
87
+    public function __construct(
88
+            Conf $config,
89
+            Database $db,
90
+            EntityTable $entities,
91
+            ElggStaticVariableCache $cache,
92
+            PluginHooksService $hooks,
93
+            ElggSession $session,
94
+            Translator $translator) {
95
+        $this->config = $config;
96
+        $this->db = $db;
97
+        $this->entities = $entities;
98
+        $this->access_cache = $cache;
99
+        $this->hooks = $hooks;
100
+        $this->session = $session;
101
+        $this->translator = $translator;
102
+
103
+        $this->table = "{$this->db->prefix}access_collections";
104
+        $this->membership_table = "{$this->db->prefix}access_collection_membership";
105
+    }
106
+
107
+    /**
108
+     * Mark the access system as initialized
109
+     *
110
+     * @return void
111
+     */
112
+    public function markInitComplete() {
113
+        $this->init_complete = true;
114
+    }
115
+
116
+    /**
117
+     * Returns a string of access_ids for $user_guid appropriate for inserting into an SQL IN clause.
118
+     *
119
+     * @see get_access_array()
120
+     *
121
+     * @param int  $user_guid User ID; defaults to currently logged in user
122
+     * @param bool $flush     If set to true, will refresh the access list from the
123
+     *                        database rather than using this function's cache.
124
+     *
125
+     * @return string A concatenated string of access collections suitable for using in an SQL IN clause
126
+     * @access private
127
+     */
128
+    public function getAccessList($user_guid = 0, $flush = false) {
129
+        $access_array = $this->getAccessArray($user_guid, $flush);
130
+        $access_ids = implode(',', $access_array);
131
+        $list = "($access_ids)";
132
+
133
+        // for BC, populate the cache
134
+        $hash = $user_guid . 'get_access_list';
135
+        $this->access_cache->add($hash, $list);
136
+
137
+        return $list;
138
+    }
139
+
140
+    /**
141
+     * Returns an array of access IDs a user is permitted to see.
142
+     *
143
+     * Can be overridden with the 'access:collections:read', 'user' plugin hook.
144
+     * @warning A callback for that plugin hook needs to either not retrieve data
145
+     * from the database that would use the access system (triggering the plugin again)
146
+     * or ignore the second call. Otherwise, an infinite loop will be created.
147
+     *
148
+     * This returns a list of all the collection ids a user owns or belongs
149
+     * to plus public and logged in access levels. If the user is an admin, it includes
150
+     * the private access level.
151
+     *
152
+     * @internal this is only used in core for creating the SQL where clause when
153
+     * retrieving content from the database. The friends access level is handled by
154
+     * _elgg_get_access_where_sql().
155
+     *
156
+     * @see get_write_access_array() for the access levels that a user can write to.
157
+     *
158
+     * @param int  $user_guid User ID; defaults to currently logged in user
159
+     * @param bool $flush     If set to true, will refresh the access ids from the
160
+     *                        database rather than using this function's cache.
161
+     *
162
+     * @return array An array of access collections ids
163
+     */
164
+    public function getAccessArray($user_guid = 0, $flush = false) {
165
+        $cache = $this->access_cache;
166
+
167
+        if ($flush) {
168
+            $cache->clear();
169
+        }
170
+
171
+        if ($user_guid == 0) {
172
+            $user_guid = $this->session->getLoggedInUserGuid();
173
+        }
174
+
175
+        $user_guid = (int) $user_guid;
176
+
177
+        $hash = $user_guid . 'get_access_array';
178
+
179
+        if ($cache[$hash]) {
180
+            $access_array = $cache[$hash];
181
+        } else {
182
+            // Public access is always visible
183
+            $access_array = [ACCESS_PUBLIC];
184
+
185
+            // The following can only return sensible data for a known user.
186
+            if ($user_guid) {
187
+                $access_array[] = ACCESS_LOGGED_IN;
188
+
189
+                // Get ACLs that user owns or is a member of
190
+                $query = "
191 191
 					SELECT ac.id
192 192
 					FROM {$this->table} ac
193 193
 					WHERE ac.owner_guid = :user_guid
@@ -197,686 +197,686 @@  discard block
 block discarded – undo
197 197
 							   AND user_guid = :user_guid)
198 198
 				";
199 199
 
200
-				$collections = $this->db->getData($query, null, [
201
-					':user_guid' => $user_guid,
202
-				]);
203
-
204
-				if ($collections) {
205
-					foreach ($collections as $collection) {
206
-						$access_array[] = (int) $collection->id;
207
-					}
208
-				}
209
-
210
-				$ignore_access = elgg_check_access_overrides($user_guid);
211
-
212
-				if ($ignore_access == true) {
213
-					$access_array[] = ACCESS_PRIVATE;
214
-				}
215
-			}
216
-
217
-			if ($this->init_complete) {
218
-				$cache[$hash] = $access_array;
219
-			}
220
-		}
221
-
222
-		$options = [
223
-			'user_id' => $user_guid,
224
-		];
225
-
226
-		// see the warning in the docs for this function about infinite loop potential
227
-		return $this->hooks->trigger('access:collections:read', 'user', $options, $access_array);
228
-	}
229
-
230
-	/**
231
-	 * Returns the SQL where clause for enforcing read access to data.
232
-	 *
233
-	 * Note that if this code is executed in privileged mode it will return (1=1).
234
-	 *
235
-	 * Otherwise it returns a where clause to retrieve the data that a user has
236
-	 * permission to read.
237
-	 *
238
-	 * Plugin authors can hook into the 'get_sql', 'access' plugin hook to modify,
239
-	 * remove, or add to the where clauses. The plugin hook will pass an array with the current
240
-	 * ors and ands to the function in the form:
241
-	 *  array(
242
-	 *      'ors' => array(),
243
-	 *      'ands' => array()
244
-	 *  )
245
-	 *
246
-	 * The results will be combined into an SQL where clause in the form:
247
-	 *  ((or1 OR or2 OR orN) AND (and1 AND and2 AND andN))
248
-	 *
249
-	 * @param array $options Array in format:
250
-	 *
251
-	 * 	table_alias => STR Optional table alias. This is based on the select and join clauses.
252
-	 *                     Default is 'e'.
253
-	 *
254
-	 *  user_guid => INT Optional GUID for the user that we are retrieving data for.
255
-	 *                   Defaults to the logged in user if null.
256
-	 *                   Passing 0 will build a query for a logged out user (even if there is a logged in user)
257
-	 *
258
-	 *  use_enabled_clause => BOOL Optional. Should we append the enabled clause? The default
259
-	 *                             is set by access_show_hidden_entities().
260
-	 *
261
-	 *  access_column => STR Optional access column name. Default is 'access_id'.
262
-	 *
263
-	 *  owner_guid_column => STR Optional owner_guid column. Default is 'owner_guid'.
264
-	 *
265
-	 *  guid_column => STR Optional guid_column. Default is 'guid'.
266
-	 *
267
-	 * @return string
268
-	 * @access private
269
-	 */
270
-	public function getWhereSql(array $options = []) {
271
-
272
-		$defaults = [
273
-			'table_alias' => 'e',
274
-			'user_guid' => $this->session->getLoggedInUserGuid(),
275
-			'use_enabled_clause' => !access_get_show_hidden_status(),
276
-			'access_column' => 'access_id',
277
-			'owner_guid_column' => 'owner_guid',
278
-			'guid_column' => 'guid',
279
-		];
280
-
281
-		foreach ($options as $key => $value) {
282
-			if (is_null($value)) {
283
-				// remove null values so we don't loose defaults in array_merge
284
-				unset($options[$key]);
285
-			}
286
-		}
287
-
288
-		$options = array_merge($defaults, $options);
289
-
290
-		// just in case someone passes a . at the end
291
-		$options['table_alias'] = rtrim($options['table_alias'], '.');
292
-
293
-		foreach (['table_alias', 'access_column', 'owner_guid_column', 'guid_column'] as $key) {
294
-			$options[$key] = sanitize_string($options[$key]);
295
-		}
296
-		$options['user_guid'] = sanitize_int($options['user_guid'], false);
297
-
298
-		// only add dot if we have an alias or table name
299
-		$table_alias = $options['table_alias'] ? $options['table_alias'] . '.' : '';
300
-
301
-		if (!isset($options['ignore_access'])) {
302
-			$options['ignore_access'] = elgg_check_access_overrides($options['user_guid']);
303
-		}
304
-
305
-		$clauses = [
306
-			'ors' => [],
307
-			'ands' => []
308
-		];
309
-
310
-		$prefix = $this->db->prefix;
311
-
312
-		if ($options['ignore_access']) {
313
-			$clauses['ors']['ignore_access'] = '1 = 1';
314
-		} else if ($options['user_guid']) {
315
-			// include content of user's friends
316
-			$clauses['ors']['friends_access'] = "$table_alias{$options['access_column']} = " . ACCESS_FRIENDS . "
200
+                $collections = $this->db->getData($query, null, [
201
+                    ':user_guid' => $user_guid,
202
+                ]);
203
+
204
+                if ($collections) {
205
+                    foreach ($collections as $collection) {
206
+                        $access_array[] = (int) $collection->id;
207
+                    }
208
+                }
209
+
210
+                $ignore_access = elgg_check_access_overrides($user_guid);
211
+
212
+                if ($ignore_access == true) {
213
+                    $access_array[] = ACCESS_PRIVATE;
214
+                }
215
+            }
216
+
217
+            if ($this->init_complete) {
218
+                $cache[$hash] = $access_array;
219
+            }
220
+        }
221
+
222
+        $options = [
223
+            'user_id' => $user_guid,
224
+        ];
225
+
226
+        // see the warning in the docs for this function about infinite loop potential
227
+        return $this->hooks->trigger('access:collections:read', 'user', $options, $access_array);
228
+    }
229
+
230
+    /**
231
+     * Returns the SQL where clause for enforcing read access to data.
232
+     *
233
+     * Note that if this code is executed in privileged mode it will return (1=1).
234
+     *
235
+     * Otherwise it returns a where clause to retrieve the data that a user has
236
+     * permission to read.
237
+     *
238
+     * Plugin authors can hook into the 'get_sql', 'access' plugin hook to modify,
239
+     * remove, or add to the where clauses. The plugin hook will pass an array with the current
240
+     * ors and ands to the function in the form:
241
+     *  array(
242
+     *      'ors' => array(),
243
+     *      'ands' => array()
244
+     *  )
245
+     *
246
+     * The results will be combined into an SQL where clause in the form:
247
+     *  ((or1 OR or2 OR orN) AND (and1 AND and2 AND andN))
248
+     *
249
+     * @param array $options Array in format:
250
+     *
251
+     * 	table_alias => STR Optional table alias. This is based on the select and join clauses.
252
+     *                     Default is 'e'.
253
+     *
254
+     *  user_guid => INT Optional GUID for the user that we are retrieving data for.
255
+     *                   Defaults to the logged in user if null.
256
+     *                   Passing 0 will build a query for a logged out user (even if there is a logged in user)
257
+     *
258
+     *  use_enabled_clause => BOOL Optional. Should we append the enabled clause? The default
259
+     *                             is set by access_show_hidden_entities().
260
+     *
261
+     *  access_column => STR Optional access column name. Default is 'access_id'.
262
+     *
263
+     *  owner_guid_column => STR Optional owner_guid column. Default is 'owner_guid'.
264
+     *
265
+     *  guid_column => STR Optional guid_column. Default is 'guid'.
266
+     *
267
+     * @return string
268
+     * @access private
269
+     */
270
+    public function getWhereSql(array $options = []) {
271
+
272
+        $defaults = [
273
+            'table_alias' => 'e',
274
+            'user_guid' => $this->session->getLoggedInUserGuid(),
275
+            'use_enabled_clause' => !access_get_show_hidden_status(),
276
+            'access_column' => 'access_id',
277
+            'owner_guid_column' => 'owner_guid',
278
+            'guid_column' => 'guid',
279
+        ];
280
+
281
+        foreach ($options as $key => $value) {
282
+            if (is_null($value)) {
283
+                // remove null values so we don't loose defaults in array_merge
284
+                unset($options[$key]);
285
+            }
286
+        }
287
+
288
+        $options = array_merge($defaults, $options);
289
+
290
+        // just in case someone passes a . at the end
291
+        $options['table_alias'] = rtrim($options['table_alias'], '.');
292
+
293
+        foreach (['table_alias', 'access_column', 'owner_guid_column', 'guid_column'] as $key) {
294
+            $options[$key] = sanitize_string($options[$key]);
295
+        }
296
+        $options['user_guid'] = sanitize_int($options['user_guid'], false);
297
+
298
+        // only add dot if we have an alias or table name
299
+        $table_alias = $options['table_alias'] ? $options['table_alias'] . '.' : '';
300
+
301
+        if (!isset($options['ignore_access'])) {
302
+            $options['ignore_access'] = elgg_check_access_overrides($options['user_guid']);
303
+        }
304
+
305
+        $clauses = [
306
+            'ors' => [],
307
+            'ands' => []
308
+        ];
309
+
310
+        $prefix = $this->db->prefix;
311
+
312
+        if ($options['ignore_access']) {
313
+            $clauses['ors']['ignore_access'] = '1 = 1';
314
+        } else if ($options['user_guid']) {
315
+            // include content of user's friends
316
+            $clauses['ors']['friends_access'] = "$table_alias{$options['access_column']} = " . ACCESS_FRIENDS . "
317 317
 				AND $table_alias{$options['owner_guid_column']} IN (
318 318
 					SELECT guid_one FROM {$prefix}entity_relationships
319 319
 					WHERE relationship = 'friend' AND guid_two = {$options['user_guid']}
320 320
 				)";
321 321
 
322
-			// include user's content
323
-			$clauses['ors']['owner_access'] = "$table_alias{$options['owner_guid_column']} = {$options['user_guid']}";
324
-		}
325
-
326
-		// include standard accesses (public, logged in, access collections)
327
-		if (!$options['ignore_access']) {
328
-			$access_list = $this->getAccessList($options['user_guid']);
329
-			$clauses['ors']['acl_access'] = "$table_alias{$options['access_column']} IN {$access_list}";
330
-		}
331
-
332
-		if ($options['use_enabled_clause']) {
333
-			$clauses['ands']['use_enabled'] = "{$table_alias}enabled = 'yes'";
334
-		}
335
-
336
-		$clauses = $this->hooks->trigger('get_sql', 'access', $options, $clauses);
337
-
338
-		$clauses_str = '';
339
-		if (is_array($clauses['ors']) && $clauses['ors']) {
340
-			$clauses_str = '(' . implode(' OR ', $clauses['ors']) . ')';
341
-		}
342
-
343
-		if (is_array($clauses['ands']) && $clauses['ands']) {
344
-			if ($clauses_str) {
345
-				$clauses_str .= ' AND ';
346
-			}
347
-			$clauses_str .= '(' . implode(' AND ', $clauses['ands']) . ')';
348
-		}
349
-
350
-		return "($clauses_str)";
351
-	}
352
-
353
-	/**
354
-	 * Can a user access an entity.
355
-	 *
356
-	 * @warning If a logged in user doesn't have access to an entity, the
357
-	 * core engine will not load that entity.
358
-	 *
359
-	 * @tip This is mostly useful for checking if a user other than the logged in
360
-	 * user has access to an entity that is currently loaded.
361
-	 *
362
-	 * @todo This function would be much more useful if we could pass the guid of the
363
-	 * entity to test access for. We need to be able to tell whether the entity exists
364
-	 * and whether the user has access to the entity.
365
-	 *
366
-	 * @param ElggEntity $entity The entity to check access for.
367
-	 * @param ElggUser   $user   Optionally user to check access for. Defaults to
368
-	 *                           logged in user (which is a useless default).
369
-	 *
370
-	 * @return bool
371
-	 */
372
-	public function hasAccessToEntity($entity, $user = null) {
373
-		if (!$entity instanceof \ElggEntity) {
374
-			return false;
375
-		}
376
-
377
-		if ($entity->access_id == ACCESS_PUBLIC) {
378
-			// Public entities are always accessible
379
-			return true;
380
-		}
381
-
382
-		$user_guid = isset($user) ? (int) $user->guid : elgg_get_logged_in_user_guid();
383
-
384
-		if ($user_guid && $user_guid == $entity->owner_guid) {
385
-			// Owners have access to their own content
386
-			return true;
387
-		}
388
-
389
-		if ($user_guid && $entity->access_id == ACCESS_LOGGED_IN) {
390
-			// Existing users have access to entities with logged in access
391
-			return true;
392
-		}
393
-
394
-		// See #7159. Must not allow ignore access to affect query
395
-		$ia = elgg_set_ignore_access(false);
322
+            // include user's content
323
+            $clauses['ors']['owner_access'] = "$table_alias{$options['owner_guid_column']} = {$options['user_guid']}";
324
+        }
325
+
326
+        // include standard accesses (public, logged in, access collections)
327
+        if (!$options['ignore_access']) {
328
+            $access_list = $this->getAccessList($options['user_guid']);
329
+            $clauses['ors']['acl_access'] = "$table_alias{$options['access_column']} IN {$access_list}";
330
+        }
331
+
332
+        if ($options['use_enabled_clause']) {
333
+            $clauses['ands']['use_enabled'] = "{$table_alias}enabled = 'yes'";
334
+        }
335
+
336
+        $clauses = $this->hooks->trigger('get_sql', 'access', $options, $clauses);
337
+
338
+        $clauses_str = '';
339
+        if (is_array($clauses['ors']) && $clauses['ors']) {
340
+            $clauses_str = '(' . implode(' OR ', $clauses['ors']) . ')';
341
+        }
342
+
343
+        if (is_array($clauses['ands']) && $clauses['ands']) {
344
+            if ($clauses_str) {
345
+                $clauses_str .= ' AND ';
346
+            }
347
+            $clauses_str .= '(' . implode(' AND ', $clauses['ands']) . ')';
348
+        }
349
+
350
+        return "($clauses_str)";
351
+    }
352
+
353
+    /**
354
+     * Can a user access an entity.
355
+     *
356
+     * @warning If a logged in user doesn't have access to an entity, the
357
+     * core engine will not load that entity.
358
+     *
359
+     * @tip This is mostly useful for checking if a user other than the logged in
360
+     * user has access to an entity that is currently loaded.
361
+     *
362
+     * @todo This function would be much more useful if we could pass the guid of the
363
+     * entity to test access for. We need to be able to tell whether the entity exists
364
+     * and whether the user has access to the entity.
365
+     *
366
+     * @param ElggEntity $entity The entity to check access for.
367
+     * @param ElggUser   $user   Optionally user to check access for. Defaults to
368
+     *                           logged in user (which is a useless default).
369
+     *
370
+     * @return bool
371
+     */
372
+    public function hasAccessToEntity($entity, $user = null) {
373
+        if (!$entity instanceof \ElggEntity) {
374
+            return false;
375
+        }
376
+
377
+        if ($entity->access_id == ACCESS_PUBLIC) {
378
+            // Public entities are always accessible
379
+            return true;
380
+        }
381
+
382
+        $user_guid = isset($user) ? (int) $user->guid : elgg_get_logged_in_user_guid();
383
+
384
+        if ($user_guid && $user_guid == $entity->owner_guid) {
385
+            // Owners have access to their own content
386
+            return true;
387
+        }
388
+
389
+        if ($user_guid && $entity->access_id == ACCESS_LOGGED_IN) {
390
+            // Existing users have access to entities with logged in access
391
+            return true;
392
+        }
393
+
394
+        // See #7159. Must not allow ignore access to affect query
395
+        $ia = elgg_set_ignore_access(false);
396 396
 		
397
-		$row = $this->entities->getRow($entity->guid, $user_guid);
398
-
399
-		elgg_set_ignore_access($ia);
400
-
401
-		return !empty($row);
402
-	}
403
-
404
-	/**
405
-	 * Returns an array of access permissions that the user is allowed to save content with.
406
-	 * Permissions returned are of the form (id => 'name').
407
-	 *
408
-	 * Example return value in English:
409
-	 * array(
410
-	 *     0 => 'Private',
411
-	 *    -2 => 'Friends',
412
-	 *     1 => 'Logged in users',
413
-	 *     2 => 'Public',
414
-	 *    34 => 'My favorite friends',
415
-	 * );
416
-	 *
417
-	 * Plugin hook of 'access:collections:write', 'user'
418
-	 *
419
-	 * @warning this only returns access collections that the user owns plus the
420
-	 * standard access levels. It does not return access collections that the user
421
-	 * belongs to such as the access collection for a group.
422
-	 *
423
-	 * @param int   $user_guid    The user's GUID.
424
-	 * @param bool  $flush        If this is set to true, this will ignore a cached access array
425
-	 * @param array $input_params Some parameters passed into an input/access view
426
-	 *
427
-	 * @return array List of access permissions
428
-	 */
429
-	public function getWriteAccessArray($user_guid = 0, $flush = false, array $input_params = []) {
430
-		$cache = $this->access_cache;
431
-
432
-		if ($flush) {
433
-			$cache->clear();
434
-		}
435
-
436
-		if ($user_guid == 0) {
437
-			$user_guid = $this->session->getLoggedInUserGuid();
438
-		}
439
-
440
-		$user_guid = (int) $user_guid;
441
-
442
-		$hash = $user_guid . 'get_write_access_array';
443
-
444
-		if ($cache[$hash]) {
445
-			$access_array = $cache[$hash];
446
-		} else {
447
-			// @todo is there such a thing as public write access?
448
-			$access_array = [
449
-				ACCESS_PRIVATE => $this->getReadableAccessLevel(ACCESS_PRIVATE),
450
-				ACCESS_LOGGED_IN => $this->getReadableAccessLevel(ACCESS_LOGGED_IN),
451
-				ACCESS_PUBLIC => $this->getReadableAccessLevel(ACCESS_PUBLIC)
452
-			];
453
-
454
-			$collections = $this->getEntityCollections($user_guid);
455
-			if ($collections) {
456
-				foreach ($collections as $collection) {
457
-					$access_array[$collection->id] = $collection->name;
458
-				}
459
-			}
460
-
461
-			if ($this->init_complete) {
462
-				$cache[$hash] = $access_array;
463
-			}
464
-		}
465
-
466
-		$options = [
467
-			'user_id' => $user_guid,
468
-			'input_params' => $input_params,
469
-		];
470
-		return $this->hooks->trigger('access:collections:write', 'user', $options, $access_array);
471
-	}
472
-
473
-	/**
474
-	 * Can the user change this access collection?
475
-	 *
476
-	 * Use the plugin hook of 'access:collections:write', 'user' to change this.
477
-	 * @see get_write_access_array() for details on the hook.
478
-	 *
479
-	 * Respects access control disabling for admin users and {@link elgg_set_ignore_access()}
480
-	 *
481
-	 * @see get_write_access_array()
482
-	 *
483
-	 * @param int   $collection_id The collection id
484
-	 * @param mixed $user_guid     The user GUID to check for. Defaults to logged in user.
485
-	 * @return bool
486
-	 */
487
-	public function canEdit($collection_id, $user_guid = null) {
488
-		try {
489
-			$user = $this->entities->getUserForPermissionsCheck($user_guid);
490
-		} catch (UserFetchFailureException $e) {
491
-			return false;
492
-		}
493
-
494
-		$collection = $this->get($collection_id);
495
-
496
-		if (!$user || !$collection) {
497
-			return false;
498
-		}
499
-
500
-		if (elgg_check_access_overrides($user->guid)) {
501
-			return true;
502
-		}
503
-
504
-		$write_access = $this->getWriteAccessArray($user->guid, true);
505
-		return array_key_exists($collection_id, $write_access);
506
-	}
507
-
508
-	/**
509
-	 * Creates a new access collection.
510
-	 *
511
-	 * Access colletions allow plugins and users to create granular access
512
-	 * for entities.
513
-	 *
514
-	 * Triggers plugin hook 'access:collections:addcollection', 'collection'
515
-	 *
516
-	 * @internal Access collections are stored in the access_collections table.
517
-	 * Memberships to collections are in access_collections_membership.
518
-	 *
519
-	 * @param string $name       The name of the collection.
520
-	 * @param int    $owner_guid The GUID of the owner (default: currently logged in user).
521
-	 *
522
-	 * @return int|false The collection ID if successful and false on failure.
523
-	 */
524
-	public function create($name, $owner_guid = 0) {
525
-		$name = trim($name);
526
-		if (empty($name)) {
527
-			return false;
528
-		}
529
-
530
-		if ($owner_guid == 0) {
531
-			$owner_guid = $this->session->getLoggedInUserGuid();
532
-		}
533
-
534
-		$query = "
397
+        $row = $this->entities->getRow($entity->guid, $user_guid);
398
+
399
+        elgg_set_ignore_access($ia);
400
+
401
+        return !empty($row);
402
+    }
403
+
404
+    /**
405
+     * Returns an array of access permissions that the user is allowed to save content with.
406
+     * Permissions returned are of the form (id => 'name').
407
+     *
408
+     * Example return value in English:
409
+     * array(
410
+     *     0 => 'Private',
411
+     *    -2 => 'Friends',
412
+     *     1 => 'Logged in users',
413
+     *     2 => 'Public',
414
+     *    34 => 'My favorite friends',
415
+     * );
416
+     *
417
+     * Plugin hook of 'access:collections:write', 'user'
418
+     *
419
+     * @warning this only returns access collections that the user owns plus the
420
+     * standard access levels. It does not return access collections that the user
421
+     * belongs to such as the access collection for a group.
422
+     *
423
+     * @param int   $user_guid    The user's GUID.
424
+     * @param bool  $flush        If this is set to true, this will ignore a cached access array
425
+     * @param array $input_params Some parameters passed into an input/access view
426
+     *
427
+     * @return array List of access permissions
428
+     */
429
+    public function getWriteAccessArray($user_guid = 0, $flush = false, array $input_params = []) {
430
+        $cache = $this->access_cache;
431
+
432
+        if ($flush) {
433
+            $cache->clear();
434
+        }
435
+
436
+        if ($user_guid == 0) {
437
+            $user_guid = $this->session->getLoggedInUserGuid();
438
+        }
439
+
440
+        $user_guid = (int) $user_guid;
441
+
442
+        $hash = $user_guid . 'get_write_access_array';
443
+
444
+        if ($cache[$hash]) {
445
+            $access_array = $cache[$hash];
446
+        } else {
447
+            // @todo is there such a thing as public write access?
448
+            $access_array = [
449
+                ACCESS_PRIVATE => $this->getReadableAccessLevel(ACCESS_PRIVATE),
450
+                ACCESS_LOGGED_IN => $this->getReadableAccessLevel(ACCESS_LOGGED_IN),
451
+                ACCESS_PUBLIC => $this->getReadableAccessLevel(ACCESS_PUBLIC)
452
+            ];
453
+
454
+            $collections = $this->getEntityCollections($user_guid);
455
+            if ($collections) {
456
+                foreach ($collections as $collection) {
457
+                    $access_array[$collection->id] = $collection->name;
458
+                }
459
+            }
460
+
461
+            if ($this->init_complete) {
462
+                $cache[$hash] = $access_array;
463
+            }
464
+        }
465
+
466
+        $options = [
467
+            'user_id' => $user_guid,
468
+            'input_params' => $input_params,
469
+        ];
470
+        return $this->hooks->trigger('access:collections:write', 'user', $options, $access_array);
471
+    }
472
+
473
+    /**
474
+     * Can the user change this access collection?
475
+     *
476
+     * Use the plugin hook of 'access:collections:write', 'user' to change this.
477
+     * @see get_write_access_array() for details on the hook.
478
+     *
479
+     * Respects access control disabling for admin users and {@link elgg_set_ignore_access()}
480
+     *
481
+     * @see get_write_access_array()
482
+     *
483
+     * @param int   $collection_id The collection id
484
+     * @param mixed $user_guid     The user GUID to check for. Defaults to logged in user.
485
+     * @return bool
486
+     */
487
+    public function canEdit($collection_id, $user_guid = null) {
488
+        try {
489
+            $user = $this->entities->getUserForPermissionsCheck($user_guid);
490
+        } catch (UserFetchFailureException $e) {
491
+            return false;
492
+        }
493
+
494
+        $collection = $this->get($collection_id);
495
+
496
+        if (!$user || !$collection) {
497
+            return false;
498
+        }
499
+
500
+        if (elgg_check_access_overrides($user->guid)) {
501
+            return true;
502
+        }
503
+
504
+        $write_access = $this->getWriteAccessArray($user->guid, true);
505
+        return array_key_exists($collection_id, $write_access);
506
+    }
507
+
508
+    /**
509
+     * Creates a new access collection.
510
+     *
511
+     * Access colletions allow plugins and users to create granular access
512
+     * for entities.
513
+     *
514
+     * Triggers plugin hook 'access:collections:addcollection', 'collection'
515
+     *
516
+     * @internal Access collections are stored in the access_collections table.
517
+     * Memberships to collections are in access_collections_membership.
518
+     *
519
+     * @param string $name       The name of the collection.
520
+     * @param int    $owner_guid The GUID of the owner (default: currently logged in user).
521
+     *
522
+     * @return int|false The collection ID if successful and false on failure.
523
+     */
524
+    public function create($name, $owner_guid = 0) {
525
+        $name = trim($name);
526
+        if (empty($name)) {
527
+            return false;
528
+        }
529
+
530
+        if ($owner_guid == 0) {
531
+            $owner_guid = $this->session->getLoggedInUserGuid();
532
+        }
533
+
534
+        $query = "
535 535
 			INSERT INTO {$this->table}
536 536
 			SET name = :name,
537 537
 				owner_guid = :owner_guid
538 538
 		";
539 539
 
540
-		$params = [
541
-			':name' => $name,
542
-			':owner_guid' => (int) $owner_guid,
543
-		];
544
-
545
-		$id = $this->db->insertData($query, $params);
546
-		if (!$id) {
547
-			return false;
548
-		}
549
-
550
-		$this->access_cache->clear();
551
-
552
-		$hook_params = [
553
-			'collection_id' => $id,
554
-			'name' => $name,
555
-			'owner_guid' => $owner_guid,
556
-		];
557
-
558
-		if (!$this->hooks->trigger('access:collections:addcollection', 'collection', $hook_params, true)) {
559
-			$this->delete($id);
560
-			return false;
561
-		}
562
-
563
-		return $id;
564
-	}
565
-
566
-	/**
567
-	 * Renames an access collection
568
-	 *
569
-	 * @param int    $collection_id ID of the collection
570
-	 * @param string $name          The name of the collection
571
-	 * @return bool
572
-	 */
573
-	public function rename($collection_id, $name) {
574
-
575
-		$query = "
540
+        $params = [
541
+            ':name' => $name,
542
+            ':owner_guid' => (int) $owner_guid,
543
+        ];
544
+
545
+        $id = $this->db->insertData($query, $params);
546
+        if (!$id) {
547
+            return false;
548
+        }
549
+
550
+        $this->access_cache->clear();
551
+
552
+        $hook_params = [
553
+            'collection_id' => $id,
554
+            'name' => $name,
555
+            'owner_guid' => $owner_guid,
556
+        ];
557
+
558
+        if (!$this->hooks->trigger('access:collections:addcollection', 'collection', $hook_params, true)) {
559
+            $this->delete($id);
560
+            return false;
561
+        }
562
+
563
+        return $id;
564
+    }
565
+
566
+    /**
567
+     * Renames an access collection
568
+     *
569
+     * @param int    $collection_id ID of the collection
570
+     * @param string $name          The name of the collection
571
+     * @return bool
572
+     */
573
+    public function rename($collection_id, $name) {
574
+
575
+        $query = "
576 576
 			UPDATE {$this->table}
577 577
 			SET name = :name
578 578
 			WHERE id = :id
579 579
 		";
580 580
 
581
-		$params = [
582
-			':name' => $name,
583
-			':id' => (int) $collection_id,
584
-		];
585
-
586
-		if ($this->db->insertData($query, $params)) {
587
-			$this->access_cache->clear();
588
-			return (int) $collection_id;
589
-		}
590
-
591
-		return false;
592
-	}
593
-
594
-
595
-	/**
596
-	 * Updates the membership in an access collection.
597
-	 *
598
-	 * @warning Expects a full list of all members that should
599
-	 * be part of the access collection
600
-	 *
601
-	 * @note This will run all hooks associated with adding or removing
602
-	 * members to access collections.
603
-	 *
604
-	 * @param int   $collection_id ID of the collection.
605
-	 * @param array $new_members   Array of member entities or GUIDs
606
-	 * @return bool
607
-	 */
608
-	public function update($collection_id, array $new_members = []) {
609
-		$acl = $this->get($collection_id);
610
-
611
-		if (!$acl) {
612
-			return false;
613
-		}
581
+        $params = [
582
+            ':name' => $name,
583
+            ':id' => (int) $collection_id,
584
+        ];
585
+
586
+        if ($this->db->insertData($query, $params)) {
587
+            $this->access_cache->clear();
588
+            return (int) $collection_id;
589
+        }
590
+
591
+        return false;
592
+    }
593
+
594
+
595
+    /**
596
+     * Updates the membership in an access collection.
597
+     *
598
+     * @warning Expects a full list of all members that should
599
+     * be part of the access collection
600
+     *
601
+     * @note This will run all hooks associated with adding or removing
602
+     * members to access collections.
603
+     *
604
+     * @param int   $collection_id ID of the collection.
605
+     * @param array $new_members   Array of member entities or GUIDs
606
+     * @return bool
607
+     */
608
+    public function update($collection_id, array $new_members = []) {
609
+        $acl = $this->get($collection_id);
610
+
611
+        if (!$acl) {
612
+            return false;
613
+        }
614 614
 		
615
-		$to_guid = function($elem) {
616
-			if (empty($elem)) {
617
-				return 0;
618
-			}
619
-			if (is_object($elem)) {
620
-				return (int) $elem->guid;
621
-			}
622
-			return (int) $elem;
623
-		};
615
+        $to_guid = function($elem) {
616
+            if (empty($elem)) {
617
+                return 0;
618
+            }
619
+            if (is_object($elem)) {
620
+                return (int) $elem->guid;
621
+            }
622
+            return (int) $elem;
623
+        };
624 624
 		
625
-		$current_members = [];
626
-		$new_members = array_map($to_guid, $new_members);
625
+        $current_members = [];
626
+        $new_members = array_map($to_guid, $new_members);
627 627
 
628
-		$current_members_batch = $this->getMembers($collection_id, [
629
-			'batch' => true,
630
-			'limit' => 0,
631
-			'callback' => false,
632
-		]);
628
+        $current_members_batch = $this->getMembers($collection_id, [
629
+            'batch' => true,
630
+            'limit' => 0,
631
+            'callback' => false,
632
+        ]);
633 633
 
634
-		foreach ($current_members_batch as $row) {
635
-			$current_members[] = $to_guid($row);
636
-		}
634
+        foreach ($current_members_batch as $row) {
635
+            $current_members[] = $to_guid($row);
636
+        }
637 637
 
638
-		$remove_members = array_diff($current_members, $new_members);
639
-		$add_members = array_diff($new_members, $current_members);
638
+        $remove_members = array_diff($current_members, $new_members);
639
+        $add_members = array_diff($new_members, $current_members);
640 640
 
641
-		$result = true;
641
+        $result = true;
642 642
 
643
-		foreach ($add_members as $guid) {
644
-			$result = $result && $this->addUser($guid, $collection_id);
645
-		}
643
+        foreach ($add_members as $guid) {
644
+            $result = $result && $this->addUser($guid, $collection_id);
645
+        }
646 646
 
647
-		foreach ($remove_members as $guid) {
648
-			$result = $result && $this->removeUser($guid, $collection_id);
649
-		}
647
+        foreach ($remove_members as $guid) {
648
+            $result = $result && $this->removeUser($guid, $collection_id);
649
+        }
650 650
 
651
-		$this->access_cache->clear();
651
+        $this->access_cache->clear();
652 652
 
653
-		return $result;
654
-	}
653
+        return $result;
654
+    }
655 655
 
656
-	/**
657
-	 * Deletes a collection and its membership information
658
-	 *
659
-	 * @param int $collection_id ID of the collection
660
-	 * @return bool
661
-	 */
662
-	public function delete($collection_id) {
663
-		$collection_id = (int) $collection_id;
656
+    /**
657
+     * Deletes a collection and its membership information
658
+     *
659
+     * @param int $collection_id ID of the collection
660
+     * @return bool
661
+     */
662
+    public function delete($collection_id) {
663
+        $collection_id = (int) $collection_id;
664 664
 
665
-		$params = [
666
-			'collection_id' => $collection_id,
667
-		];
665
+        $params = [
666
+            'collection_id' => $collection_id,
667
+        ];
668 668
 
669
-		if (!$this->hooks->trigger('access:collections:deletecollection', 'collection', $params, true)) {
670
-			return false;
671
-		}
669
+        if (!$this->hooks->trigger('access:collections:deletecollection', 'collection', $params, true)) {
670
+            return false;
671
+        }
672 672
 
673
-		// Deleting membership doesn't affect result of deleting ACL.
674
-		$query = "
673
+        // Deleting membership doesn't affect result of deleting ACL.
674
+        $query = "
675 675
 			DELETE FROM {$this->membership_table}
676 676
 			WHERE access_collection_id = :access_collection_id
677 677
 		";
678
-		$this->db->deleteData($query, [
679
-			':access_collection_id' => $collection_id,
680
-		]);
678
+        $this->db->deleteData($query, [
679
+            ':access_collection_id' => $collection_id,
680
+        ]);
681 681
 
682
-		$query = "
682
+        $query = "
683 683
 			DELETE FROM {$this->table}
684 684
 			WHERE id = :id
685 685
 		";
686
-		$result = $this->db->deleteData($query, [
687
-			':id' => $collection_id,
688
-		]);
686
+        $result = $this->db->deleteData($query, [
687
+            ':id' => $collection_id,
688
+        ]);
689 689
 
690
-		$this->access_cache->clear();
690
+        $this->access_cache->clear();
691 691
 		
692
-		return (bool) $result;
693
-	}
694
-
695
-	/**
696
-	 * Transforms a database row to an instance of ElggAccessCollection
697
-	 *
698
-	 * @param \stdClass $row Database row
699
-	 * @return \ElggAccessCollection
700
-	 */
701
-	public function rowToElggAccessCollection(\stdClass $row) {
702
-		return new \ElggAccessCollection($row);
703
-	}
704
-
705
-	/**
706
-	 * Get a specified access collection
707
-	 *
708
-	 * @note This doesn't return the members of an access collection,
709
-	 * just the database row of the actual collection.
710
-	 *
711
-	 * @see get_members_of_access_collection()
712
-	 *
713
-	 * @param int $collection_id The collection ID
714
-	 * @return \ElggAccessCollection|false
715
-	 */
716
-	public function get($collection_id) {
717
-
718
-		$callback = [$this, 'rowToElggAccessCollection'];
719
-
720
-		$query = "
692
+        return (bool) $result;
693
+    }
694
+
695
+    /**
696
+     * Transforms a database row to an instance of ElggAccessCollection
697
+     *
698
+     * @param \stdClass $row Database row
699
+     * @return \ElggAccessCollection
700
+     */
701
+    public function rowToElggAccessCollection(\stdClass $row) {
702
+        return new \ElggAccessCollection($row);
703
+    }
704
+
705
+    /**
706
+     * Get a specified access collection
707
+     *
708
+     * @note This doesn't return the members of an access collection,
709
+     * just the database row of the actual collection.
710
+     *
711
+     * @see get_members_of_access_collection()
712
+     *
713
+     * @param int $collection_id The collection ID
714
+     * @return \ElggAccessCollection|false
715
+     */
716
+    public function get($collection_id) {
717
+
718
+        $callback = [$this, 'rowToElggAccessCollection'];
719
+
720
+        $query = "
721 721
 			SELECT * FROM {$this->table}
722 722
 			WHERE id = :id
723 723
 		";
724 724
 
725
-		return $this->db->getDataRow($query, $callback, [
726
-			':id' => (int) $collection_id,
727
-		]);
728
-	}
729
-
730
-	/**
731
-	 * Check if user is already in the collection
732
-	 *
733
-	 * @param int $user_guid     GUID of the user
734
-	 * @param int $collection_id ID of the collection
735
-	 * @return bool
736
-	 */
737
-	public function hasUser($user_guid, $collection_id) {
738
-		$options = [
739
-			'guids' => (int) $user_guid,
740
-			'count' => true,
741
-		];
742
-		return (bool) $this->getMembers($collection_id, $options);
743
-	}
744
-
745
-	/**
746
-	 * Adds a user to an access collection.
747
-	 *
748
-	 * Triggers the 'access:collections:add_user', 'collection' plugin hook.
749
-	 *
750
-	 * @param int $user_guid     GUID of the user to add
751
-	 * @param int $collection_id ID of the collection to add them to
752
-	 * @return bool
753
-	 */
754
-	public function addUser($user_guid, $collection_id) {
755
-
756
-		$collection = $this->get($collection_id);
757
-
758
-		if (!$collection) {
759
-			return false;
760
-		}
761
-
762
-		if (!$this->entities->exists($user_guid)) {
763
-			return false;
764
-		}
765
-
766
-		$hook_params = [
767
-			'collection_id' => $collection->id,
768
-			'user_guid' => (int) $user_guid
769
-		];
770
-
771
-		$result = $this->hooks->trigger('access:collections:add_user', 'collection', $hook_params, true);
772
-		if ($result == false) {
773
-			return false;
774
-		}
775
-
776
-		// if someone tries to insert the same data twice, we do a no-op on duplicate key
777
-		$query = "
725
+        return $this->db->getDataRow($query, $callback, [
726
+            ':id' => (int) $collection_id,
727
+        ]);
728
+    }
729
+
730
+    /**
731
+     * Check if user is already in the collection
732
+     *
733
+     * @param int $user_guid     GUID of the user
734
+     * @param int $collection_id ID of the collection
735
+     * @return bool
736
+     */
737
+    public function hasUser($user_guid, $collection_id) {
738
+        $options = [
739
+            'guids' => (int) $user_guid,
740
+            'count' => true,
741
+        ];
742
+        return (bool) $this->getMembers($collection_id, $options);
743
+    }
744
+
745
+    /**
746
+     * Adds a user to an access collection.
747
+     *
748
+     * Triggers the 'access:collections:add_user', 'collection' plugin hook.
749
+     *
750
+     * @param int $user_guid     GUID of the user to add
751
+     * @param int $collection_id ID of the collection to add them to
752
+     * @return bool
753
+     */
754
+    public function addUser($user_guid, $collection_id) {
755
+
756
+        $collection = $this->get($collection_id);
757
+
758
+        if (!$collection) {
759
+            return false;
760
+        }
761
+
762
+        if (!$this->entities->exists($user_guid)) {
763
+            return false;
764
+        }
765
+
766
+        $hook_params = [
767
+            'collection_id' => $collection->id,
768
+            'user_guid' => (int) $user_guid
769
+        ];
770
+
771
+        $result = $this->hooks->trigger('access:collections:add_user', 'collection', $hook_params, true);
772
+        if ($result == false) {
773
+            return false;
774
+        }
775
+
776
+        // if someone tries to insert the same data twice, we do a no-op on duplicate key
777
+        $query = "
778 778
 			INSERT INTO {$this->membership_table}
779 779
 				SET access_collection_id = :access_collection_id,
780 780
 				    user_guid = :user_guid
781 781
 				ON DUPLICATE KEY UPDATE user_guid = user_guid
782 782
 		";
783 783
 
784
-		$result = $this->db->insertData($query, [
785
-			':access_collection_id' => (int) $collection->id,
786
-			':user_guid' => (int) $user_guid,
787
-		]);
784
+        $result = $this->db->insertData($query, [
785
+            ':access_collection_id' => (int) $collection->id,
786
+            ':user_guid' => (int) $user_guid,
787
+        ]);
788 788
 
789
-		$this->access_cache->clear();
789
+        $this->access_cache->clear();
790 790
 		
791
-		return $result !== false;
792
-	}
793
-
794
-	/**
795
-	 * Removes a user from an access collection.
796
-	 *
797
-	 * Triggers the 'access:collections:remove_user', 'collection' plugin hook.
798
-	 *
799
-	 * @param int $user_guid     GUID of the user
800
-	 * @param int $collection_id ID of the collection
801
-	 * @return bool
802
-	 */
803
-	public function removeUser($user_guid, $collection_id) {
804
-
805
-		$params = [
806
-			'collection_id' => (int) $collection_id,
807
-			'user_guid' => (int) $user_guid,
808
-		];
809
-
810
-		if (!$this->hooks->trigger('access:collections:remove_user', 'collection', $params, true)) {
811
-			return false;
812
-		}
813
-
814
-		$query = "
791
+        return $result !== false;
792
+    }
793
+
794
+    /**
795
+     * Removes a user from an access collection.
796
+     *
797
+     * Triggers the 'access:collections:remove_user', 'collection' plugin hook.
798
+     *
799
+     * @param int $user_guid     GUID of the user
800
+     * @param int $collection_id ID of the collection
801
+     * @return bool
802
+     */
803
+    public function removeUser($user_guid, $collection_id) {
804
+
805
+        $params = [
806
+            'collection_id' => (int) $collection_id,
807
+            'user_guid' => (int) $user_guid,
808
+        ];
809
+
810
+        if (!$this->hooks->trigger('access:collections:remove_user', 'collection', $params, true)) {
811
+            return false;
812
+        }
813
+
814
+        $query = "
815 815
 			DELETE FROM {$this->membership_table}
816 816
 			WHERE access_collection_id = :access_collection_id
817 817
 				AND user_guid = :user_guid
818 818
 		";
819 819
 
820
-		$this->access_cache->clear();
820
+        $this->access_cache->clear();
821 821
 
822
-		return (bool) $this->db->deleteData($query, [
823
-			':access_collection_id' => (int) $collection_id,
824
-			':user_guid' => (int) $user_guid,
825
-		]);
826
-	}
822
+        return (bool) $this->db->deleteData($query, [
823
+            ':access_collection_id' => (int) $collection_id,
824
+            ':user_guid' => (int) $user_guid,
825
+        ]);
826
+    }
827 827
 
828
-	/**
829
-	 * Returns access collections owned by the user
830
-	 *
831
-	 * @param int $owner_guid GUID of the owner
832
-	 * @return ElggAccessCollection[]|false
833
-	 */
834
-	public function getEntityCollections($owner_guid) {
828
+    /**
829
+     * Returns access collections owned by the user
830
+     *
831
+     * @param int $owner_guid GUID of the owner
832
+     * @return ElggAccessCollection[]|false
833
+     */
834
+    public function getEntityCollections($owner_guid) {
835 835
 
836
-		$callback = [$this, 'rowToElggAccessCollection'];
836
+        $callback = [$this, 'rowToElggAccessCollection'];
837 837
 
838
-		$query = "
838
+        $query = "
839 839
 			SELECT * FROM {$this->table}
840 840
 				WHERE owner_guid = :owner_guid
841 841
 				ORDER BY name ASC
842 842
 		";
843 843
 
844
-		$params = [
845
-			':owner_guid' => (int) $owner_guid,
846
-		];
844
+        $params = [
845
+            ':owner_guid' => (int) $owner_guid,
846
+        ];
847 847
 
848
-		return $this->db->getData($query, $callback, $params);
849
-	}
848
+        return $this->db->getData($query, $callback, $params);
849
+    }
850 850
 
851
-	/**
852
-	 * Get members of an access collection
853
-	 *
854
-	 * @param int   $collection_id The collection's ID
855
-	 * @param array $options       Ege* options
856
-	 * @return ElggEntity[]|false
857
-	 */
858
-	public function getMembers($collection_id, array $options = []) {
851
+    /**
852
+     * Get members of an access collection
853
+     *
854
+     * @param int   $collection_id The collection's ID
855
+     * @param array $options       Ege* options
856
+     * @return ElggEntity[]|false
857
+     */
858
+    public function getMembers($collection_id, array $options = []) {
859 859
 
860
-		$options['joins'][] = "JOIN {$this->membership_table} acm";
860
+        $options['joins'][] = "JOIN {$this->membership_table} acm";
861 861
 
862
-		$collection_id = (int) $collection_id;
863
-		$options['wheres'][] = "e.guid = acm.user_guid AND acm.access_collection_id = {$collection_id}";
862
+        $collection_id = (int) $collection_id;
863
+        $options['wheres'][] = "e.guid = acm.user_guid AND acm.access_collection_id = {$collection_id}";
864 864
 
865
-		return $this->entities->getEntities($options);
866
-	}
865
+        return $this->entities->getEntities($options);
866
+    }
867 867
 
868
-	/**
869
-	 * Return an array of collections that the entity is member of
870
-	 *
871
-	 * @param int $member_guid GUID of th member
872
-	 *
873
-	 * @return ElggAccessCollection[]|false
874
-	 */
875
-	public function getCollectionsByMember($member_guid) {
868
+    /**
869
+     * Return an array of collections that the entity is member of
870
+     *
871
+     * @param int $member_guid GUID of th member
872
+     *
873
+     * @return ElggAccessCollection[]|false
874
+     */
875
+    public function getCollectionsByMember($member_guid) {
876 876
 
877
-		$callback = [$this, 'rowToElggAccessCollection'];
877
+        $callback = [$this, 'rowToElggAccessCollection'];
878 878
 
879
-		$query = "
879
+        $query = "
880 880
 			SELECT ac.* FROM {$this->table} ac
881 881
 				JOIN {$this->membership_table} acm
882 882
 					ON ac.id = acm.access_collection_id
@@ -884,58 +884,58 @@  discard block
 block discarded – undo
884 884
 				ORDER BY name ASC
885 885
 		";
886 886
 
887
-		return $this->db->getData($query, $callback, [
888
-			':member_guid' => (int) $member_guid,
889
-		]);
890
-	}
891
-
892
-	/**
893
-	 * Return the name of an ACCESS_* constant or an access collection,
894
-	 * but only if the logged in user owns the access collection or is an admin.
895
-	 * Ownership requirement prevents us from exposing names of access collections
896
-	 * that current user has been added to by other members and may contain
897
-	 * sensitive classification of the current user (e.g. close friends vs acquaintances).
898
-	 *
899
-	 * Returns a string in the language of the user for global access levels, e.g.'Public, 'Friends', 'Logged in', 'Private';
900
-	 * or a name of the owned access collection, e.g. 'My work colleagues';
901
-	 * or a name of the group or other access collection, e.g. 'Group: Elgg technical support';
902
-	 * or 'Limited' if the user access is restricted to read-only, e.g. a friends collection the user was added to
903
-	 *
904
-	 * @param int $entity_access_id The entity's access id
905
-	 *
906
-	 * @return string
907
-	 * @since 1.11
908
-	 */
909
-	public function getReadableAccessLevel($entity_access_id) {
910
-		$access = (int) $entity_access_id;
911
-
912
-		$translator = $this->translator;
913
-
914
-		// Check if entity access id is a defined global constant
915
-		$access_array = [
916
-			ACCESS_PRIVATE => $translator->translate("PRIVATE"),
917
-			ACCESS_FRIENDS => $translator->translate("access:friends:label"),
918
-			ACCESS_LOGGED_IN => $translator->translate("LOGGED_IN"),
919
-			ACCESS_PUBLIC => $translator->translate("PUBLIC"),
920
-		];
921
-
922
-		if (array_key_exists($access, $access_array)) {
923
-			return $access_array[$access];
924
-		}
925
-
926
-		// Entity access id is probably a custom access collection
927
-		// Check if the user has write access to it and can see it's label
928
-		// Admins should always be able to see the readable version
929
-		$collection = $this->get($access);
930
-
931
-		$user_guid = $this->session->getLoggedInUserGuid();
887
+        return $this->db->getData($query, $callback, [
888
+            ':member_guid' => (int) $member_guid,
889
+        ]);
890
+    }
891
+
892
+    /**
893
+     * Return the name of an ACCESS_* constant or an access collection,
894
+     * but only if the logged in user owns the access collection or is an admin.
895
+     * Ownership requirement prevents us from exposing names of access collections
896
+     * that current user has been added to by other members and may contain
897
+     * sensitive classification of the current user (e.g. close friends vs acquaintances).
898
+     *
899
+     * Returns a string in the language of the user for global access levels, e.g.'Public, 'Friends', 'Logged in', 'Private';
900
+     * or a name of the owned access collection, e.g. 'My work colleagues';
901
+     * or a name of the group or other access collection, e.g. 'Group: Elgg technical support';
902
+     * or 'Limited' if the user access is restricted to read-only, e.g. a friends collection the user was added to
903
+     *
904
+     * @param int $entity_access_id The entity's access id
905
+     *
906
+     * @return string
907
+     * @since 1.11
908
+     */
909
+    public function getReadableAccessLevel($entity_access_id) {
910
+        $access = (int) $entity_access_id;
911
+
912
+        $translator = $this->translator;
913
+
914
+        // Check if entity access id is a defined global constant
915
+        $access_array = [
916
+            ACCESS_PRIVATE => $translator->translate("PRIVATE"),
917
+            ACCESS_FRIENDS => $translator->translate("access:friends:label"),
918
+            ACCESS_LOGGED_IN => $translator->translate("LOGGED_IN"),
919
+            ACCESS_PUBLIC => $translator->translate("PUBLIC"),
920
+        ];
921
+
922
+        if (array_key_exists($access, $access_array)) {
923
+            return $access_array[$access];
924
+        }
925
+
926
+        // Entity access id is probably a custom access collection
927
+        // Check if the user has write access to it and can see it's label
928
+        // Admins should always be able to see the readable version
929
+        $collection = $this->get($access);
930
+
931
+        $user_guid = $this->session->getLoggedInUserGuid();
932 932
 		
933
-		if (!$collection || !$user_guid) {
934
-			// return 'Limited' if there is no logged in user or collection can not be loaded
935
-			return $translator->translate('access:limited:label');
936
-		}
933
+        if (!$collection || !$user_guid) {
934
+            // return 'Limited' if there is no logged in user or collection can not be loaded
935
+            return $translator->translate('access:limited:label');
936
+        }
937 937
 
938
-		return $collection->getDisplayName();
939
-	}
938
+        return $collection->getDisplayName();
939
+    }
940 940
 
941 941
 }
Please login to merge, or discard this patch.
views/default/languages.js.php 1 patch
Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -9,13 +9,13 @@
 block discarded – undo
9 9
 $translations = $all_translations['en'];
10 10
 
11 11
 if ($language != 'en' && !isset($all_translations[$language])) {
12
-	// try to reload missing translations
13
-	reload_all_translations();
14
-	$all_translations = _elgg_services()->translator->getLoadedTranslations();
12
+    // try to reload missing translations
13
+    reload_all_translations();
14
+    $all_translations = _elgg_services()->translator->getLoadedTranslations();
15 15
 }
16 16
 
17 17
 if ($language != 'en' && isset($all_translations[$language])) {
18
-	$translations = array_merge($translations, $all_translations[$language]);
18
+    $translations = array_merge($translations, $all_translations[$language]);
19 19
 }
20 20
 
21 21
 ?>
Please login to merge, or discard this patch.
engine/classes/Elgg/Database/SiteSecret.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -108,7 +108,7 @@
 block discarded – undo
108 108
 	 * @return SiteSecret
109 109
 	 */
110 110
 	public static function regenerate(ElggCrypto $crypto, ConfigTable $table) {
111
-		$key = 'z' . $crypto->getRandomString(31);
111
+		$key = 'z'.$crypto->getRandomString(31);
112 112
 
113 113
 		$table->set(self::CONFIG_KEY, $key);
114 114
 
Please login to merge, or discard this patch.
Indentation   +128 added lines, -128 removed lines patch added patch discarded remove patch
@@ -22,132 +22,132 @@
 block discarded – undo
22 22
  */
23 23
 class SiteSecret {
24 24
 
25
-	const CONFIG_KEY = '__site_secret__';
26
-
27
-	/**
28
-	 * Constructor
29
-	 *
30
-	 * @param string $key Site key (32 hex chars, or "z" and 31 base64 chars)
31
-	 */
32
-	public function __construct($key) {
33
-		$this->key = $key;
34
-	}
35
-
36
-	/**
37
-	 * @var string
38
-	 */
39
-	private $key;
40
-
41
-	/**
42
-	 * Returns the site secret.
43
-	 *
44
-	 * Used to generate difficult to guess hashes for sessions and action tokens.
45
-	 *
46
-	 * @param bool $raw If true, a binary key will be returned
47
-	 *
48
-	 * @return string Site secret.
49
-	 * @access private
50
-	 */
51
-	public function get($raw = false) {
52
-		if (!$this->key) {
53
-			throw new \RuntimeException('Secret key is not set');
54
-		}
55
-
56
-		if (!$raw) {
57
-			return $this->key;
58
-		}
59
-
60
-		// try to return binary key
61
-		if ($this->key[0] === 'z') {
62
-			// new keys are "z" + base64URL
63
-			$base64 = strtr(substr($this->key, 1), '-_', '+/');
64
-			$key = base64_decode($base64);
65
-			if ($key !== false) {
66
-				return $key;
67
-			}
68
-
69
-			// on failure, at least return string key :/
70
-			return $this->key;
71
-		}
72
-
73
-		// old keys are hex
74
-		return hex2bin($this->key);
75
-	}
76
-
77
-	/**
78
-	 * Get the strength of the site secret
79
-	 *
80
-	 * If "weak" or "moderate" is returned, this assumes we're running on the same system that created
81
-	 * the key.
82
-	 *
83
-	 * @return string "strong", "moderate", or "weak"
84
-	 * @access private
85
-	 */
86
-	public function getStrength() {
87
-		$secret = $this->get();
88
-		if ($secret[0] !== 'z') {
89
-			$rand_max = getrandmax();
90
-			if ($rand_max < pow(2, 16)) {
91
-				return 'weak';
92
-			}
93
-			if ($rand_max < pow(2, 32)) {
94
-				return 'moderate';
95
-			}
96
-		}
97
-		return 'strong';
98
-	}
99
-
100
-	/**
101
-	 * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL)
102
-	 * and save to config table.
103
-	 *
104
-	 * Used during installation or regeneration.
105
-	 *
106
-	 * @param ElggCrypto  $crypto Crypto service
107
-	 * @param ConfigTable $table  Config table
108
-	 * @return SiteSecret
109
-	 */
110
-	public static function regenerate(ElggCrypto $crypto, ConfigTable $table) {
111
-		$key = 'z' . $crypto->getRandomString(31);
112
-
113
-		$table->set(self::CONFIG_KEY, $key);
114
-
115
-		return new self($key);
116
-	}
117
-
118
-	/**
119
-	 * Create from config/storage.
120
-	 *
121
-	 * @param ConfigTable $table Config table
122
-	 *
123
-	 * @return SiteSecret
124
-	 * @throws \InstallationException
125
-	 */
126
-	public static function fromDatabase(ConfigTable $table) {
127
-		$key = $table->get(self::CONFIG_KEY);
128
-		if (!$key) {
129
-			throw new \InstallationException('Site secret is not in the config table.');
130
-		}
131
-
132
-		return new self($key);
133
-	}
134
-
135
-	/**
136
-	 * Create from a config value. If successful, the value will be erased from config.
137
-	 *
138
-	 * @param ElggConfig $config Config
139
-	 *
140
-	 * @return SiteSecret|false
141
-	 */
142
-	public static function fromConfig(ElggConfig $config) {
143
-		$key = $config->{self::CONFIG_KEY};
144
-		if (!$key) {
145
-			return false;
146
-		}
147
-
148
-		// Don't leave this sitting around in config, in case it gets dumped
149
-		unset($config->{self::CONFIG_KEY});
150
-
151
-		return new self($key);
152
-	}
25
+    const CONFIG_KEY = '__site_secret__';
26
+
27
+    /**
28
+     * Constructor
29
+     *
30
+     * @param string $key Site key (32 hex chars, or "z" and 31 base64 chars)
31
+     */
32
+    public function __construct($key) {
33
+        $this->key = $key;
34
+    }
35
+
36
+    /**
37
+     * @var string
38
+     */
39
+    private $key;
40
+
41
+    /**
42
+     * Returns the site secret.
43
+     *
44
+     * Used to generate difficult to guess hashes for sessions and action tokens.
45
+     *
46
+     * @param bool $raw If true, a binary key will be returned
47
+     *
48
+     * @return string Site secret.
49
+     * @access private
50
+     */
51
+    public function get($raw = false) {
52
+        if (!$this->key) {
53
+            throw new \RuntimeException('Secret key is not set');
54
+        }
55
+
56
+        if (!$raw) {
57
+            return $this->key;
58
+        }
59
+
60
+        // try to return binary key
61
+        if ($this->key[0] === 'z') {
62
+            // new keys are "z" + base64URL
63
+            $base64 = strtr(substr($this->key, 1), '-_', '+/');
64
+            $key = base64_decode($base64);
65
+            if ($key !== false) {
66
+                return $key;
67
+            }
68
+
69
+            // on failure, at least return string key :/
70
+            return $this->key;
71
+        }
72
+
73
+        // old keys are hex
74
+        return hex2bin($this->key);
75
+    }
76
+
77
+    /**
78
+     * Get the strength of the site secret
79
+     *
80
+     * If "weak" or "moderate" is returned, this assumes we're running on the same system that created
81
+     * the key.
82
+     *
83
+     * @return string "strong", "moderate", or "weak"
84
+     * @access private
85
+     */
86
+    public function getStrength() {
87
+        $secret = $this->get();
88
+        if ($secret[0] !== 'z') {
89
+            $rand_max = getrandmax();
90
+            if ($rand_max < pow(2, 16)) {
91
+                return 'weak';
92
+            }
93
+            if ($rand_max < pow(2, 32)) {
94
+                return 'moderate';
95
+            }
96
+        }
97
+        return 'strong';
98
+    }
99
+
100
+    /**
101
+     * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL)
102
+     * and save to config table.
103
+     *
104
+     * Used during installation or regeneration.
105
+     *
106
+     * @param ElggCrypto  $crypto Crypto service
107
+     * @param ConfigTable $table  Config table
108
+     * @return SiteSecret
109
+     */
110
+    public static function regenerate(ElggCrypto $crypto, ConfigTable $table) {
111
+        $key = 'z' . $crypto->getRandomString(31);
112
+
113
+        $table->set(self::CONFIG_KEY, $key);
114
+
115
+        return new self($key);
116
+    }
117
+
118
+    /**
119
+     * Create from config/storage.
120
+     *
121
+     * @param ConfigTable $table Config table
122
+     *
123
+     * @return SiteSecret
124
+     * @throws \InstallationException
125
+     */
126
+    public static function fromDatabase(ConfigTable $table) {
127
+        $key = $table->get(self::CONFIG_KEY);
128
+        if (!$key) {
129
+            throw new \InstallationException('Site secret is not in the config table.');
130
+        }
131
+
132
+        return new self($key);
133
+    }
134
+
135
+    /**
136
+     * Create from a config value. If successful, the value will be erased from config.
137
+     *
138
+     * @param ElggConfig $config Config
139
+     *
140
+     * @return SiteSecret|false
141
+     */
142
+    public static function fromConfig(ElggConfig $config) {
143
+        $key = $config->{self::CONFIG_KEY};
144
+        if (!$key) {
145
+            return false;
146
+        }
147
+
148
+        // Don't leave this sitting around in config, in case it gets dumped
149
+        unset($config->{self::CONFIG_KEY});
150
+
151
+        return new self($key);
152
+    }
153 153
 }
Please login to merge, or discard this patch.
index.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@
 block discarded – undo
2 2
 $autoload_path = __DIR__ . '/vendor/autoload.php';
3 3
 $autoload_available = include_once($autoload_path);
4 4
 if (!$autoload_available) {
5
-	die("Couldn't include '$autoload_path'. Did you run `composer install`?");
5
+    die("Couldn't include '$autoload_path'. Did you run `composer install`?");
6 6
 }
7 7
 
8 8
 return \Elgg\Application::index();
Please login to merge, or discard this patch.
engine/classes/ElggPlugin.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -59,7 +59,7 @@  discard block
 block discarded – undo
59 59
 		if (is_object($path)) {
60 60
 			// database object
61 61
 			parent::__construct($path);
62
-			$this->path = _elgg_config()->plugins_path . $this->getID();
62
+			$this->path = _elgg_config()->plugins_path.$this->getID();
63 63
 			_elgg_cache_plugin_by_id($this);
64 64
 			return;
65 65
 		}
@@ -147,7 +147,7 @@  discard block
 block discarded – undo
147 147
 	 * @deprecated 3.0
148 148
 	 */
149 149
 	public function getFriendlyName() {
150
-		elgg_deprecated_notice(__METHOD__ . ' is deprecated. Use getDisplayName().', '3.0');
150
+		elgg_deprecated_notice(__METHOD__.' is deprecated. Use getDisplayName().', '3.0');
151 151
 	
152 152
 		return $this->getDisplayName();
153 153
 	}
@@ -1233,7 +1233,7 @@  discard block
 block discarded – undo
1233 1233
 			}
1234 1234
 			$this->manifest = $package->getManifest();
1235 1235
 		} catch (Exception $e) {
1236
-			_elgg_services()->logger->warn("Failed to load manifest for plugin $this->guid. " . $e->getMessage());
1236
+			_elgg_services()->logger->warn("Failed to load manifest for plugin $this->guid. ".$e->getMessage());
1237 1237
 			$this->errorMsg = $e->getmessage();
1238 1238
 		}
1239 1239
 
@@ -1253,7 +1253,7 @@  discard block
 block discarded – undo
1253 1253
 		try {
1254 1254
 			$this->package = new \ElggPluginPackage($this->path, false);
1255 1255
 		} catch (Exception $e) {
1256
-			_elgg_services()->logger->warn("Failed to load package for $this->guid. " . $e->getMessage());
1256
+			_elgg_services()->logger->warn("Failed to load package for $this->guid. ".$e->getMessage());
1257 1257
 			$this->errorMsg = $e->getmessage();
1258 1258
 		}
1259 1259
 
Please login to merge, or discard this patch.
Indentation   +1195 added lines, -1195 removed lines patch added patch discarded remove patch
@@ -12,1252 +12,1252 @@
 block discarded – undo
12 12
  * @subpackage Plugins.Settings
13 13
  */
14 14
 class ElggPlugin extends \ElggObject {
15
-	private $package;
16
-	private $manifest;
17
-
18
-	/**
19
-	 * Data from static config file. null if not yet read.
20
-	 *
21
-	 * @var array|null
22
-	 */
23
-	private $static_config;
24
-
25
-	private $path;
26
-	private $errorMsg = '';
27
-
28
-	/**
29
-	 * Set subtype to 'plugin'
30
-	 *
31
-	 * @return void
32
-	 */
33
-	protected function initializeAttributes() {
34
-		parent::initializeAttributes();
35
-
36
-		$this->attributes['subtype'] = "plugin";
37
-
38
-		// plugins must be public.
39
-		$this->access_id = ACCESS_PUBLIC;
40
-	}
41
-
42
-	/**
43
-	 * Creates a new plugin from path
44
-	 *
45
-	 * @note Internal: also supports database objects
46
-	 *
47
-	 * @warning Unlike other \ElggEntity objects, you cannot null instantiate
48
-	 *          \ElggPlugin. You must provide the path to the plugin directory.
49
-	 *
50
-	 * @param string $path The absolute path of the plugin
51
-	 *
52
-	 * @throws PluginException
53
-	 */
54
-	public function __construct($path) {
55
-		if (!$path) {
56
-			throw new \PluginException("ElggPlugin cannot be null instantiated. You must pass a full path.");
57
-		}
58
-
59
-		if (is_object($path)) {
60
-			// database object
61
-			parent::__construct($path);
62
-			$this->path = _elgg_config()->plugins_path . $this->getID();
63
-			_elgg_cache_plugin_by_id($this);
64
-			return;
65
-		}
66
-
67
-		if (is_numeric($path)) {
68
-			// guid
69
-			// @todo plugins with directory names of '12345'
70
-			throw new \InvalidArgumentException('$path cannot be a GUID');
71
-		}
72
-
73
-		$this->initializeAttributes();
74
-
75
-		// path checking is done in the package
76
-		$path = sanitise_filepath($path);
77
-		$this->path = $path;
78
-		$path_parts = explode('/', rtrim($path, '/'));
79
-		$plugin_id = array_pop($path_parts);
80
-		$this->title = $plugin_id;
81
-
82
-		// check if we're loading an existing plugin
83
-		$existing_plugin = elgg_get_plugin_from_id($plugin_id);
84
-
85
-		if ($existing_plugin) {
86
-			$this->load((object) ['guid' => $existing_plugin->guid]);
87
-		}
88
-
89
-		_elgg_cache_plugin_by_id($this);
90
-	}
91
-
92
-	/**
93
-	 * Save the plugin object.  Make sure required values exist.
94
-	 *
95
-	 * @see \ElggObject::save()
96
-	 * @return bool
97
-	 */
98
-	public function save() {
99
-		// own by the current site so users can be deleted without affecting plugins
100
-		$site = elgg_get_site_entity();
101
-		$this->attributes['owner_guid'] = $site->guid;
102
-		$this->attributes['container_guid'] = $site->guid;
15
+    private $package;
16
+    private $manifest;
17
+
18
+    /**
19
+     * Data from static config file. null if not yet read.
20
+     *
21
+     * @var array|null
22
+     */
23
+    private $static_config;
24
+
25
+    private $path;
26
+    private $errorMsg = '';
27
+
28
+    /**
29
+     * Set subtype to 'plugin'
30
+     *
31
+     * @return void
32
+     */
33
+    protected function initializeAttributes() {
34
+        parent::initializeAttributes();
35
+
36
+        $this->attributes['subtype'] = "plugin";
37
+
38
+        // plugins must be public.
39
+        $this->access_id = ACCESS_PUBLIC;
40
+    }
41
+
42
+    /**
43
+     * Creates a new plugin from path
44
+     *
45
+     * @note Internal: also supports database objects
46
+     *
47
+     * @warning Unlike other \ElggEntity objects, you cannot null instantiate
48
+     *          \ElggPlugin. You must provide the path to the plugin directory.
49
+     *
50
+     * @param string $path The absolute path of the plugin
51
+     *
52
+     * @throws PluginException
53
+     */
54
+    public function __construct($path) {
55
+        if (!$path) {
56
+            throw new \PluginException("ElggPlugin cannot be null instantiated. You must pass a full path.");
57
+        }
58
+
59
+        if (is_object($path)) {
60
+            // database object
61
+            parent::__construct($path);
62
+            $this->path = _elgg_config()->plugins_path . $this->getID();
63
+            _elgg_cache_plugin_by_id($this);
64
+            return;
65
+        }
66
+
67
+        if (is_numeric($path)) {
68
+            // guid
69
+            // @todo plugins with directory names of '12345'
70
+            throw new \InvalidArgumentException('$path cannot be a GUID');
71
+        }
72
+
73
+        $this->initializeAttributes();
74
+
75
+        // path checking is done in the package
76
+        $path = sanitise_filepath($path);
77
+        $this->path = $path;
78
+        $path_parts = explode('/', rtrim($path, '/'));
79
+        $plugin_id = array_pop($path_parts);
80
+        $this->title = $plugin_id;
81
+
82
+        // check if we're loading an existing plugin
83
+        $existing_plugin = elgg_get_plugin_from_id($plugin_id);
84
+
85
+        if ($existing_plugin) {
86
+            $this->load((object) ['guid' => $existing_plugin->guid]);
87
+        }
88
+
89
+        _elgg_cache_plugin_by_id($this);
90
+    }
91
+
92
+    /**
93
+     * Save the plugin object.  Make sure required values exist.
94
+     *
95
+     * @see \ElggObject::save()
96
+     * @return bool
97
+     */
98
+    public function save() {
99
+        // own by the current site so users can be deleted without affecting plugins
100
+        $site = elgg_get_site_entity();
101
+        $this->attributes['owner_guid'] = $site->guid;
102
+        $this->attributes['container_guid'] = $site->guid;
103 103
 		
104
-		if (parent::save()) {
105
-			// make sure we have a priority
106
-			$priority = $this->getPriority();
107
-			if ($priority === false || $priority === null) {
108
-				return $this->setPriority('last');
109
-			}
110
-		} else {
111
-			return false;
112
-		}
113
-	}
114
-
115
-
116
-	// Plugin ID and path
117
-
118
-	/**
119
-	 * Returns the ID (dir name) of this plugin
120
-	 *
121
-	 * @return string
122
-	 */
123
-	public function getID() {
124
-		return $this->title;
125
-	}
126
-
127
-	/**
128
-	 * Returns the manifest's name if available, otherwise the ID.
129
-	 *
130
-	 * @return string
131
-	 * @since 3.0
132
-	 */
133
-	public function getDisplayName() {
134
-		$manifest = $this->getManifest();
135
-		if ($manifest) {
136
-			return $manifest->getName();
137
-		}
138
-
139
-		return $this->getID();
140
-	}
141
-
142
-	/**
143
-	 * Returns the manifest's name if available, otherwise the ID.
144
-	 *
145
-	 * @return string
146
-	 * @since 1.8.1
147
-	 * @deprecated 3.0
148
-	 */
149
-	public function getFriendlyName() {
150
-		elgg_deprecated_notice(__METHOD__ . ' is deprecated. Use getDisplayName().', '3.0');
104
+        if (parent::save()) {
105
+            // make sure we have a priority
106
+            $priority = $this->getPriority();
107
+            if ($priority === false || $priority === null) {
108
+                return $this->setPriority('last');
109
+            }
110
+        } else {
111
+            return false;
112
+        }
113
+    }
114
+
115
+
116
+    // Plugin ID and path
117
+
118
+    /**
119
+     * Returns the ID (dir name) of this plugin
120
+     *
121
+     * @return string
122
+     */
123
+    public function getID() {
124
+        return $this->title;
125
+    }
126
+
127
+    /**
128
+     * Returns the manifest's name if available, otherwise the ID.
129
+     *
130
+     * @return string
131
+     * @since 3.0
132
+     */
133
+    public function getDisplayName() {
134
+        $manifest = $this->getManifest();
135
+        if ($manifest) {
136
+            return $manifest->getName();
137
+        }
138
+
139
+        return $this->getID();
140
+    }
141
+
142
+    /**
143
+     * Returns the manifest's name if available, otherwise the ID.
144
+     *
145
+     * @return string
146
+     * @since 1.8.1
147
+     * @deprecated 3.0
148
+     */
149
+    public function getFriendlyName() {
150
+        elgg_deprecated_notice(__METHOD__ . ' is deprecated. Use getDisplayName().', '3.0');
151 151
 	
152
-		return $this->getDisplayName();
153
-	}
154
-
155
-	/**
156
-	 * Returns the plugin's full path with trailing slash.
157
-	 *
158
-	 * @return string
159
-	 */
160
-	public function getPath() {
161
-		return sanitise_filepath($this->path);
162
-	}
163
-
164
-	/**
165
-	 * Get a value from the plugins's static config file.
166
-	 *
167
-	 * @note If the system cache is on, Elgg APIs should not call this on every request.
168
-	 *
169
-	 * @param string $key     Config key
170
-	 * @param mixed  $default Value returned if missing
171
-	 *
172
-	 * @return mixed
173
-	 * @throws PluginException
174
-	 * @access private
175
-	 * @internal For Elgg internal use only
176
-	 */
177
-	public function getStaticConfig($key, $default = null) {
178
-		if ($this->static_config === null) {
179
-			$this->static_config = [];
180
-
181
-			if ($this->canReadFile(ElggPluginPackage::STATIC_CONFIG_FILENAME)) {
182
-				$this->static_config = $this->includeFile(ElggPluginPackage::STATIC_CONFIG_FILENAME);
183
-			}
184
-		}
185
-
186
-		if (array_key_exists($key, $this->static_config)) {
187
-			return $this->static_config[$key];
188
-		} else {
189
-			return $default;
190
-		}
191
-	}
192
-
193
-	/**
194
-	 * Sets the location of this plugin.
195
-	 *
196
-	 * @param string $id The path to the plugin's dir.
197
-	 * @return bool
198
-	 */
199
-	public function setID($id) {
200
-		return $this->attributes['title'] = $id;
201
-	}
202
-
203
-	/**
204
-	 * Returns an array of available markdown files for this plugin
205
-	 *
206
-	 * @return array
207
-	 */
208
-	public function getAvailableTextFiles() {
209
-		$filenames = $this->getPackage()->getTextFilenames();
210
-
211
-		$files = [];
212
-		foreach ($filenames as $filename) {
213
-			if ($this->canReadFile($filename)) {
214
-				$files[$filename] = "$this->path/$filename";
215
-			}
216
-		}
217
-
218
-		return $files;
219
-	}
220
-
221
-	// Load Priority
222
-
223
-	/**
224
-	 * Gets the plugin's load priority.
225
-	 *
226
-	 * @return int
227
-	 */
228
-	public function getPriority() {
229
-		$name = _elgg_namespace_plugin_private_setting('internal', 'priority');
230
-		return $this->getSetting($name);
231
-	}
232
-
233
-	/**
234
-	 * Sets the priority of the plugin
235
-	 *
236
-	 * @param mixed $priority The priority to set. One of +1, -1, first, last, or a number.
237
-	 *                        If given a number, this will displace all plugins at that number
238
-	 *                        and set their priorities +1
239
-	 * @return bool
240
-	 */
241
-	public function setPriority($priority) {
242
-		if (!$this->guid) {
243
-			return false;
244
-		}
245
-
246
-		$db = $this->getDatabase();
247
-		$name = _elgg_namespace_plugin_private_setting('internal', 'priority');
248
-		// if no priority assume a priority of 1
249
-		$old_priority = (int) $this->getPriority();
250
-		$old_priority = (!$old_priority) ? 1 : $old_priority;
251
-		$max_priority = _elgg_get_max_plugin_priority();
252
-
253
-		// can't use switch here because it's not strict and
254
-		// php evaluates +1 == 1
255
-		if ($priority === '+1') {
256
-			$priority = $old_priority + 1;
257
-		} elseif ($priority === '-1') {
258
-			$priority = $old_priority - 1;
259
-		} elseif ($priority === 'first') {
260
-			$priority = 1;
261
-		} elseif ($priority === 'last') {
262
-			$priority = $max_priority;
263
-		}
264
-
265
-		// should be a number by now
266
-		if ($priority > 0) {
267
-			if (!is_numeric($priority)) {
268
-				return false;
269
-			}
270
-
271
-			// there's nothing above the max.
272
-			if ($priority > $max_priority) {
273
-				$priority = $max_priority;
274
-			}
275
-
276
-			// there's nothing below 1.
277
-			if ($priority < 1) {
278
-				$priority = 1;
279
-			}
280
-
281
-			if ($priority > $old_priority) {
282
-				$op = '-';
283
-				$where = "CAST(value as unsigned) BETWEEN $old_priority AND $priority";
284
-			} else {
285
-				$op = '+';
286
-				$where = "CAST(value as unsigned) BETWEEN $priority AND $old_priority";
287
-			}
288
-
289
-			// displace the ones affected by this change
290
-			$q = "UPDATE {$db->prefix}private_settings
152
+        return $this->getDisplayName();
153
+    }
154
+
155
+    /**
156
+     * Returns the plugin's full path with trailing slash.
157
+     *
158
+     * @return string
159
+     */
160
+    public function getPath() {
161
+        return sanitise_filepath($this->path);
162
+    }
163
+
164
+    /**
165
+     * Get a value from the plugins's static config file.
166
+     *
167
+     * @note If the system cache is on, Elgg APIs should not call this on every request.
168
+     *
169
+     * @param string $key     Config key
170
+     * @param mixed  $default Value returned if missing
171
+     *
172
+     * @return mixed
173
+     * @throws PluginException
174
+     * @access private
175
+     * @internal For Elgg internal use only
176
+     */
177
+    public function getStaticConfig($key, $default = null) {
178
+        if ($this->static_config === null) {
179
+            $this->static_config = [];
180
+
181
+            if ($this->canReadFile(ElggPluginPackage::STATIC_CONFIG_FILENAME)) {
182
+                $this->static_config = $this->includeFile(ElggPluginPackage::STATIC_CONFIG_FILENAME);
183
+            }
184
+        }
185
+
186
+        if (array_key_exists($key, $this->static_config)) {
187
+            return $this->static_config[$key];
188
+        } else {
189
+            return $default;
190
+        }
191
+    }
192
+
193
+    /**
194
+     * Sets the location of this plugin.
195
+     *
196
+     * @param string $id The path to the plugin's dir.
197
+     * @return bool
198
+     */
199
+    public function setID($id) {
200
+        return $this->attributes['title'] = $id;
201
+    }
202
+
203
+    /**
204
+     * Returns an array of available markdown files for this plugin
205
+     *
206
+     * @return array
207
+     */
208
+    public function getAvailableTextFiles() {
209
+        $filenames = $this->getPackage()->getTextFilenames();
210
+
211
+        $files = [];
212
+        foreach ($filenames as $filename) {
213
+            if ($this->canReadFile($filename)) {
214
+                $files[$filename] = "$this->path/$filename";
215
+            }
216
+        }
217
+
218
+        return $files;
219
+    }
220
+
221
+    // Load Priority
222
+
223
+    /**
224
+     * Gets the plugin's load priority.
225
+     *
226
+     * @return int
227
+     */
228
+    public function getPriority() {
229
+        $name = _elgg_namespace_plugin_private_setting('internal', 'priority');
230
+        return $this->getSetting($name);
231
+    }
232
+
233
+    /**
234
+     * Sets the priority of the plugin
235
+     *
236
+     * @param mixed $priority The priority to set. One of +1, -1, first, last, or a number.
237
+     *                        If given a number, this will displace all plugins at that number
238
+     *                        and set their priorities +1
239
+     * @return bool
240
+     */
241
+    public function setPriority($priority) {
242
+        if (!$this->guid) {
243
+            return false;
244
+        }
245
+
246
+        $db = $this->getDatabase();
247
+        $name = _elgg_namespace_plugin_private_setting('internal', 'priority');
248
+        // if no priority assume a priority of 1
249
+        $old_priority = (int) $this->getPriority();
250
+        $old_priority = (!$old_priority) ? 1 : $old_priority;
251
+        $max_priority = _elgg_get_max_plugin_priority();
252
+
253
+        // can't use switch here because it's not strict and
254
+        // php evaluates +1 == 1
255
+        if ($priority === '+1') {
256
+            $priority = $old_priority + 1;
257
+        } elseif ($priority === '-1') {
258
+            $priority = $old_priority - 1;
259
+        } elseif ($priority === 'first') {
260
+            $priority = 1;
261
+        } elseif ($priority === 'last') {
262
+            $priority = $max_priority;
263
+        }
264
+
265
+        // should be a number by now
266
+        if ($priority > 0) {
267
+            if (!is_numeric($priority)) {
268
+                return false;
269
+            }
270
+
271
+            // there's nothing above the max.
272
+            if ($priority > $max_priority) {
273
+                $priority = $max_priority;
274
+            }
275
+
276
+            // there's nothing below 1.
277
+            if ($priority < 1) {
278
+                $priority = 1;
279
+            }
280
+
281
+            if ($priority > $old_priority) {
282
+                $op = '-';
283
+                $where = "CAST(value as unsigned) BETWEEN $old_priority AND $priority";
284
+            } else {
285
+                $op = '+';
286
+                $where = "CAST(value as unsigned) BETWEEN $priority AND $old_priority";
287
+            }
288
+
289
+            // displace the ones affected by this change
290
+            $q = "UPDATE {$db->prefix}private_settings
291 291
 				SET value = CAST(value as unsigned) $op 1
292 292
 				WHERE entity_guid != $this->guid
293 293
 				AND name = '$name'
294 294
 				AND $where";
295 295
 
296
-			if (!$db->updateData($q)) {
297
-				return false;
298
-			}
299
-
300
-			// set this priority
301
-			if ($this->setPrivateSetting($name, $priority)) {
302
-				return true;
303
-			} else {
304
-				return false;
305
-			}
306
-		}
307
-
308
-		return false;
309
-	}
310
-
311
-
312
-	// Plugin settings
313
-
314
-	/**
315
-	 * Returns a plugin setting
316
-	 *
317
-	 * @param string $name    The setting name
318
-	 * @param mixed  $default The default value to return if none is set
319
-	 * @return mixed
320
-	 */
321
-	public function getSetting($name, $default = null) {
322
-		$values = $this->getAllSettings();
323
-
324
-		return elgg_extract($name, $values, $default);
325
-	}
326
-
327
-	/**
328
-	 * Returns an array of all settings saved for this plugin.
329
-	 *
330
-	 * @note Unlike user settings, plugin settings are not namespaced.
331
-	 *
332
-	 * @return array An array of key/value pairs.
333
-	 */
334
-	public function getAllSettings() {
296
+            if (!$db->updateData($q)) {
297
+                return false;
298
+            }
299
+
300
+            // set this priority
301
+            if ($this->setPrivateSetting($name, $priority)) {
302
+                return true;
303
+            } else {
304
+                return false;
305
+            }
306
+        }
307
+
308
+        return false;
309
+    }
310
+
311
+
312
+    // Plugin settings
313
+
314
+    /**
315
+     * Returns a plugin setting
316
+     *
317
+     * @param string $name    The setting name
318
+     * @param mixed  $default The default value to return if none is set
319
+     * @return mixed
320
+     */
321
+    public function getSetting($name, $default = null) {
322
+        $values = $this->getAllSettings();
323
+
324
+        return elgg_extract($name, $values, $default);
325
+    }
326
+
327
+    /**
328
+     * Returns an array of all settings saved for this plugin.
329
+     *
330
+     * @note Unlike user settings, plugin settings are not namespaced.
331
+     *
332
+     * @return array An array of key/value pairs.
333
+     */
334
+    public function getAllSettings() {
335 335
 		
336
-		$defaults = $this->getStaticConfig('settings', []);
337
-		$values = _elgg_services()->pluginSettingsCache->getAll($this->guid);
336
+        $defaults = $this->getStaticConfig('settings', []);
337
+        $values = _elgg_services()->pluginSettingsCache->getAll($this->guid);
338 338
 		
339
-		if ($values !== null) {
340
-			return array_merge($defaults, $values);
341
-		}
339
+        if ($values !== null) {
340
+            return array_merge($defaults, $values);
341
+        }
342 342
 
343
-		if (!$this->guid) {
344
-			return false;
345
-		}
343
+        if (!$this->guid) {
344
+            return false;
345
+        }
346 346
 
347
-		$db_prefix = _elgg_config()->dbprefix;
348
-		// need to remove all namespaced private settings.
349
-		$us_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
347
+        $db_prefix = _elgg_config()->dbprefix;
348
+        // need to remove all namespaced private settings.
349
+        $us_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
350 350
 
351
-		// Get private settings for user
352
-		$q = "SELECT * FROM {$db_prefix}private_settings
351
+        // Get private settings for user
352
+        $q = "SELECT * FROM {$db_prefix}private_settings
353 353
 			WHERE entity_guid = $this->guid
354 354
 			AND name NOT LIKE '$us_prefix%'";
355 355
 
356
-		$private_settings = $this->getDatabase()->getData($q);
357
-
358
-		$return = [];
359
-
360
-		if ($private_settings) {
361
-			foreach ($private_settings as $setting) {
362
-				$return[$setting->name] = $setting->value;
363
-			}
364
-		}
365
-
366
-		return array_merge($defaults, $return);
367
-	}
368
-
369
-	/**
370
-	 * Set a plugin setting for the plugin
371
-	 *
372
-	 * @todo This will only work once the plugin has a GUID.
373
-	 *
374
-	 * @param string $name  The name to set
375
-	 * @param string $value The value to set
376
-	 *
377
-	 * @return bool
378
-	 */
379
-	public function setSetting($name, $value) {
380
-		if (!$this->guid) {
381
-			return false;
382
-		}
356
+        $private_settings = $this->getDatabase()->getData($q);
357
+
358
+        $return = [];
359
+
360
+        if ($private_settings) {
361
+            foreach ($private_settings as $setting) {
362
+                $return[$setting->name] = $setting->value;
363
+            }
364
+        }
365
+
366
+        return array_merge($defaults, $return);
367
+    }
368
+
369
+    /**
370
+     * Set a plugin setting for the plugin
371
+     *
372
+     * @todo This will only work once the plugin has a GUID.
373
+     *
374
+     * @param string $name  The name to set
375
+     * @param string $value The value to set
376
+     *
377
+     * @return bool
378
+     */
379
+    public function setSetting($name, $value) {
380
+        if (!$this->guid) {
381
+            return false;
382
+        }
383 383
 		
384
-		// Hook to validate setting
385
-		$value = elgg_trigger_plugin_hook('setting', 'plugin', [
386
-			'plugin_id' => $this->getID(),
387
-			'plugin' => $this,
388
-			'name' => $name,
389
-			'value' => $value,
390
-		], $value);
384
+        // Hook to validate setting
385
+        $value = elgg_trigger_plugin_hook('setting', 'plugin', [
386
+            'plugin_id' => $this->getID(),
387
+            'plugin' => $this,
388
+            'name' => $name,
389
+            'value' => $value,
390
+        ], $value);
391 391
 		
392
-		if (is_array($value)) {
393
-			elgg_log('Plugin settings cannot store arrays.', 'ERROR');
394
-			return false;
395
-		}
392
+        if (is_array($value)) {
393
+            elgg_log('Plugin settings cannot store arrays.', 'ERROR');
394
+            return false;
395
+        }
396 396
 		
397
-		return $this->setPrivateSetting($name, $value);
398
-	}
399
-
400
-	/**
401
-	 * Removes a plugin setting name and value.
402
-	 *
403
-	 * @param string $name The setting name to remove
404
-	 *
405
-	 * @return bool
406
-	 */
407
-	public function unsetSetting($name) {
408
-		return remove_private_setting($this->guid, $name);
409
-	}
410
-
411
-	/**
412
-	 * Removes all settings for this plugin.
413
-	 *
414
-	 * @todo Should be a better way to do this without dropping to raw SQL.
415
-	 * @todo If we could namespace the plugin settings this would be cleaner.
416
-	 * @todo this shouldn't work because ps_prefix will be empty string
417
-	 * @return bool
418
-	 */
419
-	public function unsetAllSettings() {
420
-		_elgg_services()->pluginSettingsCache->clear($this->guid);
421
-		_elgg_services()->boot->invalidateCache();
422
-
423
-		$db = $this->getDatabase();
424
-		$us_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
425
-		$is_prefix = _elgg_namespace_plugin_private_setting('internal', '', $this->getID());
426
-
427
-		$q = "DELETE FROM {$db->prefix}private_settings
397
+        return $this->setPrivateSetting($name, $value);
398
+    }
399
+
400
+    /**
401
+     * Removes a plugin setting name and value.
402
+     *
403
+     * @param string $name The setting name to remove
404
+     *
405
+     * @return bool
406
+     */
407
+    public function unsetSetting($name) {
408
+        return remove_private_setting($this->guid, $name);
409
+    }
410
+
411
+    /**
412
+     * Removes all settings for this plugin.
413
+     *
414
+     * @todo Should be a better way to do this without dropping to raw SQL.
415
+     * @todo If we could namespace the plugin settings this would be cleaner.
416
+     * @todo this shouldn't work because ps_prefix will be empty string
417
+     * @return bool
418
+     */
419
+    public function unsetAllSettings() {
420
+        _elgg_services()->pluginSettingsCache->clear($this->guid);
421
+        _elgg_services()->boot->invalidateCache();
422
+
423
+        $db = $this->getDatabase();
424
+        $us_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
425
+        $is_prefix = _elgg_namespace_plugin_private_setting('internal', '', $this->getID());
426
+
427
+        $q = "DELETE FROM {$db->prefix}private_settings
428 428
 			WHERE entity_guid = $this->guid
429 429
 			AND name NOT LIKE '$us_prefix%'
430 430
 			AND name NOT LIKE '$is_prefix%'";
431 431
 
432
-		return $db->deleteData($q);
433
-	}
434
-
435
-
436
-	// User settings
437
-
438
-	/**
439
-	 * Returns a user's setting for this plugin
440
-	 *
441
-	 * @param string $name      The setting name
442
-	 * @param int    $user_guid The user GUID
443
-	 * @param mixed  $default   The default value to return if none is set
444
-	 *
445
-	 * @return mixed The setting string value, the default value or false if there is no user
446
-	 */
447
-	public function getUserSetting($name, $user_guid = 0, $default = null) {
448
-		$values = $this->getAllUserSettings($user_guid);
449
-		if ($values === false) {
450
-			return false;
451
-		}
432
+        return $db->deleteData($q);
433
+    }
434
+
435
+
436
+    // User settings
437
+
438
+    /**
439
+     * Returns a user's setting for this plugin
440
+     *
441
+     * @param string $name      The setting name
442
+     * @param int    $user_guid The user GUID
443
+     * @param mixed  $default   The default value to return if none is set
444
+     *
445
+     * @return mixed The setting string value, the default value or false if there is no user
446
+     */
447
+    public function getUserSetting($name, $user_guid = 0, $default = null) {
448
+        $values = $this->getAllUserSettings($user_guid);
449
+        if ($values === false) {
450
+            return false;
451
+        }
452 452
 		
453
-		return elgg_extract($name, $values, $default);
454
-	}
455
-
456
-	/**
457
-	 * Returns an array of all user settings saved for this plugin for the user.
458
-	 *
459
-	 * @note Plugin settings are saved with a prefix. This removes that prefix.
460
-	 *
461
-	 * @param int $user_guid The user GUID. Defaults to logged in.
462
-	 * @return array An array of key/value pairs.
463
-	 */
464
-	public function getAllUserSettings($user_guid = 0) {
465
-		$user_guid = (int) $user_guid;
466
-
467
-		if ($user_guid) {
468
-			$user = get_entity($user_guid);
469
-		} else {
470
-			$user = _elgg_services()->session->getLoggedInUser();
471
-		}
472
-
473
-		if (!($user instanceof \ElggUser)) {
474
-			return false;
475
-		}
476
-
477
-		$defaults = $this->getStaticConfig('user_settings', []);
453
+        return elgg_extract($name, $values, $default);
454
+    }
455
+
456
+    /**
457
+     * Returns an array of all user settings saved for this plugin for the user.
458
+     *
459
+     * @note Plugin settings are saved with a prefix. This removes that prefix.
460
+     *
461
+     * @param int $user_guid The user GUID. Defaults to logged in.
462
+     * @return array An array of key/value pairs.
463
+     */
464
+    public function getAllUserSettings($user_guid = 0) {
465
+        $user_guid = (int) $user_guid;
466
+
467
+        if ($user_guid) {
468
+            $user = get_entity($user_guid);
469
+        } else {
470
+            $user = _elgg_services()->session->getLoggedInUser();
471
+        }
472
+
473
+        if (!($user instanceof \ElggUser)) {
474
+            return false;
475
+        }
476
+
477
+        $defaults = $this->getStaticConfig('user_settings', []);
478 478
 		
479
-		$db_prefix = _elgg_config()->dbprefix;
480
-		// send an empty name so we just get the first part of the namespace
481
-		$ps_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
482
-		$ps_prefix_len = strlen($ps_prefix);
479
+        $db_prefix = _elgg_config()->dbprefix;
480
+        // send an empty name so we just get the first part of the namespace
481
+        $ps_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
482
+        $ps_prefix_len = strlen($ps_prefix);
483 483
 
484
-		// Get private settings for user
485
-		$q = "SELECT * FROM {$db_prefix}private_settings
484
+        // Get private settings for user
485
+        $q = "SELECT * FROM {$db_prefix}private_settings
486 486
 			WHERE entity_guid = {$user->guid}
487 487
 			AND name LIKE '$ps_prefix%'";
488 488
 
489
-		$private_settings = $this->getDatabase()->getData($q);
490
-
491
-		$return = [];
492
-
493
-		if ($private_settings) {
494
-			foreach ($private_settings as $setting) {
495
-				$name = substr($setting->name, $ps_prefix_len);
496
-				$value = $setting->value;
497
-
498
-				$return[$name] = $value;
499
-			}
500
-		}
501
-
502
-		return array_merge($defaults, $return);
503
-	}
504
-
505
-	/**
506
-	 * Sets a user setting for a plugin
507
-	 *
508
-	 * @param string $name      The setting name
509
-	 * @param string $value     The setting value
510
-	 * @param int    $user_guid The user GUID
511
-	 *
512
-	 * @return mixed The new setting ID or false
513
-	 */
514
-	public function setUserSetting($name, $value, $user_guid = 0) {
515
-		$user_guid = (int) $user_guid;
516
-
517
-		if ($user_guid) {
518
-			$user = get_entity($user_guid);
519
-		} else {
520
-			$user = _elgg_services()->session->getLoggedInUser();
521
-		}
522
-
523
-		if (!($user instanceof \ElggUser)) {
524
-			return false;
525
-		}
526
-
527
-		// Hook to validate setting
528
-		// note: this doesn't pass the namespaced name
529
-		$value = _elgg_services()->hooks->trigger('usersetting', 'plugin', [
530
-			'user' => $user,
531
-			'plugin' => $this,
532
-			'plugin_id' => $this->getID(),
533
-			'name' => $name,
534
-			'value' => $value
535
-		], $value);
489
+        $private_settings = $this->getDatabase()->getData($q);
490
+
491
+        $return = [];
492
+
493
+        if ($private_settings) {
494
+            foreach ($private_settings as $setting) {
495
+                $name = substr($setting->name, $ps_prefix_len);
496
+                $value = $setting->value;
497
+
498
+                $return[$name] = $value;
499
+            }
500
+        }
501
+
502
+        return array_merge($defaults, $return);
503
+    }
504
+
505
+    /**
506
+     * Sets a user setting for a plugin
507
+     *
508
+     * @param string $name      The setting name
509
+     * @param string $value     The setting value
510
+     * @param int    $user_guid The user GUID
511
+     *
512
+     * @return mixed The new setting ID or false
513
+     */
514
+    public function setUserSetting($name, $value, $user_guid = 0) {
515
+        $user_guid = (int) $user_guid;
516
+
517
+        if ($user_guid) {
518
+            $user = get_entity($user_guid);
519
+        } else {
520
+            $user = _elgg_services()->session->getLoggedInUser();
521
+        }
522
+
523
+        if (!($user instanceof \ElggUser)) {
524
+            return false;
525
+        }
526
+
527
+        // Hook to validate setting
528
+        // note: this doesn't pass the namespaced name
529
+        $value = _elgg_services()->hooks->trigger('usersetting', 'plugin', [
530
+            'user' => $user,
531
+            'plugin' => $this,
532
+            'plugin_id' => $this->getID(),
533
+            'name' => $name,
534
+            'value' => $value
535
+        ], $value);
536 536
 		
537
-		if (is_array($value)) {
538
-			elgg_log('Plugin user settings cannot store arrays.', 'ERROR');
539
-			return false;
540
-		}
537
+        if (is_array($value)) {
538
+            elgg_log('Plugin user settings cannot store arrays.', 'ERROR');
539
+            return false;
540
+        }
541 541
 		
542
-		// set the namespaced name.
543
-		$name = _elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
544
-
545
-		return set_private_setting($user->guid, $name, $value);
546
-	}
547
-
548
-	/**
549
-	 * Removes a user setting name and value.
550
-	 *
551
-	 * @param string $name      The user setting name
552
-	 * @param int    $user_guid The user GUID
553
-	 * @return bool
554
-	 */
555
-	public function unsetUserSetting($name, $user_guid = 0) {
556
-		$user_guid = (int) $user_guid;
557
-
558
-		if ($user_guid) {
559
-			$user = get_entity($user_guid);
560
-		} else {
561
-			$user = _elgg_services()->session->getLoggedInUser();
562
-		}
563
-
564
-		if (!($user instanceof \ElggUser)) {
565
-			return false;
566
-		}
567
-
568
-		// set the namespaced name.
569
-		$name = _elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
570
-
571
-		return remove_private_setting($user->guid, $name);
572
-	}
573
-
574
-	/**
575
-	 * Removes all User Settings for this plugin for a particular user
576
-	 *
577
-	 * Use {@link removeAllUsersSettings()} to remove all user
578
-	 * settings for all users.  (Note the plural 'Users'.)
579
-	 *
580
-	 * @warning 0 does not equal logged in user for this method!
581
-	 * @todo fix that
582
-	 *
583
-	 * @param int $user_guid The user GUID to remove user settings.
584
-	 * @return bool
585
-	 */
586
-	public function unsetAllUserSettings($user_guid) {
587
-		$db = $this->getDatabase();
588
-		$ps_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
589
-
590
-		$q = "DELETE FROM {$db->prefix}private_settings
542
+        // set the namespaced name.
543
+        $name = _elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
544
+
545
+        return set_private_setting($user->guid, $name, $value);
546
+    }
547
+
548
+    /**
549
+     * Removes a user setting name and value.
550
+     *
551
+     * @param string $name      The user setting name
552
+     * @param int    $user_guid The user GUID
553
+     * @return bool
554
+     */
555
+    public function unsetUserSetting($name, $user_guid = 0) {
556
+        $user_guid = (int) $user_guid;
557
+
558
+        if ($user_guid) {
559
+            $user = get_entity($user_guid);
560
+        } else {
561
+            $user = _elgg_services()->session->getLoggedInUser();
562
+        }
563
+
564
+        if (!($user instanceof \ElggUser)) {
565
+            return false;
566
+        }
567
+
568
+        // set the namespaced name.
569
+        $name = _elgg_namespace_plugin_private_setting('user_setting', $name, $this->getID());
570
+
571
+        return remove_private_setting($user->guid, $name);
572
+    }
573
+
574
+    /**
575
+     * Removes all User Settings for this plugin for a particular user
576
+     *
577
+     * Use {@link removeAllUsersSettings()} to remove all user
578
+     * settings for all users.  (Note the plural 'Users'.)
579
+     *
580
+     * @warning 0 does not equal logged in user for this method!
581
+     * @todo fix that
582
+     *
583
+     * @param int $user_guid The user GUID to remove user settings.
584
+     * @return bool
585
+     */
586
+    public function unsetAllUserSettings($user_guid) {
587
+        $db = $this->getDatabase();
588
+        $ps_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
589
+
590
+        $q = "DELETE FROM {$db->prefix}private_settings
591 591
 			WHERE entity_guid = $user_guid
592 592
 			AND name LIKE '$ps_prefix%'";
593 593
 
594
-		return $db->deleteData($q);
595
-	}
596
-
597
-	/**
598
-	 * Removes this plugin's user settings for all users.
599
-	 *
600
-	 * Use {@link removeAllUserSettings()} if you just want to remove
601
-	 * settings for a single user.
602
-	 *
603
-	 * @return bool
604
-	 */
605
-	public function unsetAllUsersSettings() {
606
-		$db = $this->getDatabase();
607
-		$ps_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
608
-
609
-		$q = "DELETE FROM {$db->prefix}private_settings
594
+        return $db->deleteData($q);
595
+    }
596
+
597
+    /**
598
+     * Removes this plugin's user settings for all users.
599
+     *
600
+     * Use {@link removeAllUserSettings()} if you just want to remove
601
+     * settings for a single user.
602
+     *
603
+     * @return bool
604
+     */
605
+    public function unsetAllUsersSettings() {
606
+        $db = $this->getDatabase();
607
+        $ps_prefix = _elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
608
+
609
+        $q = "DELETE FROM {$db->prefix}private_settings
610 610
 			WHERE name LIKE '$ps_prefix%'";
611 611
 
612
-		return $db->deleteData($q);
613
-	}
614
-
615
-
616
-	// validation
617
-
618
-	/**
619
-	 * Returns if the plugin is complete, meaning has all required files
620
-	 * and Elgg can read them and they make sense.
621
-	 *
622
-	 * @todo bad name? This could be confused with isValid() from \ElggPluginPackage.
623
-	 *
624
-	 * @return bool
625
-	 */
626
-	public function isValid() {
627
-		if (!$this->getID()) {
628
-			$this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:MissingID', [$this->guid]);
629
-			return false;
630
-		}
631
-
632
-		if (!$this->getPackage() instanceof \ElggPluginPackage) {
633
-			$this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:NoPluginPackagePackage', [$this->getID(), $this->guid]);
634
-			return false;
635
-		}
636
-
637
-		if (!$this->getPackage()->isValid()) {
638
-			$this->errorMsg = $this->getPackage()->getError();
639
-			return false;
640
-		}
641
-
642
-		return true;
643
-	}
644
-
645
-	/**
646
-	 * Is this plugin active?
647
-	 *
648
-	 * @return bool
649
-	 */
650
-	public function isActive() {
651
-		if (!$this->guid) {
652
-			return false;
653
-		}
654
-
655
-		$site = elgg_get_site_entity();
656
-
657
-		if (!($site instanceof \ElggSite)) {
658
-			return false;
659
-		}
660
-
661
-		return check_entity_relationship($this->guid, 'active_plugin', $site->guid);
662
-	}
663
-
664
-	/**
665
-	 * Checks if this plugin can be activated on the current
666
-	 * Elgg installation.
667
-	 *
668
-	 * @return bool
669
-	 */
670
-	public function canActivate() {
671
-		if ($this->isActive()) {
672
-			return false;
673
-		}
674
-
675
-		if ($this->getPackage()) {
676
-			$result = $this->getPackage()->isValid() && $this->getPackage()->checkDependencies();
677
-			if (!$result) {
678
-				$this->errorMsg = $this->getPackage()->getError();
679
-			}
680
-
681
-			return $result;
682
-		}
683
-
684
-		return false;
685
-	}
686
-
687
-
688
-	// activating and deactivating
689
-
690
-	/**
691
-	 * Actives the plugin for the current site.
692
-	 *
693
-	 * @return bool
694
-	 */
695
-	public function activate() {
696
-		if ($this->isActive()) {
697
-			return false;
698
-		}
699
-
700
-		if (!$this->canActivate()) {
701
-			return false;
702
-		}
703
-
704
-		// Check this before setting status because the file could potentially throw
705
-		if (!$this->isStaticConfigValid()) {
706
-			return false;
707
-		}
708
-
709
-		if (!$this->setStatus(true)) {
710
-			return false;
711
-		}
712
-
713
-		// perform tasks and emit events
714
-		// emit an event. returning false will make this not be activated.
715
-		// we need to do this after it's been fully activated
716
-		// or the deactivate will be confused.
717
-		$params = [
718
-			'plugin_id' => $this->getID(),
719
-			'plugin_entity' => $this,
720
-		];
721
-
722
-		$return = _elgg_services()->hooks->getEvents()->trigger('activate', 'plugin', $params);
723
-
724
-		// if there are any on_enable functions, start the plugin now and run them
725
-		// Note: this will not run re-run the init hooks!
726
-		if ($return) {
727
-			$this->activateEntities();
612
+        return $db->deleteData($q);
613
+    }
614
+
615
+
616
+    // validation
617
+
618
+    /**
619
+     * Returns if the plugin is complete, meaning has all required files
620
+     * and Elgg can read them and they make sense.
621
+     *
622
+     * @todo bad name? This could be confused with isValid() from \ElggPluginPackage.
623
+     *
624
+     * @return bool
625
+     */
626
+    public function isValid() {
627
+        if (!$this->getID()) {
628
+            $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:MissingID', [$this->guid]);
629
+            return false;
630
+        }
631
+
632
+        if (!$this->getPackage() instanceof \ElggPluginPackage) {
633
+            $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:NoPluginPackagePackage', [$this->getID(), $this->guid]);
634
+            return false;
635
+        }
636
+
637
+        if (!$this->getPackage()->isValid()) {
638
+            $this->errorMsg = $this->getPackage()->getError();
639
+            return false;
640
+        }
641
+
642
+        return true;
643
+    }
644
+
645
+    /**
646
+     * Is this plugin active?
647
+     *
648
+     * @return bool
649
+     */
650
+    public function isActive() {
651
+        if (!$this->guid) {
652
+            return false;
653
+        }
654
+
655
+        $site = elgg_get_site_entity();
656
+
657
+        if (!($site instanceof \ElggSite)) {
658
+            return false;
659
+        }
660
+
661
+        return check_entity_relationship($this->guid, 'active_plugin', $site->guid);
662
+    }
663
+
664
+    /**
665
+     * Checks if this plugin can be activated on the current
666
+     * Elgg installation.
667
+     *
668
+     * @return bool
669
+     */
670
+    public function canActivate() {
671
+        if ($this->isActive()) {
672
+            return false;
673
+        }
674
+
675
+        if ($this->getPackage()) {
676
+            $result = $this->getPackage()->isValid() && $this->getPackage()->checkDependencies();
677
+            if (!$result) {
678
+                $this->errorMsg = $this->getPackage()->getError();
679
+            }
680
+
681
+            return $result;
682
+        }
683
+
684
+        return false;
685
+    }
686
+
687
+
688
+    // activating and deactivating
689
+
690
+    /**
691
+     * Actives the plugin for the current site.
692
+     *
693
+     * @return bool
694
+     */
695
+    public function activate() {
696
+        if ($this->isActive()) {
697
+            return false;
698
+        }
699
+
700
+        if (!$this->canActivate()) {
701
+            return false;
702
+        }
703
+
704
+        // Check this before setting status because the file could potentially throw
705
+        if (!$this->isStaticConfigValid()) {
706
+            return false;
707
+        }
708
+
709
+        if (!$this->setStatus(true)) {
710
+            return false;
711
+        }
712
+
713
+        // perform tasks and emit events
714
+        // emit an event. returning false will make this not be activated.
715
+        // we need to do this after it's been fully activated
716
+        // or the deactivate will be confused.
717
+        $params = [
718
+            'plugin_id' => $this->getID(),
719
+            'plugin_entity' => $this,
720
+        ];
721
+
722
+        $return = _elgg_services()->hooks->getEvents()->trigger('activate', 'plugin', $params);
723
+
724
+        // if there are any on_enable functions, start the plugin now and run them
725
+        // Note: this will not run re-run the init hooks!
726
+        if ($return) {
727
+            $this->activateEntities();
728 728
 			
729
-			if ($this->canReadFile('activate.php')) {
730
-				$flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES |
731
-						ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS | ELGG_PLUGIN_REGISTER_WIDGETS | ELGG_PLUGIN_REGISTER_ACTIONS;
729
+            if ($this->canReadFile('activate.php')) {
730
+                $flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES |
731
+                        ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS | ELGG_PLUGIN_REGISTER_WIDGETS | ELGG_PLUGIN_REGISTER_ACTIONS;
732 732
 
733
-				$this->start($flags);
733
+                $this->start($flags);
734 734
 
735
-				$return = $this->includeFile('activate.php');
736
-			}
737
-		}
735
+                $return = $this->includeFile('activate.php');
736
+            }
737
+        }
738 738
 
739
-		if ($return === false) {
740
-			$this->deactivate();
741
-		}
739
+        if ($return === false) {
740
+            $this->deactivate();
741
+        }
742 742
 
743
-		_elgg_services()->hooks->getEvents()->trigger('cache:flush', 'system');
743
+        _elgg_services()->hooks->getEvents()->trigger('cache:flush', 'system');
744 744
 		
745
-		return $return;
746
-	}
747
-
748
-	/**
749
-	 * Checks if this plugin can be deactivated on the current
750
-	 * Elgg installation. Validates that this plugin has no
751
-	 * active dependants.
752
-	 *
753
-	 * @return bool
754
-	 */
755
-	public function canDeactivate() {
756
-		if (!$this->isActive()) {
757
-			return false;
758
-		}
759
-
760
-		$dependents = [];
761
-
762
-		$active_plugins = elgg_get_plugins();
763
-
764
-		foreach ($active_plugins as $plugin) {
765
-			$manifest = $plugin->getManifest();
766
-			if (!$manifest) {
767
-				return true;
768
-			}
769
-			$requires = $manifest->getRequires();
770
-
771
-			foreach ($requires as $required) {
772
-				if ($required['type'] == 'plugin' && $required['name'] == $this->getID()) {
773
-					// there are active dependents
774
-					$dependents[$manifest->getPluginID()] = $plugin;
775
-				}
776
-			}
777
-		}
778
-
779
-		if (!empty($dependents)) {
780
-			$list = array_map(function(\ElggPlugin $plugin) {
781
-				$css_id = preg_replace('/[^a-z0-9-]/i', '-', $plugin->getManifest()->getID());
782
-				return elgg_view('output/url', [
783
-					'text' => $plugin->getDisplayName(),
784
-					'href' => "#$css_id",
785
-				]);
786
-			}, $dependents);
787
-			$name = $this->getDisplayName();
788
-			$list = implode(', ', $list);
789
-			$this->errorMsg = elgg_echo('ElggPlugin:Dependencies:ActiveDependent', [$name, $list]);
790
-			return false;
791
-		}
792
-
793
-		return true;
794
-	}
795
-
796
-	/**
797
-	 * Deactivates the plugin.
798
-	 *
799
-	 * @return bool
800
-	 */
801
-	public function deactivate() {
802
-		if (!$this->isActive()) {
803
-			return false;
804
-		}
805
-
806
-		if (!$this->canDeactivate()) {
807
-			return false;
808
-		}
745
+        return $return;
746
+    }
747
+
748
+    /**
749
+     * Checks if this plugin can be deactivated on the current
750
+     * Elgg installation. Validates that this plugin has no
751
+     * active dependants.
752
+     *
753
+     * @return bool
754
+     */
755
+    public function canDeactivate() {
756
+        if (!$this->isActive()) {
757
+            return false;
758
+        }
759
+
760
+        $dependents = [];
761
+
762
+        $active_plugins = elgg_get_plugins();
763
+
764
+        foreach ($active_plugins as $plugin) {
765
+            $manifest = $plugin->getManifest();
766
+            if (!$manifest) {
767
+                return true;
768
+            }
769
+            $requires = $manifest->getRequires();
770
+
771
+            foreach ($requires as $required) {
772
+                if ($required['type'] == 'plugin' && $required['name'] == $this->getID()) {
773
+                    // there are active dependents
774
+                    $dependents[$manifest->getPluginID()] = $plugin;
775
+                }
776
+            }
777
+        }
778
+
779
+        if (!empty($dependents)) {
780
+            $list = array_map(function(\ElggPlugin $plugin) {
781
+                $css_id = preg_replace('/[^a-z0-9-]/i', '-', $plugin->getManifest()->getID());
782
+                return elgg_view('output/url', [
783
+                    'text' => $plugin->getDisplayName(),
784
+                    'href' => "#$css_id",
785
+                ]);
786
+            }, $dependents);
787
+            $name = $this->getDisplayName();
788
+            $list = implode(', ', $list);
789
+            $this->errorMsg = elgg_echo('ElggPlugin:Dependencies:ActiveDependent', [$name, $list]);
790
+            return false;
791
+        }
792
+
793
+        return true;
794
+    }
795
+
796
+    /**
797
+     * Deactivates the plugin.
798
+     *
799
+     * @return bool
800
+     */
801
+    public function deactivate() {
802
+        if (!$this->isActive()) {
803
+            return false;
804
+        }
805
+
806
+        if (!$this->canDeactivate()) {
807
+            return false;
808
+        }
809 809
 		
810
-		// emit an event. returning false will cause this to not be deactivated.
811
-		$params = [
812
-			'plugin_id' => $this->getID(),
813
-			'plugin_entity' => $this,
814
-		];
815
-
816
-		$return = _elgg_services()->hooks->getEvents()->trigger('deactivate', 'plugin', $params);
817
-
818
-		// run any deactivate code
819
-		if ($return) {
820
-			if ($this->canReadFile('deactivate.php')) {
821
-				$return = $this->includeFile('deactivate.php');
822
-			}
810
+        // emit an event. returning false will cause this to not be deactivated.
811
+        $params = [
812
+            'plugin_id' => $this->getID(),
813
+            'plugin_entity' => $this,
814
+        ];
815
+
816
+        $return = _elgg_services()->hooks->getEvents()->trigger('deactivate', 'plugin', $params);
817
+
818
+        // run any deactivate code
819
+        if ($return) {
820
+            if ($this->canReadFile('deactivate.php')) {
821
+                $return = $this->includeFile('deactivate.php');
822
+            }
823 823
 			
824
-			$this->deactivateEntities();
825
-		}
826
-
827
-		if ($return === false) {
828
-			return false;
829
-		} else {
830
-			_elgg_services()->hooks->getEvents()->trigger('cache:flush', 'system');
831
-			return $this->setStatus(false);
832
-		}
833
-	}
834
-
835
-	/**
836
-	 * Start the plugin.
837
-	 *
838
-	 * @param int $flags Start flags for the plugin. See the constants in lib/plugins.php for details.
839
-	 * @return true
840
-	 * @throws PluginException
841
-	 */
842
-	public function start($flags) {
843
-
844
-		// include classes
845
-		if ($flags & ELGG_PLUGIN_REGISTER_CLASSES) {
846
-			$this->registerClasses();
824
+            $this->deactivateEntities();
825
+        }
826
+
827
+        if ($return === false) {
828
+            return false;
829
+        } else {
830
+            _elgg_services()->hooks->getEvents()->trigger('cache:flush', 'system');
831
+            return $this->setStatus(false);
832
+        }
833
+    }
834
+
835
+    /**
836
+     * Start the plugin.
837
+     *
838
+     * @param int $flags Start flags for the plugin. See the constants in lib/plugins.php for details.
839
+     * @return true
840
+     * @throws PluginException
841
+     */
842
+    public function start($flags) {
843
+
844
+        // include classes
845
+        if ($flags & ELGG_PLUGIN_REGISTER_CLASSES) {
846
+            $this->registerClasses();
847 847
 			
848
-			$autoload_file = 'vendor/autoload.php';
849
-			if ($this->canReadFile($autoload_file)) {
850
-				require_once "{$this->path}/{$autoload_file}";
851
-			}
852
-		}
853
-
854
-		// include languages
855
-		if ($flags & ELGG_PLUGIN_REGISTER_LANGUAGES) {
856
-			// should be loaded before the first function that touches the static config (elgg-plugin.php)
857
-			// so translations can be used... for example in registering widgets
858
-			$this->registerLanguages();
859
-		}
848
+            $autoload_file = 'vendor/autoload.php';
849
+            if ($this->canReadFile($autoload_file)) {
850
+                require_once "{$this->path}/{$autoload_file}";
851
+            }
852
+        }
853
+
854
+        // include languages
855
+        if ($flags & ELGG_PLUGIN_REGISTER_LANGUAGES) {
856
+            // should be loaded before the first function that touches the static config (elgg-plugin.php)
857
+            // so translations can be used... for example in registering widgets
858
+            $this->registerLanguages();
859
+        }
860 860
 		
861
-		// include start file if it exists
862
-		if ($flags & ELGG_PLUGIN_INCLUDE_START) {
863
-			if ($this->canReadFile('start.php')) {
864
-				$this->includeFile('start.php');
865
-			}
861
+        // include start file if it exists
862
+        if ($flags & ELGG_PLUGIN_INCLUDE_START) {
863
+            if ($this->canReadFile('start.php')) {
864
+                $this->includeFile('start.php');
865
+            }
866 866
 			
867
-			$this->registerEntities();
868
-		}
867
+            $this->registerEntities();
868
+        }
869 869
 		
870
-		// include views
871
-		if ($flags & ELGG_PLUGIN_REGISTER_VIEWS) {
872
-			$this->registerViews();
873
-		}
874
-
875
-		// include actions
876
-		if ($flags & ELGG_PLUGIN_REGISTER_ACTIONS) {
877
-			$this->registerActions();
878
-		}
879
-
880
-		// include widgets
881
-		if ($flags & ELGG_PLUGIN_REGISTER_WIDGETS) {
882
-			// should load after views because those are used during registration
883
-			$this->registerWidgets();
884
-		}
885
-
886
-		return true;
887
-	}
888
-
889
-	/**
890
-	 * Includes one of the plugins files
891
-	 *
892
-	 * @param string $filename The name of the file
893
-	 *
894
-	 * @throws PluginException
895
-	 * @return mixed The return value of the included file (or 1 if there is none)
896
-	 */
897
-	protected function includeFile($filename) {
898
-		$filepath = "$this->path/$filename";
899
-
900
-		if (!$this->canReadFile($filename)) {
901
-			$msg = _elgg_services()->translator->translate('ElggPlugin:Exception:CannotIncludeFile',
902
-							[$filename, $this->getID(), $this->guid, $this->path]);
903
-			throw new \PluginException($msg);
904
-		}
905
-
906
-		try {
907
-			$ret = include $filepath;
908
-		} catch (Exception $e) {
909
-			$msg = _elgg_services()->translator->translate('ElggPlugin:Exception:IncludeFileThrew',
910
-				[$filename, $this->getID(), $this->guid, $this->path]);
911
-			throw new \PluginException($msg, 0, $e);
912
-		}
913
-
914
-		return $ret;
915
-	}
916
-
917
-	/**
918
-	 * Checks whether a plugin file with the given name exists
919
-	 *
920
-	 * @param string $filename The name of the file
921
-	 * @return bool
922
-	 */
923
-	protected function canReadFile($filename) {
924
-		$path = "{$this->path}/$filename";
925
-		return is_file($path) && is_readable($path);
926
-	}
927
-
928
-	/**
929
-	 * If a static config file is present, is it a serializable array?
930
-	 *
931
-	 * @return bool
932
-	 * @throws PluginException
933
-	 */
934
-	private function isStaticConfigValid() {
935
-		if (!$this->canReadFile(ElggPluginPackage::STATIC_CONFIG_FILENAME)) {
936
-			return true;
937
-		}
938
-
939
-		ob_start();
940
-		$value = $this->includeFile(ElggPluginPackage::STATIC_CONFIG_FILENAME);
941
-		if (ob_get_clean() !== '') {
942
-			$this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:activate:ConfigSentOutput');
943
-			return false;
944
-		}
945
-
946
-		// make sure can serialize
947
-		$value = @unserialize(serialize($value));
948
-		if (!is_array($value)) {
949
-			$this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:activate:BadConfigFormat');
950
-			return false;
951
-		}
952
-
953
-		return true;
954
-	}
955
-
956
-	/**
957
-	 * Registers the plugin's views
958
-	 *
959
-	 * @throws PluginException
960
-	 * @return void
961
-	 */
962
-	protected function registerViews() {
963
-		$views = _elgg_services()->views;
964
-
965
-		// Declared views first
966
-		$file = "{$this->path}/views.php";
967
-		if (is_file($file)) {
968
-			$spec = Includer::includeFile($file);
969
-			if (is_array($spec)) {
970
-				$views->mergeViewsSpec($spec);
971
-			}
972
-		}
973
-
974
-		$spec = $this->getStaticConfig('views');
975
-		if ($spec) {
976
-			$views->mergeViewsSpec($spec);
977
-		}
978
-
979
-		// Allow /views directory files to override
980
-		if (!$views->registerPluginViews($this->path, $failed_dir)) {
981
-			$key = 'ElggPlugin:Exception:CannotRegisterViews';
982
-			$args = [$this->getID(), $this->guid, $failed_dir];
983
-			$msg = _elgg_services()->translator->translate($key, $args);
984
-			throw new \PluginException($msg);
985
-		}
986
-	}
987
-
988
-	/**
989
-	 * Registers the plugin's entities
990
-	 *
991
-	 * @return void
992
-	 */
993
-	protected function registerEntities() {
994
-
995
-		$spec = (array) $this->getStaticConfig('entities', []);
996
-		if (empty($spec)) {
997
-			return;
998
-		}
870
+        // include views
871
+        if ($flags & ELGG_PLUGIN_REGISTER_VIEWS) {
872
+            $this->registerViews();
873
+        }
874
+
875
+        // include actions
876
+        if ($flags & ELGG_PLUGIN_REGISTER_ACTIONS) {
877
+            $this->registerActions();
878
+        }
879
+
880
+        // include widgets
881
+        if ($flags & ELGG_PLUGIN_REGISTER_WIDGETS) {
882
+            // should load after views because those are used during registration
883
+            $this->registerWidgets();
884
+        }
885
+
886
+        return true;
887
+    }
888
+
889
+    /**
890
+     * Includes one of the plugins files
891
+     *
892
+     * @param string $filename The name of the file
893
+     *
894
+     * @throws PluginException
895
+     * @return mixed The return value of the included file (or 1 if there is none)
896
+     */
897
+    protected function includeFile($filename) {
898
+        $filepath = "$this->path/$filename";
899
+
900
+        if (!$this->canReadFile($filename)) {
901
+            $msg = _elgg_services()->translator->translate('ElggPlugin:Exception:CannotIncludeFile',
902
+                            [$filename, $this->getID(), $this->guid, $this->path]);
903
+            throw new \PluginException($msg);
904
+        }
905
+
906
+        try {
907
+            $ret = include $filepath;
908
+        } catch (Exception $e) {
909
+            $msg = _elgg_services()->translator->translate('ElggPlugin:Exception:IncludeFileThrew',
910
+                [$filename, $this->getID(), $this->guid, $this->path]);
911
+            throw new \PluginException($msg, 0, $e);
912
+        }
913
+
914
+        return $ret;
915
+    }
916
+
917
+    /**
918
+     * Checks whether a plugin file with the given name exists
919
+     *
920
+     * @param string $filename The name of the file
921
+     * @return bool
922
+     */
923
+    protected function canReadFile($filename) {
924
+        $path = "{$this->path}/$filename";
925
+        return is_file($path) && is_readable($path);
926
+    }
927
+
928
+    /**
929
+     * If a static config file is present, is it a serializable array?
930
+     *
931
+     * @return bool
932
+     * @throws PluginException
933
+     */
934
+    private function isStaticConfigValid() {
935
+        if (!$this->canReadFile(ElggPluginPackage::STATIC_CONFIG_FILENAME)) {
936
+            return true;
937
+        }
938
+
939
+        ob_start();
940
+        $value = $this->includeFile(ElggPluginPackage::STATIC_CONFIG_FILENAME);
941
+        if (ob_get_clean() !== '') {
942
+            $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:activate:ConfigSentOutput');
943
+            return false;
944
+        }
945
+
946
+        // make sure can serialize
947
+        $value = @unserialize(serialize($value));
948
+        if (!is_array($value)) {
949
+            $this->errorMsg = _elgg_services()->translator->translate('ElggPlugin:activate:BadConfigFormat');
950
+            return false;
951
+        }
952
+
953
+        return true;
954
+    }
955
+
956
+    /**
957
+     * Registers the plugin's views
958
+     *
959
+     * @throws PluginException
960
+     * @return void
961
+     */
962
+    protected function registerViews() {
963
+        $views = _elgg_services()->views;
964
+
965
+        // Declared views first
966
+        $file = "{$this->path}/views.php";
967
+        if (is_file($file)) {
968
+            $spec = Includer::includeFile($file);
969
+            if (is_array($spec)) {
970
+                $views->mergeViewsSpec($spec);
971
+            }
972
+        }
973
+
974
+        $spec = $this->getStaticConfig('views');
975
+        if ($spec) {
976
+            $views->mergeViewsSpec($spec);
977
+        }
978
+
979
+        // Allow /views directory files to override
980
+        if (!$views->registerPluginViews($this->path, $failed_dir)) {
981
+            $key = 'ElggPlugin:Exception:CannotRegisterViews';
982
+            $args = [$this->getID(), $this->guid, $failed_dir];
983
+            $msg = _elgg_services()->translator->translate($key, $args);
984
+            throw new \PluginException($msg);
985
+        }
986
+    }
987
+
988
+    /**
989
+     * Registers the plugin's entities
990
+     *
991
+     * @return void
992
+     */
993
+    protected function registerEntities() {
994
+
995
+        $spec = (array) $this->getStaticConfig('entities', []);
996
+        if (empty($spec)) {
997
+            return;
998
+        }
999 999
 		
1000
-		foreach ($spec as $entity) {
1001
-			if (isset($entity['type'], $entity['subtype'], $entity['searchable']) && $entity['searchable']) {
1002
-				elgg_register_entity_type($entity['type'], $entity['subtype']);
1003
-			}
1004
-		}
1005
-	}
1006
-
1007
-	/**
1008
-	 * Registers the plugin's actions provided in the plugin config file
1009
-	 *
1010
-	 * @return void
1011
-	 */
1012
-	protected function registerActions() {
1013
-		self::addActionsFromStaticConfig($this->getStaticConfig('actions', []), $this->getPath());
1014
-	}
1015
-
1016
-	/**
1017
-	 * Register a plugin's actions provided in the config file
1018
-	 *
1019
-	 * @todo move to a static config service
1020
-	 *
1021
-	 * @param array  $spec      'actions' section of static config
1022
-	 * @param string $root_path Plugin path
1023
-	 *
1024
-	 * @return void
1025
-	 * @access private
1026
-	 * @internal
1027
-	 */
1028
-	public static function addActionsFromStaticConfig(array $spec, $root_path) {
1029
-		$actions = _elgg_services()->actions;
1030
-		$root_path = rtrim($root_path, '/\\');
1031
-
1032
-		foreach ($spec as $action => $action_spec) {
1033
-			if (!is_array($action_spec)) {
1034
-				continue;
1035
-			}
1036
-
1037
-			$options = [
1038
-				'access' => 'logged_in',
1039
-				'filename' => '', // assuming core action is registered
1040
-			];
1041
-
1042
-			$options = array_merge($options, $action_spec);
1043
-
1044
-			$filename = "$root_path/actions/{$action}.php";
1045
-			if (is_file($filename)) {
1046
-				$options['filename'] = $filename;
1047
-			}
1048
-
1049
-			$actions->register($action, $options['filename'], $options['access']);
1050
-		}
1051
-	}
1052
-
1053
-	/**
1054
-	 * Registers the plugin's widgets provided in the plugin config file
1055
-	 *
1056
-	 * @throws PluginException
1057
-	 * @return void
1058
-	 */
1059
-	protected function registerWidgets() {
1060
-		$widgets = _elgg_services()->widgets;
1000
+        foreach ($spec as $entity) {
1001
+            if (isset($entity['type'], $entity['subtype'], $entity['searchable']) && $entity['searchable']) {
1002
+                elgg_register_entity_type($entity['type'], $entity['subtype']);
1003
+            }
1004
+        }
1005
+    }
1006
+
1007
+    /**
1008
+     * Registers the plugin's actions provided in the plugin config file
1009
+     *
1010
+     * @return void
1011
+     */
1012
+    protected function registerActions() {
1013
+        self::addActionsFromStaticConfig($this->getStaticConfig('actions', []), $this->getPath());
1014
+    }
1015
+
1016
+    /**
1017
+     * Register a plugin's actions provided in the config file
1018
+     *
1019
+     * @todo move to a static config service
1020
+     *
1021
+     * @param array  $spec      'actions' section of static config
1022
+     * @param string $root_path Plugin path
1023
+     *
1024
+     * @return void
1025
+     * @access private
1026
+     * @internal
1027
+     */
1028
+    public static function addActionsFromStaticConfig(array $spec, $root_path) {
1029
+        $actions = _elgg_services()->actions;
1030
+        $root_path = rtrim($root_path, '/\\');
1031
+
1032
+        foreach ($spec as $action => $action_spec) {
1033
+            if (!is_array($action_spec)) {
1034
+                continue;
1035
+            }
1036
+
1037
+            $options = [
1038
+                'access' => 'logged_in',
1039
+                'filename' => '', // assuming core action is registered
1040
+            ];
1041
+
1042
+            $options = array_merge($options, $action_spec);
1043
+
1044
+            $filename = "$root_path/actions/{$action}.php";
1045
+            if (is_file($filename)) {
1046
+                $options['filename'] = $filename;
1047
+            }
1048
+
1049
+            $actions->register($action, $options['filename'], $options['access']);
1050
+        }
1051
+    }
1052
+
1053
+    /**
1054
+     * Registers the plugin's widgets provided in the plugin config file
1055
+     *
1056
+     * @throws PluginException
1057
+     * @return void
1058
+     */
1059
+    protected function registerWidgets() {
1060
+        $widgets = _elgg_services()->widgets;
1061 1061
 		
1062
-		$spec = (array) $this->getStaticConfig('widgets', []);
1063
-		foreach ($spec as $widget_id => $widget_definition) {
1064
-			if (!is_array($widget_definition)) {
1065
-				continue;
1066
-			}
1067
-			if (!isset($widget_definition['id'])) {
1068
-				$widget_definition['id'] = $widget_id;
1069
-			}
1062
+        $spec = (array) $this->getStaticConfig('widgets', []);
1063
+        foreach ($spec as $widget_id => $widget_definition) {
1064
+            if (!is_array($widget_definition)) {
1065
+                continue;
1066
+            }
1067
+            if (!isset($widget_definition['id'])) {
1068
+                $widget_definition['id'] = $widget_id;
1069
+            }
1070 1070
 			
1071
-			$definition = \Elgg\WidgetDefinition::factory($widget_definition);
1071
+            $definition = \Elgg\WidgetDefinition::factory($widget_definition);
1072 1072
 			
1073
-			$widgets->registerType($definition);
1074
-		}
1075
-	}
1076
-
1077
-	/**
1078
-	 * Registers the plugin's languages
1079
-	 *
1080
-	 * @throws PluginException
1081
-	 * @return true
1082
-	 */
1083
-	protected function registerLanguages() {
1084
-		return _elgg_services()->translator->registerPluginTranslations($this->path);
1085
-	}
1086
-
1087
-	/**
1088
-	 * Registers the plugin's classes
1089
-	 *
1090
-	 * @throws PluginException
1091
-	 * @return true
1092
-	 */
1093
-	protected function registerClasses() {
1094
-		$classes_path = "$this->path/classes";
1095
-
1096
-		if (is_dir($classes_path)) {
1097
-			_elgg_services()->autoloadManager->addClasses($classes_path);
1098
-		}
1099
-
1100
-		return true;
1101
-	}
1102
-
1103
-	/**
1104
-	 * Activates the plugin's entities
1105
-	 *
1106
-	 * @return void
1107
-	 */
1108
-	protected function activateEntities() {
1109
-		$spec = (array) $this->getStaticConfig('entities', []);
1110
-		if (empty($spec)) {
1111
-			return;
1112
-		}
1073
+            $widgets->registerType($definition);
1074
+        }
1075
+    }
1076
+
1077
+    /**
1078
+     * Registers the plugin's languages
1079
+     *
1080
+     * @throws PluginException
1081
+     * @return true
1082
+     */
1083
+    protected function registerLanguages() {
1084
+        return _elgg_services()->translator->registerPluginTranslations($this->path);
1085
+    }
1086
+
1087
+    /**
1088
+     * Registers the plugin's classes
1089
+     *
1090
+     * @throws PluginException
1091
+     * @return true
1092
+     */
1093
+    protected function registerClasses() {
1094
+        $classes_path = "$this->path/classes";
1095
+
1096
+        if (is_dir($classes_path)) {
1097
+            _elgg_services()->autoloadManager->addClasses($classes_path);
1098
+        }
1099
+
1100
+        return true;
1101
+    }
1102
+
1103
+    /**
1104
+     * Activates the plugin's entities
1105
+     *
1106
+     * @return void
1107
+     */
1108
+    protected function activateEntities() {
1109
+        $spec = (array) $this->getStaticConfig('entities', []);
1110
+        if (empty($spec)) {
1111
+            return;
1112
+        }
1113 1113
 		
1114
-		foreach ($spec as $entity) {
1115
-			if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1116
-				if (get_subtype_id($entity['type'], $entity['subtype'])) {
1117
-					update_subtype($entity['type'], $entity['subtype'], $entity['class']);
1118
-				} else {
1119
-					add_subtype($entity['type'], $entity['subtype'], $entity['class']);
1120
-				}
1121
-			}
1122
-		}
1123
-	}
1124
-
1125
-	/**
1126
-	 * Deactivates the plugin's entities
1127
-	 *
1128
-	 * @return void
1129
-	 */
1130
-	protected function deactivateEntities() {
1131
-		$spec = (array) $this->getStaticConfig('entities', []);
1132
-		if (empty($spec)) {
1133
-			return;
1134
-		}
1114
+        foreach ($spec as $entity) {
1115
+            if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1116
+                if (get_subtype_id($entity['type'], $entity['subtype'])) {
1117
+                    update_subtype($entity['type'], $entity['subtype'], $entity['class']);
1118
+                } else {
1119
+                    add_subtype($entity['type'], $entity['subtype'], $entity['class']);
1120
+                }
1121
+            }
1122
+        }
1123
+    }
1124
+
1125
+    /**
1126
+     * Deactivates the plugin's entities
1127
+     *
1128
+     * @return void
1129
+     */
1130
+    protected function deactivateEntities() {
1131
+        $spec = (array) $this->getStaticConfig('entities', []);
1132
+        if (empty($spec)) {
1133
+            return;
1134
+        }
1135 1135
 		
1136
-		foreach ($spec as $entity) {
1137
-			if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1138
-				update_subtype($entity['type'], $entity['subtype']);
1139
-			}
1140
-		}
1141
-	}
1142
-
1143
-	/**
1144
-	 * Get an attribute or private setting value
1145
-	 *
1146
-	 * @param string $name Name of the attribute or private setting
1147
-	 * @return mixed
1148
-	 */
1149
-	public function __get($name) {
1150
-		// See if its in our base attribute
1151
-		if (array_key_exists($name, $this->attributes)) {
1152
-			return $this->attributes[$name];
1153
-		}
1154
-
1155
-		$result = $this->getPrivateSetting($name);
1156
-		if ($result !== null) {
1157
-			return $result;
1158
-		}
1159
-		$defaults = $this->getStaticConfig('settings', []);
1160
-		return elgg_extract($name, $defaults, $result);
1161
-	}
1162
-
1163
-	/**
1164
-	 * Set a value as private setting or attribute.
1165
-	 *
1166
-	 * Attributes include title and description.
1167
-	 *
1168
-	 * @param string $name  Name of the attribute or private_setting
1169
-	 * @param mixed  $value Value to be set
1170
-	 * @return void
1171
-	 */
1172
-	public function __set($name, $value) {
1173
-		if (array_key_exists($name, $this->attributes)) {
1174
-			// Check that we're not trying to change the guid!
1175
-			if ((array_key_exists('guid', $this->attributes)) && ($name == 'guid')) {
1176
-				return;
1177
-			}
1178
-
1179
-			$this->attributes[$name] = $value;
1180
-		} else {
1181
-			// to make sure we trigger the correct hooks
1182
-			$this->setSetting($name, $value);
1183
-		}
1184
-	}
1185
-
1186
-	/**
1187
-	 * Sets the plugin to active or inactive.
1188
-	 *
1189
-	 * @param bool $active Set to active or inactive
1190
-	 *
1191
-	 * @return bool
1192
-	 */
1193
-	private function setStatus($active) {
1194
-		if (!$this->guid) {
1195
-			return false;
1196
-		}
1197
-
1198
-		$site = elgg_get_site_entity();
1199
-		if ($active) {
1200
-			$result = add_entity_relationship($this->guid, 'active_plugin', $site->guid);
1201
-		} else {
1202
-			$result = remove_entity_relationship($this->guid, 'active_plugin', $site->guid);
1203
-		}
1204
-
1205
-		_elgg_invalidate_plugins_provides_cache();
1206
-		_elgg_services()->boot->invalidateCache();
1207
-
1208
-		return $result;
1209
-	}
1210
-
1211
-	/**
1212
-	 * Returns the last error message registered.
1213
-	 *
1214
-	 * @return string|null
1215
-	 */
1216
-	public function getError() {
1217
-		return $this->errorMsg;
1218
-	}
1219
-
1220
-	/**
1221
-	 * Returns this plugin's \ElggPluginManifest object
1222
-	 *
1223
-	 * @return \ElggPluginManifest|null
1224
-	 */
1225
-	public function getManifest() {
1226
-		if ($this->manifest instanceof \ElggPluginManifest) {
1227
-			return $this->manifest;
1228
-		}
1229
-
1230
-		try {
1231
-			$package = $this->getPackage();
1232
-			if (!$package) {
1233
-				throw new \Exception('Package cannot be loaded');
1234
-			}
1235
-			$this->manifest = $package->getManifest();
1236
-		} catch (Exception $e) {
1237
-			_elgg_services()->logger->warn("Failed to load manifest for plugin $this->guid. " . $e->getMessage());
1238
-			$this->errorMsg = $e->getmessage();
1239
-		}
1240
-
1241
-		return $this->manifest;
1242
-	}
1243
-
1244
-	/**
1245
-	 * Returns this plugin's \ElggPluginPackage object
1246
-	 *
1247
-	 * @return \ElggPluginPackage|null
1248
-	 */
1249
-	public function getPackage() {
1250
-		if ($this->package instanceof \ElggPluginPackage) {
1251
-			return $this->package;
1252
-		}
1253
-
1254
-		try {
1255
-			$this->package = new \ElggPluginPackage($this->path, false);
1256
-		} catch (Exception $e) {
1257
-			_elgg_services()->logger->warn("Failed to load package for $this->guid. " . $e->getMessage());
1258
-			$this->errorMsg = $e->getmessage();
1259
-		}
1260
-
1261
-		return $this->package;
1262
-	}
1136
+        foreach ($spec as $entity) {
1137
+            if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1138
+                update_subtype($entity['type'], $entity['subtype']);
1139
+            }
1140
+        }
1141
+    }
1142
+
1143
+    /**
1144
+     * Get an attribute or private setting value
1145
+     *
1146
+     * @param string $name Name of the attribute or private setting
1147
+     * @return mixed
1148
+     */
1149
+    public function __get($name) {
1150
+        // See if its in our base attribute
1151
+        if (array_key_exists($name, $this->attributes)) {
1152
+            return $this->attributes[$name];
1153
+        }
1154
+
1155
+        $result = $this->getPrivateSetting($name);
1156
+        if ($result !== null) {
1157
+            return $result;
1158
+        }
1159
+        $defaults = $this->getStaticConfig('settings', []);
1160
+        return elgg_extract($name, $defaults, $result);
1161
+    }
1162
+
1163
+    /**
1164
+     * Set a value as private setting or attribute.
1165
+     *
1166
+     * Attributes include title and description.
1167
+     *
1168
+     * @param string $name  Name of the attribute or private_setting
1169
+     * @param mixed  $value Value to be set
1170
+     * @return void
1171
+     */
1172
+    public function __set($name, $value) {
1173
+        if (array_key_exists($name, $this->attributes)) {
1174
+            // Check that we're not trying to change the guid!
1175
+            if ((array_key_exists('guid', $this->attributes)) && ($name == 'guid')) {
1176
+                return;
1177
+            }
1178
+
1179
+            $this->attributes[$name] = $value;
1180
+        } else {
1181
+            // to make sure we trigger the correct hooks
1182
+            $this->setSetting($name, $value);
1183
+        }
1184
+    }
1185
+
1186
+    /**
1187
+     * Sets the plugin to active or inactive.
1188
+     *
1189
+     * @param bool $active Set to active or inactive
1190
+     *
1191
+     * @return bool
1192
+     */
1193
+    private function setStatus($active) {
1194
+        if (!$this->guid) {
1195
+            return false;
1196
+        }
1197
+
1198
+        $site = elgg_get_site_entity();
1199
+        if ($active) {
1200
+            $result = add_entity_relationship($this->guid, 'active_plugin', $site->guid);
1201
+        } else {
1202
+            $result = remove_entity_relationship($this->guid, 'active_plugin', $site->guid);
1203
+        }
1204
+
1205
+        _elgg_invalidate_plugins_provides_cache();
1206
+        _elgg_services()->boot->invalidateCache();
1207
+
1208
+        return $result;
1209
+    }
1210
+
1211
+    /**
1212
+     * Returns the last error message registered.
1213
+     *
1214
+     * @return string|null
1215
+     */
1216
+    public function getError() {
1217
+        return $this->errorMsg;
1218
+    }
1219
+
1220
+    /**
1221
+     * Returns this plugin's \ElggPluginManifest object
1222
+     *
1223
+     * @return \ElggPluginManifest|null
1224
+     */
1225
+    public function getManifest() {
1226
+        if ($this->manifest instanceof \ElggPluginManifest) {
1227
+            return $this->manifest;
1228
+        }
1229
+
1230
+        try {
1231
+            $package = $this->getPackage();
1232
+            if (!$package) {
1233
+                throw new \Exception('Package cannot be loaded');
1234
+            }
1235
+            $this->manifest = $package->getManifest();
1236
+        } catch (Exception $e) {
1237
+            _elgg_services()->logger->warn("Failed to load manifest for plugin $this->guid. " . $e->getMessage());
1238
+            $this->errorMsg = $e->getmessage();
1239
+        }
1240
+
1241
+        return $this->manifest;
1242
+    }
1243
+
1244
+    /**
1245
+     * Returns this plugin's \ElggPluginPackage object
1246
+     *
1247
+     * @return \ElggPluginPackage|null
1248
+     */
1249
+    public function getPackage() {
1250
+        if ($this->package instanceof \ElggPluginPackage) {
1251
+            return $this->package;
1252
+        }
1253
+
1254
+        try {
1255
+            $this->package = new \ElggPluginPackage($this->path, false);
1256
+        } catch (Exception $e) {
1257
+            _elgg_services()->logger->warn("Failed to load package for $this->guid. " . $e->getMessage());
1258
+            $this->errorMsg = $e->getmessage();
1259
+        }
1260
+
1261
+        return $this->package;
1262
+    }
1263 1263
 }
Please login to merge, or discard this patch.