1: <?php
2: /**
3: * A Site entity.
4: *
5: * ElggSite represents a single site entity.
6: *
7: * An ElggSite object is an ElggEntity child class with the subtype
8: * of "site." It is created upon installation and hold all the
9: * information about a site:
10: * - name
11: * - description
12: * - url
13: *
14: * Every ElggEntity (except ElggSite) belongs to a site.
15: *
16: * @internal ElggSite represents a single row from the sites_entity
17: * table, as well as the corresponding ElggEntity row from the entities table.
18: *
19: * @warning Multiple site support isn't fully developed.
20: *
21: * @package Elgg.Core
22: * @subpackage DataMode.Site
23: * @link http://docs.elgg.org/DataModel/Sites
24: *
25: * @property string $name The name or title of the website
26: * @property string $description A motto, mission statement, or description of the website
27: * @property string $url The root web address for the site, including trailing slash
28: */
29: class ElggSite extends ElggEntity {
30:
31: /**
32: * Initialise the attributes array.
33: * This is vital to distinguish between metadata and base parameters.
34: *
35: * Place your base parameters here.
36: *
37: * @return void
38: */
39: protected function initializeAttributes() {
40: parent::initializeAttributes();
41:
42: $this->attributes['type'] = "site";
43: $this->attributes['name'] = NULL;
44: $this->attributes['description'] = NULL;
45: $this->attributes['url'] = NULL;
46: $this->attributes['tables_split'] = 2;
47: }
48:
49: /**
50: * Load or create a new ElggSite.
51: *
52: * If no arguments are passed, create a new entity.
53: *
54: * If an argument is passed attempt to load a full Site entity. Arguments
55: * can be:
56: * - The GUID of a site entity.
57: * - A URL as stored in ElggSite->url
58: * - A DB result object with a guid property
59: *
60: * @param mixed $guid If an int, load that GUID. If a db row then will
61: * load the rest of the data.
62: *
63: * @throws IOException If passed an incorrect guid
64: * @throws InvalidParameterException If passed an Elgg* Entity that isn't an ElggSite
65: */
66: function __construct($guid = null) {
67: $this->initializeAttributes();
68:
69: // compatibility for 1.7 api.
70: $this->initialise_attributes(false);
71:
72: if (!empty($guid)) {
73: // Is $guid is a DB entity table row
74: if ($guid instanceof stdClass) {
75: // Load the rest
76: if (!$this->load($guid)) {
77: $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid));
78: throw new IOException($msg);
79: }
80: } else if ($guid instanceof ElggSite) {
81: // $guid is an ElggSite so this is a copy constructor
82: elgg_deprecated_notice('This type of usage of the ElggSite constructor was deprecated. Please use the clone method.', 1.7);
83:
84: foreach ($guid->attributes as $key => $value) {
85: $this->attributes[$key] = $value;
86: }
87: } else if ($guid instanceof ElggEntity) {
88: // @todo remove and just use else clause
89: throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggSite'));
90: } else if (strpos($guid, "http") !== false) {
91: // url so retrieve by url
92: $guid = get_site_by_url($guid);
93: foreach ($guid->attributes as $key => $value) {
94: $this->attributes[$key] = $value;
95: }
96: } else if (is_numeric($guid)) {
97: // $guid is a GUID so load
98: if (!$this->load($guid)) {
99: throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid)));
100: }
101: } else {
102: throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue'));
103: }
104: }
105: }
106:
107: /**
108: * Loads the full ElggSite when given a guid.
109: *
110: * @param mixed $guid GUID of ElggSite entity or database row object
111: *
112: * @return bool
113: * @throws InvalidClassException
114: */
115: protected function load($guid) {
116: $attr_loader = new ElggAttributeLoader(get_class(), 'site', $this->attributes);
117: $attr_loader->requires_access_control = !($this instanceof ElggPlugin);
118: $attr_loader->secondary_loader = 'get_site_entity_as_row';
119:
120: $attrs = $attr_loader->getRequiredAttributes($guid);
121: if (!$attrs) {
122: return false;
123: }
124:
125: $this->attributes = $attrs;
126: $this->attributes['tables_loaded'] = 2;
127: _elgg_cache_entity($this);
128:
129: return true;
130: }
131:
132: /**
133: * Saves site-specific attributes.
134: *
135: * @internal Site attributes are saved in the sites_entity table.
136: *
137: * @return bool
138: */
139: public function save() {
140: global $CONFIG;
141:
142: // Save generic stuff
143: if (!parent::save()) {
144: return false;
145: }
146:
147: // make sure the site guid is set (if not, set to self)
148: if (!$this->get('site_guid')) {
149: $guid = $this->get('guid');
150: update_data("UPDATE {$CONFIG->dbprefix}entities SET site_guid=$guid
151: WHERE guid=$guid");
152: }
153:
154: // Now save specific stuff
155: return create_site_entity($this->get('guid'), $this->get('name'),
156: $this->get('description'), $this->get('url'));
157: }
158:
159: /**
160: * Delete the site.
161: *
162: * @note You cannot delete the current site.
163: *
164: * @return bool
165: * @throws SecurityException
166: */
167: public function delete() {
168: global $CONFIG;
169: if ($CONFIG->site->getGUID() == $this->guid) {
170: throw new SecurityException('SecurityException:deletedisablecurrentsite');
171: }
172:
173: return parent::delete();
174: }
175:
176: /**
177: * Disable the site
178: *
179: * @note You cannot disable the current site.
180: *
181: * @param string $reason Optional reason for disabling
182: * @param bool $recursive Recursively disable all contained entities?
183: *
184: * @return bool
185: * @throws SecurityException
186: */
187: public function disable($reason = "", $recursive = true) {
188: global $CONFIG;
189:
190: if ($CONFIG->site->getGUID() == $this->guid) {
191: throw new SecurityException('SecurityException:deletedisablecurrentsite');
192: }
193:
194: return parent::disable($reason, $recursive);
195: }
196:
197: /**
198: * Gets an array of ElggUser entities who are members of the site.
199: *
200: * @param array $options An associative array for key => value parameters
201: * accepted by elgg_get_entities(). Common parameters
202: * include 'limit', and 'offset'.
203: * Note: this was $limit before version 1.8
204: * @param int $offset Offset @deprecated parameter
205: *
206: * @todo remove $offset in 2.0
207: *
208: * @return array of ElggUsers
209: */
210: public function getMembers($options = array(), $offset = 0) {
211: if (!is_array($options)) {
212: elgg_deprecated_notice("ElggSite::getMembers uses different arguments!", 1.8);
213: $options = array(
214: 'limit' => $options,
215: 'offset' => $offset,
216: );
217: }
218:
219: $defaults = array(
220: 'site_guids' => ELGG_ENTITIES_ANY_VALUE,
221: 'relationship' => 'member_of_site',
222: 'relationship_guid' => $this->getGUID(),
223: 'inverse_relationship' => TRUE,
224: 'type' => 'user',
225: );
226:
227: $options = array_merge($defaults, $options);
228:
229: return elgg_get_entities_from_relationship($options);
230: }
231:
232: /**
233: * List the members of this site
234: *
235: * @param array $options An associative array for key => value parameters
236: * accepted by elgg_list_entities(). Common parameters
237: * include 'full_view', 'limit', and 'offset'.
238: *
239: * @return string
240: * @since 1.8.0
241: */
242: public function listMembers($options = array()) {
243: $defaults = array(
244: 'site_guids' => ELGG_ENTITIES_ANY_VALUE,
245: 'relationship' => 'member_of_site',
246: 'relationship_guid' => $this->getGUID(),
247: 'inverse_relationship' => TRUE,
248: 'type' => 'user',
249: );
250:
251: $options = array_merge($defaults, $options);
252:
253: return elgg_list_entities_from_relationship($options);
254: }
255:
256: /**
257: * Adds a user to the site.
258: *
259: * @param int $user_guid GUID
260: *
261: * @return bool
262: */
263: public function addUser($user_guid) {
264: return add_site_user($this->getGUID(), $user_guid);
265: }
266:
267: /**
268: * Removes a user from the site.
269: *
270: * @param int $user_guid GUID
271: *
272: * @return bool
273: */
274: public function removeUser($user_guid) {
275: return remove_site_user($this->getGUID(), $user_guid);
276: }
277:
278: /**
279: * Returns an array of ElggObject entities that belong to the site.
280: *
281: * @warning This only returns objects that have been explicitly added to the
282: * site through addObject()
283: *
284: * @param string $subtype Entity subtype
285: * @param int $limit Limit
286: * @param int $offset Offset
287: *
288: * @return array
289: */
290: public function getObjects($subtype = "", $limit = 10, $offset = 0) {
291: return get_site_objects($this->getGUID(), $subtype, $limit, $offset);
292: }
293:
294: /**
295: * Adds an object to the site.
296: *
297: * @param int $object_guid GUID
298: *
299: * @return bool
300: */
301: public function addObject($object_guid) {
302: return add_site_object($this->getGUID(), $object_guid);
303: }
304:
305: /**
306: * Remvoes an object from the site.
307: *
308: * @param int $object_guid GUID
309: *
310: * @return bool
311: */
312: public function removeObject($object_guid) {
313: return remove_site_object($this->getGUID(), $object_guid);
314: }
315:
316: /**
317: * Get the collections associated with a site.
318: *
319: * @param string $subtype Subtype
320: * @param int $limit Limit
321: * @param int $offset Offset
322: *
323: * @return unknown
324: * @deprecated 1.8 Was never implemented
325: */
326: public function getCollections($subtype = "", $limit = 10, $offset = 0) {
327: elgg_deprecated_notice("ElggSite::getCollections() is deprecated", 1.8);
328: get_site_collections($this->getGUID(), $subtype, $limit, $offset);
329: }
330:
331: /*
332: * EXPORTABLE INTERFACE
333: */
334:
335: /**
336: * Return an array of fields which can be exported.
337: *
338: * @return array
339: */
340: public function getExportableValues() {
341: return array_merge(parent::getExportableValues(), array(
342: 'name',
343: 'description',
344: 'url',
345: ));
346: }
347:
348: /**
349: * Halts bootup and redirects to the site front page
350: * if site is in walled garden mode, no user is logged in,
351: * and the URL is not a public page.
352: *
353: * @link http://docs.elgg.org/Tutorials/WalledGarden
354: *
355: * @return void
356: * @since 1.8.0
357: */
358: public function checkWalledGarden() {
359: global $CONFIG;
360:
361: // command line calls should not invoke the walled garden check
362: if (PHP_SAPI === 'cli') {
363: return;
364: }
365:
366: if ($CONFIG->walled_garden) {
367: if ($CONFIG->default_access == ACCESS_PUBLIC) {
368: $CONFIG->default_access = ACCESS_LOGGED_IN;
369: }
370: elgg_register_plugin_hook_handler(
371: 'access:collections:write',
372: 'user',
373: '_elgg_walled_garden_remove_public_access');
374:
375: if (!elgg_is_logged_in()) {
376: // hook into the index system call at the highest priority
377: elgg_register_plugin_hook_handler('index', 'system', 'elgg_walled_garden_index', 1);
378:
379: if (!$this->isPublicPage()) {
380: if (!elgg_is_xhr()) {
381: $_SESSION['last_forward_from'] = current_page_url();
382: }
383: register_error(elgg_echo('loggedinrequired'));
384: forward();
385: }
386: }
387: }
388: }
389:
390: /**
391: * Returns if a URL is public for this site when in Walled Garden mode.
392: *
393: * Pages are registered to be public by {@elgg_plugin_hook public_pages walled_garden}.
394: *
395: * @param string $url Defaults to the current URL.
396: *
397: * @return bool
398: * @since 1.8.0
399: */
400: public function isPublicPage($url = '') {
401: global $CONFIG;
402:
403: if (empty($url)) {
404: $url = current_page_url();
405:
406: // do not check against URL queries
407: if ($pos = strpos($url, '?')) {
408: $url = substr($url, 0, $pos);
409: }
410: }
411:
412: // always allow index page
413: if ($url == elgg_get_site_url($this->guid)) {
414: return TRUE;
415: }
416:
417: // default public pages
418: $defaults = array(
419: 'walled_garden/.*',
420: 'login',
421: 'action/login',
422: 'register',
423: 'action/register',
424: 'forgotpassword',
425: 'resetpassword',
426: 'action/user/requestnewpassword',
427: 'action/user/passwordreset',
428: 'action/security/refreshtoken',
429: 'ajax/view/js/languages',
430: 'upgrade\.php',
431: 'xml-rpc\.php',
432: 'mt/mt-xmlrpc\.cgi',
433: 'css/.*',
434: 'js/.*',
435: 'cache/css/.*',
436: 'cache/js/.*',
437: 'cron/.*',
438: 'services/.*',
439: );
440:
441: // include a hook for plugin authors to include public pages
442: $plugins = elgg_trigger_plugin_hook('public_pages', 'walled_garden', NULL, array());
443:
444: // allow public pages
445: foreach (array_merge($defaults, $plugins) as $public) {
446: $pattern = "`^{$CONFIG->url}$public/*$`i";
447: if (preg_match($pattern, $url)) {
448: return TRUE;
449: }
450: }
451:
452: // non-public page
453: return FALSE;
454: }
455: }
456: