Elgg  Version 1.9
ViewsService.php
Go to the documentation of this file.
1 <?php
2 
18 
19  protected $config_wrapper;
20  protected $site_url_wrapper;
21  protected $user_wrapper;
22  protected $user_wrapped;
23 
28  protected $file_exists_cache = array();
29 
36  public function __construct(Elgg_PluginHooksService $hooks, Elgg_Logger $logger) {
37  $this->hooks = $hooks;
38  $this->logger = $logger;
39  }
40 
46  protected function getUserWrapper() {
48  if ($user) {
49  if ($user !== $this->user_wrapped) {
50  $warning = 'Use elgg_get_logged_in_user_entity() rather than assuming elgg_view() '
51  . 'populates $vars["user"]';
52  $this->user_wrapper = new Elgg_DeprecationWrapper($user, $warning, 1.8);
53  }
55  }
56  return $user;
57  }
58 
62  public function autoregisterViews($view_base, $folder, $base_location_path, $viewtype) {
63  $handle = opendir($folder);
64  if ($handle) {
65  while ($view = readdir($handle)) {
66  if (!empty($view_base)) {
67  $view_base_new = $view_base . "/";
68  } else {
69  $view_base_new = "";
70  }
71 
72  if (substr($view, 0, 1) !== '.') {
73  if (is_dir($folder . "/" . $view)) {
74  $this->autoregisterViews($view_base_new . $view, $folder . "/" . $view,
75  $base_location_path, $viewtype);
76  } else {
77  $this->setViewLocation($view_base_new . basename($view, '.php'),
78  $base_location_path, $viewtype);
79  }
80  }
81  }
82  return true;
83  }
84  return false;
85  }
86 
90  public function getViewLocation($view, $viewtype = '') {
92 
93  if (empty($viewtype)) {
95  }
96 
97  if (!isset($CONFIG->views->locations[$viewtype][$view])) {
98  if (!isset($CONFIG->viewpath)) {
99  return dirname(dirname(dirname(__FILE__))) . "/views/";
100  } else {
101  return $CONFIG->viewpath;
102  }
103  } else {
104  return $CONFIG->views->locations[$viewtype][$view];
105  }
106  }
107 
111  public function setViewLocation($view, $location, $viewtype = '') {
112  global $CONFIG;
113 
114  if (empty($viewtype)) {
115  $viewtype = 'default';
116  }
117 
118  if (!isset($CONFIG->views)) {
119  $CONFIG->views = new stdClass;
120  }
121 
122  if (!isset($CONFIG->views->locations)) {
123  $CONFIG->views->locations = array($viewtype => array($view => $location));
124 
125  } else if (!isset($CONFIG->views->locations[$viewtype])) {
126  $CONFIG->views->locations[$viewtype] = array($view => $location);
127 
128  } else {
129  $CONFIG->views->locations[$viewtype][$view] = $location;
130  }
131  }
132 
137  global $CONFIG;
138 
139  if (!isset($CONFIG->viewtype)) {
140  $CONFIG->viewtype = new stdClass;
141  }
142 
143  if (!isset($CONFIG->viewtype->fallback)) {
144  $CONFIG->viewtype->fallback = array();
145  }
146 
147  $CONFIG->viewtype->fallback[] = $viewtype;
148  }
149 
153  public function doesViewtypeFallback($viewtype) {
154  global $CONFIG;
155 
156  if (isset($CONFIG->viewtype) && isset($CONFIG->viewtype->fallback)) {
157  return in_array($viewtype, $CONFIG->viewtype->fallback);
158  }
159 
160  return false;
161  }
162 
176  public function renderDeprecatedView($view, array $vars, $suggestion, $version) {
177  $rendered = $this->renderView($view, $vars, false, '', false);
178  if ($rendered) {
179  elgg_deprecated_notice("The $view view has been deprecated. $suggestion", $version, 3);
180  }
181  return $rendered;
182  }
183 
187  public function renderView($view, array $vars = array(), $bypass = false, $viewtype = '', $issue_missing_notice = true) {
188  global $CONFIG;
189 
190  if (!is_string($view) || !is_string($viewtype)) {
191  $this->logger->log("View and Viewtype in views must be a strings: $view", 'NOTICE');
192  return '';
193  }
194  // basic checking for bad paths
195  if (strpos($view, '..') !== false) {
196  return '';
197  }
198 
199  if (!is_array($vars)) {
200  $this->logger->log("Vars in views must be an array: $view", 'ERROR');
201  $vars = array();
202  }
203 
204  // Get the current viewtype
205  if ($viewtype === '' || !_elgg_is_valid_viewtype($viewtype)) {
207  }
208 
209  $view_orig = $view;
210 
211  // Trigger the pagesetup event
212  if (!isset($CONFIG->pagesetupdone) && $CONFIG->boot_complete) {
213  $CONFIG->pagesetupdone = true;
214  elgg_trigger_event('pagesetup', 'system');
215  }
216 
217  // @warning - plugin authors: do not expect user, config, and url to be
218  // set by elgg_view() in the future. Instead, use elgg_get_logged_in_user_entity(),
219  // elgg_get_config(), and elgg_get_site_url() in your views.
220  if (!isset($vars['user'])) {
221  $vars['user'] = $this->getUserWrapper();
222  }
223  if (!isset($vars['config'])) {
224  if (!$this->config_wrapper) {
225  $warning = 'Do not rely on $vars["config"] or $CONFIG being available in views';
226  $this->config_wrapper = new Elgg_DeprecationWrapper($CONFIG, $warning, 1.8);
227  }
228  $vars['config'] = $this->config_wrapper;
229  }
230  if (!isset($vars['url'])) {
231  if (!$this->site_url_wrapper) {
232  $warning = 'Do not rely on $vars["url"] being available in views';
233  $this->site_url_wrapper = new Elgg_DeprecationWrapper(elgg_get_site_url(), $warning, 1.8);
234  }
236  }
237 
238  // full_view is the new preferred key for full view on entities @see elgg_view_entity()
239  // check if full_view is set because that means we've already rewritten it and this is
240  // coming from another view passing $vars directly.
241  if (isset($vars['full']) && !isset($vars['full_view'])) {
242  elgg_deprecated_notice("Use \$vars['full_view'] instead of \$vars['full']", 1.8, 2);
243  $vars['full_view'] = $vars['full'];
244  }
245  if (isset($vars['full_view'])) {
246  $vars['full'] = $vars['full_view'];
247  }
248 
249  // internalname => name (1.8)
250  if (isset($vars['internalname']) && !isset($vars['__ignoreInternalname']) && !isset($vars['name'])) {
251  elgg_deprecated_notice('You should pass $vars[\'name\'] now instead of $vars[\'internalname\']', 1.8, 2);
252  $vars['name'] = $vars['internalname'];
253  } elseif (isset($vars['name'])) {
254  if (!isset($vars['internalname'])) {
255  $vars['__ignoreInternalname'] = '';
256  }
257  $vars['internalname'] = $vars['name'];
258  }
259 
260  // internalid => id (1.8)
261  if (isset($vars['internalid']) && !isset($vars['__ignoreInternalid']) && !isset($vars['name'])) {
262  elgg_deprecated_notice('You should pass $vars[\'id\'] now instead of $vars[\'internalid\']', 1.8, 2);
263  $vars['id'] = $vars['internalid'];
264  } elseif (isset($vars['id'])) {
265  if (!isset($vars['internalid'])) {
266  $vars['__ignoreInternalid'] = '';
267  }
268  $vars['internalid'] = $vars['id'];
269  }
270 
271  // If it's been requested, pass off to a template handler instead
272  if ($bypass == false && isset($CONFIG->template_handler) && !empty($CONFIG->template_handler)) {
273  $template_handler = $CONFIG->template_handler;
274  if (is_callable($template_handler)) {
275  return call_user_func($template_handler, $view, $vars);
276  }
277  }
278 
279  // Set up any extensions to the requested view
280  if (isset($CONFIG->views->extensions[$view])) {
281  $viewlist = $CONFIG->views->extensions[$view];
282  } else {
283  $viewlist = array(500 => $view);
284  }
285 
286  $content = '';
287  foreach ($viewlist as $view) {
288 
289  $rendering = $this->renderViewFile($view, $vars, $viewtype, $issue_missing_notice);
290  if ($rendering !== false) {
291  $content .= $rendering;
292  continue;
293  }
294 
295  // attempt to load default view
296  if ($viewtype !== 'default' && $this->doesViewtypeFallback($viewtype)) {
297 
298  $rendering = $this->renderViewFile($view, $vars, 'default', $issue_missing_notice);
299  if ($rendering !== false) {
300  $content .= $rendering;
301  }
302  }
303  }
304 
305  // Plugin hook
306  $params = array('view' => $view_orig, 'vars' => $vars, 'viewtype' => $viewtype);
307  $content = elgg_trigger_plugin_hook('view', $view_orig, $params, $content);
308 
309  // backward compatibility with less granular hook will be gone in 2.0
310  $content_tmp = elgg_trigger_plugin_hook('display', 'view', $params, $content);
311 
312  if ($content_tmp !== $content) {
313  $content = $content_tmp;
314  elgg_deprecated_notice('The display:view plugin hook is deprecated by view:view_name', 1.8);
315  }
316 
317  return $content;
318  }
319 
327  protected function fileExists($path) {
328  if (!isset($this->file_exists_cache[$path])) {
329  $this->file_exists_cache[$path] = file_exists($path);
330  }
331  return $this->file_exists_cache[$path];
332  }
333 
344  private function renderViewFile($view, array $vars, $viewtype, $issue_missing_notice) {
345  $view_location = $this->getViewLocation($view, $viewtype);
346 
347  // @warning - plugin authors: do not expect $CONFIG to be available in views
348  // in the future. Instead, use elgg_get_config() in your views.
349  // Note: this is intentionally a local var.
351 
352  if ($this->fileExists("{$view_location}$viewtype/$view.php")) {
353  ob_start();
354  include("{$view_location}$viewtype/$view.php");
355  return ob_get_clean();
356  } else if ($this->fileExists("{$view_location}$viewtype/$view")) {
357  return file_get_contents("{$view_location}$viewtype/$view");
358  } else {
359  if ($issue_missing_notice) {
360  $this->logger->log("$viewtype/$view view does not exist.", 'NOTICE');
361  }
362  return false;
363  }
364  }
365 
369  public function viewExists($view, $viewtype = '', $recurse = true) {
370  global $CONFIG;
371 
372  // Detect view type
373  if ($viewtype === '' || !_elgg_is_valid_viewtype($viewtype)) {
375  }
376 
377  if (!isset($CONFIG->views->locations[$viewtype][$view])) {
378  if (!isset($CONFIG->viewpath)) {
379  $location = dirname(dirname(dirname(__FILE__))) . "/views/";
380  } else {
381  $location = $CONFIG->viewpath;
382  }
383  } else {
384  $location = $CONFIG->views->locations[$viewtype][$view];
385  }
386 
387  if ($this->fileExists("{$location}$viewtype/$view.php") ||
388  $this->fileExists("{$location}$viewtype/$view")) {
389  return true;
390  }
391 
392  // If we got here then check whether this exists as an extension
393  // We optionally recursively check whether the extended view exists also for the viewtype
394  if ($recurse && isset($CONFIG->views->extensions[$view])) {
395  foreach ($CONFIG->views->extensions[$view] as $view_extension) {
396  // do not recursively check to stay away from infinite loops
397  if ($this->viewExists($view_extension, $viewtype, false)) {
398  return true;
399  }
400  }
401  }
402 
403  // Now check if the default view exists if the view is registered as a fallback
404  if ($viewtype != 'default' && $this->doesViewtypeFallback($viewtype)) {
405  return $this->viewExists($view, 'default');
406  }
407 
408  return false;
409 
410  }
411 
415  public function extendView($view, $view_extension, $priority = 501, $viewtype = '') {
416  global $CONFIG;
417 
418  if (!isset($CONFIG->views)) {
419  $CONFIG->views = (object) array(
420  'extensions' => array(),
421  );
422  $CONFIG->views->extensions[$view][500] = (string) $view;
423  } else {
424  if (!isset($CONFIG->views->extensions[$view])) {
425  $CONFIG->views->extensions[$view][500] = (string) $view;
426  }
427  }
428 
429  // raise priority until it doesn't match one already registered
430  while (isset($CONFIG->views->extensions[$view][$priority])) {
431  $priority++;
432  }
433 
434  $CONFIG->views->extensions[$view][$priority] = (string) $view_extension;
435  ksort($CONFIG->views->extensions[$view]);
436 
437  }
438 
442  public function unextendView($view, $view_extension) {
443  global $CONFIG;
444 
445  if (!isset($CONFIG->views)) {
446  return false;
447  }
448 
449  if (!isset($CONFIG->views->extensions)) {
450  return false;
451  }
452 
453  if (!isset($CONFIG->views->extensions[$view])) {
454  return false;
455  }
456 
457  $priority = array_search($view_extension, $CONFIG->views->extensions[$view]);
458  if ($priority === false) {
459  return false;
460  }
461 
462  unset($CONFIG->views->extensions[$view][$priority]);
463 
464  return true;
465  }
466 
470  public function registerCacheableView($view) {
471  global $CONFIG;
472 
473  if (!isset($CONFIG->views)) {
474  $CONFIG->views = new stdClass;
475  }
476 
477  if (!isset($CONFIG->views->simplecache)) {
478  $CONFIG->views->simplecache = array();
479  }
480 
481  $CONFIG->views->simplecache[$view] = true;
482  }
483 
487  public function isCacheableView($view) {
488  global $CONFIG;
489 
490  if (!isset($CONFIG->views)) {
491  $CONFIG->views = new stdClass;
492  }
493 
494  if (!isset($CONFIG->views->simplecache)) {
495  $CONFIG->views->simplecache = array();
496  }
497 
498  if (isset($CONFIG->views->simplecache[$view])) {
499  return true;
500  } else {
501  $currentViewtype = elgg_get_viewtype();
502  $viewtypes = array($currentViewtype);
503 
504  if ($this->doesViewtypeFallback($currentViewtype) && $currentViewtype != 'default') {
505  $viewtypes[] = 'defaut';
506  }
507 
508  // If a static view file is found in any viewtype, it's considered cacheable
509  foreach ($viewtypes as $viewtype) {
510  $view_file = $this->getViewLocation($view, $viewtype) . "$viewtype/$view";
511  if ($this->fileExists($view_file)) {
512  return true;
513  }
514  }
515 
516  // Assume not-cacheable by default
517  return false;
518  }
519  }
520 }
$view
Definition: crop.php:68
_elgg_is_valid_viewtype($viewtype)
Checks if $viewtype is a string suitable for use as a viewtype name.
Definition: views.php:158
extendView($view, $view_extension, $priority=501, $viewtype= '')
private
autoregisterViews($view_base, $folder, $base_location_path, $viewtype)
private
setViewLocation($view, $location, $viewtype= '')
private
viewExists($view, $viewtype= '', $recurse=true)
private
isCacheableView($view)
private
$params
Definition: login.php:72
renderView($view, array $vars=array(), $bypass=false, $viewtype= '', $issue_missing_notice=true)
private
__construct(Elgg_PluginHooksService $hooks, Elgg_Logger $logger)
Constructor.
elgg_get_viewtype()
Return the current view type.
Definition: views.php:91
global $CONFIG
$user
Definition: ban.php:13
registerCacheableView($view)
private
elgg_trigger_plugin_hook($hook, $type, $params=null, $returnvalue=null)
Trigger a Plugin Hook and run all handler callbacks registered to that hook:type. ...
Definition: elgglib.php:925
elgg_deprecated_notice($msg, $dep_version, $backtrace_level=1)
Sends a notice about deprecated use of a function, view, etc.
Definition: elgglib.php:1171
elgg global
Pointer to the global context.
Definition: elgglib.js:12
elgg_get_site_url($site_guid=0)
Get the URL for the current (or specified) site.
getUserWrapper()
Get the user object in a wrapper.
getViewLocation($view, $viewtype= '')
private
doesViewtypeFallback($viewtype)
private
renderDeprecatedView($view, array $vars, $suggestion, $version)
Display a view with a deprecation notice.
unextendView($view, $view_extension)
private
$content
Set robots.txt action.
Definition: set_robots.php:6
registerViewtypeFallback($viewtype)
private
elgg_get_logged_in_user_entity()
Return the current logged in user, or null if no user is logged in.
Definition: sessions.php:32
elgg_trigger_event($event, $object_type, $object=null)
Trigger an Elgg Event and attempt to run all handler callbacks registered to that event...
Definition: elgglib.php:720
$version
Definition: version.php:14
$path
Definition: invalid.php:17
$viewtype
Definition: start.php:132
fileExists($path)
Wrapper for file_exists() that caches false results (the stat cache only caches true results)...
$priority
if(file_exists($welcome)) $vars
Definition: upgrade.php:93