From 339a5da9460e30397d2f6a9c8c64698990c90975 Mon Sep 17 00:00:00 2001
From: Benjamin Lorteau <benjamin.lorteau@cbsinteractive.com>
Date: Mon, 22 Oct 2018 14:44:55 -0400
Subject: [PATCH] Move $apps out of App

- Move $nav_sel out of App
- Add new Content\Nav::getAppMenu() method
---
 mod/apps.php        |  10 ++--
 src/App.php         |  42 +++++----------
 src/Content/Nav.php | 129 ++++++++++++++++++++++++++------------------
 3 files changed, 98 insertions(+), 83 deletions(-)

diff --git a/mod/apps.php b/mod/apps.php
index 85a3d9fe2..80138f78d 100644
--- a/mod/apps.php
+++ b/mod/apps.php
@@ -2,11 +2,11 @@
 /**
  * @file mod/apps.php
  */
-use Friendica\App;
+use Friendica\Content\Nav;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
 
-function apps_content(App $a)
+function apps_content()
 {
 	$privateaddons = Config::get('config', 'private_addons');
 	if ($privateaddons === "1") {
@@ -18,13 +18,15 @@ function apps_content(App $a)
 
 	$title = L10n::t('Applications');
 
-	if (count($a->apps) == 0) {
+	$apps = Nav::getAppMenu();
+
+	if (count($apps) == 0) {
 		notice(L10n::t('No installed applications.') . EOL);
 	}
 
 	$tpl = get_markup_template('apps.tpl');
 	return replace_macros($tpl, [
 		'$title' => $title,
-		'$apps' => $a->apps,
+		'$apps'  => $apps,
 	]);
 }
diff --git a/src/App.php b/src/App.php
index 5a29d55ed..9b7a438d3 100644
--- a/src/App.php
+++ b/src/App.php
@@ -55,14 +55,12 @@ class App
 	public $interactive = true;
 	public $addons;
 	public $addons_admin = [];
-	public $apps = [];
 	public $identities;
 	public $is_mobile = false;
 	public $is_tablet = false;
 	public $performance = [];
 	public $callstack = [];
 	public $theme_info = [];
-	public $nav_sel;
 	public $category;
 	// Allow themes to control internal parameters
 	// by changing App values in theme.php
@@ -371,19 +369,6 @@ class App
 
 		Core\L10n::init();
 
-		$this->page = [
-			'aside' => '',
-			'bottom' => '',
-			'content' => '',
-			'footer' => '',
-			'htmlhead' => '',
-			'nav' => '',
-			'page_title' => '',
-			'right_aside' => '',
-			'template' => '',
-			'title' => ''
-		];
-
 		$this->process_id = Core\System::processID('log');
 	}
 
@@ -1732,17 +1717,18 @@ class App
 			Core\Addon::check();
 		}
 
-		Content\Nav::setSelected('nothing');
-
-		//Don't populate apps_menu if apps are private
-		$privateapps = Core\Config::get('config', 'private_addons');
-		if ((local_user()) || (! $privateapps === "1")) {
-			$arr = ['app_menu' => $this->apps];
-
-			Core\Addon::callHooks('app_menu', $arr);
-
-			$this->apps = $arr['app_menu'];
-		}
+		$this->page = [
+			'aside' => '',
+			'bottom' => '',
+			'content' => '',
+			'footer' => '',
+			'htmlhead' => '',
+			'nav' => '',
+			'page_title' => '',
+			'right_aside' => '',
+			'template' => '',
+			'title' => ''
+		];
 
 		if (strlen($this->module)) {
 			// Compatibility with the Android Diaspora client
@@ -1849,7 +1835,6 @@ class App
 			require_once $theme_info_file;
 		}
 
-
 		// initialise content region
 		if ($this->getMode()->isNormal()) {
 			Core\Addon::callHooks('page_content_top', $this->page['content']);
@@ -1926,7 +1911,8 @@ class App
 
 		// Add the navigation (menu) template
 		if ($this->module != 'install' && $this->module != 'maintenance') {
-			Content\Nav::build($this);
+			$this->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []);
+			$this->page['nav']       = Content\Nav::build($this);
 		}
 
 		// Build the page - now that we have all the components
diff --git a/src/Content/Nav.php b/src/Content/Nav.php
index 4f6f4ae0b..8289825ea 100644
--- a/src/Content/Nav.php
+++ b/src/Content/Nav.php
@@ -15,50 +15,102 @@ use Friendica\Model\Contact;
 use Friendica\Model\Profile;
 
 require_once 'boot.php';
-require_once 'dba.php';
 require_once 'include/text.php';
 
 class Nav
 {
+	private static $selected = [
+		'global'    => null,
+		'community' => null,
+		'network'   => null,
+		'home'      => null,
+		'profiles'  => null,
+		'introductions' => null,
+		'notifications' => null,
+		'messages'  => null,
+		'directory' => null,
+		'settings'  => null,
+		'contacts'  => null,
+		'manage'    => null,
+		'events'    => null,
+		'register'  => null
+	];
+
+	/**
+	 * An array of HTML links provided by addons providing a module via the app_menu hook
+	 *
+	 * @var array
+	 */
+	private static $app_menu = null;
+
+	/**
+	 * Set a menu item in navbar as selected
+	 */
+	public static function setSelected($item)
+	{
+		self::$selected[$item] = 'selected';
+	}
+
 	/**
 	 * Build page header and site navigation bars
 	 */
 	public static function build(App $a)
 	{
-		if (!(x($a->page, 'nav'))) {
-			$a->page['nav'] = '';
-		}
-
-		$a->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []);
-
-		/*
-		 * Placeholder div for popup panel
-		 */
-
-		$a->page['nav'] .= '<div id="panel" style="display: none;"></div>' ;
+		// Placeholder div for popup panel
+		$nav = '<div id="panel" style="display: none;"></div>' ;
 
 		$nav_info = self::getInfo($a);
 
-		/*
-		 * Build the page
-		 */
-
 		$tpl = get_markup_template('nav.tpl');
 
-		$a->page['nav'] .= replace_macros($tpl, [
-			'$baseurl' => System::baseUrl(),
+		$nav .= replace_macros($tpl, [
+			'$baseurl'      => System::baseUrl(),
 			'$sitelocation' => $nav_info['sitelocation'],
-			'$nav' => $nav_info['nav'],
-			'$banner' => $nav_info['banner'],
+			'$nav'          => $nav_info['nav'],
+			'$banner'       => $nav_info['banner'],
 			'$emptynotifications' => L10n::t('Nothing new here'),
-			'$userinfo' => $nav_info['userinfo'],
-			'$sel' =>  $a->nav_sel,
-			'$apps' => $a->apps,
+			'$userinfo'     => $nav_info['userinfo'],
+			'$sel'          => self::$selected,
+			'$apps'         => self::getAppMenu(),
 			'$clear_notifs' => L10n::t('Clear notifications'),
-			'$search_hint' => L10n::t('@name, !forum, #tags, content')
+			'$search_hint'  => L10n::t('@name, !forum, #tags, content')
 		]);
 
-		Addon::callHooks('page_header', $a->page['nav']);
+		Addon::callHooks('page_header', $nav);
+
+		return $nav;
+	}
+
+	/**
+	 * Returns the addon app menu
+	 *
+	 * @return array
+	 */
+	public static function getAppMenu()
+	{
+		if (is_null(self::$app_menu)) {
+			self::populateAppMenu();
+		}
+
+		return self::$app_menu;
+	}
+
+	/**
+	 * Fills the apps static variable with apps that require a menu
+	 */
+	private static function populateAppMenu()
+	{
+		self::$app_menu = [];
+
+		//Don't populate apps_menu if apps are private
+		$privateapps = Config::get('config', 'private_addons', false);
+		if (local_user() || !$privateapps) {
+			$arr = ['app_menu' => self::$app_menu];
+
+			Addon::callHooks('app_menu', $arr);
+
+			self::$app_menu = $arr['app_menu'];
+		}
 	}
 
 	/**
@@ -134,7 +186,7 @@ class Nav
 			$nav['help'] = [$help_url, L10n::t('Help'), '', L10n::t('Help and documentation')];
 		}
 
-		if (count($a->apps) > 0) {
+		if (count(self::getAppMenu()) > 0) {
 			$nav['apps'] = ['apps', L10n::t('Apps'), '', L10n::t('Addon applications, utilities, games')];
 		}
 
@@ -235,29 +287,4 @@ class Nav
 			'userinfo' => $userinfo,
 		];
 	}
-
-	/**
-	 * Set a menu item in navbar as selected
-	 */
-	public static function setSelected($item)
-	{
-		$a = get_app();
-		$a->nav_sel = [
-			'global' 	=> null,
-			'community' 	=> null,
-			'network' 	=> null,
-			'home'		=> null,
-			'profiles'	=> null,
-			'introductions' => null,
-			'notifications'	=> null,
-			'messages'	=> null,
-			'directory'	=> null,
-			'settings'	=> null,
-			'contacts'	=> null,
-			'manage'	=> null,
-			'events'	=> null,
-			'register'	=> null
-		];
-		$a->nav_sel[$item] = 'selected';
-	}
 }